В процессе работы с библиотекой Joi ключевым элементом диагностики
схем становится объект ошибки, возвращаемый методами
validate и validateAsync. Стандартная ошибка
содержит поле details, представляющее массив объектов,
каждый из которых описывает отдельное нарушение правил схемы.
Каждый элемент details включает:
message — человекочитаемое описание проблемы;path — путь к узлу данных, где произошла ошибка;type — тип нарушения (например,
string.min, number.base);context — дополнительный контекст (ожидаемое значение,
фактическое значение и параметры правила).Именно анализ type и path позволяет точно
локализовать ошибку в сложных вложенных структурах.
По умолчанию Joi останавливает проверку при первой найденной ошибке.
Это поведение определяется опцией abortEarly.
schema.validate(data, { abortEarly: false })
При отключённом abortEarly происходит полная проверка
всех полей схемы, что существенно упрощает диагностику комплексных
объектов.
Типичные сценарии:
false;true для ускорения
проверки.Поле path является основным инструментом навигации по
структуре данных.
Пример:
details: [
{
path: ['user', 'profile', 'age'],
type: 'number.min'
}
]
Такой результат указывает на точное место нарушения внутри вложенного объекта.
При сложных структурах (массивы объектов, динамические ключи)
path становится критически важным для построения
диагностических логов.
Метод describe() позволяет получить декларативное
описание схемы без выполнения валидации.
const description = schema.describe()
В возвращаемой структуре присутствуют:
required, optional,
default).Этот механизм используется для:
Частая проблема возникает при наложении взаимоисключающих ограничений:
Joi.number().min(10).max(5)
Такая схема всегда невалидна, однако ошибка может быть неочевидной при динамической генерации.
Ошибки часто появляются при несоответствии структуры данных и схемы:
Joi.object({
user: Joi.object({
age: Joi.number()
})
})
и данных:
{ user: null }
В этом случае ошибка возникает на уровне object.base, а
не внутри age, что затрудняет диагностику без анализа
type.
Joi строго различает типы. Например, строка "123" не
считается числом:
number.base — передано значение неверного типа;string.base — ожидалась строка, получен другой
тип.Использование messages() позволяет переопределять текст
ошибок:
Joi.string().min(3).messages({
'string.min': 'Слишком короткое значение'
})
Однако при чрезмерной кастомизации теряется диагностическая
информация, особенно type. Это усложняет автоматическую
обработку ошибок.
Оптимальная практика — сохранять оригинальный type,
изменяя только текст сообщения.
Метод validateAsync возвращает промис, что требует явной
обработки ошибок:
try {
await schema.validateAsync(data)
} catch (err) {
console.log(err.details)
}
Особенности диагностики:
message.Опция stripUnknown удаляет поля, отсутствующие в
схеме.
Joi.object().unknown(false).validate(data)
При отладке это может приводить к эффекту «исчезающих данных», когда входной объект изменяется до завершения анализа.
Для диагностики:
stripUnknown;Поле context содержит параметры, переданные в
правило.
Пример:
Joi.string().min(5)
Ошибка:
context: {
limit: 5,
value: 'abc'
}
В сложных схемах context становится основным источником
понимания причины сбоя, особенно при использовании кастомных валидаторов
через custom().
Для масштабных систем важно стандартизировать логирование:
path используется как ключ маршрутизации;type — как код ошибки;context — как диагностические данные.Пример структуры лога:
{
"field": "user.profile.age",
"errorType": "number.min",
"expected": 18,
"received": 15
}
Такой формат позволяет интегрировать Joi-ошибки в системы мониторинга.
При работе с массивами объектов ошибки часто дублируются по индексу:
path: ['items', 3, 'price']
Это означает четвёртый элемент массива. При динамической генерации данных важно учитывать:
Метод assert используется для мгновенной валидации:
Joi.assert(data, schema)
При ошибке выбрасывается исключение, что упрощает тестирование схем. Однако отсутствие возвращаемого объекта требует дополнительного логирования входных данных.
Метод extract(path) позволяет изолировать часть
схемы:
schema.extract('user.profile')
Это применяется для:
При комбинировании .required(),
.optional(), .default() часто возникают
неоднозначные состояния:
undefined;Joi обрабатывает эти состояния строго по приоритету, что может приводить к неожиданным результатам при отладке.
Функция custom() добавляет произвольную логику:
Joi.string().custom((value, helpers) => {
if (value === 'x') return helpers.error('any.invalid')
return value
})
При отладке таких схем важно:
helpers.error() с уникальными кодами;Один из ключевых методов диагностики — сравнение:
Это позволяет выявить трансформации, вызванные default,
cast или convert.
Joi выполняет неявное приведение типов при включённой опции
convert.
Joi.number().validate("123")
Возможные проблемы:
Для диагностики полезно отключать convert.
Эффективная отладка Joi-схем строится вокруг трёх уровней:
details, path,
type);describe, extract);convert,
default, stripUnknown).Совокупный анализ этих элементов позволяет точно локализовать источник несоответствия между схемой и данными без необходимости внешних инструментов.