Длина массива

В Joi массивы описываются через Joi.array() и позволяют задавать строгие ограничения на количество элементов, типы данных внутри массива и их структуру. Ограничения длины массива являются одной из ключевых частей валидации, поскольку часто требуется контролировать размер коллекций: списков идентификаторов, тегов, элементов формы или параметров запроса.

Ограничение минимального количества элементов задаётся методом min(n).

const Joi = require('joi');

const schema = Joi.object({
  tags: Joi.array().min(2)
});

schema.validate({ tags: ['js'] });
// Ошибка: "tags" must contain at least 2 items

Поведение min(n):

  • массив должен содержать не менее n элементов
  • пустой массив всегда не проходит проверку при min(1)
  • если значение отсутствует и поле необязательное, проверка не выполняется

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

Максимальная длина массива

Метод max(n) ограничивает верхнюю границу количества элементов.

const schema = Joi.object({
  roles: Joi.array().max(3)
});

schema.validate({ roles: ['admin', 'editor', 'user', 'guest'] });
// Ошибка: "roles" must contain less than or equal to 3 items

Особенности:

  • лишние элементы не обрезаются автоматически
  • валидация просто завершится ошибкой
  • применяется для защиты от перегрузки данных или ограничения бизнес-логики

Точная длина массива

Метод length(n) задаёт строго фиксированное количество элементов.

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

schema.validate({ coordinates: [10] });
// Ошибка: "coordinates" must contain 2 items

Используется, когда структура строго фиксирована:

  • координаты [x, y]
  • RGB цвета [r, g, b]
  • пары значений ключ–значение в виде массива

Комбинация ограничений длины

Ограничения можно комбинировать для более точного контроля.

const schema = Joi.object({
  values: Joi.array().min(2).max(5)
});

Логика проверки:

  • минимум 2 элемента
  • максимум 5 элементов
  • диапазон становится допустимым множеством значений длины

При этом length(n) конфликтует с min/max, поскольку задаёт фиксированное значение.

Пустые массивы и обязательность

Важно различать поведение required() и ограничений длины.

const schema = Joi.object({
  list: Joi.array().min(1).required()
});

Сценарии:

  • поле отсутствует → ошибка required
  • поле есть, но [] → ошибка min(1)
  • поле содержит элементы → проходит проверку

Если требуется разрешить пустой массив:

Joi.array().allow([])

или

Joi.array().min(0)

Валидация содержимого и длины одновременно

Ограничения длины часто используются вместе с проверкой типов элементов через items().

const schema = Joi.object({
  ids: Joi.array().items(Joi.number().integer()).min(1).max(10)
});

Здесь одновременно проверяется:

  • каждый элемент является целым числом
  • массив не пустой
  • длина не превышает 10 элементов

Уникальность элементов и длина

Метод unique() не влияет на длину напрямую, но может косвенно изменять результат валидации.

const schema = Joi.object({
  tags: Joi.array().unique().min(2)
});

Поведение:

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

Упорядоченные массивы и ограничения длины

При использовании ordered() структура массива фиксируется по позициям, но длина всё равно регулируется отдельно.

const schema = Joi.array().ordered(
  Joi.string(),
  Joi.number()
).length(2);

Это означает:

  • первый элемент — строка
  • второй элемент — число
  • строго два элемента

Особенности sparse массивов

JavaScript позволяет создавать разреженные массивы, и Joi учитывает это поведение.

const arr = [1, , 3];

Валидация:

  • пропущенные элементы могут учитываться как undefined
  • длина массива определяется как фактическая длина структуры, а не количеством значений
  • ограничения min/max/length применяются к размеру массива, а не к заполненности

Кастомизация сообщений ошибок

Joi позволяет переопределять сообщения для ограничений длины.

const schema = Joi.array()
  .min(2)
  .messages({
    'array.min': 'Необходимо минимум 2 элемента'
  });

Распространённые ключи ошибок:

  • array.min
  • array.max
  • array.length

Это позволяет адаптировать ответы под пользовательский интерфейс или API-стандарты.

Практические сценарии использования

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

  • список файлов загрузки (ограничение 5–10 элементов)
  • выбор категорий (минимум 1, максимум 3)
  • координаты и фиксированные структуры данных
  • пакетные операции API (ограничение числа операций за запрос)
  • формы с динамическими полями (например, список телефонов)

Проверка крайних случаев

При проектировании схем важно учитывать пограничные ситуации:

  • undefined и отсутствие поля
  • пустой массив []
  • массив с null элементами
  • превышение максимального размера
  • совпадение с точной длиной

Пример строгой схемы:

const schema = Joi.object({
  batch: Joi.array()
    .items(Joi.string().required())
    .min(1)
    .max(100)
    .required()
});

Такая конфигурация гарантирует:

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

Поведение при преобразованиях

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

const schema = Joi.object({
  list: Joi.array().min(1).custom((value) => {
    return value.filter(Boolean);
  })
});

В этом случае:

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