JSON Schema валидация

JSON Schema представляет собой формализованный способ описания структуры данных в формате JSON. Он задаёт правила, которым должны соответствовать объекты: типы полей, обязательность, диапазоны значений, вложенные структуры и ограничения на значения. В экосистеме JavaScript подобный подход часто пересекается с библиотеками валидации, одной из которых является Yup.

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


JSON Schema использует декларативный подход. Схема описывается в виде JSON-объекта:

{
  "type": "object",
  "properties": {
    "name": { "type": "string", "minLength": 3 },
    "age": { "type": "number", "minimum": 18 }
  },
  "required": ["name"]
}

Yup применяет программное описание схем:

import * as Yup from 'yup';

const schema = Yup.object({
  name: Yup.string().min(3).required(),
  age: Yup.number().min(18)
});

Различие заключается в уровне абстракции. JSON Schema хранится как данные, Yup — как исполняемый код. Это влияет на способы расширения, переиспользования и динамической генерации схем.


Базовые типы и их эквиваленты

В JSON Schema типизация задаётся через ключ type:

  • string
  • number
  • boolean
  • object
  • array
  • null

Yup использует методы-конструкторы:

  • Yup.string()
  • Yup.number()
  • Yup.boolean()
  • Yup.object()
  • Yup.array()

Пример сопоставления:

JSON Schema:

{ "type": "string", "minLength": 5 }

Yup:

Yup.string().min(5)

Ограничения в Yup задаются через цепочки методов, что позволяет формировать более выразительные и динамичные правила.


Валидация объектов

JSON Schema описывает структуру объекта через properties и required.

{
  "type": "object",
  "properties": {
    "email": { "type": "string", "format": "email" },
    "password": { "type": "string", "minLength": 8 }
  },
  "required": ["email", "password"]
}

В Yup аналогичная структура строится через object:

Yup.object({
  email: Yup.string().email().required(),
  password: Yup.string().min(8).required()
});

Дополнительные ключи в JSON Schema регулируются через additionalProperties. В Yup поведение контролируется через строгие схемы или кастомные проверки.


Валидация массивов

JSON Schema:

{
  "type": "array",
  "items": { "type": "number" },
  "minItems": 1
}

Yup:

Yup.array()
  .of(Yup.number())
  .min(1)

В Yup доступна дополнительная логика трансформации элементов через transform, чего нет в стандартном JSON Schema.


Условная логика

JSON Schema поддерживает условия через конструкции if / then / else:

{
  "if": {
    "properties": { "role": { "const": "admin" } }
  },
  "then": {
    "required": ["permissions"]
  }
}

В Yup аналог реализуется через when:

Yup.object({
  role: Yup.string(),
  permissions: Yup.array().when('role', {
    is: 'admin',
    then: schema => schema.required()
  })
});

Yup предоставляет более программно-ориентированную модель условной логики, позволяя использовать функции и контекст.


Кастомная валидация

JSON Schema ограничена набором стандартных правил и расширяется через custom keywords в валидаторах вроде Ajv.

Yup использует test:

Yup.string().test(
  'is-even-length',
  'Длина строки должна быть чётной',
  value => value ? value.length % 2 === 0 : true
);

Такая модель даёт возможность внедрять произвольную бизнес-логику прямо в схему.


Трансформация данных

JSON Schema не предусматривает встроенную трансформацию значений.

Yup поддерживает transform:

Yup.string().transform(value => value.trim().toLowerCase())

Это позволяет не только валидировать, но и нормализовать данные в одном описании схемы.


Совместимость и интеграция с JSON Schema

Несмотря на различия, Yup может использоваться совместно с JSON Schema через промежуточные инструменты:

  • конвертеры JSON Schema → Yup
  • генерация JSON Schema из Yup-схем
  • использование JSON Schema для API-валидации и Yup для клиентской логики

Подходы к интеграции обычно строятся вокруг следующих задач:

  1. серверная валидация через JSON Schema (например, AJV)
  2. клиентская валидация через Yup
  3. синхронизация схем через генерацию

Пример архитектурного разделения:

  • JSON Schema описывает контракт API
  • Yup описывает поведение формы и UX-валидацию

Ограничения сопоставления Yup и JSON Schema

Полного соответствия между системами не существует.

Основные расхождения:

  • JSON Schema поддерживает формальную спецификацию для контрактов данных
  • Yup ориентирован на runtime-логику и UI-сценарии
  • условные конструкции реализуются по-разному
  • расширяемость JSON Schema зависит от валидатора
  • Yup позволяет использовать произвольный JavaScript

Из-за этого прямое преобразование схем часто требует потерь в семантике.


Сложные структуры и вложенность

JSON Schema:

{
  "type": "object",
  "properties": {
    "user": {
      "type": "object",
      "properties": {
        "profile": {
          "type": "object",
          "properties": {
            "age": { "type": "number" }
          }
        }
      }
    }
  }
}

Yup:

Yup.object({
  user: Yup.object({
    profile: Yup.object({
      age: Yup.number()
    })
  })
});

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


Ошибки и структура результата валидации

JSON Schema валидаторы возвращают стандартизированные ошибки:

  • путь к полю
  • код ошибки
  • описание

Yup формирует объект ValidationError, содержащий:

  • path
  • message
  • inner (массив вложенных ошибок)

Это позволяет агрегировать ошибки сложных структур и отображать их в интерфейсах форм.


Практика построения схем

При проектировании схем в Yup и JSON Schema обычно выделяются общие принципы:

  • разделение базовых и составных схем
  • повторное использование фрагментов
  • нормализация типов данных
  • централизованное управление ограничениями

В JSON Schema это достигается через $ref:

{
  "$ref": "#/definitions/address"
}

В Yup аналог реализуется через переменные и функции:

const address = Yup.object({
  city: Yup.string(),
  zip: Yup.string()
});

Динамическая генерация схем

Yup предоставляет возможность строить схемы на основе входных параметров:

const createSchema = (minAge) =>
  Yup.object({
    age: Yup.number().min(minAge)
  });

JSON Schema также допускает генерацию, но вне самой спецификации — на уровне кода, формирующего JSON.


Использование в прикладных сценариях

Yup чаще применяется в:

  • валидации форм
  • клиентских приложениях
  • динамических интерфейсах
  • обработке пользовательского ввода

JSON Schema чаще используется в:

  • API-контрактах
  • документации сервисов
  • генерации форм
  • серверной валидации

Разделение областей применения формирует устойчивую архитектурную модель: JSON Schema описывает контракт, Yup — поведение данных в приложении.