Эксклюзивные границы

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

Базовая модель границ

При описании числовых полей применяются четыре основных ключа:

  • minimum — нижняя включительная граница
  • maximum — верхняя включительная граница
  • exclusiveMinimum — нижняя исключающая граница
  • exclusiveMaximum — верхняя исключающая граница

Включительные границы допускают совпадение значения с порогом. Исключающие границы запрещают равенство, требуя строгого выхода за пределы.

Пример включительной границы:

{
  "type": "number",
  "minimum": 10
}

Допустимыми считаются значения 10, 11, 12 и так далее.

Исключающая граница изменяет поведение:

{
  "type": "number",
  "exclusiveMinimum": 10
}

Здесь 10 уже не проходит проверку, минимально допустимое значение становится строго больше 10.

Поведение в различных версиях JSON Schema

Важная деталь заключается в эволюции спецификации.

В Draft-07 и ранее exclusiveMinimum и exclusiveMaximum задавались как булевы флаги, связанные с minimum и maximum:

{
  "type": "number",
  "minimum": 10,
  "exclusiveMinimum": true
}

Это означало: минимум 10, но 10 не включается.

Начиная с Draft 2019-09 и далее (включая 2020-12), модель изменилась. exclusiveMinimum и exclusiveMaximum стали самостоятельными числовыми значениями:

{
  "type": "number",
  "exclusiveMinimum": 10
}

Теперь 10 — это строгая нижняя граница, а допустимые значения начинаются с 10 + ε (в практическом смысле — 10 не включается).

Такая смена модели устранила неоднозначность и сделала схему более выразительной.


Реализация в Ajv

Библиотека Ajv строго следует спецификации выбранного draft-режима. Поведение exclusiveMinimum и exclusiveMaximum зависит от версии схемы, указанной при инициализации валидатора.

Базовая настройка

import Ajv fr om "ajv";

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

Ajv автоматически определяет поведение ключей в зависимости от meta-schema.


Включительные и исключительные границы в практике

Нижняя исключающая граница

const schema = {
  type: "number",
  exclusiveMinimum: 0
};

const validate = ajv.compile(schema);

validate(-1); // false
validate(0);  // false
validate(0.1); // true

Здесь 0 полностью исключён из диапазона.


Верхняя исключающая граница

const schema = {
  type: "number",
  exclusiveMaximum: 100
};

const validate = ajv.compile(schema);

validate(100); // false
validate(99.9); // true

Граница 100 становится недостижимой точкой.


Совмещение minimum/maximum с эксклюзивными границами

В современных схемах Draft 2019-09+ использование minimum вместе с exclusiveMinimum запрещено как конфликтующее выражение.

Неправильная комбинация:

{
  "type": "number",
  "minimum": 5,
  "exclusiveMinimum": 10
}

Здесь возникает логическое противоречие: нижняя включительная граница ниже исключающей.

Ajv в строгом режиме фиксирует такие ошибки на этапе компиляции схемы.


Числовые особенности и пограничные значения

Дробные значения

Эксклюзивные границы особенно важны для дробных чисел:

const schema = {
  type: "number",
  exclusiveMinimum: 1.5,
  exclusiveMaximum: 2.5
};

Допустимый диапазон:

  • 1.5 — запрещено
  • 1.50001 — допустимо
  • 2.49999 — допустимо
  • 2.5 — запрещено

Поведение зависит от точности floating-point, что требует осторожности при математически точных вычислениях.


Целые числа

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

const schema = {
  type: "integer",
  exclusiveMinimum: 0,
  exclusiveMaximum: 10,
  multipleOf: 1
};

Допустимые значения: 1–9.


Взаимодействие с coercion и типами

При включённой опции преобразования типов:

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

строковые значения могут автоматически приводиться к числам:

validate("5"); // будет преобразовано в 5

Это влияет и на проверку границ: после приведения применяются правила exclusiveMinimum и exclusiveMaximum.


Ошибки валидации и диагностика

Ajv возвращает структурированные ошибки:

validate(0).errors;

Типичная ошибка:

{
  "keyword": "exclusiveMinimum",
  "params": {
    "comparison": ">",
    "limit": 0
  },
  "message": "must be greater than 0"
}

Для exclusiveMaximum сообщение аналогично, но с условием “<”.


Поведение при NaN, Infinity и null

NaN

Всегда считается невалидным для type: number.

Infinity

Зависит от конфигурации и режима строгой проверки. В большинстве случаев:

  • Infinity > exclusiveMaximum → не проходит
  • -Infinity < exclusiveMinimum → не проходит

null

Не проходит проверку number, если не указано:

"nullable": true

или union типов:

{ "type": ["number", "null"] }

Совместимость с другими ограничениями

multipleOf и эксклюзивные границы

{
  type: "number",
  exclusiveMinimum: 0,
  exclusiveMaximum: 1,
  multipleOf: 0.2
}

Формирует дискретный набор:

0.2, 0.4, 0.6, 0.8

Граница 1 не включается.


pattern и числовые ограничения

Хотя pattern применяется к строкам, в сочетании с type: “string” и преобразованиями типов можно косвенно влиять на числовую логику, например при сериализации.


Оптимизация проверки диапазонов в Ajv

Ajv компилирует схемы в JavaScript-функции. Проверка exclusiveMinimum и exclusiveMaximum сводится к прямым числовым сравнениям:

  • value > lim it
  • value < limit

Такая реализация обеспечивает минимальные накладные расходы даже при массовой валидации больших массивов данных.

При включённом code generation оптимизации исключаются лишние проверки, если схема содержит только один из диапазонных ключей.


Типичные ошибки при проектировании схем

Перепутанные границы

{
  "exclusiveMinimum": 100,
  "exclusiveMaximum": 10
}

Логически невозможный диапазон.


Дублирование условий

{
  "minimum": 10,
  "exclusiveMinimum": 10
}

Конфликт спецификации, запрещённый в строгом режиме Ajv.


Использование без type

{
  "exclusiveMinimum": 0
}

Без type: “number” поведение может быть неопределённым в зависимости от контекста схемы.


Практические сценарии применения

Финансовые значения

Минимальные комиссии, проценты, ставки:

{
  type: "number",
  exclusiveMinimum: 0,
  maximum: 1
}

Ограничение физических величин

Температуры, скорости, массы с недостижимыми границами:

{
  type: "number",
  exclusiveMinimum: -273.15
}

Системные пороги

Настройки производительности, таймауты:

{
  type: "integer",
  exclusiveMinimum: 0,
  maximum: 10000
}

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