Валидация путей и параметров запроса

Работа с HTTP-запросами в серверных приложениях на Node.js неизбежно приводит к необходимости строгой проверки входящих данных. Параметры маршрутов, query-string и части URL формируют поверхность атаки, через которую в систему могут попадать некорректные или вредоносные значения. В таких условиях библиотека Validator.js становится базовым инструментом для проверки строковых данных, позволяя стандартизировать подход к валидации и снижать вероятность ошибок на уровне бизнес-логики.


Структура входящих данных HTTP-запроса

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

  • Параметры пути (route params) — значения в URL, например /users/:id
  • Query-параметры — строка запроса после ?, например ?page=2&limit=10
  • Тело запроса (body) — данные POST/PUT/PATCH
  • Фрагменты пути (path segments) — части URL, влияющие на маршрутизацию

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


Базовая роль Validator.js в проверке данных

Библиотека Validator.js ориентирована на строковую валидацию и предоставляет набор функций для проверки форматов:

  • числовые значения (isInt, isFloat)
  • идентификаторы (isUUID)
  • строки определённого формата (matches, isSlug)
  • логические значения (isBoolean)
  • URL и email (isURL, isEmail)

Ключевой особенностью является то, что Validator.js не работает с объектами или схемами напрямую — он проверяет только строки. Это делает её удобной для использования на уровне контроллеров и middleware, где входные данные уже приведены к строковому виду.


Валидация параметров маршрута (route params)

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

app.get('/users/:id', (req, res) => {
    const { id } = req.params;
});

Значение id всегда приходит как строка, даже если ожидается число. Без проверки это может привести к некорректной работе бизнес-логики.

Проверка числового идентификатора

import validator fr om 'validator';

app.get('/users/:id', (req, res) => {
    const { id } = req.params;

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

    const userId = parseInt(id, 10);
});

Использование isInt позволяет ограничить диапазон значений и исключить отрицательные числа или нечисловые строки.


UUID в параметрах маршрута

Современные API часто используют UUID вместо числовых идентификаторов:

app.get('/orders/:orderId', (req, res) => {
    const { orderId } = req.params;

    if (!validator.isUUID(orderId)) {
        return res.status(400).json({ error: 'Некорректный UUID заказа' });
    }
});

UUID обеспечивает более высокий уровень уникальности и снижает предсказуемость идентификаторов.


Валидация query-параметров

Query-параметры используются для фильтрации, пагинации и сортировки:

/products?page=2&limit=20&sort=price

Все значения в query-string также представлены строками.

Проверка пагинации

app.get('/products', (req, res) => {
    const { page = '1', lim it = '10' } = req.query;

    if (!validator.isInt(page, { min: 1 }) ||
        !validator.isInt(limit, { min: 1, max: 100 })) {
        return res.status(400).json({ error: 'Некорректные параметры пагинации' });
    }

    const pageNum = parseInt(page, 10);
    const limitNum = parseInt(limit, 10);
});

Ограничение max у limit защищает от чрезмерной нагрузки на сервер.


Валидация строковых фильтров

const { sort } = req.query;

if (sort && !validator.matches(sort, /^(price|name|date)$/)) {
    return res.status(400).json({ error: 'Недопустимое значение сортировки' });
}

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


Валидация сегментов пути

Иногда часть URL используется как семантический параметр:

/blog/node-js-routing-guide

Здесь node-js-routing-guide является slug-идентификатором.

app.get('/blog/:slug', (req, res) => {
    const { slug } = req.params;

    if (!validator.isSlug(slug)) {
        return res.status(400).json({ error: 'Некорректный slug' });
    }
});

Slug-валидация особенно важна при генерации SEO-дружественных URL.


Комбинированная проверка параметров

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

app.get('/posts/:postId/comments', (req, res) => {
    const { postId } = req.params;
    const { page = '1' } = req.query;

    const errors = [];

    if (!validator.isUUID(postId)) {
        errors.push('Некорректный ID поста');
    }

    if (!validator.isInt(page, { min: 1 })) {
        errors.push('Некорректная страница');
    }

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

Такой подход позволяет агрегировать ошибки вместо раннего завершения обработки.


Использование middleware для централизации валидации

Повторяющиеся проверки удобно выносить в middleware:

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

    if (!validator.isInt(id, { min: 1 })) {
        return res.status(400).json({ error: 'Некорректный ID' });
    }

    next();
}

app.get('/users/:id', validateUserId, (req, res) => {
    res.send('OK');
});

Такой подход снижает дублирование кода и повышает консистентность проверок.


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

Валидация часто сопровождается нормализацией:

const email = validator.normalizeEmail(req.body.email);

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


Защита от небезопасных значений в URL

Валидация путей напрямую связана с безопасностью:

Path Traversal

Некорректные значения могут привести к доступу к файловой системе:

/files/. ./. ./etc/passwd

Проверка:

const { file } = req.params;

if (file.includes('..') || !validator.matches(file, /^[a-zA-Z0-9_-]+$/)) {
    return res.status(400).json({ error: 'Недопустимое имя файла' });
}

Инъекции через параметры

Даже при использовании ORM или query builder некорректные параметры могут повлиять на логику:

if (!validator.isAlphanumeric(req.query.search || '')) {
    return res.status(400).json({ error: 'Недопустимый поисковый запрос' });
}

Паттерны строгой валидации API

Белые списки значений

const allowed = ['asc', 'desc'];

if (!allowed.includes(req.query.order)) {
    return res.status(400).json({ error: 'Некорректный порядок сортировки' });
}

Гибрид Validator.js + RegExp

if (!validator.isLength(req.params.slug, { min: 3, max: 100 }) ||
    !validator.matches(req.params.slug, /^[a-z0-9-]+$/)) {
    return res.status(400).json({ error: 'Некорректный slug' });
}

Особенности использования Validator.js в серверной архитектуре

Validator.js не хранит состояние и не зависит от окружения, что делает его удобным для:

  • middleware Express
  • контроллеров REST API
  • GraphQL resolvers
  • serverless функций

Однако его ограничения важно учитывать: библиотека не работает с объектными схемами и требует ручной композиции проверок.


Типовые ошибки при валидации маршрутов

Отсутствие приведения типов

// Ошибка: сравнение строки и числа без проверки
if (req.params.id > 100) {}

Проверка после использования

const userId = req.params.id;
// использование userId до валидации

Игнорирование query-параметров

Query часто остаётся невалидированным, несмотря на участие в бизнес-логике.


Композиция проверок в реальных API

Типичная структура маршрута с полной валидацией:

app.get('/users/:id/posts', (req, res) => {
    const { id } = req.params;
    const { page, limit } = req.query;

    if (!validator.isUUID(id)) {
        return res.status(400).json({ error: 'Invalid user ID' });
    }

    if (!validator.isInt(page || '1', { min: 1 }) ||
        !validator.isInt(limit || '10', { min: 1, max: 50 })) {
        return res.status(400).json({ error: 'Invalid pagination' });
    }

    // безопасная бизнес-логика
});

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

Централизованная обработка позволяет унифицировать ответы API:

function errorResponse(res, messages) {
    return res.status(400).json({
        status: 'error',
        errors: messages
    });
}

Итоговая модель использования Validator.js в маршрутах

  • все входные параметры рассматриваются как строки
  • каждая часть URL проверяется отдельно
  • регулярные выражения используются для ограничения форматов
  • числовые значения всегда проходят isInt или isFloat
  • UUID и slug проверяются специализированными функциями
  • middleware используется для повторяющихся проверок
  • нормализация применяется после успешной валидации