ToolHub
View All Posts

Руководство по валидации JSON Schema: проверка структуры данных

Каждое приложение, получающее данные из внешних источников, сталкивается с одной и той же фундаментальной проблемой: могу ли я доверять этим данным? Будь то тело API-запроса, конфигурационный файл, сообщение очереди или импорт данных, ненадёжные данные должны быть проверены до того, как они попадут в вашу систему. JSON Schema предоставляет стандартизированный, независимый от языка способ определения того, как выглядят валидные данные, и проверки соответствия входящих данных этому определению. Это руководство охватывает всё от написания вашей первой Schema до продвинутых шаблонов сложной валидации с практическими примерами, которые вы можете применить немедленно.

Что такое JSON Schema?

JSON Schema — это JSON-документ, описывающий структуру и ограничения других JSON-документов. Это словарь, позволяющий аннотировать и валидировать JSON-данные, стандартизированный Инженерным советом Интернета (IETF). JSON Schema определяет правила о том, какие поля должны присутствовать, какого они должны быть типа, какие значения допустимы и как должны быть структурированы объекты и массивы.

Думайте о JSON Schema как о контракте для ваших данных. Так же, как схема базы данных определяет столбцы, типы и ограничения таблицы, JSON Schema определяет свойства, типы и ограничения JSON-документа. Любые JSON-данные, удовлетворяющие всем ограничениям в Schema, называются валидным экземпляром, а данные, нарушающие любое ограничение, — невалидными.

Чем JSON Schema не является

Версии JSON Schema

JSON Schema эволюционировала через несколько черновиков, каждый из которых добавлял функции и уточнял словарь. Понимание версий помогает выбрать правильную для вашего проекта и избежать проблем совместимости.

ВерсияURI $schemaСтатусОсновные функции
Draft 2020-12https://json-schema.org/draft/2020-12/schemaТекущая версияprefixItems, dynamicRef, поддержка словарей
Draft 2019-09https://json-schema.org/draft/2019-09/schemaСтабильнаяunevaluatedProperties, $recursiveRef
Draft 7http://json-schema.org/draft-07/schema#Широко поддерживаетсяif/then/else, contentEncoding
Draft 6http://json-schema.org/draft-06/schema#УстаревшаяpropertyNames, contains
Draft 4http://json-schema.org/draft-04/schema#УстарелаПервая широко принятая версия
Рекомендация: для новых проектов используйте Draft 2020-12. Это последняя стабильная версия с наибольшим количеством функций, поддерживаемая основными библиотеками валидации. Если вам нужна максимальная совместимость с существующими инструментами, Draft 7 — безопасный выбор. Избегайте Draft 4 и более ранних.

Написание вашей первой Schema

Давайте начнём с простого примера: Schema для объекта пользователя с именем, email и возрастом.

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://example.com/schemas/user.json",
    "title": "User",
    "description": "A user account in the system",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "The user's full name"
        },
        "email": {
            "type": "string",
            "format": "email",
            "description": "The user's email address"
        },
        "age": {
            "type": "integer",
            "minimum": 0,
            "maximum": 150,
            "description": "The user's age in years"
        }
    },
    "required": ["name", "email"],
    "additionalProperties": false
}

Эта Schema declares, что валидный пользователь должен быть объектом, где name и email являются обязательными строковыми свойствами. Свойство age опционально, но если присутствует, должно быть целым числом от 0 до 150. additionalProperties: false предотвращает любые свойства, не определённые в Schema, что помогает отлавливать опечатки и неожиданные поля.

Справочник основных ключевых слов

JSON Schema предоставляет богатый словарь ключевых слов для определения ограничений. Вот самые важные ключевые слова, организованные по категориям.

Ключевые слова типов

Ключевое словоОписаниеПример
typeОжидаемый тип данных"type": "string" или "type": ["string", "null"]
enumСписок допустимых значений"enum": ["active", "inactive", "pending"]
constДолжно быть равно этому точному значению"const": "v2"

Ограничения чисел

Ключевое словоОписаниеПример
minimumМинимальное значение (включительно)"minimum": 0
exclusiveMinimumМинимальное значение (не включительно)"exclusiveMinimum": 0
maximumМаксимальное значение (включительно)"maximum": 100
exclusiveMaximumМаксимальное значение (не включительно)"exclusiveMaximum": 100
multipleOfДолжно быть кратно этому значению"multipleOf": 0.01

Ограничения строк

Ключевое словоОписаниеПример
minLengthМинимальная длина строки"minLength": 1
maxLengthМаксимальная длина строки"maxLength": 255
patternРегулярное выражение, которому должна соответствовать строка"pattern": "^[A-Z]{2}\\d{4}$"
formatСемантический формат (email, uri, date-time и т.д.)"format": "email"

Ограничения объектов

