Working with Route Parameters

1. Defining URL Parameters

PathExample URLCaptures
/users/:id/users/42id="42"
/u/:id([0-9]+)/u/42 (numeric only)id="42"
/files/:name.:ext/files/photo.jpgname, ext
/posts/:slug-:id/posts/hello-42slug, id

2. Accessing Parameters

Example: Reading params

app.get("/users/:id", (req, res) => {
  const id = req.params.id;        // string
  const numericId = Number(id);    // coerce
  res.json({ id: numericId });
});
PropertyType
req.paramsObject (always strings)
req.params.idString

3. Using Multiple Parameters

Example: Nested resources

app.get("/categories/:cat/products/:id", (req, res) => {
  const { cat, id } = req.params;
  res.json({ category: cat, productId: id });
});
PatternResult
/:a/:bTwo separate path segments
/:a-:bSame segment, hyphen separator

4. Validating Parameters

Example: Inline guard + express-validator

import { param, validationResult } from "express-validator";

app.get("/users/:id",
  param("id").isUUID().withMessage("Invalid UUID"),
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) return res.status(400).json({ errors: errors.array() });
    res.json({ id: req.params.id });
  }
);
StrategyLibrary
Regex in pathBuilt-in (:id(\\d+))
Validator middlewareexpress-validator, zod
Custom guardPlain function before handler

5. Making Parameters Optional

Example: Optional segment

// Express 4
app.get("/users/:id?", (req, res) => {
  if (req.params.id) return res.json(getUser(req.params.id));
  res.json(listUsers());
});

// Express 5 — optional groups via {}
app.get("/users{/:id}", handler);
SyntaxExpress 4Express 5
Optional:id?{:id}
Wildcard*{*splat}

6. Using param() Middleware

Example: Centralized lookup

app.param("userId", async (req, res, next, id) => {
  const user = await db.users.findById(id);
  if (!user) return res.sendStatus(404);
  req.user = user;
  next();
});

app.get("/users/:userId", (req, res) => res.json(req.user));
app.put("/users/:userId", (req, res) => updateUser(req.user, req.body));
BehaviorDetail
One per requestCached even if param appears in multiple routes
Per-routerUse router.param() for scoped lookups

7. Pre-processing Parameters

Example: Coerce + normalize

app.param("id", (req, res, next, raw) => {
  const id = Number(raw);
  if (!Number.isInteger(id) || id <= 0) return res.status(400).json({ error: "Invalid id" });
  req.id = id;  // attach typed value
  next();
});

8. Converting Parameter Types

TargetConversion
IntegerparseInt(p, 10) or Number(p)
FloatparseFloat(p)
Booleanp === "true"
Datenew Date(p) + isNaN() check
UUIDValidate against regex
Arrayp.split(",")

9. Handling Invalid Parameters

Example: 400 vs 404

app.get("/users/:id", async (req, res) => {
  const id = Number(req.params.id);
  if (!Number.isInteger(id)) return res.status(400).json({ error: "id must be integer" });
  const user = await db.users.findById(id);
  if (!user) return res.status(404).json({ error: "User not found" });
  res.json(user);
});
StatusWhen
400 Bad RequestParam fails validation (wrong type/format)
404 Not FoundValid format but resource missing
422 UnprocessableSemantic validation failure

10. Using Wildcard Parameters

Example: Catch-all

// Express 4
app.get("/files/*", (req, res) => {
  const path = req.params[0];  // anything after /files/
  res.sendFile(path, { root: "uploads" });
});

// Express 5 named wildcard
app.get("/files/{*splat}", (req, res) => {
  const segments = req.params.splat;  // array
  res.json({ segments });
});
SyntaxCaptured As
* (Express 4)req.params[0] (string)
{*splat} (Express 5)req.params.splat (array)
{*splat}?Optional wildcard
Warning: Always sanitize wildcard params used in file paths to prevent directory traversal (../).