В библиотеке валидации Joi ключевым концептом является instance (экземпляр схемы) — объект, который представляет собой конкретное правило валидации для данных определённого типа. Каждый такой экземпляр создаётся через набор конструкторов и фабричных методов и является неизменяемым (immutable) после создания.
Instance в Joi — это не просто структура данных, а полноценная конфигурация правил, которая включает:
Пример базового экземпляра:
const Joi = require('joi');
const schema = Joi.string().min(3).max(10).required();
В данном случае schema — это instance, созданный
конструктором Joi.string() и модифицированный цепочкой
методов.
Каждый тип данных в Joi создаётся через специализированный конструктор. Эти конструкторы являются фабричными функциями, возвращающими новый экземпляр схемы.
const schema = Joi.string();
Возвращает instance типа StringSchema, который далее
может быть расширен:
Joi.string()
.min(5)
.max(20)
.email()
.required();
const schema = Joi.number();
Поддерживает числовые ограничения:
Joi.number()
.integer()
.positive()
.min(1)
.max(100);
const schema = Joi.object({
name: Joi.string(),
age: Joi.number()
});
Объектный instance играет центральную роль в Joi, так как позволяет описывать вложенные структуры.
const schema = Joi.array().items(Joi.string());
Позволяет задавать ограничения на элементы массива:
Joi.array()
.items(Joi.number().integer())
.min(1)
.max(10);
Каждый instance в Joi содержит внутреннее состояние, которое описывает:
Пример логической структуры:
{
type: 'string',
rules: [
{ name: 'min', args: { limit: 3 } },
{ name: 'max', args: { limit: 10 } }
],
flags: {
presence: 'required'
}
}
Все instance в Joi являются immutable. Это означает, что каждый вызов метода не изменяет текущий объект, а возвращает новый экземпляр схемы.
const base = Joi.string();
const extended = base.min(5);
console.log(base === extended); // false
Такой подход обеспечивает:
Instance в Joi поддерживает fluent API, основанный на цепочках вызовов.
const passwordSchema = Joi.string()
.min(8)
.pattern(/[A-Z]/)
.pattern(/[0-9]/)
.required();
Каждый метод возвращает новый instance, расширяющий предыдущий.
Композиция позволяет создавать базовые схемы и переиспользовать их:
const baseString = Joi.string().trim().lowercase();
const username = baseString.min(3).max(30);
const tag = baseString.max(15);
При необходимости Joi создаёт копии схем через внутренний механизм clone.
const schema1 = Joi.string().min(3);
const schema2 = schema1.min(5);
Здесь schema2 — это не модификация schema1,
а новый instance с обновлёнными правилами.
Клонирование используется при:
Object instance является наиболее сложным типом в Joi.
const userSchema = Joi.object({
id: Joi.number().integer(),
name: Joi.string(),
email: Joi.string().email()
});
Внутри такой instance хранит:
Дополнительные методы:
Joi.object()
.keys({...})
.unknown(false)
.required();
Instance может создаваться динамически в зависимости от условий:
function createSchema(isStrict) {
let schema = Joi.object({
name: Joi.string(),
age: Joi.number()
});
if (isStrict) {
schema = schema.required().unknown(false);
}
return schema;
}
Joi позволяет создавать расширенные instance через extend API.
const custom = Joi.extend((joi) => ({
type: 'evenNumber',
base: joi.number(),
validate(value, helpers) {
if (value % 2 !== 0) {
return { value, errors: helpers.error('number.even') };
}
}
}));
Здесь создаётся новый тип instance, основанный на
number.
Часто используется подход создания базового instance, от которого строятся остальные схемы.
const base = Joi.string().trim().lowercase();
const email = base.email();
const username = base.alphanum().min(3);
Это позволяет централизовать общие правила.
Каждый instance содержит встроенную логику выполнения проверки:
const schema = Joi.string().min(3);
const result = schema.validate('ab');
Instance выступает как компилированное описание валидатора.
Перед валидацией Joi может компилировать schema instance в оптимизированную структуру:
Это снижает стоимость повторных вызовов validate.
Instance можно безопасно использовать многократно:
const schema = Joi.number().integer().positive();
schema.validate(10);
schema.validate(20);
Так как instance неизменяем, он подходит для глобальных конфигураций.
Joi активно использует вложенные схемы:
const schema = Joi.object({
profile: Joi.object({
age: Joi.number().min(18)
})
});
Здесь каждый уровень — отдельный instance со своей логикой.
Instance в Joi — это декларативное описание, которое преобразуется в runtime-алгоритм проверки. В отличие от ручных проверок, instance:
Это отделяет описание данных от их обработки и делает систему масштабируемой.