Ключевое словоОписаниеПример
propertiesSchema для каждого известного свойства"properties": {"name": {"type": "string"}}
requiredСписок обязательных свойств"required": ["name", "email"]
additionalPropertiesРазрешены ли дополнительные свойства"additionalProperties": false
minPropertiesМинимальное количество свойств"minProperties": 1
maxPropertiesМаксимальное количество свойств"maxProperties": 10
patternPropertiesSchema для свойств, соответствующих регулярному выражению"patternProperties": {"^S_": {"type": "string"}}

Ограничения массивов

Ключевое словоОписаниеПример
itemsSchema для всех элементов массива"items": {"type": "string"}
prefixItemsSchema для позиционных элементов (Draft 2020-12)"prefixItems": [{"type": "string"}, {"type": "number"}]
minItemsМинимальное количество элементов"minItems": 1
maxItemsМаксимальное количество элементов"maxItems": 100
uniqueItemsВсе элементы должны быть уникальными"uniqueItems": true

Распространённые шаблоны Schema

Реальные Schema часто требуют шаблонов, выходящих за рамки простой проверки типов. Вот наиболее часто используемые шаблоны.

Условная валидация с if/then/else

Используйте условную логику для применения различных ограничений в зависимости от значений свойств. Например, объект платежа требует разные поля в зависимости от способа оплаты.

{
    "type": "object",
    "properties": {
        "method": { "enum": ["credit_card", "bank_transfer"] },
        "card_number": { "type": "string" },
        "routing_number": { "type": "string" }
    },
    "required": ["method"],
    "if": {
        "properties": { "method": { "const": "credit_card" } }
    },
    "then": {
        "required": ["card_number"]
    },
    "else": {
        "required": ["routing_number"]
    }
}

Композиция с allOf, anyOf, oneOf

Ключевые слова композиции позволяют комбинировать Schema мощными способами:

{
    "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": "^\\+?[1-9]\\d{1,14}$" }
            },
            "required": ["type", "number"]
        }
    ]
}

Повторное использование Schema с $ref

Ключевое слово $ref позволяет ссылаться и повторно использовать Schema, устраняя дублирование и поддерживая сопровождаемость Schema. Вы можете ссылаться на Schema в том же документе или во внешних файлах.

{
    "$id": "https://example.com/schemas/order.json",
    "type": "object",
    "properties": {
        "customer": { "$ref": "#/$defs/address" },
        "shipping": { "$ref": "#/$defs/address" },
        "billing": { "$ref": "#/$defs/address" },
        "items": {
            "type": "array",
            "items": { "$ref": "#/$defs/lineItem" },
            "minItems": 1
        }
    },
    "required": ["customer", "items"],
    "$defs": {
        "address": {
            "type": "object",
            "properties": {
                "street": { "type": "string" },
                "city": { "type": "string" },
                "zip": { "type": "string", "pattern": "^\\d{5}(-\\d{4})?$" },
                "country": { "type": "string", "minLength": 2, "maxLength": 2 }
            },
            "required": ["street", "city", "zip", "country"]
        },
        "lineItem": {
            "type": "object",
            "properties": {
                "product": { "type": "string" },
                "quantity": { "type": "integer", "minimum": 1 },
                "price": { "type": "number", "exclusiveMinimum": 0 }
            },
            "required": ["product", "quantity", "price"]
        }
    }
}

Nullable типы

В JSON Schema Draft 2020-12 nullable типы выражаются с помощью массива типов, включающего "null":

{
    "type": ["string", "null"],
    "description": "An optional display name, or null if not set"
}

В более ранних черновиках спецификация OpenAPI использовала ключевое слово nullable: true. Для стандартной JSON Schema всегда используйте подход с массивом типов.

Валидация форматов

Ключевое слово format обеспечивает семантическую валидацию помимо структурных проверок. Оно указывает, что строка должна соответствовать хорошо известному формату. Часто поддерживаемые форматы включают:

ФорматОписаниеПример
emailАдрес электронной почтыuser@example.com
uriВалидный URIhttps://example.com/path
uri-referenceURI или относительная ссылка/path/to/resource
date-timeДата и время ISO 86012026-05-19T14:30:00Z
dateДата ISO 86012026-05-19
timeВремя ISO 860114:30:00Z
ipv4IPv4-адрес192.168.1.1
ipv6IPv6-адрес::1
uuidУниверсальный уникальный идентификатор550e8400-e29b-41d4-a716-446655440000
hostnameИмя хоста в Интернетеwww.example.com
Важное замечание: по умолчанию ключевое слово format является аннотацией, а не ограничением. Валидаторы могут игнорировать его, если вы явно не включите валидацию форматов. В Ajv передайте { strict: true } или { validateFormats: true }, чтобы принудительно выполнять проверку форматов. Всегда проверяйте, применяет ли ваш валидатор ограничения формата.

Программная валидация JSON-данных

Валидация Schema наиболее полезна при интеграции в код приложения. Вот примеры использования популярных библиотек на разных языках.

JavaScript с Ajv

Ajv — наиболее широко используемый валидатор JSON Schema для JavaScript. Он поддерживает все версии черновиков и обеспечивает отличную производительность через JIT-компиляцию Schema.

