Массивы: array()

Схема Joi.array() используется для валидации массивов произвольной структуры. Базовая проверка ограничивается только типом значения:

import Joi from 'joi';

const schema = Joi.array();

schema.validate([1, 2, 3]); // корректно
schema.validate('not array'); // ошибка

При отсутствии уточнений допускаются любые элементы, включая смешанные типы.


Определение допустимых элементов: items()

Метод items() задаёт схему элементов массива. Это основной механизм строгой типизации:

const schema = Joi.array().items(Joi.number());

schema.validate([1, 2, 3]);      // корректно
schema.validate([1, '2', 3]);    // ошибка

Допускается использование сложных схем:

const schema = Joi.array().items(
  Joi.object({
    id: Joi.number().required(),
    name: Joi.string().required()
  })
);

В этом случае каждый элемент массива должен соответствовать объектной схеме.


Ограничение длины массива

Для управления размером массива применяются методы min(), max() и length():

const schema = Joi.array().min(2).max(5);

schema.validate([1]);           // ошибка (меньше 2)
schema.validate([1, 2, 3, 4]);  // корректно
schema.validate([1, 2, 3, 4, 5, 6]); // ошибка (больше 5)

Точное значение длины задаётся через length():

const schema = Joi.array().length(3);

schema.validate([1, 2, 3]); // корректно
schema.validate([1, 2]);     // ошибка

Уникальность элементов: unique()

Метод unique() запрещает повторяющиеся значения:

const schema = Joi.array().unique();

schema.validate([1, 2, 3]); // корректно
schema.validate([1, 1, 2]); // ошибка

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

const schema = Joi.array().unique('id');

schema.validate([
  { id: 1 },
  { id: 2 }
]); // корректно

При совпадении указанного поля элементы считаются дубликатами.


Обязательные и пустые массивы

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

const schema = Joi.array().required();

Запрещает undefined и null.

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

const schema = Joi.array().min(1);

Также можно запретить пустое значение явно:

const schema = Joi.array().empty();

Смешанные типы элементов

При отсутствии items() массив может содержать любые типы:

const schema = Joi.array();

schema.validate([1, 'text', true, null]);

При этом валидация ограничивается только самим фактом массива.


contains(): обязательное наличие элементов

Метод contains() задаёт требование наличия хотя бы одного элемента, соответствующего схеме:

const schema = Joi.array().items(Joi.number()).contains(5);

schema.validate([1, 2, 5]); // корректно
schema.validate([1, 2, 3]); // ошибка

Используется для проверки обязательного присутствия значения в коллекции.


has(): проверка подмножества

Метод has() требует наличия хотя бы одного элемента, удовлетворяющего схеме:

const schema = Joi.array().has(Joi.object({ role: 'admin' }));

schema.validate([
  { role: 'user' },
  { role: 'admin' }
]); // корректно

В отличие от contains(), логика ориентирована на соответствие условию, а не конкретному значению.


ordered(): строгий порядок элементов

ordered() задаёт фиксированную позиционную структуру массива:

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

schema.validate(['text', 123, true]); // корректно
schema.validate([123, 'text', true]); // ошибка

Каждая позиция соответствует своей схеме.


items() vs ordered(): различие моделей

  • items() — все элементы должны соответствовать набору схем без привязки к позиции
  • ordered() — строгая позиционная структура

Пример комбинирования:

const schema = Joi.array().ordered(
  Joi.string(),
  Joi.number()
).items(Joi.any());

Разреженные массивы: sparse()

По умолчанию Joi допускает undefined в массиве. Поведение можно контролировать через sparse():

const schema = Joi.array().sparse(false).items(Joi.number());

Теперь undefined в элементах запрещён:

schema.validate([1, undefined, 3]); // ошибка

Вложенные массивы

Массивы могут быть рекурсивными:

const schema = Joi.array().items(
  Joi.array().items(Joi.number())
);

schema.validate([[1, 2], [3, 4]]);

Поддерживается произвольная глубина вложенности при корректной схеме.


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

Частый сценарий — массив объектов с комплексной структурой:

const schema = Joi.array().items(
  Joi.object({
    id: Joi.number().required(),
    tags: Joi.array().items(Joi.string())
  })
);

Валидация распространяется на каждый уровень вложенности.


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

Метод custom() позволяет реализовать произвольные проверки:

const schema = Joi.array().custom((value, helpers) => {
  if (value.includes(0)) {
    return helpers.error('array.containsZero');
  }
  return value;
});

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


Преобразования данных массива

Joi позволяет выполнять трансформации через custom():

const schema = Joi.array().custom((value) => {
  return value.map(Number);
});

Также возможно нормализовать данные перед дальнейшей проверкой.


Комбинирование ограничений

Сложные схемы часто включают несколько правил одновременно:

const schema = Joi.array()
  .items(Joi.number())
  .min(2)
  .max(10)
  .unique()
  .required();

Такая композиция позволяет описывать строгие контракты для входных данных API и бизнес-логики.