В Joi процесс валидации строится вокруг детерминированного выполнения цепочки правил, где каждое правило применяется к значению последовательно в соответствии с внутренним порядком схемы. При использовании методов проверки результат может возвращаться двумя основными способами: через объект результата или через выброс исключения.
Ключевое различие между подходами проявляется при использовании
schema.validate, schema.validateAsync и
Joi.attempt.
schema.validateМетод validate выполняет проверку без исключений:
const result = schema.validate(value);
if (result.error) {
// обработка ошибки
}
Возвращаемая структура содержит:
value — преобразованное значение после всех правилerror — объект ошибки, если проверка не прошлаВ этом режиме порядок обработки ошибок определяется параметрами
схемы, в частности abortEarly.
schema.validateAsyncАсинхронная версия интегрируется с async/await и
использует исключения:
try {
const value = await schema.validateAsync(input);
} catch (err) {
// обработка ошибки валидации
}
При любой ошибке выполнение прерывается, и управление передаётся в
catch.
Joi.attemptМетод attempt реализует строгий режим:
const value = Joi.attempt(input, schema);
При нарушении правил сразу выбрасывается исключение. Это делает
attempt эквивалентом синтаксического сокращения для
validateAsync с обязательным throw.
Внутри Joi порядок проверки определяется не только структурой объекта схемы, но и последовательностью вызова модификаторов.
Цепочка правил выполняется слева направо:
Joi.string()
.min(5)
.max(10)
.pattern(/^[a-z]+$/)
Фактический порядок проверки:
min(5)max(10)pattern(...)Каждый этап может модифицировать значение или завершить выполнение с ошибкой.
abortEarly на порядок ошибокПараметр abortEarly управляет тем, останавливается ли
проверка при первой ошибке:
schema.validate(value, { abortEarly: true });
При значении true:
При значении false:
Это напрямую влияет на наблюдаемый порядок проверки, но не меняет внутреннюю последовательность применения правил.
Joi выполняет преобразования до финальной валидации:
Joi.number().integer().min(10)
Фактический порядок:
integerminЕсли преобразование невозможно, дальнейшие шаги не выполняются.
when и alternativesУсловные схемы изменяют порядок проверки динамически.
whenJoi.object({
a: Joi.number(),
b: Joi.number().when('a', {
is: 10,
then: Joi.required()
})
})
Здесь порядок становится зависимым от значения a:
abalternativesJoi.alternatives().try(
Joi.string(),
Joi.number()
)
Проверка выполняется последовательно:
Порядок альтернатив критичен: первая подходящая схема завершает проверку.
Некоторые методы не просто проверяют значение, а изменяют его до следующего шага:
Joi.string()
.trim()
.lowercase()
.min(3)
Фактический порядок:
trim() — удаление пробеловlowercase() — преобразование регистраmin(3) — проверка длиныЕсли бы min выполнялся раньше, результат мог бы
отличаться, поэтому Joi строго фиксирует последовательность
трансформаций.
Исключение формируется в момент первого нарушения правила, если
включён режим остановки. При отключённом abortEarly ошибки
агрегируются, но порядок их добавления соответствует порядку правил в
схеме.
Пример:
Joi.string().min(5).max(10).pattern(/[0-9]+/)
При abortEarly: false возможны несколько ошибок:
minpatternmaxИх порядок совпадает с порядком объявления.
custom функции встраиваются в общий пайплайн:
Joi.number().custom((value, helpers) => {
if (value < 0) {
return helpers.error('number.negative');
}
return value;
})
Порядок:
Важно, что кастомное правило может прервать дальнейшую проверку, изменив логическую цепочку выполнения.
Синхронная проверка (validate) и асинхронная
(validateAsync) используют одинаковую внутреннюю
последовательность правил. Различие только в механизме доставки
результата:
Promise и исключенияПорядок применения правил не зависит от выбранной модели.
presenceПараметр presence влияет на начальную стадию
проверки:
requiredoptionalforbiddenОн обрабатывается до остальных правил, формируя базовое состояние валидности поля. Например:
Joi.string().required().min(3)
Проверка required выполняется до min,
поскольку отсутствие значения делает дальнейшие шаги бессмысленными.
При проверке объектов Joi проходит по полям в порядке их описания в схеме:
Joi.object({
a: Joi.number(),
b: Joi.string(),
c: Joi.boolean()
})
Порядок:
abcПри включённом abortEarly порядок напрямую определяет,
какая ошибка будет первой.
Некоторые типы правил имеют более высокий приоритет:
min, max,
pattern)trim, lowercase,
default)Этот порядок фиксирован и не зависит от расположения методов в цепочке, если они принадлежат разным категориям обработки.