import Ajv from 'ajv';
import addFormats from 'ajv-formats';

const ajv = new Ajv();
addFormats(ajv);

const schema = {
    type: 'object',
    properties: {
        name: { type: 'string', minLength: 1 },
        email: { type: 'string', format: 'email' },
        age: { type: 'integer', minimum: 0 }
    },
    required: ['name', 'email'],
    additionalProperties: false
};

const validate = ajv.compile(schema);
const valid = validate({ name: 'Alice', email: 'alice@example.com', age: 30 });

if (!valid) {
    console.log(validate.errors);
    // [{ keyword: 'required', params: { missingProperty: 'email' }, ... }]
}

Python с jsonschema

from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "minLength": 1},
        "email": {"type": "string", "format": "email"},
        "age": {"type": "integer", "minimum": 0}
    },
    "required": ["name", "email"],
    "additionalProperties": False
}

try:
    validate(instance={"name": "Alice", "email": "alice@example.com"}, schema=schema)
except ValidationError as e:
    print(f"Validation failed: {e.message}")

Валидация данных API с помощью JSON Schema

Одно из самых ценных применений JSON Schema — валидация данных запросов и ответов API. Это гарантирует, что ваш API получает правильно сформированные входные данные и возвращает данные в ожидаемом формате, выявляя ошибки на ранних этапах и предоставляя чёткие сообщения об ошибках клиентам.

Промежуточное ПО Express.js

import Ajv from 'ajv';

const ajv = new Ajv({ allErrors: true });

function validateBody(schema) {
    const validate = ajv.compile(schema);
    return (req, res, next) => {
        if (!validate(req.body)) {
            return res.status(400).json({
                error: 'Validation failed',
                details: validate.errors
            });
        }
        next();
    };
}

app.post('/api/users',
    validateBody({
        type: 'object',
        properties: {
            name: { type: 'string', minLength: 1, maxLength: 100 },
            email: { type: 'string', format: 'email' },
            role: { enum: ['admin', 'editor', 'viewer'] }
        },
        required: ['name', 'email'],
        additionalProperties: false
    }),
    (req, res) => {
        // req.body is guaranteed valid here
        createUser(req.body);
    }
);

OpenAPI и JSON Schema

OpenAPI (ранее Swagger) использует подмножество JSON Schema для определения схем запросов и ответов API. Если вы уже используете OpenAPI, вы можете извлечь Schema из спецификации API и использовать их для валидации во время выполнения. Инструменты, такие как openapi-schema-validator и express-openapi-validator, могут автоматизировать этот процесс, гарантируя, что ваша документация API и логика валидации всегда синхронизированы.

Лучшие практики

Нужно проверить JSON-данные по Schema? Попробуйте наш бесплатный онлайн-валидатор JSON Schema. Вставьте вашу Schema и данные, чтобы получить мгновенные результаты валидации с подробными сообщениями об ошибках.

Валидатор JSON SchemaИнструмент форматирования JSON

Часто задаваемые вопросы

Что такое JSON Schema?

JSON Schema — это JSON-документ, описывающий структуру и ограничения других JSON-документов. Он позволяет определить обязательные поля, ожидаемые типы данных, диапазоны значений, строковые шаблоны и структуры вложенных объектов. Вы можете использовать его для валидации входящих данных, генерации документации и автоматического создания интерфейсов форм.

Какую версию JSON Schema мне использовать?

Для новых проектов используйте JSON Schema Draft 2020-12. Это последняя стабильная версия, поддерживаемая основными библиотеками валидации, такими как Ajv. Если вам нужна совместимость со старыми инструментами, Draft 7 также широко поддерживается. Избегайте Draft 4 и более ранних, так как они используют устаревшие ключевые слова и не имеют современных функций.

В чём разница между JSON Schema и интерфейсами TypeScript?

Интерфейсы TypeScript обеспечивают проверку типов только во время компиляции в коде TypeScript. JSON Schema обеспечивает валидацию во время выполнения на разных языках программирования и может проверять данные из любого источника (API-запросы, файлы, базы данных). Используйте TypeScript для безопасности во время разработки и JSON Schema для валидации данных во время выполнения на границах системы.

Может ли JSON Schema валидировать тела API-запросов?

Да, JSON Schema широко используется для валидации запросов и ответов API. Фреймворки, такие как Express (с express-json-validator), FastAPI и Spring Boot, нативно или через промежуточное ПО поддерживают валидацию JSON Schema. Валидация тел запросов по Schema гарантирует, что входящие данные имеют правильную структуру до того, как ваше приложение их обработает.

Какие ключевые слова JSON Schema самые важные?

Самые важные ключевые слова: type (тип данных), properties (поля объекта), required (обязательные поля), items (схема элементов массива), minimum/maximum (границы чисел), minLength/maxLength (границы строк), pattern (регулярное выражение для строк), enum (допустимые значения) и $ref (ссылки для повторного использования Schema). Эти ключевые слова покрывают подавляющее большинство потребностей валидации.