# Routing and Routers

Course: [Express.js](https://www.devtutorials.ai/learn/expressjs) · Section: Requests and Routing
Source: https://www.devtutorials.ai/learn/expressjs/requests-routing/routing

> Route methods, parameters, query strings, the Express 5 path syntax, route order, handler chains, app.route, router files, router middleware, nested routers, mergeParams and router.param.

## Routing Introduction

**Routing and Routers** = deciding which code runs for each request.

- **Route** = a method + a path + a handler.
- `app.get("/menu", handler)` is one route.
- Express checks routes **from top to bottom**.
- The first route that matches runs.
- No match means a 404 answer.

**Simple lesson:** A route is a rule: "for this method and path, run this function".

### A Real-World Example

A school building has many rooms.

1. A sign at the gate says: Library, Room 1. Lab, Room 2.
2. A visitor reads the signs from top to bottom.
3. They walk to the first room that matches.
4. If no sign matches, they go back: "not found".

Routes are the signs. Express is the visitor reading them.

In this lesson, you will learn:

1. Route methods, paths and parameters.
2. The Express 5 path syntax: named wildcards and optional parts.
3. Query strings and safe value conversion.
4. Route order, handler chains, `next("route")` and `app.route()`.
5. How to move routes into files with `express.Router()`.
6. Router middleware, nested routers, `mergeParams` and `router.param`.

## Route Methods

- **app.get / post / put / patch / delete** = one route per HTTP method.
- **app.options / app.head** = rarely needed. Express handles both for you.
- **app.all(path, handler)** = matches every method on that path.
- Use `app.all` for things like "this path is closed for everyone".

**Simple lesson:** The method name you call is the HTTP method you answer.

## Route Paths

- **Static path** = fixed text, such as `/menu`.
- **Dynamic path** = has a **route parameter**, such as `/menu/:id`.
- **Route parameter** = a named part of the path. Its value lands in `req.params`.
- **Multiple parameters:** `/menu/:category/:id` gives two values.
- **Regular expression route:** `app.get(/^\/item-\d+$/, ...)` matches by pattern.

- `/menu/3` sets `req.params.id` to `"3"`.
- `/menu/snacks/12` sets both `category` and `id`.
- Regular expression groups land in `req.params[0]`, `req.params[1]` and so on.

**Simple lesson:** `:name` in a path catches that part of the URL into `req.params.name`.

## Express 5 Path Syntax

Express 5 changed how special paths are written.

- **Named wildcard:** `/*splat` matches any path. `req.params.splat` is an array of parts.
- **Optional part:** `{/:id}` means "this part may be missing".
- **Optional wildcard:** `/{*splat}` also matches the root `/`.
- **Reserved characters:** `( ) [ ] ? + !` are not allowed in paths. Express throws an error.
- **Old Express 4 code:** `"*"` becomes `"/*splat"`, and `"/:id?"` becomes `"{/:id}"`.

- `/files/notes/term1.pdf` gives the parts `["notes", "term1.pdf"]`.
- `/orders` and `/orders/9` use the same route.
- The last route catches everything else and sends a JSON 404.

A catch-all route must be the **last** route. Express reads top to bottom, so a catch-all at the top would answer every request.

**Simple lesson:** Express 5 wildcards need a name, and optional parts use braces.

## Query Strings

**Query string** = the `?name=value&name=value` part of a URL.

- Read it from `req.query`.
- Use it for options: search, filter, sort, page and limit.
- **Default value:** `req.query.sort || "name"`.
- **Repeated names:** `?tag=veg&tag=spicy` gives an array `["veg", "spicy"]`.
- **Missing name:** `req.query.page` is `undefined`.
- **Empty value:** `?page=` gives the empty string `""`.

### Converting Query Values

Every query value is a string, or an array of strings.

- **Numbers:** `Number(req.query.page)`. Check with `Number.isInteger`.
- **Booleans:** `req.query.veg === "true"`. The string `"false"` is truthy, so do not use it directly.
- **Arrays:** `[].concat(req.query.tag ?? [])` always gives an array.
- **Bad values:** fall back to a safe default, or answer 400.

- Try each quick request and compare the results.
- `page=abc` gives a clear 400, not a strange empty list.

Easy way to remember: **everything in `req.params` and `req.query` is text until you convert it.**

### Route Parameters or Query?

- **Route parameter:** names one thing. `/menu/7` is item 7.
- **Query:** shapes a list. `/menu?veg=true&sort=price`.
- If the URL makes no sense without the value, use a route parameter.
- If the value is optional, use the query.

**Simple lesson:** Convert query strings carefully, and always have a safe default.

## Route Order

- Express tries routes in the order you wrote them.
- Put **specific** routes before **general** ones.
- `/menu/today` must come before `/menu/:id`.
- Otherwise `:id` catches the word `"today"`.

- `/menu/today` answers "Item today". That is the bug.
- Move the `/menu/today` route above `/menu/:id` and run again.

The same rule applies to middleware and routers. Express always works through them in the order your code adds them. See **Middleware Fundamentals**.

**Simple lesson:** Specific first, general later, catch-all last.

## Multiple Handlers

A route can have more than one handler.

- Handlers run in order, like a short chain.
- Each one calls `next()` to pass to the next.
- You can pass functions one by one, or in an array, or both.
- **next("route")** = skip the rest of this route's handlers and try the next route.
- Call `next()` only once per handler.

- `/orders/5` runs all three handlers of the first route.
- `/orders/0` jumps to the second route with `next("route")`.

**Simple lesson:** Chain small handlers with `next()`. Jump to the next route with `next("route")`.

## app.route() and Reusable Handlers

**app.route(path)** = write one path, then chain its methods.

- Fewer repeated path strings, fewer typos.
- Related handlers stay together.
- Put handlers in their own file and import them.
- Named functions make error messages easier to read.

- `DELETE /orders` gives 404, because no delete handler was chained.
- Real projects group routes with a router. See the other part of this lesson.

**Simple lesson:** `app.route` keeps one path's methods together.

## Express Router

**Router** = a mini app that holds only routes and middleware.

- Create one with `express.Router()`.
- Add routes to it, just like `app.get` and `app.post`.
- Mount it with `app.use("/menu", menuRouter)`.
- A router has no settings and cannot `listen`.
- Big apps use one router per topic, such as menu, orders and students.

**Simple lesson:** A router is a box of related routes you plug into the app.

### A Second Example

A big school has one main office and many department desks.

1. The gate guard sends science questions to the science desk.
2. Sports questions go to the sports desk.
3. Each desk handles its own questions in its own way.
4. The guard only needs to know which desk is where.

`app` is the gate guard. Each router is a desk.

## Creating and Mounting a Router

- **express.Router()** = creates a router.
- **router.get(path, handler)** = adds a route to it.
- **export default router** = lets other files use it.
- **app.use("/menu", router)** = mounts it at `/menu`.
- **Mount path** = the path in front of every route in the router.

- Inside the router, paths do not repeat `/menu`.
- Change the mount to `app.use("/food", menuRouter)`. Now the routes move to `/food`.
- The router file never changed. That is the point.

**Simple lesson:** Write routes once in a router, and choose where they live with `app.use`.

## Router Methods and Options

- **router.get / post / put / patch / delete / all** = the same as on `app`.
- **router.use(fn)** = middleware for this router only.
- **router.route(path)** = chain methods on one path.
- **caseSensitive: true** = `/Menu` and `/menu` are different.
- **strict: true** = `/menu` and `/menu/` are different.
- **mergeParams: true** = lets a child router read the parent's params.

- Requests to `/orders` print a log line.
- `/menu` prints nothing, because it never enters the orders router.

**Simple lesson:** Router middleware only runs for that router's paths.

## Router-Level Middleware

**Router-level middleware** = middleware added with `router.use`.

- **For the whole router:** `router.use(fn)`.
- **For one path in it:** `router.use("/special", fn)`.
- **For one route:** `router.get("/", fn, handler)`.
- It runs in the order you add it, before the routes below it.
- Use it for things one area needs, such as a staff-only check.

Middleware gets its own lesson. See **Middleware Fundamentals**. For now, remember it is a function with `(req, res, next)` that runs before your routes.

**Simple lesson:** Put area-specific checks on the router, not on the whole app.

## Nested Routers and mergeParams

A router can be mounted inside another router.

- **Parent router:** `/menu/:id`.
- **Child router:** `/reviews`, mounted inside the parent.
- Full path: `/menu/:id/reviews`.
- By default, the child cannot see `:id`.
- Create the child with `express.Router({ mergeParams: true })` to fix this.

- With `mergeParams`, `itemId` is `"2"` or `"3"`.
- Without it, `itemId` becomes `"unknown"`.

Without `mergeParams`, the child router does not crash. It just sees `undefined`, which is easy to miss. Test nested routes with a real id.

**Simple lesson:** A child router needs `mergeParams: true` to read its parent's params.

## router.param and app.param

**router.param(name, callback)** = runs a function whenever a route uses `:name`.

- The callback gets `(req, res, next, value)`.
- Use it to load the thing the id points to.
- Answer 404 there if it does not exist.
- Every route with `:id` then gets a ready `req.item`.
- It runs once per request, even if many routes match.
- **app.param** does the same for routes on `app`. **router.param** only for routes on that router.

- Both routes use `req.item`, but the lookup code is written once.
- `/menu/99` stops in the param callback with a 404.

**Simple lesson:** Load once with `param`, then use the result in every route.

## Organising Router Files

- **One router per resource:** `routes/menu.js`, `routes/orders.js`, `routes/students.js`.
- **Name files after the resource,** in lowercase.
- **Keep handlers separate** when routers grow: `handlers/menu.js`.
- **Mount all routers in app.js,** so one file shows the whole map.
- **Prefix API routes:** `app.use("/api/menu", menuRouter)`.

```text
canteen-api/
├── routes/
│   ├── menu.js
│   └── orders.js
├── handlers/
│   └── menu.js
├── app.js
└── server.js
```

Easy way to remember: **routes/ says where, handlers/ says what.**

**Simple lesson:** One file per resource, all mounted in app.js.

## Common mistakes

<div className="tscroll">

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `/menu/:id` above `/menu/today` | Express picks the best match | Express picks the first match | `today` is read as an id |
| Catch-all route at the top | It only catches leftovers | It catches everything below it | Every request gets 404 |
| `app.get("*", ...)` in Express 5 | Old wildcards still work | Use `"/*splat"` | `TypeError: Missing parameter name` |
| `if (req.query.veg)` for `?veg=false` | `"false"` is false | Any non-empty string is truthy | Non-veg items are hidden |
| `req.query.page * limit` without checks | Query values are numbers | They are strings, maybe junk | `NaN` and empty pages |
| Calling `next()` twice | It is harmless | Two handlers run, two responses | `ERR_HTTP_HEADERS_SENT` |
| `router.get("/menu", ...)` mounted at `/menu` | Write the full path inside the router | Paths inside are relative to the mount | The route lives at `/menu/menu` |
| Forgetting `app.use(router)` | Creating a router is enough | It must be mounted | Every route gives 404 |
| No `mergeParams` on a child router | Child routers see all params | They only see their own | `req.params.id` is `undefined` |
| `import menu from "./routes/menu"` | Node.js adds `.js` | ES modules need the full name | `ERR_MODULE_NOT_FOUND` |
| Repeating the same lookup in every route | It is just a few lines | `router.param` does it once | Bugs when one copy changes |

</div>

## Check Yourself

## Exercises

## What to Remember

- A route is a method, a path and a handler. The first match wins.
- `:name` captures path parts into `req.params`, always as strings.
- Express 5 uses `/*splat` for wildcards and `{/:id}` for optional parts.
- Query values are strings. Convert them and give safe defaults.
- Specific routes first, catch-all last.
- `express.Router()` makes a mini app for related routes.
- Mount it with `app.use(path, router)`. Paths inside are relative.
- Child routers need `mergeParams: true` to read parent params.
- `router.param` loads data once for every route with that param.

Next: **Middleware Fundamentals**. You will learn the `(req, res, next)` functions that run before your routes.
