Блог

Введение в 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 — ajv
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
from jsonschema import validate, ValidationError
try:
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 по мере созревания модели данных.