Маршрутизация в Express: пути, параметры, роутеры
Содержание
О проверке кода. Примеры не запускались в этой сессии (по договорённости — фокус на контенте, а не прогонах). Говорим прямо, а не ставим бейдж «проверено».
Маршрутизация — то, как Express решает, какой код запустить на конкретный запрос. По мере роста приложения грамотная организация маршрутов становится критичной. Разберём от простого к структурированному.
Методы и пути
app.get('/products', handler); // получить список
app.post('/products', handler); // создать
app.put('/products/:id', handler); // заменить целиком
app.patch('/products/:id', handler);// изменить частично
app.delete('/products/:id', handler);// удалить
Маршрут — это пара «метод HTTP + путь». Один и тот же путь /products/:id с разными методами (GET, PUT, DELETE) — это разные маршруты с разной логикой. Так строится REST API: метод выражает действие, путь — ресурс.
Параметры пути и строка запроса
Два способа передать данные в URL — их путают:
// параметр пути — /users/:id
app.get('/users/:id', (req, res) => {
req.params.id; // '42' из /users/42 — обязательная часть маршрута
});
// несколько параметров
app.get('/users/:userId/orders/:orderId', (req, res) => {
req.params.userId; // '42'
req.params.orderId; // '7'
});
// строка запроса — ?sort=name&page=2
app.get('/products', (req, res) => {
req.query.sort; // 'name' — необязательный фильтр/сортировка
req.query.page; // '2'
});
Параметр пути /:id
req.params
- Часть самого маршрута
- Обязателен — определяет ресурс
/users/42→ id = 42- Для идентификации: какой пользователь
Строка запроса ?x=y
req.query
- После знака вопроса
- Обычно необязательна
?sort=name&page=2- Для фильтров, сортировки, пагинации
Параметр пути идентифицирует ресурс (какой именно пользователь) и обязателен. Строка запроса задаёт опции (как отсортировать, какая страница) и обычно необязательна. Значения всегда строки — число страницы приводите через Number. Разбор строки запроса Express берёт на себя (под капотом — URLSearchParams).
Разбиение на модули: express.Router
Держать все маршруты в одном файле — путь к хаосу. Router разбивает их на модули:
// routes/users.js — отдельный файл маршрутов пользователей
const router = express.Router();
router.get('/', (req, res) => { /* GET /users */ });
router.get('/:id', (req, res) => { /* GET /users/:id */ });
router.post('/', (req, res) => { /* POST /users */ });
module.exports = router;
// app.js — подключаем модуль по префиксу
const usersRouter = require('./routes/users');
app.use('/users', usersRouter); // все маршруты внутри — с префиксом /users
express.Router — это мини-приложение со своими маршрутами, которое подключают к основному по префиксу. Маршруты пользователей, заказов, товаров живут в отдельных файлах, а app.use('/users', usersRouter) даёт им общий префикс. Это стандартная структура любого нетривиального Express-приложения — иначе один файл раздувается до тысяч строк.
Порядок маршрутов важен
// ❌ НЕВЕРНЫЙ порядок
app.get('/users/:id', handler); // этот поймает и /users/new!
app.get('/users/new', showForm); // сюда никогда не дойдёт
// ✅ конкретное — выше общего
app.get('/users/new', showForm); // сначала конкретный путь
app.get('/users/:id', handler); // потом параметрический
Express проверяет маршруты сверху вниз и берёт ПЕРВЫЙ совпавший. Поэтому /users/:id, стоящий выше /users/new, перехватит /users/new (посчитав new за :id), и до конкретного маршрута дело не дойдёт. Правило: конкретные пути — выше параметрических. Это неочевидная, но частая причина «маршрут не работает».
Обработка несуществующих путей (404)
// ... все маршруты выше ...
// в САМОМ КОНЦЕ — ловит всё, что не совпало
app.use((req, res) => {
res.status(404).json({ error: 'Не найдено' });
});
Обработчик без пути в самом конце ловит всё несовпавшее и возвращает 404. Критично, что он стоит после всех маршрутов — иначе перехватит запросы, которые должны были дойти до реальных обработчиков. Это следствие того же правила порядка: 404-обработчик — последний рубеж.
Практика организации
- группируйте по ресурсам —
routes/users.js,routes/orders.js, каждый со своимRouter; - конкретные маршруты выше параметрических — избегаете перехвата;
- 404-обработчик — последним, обработчик ошибок — самым последним;
- префиксы через
app.use('/api', ...)— версионирование API (/api/v1) делается одной строкой.
Хорошая маршрутизация делает приложение читаемым: по структуре файлов видно, какие ресурсы есть и что с ними можно делать.
Смежные темы: Express с нуля — основы; middleware — общая логика для маршрутов; REST API; строка запроса. Полный список — в уроках Node.js.