Миграция между версиями

Переход между основными версиями библиотеки Ajv сопровождается изменениями в поведении валидатора, расширением поддержки спецификаций JSON Schema и переработкой внутренних оптимизаций компиляции схем. На практике миграция чаще всего затрагивает переходы между версиями v6 → v7 → v8, где каждая ветка приносит как функциональные улучшения, так и изменения, нарушающие обратную совместимость.

Ключевая сложность миграции заключается в том, что Ajv активно следует изменениям стандартов JSON Schema (Draft 07, 2019-09, 2020-12), а также пересматривает собственные расширения. Поэтому код, корректно работавший в одной версии, может требовать пересмотра опций, подключаемых модулей и структуры схем.


Переход с v6 на v7: отказ от устаревших расширений

Основное изменение связано с удалением и переработкой поведения по умолчанию.

Удаление поддержки некоторых устаревших возможностей

В v7 были удалены или вынесены в плагины:

  • jsonPointers как основной механизм работы с ошибками
  • часть неформализованных расширений форматов
  • устаревшие keyword-обработчики

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

Изменение поведения строгого режима

Строгий режим стал более агрессивным:

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

Это приводит к необходимости предварительной валидации самих схем перед использованием.


Форматы и плагины как обязательные зависимости

Начиная с v7, многие встроенные форматы были вынесены из ядра библиотеки.

Переход на ajv-formats

Ранее встроенные проверки:

  • email
  • uri
  • date-time

перестали быть частью ядра и требуют подключения пакета ajv-formats.

Пример изменения архитектуры:

import Ajv from "ajv";
import addFormats from "ajv-formats";

const ajv = new Ajv();
addFormats(ajv);

Без этого шага схемы, использующие стандартные форматы, начинают возвращать ошибки валидации.


Переход с v7 на v8: оптимизация и унификация стандарта

Версия v8 ориентирована на поддержку JSON Schema 2020-12 и упрощение внутренней модели компиляции.

Удаление legacy-режимов

В v8 полностью исключены:

  • частичная поддержка устаревших draft-версий без явного указания
  • неявное поведение для неизвестных ключей
  • автоматическое преобразование типов без настройки

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


Изменения в создании экземпляра валидатора

В v8 пересмотрена структура инициализации:

import Ajv from "ajv";

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

Важные изменения поведения:

  • allErrors теперь влияет на производительность сильнее, чем в предыдущих версиях
  • strict стал фактическим стандартом и рекомендуется оставлять включённым
  • опции, связанные с форматами и коэрцией типов, требуют явного объявления

Изменение обработки типов и coercion

Одно из наиболее частых источников проблем при миграции — изменение поведения coerceTypes.

v6/v7

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

Типы могли преобразовываться автоматически при валидации.

v8

Поведение стало более предсказуемым:

  • преобразование выполняется только в строго определённых случаях
  • сложные типы (например, массивы и объекты) больше не приводятся автоматически
  • требуется явное указание правил приведения

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


Изменения в обработке defaults

Опция useDefaults также была переработана.

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

Пример:

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

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


Обновление ключевых слов JSON Schema

С переходом между версиями усилилась привязка к спецификации.

Изменения включают:

  • строгую валидацию const и enum
  • корректную обработку if/then/else
  • пересмотр логики oneOf, anyOf, allOf

Особенно заметно изменение поведения oneOf, где ранее допускались более гибкие совпадения, а теперь требуется строгое соответствие только одной ветке.


Ошибки и их структура

В новых версиях изменён формат массива ошибок.

Ранее:

ajv.errors

мог содержать менее структурированную информацию.

Теперь:

  • каждая ошибка содержит instancePath
  • добавлены поля schemaPath и keyword
  • улучшена трассировка вложенных схем

Это упрощает диагностику, но требует адаптации обработчиков ошибок.


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

Внутренний механизм компиляции был существенно переработан:

  • схемы кэшируются более агрессивно
  • повторная компиляция минимизируется
  • оптимизированы ветвления if/then

Однако при миграции возможны ситуации, когда:

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

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

Миграция почти всегда сопровождается обновлением зависимостей:

  • ajv-formats для стандартных форматов
  • ajv-errors для кастомных сообщений
  • сторонние keyword-плагины

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


Типовые проблемы при миграции

На практике чаще всего возникают следующие ситуации:

  • схемы, написанные под Draft 04/06, начинают давать ошибки строгой проверки
  • отсутствующие форматы требуют явного подключения модулей
  • поведение coerceTypes отличается от ожидаемого
  • кастомные keyword требуют переписывания под новый API регистрации

Совместимость схем и стратегий перехода

Для больших проектов применяется поэтапная стратегия:

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

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