Лимиты на размер данных

Валидация строковых значений в Joi начинается с управления их размером. Основные методы контроля — min() и max(), задающие допустимые границы длины строки в символах.

import Joi from 'joi';

const schema = Joi.object({
  username: Joi.string()
    .min(3)
    .max(30)
});

В этом примере строка username должна содержать от 3 до 30 символов включительно. Если значение выходит за пределы, Joi формирует ошибку валидации с типом string.min или string.max.

При работе с Unicode-строками важно учитывать, что длина измеряется в символах JavaScript, а не в байтах. Это означает, что эмодзи и сложные символы могут занимать больше одного байта, но для Joi это всё равно один символ.

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

const schema = Joi.object({
  title: Joi.string()
    .trim()
    .min(5)
    .max(100)
});

Метод trim() позволяет исключить влияние пробелов в начале и конце строки, что особенно важно при ограничениях минимальной длины.


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

Для числовых данных ограничения размера выражаются через диапазоны. Основные методы — min(), max() и greater(), less().

const schema = Joi.object({
  age: Joi.number()
    .min(0)
    .max(120)
});

Такое определение гарантирует, что значение находится в допустимом диапазоне человеческого возраста.

Более строгие условия задаются через исключение границ:

const schema = Joi.object({
  score: Joi.number()
    .greater(0)
    .less(100)
});

Здесь значение должно быть строго больше 0 и строго меньше 100.

Joi также поддерживает проверку целочисленных значений:

const schema = Joi.object({
  quantity: Joi.number()
    .integer()
    .min(1)
    .max(1000)
});

Это важно при ограничении размеров партий, количества элементов или других дискретных величин.


Ограничение количества элементов в массивах

Массивы требуют отдельного подхода, так как их «размер» выражается числом элементов. Для этого используются методы min(), max() и length().

const schema = Joi.object({
  tags: Joi.array()
    .items(Joi.string())
    .min(1)
    .max(10)
});

Такое правило задаёт диапазон допустимого количества тегов.

Если требуется строго фиксированное количество элементов, используется length():

const schema = Joi.object({
  coordinates: Joi.array()
    .length(2)
    .items(Joi.number())
});

Здесь массив обязан содержать ровно два числовых элемента.

Для более сложных структур возможно комбинирование ограничений на элементы и общий размер:

const schema = Joi.object({
  permissions: Joi.array()
    .items(Joi.string().valid('read', 'write', 'delete'))
    .min(1)
    .max(3)
    .unique()
});

Метод unique() дополнительно ограничивает повторяющиеся значения, что влияет на логический размер множества данных.


Ограничение структуры объектов

Хотя объект не имеет прямого «размера» в байтах в Joi, его сложность ограничивается количеством ключей и глубиной вложенности.

Для ограничения количества полей используется .max() и .min() на уровне объекта:

const schema = Joi.object({
  profile: Joi.object({
    name: Joi.string(),
    age: Joi.number()
  }).min(1).max(5)
});

Эти ограничения применяются к числу разрешённых ключей внутри объекта.

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

const schema = Joi.object({
  id: Joi.number(),
  email: Joi.string()
}).unknown(false);

Параметр unknown(false) запрещает дополнительные поля, тем самым фиксируя размер объекта на уровне схемы.


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

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

const schema = Joi.object({
  file: Joi.binary()
    .min(1024)
    .max(5 * 1024 * 1024)
});

В этом случае проверяется размер файла от 1 КБ до 5 МБ. Это особенно важно при загрузке изображений, архивов и других бинарных данных.


Глубокие ограничения и вложенные структуры

Сложные структуры требуют контроля на нескольких уровнях. Например, массив объектов с ограничениями внутри:

const schema = Joi.object({
  users: Joi.array().items(
    Joi.object({
      id: Joi.number().min(1),
      name: Joi.string().max(50)
    })
  ).max(100)
});

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

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

const nodeSchema = Joi.object({
  value: Joi.string().max(20),
  children: Joi.array().items(Joi.link('#node')).max(5)
}).id('node');

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


Производственные аспекты ограничений

Ограничения на размер данных напрямую влияют на производительность валидации. Чем больше допустимый объём структуры, тем выше стоимость проверки.

Особенно критичны:

  • глубокие вложенные объекты;
  • большие массивы;
  • длинные строки без ограничений.

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

Оптимизация достигается за счёт:

  • ранних ограничений (max() на верхнем уровне);
  • строгих схем без unknown(true);
  • ограничения глубины вложенности;
  • предварительной нормализации входных данных.

Кастомные ошибки при превышении лимитов

Joi позволяет задавать собственные сообщения для разных типов превышений:

const schema = Joi.object({
  password: Joi.string()
    .min(8)
    .max(64)
    .messages({
      'string.min': 'Пароль слишком короткий',
      'string.max': 'Пароль превышает допустимую длину'
    })
});

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


Ограничения валидации как часть контракта данных

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

  • предсказуемо распределять ресурсы;
  • избегать переполнения памяти;
  • стандартизировать формат обмена данными;
  • контролировать поведение API при нагрузке.

Joi выступает в этом контексте как декларативный слой описания допустимого объёма и формы данных, обеспечивая строгую структуру без необходимости ручной проверки каждого поля.