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.

Команда JSONTechFebruary 1, 202511 min read

Что такое 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"}
number3.14, -1, 0{"type": "number"}
integer42, -7{"type": "integer"}
booleantrue, false{"type": "boolean"}
nullnull{"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-042013Основной словарь, $ref, базовые типыУстаревший (по-прежнему широко используется)
Draft-062017const, contains, propertyNamesУстаревший
Draft-072018if/then/else, readOnly, writeOnlyШироко поддерживается
2019-092019$defs, unevaluatedProperties, dependentRequiredПоддерживается основными валидаторами
2020-122020prefixItems (заменяет валидацию кортежей), динамический $refТекущий / рекомендуемый

Для новых проектов используйте 2020-12. Если вам нужна максимальная совместимость с существующими инструментами, Draft-07 является безопасным выбором — он имеет почти универсальную поддержку библиотек.

Общие ошибки, которых следует избегать

  • Забывать о required. Свойства, определенные в properties, по умолчанию являются необязательными. Если поле должно присутствовать, перечислите его в required.
  • Смешивать number и integer. number принимает десятичные; integer — нет. Используйте integer для идентификаторов, счетчиков и других целых чисел.
  • Слишком ранняя переоценка ограничений. Начните с минимальной схемы, которая ловит реальные ошибки. Вы всегда можете ужесточить ограничения позже — ослабление их является нарушением совместимости.
  • Не использовать $ref. Дублирование одной и той же подсхемы в нескольких местах — это кошмар для обслуживания. Извлекайте общие структуры в $defs.
  • Игнорировать валидацию format. По умолчанию большинство валидаторов рассматривают format как аннотацию, а не как ограничение. Вам нужно явно включить валидацию формата (например, ajv.addFormat() или передав { validateFormats: true }).

Попробуйте сами: Сгенерируйте схему из любого образца JSON с помощью нашего Генератора JSON Schema, а затем настройте ограничения в соответствии с вашими требованиями.

Похожие инструменты