A pipeline for every request
Before your route runs, you often want to log the request, parse its JSON body, or check an API key. middleware are functions in a pipeline: each gets (req, res, next) and either answers or calls next() to pass the request on.
app.use and next
import express from "express";
const app = express();
app.use((req, res, next) => {
const start = Date.now();
res.on("finish", () => console.log(req.method, req.path, res.statusCode, Date.now() - start + "ms"));
next();
});
app.use(express.json());
function requireKey(req, res, next) {
if (req.get("x-api-key") !== "secret") return res.status(401).json({ error: "Missing or wrong API key" });
next();
}
app.post("/orders", requireKey, (req, res) => {
res.status(201).json({ ok: true, dish: req.body.dish });
});
app.use((err, req, res, next) => {
console.error("Oops:", err.message);
res.status(err.status ?? 500).json({ error: err.message });
});
app.listen(3000);
const post = (headers) => fetch("http://localhost:3000/orders", { method: "POST", headers: { "Content-Type": "application/json", ...headers }, body: JSON.stringify({ dish: "Momo" }) });
console.log((await post({})).status);
console.log(await (await post({ "x-api-key": "secret" })).json());- Order matters: middleware runs in the order you use it.
- Popular packages: cors, helmet (security headers), morgan (logging), express-rate-limit.
- In Express 5, errors thrown in async handlers go to the error middleware automatically.