app.use((req, res, next) => {
console.log(`Incoming: ${req.path}`);
next(); // pass control down the chain
});
app.use(authenticate);
app.use(authorize);
app.get("/orders/:id", getOrderHandler);
Same shape, different keyword: calling next() (instead of awaiting it) hands off to the next middleware. Forgetting to call next() — or to send a response — is the classic Express bug: the request just hangs forever, satisfying neither path, with no error and no timeout by default.
// Applied to EVERY route, because it's registered before the routes with app.use
app.use(express.json());
// Applied to only ONE route, as an extra argument before the handler
app.get("/orders/:id", authenticate, getOrderHandler);
// Applied to every route under a specific path prefix
app.use("/admin", adminAuthMiddleware);
Express doesn't have a separate "branch" concept the way ASP.NET Core's Map does — instead, app.use(path, middleware) scopes a middleware to a path prefix, and passing extra functions before the final handler in a route definition scopes middleware to just that one route. Both are just variations on the same registration order the whole pattern depends on.
app.get("/orders/:id", (req, res, next) => {
fetchOrder(req.params.id)
.then(order => res.json(order))
.catch(next); // forwards the error to Express's error-handling chain
});
// An error handler is identified by having FOUR parameters, not three
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: "Something went wrong" });
});
Express distinguishes an error-handling middleware purely by arity — a function with four parameters (err, req, res, next) instead of three is treated specially and only invoked when something calls next(err) (or a synchronous handler throws). Passing anything to next() other than nothing skips every remaining normal middleware and jumps straight to the nearest error handler — this is the mechanism by which Express implements short-circuiting for the error path specifically.