Валидация JSON Schema: данные, документация и подсказки кода

JSONJSON and structured data

JSON Schema: Контракт данных

JSON Schema — это язык определения структур для данных JSON, подобно TypeScript для JavaScript, но применимый к валидации во время выполнения и межъязыковым сценариям.

Назначение Описание
Валидация данных Проверка запросов/ответов API
Генерация документации Автоматическая генерация документации API
Подсказки IDE Интеллектуальное автодополнение в VS Code
Mock-данные Автоматическая генерация тестовых данных
Валидация конфигурации package.json, tsconfig.json и т. д.

I. Базовые типы

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "name": { "type": "string", "minLength": 1, "maxLength": 100 },
    "age": { "type": "integer", "minimum": 0, "maximum": 150 },
    "email": { "type": "string", "format": "email" },
    "isActive": { "type": "boolean" },
    "score": { "type": "number", "minimum": 0, "maximum": 100 },
    "tags": {
      "type": "array",
      "items": { "type": "string" },
      "minItems": 1,
      "maxItems": 10,
      "uniqueItems": true
    }
  },
  "required": ["name", "email"],
  "additionalProperties": false
}

Встроенные форматы

format Правило соответствия Пример
email RFC 5322 user@example.com
uri URI https://example.com
date Дата ISO 8601 2026-06-02
time Время ISO 8601 14:30:00
date-time Дата и время ISO 8601 2026-06-02T14:30:00Z
ipv4 Адрес IPv4 192.168.1.1
ipv6 Адрес IPv6 ::1
uuid UUID 550e8400-e29b-41d4-a716-446655440000
hostname Имя хоста example.com

II. Продвинутые паттерны

Вложенные объекты

{
  "type": "object",
  "properties": {
    "user": {
      "type": "object",
      "properties": {
        "profile": {
          "type": "object",
          "properties": {
            "avatar": { "type": "string", "format": "uri" },
            "bio": { "type": "string", "maxLength": 200 }
          }
        }
      }
    }
  }
}

Перечисления и объединённые типы

{
  "status": {
    "type": "string",
    "enum": ["pending", "active", "completed", "cancelled"]
  },
  "id": {
    "oneOf": [
      { "type": "string", "format": "uuid" },
      { "type": "integer", "minimum": 1 }
    ]
  }
}

Условная валидация

{
  "type": "object",
  "properties": {
    "paymentMethod": { "type": "string", "enum": ["credit_card", "bank_transfer"] },
    "cardNumber": { "type": "string" },
    "bankAccount": { "type": "string" }
  },
  "if": {
    "properties": { "paymentMethod": { "const": "credit_card" } }
  },
  "then": {
    "required": ["cardNumber"],
    "properties": { "cardNumber": { "pattern": "^\\d{16}$" } }
  },
  "else": {
    "required": ["bankAccount"]
  }
}

Паттерны регулярных выражений

{
  "phone": { "type": "string", "pattern": "^1[3-9]\\d{9}$" },
  "postalCode": { "type": "string", "pattern": "^\\d{6}$" },
  "slug": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" }
}

III. $ref и повторное использование определений

{
  "$defs": {
    "address": {
      "type": "object",
      "properties": {
        "street": { "type": "string" },
        "city": { "type": "string" },
        "zipCode": { "type": "string", "pattern": "^\\d{6}$" }
      },
      "required": ["street", "city", "zipCode"]
    }
  },
  "type": "object",
  "properties": {
    "homeAddress": { "$ref": "#/$defs/address" },
    "workAddress": { "$ref": "#/$defs/address" }
  }
}

IV. Валидация во время выполнения

Ajv (самый быстрый валидатор)

import Ajv from 'ajv';

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

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

const validate = ajv.compile(schema);

const valid = validate({ name: '张三', age: 25 });
if (!valid) {
  console.log(validate.errors);
  // [{ keyword: 'minimum', dataPath: '/age', message: 'must be >= 0' }]
}

Zod (TypeScript-первый подход)

import { z } from 'zod';

const UserSchema = z.object({
  name: z.string().min(1).max(100),
  age: z.number().int().min(0).max(150),
  email: z.string().email(),
  tags: z.array(z.string()).min(1).max(10),
});

// Автоматический вывод типов
type User = z.infer<typeof UserSchema>;

// Валидация
const result = UserSchema.safeParse(input);
if (result.success) {
  console.log(result.data); // Типобезопасно
} else {
  console.log(result.error.issues);
}

V. Интеллектуальные подсказки IDE

Конфигурация VS Code

// .vscode/settings.json
{
  "json.schemas": [
    {
      "fileMatch": ["/config/*.json"],
      "url": "./schemas/config-schema.json"
    },
    {
      "fileMatch": ["package.json"],
      "url": "https://json.schemastore.org/package"
    }
  ]
}

Ссылка на Schema в JSON-файлах

{
  "$schema": "./schemas/config-schema.json",
  "name": "my-project"
  // Автодополнение IDE, подсказки об ошибках
}

Schema Store

Schema Store предоставляет более 400 распространённых JSON Schema:

  • package.json
  • tsconfig.json
  • .eslintrc.json
  • docker-compose.json
  • GitHub Actions workflows

VI. Генерация Schema из JSON

Использование инструментов

  1. Откройте Инструмент форматирования JSON
  2. Вставьте данные JSON
  3. Нажмите «Генерировать Schema»
  4. Автоматический вывод типов, перечислений и диапазонов

Инструменты командной строки

# Использовать json-schema-generator
npx json-schema-generator sample.json -o schema.json

# Использовать quicktype
npx quicktype sample.json -o schema.json --lang schema

VII. Генерация Mock-данных

import { faker } from '@faker-js/faker';

// Генерация Mock-данных на основе Schema
function generateMock(schema) {
  if (schema.type === 'string') {
    if (schema.format === 'email') return faker.internet.email();
    if (schema.format === 'uri') return faker.internet.url();
    if (schema.enum) return faker.helpers.arrayElement(schema.enum);
    return faker.lorem.word();
  }
  if (schema.type === 'integer') return faker.number.int(schema);
  if (schema.type === 'boolean') return faker.datatype.boolean();
  if (schema.type === 'array') {
    return Array.from({ length: 3 }, () => generateMock(schema.items));
  }
  if (schema.type === 'object') {
    const result = {};
    for (const [key, propSchema] of Object.entries(schema.properties)) {
      result[key] = generateMock(propSchema);
    }
    return result;
  }
}

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

  1. Всегда объявляйте $schema: Указывайте версию Draft, чтобы избежать неоднозначности
  2. Используйте additionalProperties: false: Запрещайте неопределённые поля
  3. Используйте $defs + $ref: Переиспользуйте общие структуры
  4. Используйте format вместо самостоятельного написания pattern: Более читаемо, валидатор обрабатывает автоматически
  5. Интегрируйте валидацию в CI: Убедитесь, что ответы API всегда соответствуют Schema
  6. Управляйте версиями Schema: Синхронизируйте с версиями API, поддерживайте проверку обратной совместимости
#JSON Schema#数据校验#Ajv#Zod#API