JSON Schema: как валидировать данные и описывать API
JSON Schema — язык описания структуры и ограничений JSON-данных. Схема задаёт типы полей, обязательность, диапазоны значений, форматы строк и вложенные объекты. На основе схемы можно валидировать входящие данные, генерировать документацию и типы для TypeScript, описывать контракты API. В этой статье разберём версии JSON Schema (draft-07, 2020-12), основные ключевые слова, практические примеры, библиотеки и интеграцию с OpenAPI.
Для проверки JSON по схеме используйте JSON Schema Validator на reChecker.
Что такое JSON Schema
JSON Schema — это сам по себе JSON-документ, описывающий допустимую структуру других JSON-документов. Схема отвечает на вопросы: какие поля обязательны, какие типы у значений, какие ограничения (минимум, максимум, паттерны, форматы).
Версии: draft-07 и 2020-12
- draft-07 (JSON Schema Draft 7) — стабильная, широко поддерживаемая версия. Используется в OpenAPI 3.0, многих библиотеках.
- 2020-12 (JSON Schema 2020-12) — актуальная версия с улучшениями:
$dynamicRef,$anchor, условные схемы, улучшенная работа сnull.
В $schema указывают версию:
{
"$schema": "https://json-schema.org/draft/2020-12/schema"
}
или для draft-07:
{
"$schema": "http://json-schema.org/draft-07/schema#"
}
Основные ключевые слова
type
Тип значения: string, number, integer, boolean, array, object, null.
{
"type": "string"
}
Несколько типов — массив:
{
"type": ["string", "null"]
}
properties и additionalProperties
properties — описание полей объекта. additionalProperties — разрешать ли поля, не перечисленные в properties.
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"additionalProperties": false
}
required
Массив обязательных полей:
{
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"password": { "type": "string", "minLength": 8 }
},
"required": ["email", "password"]
}
string: minLength, maxLength, pattern, format
{
"type": "string",
"minLength": 1,
"maxLength": 100,
"pattern": "^[a-zA-Z0-9_]+$",
"format": "email"
}
Популярные format: email, uri, date, date-time, uuid, ipv4, ipv6.
number/integer: minimum, maximum, exclusiveMinimum, exclusiveMaximum
{
"type": "integer",
"minimum": 0,
"maximum": 120,
"exclusiveMaximum": true
}
array: items, minItems, maxItems
{
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10
}
Для кортежей (разные типы по позициям) — массив в items:
{
"type": "array",
"items": [
{ "type": "string" },
{ "type": "integer" }
]
}
enum
Допустимые значения:
{
"type": "string",
"enum": ["draft", "published", "archived"]
}
$ref и $defs
Переиспользование схем:
{
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
},
"type": "object",
"properties": {
"shipping": { "$ref": "#/$defs/address" },
"billing": { "$ref": "#/$defs/address" }
}
}
Практические примеры
Валидация пользователя
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"email": { "type": "string", "format": "email" },
"name": { "type": "string", "minLength": 1, "maxLength": 100 },
"age": { "type": "integer", "minimum": 0, "maximum": 150 },
"role": { "type": "string", "enum": ["user", "admin", "moderator"] }
},
"required": ["email", "name"],
"additionalProperties": false
}
API-контракт (запрос)
{
"type": "object",
"properties": {
"query": { "type": "string" },
"page": { "type": "integer", "minimum": 1, "default": 1 },
"limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
},
"required": ["query"]
}
Вложенные объекты
{
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"name": { "type": "string" },
"address": {
"type": "object",
"properties": {
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^[0-9]{5,6}$" }
}
}
}
}
}
}
Библиотеки и инструменты
Ajv (JavaScript/TypeScript)
Популярная библиотека валидации:
import Ajv from 'ajv';
const ajv = new Ajv();
const validate = ajv.compile(schema);
const valid = validate(data);
if (!valid) console.log(validate.errors);
Python: jsonschema
import jsonschema
jsonschema.validate(instance=data, schema=schema)
OpenAPI и JSON Schema
OpenAPI 3.x использует подмножество JSON Schema для описания тел запросов и ответов. Схемы в components.schemas — это JSON Schema с небольшими отличиями. Инструменты вроде Swagger UI и генераторы клиентов опираются на эти схемы. При миграции с OpenAPI 2.0 (Swagger) на 3.x проверьте совместимость ключевых слов — в 2.0 использовалась устаревшая версия схемы.
Генерация кода из схемы
Из JSON Schema можно генерировать типы TypeScript, классы для валидации, формы и документацию. Популярные инструменты: quicktype, json-schema-to-typescript, openapi-generator. Это сокращает ручную работу и снижает расхождения между схемой и кодом.
Условные схемы: if/then/else, oneOf, anyOf, allOf
Для сложной логики валидации используются условные конструкции:
- oneOf — данные должны соответствовать ровно одной из схем
- anyOf — хотя бы одной
- allOf — всем перечисленным схемам
- if/then/else — если выполняется условие
if, применяетсяthen, иначеelse
Пример: поле type определяет обязательные поля:
{
"if": { "properties": { "type": { "const": "company" } }, "required": ["type"] },
"then": { "required": ["companyName"] },
"else": { "required": ["firstName", "lastName"] }
}
Инструмент JSON Schema Validator на reChecker
Валидатор JSON Schema на reChecker позволяет:
- Вставить JSON и схему в отдельные поля
- Проверить соответствие данных схеме
- Получить список ошибок с путями к полям
- Отладить схемы перед использованием в коде
Инструмент поддерживает draft-07 и 2020-12. Удобен для разработчиков при написании и отладке схем, а также при разборе ошибок валидации.
Типичные ошибки при написании схем
- Забыть required — поле может отсутствовать, валидатор не сообщит об ошибке
- Слишком мягкая схема —
additionalProperties: trueпо умолчанию допускает лишние поля; для API лучше явно запрещать - Некорректный $ref — путь должен указывать на существующее определение в
$defsили во внешнем файле - format без проверки — не все валидаторы проверяют
formatпо умолчанию; в Ajv нужно подключатьformatотдельно
Рекомендации
- Версия схемы — указывайте
$schemaявно - additionalProperties — при строгом контракте ставьте
false - format — поддержка зависит от валидатора; проверяйте документацию
- $ref — используйте для переиспользования и уменьшения дублирования
- Тестирование — валидируйте граничные случаи и невалидные данные
- Документация — добавляйте
titleиdescriptionк полям для автогенерации документации
FAQ
Чем draft-07 отличается от 2020-12?
2020-12 добавляет $dynamicRef, $anchor, улучшенную поддержку null и условных схем. Для большинства задач draft-07 достаточно. Выбирайте 2020-12, если нужны новые возможности или совместимость с актуальными инструментами.
Можно ли использовать JSON Schema с TypeScript?
Да. Инструменты вроде json-schema-to-typescript генерируют типы TypeScript из схемы. Также существуют библиотеки для runtime-валидации с выводом типов (например, Zod, который не является JSON Schema, но решает похожие задачи).
Как описать массив объектов с разной структурой?
Используйте oneOf, anyOf или allOf в items:
{
"type": "array",
"items": {
"oneOf": [
{ "type": "object", "properties": { "type": { "const": "A" } } },
{ "type": "object", "properties": { "type": { "const": "B" } } }
]
}
}
Поддерживает ли OpenAPI полный JSON Schema?
OpenAPI 3.x использует подмножество JSON Schema. Не поддерживаются, например, $ref на внешние файлы в произвольных местах, часть ключевых слов. Для сложных схем проверяйте документацию OpenAPI.
Какой инструмент использовать для валидации JSON по схеме?
JSON Schema Validator на reChecker — бесплатный онлайн-инструмент. Вставьте JSON и схему, получите результат валидации и список ошибок с путями. Поддерживает draft-07 и 2020-12. Подходит для разработчиков при написании схем и отладке API.