Question presented to candidate: "An incoming request to your Express API needs to be logged, then authenticated, and only then handled — and if anything throws along the way, it needs to return a clean error instead of crashing. How does Express let you build this as separate, reusable pieces instead of one giant handler function?"
What a strong answer should cover:
- Middleware is a function with the signature
(req, res, next)that sits in an ordered chain between the incoming request and the final route handler — each middleware can inspect/modifyreq/res, and must either callnext()to pass control to the next function in the chain, or end the response itself (res.json(...),res.status(...).send(...)). - 📌 Verified, not assumed: a real chain of
logger, auth, handlergenuinely ran in that exact order for a valid request; for an invalid one,authgenuinely short-circuited the chain — responding with a real 401 and never callingnext(), so the route handler genuinely never ran at all. - The prompt's exact scenario — logging, then auth, then the handler, with clean error handling — maps directly onto middleware composition: each concern (logging, auth, the actual business logic) lives in its own small, reusable function, composed in order for a given route, rather than one function doing everything inline.
- 📌 Verified, not assumed — error handling: a real 4-argument middleware
(err, req, res, next)genuinely caught an error passed tonext(err)from an earlier middleware, and the normal route handler genuinely never ran — Express recognizes the 4-arg signature specifically and routes errors to it, skipping every normal (3-arg) middleware/handler still queued after the failure point. - A precise answer names that middleware order is not automatic or content-based — it is exactly the order the developer registers it in (
app.use()/ route-level arguments), which is precisely why auth must be registered before the handler it's protecting, not after, and why error-handling middleware is conventionally registered last.
Clarifying questions expected:
- "Should this middleware apply to this one route only, or to the whole app/router?" — decides between route-level middleware arguments and
app.use(). - "What should happen on an authentication failure — a redirect, a JSON error, or something else?" — shapes what the short-circuiting middleware actually does before skipping
next().
Code / implementation expected: Yes — a real, complete middleware chain with genuinely observed short-circuiting and a genuinely working 4-arg error handler is the concrete, convincing proof of exactly how the composition and ordering work.