Appearance
Middleware
Middleware is just a function that sees
req/res, maybe mutates them, then callsnext()- or ends the response. Axios interceptors with a Node accent.
The shape
ts
function logger(req: express.Request, res: express.Response, next: express.NextFunction) {
console.log(req.method, req.url)
next() // hand off to the next layer
}
app.use(logger)If you never call next() and never send a response, the request hangs. Classic "why is fetch pending forever" bug - except it's your server this time. 😅
Onion / pipeline
Registration order = execution order for incoming requests:
ts
app.use(cors({ origin: 'http://localhost:5173' }))
app.use(express.json())
app.use('/api/notes', requireAuth, notesRouter)Built-ins you'll use constantly
ts
app.use(express.json()) // parse JSON bodies → req.body
app.use(express.urlencoded({ extended: true })) // form postsWithout express.json(), req.body is undefined and your POST handler looks "broken".
Route-level middleware
ts
function requireAuth(req, res, next) {
const header = req.headers.authorization
if (!header?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'unauthorized' })
}
// …verify JWT, attach req.user…
next()
}
app.get('/api/me', requireAuth, (req, res) => {
res.json({ user: req.user })
})FE map:
| FE | Express |
|---|---|
Axios request interceptor adding Authorization | client side |
| Server checks that header | requireAuth |
Vue Router beforeEach redirect to login | 401 + SPA handles it |
We'll flesh out JWT verify in Protecting routes.
Error-handling middleware (preview)
Special signature with four args:
ts
app.use((err, req, res, next) => {
console.error(err)
res.status(500).json({ error: 'server error' })
})Express only treats it as error middleware if it has arity 4. Details in the next-next chapter.
Don't do heavy work in every middleware
Logging is fine. Hitting the DB on every static asset request is not. Scope middleware to /api when it only matters there:
ts
app.use('/api', requireAuth) // careful: then *all* /api needs authUsually better: attach requireAuth per router or per sensitive route.
As you can see, middleware isn't a new paradigm - it's shared pipeline steps. Same idea you already use around fetch.
Best,
-- ł.