Express Routing
Routing determines how an application responds to client requests at specific endpoints. Express provides a full-featured routing system that supports route parameters, query strings, route-level middleware, and modular Router instances for organizing large APIs.
Basic Routing & HTTP Methods
// HTTP method handlers
app.get('/api/users', (req, res) => { /* ... */ });
app.post('/api/users', (req, res) => { /* ... */ });
app.put('/api/users/:id', (req, res) => { /* ... */ });
app.patch('/api/users/:id', (req, res) => { /* ... */ });
app.delete('/api/users/:id', (req, res) => { /* ... */ });
app.options('/api/users', (req, res) => { /* ... */ });
// Handle all HTTP methods
app.all('/api/users', (req, res) => {
res.json({ method: req.method });
});
// Chained route handlers for the same path
app.route('/api/users/:id')
.get((req, res) => {
res.json({ id: req.params.id });
})
.put((req, res) => {
res.json({ updated: req.params.id });
})
.delete((req, res) => {
res.status(204).end();
});
// Multiple handlers per route (middleware chain)
app.get('/api/data', authenticate, authorize('read'), (req, res) => {
res.json({ data: 'secret' });
});Route Parameters & Query Strings
// Route parameters - :param in path
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
// GET /users/42/posts/7 => { userId: '42', postId: '7' }
res.json({ userId, postId });
});
// Optional parameter
app.get('/users/:userId/profile/:section?', (req, res) => {
const section = req.params.section || 'overview';
res.json({ section });
});
// Query strings
app.get('/api/products', (req, res) => {
const {
search = '',
category,
page = '1',
limit = '20',
sortBy = 'name',
order = 'asc',
} = req.query;
// GET /api/products?search=laptop&category=tech&page=2
const pageNum = parseInt(page, 10);
const limitNum = parseInt(limit, 10);
const offset = (pageNum - 1) * limitNum;
res.json({ search, category, pageNum, limitNum, offset, sortBy, order });
});
// Route parameter middleware (runs before any route with :userId)
app.param('userId', async (req, res, next, id) => {
try {
const user = await User.findById(id);
if (!user) return res.status(404).json({ error: 'User not found' });
req.user = user; // Attach to req for route handlers
next();
} catch (err) {
next(err);
}
});Express Router - Modular Routes
Use express.Router() to create modular route handlers. Each router is a mini Express application with its own middleware and routing. Mount routers at a path prefix in your main app.
// routes/users.js
const express = require('express');
const router = express.Router();
const { authenticate } = require('../middleware/auth');
const usersController = require('../controllers/usersController');
// Router-level middleware (applies to all routes in this file)
router.use(authenticate);
// Routes (paths are relative to the mount point)
router.get('/', usersController.list); // GET /api/users
router.post('/', usersController.create); // POST /api/users
router.get('/:id', usersController.getById); // GET /api/users/:id
router.put('/:id', usersController.update); // PUT /api/users/:id
router.delete('/:id', usersController.remove); // DELETE /api/users/:id
module.exports = router;
// app.js - mount the router
const usersRouter = require('./routes/users');
app.use('/api/users', usersRouter);
// Nest routers
const v1Router = express.Router();
v1Router.use('/users', usersRouter);
v1Router.use('/products', productsRouter);
app.use('/api/v1', v1Router);RESTful API Pattern
// controllers/usersController.js - RESTful controller
const User = require('../models/User');
exports.list = async (req, res, next) => {
try {
const users = await User.findAll();
res.json({ data: users, total: users.length });
} catch (err) { next(err); }
};
exports.create = async (req, res, next) => {
try {
const user = await User.create(req.body);
res.status(201).json({ data: user });
} catch (err) { next(err); }
};
exports.getById = async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json({ data: user });
} catch (err) { next(err); }
};
exports.update = async (req, res, next) => {
try {
const user = await User.findByIdAndUpdate(req.params.id, req.body);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json({ data: user });
} catch (err) { next(err); }
};
exports.remove = async (req, res, next) => {
try {
await User.findByIdAndDelete(req.params.id);
res.status(204).end();
} catch (err) { next(err); }
};Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free