Ajv для JSON Schema

Ajv — высокопроизводительный валидатор JSON Schema для JavaScript, ориентированный на строгую проверку данных, компиляцию схем в оптимизированные функции и поддержку современных спецификаций стандарта JSON Schema (draft-07, 2019-09, 2020-12 в зависимости от версии).

Основой работы является преобразование JSON Schema в исполняемую функцию проверки. При первом вызове схема компилируется, после чего повторные проверки выполняются без повторного разбора структуры схемы.

Ключевой принцип:

схема → компиляция → валидирующая функция → многократное использование

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

Подключение и базовая конфигурация

import Ajv from "ajv";

const ajv = new Ajv();

Создание экземпляра валидатора предполагает конфигурацию поведения:

  • strict — строгая проверка схем
  • allErrors — сбор всех ошибок, а не остановка на первой
  • coerceTypes — автоматическое приведение типов
  • removeAdditional — удаление лишних полей

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

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

Простейшая схема валидации

JSON Schema описывает структуру объекта:

const schema = {
  type: "object",
  properties: {
    name: { type: "string" },
    age: { type: "number" }
  },
  required: ["name", "age"],
  additionalProperties: false
};

const validate = ajv.compile(schema);

const data = { name: "Ivan", age: 30 };

const valid = validate(data);

Результат проверки доступен через булево значение, а ошибки — в validate.errors.

Структура ошибок

Ошибки представляют собой массив объектов:

validate.errors;

Типичная структура:

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

Пример анализа:

if (!validate(data)) {
  console.log(validate.errors);
}

Основные ключевые слова JSON Schema

type

Определяет тип значения:

{ type: "string" }
{ type: "number" }
{ type: "object" }

properties

Описание структуры объекта:

properties: {
  id: { type: "integer" },
  title: { type: "string" }
}

required

Массив обязательных полей:

required: ["id", "title"]

additionalProperties

Контроль лишних полей:

additionalProperties: false

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

Главная особенность Ajv — предварительная компиляция схемы в функцию.

При компиляции происходит:

  • разбор схемы
  • оптимизация условий
  • генерация JS-кода проверки
  • кэширование результата

Это делает выполнение валидации сопоставимым по скорости с ручной проверкой условий.

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

Компилированные функции можно использовать многократно:

const validateUser = ajv.compile(userSchema);

validateUser(user1);
validateUser(user2);
validateUser(user3);

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

Вложенные структуры

JSON Schema поддерживает рекурсивные описания:

const schema = {
  type: "object",
  properties: {
    node: {
      type: "object",
      properties: {
        value: { type: "number" },
        next: { $ref: "#" }
      }
    }
  }
};

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

Пользовательские форматы

Ajv поддерживает расширение через форматы:

ajv.addFormat("uppercase", {
  type: "string",
  validate: (data) => data === data.toUpperCase()
});

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

const schema = {
  type: "string",
  format: "uppercase"
};

Кастомные ключевые слова

Расширение логики через свои правила:

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

Схема:

const schema = {
  type: "number",
  isEven: true
};

Работа с массивами

Поддерживаются ограничения:

const schema = {
  type: "array",
  items: { type: "number" },
  minItems: 1,
  maxItems: 5,
  uniqueItems: true
};

Условные конструкции

JSON Schema позволяет описывать зависимости:

const schema = {
  type: "object",
  properties: {
    type: { enum: ["A", "B"] },
    value: { type: "string" }
  },
  if: {
    properties: { type: { const: "A" } }
  },
  then: {
    required: ["value"]
  }
};

Обработка null и nullable значений

const schema = {
  type: ["string", "null"]
};

Используется для совместимости с API, где значение может отсутствовать.

Строгий режим

В строгом режиме выявляются:

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

Это важно для предотвращения скрытых логических ошибок.

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

Поддерживаются асинхронные проверки, например обращение к базе данных:

ajv.addKeyword({
  keyword: "existsInDB",
  async: true,
  validate: async (schema, data) => {
    return await checkInDatabase(data);
  }
});

В этом случае validate возвращает Promise.

Типизация и TypeScript

Ajv интегрируется с TypeScript через генерацию типов:

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

Оптимизация памяти и кэширование

Внутренний механизм включает:

  • кэш схем
  • переиспользование валидаторов
  • минимизацию создания временных объектов

Это особенно важно при высоконагруженных API.

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

Ошибки можно форматировать:

ajv.errorsText(validate.errors);

Либо анализировать вручную для построения структурированных ответов API.

Использование ссылок $ref

const schema = {
  $id: "user.json",
  type: "object",
  properties: {
    address: { $ref: "address.json" }
  }
};

Позволяет строить модульные схемы.

Практика построения схем API

Типичный подход:

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

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