При валидации JSON-данных в схемах JSON Schema одной из ключевых задач является контроль структуры объекта. Помимо проверки обязательных полей и типов значений, важно ограничивать появление неожиданных свойств, которые не предусмотрены контрактом данных. В Ajv это поведение реализуется через механизм запрета дополнительных свойств.
В спецификации JSON Schema за контроль «лишних» полей отвечает ключ
additionalProperties. Его поведение зависит от
значения:
true — разрешены любые дополнительные поляfalse — запрещены все свойства, не описанные в
properties или patternPropertiesПростейший пример ограничения:
{
"type": "object",
"properties": {
"id": { "type": "number" },
"name": { "type": "string" }
},
"additionalProperties": false
}
При такой схеме объект:
{
"id": 1,
"name": "Alice",
"role": "admin"
}
будет считаться невалидным из-за поля role.
Библиотека Ajv строго следует спецификации JSON Schema, но добавляет
собственные режимы строгой проверки и оптимизации. При использовании
additionalProperties: false выполняется проверка всех
ключей объекта на соответствие описанным в схеме.
Внутренне Ajv:
propertiespatternPropertiesТипичная ошибка выглядит так:
data should NOT have additional properties 'role'
В современных версиях Ajv важную роль играет режим
strict, который усиливает контроль над схемами. В контексте
запрета дополнительных свойств он позволяет выявлять ошибки
проектирования схем:
При включённом строгом режиме Ajv предупреждает о потенциально
некорректных конструкциях, связанных с
additionalProperties, особенно если они могут привести к
неоднозначной валидации.
Начиная с JSON Schema Draft 2019-09, появился более универсальный
механизм — unevaluatedProperties. В Ajv он также
поддерживается и часто используется в сложных композициях схем.
Различие:
additionalProperties проверяет только свойства, не
описанные напрямую в properties и
patternPropertiesunevaluatedProperties учитывает все свойства, которые
не были «поглощены» другими частями схемы (например, allOf,
oneOf, if/then/else)Пример:
{
"type": "object",
"properties": {
"a": { "type": "string" }
},
"allOf": [
{
"properties": {
"b": { "type": "number" }
}
}
],
"unevaluatedProperties": false
}
В такой конструкции additionalProperties уже
недостаточно, поскольку свойства могут появляться через композиции.
Запрет дополнительных свойств распространяется рекурсивно на вложенные структуры. Например:
{
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"id": { "type": "number" }
},
"additionalProperties": false
}
},
"additionalProperties": false
}
Здесь ограничения действуют на двух уровнях:
user также строго ограничен полем
idAjv обрабатывает такие схемы по дереву, формируя отдельные проверки для каждого уровня вложенности.
Помимо простого запрета дополнительных свойств Ajv предоставляет механизм автоматического удаления лишних полей.
Опция removeAdditional может принимать значения:
false — ничего не удаляетсяtrue — удаляются все дополнительные свойства"all" — удаляются даже свойства, не описанные в
properties, включая вложенные структурыПример использования:
const ajv = new Ajv({ removeAdditional: "all" })
Схема:
{
"type": "object",
"properties": {
"id": { "type": "number" }
},
"additionalProperties": false
}
Вход:
{
"id": 1,
"temp": 123
}
Результат после валидации:
{
"id": 1
}
Удаление происходит до завершения валидации, что влияет на итоговый объект.
patternProperties изменяет поведение запрета
дополнительных свойств, так как расширяет набор допустимых ключей через
регулярные выражения.
Пример:
{
"type": "object",
"patternProperties": {
"^x-": { "type": "string" }
},
"additionalProperties": false
}
Здесь разрешены все свойства, начинающиеся с x-,
например:
{
"x-meta": "value",
"x-id": "123"
}
При этом любые другие ключи будут отклонены.
Ajv при валидации объединяет:
propertiespatternPropertiesadditionalPropertiesВ реальных схемах часто встречаются следующие проблемы:
{
"allOf": [
{
"properties": {
"a": { "type": "string" }
}
},
{
"additionalProperties": false
}
]
}
В таком случае может возникнуть ситуация, когда свойства,
определённые в разных частях allOf, не учитываются
корректно без использования unevaluatedProperties.
Если забыть определить properties, но указать
additionalProperties: false, объект будет полностью
запрещён:
{
"type": "object",
"additionalProperties": false
}
Любой ключ приведёт к ошибке, включая пустой объект с динамическими расширениями.
При интеграции внешних API часто появляются поля, не описанные в схеме. В режиме строгого запрета это приводит к массовым ошибкам валидации, особенно если API возвращает метаданные или служебные поля.
Ajv оптимизирует проверку дополнительных свойств:
Тем не менее, при глубоко вложенных объектах с большим числом свойств
проверка additionalProperties: false может становиться
заметной по стоимости, особенно в сочетании с
patternProperties.
Использование запрета дополнительных свойств формирует строгий контракт данных:
Ajv в таком режиме используется как инструмент обеспечения жёсткой схемы данных, где любое отклонение структуры считается ошибкой, а не игнорируется.
В схемах, которые отражают типы из TypeScript,
additionalProperties: false эквивалентен индексной
сигнатуре с запретом расширений. Это особенно важно при генерации схем
из типов, где требуется сохранить строгую структуру без лишних
ключей.
Ajv возвращает структурированные ошибки, содержащие:
instancePath)Пример:
{
"instancePath": "",
"message": "must NOT have additional properties",
"params": {
"additionalProperty": "role"
}
}
Это позволяет точно определить источник нарушения структуры.
Запрет дополнительных свойств в Ajv формирует жёсткую модель валидации, в которой:
unevaluatedPropertiesТакой подход делает схемы предсказуемыми и строгими, особенно в системах, где важна точность контракта данных между компонентами.