Router и маршруты в отдельных файлах
Когда все маршруты лежат в src/app.js, файл быстро разрастается. express.Router — это мини-приложение, в котором можно описать группу маршрутов в отдельном файле, а потом подключить её к основному приложению под общим адресом.
Файл маршрутов
Создайте файл src/routes/posts.js:
// src/routes/posts.js
import { Router } from 'express';
const router = Router();
router.get('/', (req, res) => {
res.send('Список статей');
});
router.get('/:id', (req, res) => {
res.send(`Статья ${req.params.id}`);
});
export default router;Методы у роутера те же, что у приложения: get, post, delete и другие. Адреса здесь пишутся относительно места подключения.
Подключение
В src/app.js импортируйте роутер и подключите его через app.use():
// src/app.js
import express from 'express';
import postsRouter from './routes/posts.js';
const app = express();
app.use('/posts', postsRouter);
export default app;Теперь /posts вызовет маршрут '/' роутера, а /posts/2 — маршрут '/:id'. Если раздел переедет на /articles, достаточно поменять одну строку в app.js.
Контроллеры
Чтобы файл маршрутов оставался коротким списком адресов, сами обработчики выносят в контроллер. Создайте src/controllers/postsController.js:
// src/controllers/postsController.js
import { posts } from '../data/posts.js';
export function index(req, res) {
res.send(posts.map((post) => post.title).join(', '));
}
export function show(req, res) {
const post = posts.find((item) => item.id === Number(req.params.id));
if (!post) {
return res.status(404).send('Статья не найдена');
}
res.send(post.title);
}И замените функции в роутере ссылками на них:
// src/routes/posts.js
import { Router } from 'express';
import * as postsController from '../controllers/postsController.js';
const router = Router();
router.get('/', postsController.index);
router.get('/:id', postsController.show);
export default router;Страницы /posts и /posts/1 работают как прежде, но теперь с первого взгляда на routes/posts.js видно все адреса раздела.
Параметры родителя
Если роутер подключён по адресу с параметром, например '/posts/:postId/comments', по умолчанию он не видит postId. Опция mergeParams передаёт параметры родителя:
// src/routes/comments.js
import { Router } from 'express';
const router = Router({ mergeParams: true });
router.get('/', (req, res) => {
res.send(`Комментарии к статье ${req.params.postId}`);
});
export default router;В app.js его подключают так: app.use('/posts/:postId/comments', commentsRouter).
Частая ошибка
Внутри роутера адрес не повторяют. Если написать router.get('/posts/:id') и подключить роутер через app.use('/posts', ...), маршрут будет доступен только по /posts/posts/2. Общая часть адреса указывается один раз — в app.use().