Ограничения длины

Валидация длины значений в JSON Schema опирается на набор стандартных ключевых слов, которые позволяют строго контролировать размер строк, массивов и объектов. В библиотеке Ajv эти ограничения реализованы напрямую через спецификацию JSON Schema Draft 7/2019-09/2020-12 и обрабатываются на этапе компиляции схемы в оптимизированный валидатор.

Ограничения длины строк: minLength и maxLength

Для строковых значений используются ключевые слова:

  • minLength — минимальная длина строки
  • maxLength — максимальная длина строки

Оба ограничения применяются к количеству символов в строке, однако важно учитывать, что в JavaScript строка представлена в UTF-16, и длина считается в кодовых единицах, а не в «человеческих символах» (графемах).

Базовый пример

{
  "type": "string",
  "minLength": 3,
  "maxLength": 10
}

Такая схема допускает строки длиной от 3 до 10 символов включительно.

Поведение Ajv при нарушении ограничений

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

{
  "instancePath": "/username",
  "schemaPath": "#/properties/username/minLength",
  "keyword": "minLength",
  "params": {
    "limit": 3
  },
  "message": "must NOT have fewer than 3 characters"
}

Сообщения можно кастомизировать через messages или через ajv-errors, но сами проверки остаются неизменными.

Unicode и особенности измерения длины

Одной из ключевых проблем при работе с ограничениями длины является различие между:

  • символами (графемами),
  • UTF-16 кодовыми единицами,
  • байтами (в контексте хранения).

Ajv использует стандартное поведение Jav * aScript:

"?".length === 2

Это означает, что emoji или символы вне BMP (Basic Multilingual Plane) считаются как два символа.

Пример:

{
  "type": "string",
  "maxLength": 2
}

Строка "?" будет считаться длиной 2 и пройдет валидацию, хотя визуально это один символ.

Для корректной работы с реальной «человеческой длиной» требуется предварительная нормализация данных или использование кастомных валидаторов.

Ограничения длины массивов: minItems и maxItems

Для массивов используются:

  • minItems — минимальное количество элементов
  • maxItems — максимальное количество элементов

Пример схемы

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

Такая схема ограничивает массив от 1 до 5 чисел.

Поведение Ajv

Ajv проверяет длину массива через .length, без дополнительных преобразований:

  • пустой массив: length = 0
  • массив с 3 элементами: length = 3

Ошибки имеют вид:

{
  "keyword": "maxItems",
  "params": {
    "limit": 5
  },
  "message": "must NOT have more than 5 items"
}

additionalItems и контроль «лишних» элементов

При использовании фиксированной схемы массива:

{
  "type": "array",
  "items": [
    { "type": "string" },
    { "type": "number" }
  ],
  "additionalItems": false
}

ограничение длины становится косвенным: массив не может содержать более двух элементов.

Таким образом, additionalItems: false часто используется как альтернативный способ ограничения длины.

Ограничения длины объектов: minProperties и maxProperties

Для объектов применяются:

  • minProperties — минимальное количество ключей
  • maxProperties — максимальное количество ключей

Пример

{
  "type": "object",
  "minProperties": 2,
  "maxProperties": 4
}

Эта схема ограничивает количество свойств объекта.

Особенности работы

Ajv считает только собственные перечисляемые ключи объекта. Наследуемые свойства не учитываются.

Пример:

const obj = Object.create({ inherited: true });
obj.a = 1;
obj.b = 2;

Для схемы:

{ "minProperties": 2 }

объект будет валиден, поскольку учитываются только a и b.

Взаимодействие ограничений длины с другими ключевыми словами

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

String + pattern + length

{
  "type": "string",
  "minLength": 5,
  "maxLength": 20,
  "pattern": "^[a-zA-Z0-9_]+$"
}

Здесь порядок проверки в Ajv оптимизирован:

  1. Быстрая проверка длины
  2. Проверка регулярного выражения

Если длина не проходит, pattern не вычисляется, что повышает производительность.

Array + items + length

{
  "type": "array",
  "minItems": 2,
  "maxItems": 10,
  "items": {
    "type": "string",
    "minLength": 3
  }
}

Здесь ограничения применяются на двух уровнях:

  • уровень структуры массива
  • уровень содержимого элементов

Компиляция схем и производительность

Ajv при компиляции схемы преобразует ограничения длины в оптимизированные JavaScript-функции без промежуточных абстракций.

Пример внутренней логики:

  • minLength → сравнение числа (str.length >= N)
  • maxLength → сравнение числа (str.length <= N)
  • minItemsarr.length >= N

Это позволяет добиться минимальной стоимости проверки.

Строгий режим и ограничения длины

В строгом режиме Ajv (strict: true) дополнительно проверяет:

  • допустимость использования ключевых слов
  • соответствие версии JSON Schema
  • отсутствие конфликтующих ограничений

Пример конфликтной схемы:

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

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

Граничные случаи и особенности поведения

Пустые значения

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

Эквивалентно отсутствию ограничения, но формально фиксирует допустимость пустой строки.

null и отсутствие значения

Ограничения длины не применяются к null. Для этого требуется:

{
  "type": ["string", "null"],
  "maxLength": 10
}

Числовые строки

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

Строка "12345" валидна, но число 12345 должно быть предварительно приведено к строке, иначе будет ошибка типа.

Кастомные ограничения длины

Ajv позволяет расширять поведение через пользовательские ключевые слова:

ajv.addKeyword({
  keyword: "byteLength",
  type: "string",
  validate: function (schema, data) {
    return Buffer.byteLength(data, "utf8") <= schema;
  }
});

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

Типовые ошибки при использовании ограничений длины

Несоответствие ожиданий UTF-8 и JS-length

Наиболее частая проблема — ожидание, что length соответствует байтам или визуальным символам.

Ошибки при работе с массивами вложенных структур

{
  "type": "array",
  "maxItems": 3,
  "items": {
    "type": "array",
    "maxItems": 2
  }
}

Ограничения применяются рекурсивно, но каждая вложенная структура проверяется отдельно.

Конфликты схем

{
  "minItems": 5,
  "maxItems": 2
}

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

Оптимизация схем с ограничениями длины

Для повышения производительности при массовой валидации:

  • использовать maxLength как первую линию защиты для строк
  • ставить более дешевые проверки выше в логической структуре
  • избегать избыточных комбинаций pattern + format + length, если достаточно одного ограничения

Ajv компилирует схемы в функции, поэтому упрощение структуры напрямую влияет на скорость выполнения.

Итоговая модель поведения ограничений длины в Ajv

Ограничения длины представляют собой базовый слой валидации, который:

  • выполняется максимально быстро
  • применяется до сложных проверок
  • работает напрямую через свойства JavaScript объектов (length, Object.keys().length)
  • не требует дополнительных преобразований данных

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