Форматирование сообщений

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

Каждая ошибка в Ajv представляет собой объект со следующими основными полями:

  • instancePath — путь к данным, в которых обнаружена ошибка
  • schemaPath — путь к нарушенному правилу схемы
  • keyword — ключевое слово JSON Schema, вызвавшее ошибку
  • params — параметры, связанные с конкретным правилом
  • message — стандартное текстовое описание ошибки

Пример структуры:

{
  "instancePath": "/age",
  "schemaPath": "#/properties/age/minimum",
  "keyword": "minimum",
  "params": {
    "comparison": ">=",
    "limit": 18
  },
  "message": "must be >= 18"
}

Базовое формирование сообщений

По умолчанию Ajv генерирует англоязычные сообщения на основе keyword и params. Эти сообщения являются универсальными и не зависят от структуры приложения.

Основные особенности стандартного поведения:

  • сообщения формируются автоматически
  • текст зависит от типа ограничения (minimum, maxLength, pattern и т.д.)
  • отсутствует поддержка локализации без дополнительной настройки
  • формат сообщений не всегда подходит для пользовательского интерфейса

Управление подробностью ошибок

Ajv позволяет контролировать уровень детализации ошибок через конфигурацию:

  • allErrors — продолжать сбор ошибок после первой найденной
  • verbose — расширенные данные о путях схемы и данных
  • messages — включение/отключение текстовых сообщений

Пример конфигурации:

const ajv = new Ajv({
  allErrors: true,
  verbose: true,
  messages: true
});

При verbose: true добавляются дополнительные поля, полезные для отладки сложных схем.


Кастомизация сообщений через errorMessage

Расширение ajv-errors позволяет задавать собственные тексты ошибок на уровне схемы.

Подключение:

import Ajv fr om "ajv";
import addFormats fr om "ajv-formats";
import ajvErrors fr om "ajv-errors";

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
ajvErrors(ajv);

Использование в JSON Schema:

{
  "type": "object",
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "errorMessage": "Некорректный формат email"
    }
  },
  "required": ["email"],
  "errorMessage": {
    "required": {
      "email": "Поле email обязательно для заполнения"
    }
  }
}

Механизм позволяет:

  • переопределять сообщения на уровне поля
  • задавать сообщения для конкретных правил (required, type, format)
  • формировать разные тексты для разных типов ошибок

Форматирование на основе keyword

Каждое keyword в схеме может иметь собственную логику формирования сообщения.

Примеры распространённых ключевых слов:

  • type
  • minimum
  • maxLength
  • pattern
  • enum
  • required

Структура params используется как источник данных для генерации текста.

Пример интерпретации:

keyword: minimum
params: { lim it: 10 }

результат: значение должно быть >= 10

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

const messages = {
  minimum: (e) => `Минимальное значение: ${e.params.lim it}`,
  maxLength: (e) => `Максимальная длина: ${e.params.lim it}`,
  required: (e) => `Отсутствует поле: ${e.params.missingProperty}`
};

Перехват и постобработка ошибок

Ajv позволяет обрабатывать массив ошибок после валидации:

const valid = validate(data);

if (!valid) {
  const formatted = validate.errors.map(formatError);
}

Функция форматирования:

function formatError(error) {
  return {
    path: error.instancePath,
    message: error.message,
    rule: error.keyword
  };
}

Такой подход используется для:

  • унификации API-ответов
  • локализации сообщений
  • интеграции с UI-валидацией

Использование instancePath для читаемых сообщений

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

Пример:

{
  "instancePath": "/user/address/street"
}

На его основе формируются пути вида:

user.address.street: значение не может быть пустым

Часто применяется преобразование:

const path = error.instancePath
  .replace(/\//g, ".")
  .replace(/^\./, "");

Локализация сообщений

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

const i18n = {
  en: {
    required: "Field is required"
  },
  ru: {
    required: "Поле обязательно"
  }
};

function localize(error, lang = "ru") {
  return i18n[lang][error.keyword] || error.message;
}

Ajv не предоставляет встроенной полноценной локализации, поэтому она реализуется на уровне приложения.


Кастомные keyword с собственными сообщениями

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

ajv.addKeyword({
  keyword: "positive",
  type: "number",
  validate: (schema, data) => data > 0,
  errors: true,
  metaSchema: {
    type: "boolean"
  }
});

Добавление сообщения:

ajv.addKeyword({
  keyword: "positive",
  validate: (schema, data) => data > 0,
  errors: true,
  error: {
    message: "Значение должно быть положительным"
  }
});

Группировка и агрегация сообщений

При работе с формами часто требуется объединять ошибки по полям:

function groupErrors(errors) {
  return errors.reduce((acc, err) => {
    const path = err.instancePath || "root";
    if (!acc[path]) acc[path] = [];
    acc[path].push(err.message);
    return acc;
  }, {});
}

Результат:

{
  "/email": ["Некорректный формат email"],
  "/password": ["Минимальная длина 8"]
}

Управление форматированием через middleware-слой

В архитектурах API часто вводится промежуточный слой, преобразующий ошибки Ajv в стандартизированный формат:

function ajvErrorMiddleware(errors) {
  return {
    status: "validation_error",
    errors: errors.map(e => ({
      field: e.instancePath,
      rule: e.keyword,
      message: e.message
    }))
  };
}

Такой слой позволяет:

  • отделить схему от представления ошибок
  • унифицировать ответы сервера
  • упрощать интеграцию с фронтендом

Особенности форматирования при вложенных схемах

При использовании $ref и сложных вложенных структур ошибки могут содержать длинные пути и пересекающиеся контексты.

Пример:

{
  "instancePath": "/order/items/0/price"
}

Для удобства отображения применяются:

  • сокращение путей
  • добавление индексов массивов
  • преобразование в читаемые цепочки
order.items[0].price: значение некорректно

Ограничения стандартного механизма сообщений

Стандартный механизм Ajv имеет ряд особенностей:

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

Эти ограничения компенсируются через ajv-errors, кастомные keyword и постобработку результатов валидации.