Backend Node.js Course · Level 2
Routing in Express
On this page
1. Route params and route declaration order
/users/:idmatches any value at that path position and binds it toreq.params.idas a string. For example, onGET /users/5,req.params.id === '5'.- Express matches routes in the exact order of declaration, from top to bottom, executing the first matching route without prioritizing "more specific" routes automatically.
- Common bug: declaring
/users/:idbefore/users/mecausesGET /users/meto be swallowed by/users/:id(mistakenly invoking the get-user-by-id handler withid = 'me'), meaning/users/meis never reached. - Fix: specific routes must be declared before generalized parameterized routes:
js
app.get('/users/me', getCurrentUser);
app.get('/users/:id', getUserById);
2. Query string
req.querycontains the parsed query string as an object. For example, onGET /orders?status=pending&limit=10,req.query.status === 'pending'andreq.query.limit === '10'.- All values in
req.queryare strings, even if they look like numbers. Express does not infer data types because query strings are fundamentally plain text in the URL. - To treat them as numbers or booleans, you must explicitly convert them (
Number(req.query.limit),parseInt(), etc.). Common mistake: comparingreq.query.limit === 10always evaluates tofalsedue to comparing a string with a number.
3. Wildcard
- Routes using
/files/*match any subpath following the prefix, regardless of folder depth (/files/images/logo.png,/files/docs/a/b/c.pdf). - Common use case: serving static files with nested directory structures whose depths are unknown in advance.
- Another use case: catch-all 404 handler route, placed at the very bottom of the entire route list (applying the principle that "generalized routes go after specific routes"):
js
app.use('/api', apiRoutes);
app.use('/*', (req, res) => {
res.status(404).json({ error: 'Not found' });
});
4. Router() to split routes across multiple files
- As a project grows, managing multiple resources with complex logic is easier to read, debug, and update by splitting routes across files based on resources.
express.Router()creates an isolated "mini Express app" to define dedicated routes and middleware, attached to the main app viaapp.use(prefix, router):
js
// routes/users.js
const router = require('express').Router();
router.get('/', getUsersHandler);
router.get('/:id', getUserByIdHandler);
router.post('/', createUserHandler);
module.exports = router;
// app.js
const usersRouter = require('./routes/users');
app.use('/users', usersRouter);
- Inside the sub-route file, there is no need to repeat the prefix (
/users) on every route, becauseapp.use('/users', usersRouter)attaches that prefix automatically; the sub-file only defines relative routes (/,/:id).
