Node.jsМодуль 4: HTTP и Express
Маршрутизация
Параметры, query strings, Router
Цель урока
В этом уроке ты научишься:
- Работать с параметрами маршрутов
- Использовать query параметры
- Организовывать маршруты с Router
Параметры маршрутов
Базовые параметры
// /users/123
app.get('/users/:id', (req, res) => {
const userId = req.params.id; // '123'
res.json({ userId });
});
// /users/123/posts/456
app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params;
res.json({ userId, postId });
});Опциональные параметры
// /posts или /posts/123
app.get('/posts/:id?', (req, res) => {
if (req.params.id) {
res.json({ post: req.params.id });
} else {
res.json({ posts: [] });
}
});Регулярные выражения
// Только числа
app.get('/users/:id(\\d+)', (req, res) => {
res.json({ id: parseInt(req.params.id) });
});
// Любой путь
app.get('/files/*', (req, res) => {
res.json({ path: req.params[0] });
});Query параметры
// /search?q=node&page=1&limit=10
app.get('/search', (req, res) => {
const { q, page = 1, limit = 10 } = req.query;
res.json({
query: q,
page: parseInt(page),
limit: parseInt(limit)
});
});
// /filter?tags=js&tags=node
app.get('/filter', (req, res) => {
const tags = req.query.tags; // ['js', 'node'] или 'js'
// Гарантируем массив
const tagsArray = Array.isArray(tags) ? tags : [tags].filter(Boolean);
res.json({ tags: tagsArray });
});Express Router
Создание роутера
// routes/users.js
const express = require('express');
const router = express.Router();
// Все маршруты относительно /api/users
router.get('/', (req, res) => {
res.json([]);
});
router.get('/:id', (req, res) => {
res.json({ id: req.params.id });
});
router.post('/', (req, res) => {
res.status(201).json(req.body);
});
router.put('/:id', (req, res) => {
res.json({ id: req.params.id, ...req.body });
});
router.delete('/:id', (req, res) => {
res.status(204).send();
});
module.exports = router;Подключение роутера
// app.js
const express = require('express');
const usersRouter = require('./routes/users');
const postsRouter = require('./routes/posts');
const app = express();
app.use(express.json());
app.use('/api/users', usersRouter);
app.use('/api/posts', postsRouter);Вложенные роутеры
// routes/users.js
const express = require('express');
const router = express.Router();
const postsRouter = require('./userPosts');
router.get('/', (req, res) => res.json([]));
router.get('/:id', (req, res) => res.json({ id: req.params.id }));
// Вложенный роутер: /api/users/:userId/posts
router.use('/:userId/posts', postsRouter);
module.exports = router;
// routes/userPosts.js
const express = require('express');
const router = express.Router({ mergeParams: true }); // Важно!
router.get('/', (req, res) => {
const { userId } = req.params;
res.json({ userId, posts: [] });
});
module.exports = router;Middleware для роутера
const router = express.Router();
// Middleware для всех маршрутов роутера
router.use((req, res, next) => {
console.log('Запрос к users API');
next();
});
// Middleware для конкретного маршрута
router.get('/:id',
validateId, // Middleware 1
checkPermission, // Middleware 2
(req, res) => { // Handler
res.json({ id: req.params.id });
}
);
function validateId(req, res, next) {
const id = parseInt(req.params.id);
if (isNaN(id)) {
return res.status(400).json({ error: 'Invalid ID' });
}
req.userId = id;
next();
}
function checkPermission(req, res, next) {
// Проверка прав
next();
}route() метод
// Группировка методов для одного пути
router.route('/:id')
.get((req, res) => {
res.json({ id: req.params.id });
})
.put((req, res) => {
res.json({ id: req.params.id, ...req.body });
})
.delete((req, res) => {
res.status(204).send();
});Практика
Задание 1: API с роутером
Задача: Создай роутер для продуктов с CRUD операциями.
Решение:
// routes/products.js
const express = require('express');
const router = express.Router();
let products = [];
let nextId = 1;
router.get('/', (req, res) => {
const { category, minPrice, maxPrice } = req.query;
let result = products;
if (category) {
result = result.filter(p => p.category === category);
}
if (minPrice) {
result = result.filter(p => p.price >= parseFloat(minPrice));
}
if (maxPrice) {
result = result.filter(p => p.price <= parseFloat(maxPrice));
}
res.json(result);
});
router.get('/:id', (req, res) => {
const product = products.find(p => p.id === parseInt(req.params.id));
if (!product) return res.status(404).json({ error: 'Not found' });
res.json(product);
});
router.post('/', (req, res) => {
const product = { id: nextId++, ...req.body };
products.push(product);
res.status(201).json(product);
});
module.exports = router;Проверь себя
- Как получить параметр :id из URL?
- Что делает
mergeParams: true? - Как сгруппировать методы для одного пути?