Joi — система валидации схем, построенная вокруг идеи декларативного описания данных и их строгой проверки с возможностью автоматических преобразований типов. Одной из ключевых возможностей является механизм приведения (coercion), который позволяет нормализовать входные значения до этапа основной валидации.
Внутренний процесс обработки значения в Joi можно рассматривать как последовательность стадий:
Coercion выполняется до проверки ограничений, что принципиально важно: схема работает не с тем, что пришло «как есть», а с тем, что было приведено к ожидаемому типу.
Типичный пример поведения:
const schema = Joi.number();
schema.validate("42"); // результат: 42 (число)
Строка "42" автоматически преобразуется в число,
поскольку включена опция преобразования по умолчанию.
Поведение coercion регулируется глобально и локально через
convert.
const schema = Joi.number();
schema.validate("42", { convert: false });
// ошибка валидации: expected number
Или через параметры схемы:
const schema = Joi.object({
value: Joi.number()
}).prefs({ convert: false });
Отключение coercion переводит Joi в строгий режим: тип входных данных должен совпадать с ожидаемым.
По умолчанию convert: true, что включает:
Joi содержит набор встроенных трансформаций, которые являются частью coercion pipeline.
const schema = Joi.string().trim().lowercase();
schema.validate(" HELLO ");
// результат: "hello"
Этапы:
Важно, что это не «валидаторы», а трансформеры.
const schema = Joi.number();
schema.validate("0032");
// 32
Поддерживается:
Некорректные значения:
Joi.number().validate("12px"); // ошибка
const schema = Joi.boolean();
schema.validate("true"); // true
schema.validate("false"); // false
schema.validate(1); // true
schema.validate(0); // false
Coercion boolean значений опирается на набор предопределённых правил интерпретации.
const schema = Joi.object({
id: Joi.number(),
active: Joi.boolean()
});
schema.validate({
id: "10",
active: "true"
});
Результат:
{
id: 10,
active: true
}
Каждое поле проходит собственный pipeline преобразований.
Joi.object({
a: Joi.number()
}).prefs({ stripUnknown: true });
Coercion применяется до удаления неизвестных полей, что важно для корректной нормализации входа.
customJoi позволяет задавать пользовательскую логику трансформации.
const schema = Joi.string().custom((value, helpers) => {
return value.replace(/\s+/g, "-");
});
schema.validate("hello world");
// "hello-world"
Особенности:
helpers.erroralter для условных преобразованийconst schema = Joi.object({
name: Joi.string().alter({
trim: (schema) => schema.trim(),
upper: (schema) => schema.uppercase()
})
});
const extended = schema.tailor('trim');
Механизм позволяет динамически включать разные наборы преобразований.
Для сложных типов используется расширение Joi:
const customType = Joi.extend((joi) => ({
type: "timestamp",
base: joi.number(),
coerce(value) {
if (typeof value === "string") {
return { value: Date.parse(value) };
}
return { value };
}
}));
const schema = Joi.array().items(Joi.number());
schema.validate(["1", "2", "3"]);
// [1, 2, 3]
Дополнительные трансформации:
Joi.array().single();
Позволяет принимать одиночное значение как массив:
schema.validate("1"); // ["1"]
const schema = Joi.number().default(10);
schema.validate(undefined);
// 10
Порядок:
presence и
влияние на преобразованияJoi.object({
a: Joi.number().required()
}).prefs({ presence: "optional" });
Coercion применяется даже к отсутствующим значениям при наличии default-логики, но required-поля должны присутствовать до финальной проверки.
const schema = Joi.number().strict();
schema.validate("42");
// ошибка
strict() эквивалентен convert: false на
уровне схемы.
const schema = Joi.object({
a: Joi.number(),
b: Joi.number().valid(Joi.ref("a"))
});
Значение a сначала приводится к числу, и только затем
используется в ref.
Порядок применения трансформаций:
.custom().default()Полное описание поведения и актуальные изменения схемной системы находятся в официальной документации библиотеки Joi Documentation