Обязательные свойства в JSON Schema определяются ключевым словом
required, которое используется внутри описания объекта и
задаёт перечень полей, без которых структура считается невалидной. В Ajv
эта проверка выполняется на этапе валидации и приводит к формированию
ошибки, если хотя бы одно из указанных свойств отсутствует в проверяемом
объекте.
Ключевое слово required представляет собой массив строк,
каждая из которых соответствует имени свойства объекта. Эти имена должны
присутствовать непосредственно в проверяемом объекте, иначе объект не
проходит валидацию.
Базовая структура:
{
"type": "object",
"properties": {
"id": { "type": "number" },
"name": { "type": "string" }
},
"required": ["id", "name"]
}
В данной схеме объект обязан содержать оба свойства: id
и name. Отсутствие любого из них приводит к ошибке
валидации.
Ajv интерпретирует required строго: наличие свойства
проверяется по ключу объекта, а не по значению и не по типу. Значение
null, пустая строка или 0 считаются валидными
значениями, если ключ существует.
При валидации Ajv формирует детализированное сообщение об ошибке, указывая конкретное отсутствующее свойство.
Пример:
const Ajv = require("ajv");
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
email: { type: "string" },
age: { type: "number" }
},
required: ["email", "age"]
};
const validate = ajv.compile(schema);
const data = {
email: "user@example.com"
};
console.log(validate(data));
console.log(validate.errors);
Результат валидации будет отрицательным, а ошибка укажет, что
отсутствует свойство age.
Типичная структура ошибки Ajv:
{
"instancePath": "",
"schemaPath": "#/required",
"keyword": "required",
"params": {
"missingProperty": "age"
},
"message": "must have required property 'age'"
}
Ключевое поведение required заключается в том, что оно
проверяет только наличие ключа, но не его содержимое.
Следующий объект считается валидным:
{
email: "",
age: null
}
Даже если значения пустые или неинформативные, ключи присутствуют,
следовательно, правило required выполняется.
Каждый уровень объекта имеет собственный контекст обязательных
свойств. required применяется локально к конкретному
объекту, а не глобально ко всей структуре.
Пример:
{
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"id": { "type": "number" },
"profile": {
"type": "object",
"properties": {
"nickname": { "type": "string" }
},
"required": ["nickname"]
}
},
"required": ["id", "profile"]
}
}
}
Здесь:
user обязан содержать id и
profileprofile обязан содержать
nicknameОшибки будут формироваться на том уровне, где нарушено правило, что позволяет точно локализовать проблему в структуре данных.
Если required указан как пустой массив, обязательные
свойства отсутствуют:
{
"type": "object",
"properties": {
"a": { "type": "string" }
},
"required": []
}
Такой объект всегда валиден с точки зрения обязательных полей, даже
если свойства определены в properties.
Если ключ required полностью отсутствует, все свойства
считаются необязательными. Это часто используется для частично
заполняемых структур данных или форм с гибкой валидацией.
{
"type": "object",
"properties": {
"title": { "type": "string" },
"description": { "type": "string" }
}
}
В этом случае объект может содержать любое подмножество свойств или не содержать их вовсе.
required часто используется совместно с
additionalProperties, что позволяет контролировать не
только обязательные поля, но и запрет лишних данных.
{
"type": "object",
"properties": {
"id": { "type": "number" }
},
"required": ["id"],
"additionalProperties": false
}
Такой подход задаёт строгую структуру: объект обязан содержать
id и не может содержать других свойств.
Ajv проверяет эти условия независимо: отсутствие обязательного поля вызывает одну ошибку, лишние поля — другую.
В более сложных схемах обязательные свойства могут зависеть от
условий. Ajv поддерживает конструкцию if / then / else,
которая позволяет изменять требования required в
зависимости от данных.
Пример:
{
"type": "object",
"properties": {
"type": { "type": "string" },
"email": { "type": "string" },
"phone": { "type": "string" }
},
"if": {
"properties": { "type": { "const": "email" } }
},
"then": {
"required": ["email"]
},
"else": {
"required": ["phone"]
}
}
В этом случае обязательные свойства зависят от значения поля
type. Ajv последовательно применяет условия и динамически
изменяет набор обязательных ключей.
В схемах с объединениями (allOf, anyOf,
oneOf) несколько required могут накладываться
одновременно.
Пример с allOf:
{
"allOf": [
{
"type": "object",
"required": ["id"]
},
{
"type": "object",
"required": ["name"]
}
]
}
Итоговая структура требует наличия обоих свойств: id и
name. Ajv объединяет ограничения всех подсхем.
В случае oneOf поведение может приводить к конфликтам,
если разные схемы требуют разные наборы обязательных полей, что делает
объект неоднозначным для проверки.
В режиме strict Ajv может выдавать предупреждения о
потенциально некорректных схемах, например:
required без соответствующих
propertiesrequiredХотя это не всегда приводит к ошибке выполнения, такие предупреждения помогают выявлять логические ошибки в схемах до этапа валидации данных.
Одной из частых проблем является несоответствие имен свойств в
required и properties.
Пример некорректной схемы:
{
"type": "object",
"properties": {
"userId": { "type": "number" }
},
"required": ["userid"]
}
Здесь ошибка заключается в регистре символов. Ajv не выполняет
нормализацию ключей, поэтому userId и userid
считаются разными свойствами.
Другой распространённый случай — забытое обновление
required при изменении структуры объекта, что приводит к
рассинхронизации схемы и реальных данных.
Если сам объект отсутствует или имеет тип, отличный от
object, проверка required не выполняется
напрямую, а сначала срабатывает проверка type.
{
"type": "object",
"required": ["id"]
}
При передаче null или строки ошибка будет связана с
типом, а не с отсутствием обязательных свойств. Только после успешной
проверки типа выполняется анализ required.
Использование обязательных свойств формирует структуру контракта
данных. В Ajv схемы с required часто используются для:
Чем жёстче определён набор обязательных полей, тем меньше допустимых вариаций входных данных, что снижает вероятность некорректной обработки, но увеличивает требования к источнику данных.
Важно учитывать, что required не подставляет значения
автоматически. Даже если свойство имеет default, оно не
будет создано, если отсутствует ключ. В Ajv автоматическое добавление
значений требует включения соответствующих опций и плагинов, но само по
себе required не влияет на модификацию данных.
Также наличие nullable или
type: ["string", "null"] не отменяет обязательность
свойства: ключ должен существовать, даже если его значение
null.