Learning Goals
3 minBy the end of this lesson you will be able to:
- Explain what middleware is: a function that runs between the request and the response.
- Register middleware with
app.use(...)and pass control on by callingnext(). - Write a logger and watch
req.methodandreq.urlprint in the terminal for every request. - Switch on
express.json()so a POST route can finally readreq.body.
Warm-Up · Predict the Order
5 minLast lesson you used req.query and res.json. Today we add a step before the route runs.
Read this tiny server. A request comes in for /menu. Predict the order the three messages print:
app.use((req, res, next) => { console.log('one'); next() })
app.use((req, res, next) => { console.log('two'); next() })
app.get('/menu', (req, res) => { console.log('three'); res.send('ok') })Reveal
They print in the order they were written: one, then two, then three. Middleware runs top to bottom. Each one calls next() to hand the request to whatever comes next, until the route finally answers. Change the order of the lines, and the order of the logs changes with it.
New Concept · The Checkpoint Between Request and Response
12 minThink of an airport. Every passenger passes through the same checkpoints — a bag scan, a passport desk — before reaching their gate. Middleware is like those checkpoints. Every request passes through them before it reaches a route.
A middleware is a function Express runs on the way in. It receives three things: the request, the response, and a special next function. Calling next() means “I am done — send this request on to the next checkpoint”.
The syntax
You register middleware with app.use:
app.use((req, res, next) => {
// do something with the request here
next() // pass control to the next checkpoint
})That (req, res, next) shape is the whole idea. The route handlers you already write take (req, res). Middleware takes one more argument — next — and must call it to keep the request moving.
Why it matters
Almost every useful thing a real server does happens as middleware. Logging every request, parsing the JSON a form sends, and checking whether a user is allowed in — all of these are middleware. Learn this one pattern, and the rest of Level 3 fits together.
Worked Example · A Logger, Then req.body
12 minFollow along in your Express project. Aisyah is building the API for a nasi lemak stall, and wants to see every request as it arrives.
Step 1 — Write a logger middleware
Add this near the top of server.js, before your routes:
// log the method and url of every request
app.use((req, res, next) => {
console.log(req.method, req.url)
next() // hand the request on to the route
})Step 2 — Run it and hit a couple of routes
Start the server in the terminal:
$ node server.jsNow visit /menu and then /menu/nasi-lemak in your browser. Watch the terminal — one line appears per request:
GET /menu
GET /menu/nasi-lemakThe logger ran first, printed the method and url, then called next() so the route could send its answer.
Step 3 — Switch on express.json() so req.body works
Last lesson we promised req.body would work once we added a parser. Here it is. express.json() is built-in middleware that reads the JSON in a request and puts it on req.body:
app.use(express.json()) // fills req.body from JSON
app.post('/order', (req, res) => {
const item = req.body.item // now this works!
res.json({ ordered: item })
})Send a POST with a JSON body of { "item": "teh tarik" }. The reply:
{ "ordered": "teh tarik" }Without express.json(), req.body is undefined. The middleware is what fills it in.
Step 4 — Warning: what if you forget next()?
Every middleware must either send a response or call next(). Forget both, and the request hangs forever:
app.use((req, res, next) => {
console.log(req.method, req.url)
// oops — no next() and no response
})The browser tab keeps spinning. Nothing ever replies. The request is stuck at the checkpoint with no way forward. What changed? Only one missing line — next() — decides whether the request moves on or freezes.
Try It Yourself
13 minThree tasks, all in your server.js. Restart the server with node server.js after each change.
Task 1 — Add a timestamp
Extend your logger so it also prints the time of each request. Use
new Date().toLocaleTimeString()and log it alongsidereq.methodandreq.url:app.use((req, res, next) => { const time = new Date().toLocaleTimeString() console.log(time, req.method, req.url) next() })Hit a route and check the terminal shows a time in front of each line.
Task 2 — Echo it back
Make sure
app.use(express.json())is switched on. Then add aPOST /echoroute that returns whatever body it was sent, straight back as JSON:app.post('/echo', (req, res) => { res.json(req.body) })Send
{ "name": "Wei Jie" }and confirm the same object comes back.Task 3 — Your own checkpoint
Write a small middleware of your own that attaches or logs something useful. For example, count how many requests the server has handled so far, or log the browser's language from
req.headers. Callnext()at the end so the request still reaches its route.
Mini-Challenge · The Secret Key Gate
8 minWrite a middleware that guards a route. Combine today's idea with req.query from last lesson. The rule: a request may pass only if the query string contains ?key=secret. Otherwise, block it.
It works if: visiting /vip replies with a 401 and a refusal message, but /vip?key=secret lets you through to the route.
Reveal a sample answer
// only let the request through if ?key=secret is present
app.use((req, res, next) => {
if (req.query.key !== 'secret') {
return res.status(401).send('Sorry, wrong key.')
}
next() // key is correct — carry on
})
app.get('/vip', (req, res) => {
res.send('Selamat datang to the VIP room!')
})Visiting /vip with no key returns:
401 Sorry, wrong key.Visiting /vip?key=secret returns:
200 Selamat datang to the VIP room!Notice the return in front of res.status(401). It stops the middleware right there, so next() never runs and the route is never reached.
Recap
3 min- Middleware runs between the request coming in and the response going out.
- Register it with
app.use(...); it takes(req, res, next). - Call
next()to pass control on, or send a response to stop the request. - Order matters — middleware runs top to bottom, in the order you write it.
express.json()is built-in middleware that fillsreq.bodyfrom a JSON request.
New words
- Middleware — a function that runs between the request and the response.
- next() — the function that hands the request on to the next checkpoint.
- app.use — how you register a middleware so every request passes through it.
- express.json() — built-in middleware that reads JSON and puts it on
req.body.
Homework
4 min to brief · ~20 min to doRequired
- Add a logger middleware to your Express server that prints
req.methodandreq.urlfor every request. Start the server, visit three different routes, then take a screenshot of the terminal logs and bring it to next lesson.
Optional stretch
- Read one paragraph on the difference between app-level middleware (registered with
app.use, runs for the whole app) and router-level middleware (registered on anexpress.Router(), runs for one group of routes). Write two sentences in your own words explaining when you would reach for each.