Валидация JSON-схем в Ajv основана на формировании структурированных объектов ошибок, которые затем преобразуются в человекочитаемые сообщения. Понимание внутреннего формата ошибок является ключевым для их корректного форматирования и дальнейшей интеграции в пользовательские интерфейсы, API-ответы и системы логирования.
Каждая ошибка в Ajv представляет собой объект со следующими основными полями:
Пример структуры:
{
"instancePath": "/age",
"schemaPath": "#/properties/age/minimum",
"keyword": "minimum",
"params": {
"comparison": ">=",
"limit": 18
},
"message": "must be >= 18"
}
По умолчанию Ajv генерирует англоязычные сообщения на основе
keyword и params. Эти сообщения являются
универсальными и не зависят от структуры приложения.
Основные особенности стандартного поведения:
Ajv позволяет контролировать уровень детализации ошибок через конфигурацию:
Пример конфигурации:
const ajv = new Ajv({
allErrors: true,
verbose: true,
messages: true
});
При verbose: true добавляются дополнительные поля,
полезные для отладки сложных схем.
Расширение 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 в схеме может иметь собственную логику
формирования сообщения.
Примеры распространённых ключевых слов:
typeminimummaxLengthpatternenumrequiredСтруктура 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
};
}
Такой подход используется для:
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 не предоставляет встроенной полноценной локализации, поэтому она реализуется на уровне приложения.
При создании собственных правил в 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"]
}
В архитектурах 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 имеет ряд особенностей:
Эти ограничения компенсируются через ajv-errors,
кастомные keyword и постобработку результатов валидации.