Строгая типизация схем

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

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


Базовые принципы строгой схемы

Строгая схема в Joi строится вокруг трёх ключевых аспектов:

1. Отключение преобразования типов 2. Запрет неявных полей и структурных изменений 3. Жёсткое определение обязательности значений

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


Отключение преобразования типов

Joi по умолчанию пытается «исправить» входные данные. Например:

Joi.number().validate("42")

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

Для строгой типизации такое поведение недопустимо. Отключение выполняется через convert: false:

const schema = Joi.number().prefs({ convert: false });

Теперь строка "42" не будет автоматически преобразована в число и приведёт к ошибке валидации.

Аналогичный эффект можно задать глобально:

const schema = Joi.object({
  age: Joi.number()
}).options({ convert: false });

Явная типовая строгость

Каждый тип в Joi имеет строгую интерпретацию:

  • Joi.string() — допускает только строки
  • Joi.number() — только числа
  • Joi.boolean() — только булевы значения
  • Joi.object() — только объекты

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

Пример:

const schema = Joi.object({
  id: Joi.number()
}).prefs({ convert: false });

schema.validate({ id: "10" });

Результат: ошибка, так как строка не преобразуется в число.


Контроль обязательных значений

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

Joi предоставляет три основных модификатора:

  • required() — поле обязательно
  • optional() — поле может отсутствовать
  • forbidden() — поле запрещено

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

const schema = Joi.object({
  username: Joi.string().required(),
  password: Joi.string().required(),
  token: Joi.string().forbidden()
}).prefs({ convert: false });

В данном случае:

  • отсутствие username или password приведёт к ошибке
  • наличие token приведёт к ошибке

Запрет неизвестных полей

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

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

const schema = Joi.object({
  name: Joi.string()
}).unknown(false);

или через опции:

const schema = Joi.object({
  name: Joi.string()
}).options({ allowUnknown: false });

Теперь любой дополнительный ключ в объекте приведёт к ошибке.

Пример:

schema.validate({
  name: "Alex",
  age: 30
});

Результат — ошибка, так как age не описан в схеме.


Строгость вложенных объектов

Строгая типизация должна распространяться на все уровни вложенности.

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

Здесь:

  • запрещены лишние поля внутри user
  • запрещены нечисловые значения id
  • запрещено автоматическое преобразование типов

Поведение при строгой валидации

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

  • данные полностью соответствуют схеме → успех
  • любое отклонение → ошибка

Пример результата ошибки:

{
  "error": {
    "message": "\"id\" must be a number",
    "type": "number.base"
  }
}

Удаление лишних данных вместо отклонения

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

const schema = Joi.object({
  name: Joi.string()
}).stripUnknown(true);

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

Однако это уже не строгая типизация, а контролируемая фильтрация структуры.


Комбинирование строгих правил

На практике строгая схема формируется комбинацией параметров:

const schema = Joi.object({
  id: Joi.number().required(),
  name: Joi.string().required()
})
.unknown(false)
.options({ convert: false });

Такой подход фиксирует:

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

Поведение .strict()

Joi предоставляет метод .strict(), который отключает преобразования для конкретного типа:

const schema = Joi.number().strict();

Это эквивалентно:

Joi.number().prefs({ convert: false });

Однако .strict() применяется локально и удобен для точечной настройки отдельных полей:

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

Влияние строгой типизации на производительность и контроль данных

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

Дополнительный эффект:

  • упрощение серверной логики (данные приходят уже в предсказуемом виде)
  • снижение риска скрытых преобразований
  • более стабильное поведение API

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


Работа с массивами в строгом режиме

Для массивов строгая типизация включает контроль элементов:

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

Здесь запрещены:

  • строки вместо чисел
  • смешанные типы внутри массива

Любое несоответствие одного элемента приводит к ошибке всей структуры.


Ограничение расширяемости объектов

В строгом режиме часто используется фиксация структуры объекта:

const schema = Joi.object({
  id: Joi.number(),
  name: Joi.string()
}).length(2);

Это дополнительно гарантирует, что объект содержит ровно два поля.


Согласованность строгих схем

При построении сложных схем важно поддерживать единый уровень строгости:

  • единые правила для convert
  • единое поведение unknown
  • согласованные требования required

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


Итоговые характеристики строгой модели Joi

Строгая типизация в Joi формируется набором ограничений:

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