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

При использовании Validator.js результаты проверок представляют собой булевы значения, что формирует специфический подход к обработке ошибок: библиотека не выбрасывает исключения и не формирует структурированные объекты ошибок, а лишь сообщает о валидности входного значения через true или false. Такая модель требует явного проектирования слоя обработки ошибок на уровне приложения.

Каждая функция валидации в Validator.js возвращает логический результат:

  • true — значение соответствует условию
  • false — значение не соответствует условию

Пример:

import validator from "validator";

validator.isEmail("test@example.com"); // true
validator.isEmail("invalid-email");    // false

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

Преобразование булевых результатов в структуру ошибок

Практическое применение требует преобразования простых результатов в объект ошибок. Обычно формируется структура вида «поле → сообщение»:

const errors = {};

const email = "invalid-email";

if (!validator.isEmail(email)) {
  errors.email = "Некорректный формат email";
}

const password = "123";

if (!validator.isLength(password, { min: 8 })) {
  errors.password = "Пароль должен содержать минимум 8 символов";
}

Такой подход формирует централизованный контейнер ошибок, пригодный для передачи в UI или API-ответ.

Агрегация ошибок по полям

При проверке форм с множеством полей важна агрегация всех ошибок за один проход. Распространённый паттерн — накопление результатов в одном объекте:

function validateUser(data) {
  const errors = {};

  if (!validator.isEmail(data.email || "")) {
    errors.email = "Email некорректен";
  }

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

  if (!validator.isAlphanumeric(data.username || "")) {
    errors.username = "Имя пользователя должно быть буквенно-цифровым";
  }

  return errors;
}

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

Нормализация ошибок

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

{
  field: "email",
  rule: "isEmail",
  message: "Некорректный email",
  value: "bad-email"
}

Это позволяет:

  • логировать причины ошибок
  • строить диагностические отчёты
  • выполнять автоматическую обработку на клиенте

Кастомные сообщения и сопоставление правил

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

const rules = {
  email: {
    check: (v) => validator.isEmail(v),
    message: "Некорректный email"
  },
  password: {
    check: (v) => validator.isLength(v, { min: 8 }),
    message: "Пароль слишком короткий"
  }
};

function validate(data) {
  const errors = {};

  Object.keys(rules).forEach((field) => {
    const value = data[field];

    if (!rules[field].check(value || "")) {
      errors[field] = rules[field].message;
    }
  });

  return errors;
}

Такой подход отделяет логику проверки от текстов ошибок, упрощая поддержку.

Комбинирование нескольких правил для одного поля

Один параметр часто требует нескольких проверок. В этом случае ошибки могут накапливаться по приоритету или в виде списка:

function validatePassword(password) {
  const errors = [];

  if (!validator.isLength(password, { min: 8 })) {
    errors.push("Минимум 8 символов");
  }

  if (!validator.matches(password, /[A-Z]/)) {
    errors.push("Должна быть хотя бы одна заглавная буква");
  }

  if (!validator.matches(password, /[0-9]/)) {
    errors.push("Должна быть хотя бы одна цифра");
  }

  return errors;
}

В результате поле может содержать массив ошибок вместо одной строки.

Подход с ранним выходом и накоплением ошибок

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

Ранний выход:

if (!validator.isEmail(email)) {
  return { email: "Ошибка email" };
}

Полное накопление:

const errors = {};

if (!validator.isEmail(email)) {
  errors.email = "Ошибка email";
}

if (!validator.isLength(password, { min: 8 })) {
  errors.password = "Ошибка пароля";
}

return errors;

Первый вариант применяется в потоках, где важна производительность. Второй — в пользовательских формах.

Ошибки и приведение типов

Validator.js работает со строками, поэтому некорректные типы часто становятся источником скрытых ошибок. Распространённая практика — явное приведение:

const value = String(data.email || "");

Это снижает вероятность некорректного поведения функций вроде isEmail, isLength и других.

Интеграция с API-ответами

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

const errors = validateUser(req.body);

if (Object.keys(errors).length > 0) {
  res.status(400).json({
    status: "error",
    errors
  });
}

Такой формат позволяет клиентской стороне унифицировать обработку ошибок независимо от типа формы.

Композиция валидаторов и централизованная обработка

При росте количества правил применяется композиционный подход, при котором каждая проверка — это независимая функция:

const isValidEmail = (v) => validator.isEmail(v);
const isValidPassword = (v) => validator.isLength(v, { min: 8 });

function runValidators(value, validators) {
  return validators.every((fn) => fn(value));
}

Ошибки при этом формируются отдельно, на основе неудачных функций.

Интернационализация сообщений об ошибках

Так как Validator.js не предоставляет локализацию, слой сообщений обычно выносится отдельно:

const messages = {
  ru: {
    email: "Некорректный email",
    password: "Слабый пароль"
  },
  en: {
    email: "Invalid email",
    password: "Weak password"
  }
};

Выбор языка происходит на уровне бизнес-логики, а не валидатора.

Паттерн Result-объекта

Для унификации обработки часто используется структура результата:

function validateEmail(email) {
  if (!validator.isEmail(email)) {
    return {
      valid: false,
      error: "Некорректный email"
    };
  }

  return {
    valid: true,
    error: null
  };
}

Это позволяет избегать работы с «сырыми» булевыми значениями и упрощает цепочки обработки.

Ошибки как часть доменной логики

Валидация на базе Validator.js часто становится частью доменного слоя, где ошибки рассматриваются не как исключения, а как ожидаемый результат проверки входных данных. Это приводит к архитектуре, в которой:

  • ошибки — нормальный исход выполнения функций
  • исключения используются только для системных сбоев
  • структура ошибок унифицирована по всему приложению

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