Express / 39 минут

Маршруты Express

Создайте HTTP-маршрут и верните JSON-ответ.

В процессе Теория: впереди Практика: впереди Тест: впереди
02 / 12
После этой главы
  • Создайте HTTP-маршрут и верните JSON-ответ.
  • Применить тему в задаче «Маршруты Express» и объяснить граничные случаи.

Около 9 минут на чтение и разбор примеров. Практика — отдельно, в своём темпе.

Метод и путь образуют контракт

Маршрут связывает HTTP-метод и путь с обработкой запроса. GET /users и POST /users — разные операции, даже если адресная часть совпадает. Метод выбирают по смыслу, а не по удобству отправить всё через одну кнопку. Чтение не должно скрыто создавать запись, если контракт обещает безопасный GET.

Обработчик получает req и res. Через req читают параметры запроса, через res формируют ответ. Вызов res.json сериализует подходящее значение как JSON и завершает соответствующий ответ. Возврат res.json из функции помогает прекратить выполнение текущей ветви, но важен именно вызов метода ответа, а не магическое значение return для Express.

JavaScript
app.get('/courses', (_req, res) => res.json(['JS', 'TS']));
app.post('/courses', (_req, res) => res.status(201).json({ id: 'new' }));

Параметры пути и query

Параметр :id выделяет часть пути и становится строковым значением в req.params. То, что в URL написано 42, не делает его автоматически числом. Query используется отдельно для фильтра, поиска и пагинации. Не регистрируйте маршрут с вопросительным знаком и конкретной query-строкой вместо нормальной проверки req.query.

JavaScript
app.get('/courses/:id', (req, res) => {
  res.json({ id: req.params.id, preview: req.query.preview === 'true' });
});
// GET /courses/42?preview=true

Внешние значения требуют проверки типа, формата и допустимого диапазона. Не передавайте произвольный id напрямую в опасную файловую операцию. Для числового идентификатора преобразование после полной проверки отличается от parseInt, который может принять начальный фрагмент '42bad'. Путь помогает выбрать ресурс, но не доказывает право пользователя его читать.

Порядок регистрации

Express обрабатывает зарегистрированные слои по порядку. Если более общий маршрут перехватывает запрос и завершает ответ раньше специального, следующий не выполнится. Например, динамический /users/:id может принять слово stats за идентификатор, если вы поставили его перед нужным специальным случаем. Порядок должен быть понятен из структуры приложения.

JavaScript
app.get('/users/stats', (_req, res) => res.json({ total: 10 }));
app.get('/users/:id', (req, res) => res.json({ id: req.params.id }));

Не исправляйте конфликты бесконечными исключениями внутри большого handler. Иногда нужно изменить ресурсную модель, сгруппировать пути или точнее валидировать идентификаторы. После рефакторинга полезно иметь тесты обоих маршрутов, чтобы новый общий случай не поглотил старый специальный.

Несколько обработчиков и завершение ответа

Маршрут может иметь несколько функций: проверку, загрузку данных и формирование ответа. Обычный middleware вызывает next, если передаёт работу дальше, либо завершает ответ. Если он не делает ни того ни другого, запрос зависает. Если после завершения ответа продолжает выполнять ветви, можно получить повторную отправку заголовков.

JavaScript
function checkId(req, res, next) {
  if (!/^[0-9]+$/.test(req.params.id)) return res.sendStatus(400);
  next();
}
app.get('/items/:id', checkId, (req, res) => {
  res.json({ id: Number(req.params.id) });
});

Короткий return на отказе делает контроль потока явным. Не считайте next обычным «продолжить эту же функцию позже»: это передача управления следующему слою цепочки. Инструкции после next тоже могут выполниться в текущем стеке, поэтому порядок побочных действий требует отдельного внимания.

Express 5 и обработка отсутствующего маршрута

Синтаксис некоторых шаблонов путей изменился в Express 5. В частности, старые безымянные wildcard-примеры из Express 4 нельзя переносить без проверки руководства миграции. Для простого 404-ответа часто достаточно обычного завершающего app.use после маршрутов, не используя сложный wildcard-путь.

JavaScript
app.use((_req, res) => {
  res.status(404).json({ error: 'not_found' });
});

Отсутствующий маршрут не является автоматически брошенным исключением вашего обработчика. Нормальная цепочка может просто дойти до конца без подходящего endpoint. Держите обработку 404 и неожиданных исключений понятными отдельными слоями, чтобы клиент не получал внутреннюю 500 там, где ресурса просто нет.

Практика маршрута health

В задании нужно зарегистрировать GET /health и проверить его через Supertest. Ответом является {ok:true}. Значение должно прийти из HTTP-ответа, а не из обходного прямого return в solve. Эта небольшая задача проверяет, что вы различаете описание приложения, вызов маршрута и извлечение тела ответа.

После успешной проверки добавьте POST к тому же пути и убедитесь, что методы не смешиваются. Затем запросите неизвестный путь и сравните результат. Для самостоятельного API выпишите таблицу «метод — путь — вход — успешный ответ — ошибки» до реализации. Такая таблица помогает согласовать маршрутизацию, теорию, практику и будущие клиентские вызовы.

Загружаем редактор…
Следующая темаПорядок middleware

Музыка: Reverie — Scott Buckley · CC BY 4.0