Express / 37 минут

Валидация HTTP-ввода

Проверяйте req.body и возвращайте корректные статусы.

В процессе Теория: впереди Практика: впереди Тест: впереди
06 / 12
После этой главы
  • Проверяйте req.body и возвращайте корректные статусы.
  • Применить тему в задаче «Валидация HTTP-ввода» и объяснить граничные случаи.

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

Разбор формата и проверка смысла

express.json превращает подходящее JSON-тело в JavaScript-значение. Он не знает, что у нового пользователя должно быть непустое имя, какие поля разрешены и кто вправе задавать роль. После успешного разбора результат может быть массивом, null, числом или объектом с неожиданными полями. Поэтому чтение req.body.name без проверки делает границу хрупкой.

Валидация обычно включает форму корня, типы свойств, ограничения длины и диапазонов, разрешённые поля и нормализацию. Авторизация и доменные ограничения остаются отдельными этапами. Корректная строка ownerId не доказывает, что клиент владеет этой записью. Удобно думать о validator как о переходе из неизвестного ввода в конкретный разрешённый DTO.

Последовательность проверок

Для name сначала проверяют typeof, затем вызывают trim и проверяют непустоту. Обратный порядок может бросить исключение на числе или null. Нормализацию выполняют осознанно: удаление внешних пробелов подходит имени в данном контракте, но не должно автоматически применяться к паролю или произвольной строке, где пробелы значимы.

JavaScript
function parseName(body) {
  if (body === null || typeof body !== 'object' || Array.isArray(body)) return null;
  if (typeof body.name !== 'string') return null;
  const name = body.name.trim();
  if (name.length < 1 || name.length > 100) return null;
  return { name };
}

Возвращённый объект содержит только разрешённое поле. Это надёжнее, чем пометить исходный body «проверенным» и затем использовать все соседние свойства. Проверка одного name не делает произвольное body.role безопасным. Если приложение принимает обновление, отдельно определите, какие поля можно менять и чем отсутствие отличается от сброса.

HTTP-ответ при неверном вводе

Ошибку формы обычно представляют согласованным 400 или иным выбранным статусом в соответствии с контрактом API. Клиенту полезно знать безопасный код поля или правила. Не возвращайте stack trace, внутренние SQL-сообщения и структуру серверного класса вместо понятного ответа. При нескольких полях иногда удобно собрать список ошибок, но его размер тоже должен оставаться ограниченным.

JavaScript
app.use(express.json({ limit: '16kb' }));
app.post('/users', (req, res) => {
  const input = parseName(req.body);
  if (input === null) return res.status(400).json({ error: 'name' });
  return res.status(201).json(input);
});

Обратите внимание на return после отказа: он предотвращает выполнение успешной ветви. Нельзя сначала записать объект в БД, а потом решать, прошёл ли он валидацию. Проверки и построение входного DTO предшествуют изменению состояния, а атомарные связанные изменения оформляют на уровне сценария.

Лишние поля и массовое присваивание

Передача {...req.body} напрямую в запись пользователя опасна, если серверные поля случайно совпадут с клиентскими ключами. Даже когда текущая форма отправляет только name, другой клиент может добавить role или ownerId. Явный allowlist отделяет публичный ввод от внутренней модели и делает изменения API осознанными.

JavaScript
const allowed = { name: input.name };
// service.createUser(allowed, confirmedActor);

Не считайте TypeScript-интерфейс автоматическим фильтром объекта. Аннотации исчезают при компиляции, а Express получает реальные данные запроса. Для большой схемы используйте подходящую библиотеку валидации, но изучите её поведение по неизвестным полям, преобразованиям и ограничениям: настройки по умолчанию могут не совпадать с вашим контрактом.

Ограничения и стоимость обработки

Предел JSON-тела, максимальная длина строк и количество элементов защищают от случайно дорогих входов. Проверка типа массива без ограничения его длины не делает обработку бесплатной. Аналогично сложное регулярное выражение может быть опасно на длинной специально подобранной строке. Ограничения должны соответствовать реальной операции.

Различайте валидацию и экранирование в точке использования. Корректно записанное имя всё равно следует выводить в HTML через текстовый API, а значения для БД передавать параметризованно. Не существует одного «очищенного» текста, который после общей проверки безопасен во всех возможных контекстах HTML, URL и SQL.

Практика непустого имени

Задание требует 201 для строкового name, которое после trim не пусто, и 400 для другого ввода. Это ограниченный учебный контракт: не добавляйте произвольный минимальный возраст или обязательный email. Проверьте число вместо строки, отсутствующее поле и строку из пробелов. Обычное имя с внешними пробелами должно пройти.

После решения расширьте упражнение отдельной функцией parseInput и тестируйте её без HTTP, а затем оставьте несколько интеграционных запросов для связки parser → validator → response. Такая комбинация быстрее объясняет причину отказа и одновременно подтверждает настоящую границу сервера. В итоговом API заметок используйте те же принципы для title, идентификатора и разрешённых полей обновления.

Загружаем редактор…
Следующая темаREST и CRUD-ресурсы

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