В JSON Schema механизм зависимых схем позволяет описывать условия,
при которых наличие одного свойства в объекте автоматически требует
проверки дополнительных ограничений или наличия других свойств. В
библиотеке Ajv этот механизм реализуется через ключевые слова
dependentSchemas и dependentRequired,
обеспечивая строгую и декларативную валидацию сложных структур
данных.
Зависимые схемы формируют условную логику на уровне структуры объекта. В отличие от простого перечисления обязательных полей, зависимость вводит контекст: наличие одного ключа изменяет правила проверки всего объекта.
В JSON Schema различают два основных типа зависимостей:
В Ajv эти механизмы представлены следующим образом:
dependentSchemas — применение дополнительной схемы при
наличии определённого свойстваdependentRequired — требование наличия других свойств
при наличии ключевогоКлюч dependentSchemas позволяет ассоциировать свойство с
полноценной JSON Schema. Если свойство присутствует в объекте,
активируется соответствующая схема.
Пример описания банковских данных пользователя:
import Ajv from "ajv";
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
paymentMethod: { type: "string" },
cardNumber: { type: "string" },
paypalEmail: { type: "string" }
},
dependentSchemas: {
cardNumber: {
required: ["cardNumber"],
properties: {
billingAddress: { type: "string", minLength: 10 }
},
additionalProperties: false
},
paypalEmail: {
required: ["paypalEmail"],
properties: {
paypalVerified: { type: "boolean", const: true }
}
}
}
};
const validate = ajv.compile(schema);
В данной схеме наличие cardNumber автоматически включает
дополнительную проверку billingAddress. Таким образом,
структура объекта становится динамически расширяемой в зависимости от
введённых данных.
Ключ dependentRequired представляет более простую форму
зависимости, при которой наличие одного свойства требует присутствия
других свойств, без дополнительной вложенной логики.
Пример:
const schema = {
type: "object",
properties: {
username: { type: "string" },
password: { type: "string" },
otp: { type: "string" }
},
dependentRequired: {
otp: ["password"]
}
};
Здесь наличие otp невозможно без password.
В отличие от dependentSchemas, здесь отсутствует
возможность задавать сложные правила валидации — только требования
наличия ключей.
Разграничение этих механизмов принципиально важно при проектировании схем:
dependentRequired проверяет только структуру наличия
ключейdependentSchemas добавляет полноценную логическую ветку
проверкиСравнение:
| Механизм | Проверка | Гибкость |
|---|---|---|
| dependentRequired | наличие свойств | низкая |
| dependentSchemas | полная JSON Schema логика | высокая |
Ajv при компиляции схемы с зависимостями преобразует их в оптимизированное дерево проверок. Это позволяет минимизировать повторные вычисления при валидации больших объектов.
Особенности:
При включённом строгом режиме Ajv дополнительно проверяет корректность структуры зависимостей и наличие конфликтующих правил.
Зависимые схемы могут образовывать цепочки, в которых одно свойство активирует другое, создавая каскад условий.
Пример каскадной структуры:
const schema = {
type: "object",
properties: {
role: { type: "string" },
adminCode: { type: "string" },
permissions: { type: "array" }
},
dependentSchemas: {
adminCode: {
required: ["permissions"],
properties: {
permissions: {
type: "array",
minItems: 1
}
}
},
permissions: {
required: ["role"],
properties: {
role: {
const: "admin"
}
}
}
}
};
Такие конструкции позволяют описывать сложные бизнес-правила, но увеличивают риск логических циклов, которые должны контролироваться на уровне проектирования схемы.
Наиболее частые области применения:
Пример API-объекта:
const schema = {
type: "object",
properties: {
type: { enum: ["email", "sms"] },
email: { type: "string" },
phone: { type: "string" }
},
dependentSchemas: {
email: {
required: ["email"],
properties: {
email: { format: "email" }
}
},
phone: {
required: ["phone"],
properties: {
phone: { pattern: "^[0-9]+$" }
}
}
}
};
Здесь тип сообщения определяет, какие поля становятся валидными и обязательными.
В более новых версиях JSON Schema механизм зависимостей частично
пересекается с конструкцией if / then / else. В Ajv эти
подходы могут использоваться совместно, однако их семантика
различается:
Пример комбинации:
const schema = {
type: "object",
if: {
properties: { type: { const: "premium" } }
},
then: {
required: ["subscriptionId"]
},
dependentSchemas: {
subscriptionId: {
properties: {
subscriptionId: { type: "string" }
}
}
}
};
Такое сочетание позволяет отделять структурные зависимости от бизнес-логики.
При нарушении зависимых схем Ajv формирует ошибки, содержащие:
Пример типичной ошибки:
data should have required property 'billingAddress'
При использовании dependentSchemas ошибки могут быть
более глубокими, поскольку фиксируется не только отсутствие поля, но и
провал вложенной схемы.
Зависимости увеличивают сложность графа валидации. На практике это влияет на:
Оптимизации Ajv:
При проектировании схем с высокой нагрузкой рекомендуется избегать избыточных каскадных зависимостей и дублирующих условий.
Наиболее частые проблемы:
required и
dependentRequireddependentSchemas вместо более
простых конструкцийОсобенно критичны ситуации, когда одно свойство последовательно активирует другое, формируя неочевидный цикл условий, который сложно отладить.
Внутренняя модель Ajv рассматривает зависимости как граф:
При валидации объект проходит по этому графу, активируя соответствующие ветки в зависимости от присутствующих ключей.