Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Маршруты

Любое приложение на express состоит минимум из трёх элементов:

  1. Создание объекта приложения;
  2. Определение обработчиков маршрутов;
  3. Запуск приложения на определённом порту.
import Express from 'express';
const app = new Express();

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Example app listening on port 3000!');
});

С первым и последним пунктом всё более-менее понятно, а вот обработчики — это уже интересно. Напомню, что микрофреймворки строятся по схеме: http verb + path + callback. В случае express глагол определяется функцией, которая вызывается на объекте app. Например если мы хотим определить маршрут GET /, то для этого необходимо вызывать функцию get и первым параметром передать в неё строку /. Таким же образом нужно поступать для любого другого маршрута. Вот список глаголов, которые нас будут интересовать в процессе этого курса:

// И - Идемпотентный
app.get // И
app.post
app.delete // И

// Полное обновление
app.put // И

// Частичное обновление
app.patch

Семантика http подразумевает, что глаголы get, delete и put, являются идемпотентными. Это должно обеспечиваться программистом, который реализует обработчики.

Динамические маршруты

Самая главная и мощная функциональность системы роутинга — это работа с динамическими маршрутами.

Route path: /users/:userId/books/:id
Request URL: http://localhost:3000/users/34/books/8989
req.params: { "userId": "34", "id": "8989" }
app.get('/users/:userId/books/:id', (req, res) => {
  const { userId, id } = req.params;
});

Для динамических частей используется заполнитель :name, который состоит из двоеточия и произвольного имени. Express производит сопоставление актуального запроса со всеми шаблонами в порядке определения и выполняет соответствующие обработчики. Все динамические части маршрута попадают в объект req.params.

Кроме этого, express позволяет использовать регулярные выражения прямо в шаблоне:

// abcd, abxcd, abRANDOMcd, ab123cd
app.get('/ab*cd', (req, res) => {
  res.send('ab*cd');
});

Честно говоря, за свой многолетний опыт я не припомню ситуацию, когда мне это могло понадобиться. Всегда, если у вас есть возможность управлять урлами, можно сделать хороший вариант на одних плейсхолдерах (заполнителях), без прямого использования регулярных выражений.

Именованные маршруты

У системы маршрутизации есть ещё одна важная задача - генерация ссылок. В стандартной поставке express такого механизма нет. Это приводит к тому, что люди, незнакомые с концепцией, генерируют адреса в html, используя строки. Даже существует специальный термин, который называется хардкодинг, при котором прописываются конкретные значения вместо генерации.

<a href=`/posts/${post.id}`>edit</a>

На любом веб-фреймворке, в любом языке так делать нельзя. Если вы измените свои маршруты, то без полной проверки сайта будет невозможно понять что и где сломалось, ведь все ссылки остались старыми. Кроме помощи при отладке и рефакторинге, такой механизм убирает дублирование и позволяет (работает не всегда) изменять маршруты без необходимости переписывать генерацию адресов в html.

import Express from 'express';
import Router from 'named-routes';

const app = new Express();
const router = new Router();
router.extendExpress(app);
router.registerAppHelpers(app);

app.get('/admin/users/:id', 'admin.user', (req, res, next) => {
  //... implementation
  // the names can also be accessed here:
  const path = app.namedRoutes.build('admin.user', { id: 2 }); // /admin/users/2
  // the name of the current route can be found at req.route.name
});

В примере выше был создан именованный маршрут admin.user. Теперь, где-то в другом обработчике можно строить ссылки используя имя маршрута:

app.get('/users', 'users', (req, res, next) => {
  const path = app.namedRoutes.build('admin.user', { id: 2 }); // /admin/users/2
  // path содержит путь с которым можно сделать что-то полезное
});

Преимущества:

  • Если удалится маршрут, то при генерации ссылки мы получим исключение. И тесты его поймают.
  • Если изменится маршрут, то везде будут автоматически подставлены новые адреса.

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

Request/Response

Каждый определяемый обработчик принимает на вход два параметра: req и res. В этом смысле, всё очень похоже на ситуацию с http модулем с той лишь разницей, что там подобный обработчик один, а здесь на каждый маршрут свой. Request и Response предоставляют упрощенный интерфейс. Больше нет необходимости, по крайней мере в простых случаях, пользоваться ими как eventEmitter. На каждую задачу эти объекты предоставляют метод или свойство.

// GET /users?page=3
app.get('/users', (req, res) => {
  console.log(req.query); // { page: 3 }
  res.status(200);
  res.send(users);
  // res.json(users);
});

Пройдёмся по базовым возможностям:

  • req.query готовый к обработке query string, другими словами вам не придётся парсить эти параметры, они уже поступают в виде объекта;
  • Установка статуса работает через метод res.status(code);
  • Отправка данных выполняется функцией res.send(data). Все необходимые заголовки выставляются автоматически;
  • Если необходимо отдавать данные в виде json, то express позволяет это делать без использования дополнительных механизмов. Всё что нужно сделать это вызвать метод res.json(data), и данные будут автоматически сериализованы и отправлены клиенту.

Дополнительные материалы

  1. Named Routes (Документация)

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, даст возможность обращаться за помощью к менторам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».