Routes are the public surface of your API; organising them well keeps an app understandable.
A route is method + path + one or more handlers. Express has a method for each HTTP verb: app.get, app.post, app.put, app.patch, app.delete, plus app.all for every method.
Routes are checked in the order you register them, and the first one that matches and sends a response wins. Put specific routes before general ones: /users/me must come before /users/:id, or me is treated as an id.
Path matching details:
- Matching is case-insensitive and ignores a trailing slash by default (
/aboutmatches/about/). - The query string is not part of the path:
/search?q=xmatches/search. HEADrequests are answered by yourGETroutes automatically, without a body.- You can pass an array of paths:
app.get(["/", "/home"], handler).
When several methods share a path, app.route(path) chains them and avoids repeating the string:
app.route("/books")
.get(listBooks)
.post(createBook);A route can take several handlers; each calls next() to pass control to the following one. That is how per-route middleware (checking a login, loading a record) is attached: app.delete("/posts/:id", requireLogin, deletePost).
Express 5 dropped app.del() — use app.delete(). If a path exists but not for the requested method, Express returns 404, not 405; add an app.all fallback for that path if you want a proper 405 Method Not Allowed with an Allow header.
Example
import express from "express";
const app = express();
const books = [{ id: 1, title: "Dune" }];
function requireApiKey(req, res, next) {
if (req.get("x-api-key") === "secret") return next(); // pass to the next handler
res.status(401).json({ error: "missing or bad API key" });
}
app.get("/books/latest", (req, res) => res.json(books.at(-1))); // before /books/:id
app.route("/books")
.get((req, res) => res.json(books))
.post(requireApiKey, (req, res) => res.status(201).json({ created: true }))
.all((req, res) => res.set("Allow", "GET, POST").status(405).end());
app.get(["/", "/home"], (req, res) => res.send("Welcome"));
app.listen(3000);
// curl -X POST localhost:3000/books -> 401
// curl -X DELETE localhost:3000/books -> 405Remember
- Routes match in registration order — specific before general
app.route(path)chains several methods on one path- A route can have several handlers linked with
next()
Watch out for
- Declaring
/users/:idbefore/users/me, someis captured as an id.