Найти в Дзене
Анастасия Софт

Пишем строгие JSON схемы: обязательные поля, enum, паттерны и условная логика

Привет, друг! Если ты читаешь эту статью, значит, хочешь научиться создавать строгие JSON-схемы, которые не только описывают структуру данных, но и проверяют их на соответствие строгим правилам. Мы поговорим о: И сделаем это с примерами, комментариями и немного юмора, чтобы было не только полезно, но и весело. Задача: У нас есть объект пользователя, и мы хотим убедиться, что в нём всегда присутствуют поля name и email. {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
},
"required": ["name", "email"]
} 🔍 Пояснение: ✅ Пример валидных данных: { "name": "Alice", "email": "alice@example.com" } ❌ Пример невалидных данных: { "name": "Bob" } Задача: У нас есть поле status, которое может принимать только значения "active", "inactive" или "pending". {
"type": "object",
"properties": {
"status": { "type": "string", "enum": ["active", "inactive", "pending"] }
}
} 🔍 Пояснение: ✅ Пример валидных данных: { "
Оглавление

Привет, друг! Если ты читаешь эту статью, значит, хочешь научиться создавать строгие JSON-схемы, которые не только описывают структуру данных, но и проверяют их на соответствие строгим правилам. Мы поговорим о:

  • Обязательных полях
  • Перечислениях (enum)
  • Регулярных выражениях (pattern)
  • Условной логике (if, then, else)

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

1. Обязательные поля (required)

Задача: У нас есть объект пользователя, и мы хотим убедиться, что в нём всегда присутствуют поля name и email.

{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
},
"required": ["name", "email"]
}

🔍 Пояснение:

  • "type": "object" — объект.
  • "properties" — описание свойств объекта.
  • "required" — список обязательных свойств.

Пример валидных данных:

{ "name": "Alice", "email": "alice@example.com" }

Пример невалидных данных:

{ "name": "Bob" }

2. Перечисления (enum)

Задача: У нас есть поле status, которое может принимать только значения "active", "inactive" или "pending".

{
"type": "object",
"properties": {
"status": { "type": "string", "enum": ["active", "inactive", "pending"] }
}
}

🔍 Пояснение:

  • "enum" — ограничивает значение поля набором допустимых значений.

Пример валидных данных:

{ "status": "active" }

Пример невалидных данных:

{ "status": "archived" }

3. Регулярные выражения (pattern)

Задача: У нас есть поле phone, которое должно содержать номер телефона в формате +1234567890.

{
"type": "object",
"properties": {
"phone": { "type": "string", "pattern": "^\\+\\d{10}$" }
}
}

🔍 Пояснение:

  • "pattern" — проверяет, соответствует ли строка заданному регулярному выражению.

Пример валидных данных:

{ "phone": "+1234567890" }

Пример невалидных данных:

{ "phone": "1234567890" }

4. Условная логика (if, then, else)

Задача: Если поле isStudent равно true, то поле age обязательно; если isStudent равно false, то поле grade обязательно.

{
"type": "object",
"properties": {
"isStudent": { "type": "boolean" },
"age": { "type": "integer" },
"grade": { "type": "string" }
},
"required": ["isStudent"],
"if": {
"properties": { "isStudent": { "const": true } }
},
"then": {
"required": ["age"]
},
"else": {
"required": ["grade"]
}
}

🔍 Пояснение:

  • "if" — условие, проверяется, если оно истинно.
  • "then" — применяется, если условие истинно.
  • "else" — применяется, если условие ложно.

Пример валидных данных:

{ "isStudent": true, "age": 20 }

{ "isStudent": false, "grade": "A" }

Пример невалидных данных:

{ "isStudent": true, "grade": "A" }

5. Вложенные объекты и зависимости

Задача: У нас есть объект address, который содержит поле type. Если type равно "business", то поле department обязательно.

{
"type": "object",
"properties": {
"address": {
"type": "object",
"properties": {
"type": { "type": "string", "enum": ["residential", "business"] },
"department": { "type": "string" }
},
"required": ["type"],
"if": {
"properties": { "type": { "const": "business" } }
},
"then": {
"required": ["department"]
}
}
}
}

