BugForge
All lessons
Node.js · 14/19 6 min

Express routing traps

Route order, params vs literals, Router mount paths, and middleware that runs for the wrong routes.

First match wins

router.get("/:id", getOne);       // ❌ "/stats" is captured as id = "stats"
router.get("/stats", getStats);   //    never reached

router.get("/stats", getStats);   // ✅ literals before params
router.get("/:id", getOne);

Mount paths are stripped

app.use("/api/orders", ordersRouter);
// inside ordersRouter the path is relative:
router.get("/", list);            // GET /api/orders
router.get("/orders", list);      // ❌ this is /api/orders/orders

A 404 from a test that "obviously" has a route is almost always a doubled or missing prefix.

Params

  • req.params.id is a string. Compare with === against a number and it never matches.
  • Param names must match: /:userId is req.params.userId, not req.params.id.
  • A Router that needs the parent's params needs express.Router({ mergeParams: true }).

Middleware scope

app.use(requireAuth);                 // every route BELOW this line, including public ones
app.post("/login", login);            // ❌ now login needs a token

app.post("/login", login);            // ✅ public routes first
app.use("/api", requireAuth, api);    // or scope it to a mount

Methods

  • app.get won't answer a POST. A 404 on the right path often means the wrong verb.
  • PUT replaces, PATCH updates fields. Tests for PATCH expect untouched fields to survive.
  • DELETE that succeeds with no body is 204; don't call res.json after res.status(204).

Order inside app.js

  1. body parsers (express.json()), CORS, logging
  2. public routes
  3. auth, then protected routes
  4. 404 handler
  5. error handler (four arguments)
Next in Node.js
Config and environment variables