JSON Schema: What It Is and How to Use It
Learn JSON Schema from scratch. Understand types, constraints, composition keywords, $ref, and see a complete practical example for API validation.
Что такое JSON Schema?
JSON Schema — это словарь, который позволяет описывать структуру данных JSON. Рассматривайте это как контракт: он определяет, какие поля должен содержать документ JSON, какие типы должны быть у этих полей и какие ограничения они должны удовлетворять. Когда документ соответствует своей схеме, он является действительным. Когда нет, валидатор точно указывает, что пошло не так.
Это важно, потому что сам JSON структурно допускает много вариантов. Ничто в спецификации JSON не мешает API возвращать строку, когда вы ожидаете число, или пропускать обязательное поле. JSON Schema закрывает этот пробел.
Почему JSON Schema важен
- Контракты API. Определите точно, что ожидает и возвращает ваш API. Команды клиента и сервера могут независимо проверять полезные нагрузки.
- Валидация данных. Ловите неправильно оформленные данные на границе — в формах, полезных нагрузках вебхуков, конфигурационных файлах или записях в базе данных.
- Документация. Схема — это документация, читаемая машиной. Инструменты могут генерировать документацию для человека, формы и даже макетные данные на ее основе.
- Генерация кода. Генерируйте интерфейсы TypeScript, структуры Go или классы данных Python непосредственно из вашей схемы.
Основы: тип, свойства, обязательные
Каждая JSON Schema начинается с type. Это говорит валидатору, какой тип значения ожидать на верхнем уровне:
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Полное имя пользователя"
},
"age": {
"type": "integer",
"description": "Возраст в годах"
}
},
"required": ["name"]
}
Эта схема говорит: "Я ожидаю объект JSON с полем name (строка, обязательное) и необязательным полем age (целое число)." Любой объект, у которого отсутствует name или который предоставляет нестроковое значение для name, является недействительным.
Все типы JSON Schema
JSON Schema поддерживает семь примитивных типов. Вот каждый из них с минимальным примером схемы:
| Тип | Допустимые значения | Пример схемы |
|---|---|---|
string | "hello", "" | {"type": "string"} |
number | 3.14, -1, 0 | {"type": "number"} |
integer | 42, -7 | {"type": "integer"} |
boolean | true, false | {"type": "boolean"} |
null | null | {"type": "null"} |
object | {"key": "value"} | {"type": "object", "properties": {...}} |
array | [1, 2, 3] | {"type": "array", "items": {...}} |
Объекты в деталях
Используйте properties, чтобы определить ожидаемые поля, required, чтобы перечислить обязательные, и additionalProperties, чтобы контролировать, разрешены ли дополнительные поля:
{
"type": "object",
"properties": {
"id": { "type": "integer" },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "email"],
"additionalProperties": false
}
Установка additionalProperties: false отклоняет любой объект, содержащий ключи, не перечисленные в properties. Это полезно для строгих контрактов API.
Массивы в деталях
Используйте items, чтобы определить, как должен выглядеть каждый элемент, и minItems / maxItems, чтобы ограничить длину:
{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10,
"uniqueItems": true
}
Это принимает массив из 1 до 10 уникальных строк. Пустой массив или массив с дубликатами не пройдет валидацию.
Ограничения и ключевые слова валидации
Помимо базовых типов, JSON Schema предоставляет тонкие ограничения для каждого типа:
Ограничения строк
| Ключевое слово | Описание | Пример |
|---|---|---|
minLength | Минимальное количество символов | "minLength": 1 |
maxLength | Максимальное количество символов | "maxLength": 255 |
pattern | Регулярное выражение, которому должна соответствовать строка | "pattern": "^[A-Z]{2}\\\\d{4}$" |
format | Семантический подсказка формата | "format": "email" |
enum | Допустимые значения | "enum": ["active", "inactive"] |
Ограничения чисел
| Ключевое слово | Описание | Пример |
|---|---|---|
minimum | Значение должно быть >= этому | "minimum": 0 |
maximum | Значение должно быть <= этому | "maximum": 100 |
exclusiveMinimum | Значение должно быть > этому | "exclusiveMinimum": 0 |
exclusiveMaximum | Значение должно быть < этому | "exclusiveMaximum": 1000 |
multipleOf | Значение должно делиться на это | "multipleOf": 0.01 |
Комбинирование схем: allOf, anyOf, oneOf, not
Ключевые слова композиции позволяют вам строить сложные схемы из более простых:
- allOf — Данные должны быть действительными по всем перечисленным схемам. Используется для комбинирования нескольких ограничений или расширения базовой схемы.
- anyOf — Данные должны быть действительными по по крайней мере одной из перечисленных схем. Полезно для полей, которые принимают несколько форматов.
- oneOf — Данные должны быть действительными по ровно одной из перечисленных схем. Хорошо подходит для дискриминированных объединений.
- not — Данные не должны быть действительными по данной схеме.
{
"oneOf": [
{
"type": "object",
"properties": {
"type": { "const": "email" },
"address": { "type": "string", "format": "email" }
},
"required": ["type", "address"]
},
{
"type": "object",
"properties": {
"type": { "const": "phone" },
"number": { "type": "string", "pattern": "^\\\\+?[0-9]{7,15}$" }
},
"required": ["type", "number"]
}
]
}
Эта схема принимает либо контакт по электронной почте, либо контакт по телефону, но не оба — чистый способ моделирования помеченных объединений.
Повторное использование с $ref
Схемы быстро становятся повторяющимися. Ключевое слово $ref позволяет вам ссылаться на повторно используемое определение:
{
"type": "object",
"properties": {
"billing_address": { "$ref": "#/$defs/address" },
"shipping_address": { "$ref": "#/$defs/address" }
},
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^[0-9]{5}(-[0-9]{4})?$" }
},
"required": ["street", "city", "zip"]
}
}
}
Оба billing_address и shipping_address имеют одинаковую структуру без дублирования. Раздел $defs (называемый definitions в более ранних черновиках) — это обычное место для хранения повторно используемых схем.
Полный пример: Валидация регистрации пользователя
Вот схема для валидации полезной нагрузки регистрации пользователя. Она использует большинство функций, которые мы рассмотрели:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UserRegistration",
"description": "Схема для конечной точки POST /api/register",
"type": "object",
"properties": {
"username": {
"type": "string",
"minLength": 3,
"maxLength": 30,
"pattern": "^[a-zA-Z0-9_]+$",
"description": "Алфавитно-цифровое имя пользователя, 3-30 символов"
},
"email": {
"type": "string",
"format": "email",
"maxLength": 254
},
"password": {
"type": "string",
"minLength": 8,
"maxLength": 128,
"description": "Не менее 8 символов"
},
"age": {
"type": "integer",
"minimum": 13,
"maximum": 150
},
"role": {
"type": "string",
"enum": ["user", "moderator"],
"default": "user"
},
"acceptedTerms": {
"type": "boolean",
"const": true
},
"tags": {
"type": "array",
"items": { "type": "string", "maxLength": 20 },
"maxItems": 5,
"uniqueItems": true
}
},
"required": ["username", "email", "password", "acceptedTerms"],
"additionalProperties": false
}
Обратите внимание, как каждое поле имеет четкие, обязательные ограничения. Валидатор отклонит имя пользователя из 2 символов, возраст ниже 13, дублирующиеся теги или любые дополнительные поля, не перечисленные в схеме.
Попробуйте сами: Вставьте любой JSON и автоматически сгенерируйте схему с помощью нашего Генератора JSON Schema.
JSON Schema в реальном мире
OpenAPI / Swagger
OpenAPI использует JSON Schema (с некоторыми расширениями) для определения тел запросов, форматов ответов и параметров запроса. Каждый блок schema в спецификации OpenAPI является JSON Schema. Если вы пишете документацию OpenAPI, вы уже пишете JSON Schema.
Валидация форм
Библиотеки, такие как react-jsonschema-form и ajv (самый быстрый валидатор JSON Schema для JavaScript), используют схемы для генерации и валидации форм во время выполнения. Определите свою схему один раз, и как бэкэнд, так и фронтэнд могут проверять по одним и тем же правилам.
Схемы баз данных
MongoDB поддерживает валидацию JSON Schema на уровне коллекции. Вы можете установить валидатор $jsonSchema, который отклоняет любой документ, не соответствующий вашей схеме при вставке или обновлении.
Конфигурационные файлы
VS Code, ESLint и многие другие инструменты используют JSON Schema для валидации своих конфигурационных файлов. То автозаполнение, которое вы получаете при редактировании tsconfig.json? Оно работает благодаря JSON Schema.
Сравнение версий черновиков
JSON Schema развивался через несколько черновиков. Вот те, с которыми вы столкнетесь:
| Черновик | Год | Ключевые дополнения | Статус |
|---|---|---|---|
| Draft-04 | 2013 | Основной словарь, $ref, базовые типы | Устаревший (по-прежнему широко используется) |
| Draft-06 | 2017 | const, contains, propertyNames | Устаревший |
| Draft-07 | 2018 | if/then/else, readOnly, writeOnly | Широко поддерживается |
| 2019-09 | 2019 | $defs, unevaluatedProperties, dependentRequired | Поддерживается основными валидаторами |
| 2020-12 | 2020 | prefixItems (заменяет валидацию кортежей), динамический $ref | Текущий / рекомендуемый |
Для новых проектов используйте 2020-12. Если вам нужна максимальная совместимость с существующими инструментами, Draft-07 является безопасным выбором — он имеет почти универсальную поддержку библиотек.
Общие ошибки, которых следует избегать
- Забывать о
required. Свойства, определенные вproperties, по умолчанию являются необязательными. Если поле должно присутствовать, перечислите его вrequired. - Смешивать
numberиinteger.numberпринимает десятичные;integer— нет. Используйтеintegerдля идентификаторов, счетчиков и других целых чисел. - Слишком ранняя переоценка ограничений. Начните с минимальной схемы, которая ловит реальные ошибки. Вы всегда можете ужесточить ограничения позже — ослабление их является нарушением совместимости.
- Не использовать
$ref. Дублирование одной и той же подсхемы в нескольких местах — это кошмар для обслуживания. Извлекайте общие структуры в$defs. - Игнорировать валидацию
format. По умолчанию большинство валидаторов рассматриваютformatкак аннотацию, а не как ограничение. Вам нужно явно включить валидацию формата (например,ajv.addFormat()или передав{ validateFormats: true }).
Попробуйте сами: Сгенерируйте схему из любого образца JSON с помощью нашего Генератора JSON Schema, а затем настройте ограничения в соответствии с вашими требованиями.