🔍 Пояснение:

  • Вложенные объекты описываются через "properties".
  • Условная логика применяется внутри вложенных объектов.

Пример валидных данных:

{ "address": { "type": "business", "department": "HR" } }

Пример невалидных данных:

{ "address": { "type": "business" } }

6. Использование allOf, anyOf, oneOf

Задача: У нас есть объект, который должен соответствовать всем схемам из allOf, хотя бы одной из схем из anyOf или ровно одной из схем из oneOf.

{
"type": "object",
"allOf": [
{ "properties": { "name": { "type": "string" } } },
{ "properties": { "age": { "type": "integer" } } }
]
}

🔍 Пояснение:

  • "allOf" — объект должен соответствовать всем схемам.
  • "anyOf" — объект должен соответствовать хотя бы одной схеме.
  • "oneOf" — объект должен соответствовать ровно одной схеме.

Пример валидных данных:

{ "name": "Alice", "age": 30 }

Пример невалидных данных:

{ "name": "Bob" }

7. Уникальные элементы в массиве (uniqueItems)

Задача: Убедиться, что массив tags не содержит повторяющихся значений.

{
"type": "object",
"properties": {
"tags": {
"type": "array",
"items": { "type": "string" },
"uniqueItems": true
}
},
"required": ["tags"]
}

🔍 Пояснение:

  • "uniqueItems": true — гарантирует, что все значения в массиве уникальны.

Пример валидных данных:

{ "tags": ["api", "json", "schema"] }

Пример невалидных данных:

{ "tags": ["json", "json"] }

8. Валидация по длине строки (minLength, maxLength)

Задача: Поле password должно содержать от 8 до 20 символов.

{
"type": "object",
"properties": {
"password": {
"type": "string",
"minLength": 8,
"maxLength": 20
}
},
"required": ["password"]
}

🔍 Пояснение:

  • minLength и maxLength — ограничивают количество символов в строке.

Пример:

{ "password": "s3cr3t123" }

Пример:

{ "password": "123" }

9. Зависимости между полями (dependencies / dependentRequired)

Задача: Если указано поле creditCard, то обязательно должно быть и billingAddress.

{
"type": "object",
"properties": {
"creditCard": { "type": "string" },
"billingAddress": { "type": "string" }
},
"dependentRequired": {
"creditCard": ["billingAddress"]
}
}

🔍 Пояснение:

  • "dependentRequired" — если указано одно поле, другие становятся обязательными.

Пример:

{ "creditCard": "4111111111111111", "billingAddress": "123 Main St" }

Пример:

{ "creditCard": "4111111111111111" }

10. Комбинирование типов (type: [ ... ])

Задача: Поле id может быть как строкой, так и числом.

{
"type": "object",
"properties": {
"id": {
"type": ["string", "integer"]
}
},
"required": ["id"]
}

🔍 Пояснение:

  • Указание массива типов означает, что поле может быть любым из указанных типов.

Примеры:

{ "id": "abc123" }

{ "id": 123 }

Пример невалидных данных:

{ "id": true }

🎁 Бонус: валидатор дат и времён

Задача: Проверка корректности ISO 8601 даты (YYYY-MM-DD) и времени (HH:MM:SS).

{
"type": "object",
"properties": {
"startDate": {
"type": "string",
"format": "date"
},
"startTime": {
"type": "string",
"pattern": "^([01]\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?$"
}
},
"required": ["startDate", "startTime"]
}

🔍 Пояснение:

  • "format": "date" — встроенный формат в JSON Schema (если поддерживается валидатором).
  • "pattern" для времени — проверяет, что оно в формате HH:MM или HH:MM:SS.

Пример:

{
"startDate": "2025-05-07",
"startTime": "14:30:00"
}

✨ Заключение

Ты только что научился:

✅ делать поля обязательными,

✅ использовать enum,

✅ применять регулярные выражения,

✅ настраивать условную логику,

✅ управлять зависимостями и вложенностью,

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

JSON Schema — это как скрупулёзный контролёр, который знает, что и где должно быть. Но ты теперь умеешь им управлять 💼😄