Руководство по валидации 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 не определяет, как данные сериализуются или передаются. Она только описывает, как выглядят валидные данные.
- Не замена бизнес-логики: валидация Schema проверяет структурную корректность (типы, форматы, диапазоны). Сложные бизнес-правила (например, «пользователь не может перевести больше, чем его баланс») относятся к коду приложения.
- Не схема базы данных: хотя концептуально похожи, JSON Schema валидирует JSON-документы, а не таблицы базы данных. Однако вы можете использовать JSON Schema вместе с ограничениями базы данных для глубокоэшелонированной защиты.
Версии JSON Schema
JSON Schema эволюционировала через несколько черновиков, каждый из которых добавлял функции и уточнял словарь. Понимание версий помогает выбрать правильную для вашего проекта и избежать проблем совместимости.
| Версия | URI $schema | Статус | Основные функции |
|---|---|---|---|
| Draft 2020-12 | https://json-schema.org/draft/2020-12/schema | Текущая версия | prefixItems, dynamicRef, поддержка словарей |
| Draft 2019-09 | https://json-schema.org/draft/2019-09/schema | Стабильная | unevaluatedProperties, $recursiveRef |
| Draft 7 | http://json-schema.org/draft-07/schema# | Широко поддерживается | if/then/else, contentEncoding |
| Draft 6 | http://json-schema.org/draft-06/schema# | Устаревшая | propertyNames, contains |
| Draft 4 | http://json-schema.org/draft-04/schema# | Устарела | Первая широко принятая версия |
Написание вашей первой 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" |
Ограничения объектов
| Ключевое слово | Описание | Пример |
|---|---|---|
| properties | Schema для каждого известного свойства | "properties": {"name": {"type": "string"}} |
| required | Список обязательных свойств | "required": ["name", "email"] |
| additionalProperties | Разрешены ли дополнительные свойства | "additionalProperties": false |
| minProperties | Минимальное количество свойств | "minProperties": 1 |
| maxProperties | Максимальное количество свойств | "maxProperties": 10 |
| patternProperties | Schema для свойств, соответствующих регулярному выражению | "patternProperties": {"^S_": {"type": "string"}} |
Ограничения массивов
| Ключевое слово | Описание | Пример |
|---|---|---|
| items | Schema для всех элементов массива | "items": {"type": "string"} |
| prefixItems | Schema для позиционных элементов (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 мощными способами:
- allOf: данные должны удовлетворять всем подсхемам. Используется для комбинирования нескольких ограничений или примешивания повторно используемых фрагментов Schema.
- anyOf: данные должны удовлетворять хотя бы одной подсхеме. Используется для union-типов, где допустимы несколько форм.
- oneOf: данные должны удовлетворять ровно одной подсхеме. Используется для взаимоисключающих альтернатив.
{
"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 обеспечивает семантическую валидацию помимо структурных проверок. Оно указывает, что строка должна соответствовать хорошо известному формату. Часто поддерживаемые форматы включают:
| Формат | Описание | Пример |
|---|---|---|
| Адрес электронной почты | user@example.com | |
| uri | Валидный URI | https://example.com/path |
| uri-reference | URI или относительная ссылка | /path/to/resource |
| date-time | Дата и время ISO 8601 | 2026-05-19T14:30:00Z |
| date | Дата ISO 8601 | 2026-05-19 |
| time | Время ISO 8601 | 14:30:00Z |
| ipv4 | IPv4-адрес | 192.168.1.1 |
| ipv6 | IPv6-адрес | ::1 |
| uuid | Универсальный уникальный идентификатор | 550e8400-e29b-41d4-a716-446655440000 |
| hostname | Имя хоста в Интернете | www.example.com |
Программная валидация 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 и логика валидации всегда синхронизированы.
Лучшие практики
- Всегда устанавливайте $schema: включайте ключевое слово $schema, чтобы объявить, какую версию черновика использует ваша Schema. Это предотвращает неоднозначность и гарантирует, что валидаторы правильно интерпретируют вашу Schema.
- Используйте $id для идентификации Schema: ключевое слово $id предоставляет уникальный идентификатор для вашей Schema и служит базовым URI для разрешения ссылок $ref. Всегда устанавливайте его, даже для локальных Schema.
- Устанавливайте additionalProperties: false: по умолчанию JSON Schema разрешает любые дополнительные свойства в объектах. Установка additionalProperties: false отлавливает опечатки и неожиданные поля, делая вашу Schema более строгой, а API более предсказуемым.
- Используйте $defs для повторно используемых компонентов: определяйте общие Schema в $defs и ссылайтесь на них через $ref. Это уменьшает дублирование и делает Schema более сопровождаемой.
- Добавляйте описания: каждое свойство и Schema должны иметь поле description. Это служит документацией и помогает другим разработчикам понять назначение и ограничения каждого поля.
- Валидируйте на границах системы: применяйте валидацию Schema на периферии вашей системы: конечные точки API, потребители сообщений, конвейеры импорта данных и загрузчики конфигурации. Не валидируйте данные, которые ваш собственный код уже произвёл и которым доверяет.
- Включайте строгий режим в валидаторах: настройте валидатор отклонять неизвестные ключевые слова, принудительно выполнять валидацию форматов и сообщать все ошибки, а не останавливаться на первой. Это позволяет выявить больше проблем за одну проверку.
- Версионируйте ваши Schema: включайте версию Schema в URI $id (например, https://example.com/schemas/user/v2.json). Это позволяет развивать Schema, не ломая существующих потребителей.
- Тестируйте ваши Schema: пишите модульные тесты для ваших Schema с примерами валидных и невалидных данных. Это гарантирует, что ваша Schema применяет задуманные вами ограничения, и выявляет регрессии при изменении Schema.
- Используйте format для семантической валидации: предпочитайте format: "email" сложным шаблонам регулярных выражений. Форматы более читаемы, лучше сопровождаемы и выигрывают от хорошо протестированной логики валидации в библиотеках валидаторов.
Нужно проверить 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). Эти ключевые слова покрывают подавляющее большинство потребностей валидации.