Routing & Parameters
Checking access...
Routing determines how an application responds to client requests for specific endpoints (URIs) and HTTP methods.
Route Methods
Express supports all HTTP methods:
const express = require("express");const app = express();
app.get("/resource", (req, res) => { res.send("GET — retrieve resource");});
app.post("/resource", (req, res) => { res.send("POST — create resource");});
app.put("/resource/:id", (req, res) => { res.send(`PUT — replace resource ${req.params.id}`);});
app.patch("/resource/:id", (req, res) => { res.send(`PATCH — partial update ${req.params.id}`);});
app.delete("/resource/:id", (req, res) => { res.send(`DELETE — remove resource ${req.params.id}`);});Method Chaining
Chain multiple methods on the same path:
app.route("/api/items") .get((req, res) => { res.json([{ id: 1, name: "Item 1" }]); }) .post((req, res) => { const item = { id: Date.now(), ...req.body }; res.status(201).json(item); }) .put((req, res) => { res.json({ message: "Replace all items" }); }) .delete((req, res) => { res.json({ message: "Delete all items" }); });Route Parameters
Named segments in the URL path, prefixed with ::
// Single parameterapp.get("/users/:userId", (req, res) => { res.json({ userId: req.params.userId });});
// Multiple parametersapp.get("/users/:userId/posts/:postId", (req, res) => { res.json({ userId: req.params.userId, postId: req.params.postId, });});
// Optional parameter (use ?)app.get("/products/:category?/:id?", (req, res) => { // /products → category=undefined, id=undefined // /products/books → category="books", id=undefined // /products/books/5 → category="books", id="5" res.json(req.params);});Parameter Validation
Use regex patterns in route parameters:
// Only match numeric IDsapp.get("/users/:id(\\d+)", (req, res) => { // Matches /users/123 but NOT /users/abc res.json({ id: parseInt(req.params.id) });});
// Match specific string patternsapp.get("/files/:type(pdf|jpg|png)/:name", (req, res) => { // Matches /files/pdf/report but NOT /files/doc/report res.json({ type: req.params.type, name: req.params.name });});Query Parameters
Data appended to the URL after ?:
// URL: /api/users?role=admin&page=2&sort=nameapp.get("/api/users", (req, res) => { const { role, page = "1", sort = "createdAt", limit = "10" } = req.query;
res.json({ filters: { role }, pagination: { page: parseInt(page), limit: parseInt(limit), }, sort, });});
// Array query params: /api/users?roles=admin&roles=editorapp.get("/api/users/roles", (req, res) => { const roles = req.query.roles; // "admin" (single) or ["admin", "editor"] (multiple) const roleArray = Array.isArray(roles) ? roles : [roles];
res.json({ roles: roleArray });});Modular Routers
Split routes into separate files using express.Router():
const router = require("express").Router();
// Middleware specific to this routerrouter.use((req, res, next) => { console.log(`[Users] ${req.method} ${req.path}`); next();});
router.get("/", (req, res) => { res.json([{ id: 1, name: "Alice" }]);});
router.get("/:id", (req, res) => { res.json({ id: req.params.id, name: "Alice" });});
module.exports = router;const router = require("express").Router();
router.get("/", (req, res) => { res.json([{ id: 1, product: "Widget" }]);});
router.get("/:id", (req, res) => { res.json({ id: req.params.id, product: "Widget" });});
module.exports = router;const express = require("express");const app = express();
app.use("/api/users", require("./routes/users"));app.use("/api/products", require("./routes/products"));
// The router paths are PREFIXED:// GET /api/users// GET /api/users/:id// GET /api/products// GET /api/products/:idRoute Groups with Prefix
const router = require("express").Router();
// All routes have /v1 prefixapp.use("/v1", router);
router.get("/users", (req, res) => { /* ... */ }); // GET /v1/usersrouter.get("/posts", (req, res) => { /* ... */ }); // GET /v1/postsrouter.post("/users", (req, res) => { /* ... */ }); // POST /v1/users
// Multiple versionsconst v1Router = require("./routes/v1");const v2Router = require("./routes/v2");
app.use("/api/v1", v1Router);app.use("/api/v2", v2Router);Wildcard Routes
// Catch-all for a segmentapp.get("/users/*", (req, res) => { // Matches /users/anything/here res.json({ path: req.path });});
// 404 handler (must be last)app.use("*", (req, res) => { res.status(404).json({ error: "Not Found", message: `Route ${req.method} ${req.originalUrl} not found`, });});Route Listing with express-list-endpoints
npm install express-list-endpointsconst listEndpoints = require("express-list-endpoints");
app.listen(3000, () => { console.log("Available routes:"); console.table(listEndpoints(app));});
// Output:// ┌─────────┬──────────┬──────────────────┐// │ (index) │ methods │ path │// ├─────────┼──────────┼──────────────────┤// │ 0 │ ['GET'] │ '/api/users' │// │ 1 │ ['POST'] │ '/api/users' │// │ 2 │ ['GET'] │ '/api/users/:id' │// └─────────┴──────────┴──────────────────┘Quick Reference
// Route patternsapp.get("/path", handler); // staticapp.get("/:param", handler); // parameterapp.get("/:id(\\d+)", handler); // parameter with regexapp.get("/path?", handler); // optional segmentapp.get("/*", handler); // wildcard (catch-all)
// Multiple handlersapp.get("/path", handler1, handler2);
// Routerconst router = express.Router();router.get("/", handler);app.use("/prefix", router);
// Chainingapp.route("/path").get(handler).post(handler);Practice Exercises
RESTful task routes: Create a router for
/api/taskswithGET /,GET /:id,POST /,PUT /:id, andDELETE /:id. Use query parameters for filtering (by status) and pagination (page, limit).Nested routing: Create
/api/users/:userId/postsand/api/users/:userId/posts/:postId/comments. Each should use Express Router and have full CRUD.API versioning: Set up two route versions —
/api/v1and/api/v2. V1 returns data in one format, V2 in an enhanced format. Both should use modular routers.