Откат изменений

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


Откат добавленных JSON Schema

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

Удаление ранее добавленной схемы выполняется через removeSchema, что фактически возвращает состояние реестра к моменту до регистрации этой схемы.

import Ajv from "ajv";

const ajv = new Ajv();

const schemaV1 = {
  $id: "user-schema",
  type: "object",
  properties: {
    name: { type: "string" }
  },
  required: ["name"]
};

ajv.addSchema(schemaV1);

// Откат схемы
ajv.removeSchema("user-schema");

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

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


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

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

const validate = ajv.compile(schemaV1);

Даже если схема удалена через removeSchema, переменная validate продолжит работать, так как содержит уже скомпилированную функцию. Это означает, что откат схемы не влияет на уже созданные валидаторы.

Для полного отката поведения необходимо:

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

Откат пользовательских ключевых слов

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

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

Удаление выполняется через removeKeyword:

ajv.removeKeyword("isPositive");

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


Откат пользовательских форматов

Форматы в Ajv используются для валидации строковых значений (например, email, uri и т.д.). Добавление кастомных форматов осуществляется через addFormat.

ajv.addFormat("phone", {
  type: "string",
  validate: (value) => /^\+\d{10,15}$/.test(value)
});

Удаление формата возможно через removeFormat:

ajv.removeFormat("phone");

При откате формата необходимо учитывать, что:

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

Полный сброс состояния экземпляра Ajv

В Ajv нет встроенного метода «reset», поэтому полный откат состояния достигается созданием нового экземпляра валидатора.

const ajv = new Ajv();

// при необходимости полного отката
const ajvNew = new Ajv();

Такой подход гарантирует:

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

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


Работа с кэшем скомпилированных схем

Ajv активно использует кэширование для ускорения компиляции схем. Этот механизм влияет на процесс отката, поскольку:

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

Контроль кэша осуществляется через параметры конфигурации экземпляра:

const ajv = new Ajv({
  cache: false
});

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


Версионирование схем как стратегия отката

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

const schemaV1 = { $id: "user-v1", type: "object", properties: { name: { type: "string" } } };
const schemaV2 = { $id: "user-v2", type: "object", properties: { name: { type: "string" }, age: { type: "number" } } };

ajv.addSchema(schemaV1);
ajv.addSchema(schemaV2);

Откат в таком случае выполняется не удалением логики, а переключением на нужную версию схемы:

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

Удаление устаревших версий становится отдельной операцией очистки, а не частью отката.


Откат при миграции draft-версий JSON Schema

Ajv поддерживает различные версии спецификации JSON Schema (draft-07, draft-2019-09, draft-2020-12). Изменение draft-версии может приводить к несовместимости схем.

const ajv = new Ajv({
  schemaId: "auto"
});

При смене draft-версии возможны ситуации, когда:

  • ранее валидные схемы становятся некорректными
  • изменяется поведение операторов (if/then/else, contains, dependentRequired)
  • требуется перекомпиляция всех схем

Откат в этом контексте фактически означает возврат к предыдущему экземпляру Ajv с нужной версией спецификации.


Откат изменений в условиях горячей перезагрузки схем

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

  • регистрация новых схем с временными идентификаторами
  • сохранение предыдущих схем в памяти
  • переключение ссылок на активную версию схемы
const schemaRegistry = {
  active: schemaV2,
  previous: schemaV1
};

// откат
schemaRegistry.active = schemaRegistry.previous;

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


Типичные проблемы при откате изменений

При возврате к предыдущему состоянию часто возникают следующие несоответствия:

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

Эти эффекты делают невозможным частичный откат без учёта всей цепочки зависимостей внутри экземпляра Ajv.


Согласованность состояния валидатора

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

  • схемами
  • форматами
  • ключевыми словами
  • кэшем компиляции
  • ссылками на скомпилированные функции

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