Введение в JSON Schema: определение и валидация структур данных
JSON гибок по своей природе — любой ключ может содержать любое значение, и никакой встроенной проверки структуры не предусмотрено. Эта гибкость удобна при прототипировании, но опасна в production-системах, где вы ожидаете конкретные поля, конкретные типы и конкретные ограничения. JSON Schema решает эту проблему, предоставляя декларативный язык для точного описания того, как должен выглядеть валидный JSON.
Что такое JSON Schema?
JSON Schema — это словарь для аннотирования и валидации JSON-документов. Сам он написан в JSON, что делает его удобным для чтения, написания и интеграции в инструментальные цепочки. Текущая стабильная спецификация — Draft 2020-12, поддерживаемая на json-schema.org.
Схема описывает ожидаемую форму JSON-значения. Валидаторы используют схему для проверки соответствия документа — и если документ не соответствует, они точно сообщают, какие ограничения нарушены и где.
{"$schema": "https://json-schema.org/draft/2020-12/schema","type": "object","properties": {"name": { "type": "string" },"age": { "type": "integer", "minimum": 0 }},"required": ["name"]}
Эта схема принимает любой объект с полем name типа string. Поле age необязательное, но если оно присутствует, должно быть неотрицательным целым числом.
Базовые определения типов
JSON Schema напрямую отображается на шесть встроенных типов JSON.
String
{ "type": "string" }
Соответствует любому строковому значению JSON. Можно добавить ограничения на минимальную и максимальную длину:
{"type": "string","minLength": 1,"maxLength": 100}
Number и Integer
{ "type": "number" }{ "type": "integer" }
number принимает как целые числа, так и числа с плавающей точкой. integer принимает только целые числа. Добавляйте ограничения диапазона с помощью minimum, maximum, exclusiveMinimum и exclusiveMaximum.
{"type": "number","minimum": 0,"maximum": 1}
Boolean
{ "type": "boolean" }
Соответствует только true или false.
Null
{ "type": "null" }
Соответствует только значению null в JSON. Часто комбинируется с другим типом через массив:
{ "type": ["string", "null"] }
Object
{"type": "object","properties": {"id": { "type": "integer" },"email": { "type": "string" }}}
Ключевое слово properties определяет именованные поля. По умолчанию все свойства необязательны.
Array
{"type": "array","items": { "type": "string" }}
Ключевое слово items ограничивает тип каждого элемента. Добавьте minItems и maxItems для управления длиной.
Обязательные и необязательные поля
По умолчанию все свойства объектной схемы необязательны. Используйте ключевое слово required для принудительного присутствия полей:
{"type": "object","properties": {"username": { "type": "string" },"email": { "type": "string" },"bio": { "type": "string" }},"required": ["username", "email"]}
Здесь username и email должны присутствовать. bio необязательно. Обратите внимание: required является соседом properties, а не вложен в него.
Чтобы полностью запретить неизвестные свойства, добавьте "additionalProperties": false:
{"type": "object","properties": {"id": { "type": "integer" },"name": { "type": "string" }},"required": ["id", "name"],"additionalProperties": false}
Продвинутые возможности
enum
Ограничивает значение фиксированным набором допустимых вариантов:
{"type": "string","enum": ["draft", "published", "archived"]}
enum также работает с разными типами — можно перечислять конкретные значения любого JSON-типа в одном списке.
pattern
Валидирует строки по регулярному выражению:
{"type": "string","pattern": "^[a-z0-9_-]{3,30}$"}
Полезно для слагов, имён пользователей, идентификаторов и любых строк с предсказуемым форматом.
format
Обеспечивает семантическую валидацию для распространённых форматов строк:
{ "type": "string", "format": "email" }{ "type": "string", "format": "date" }{ "type": "string", "format": "uri" }{ "type": "string", "format": "uuid" }
Примечание: валидация format необязательна в спецификации. Одни валидаторы применяют её по умолчанию, другие требуют явной настройки.
minimum и maximum
Уже рассмотрены для чисел, но стоит отметить, что они применяются и к integer:
{"type": "integer","minimum": 1,"maximum": 100}
$ref и композиция схем
$ref позволяет ссылаться на другое определение схемы, обеспечивая повторное использование и устраняя дублирование:
{"$defs": {"address": {"type": "object","properties": {"street": { "type": "string" },"city": { "type": "string" },"country": { "type": "string" }},"required": ["street", "city", "country"]}},"type": "object","properties": {"billing": { "$ref": "#/$defs/address" },"shipping": { "$ref": "#/$defs/address" }}}
Для комбинирования схем используйте allOf, anyOf, oneOf и not:
| Ключевое слово | Значение |
|---|---|
allOf | Должно быть валидным по всем перечисленным схемам |
anyOf | Должно быть валидным хотя бы по одной схеме |
oneOf | Должно быть валидным ровно по одной схеме |
not | Не должно быть валидным по указанной схеме |
Практическое применение
Документация API
JSON Schema лежит в основе OpenAPI (ранее Swagger). Каждое тело запроса и тело ответа в спецификации OpenAPI описывается с помощью JSON Schema. Написание схем вынуждает сделать неявные допущения явными, что повышает качество документации и надёжность клиентского кода.
Генерация форм
Библиотеки вроде react-jsonschema-form и jsonforms читают JSON Schema и автоматически генерируют UI-формы со встроенной валидацией. Одно определение схемы управляет и серверной валидацией, и рендерингом на фронтенде.
Валидация данных в коде
В большинстве языков есть зрелые библиотеки-валидаторы JSON Schema:
// JavaScript — ajvimport Ajv from 'ajv';const ajv = new Ajv();const validate = ajv.compile(schema);const valid = validate(data);if (!valid) console.log(validate.errors);
# Python — jsonschemafrom jsonschema import validate, ValidationErrortry:validate(instance=data, schema=schema)except ValidationError as e:print(e.message)
Валидация в CI-пайплайне
Хуки коммитов или шаги CI могут автоматически валидировать JSON-конфиги по схеме, перехватывая структурные ошибки ещё до попадания в production.
Использование инструмента Schema в JSONKit
Инструмент Schema на JSONKit предоставляет интерактивную среду для работы с JSON Schema:
- Вставьте JSON Schema и JSON-документ рядом друг с другом
- Запустите валидацию мгновенно и просматривайте сообщения об ошибках для каждого поля
- Сгенерируйте стартовую схему из существующего JSON-документа
- Исследуйте композицию схем с
allOf,anyOfи$ref
Функция генерации схемы из JSON особенно полезна, когда у вас есть готовый датасет и нужно быстро создать схему, описывающую его структуру.
Заключение
JSON Schema привносит типобезопасность и структурные контракты в JSON-данные без необходимости компиляции или привязки к конкретному языку программирования. Она работает на уровне протокола — между сервисами, командами, фронтендом и бэкендом — что делает её одним из наиболее универсальных инструментов в арсенале разработчика для валидации данных. Начните с простых определений типов и обязательных полей, затем добавляйте ограничения вроде pattern, enum и $ref по мере созревания модели данных.