Express: Router и модуляризация
express.Router — это мини-приложение Express, которое позволяет разбить маршруты на отдельные модули и подключать их к основному приложению через app.use.
Зачем нужно
В монолитном app.js с десятками маршрутов код быстро становится неуправляемым. express.Router позволяет группировать маршруты по ресурсам (users, products, orders) в отдельные файлы, сохраняя SRP (Single Responsibility Principle). Каждый роутер монтируется на свой префикс и может иметь собственный middleware-стек.
Где используется
- REST API с несколькими ресурсами (
/api/users,/api/products,/api/orders) - Версионирование API (
/api/v1/...,/api/v2/...) - Разделение публичных и приватных маршрутов (публичные без auth, приватные — с)
- Большие монорепозитории, где каждый модуль экспортирует свой Router
Основной контент
Структура проекта
src/
app.js
routes/
users.js
products.js
index.js ← точка сборки всех роутеров
Создание роутера
// routes/users.js
const express = require('express');
const router = express.Router;
// GET /api/users
router.get('/', async (req, res) => {
const users = await UserService.getAll;
res.json(users);
});
// GET /api/users/:id
router.get('/:id', async (req, res) => {
const user = await UserService.getById(req.params.id);
if (!user) return res.status(404).json({ error: 'Not found' });
res.json(user);
});
// POST /api/users
router.post('/', async (req, res) => {
const user = await UserService.create(req.body);
res.status(201).json(user);
});
module.exports = router;
Точка сборки роутеров
// routes/index.js
const express = require('express');
const router = express.Router;
router.use('/users', require('./users'));
router.use('/products', require('./products'));
module.exports = router;
Подключение к приложению
// app.js
const express = require('express');
const app = express;
app.use(express.json());
app.use('/api', require('./routes'));
app.listen(3000, () => console.log('Server on port 3000'));
Middleware на уровне роутера
// Применяется только к маршрутам этого роутера
router.use(authMiddleware);
// Или для конкретного маршрута
router.get('/profile', authMiddleware, (req, res) => {
res.json(req.user);
});
Router.param — перехват параметров
// Выполняется при наличии :userId в маршруте
router.param('userId', async (req, res, next, id) => {
req.user = await UserService.getById(id);
if (!req.user) return res.status(404).json({ error: 'User not found' });
next;
});
router.get('/:userId', (req, res) => res.json(req.user));
router.delete('/:userId', (req, res) => { /* req.user уже есть */ });
Частые ошибки
- Забыть
nextв middleware — запрос зависает, ответ не отправляется - Монтировать роутер без префикса —
app.use(router)вместоapp.use('/api', router), маршруты перекрываются - Повторять префикс внутри роутера — если роутер смонтирован на
/api/users, не нужно писать/api/users/:idвнутри него, только/:id - Импортировать
routerв неправильном порядке — если middleware (express.json) подключён после роутера,req.bodyбудет пустым