Дополнительные элементы

Одной из ключевых возможностей Ajv является механизм расширения языка JSON Schema за счёт пользовательских ключевых слов. Это позволяет внедрять собственную бизнес-логику прямо в процесс валидации без необходимости постобработки данных.

Регистрация нового ключевого слова выполняется через метод addKeyword, который может принимать как простую функцию-валидатор, так и полноценный объект конфигурации.

Базовая форма определения:

ajv.addKeyword({
  keyword: 'isEven',
  type: 'number',
  validate: function (schema, data) {
    return data % 2 === 0;
  }
});

В этом примере вводится новое правило isEven, применимое к числам. Такая конструкция позволяет интегрировать произвольные проверки, сохраняя совместимость со стандартом JSON Schema.

Генерация кода в пользовательских ключевых словах

Ajv компилирует схемы в JavaScript-функции. Пользовательские ключевые слова также могут участвовать в генерации кода, что критично для производительности.

ajv.addKeyword({
  keyword: 'multipleOf5',
  compile: () => {
    return (data) => data % 5 === 0;
  }
});

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


Работа с форматами данных

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

Расширение выполняется через addFormat:

ajv.addFormat('hexColor', {
  type: 'string',
  validate: (data) => /^#[0-9A-Fa-f]{6}$/.test(data)
});

Для стандартизированных форматов часто используется пакет расширений ajv-formats, который добавляет поддержку email, uri, date-time и других спецификаций.

Особенность форматов:

  • применяются только к строкам
  • могут быть синхронными или асинхронными
  • могут использовать оптимизированную проверку через RegExp

Плагины и расширения экосистемы

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

Наиболее часто используемые расширения:

  • ajv-formats — набор стандартных форматов
  • ajv-errors — кастомизация сообщений об ошибках
  • ajv-keywords — дополнительные ключевые слова JSON Schema

Пример подключения плагина

import addFormats from "ajv-formats";

addFormats(ajv);

Расширение поведения ошибок

С помощью ajv-errors можно задавать человекочитаемые сообщения:

const schema = {
  type: "number",
  errorMessage: "Значение должно быть числом"
};

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


Управление данными во время валидации

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

Автозаполнение значений

const ajv = new Ajv({ useDefaults: true });

Если в схеме указано:

{
  "type": "object",
  "properties": {
    "role": {
      "type": "string",
      "default": "user"
    }
  }
}

Отсутствующее поле будет автоматически добавлено.


Приведение типов

const ajv = new Ajv({ coerceTypes: true });

Это позволяет автоматически преобразовывать значения:

  • "42"42
  • "true"true

Такой режим особенно полезен при обработке данных из HTTP-запросов.


Удаление лишних полей

const ajv = new Ajv({ removeAdditional: true });

При использовании:

{
  "type": "object",
  "additionalProperties": false
}

лишние поля будут удалены из объекта, а не только помечены как ошибочные.


$data-ссылки и динамическая валидация

Механизм $data позволяет использовать значения из самого объекта данных внутри схемы.

Пример:

{
  "properties": {
    "min": { "type": "number" },
    "value": {
      "type": "number",
      "minimum": { "$data": "1/min" }
    }
  }
}

Здесь значение value проверяется относительно min.

Особенности $data:

  • требует включения опции ajv.$data = true
  • повышает выразительность схем
  • увеличивает сложность компиляции

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

Ajv поддерживает асинхронные проверки через async/await.

Для этого используется ключевое слово $async:

const schema = {
  $async: true,
  type: "string",
  validate: async function (data) {
    return await checkDatabase(data);
  }
};

Если валидация асинхронная, результатом будет Promise.

Особенность:

  • ошибки возвращаются через throw
  • требуется обработка через await validate(data)

Управление ошибками и их структура

Ajv формирует детализированный объект ошибок, который содержит:

  • путь к данным (instancePath)
  • правило (keyword)
  • описание (message)
  • параметры (params)

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

{
  "instancePath": "/age",
  "keyword": "minimum",
  "message": "should be >= 18",
  "params": { "comparison": 18 }
}

Поведение ошибок

Режимы управления:

  • allErrors: true — сбор всех ошибок
  • allErrors: false — остановка на первой ошибке

Компиляция схем и производительность

Одним из фундаментальных механизмов Ajv является предварительная компиляция схем в исполняемые функции JavaScript.

const validate = ajv.compile(schema);
validate(data);

Преимущества компиляции:

  • отсутствие интерпретации JSON Schema на каждом вызове
  • возможность JIT-оптимизации движком V8
  • повторное использование функций

Кэширование схем

Ajv автоматически кэширует скомпилированные схемы, если они идентичны по ссылке или содержимому.


Строгий режим (strict mode)

Ajv может работать в строгом режиме, который выявляет:

  • неизвестные ключевые слова
  • несовместимости версий JSON Schema
  • потенциальные ошибки схем
const ajv = new Ajv({ strict: true });

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


Совместимость с версиями JSON Schema

Ajv поддерживает несколько спецификаций:

  • Draft-07
  • 2019-09
  • 2020-12

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

Некоторые ключевые различия:

  • $id вместо id
  • изменённая логика $recursiveRef
  • обновлённые правила объединения схем

Композиция схем

Хотя композиционные ключевые слова являются базовой частью JSON Schema, в Ajv они получают оптимизированную реализацию.

allOf

Все схемы должны быть валидны:

{
  "allOf": [schema1, schema2]
}

anyOf

Достаточно соответствия одной схемы.

oneOf

Требуется соответствие ровно одной схеме.

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


Повторное использование и ссылки на схемы

Ajv поддерживает референсы $ref, позволяющие строить модульные схемы.

const schema = {
  $ref: "user.json"
};

Схемы могут регистрироваться в реестре:

ajv.addSchema(userSchema, "user.json");

Это создаёт централизованную систему схем, пригодную для крупных приложений.


Оптимизация и режимы выполнения

Ajv включает несколько уровней оптимизации:

  • отключение лишних проверок в production
  • минимизация runtime-ветвлений
  • генерация компактного кода валидаторов

Дополнительные опции:

  • code: { es5: false } — использование современных конструкций
  • inlineRefs: true — инлайн ссылок
  • messages: false — отключение генерации сообщений

Поведение с дополнительными свойствами

Ajv строго контролирует поля, не описанные в схеме:

  • additionalProperties: false — запрет
  • additionalProperties: true — разрешение
  • объект-схема — проверка дополнительных полей

Пример:

{
  "type": "object",
  "additionalProperties": {
    "type": "string"
  }
}

Каждое дополнительное поле проверяется как строка.


Механизмы удаления и трансформации данных

Валидация в Ajv может выполнять не только проверку, но и трансформацию входного объекта.

Поддерживаемые механизмы:

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

Эти возможности превращают Ajv в инструмент не только проверки, но и нормализации данных перед дальнейшей обработкой.


Поведение экземпляра Ajv

Экземпляр Ajv хранит внутреннее состояние:

  • реестр схем
  • скомпилированные валидаторы
  • настройки глобальных режимов

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