Using Express Router
1. Creating Router Instance
| Option | Default | Purpose |
|---|---|---|
caseSensitive | false | Treat /Foo ≠ /foo |
mergeParams | false | Inherit parent route params |
strict | false | Treat /foo ≠ /foo/ |
Example: Router with mergeParams
import { Router } from "express";
const router = Router({ mergeParams: true, strict: true });
// In sub-router mounted at /users/:userId — req.params.userId now visible
2. Defining Router-Level Routes
| API | Description |
|---|---|
router.get/post/put/patch/delete() | HTTP method routes |
router.all() | All methods |
router.use() | Middleware (any method) |
router.route(path) | Chainable verbs |
3. Mounting Routers
Example: Versioned mounting
app.use("/api/v1", v1Router);
app.use("/api/v2", v2Router);
app.use("/admin", requireAdmin, adminRouter);
| Form | Behavior |
|---|---|
app.use(router) | Mount at root |
app.use(prefix, router) | Strip prefix from req.url inside router |
app.use(prefix, mw, router) | Run middleware before router |
4. Using Router Middleware
Example: Scoped auth
const router = Router();
router.use(requireAuth); // applies to ALL routes below
router.get("/me", getProfile);
router.put("/me", updateProfile);
| Scope | API |
|---|---|
| App-wide | app.use(mw) |
| Router-wide | router.use(mw) |
| Path-specific | router.use("/admin", mw) |
| Per-route | Inline before handler |
5. Implementing Nested Routers
Example: Posts under users
const postsRouter = Router({ mergeParams: true });
postsRouter.get("/", (req, res) => {
// Access parent param thanks to mergeParams
res.json({ userId: req.params.userId });
});
const usersRouter = Router();
usersRouter.use("/:userId/posts", postsRouter);
app.use("/users", usersRouter);
// GET /users/42/posts → { userId: "42" }
| Requirement | Detail |
|---|---|
mergeParams: true | Required to read parent :params |
| Order | Define inner router before mounting |
6. Using Router Parameters
Example: param() prefetch
router.param("id", async (req, res, next, id) => {
try {
const user = await db.users.findById(id);
if (!user) return res.sendStatus(404);
req.user = user;
next();
} catch (err) { next(err); }
});
router.get("/users/:id", (req, res) => res.json(req.user));
| Trigger | Behavior |
|---|---|
| Param appears in URL | Callback runs before route handler |
| Multiple params | Each param() runs once per request |
7. Organizing Routes by Resource
src/
├── routes/
│ ├── index.js ← mounts all routers
│ ├── users.routes.js
│ ├── posts.routes.js
│ └── auth.routes.js
├── controllers/
│ ├── users.controller.js
│ └── posts.controller.js
└── services/
└── users.service.js
| Layer | Responsibility |
|---|---|
| Route | Path + method + middleware → controller |
| Controller | HTTP-aware: parse req, format res |
| Service | Business logic, DB access |
8. Creating Route Prefixes
Example: API versioning prefix
const apiV1 = Router();
apiV1.use("/users", usersRouter);
apiV1.use("/posts", postsRouter);
app.use("/api/v1", apiV1);
// → /api/v1/users, /api/v1/posts
| Prefix Convention | Use |
|---|---|
/api/v1 | REST API versioning |
/admin | Admin-only routes |
/auth | Authentication endpoints |
/internal | Internal microservice calls |
9. Exporting Router Modules
| Style | Syntax |
|---|---|
| ESM default | export default router + import router from "..." |
| ESM named | export { router } |
| CommonJS | module.exports = router |
| Factory | export const createRouter = (deps) => { ... } |
Example: Dependency-injected router
export function createUsersRouter({ usersService }) {
const router = Router();
router.get("/", async (req, res) => res.json(await usersService.list()));
return router;
}
10. Handling Router-Level Errors
Example: Per-router error handler
const router = Router();
router.get("/", asyncHandler(listUsers));
// Router-scoped error handler — catches only errors from this router
router.use((err, req, res, next) => {
if (err.code === "USER_NOT_FOUND") return res.status(404).json({ error: err.message });
next(err); // delegate to global handler
});
| Pattern | When |
|---|---|
| Global handler | Standard error formatting |
| Router handler | Domain-specific errors (e.g., 404 per resource) |