Валидация API запросов

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

При построении REST или GraphQL API валидация рассматривается как отдельный слой, располагающийся до контроллеров и сервисов. На этом уровне происходит фильтрация и нормализация входящих данных: тела запроса, query-параметров, path-параметров и заголовков.

Структура входных данных API

HTTP-запрос в типичном серверном приложении включает несколько областей данных:

1. Тело запроса (body) Содержит основные данные, передаваемые клиентом. Используется в POST, PUT, PATCH запросах.

2. Query-параметры (query string) Передаются в URL и часто используются для фильтрации, сортировки и пагинации.

3. Path-параметры (params) Являются частью маршрута и обычно идентифицируют ресурсы.

4. Заголовки (headers) Содержат метаинформацию: токены авторизации, тип контента, язык и др.

Каждый из этих источников требует отдельной стратегии проверки, так как их семантика и допустимые значения различаются.

Подходы к валидации

Существует несколько основных стратегий обработки входных данных:

Явная ручная валидация Проверка каждого поля с использованием условий. Подходит для небольших проектов, но плохо масштабируется.

Схемная валидация Использование описательных схем, в которых заранее задаются правила для структуры данных. Такой подход применяется в большинстве современных библиотек валидации.

Middleware-валидация Интеграция валидации в промежуточные обработчики HTTP-запросов, особенно в экосистеме Express.js.

Validator.js и схемная проверка

Библиотека Validator.js предоставляет набор функций для проверки и санитаризации строковых значений. В отличие от полноценных схемных валидаторов, она ориентирована на атомарные проверки: email, URL, числовые строки, длина, регэксп-совпадения и другие примитивные правила.

В контексте API она используется как низкоуровневый инструмент, поверх которого часто строятся собственные схемы или комбинируется с middleware-слоем.

Пример типовых проверок:

  • проверка email-адресов
  • валидация URL
  • проверка числовых строк
  • контроль длины строк
  • нормализация строковых значений

Валидация запроса в Node.js приложении

В серверной архитектуре на базе Express.js Validator.js обычно применяется внутри middleware, который перехватывает запрос до передачи в контроллер.

Пример логики проверки тела запроса:

import validator fr om "validator";

function validateCreateUser(req, res, next) {
  const { email, password, age } = req.body;

  const errors = [];

  if (!validator.isEmail(email || "")) {
    errors.push("Некорректный email");
  }

  if (!validator.isLength(password || "", { min: 8 })) {
    errors.push("Пароль слишком короткий");
  }

  if (!validator.isInt(String(age || ""), { min: 0 })) {
    errors.push("Некорректный возраст");
  }

  if (errors.length > 0) {
    return res.status(400).json({ errors });
  }

  next();
}

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

Валидация query и params

Query-параметры часто используются для управления выборкой данных, и их некорректная обработка может приводить к логическим ошибкам.

Пример проверки query string:

function validateQuery(req, res, next) {
  const { page, lim it } = req.query;

  if (!validator.isInt(page || "1", { min: 1 })) {
    return res.status(400).json({ error: "page должен быть целым числом >= 1" });
  }

  if (!validator.isInt(limit || "10", { min: 1, max: 100 })) {
    return res.status(400).json({ error: "limit вне допустимого диапазона" });
  }

  next();
}

Path-параметры требуют строгой проверки идентификаторов ресурсов:

function validateParams(req, res, next) {
  const { id } = req.params;

  if (!validator.isUUID(id)) {
    return res.status(400).json({ error: "Некорректный идентификатор" });
  }

  next();
}

Нормализация и санитаризация данных

Валидация часто дополняется санитаризацией — приведением данных к безопасному и предсказуемому виду.

Типовые операции:

  • удаление лишних пробелов
  • приведение строк к нижнему регистру
  • экранирование специальных символов
  • удаление потенциально опасных HTML-тегов

Пример:

const cleanEmail = validator.normalizeEmail(email, {
  gmail_remove_dots: false,
});

Санитаризация особенно важна при работе с пользовательским вводом, который впоследствии отображается в интерфейсе или сохраняется в базе данных.

Кастомные правила валидации

Стандартных функций Validator.js недостаточно для сложных доменных ограничений. В таких случаях формируются кастомные проверки.

Пример:

function isStrongPassword(value) {
  return (
    validator.isLength(value, { min: 10 }) &&
    /[A-Z]/.test(value) &&
    /[0-9]/.test(value) &&
    /[^A-Za-z0-9]/.test(value)
  );
}

Подобные функции часто выносятся в отдельные модули и переиспользуются в разных сервисах.

Обработка ошибок валидации

Единообразная структура ошибок является важной частью API-дизайна. Обычно используется централизованный формат ответа:

return res.status(400).json({
  status: "error",
  errors: [
    { field: "email", message: "Некорректный формат" }
  ]
});

Такой формат упрощает обработку ошибок на клиентской стороне и обеспечивает предсказуемость поведения API.

Асинхронная валидация

Часть проверок требует обращения к внешним источникам данных: базе данных или сторонним сервисам.

Пример проверки уникальности email:

async function validateEmailUnique(req, res, next) {
  const user = await User.findOne({ email: req.body.email });

  if (user) {
    return res.status(400).json({ error: "Email уже используется" });
  }

  next();
}

Validator.js в таких сценариях используется только для первичной проверки формата, а бизнес-ограничения реализуются отдельно.

Безопасность и влияние валидации на уязвимости

Корректная валидация снижает риск следующих проблем:

  • SQL-инъекции при некорректной обработке строковых параметров
  • NoSQL-инъекции при использовании объектов без проверки структуры
  • XSS при отсутствии санитаризации пользовательского ввода
  • переполнения логики при передаче некорректных числовых значений

Валидация не заменяет параметризацию запросов и безопасные методы доступа к данным, но является важным дополнительным слоем защиты.

Архитектурные паттерны применения

В крупных системах валидация строится по слоям:

  • middleware-валидация входа
  • доменная валидация внутри сервисов
  • проверка ограничений на уровне базы данных

Такое разделение позволяет поддерживать консистентность данных независимо от точки входа в систему и уменьшает связность компонентов.