object()
Валидация объектов в Joi строится вокруг описания структуры данных
через схемы, где каждый ключ и его значение проверяются по заданным
правилам. Базовый конструктор для описания объектов —
Joi.object(). Он задаёт контейнер, внутри которого
определяются правила для полей и их взаимосвязей.
Основная идея заключается в том, что объект рассматривается как набор ключей, каждый из которых может иметь собственную схему валидации. Это позволяет строго контролировать структуру входных данных, включая вложенные объекты и сложные иерархии.
Схема объекта создаётся через вызов:
const schema = Joi.object({
name: Joi.string(),
age: Joi.number()
});
В этом случае описывается структура, где объект должен содержать поля
name и age, соответствующие указанным
типам.
Joi по умолчанию разрешает наличие дополнительных полей, если это не ограничено явно.
Каждое свойство объекта описывается как самостоятельная схема:
const schema = Joi.object({
id: Joi.string().alphanum().required(),
email: Joi.string().email().required(),
isActive: Joi.boolean().default(true)
});
Здесь:
id должен быть строкой, содержащей только буквы и
цифрыemail должен соответствовать формату emailisActive необязателен и получает значение по
умолчаниюJoi различает обязательные и необязательные поля через методы
.required() и .optional().
const schema = Joi.object({
username: Joi.string().required(),
nickname: Joi.string().optional()
});
По умолчанию поля считаются необязательными, если не указано обратное.
Одним из ключевых механизмов управления структурой объекта является
метод .unknown().
const schema = Joi.object({
name: Joi.string()
}).unknown(false);
Поведение:
unknown(false) — запрещает любые поля, не описанные в
схемеunknown(true) — разрешает дополнительные поля
(поведение по умолчанию)Пример строгой схемы:
const schema = Joi.object({
id: Joi.number()
}).unknown(false);
Любые лишние ключи приведут к ошибке валидации.
Метод .keys() используется для явного задания структуры
объекта после его создания.
const schema = Joi.object().keys({
title: Joi.string(),
content: Joi.string()
});
Этот вариант эквивалентен передаче объекта в
Joi.object({...}), но удобен при динамическом построении
схем.
Joi поддерживает рекурсивное описание объектов:
const schema = Joi.object({
user: Joi.object({
id: Joi.number().required(),
profile: Joi.object({
firstName: Joi.string(),
lastName: Joi.string()
})
})
});
Вложенные структуры позволяют описывать сложные модели данных, включая API-ответы и конфигурации.
Joi позволяет ограничивать количество ключей в объекте:
const schema = Joi.object({
a: Joi.string(),
b: Joi.string()
}).min(1).max(2);
Методы:
.min(n) — минимальное количество ключей.max(n) — максимальное количество ключей.length(n) — строго фиксированное количество
ключейВсе указанные ключи должны присутствовать одновременно:
Joi.object({
a: Joi.string(),
b: Joi.string(),
c: Joi.string()
}).and('a', 'b');
Если присутствует a, то обязательно должен быть
b, и наоборот.
Должен присутствовать хотя бы один из ключей:
Joi.object({
a: Joi.string(),
b: Joi.string()
}).or('a', 'b');
Присутствует ровно один из указанных ключей:
Joi.object({
a: Joi.string(),
b: Joi.string()
}).xor('a', 'b');
Эксклюзивный вариант, где допускается не более одного из ключей:
Joi.object({
a: Joi.string(),
b: Joi.string(),
c: Joi.string()
}).oxor('a', 'b', 'c');
Запрещает одновременное присутствие ключей:
Joi.object({
a: Joi.string(),
b: Joi.string()
}).nand('a', 'b');
Метод .pattern() позволяет валидировать динамические
ключи:
const schema = Joi.object({
[Joi.string().pattern(/^[a-z]+$/)]: Joi.number()
});
Также используется альтернативная форма:
const schema = Joi.object().pattern(
/^[a-z]+$/,
Joi.number()
);
Это полезно для объектов с неизвестной заранее структурой, например:
{
"a": 1,
"b": 2,
"c": 3
}
Joi позволяет изменять структуру входного объекта до валидации.
const schema = Joi.object({
firstName: Joi.string()
}).rename('first_name', 'firstName');
Дополнительные параметры:
.rename('oldKey', 'newKey', {
ignoreUndefined: true,
override: true
});
override — заменяет существующее значениеignoreUndefined — игнорирует
undefinedМетод .fork() позволяет модифицировать поведение
отдельных ключей без переписывания всей схемы.
const baseSchema = Joi.object({
password: Joi.string(),
email: Joi.string().email()
});
const strictSchema = baseSchema.fork(['password'], (schema) =>
schema.required()
);
Это позволяет создавать вариации одной и той же модели данных.
Объекты могут иметь значения по умолчанию:
const schema = Joi.object({
role: Joi.string().default('user'),
active: Joi.boolean().default(true)
});
Если поле отсутствует, оно автоматически добавляется при валидации.
Метод .prefs() задаёт поведение валидации:
const schema = Joi.object({
name: Joi.string()
}).prefs({
abortEarly: false,
stripUnknown: true
});
Основные параметры:
abortEarly: false — собирает все ошибки, а не
останавливается на первойstripUnknown: true — удаляет лишние поляconvert: true — автоматически приводит типыУдаление неописанных полей часто используется в API:
const schema = Joi.object({
id: Joi.number()
}).unknown(false).prefs({
stripUnknown: true
});
Результат — объект содержит только валидированные ключи.
Joi обрабатывает вложенные структуры рекурсивно:
const schema = Joi.object({
config: Joi.object({
settings: Joi.object({
theme: Joi.string(),
layout: Joi.string()
})
})
});
Каждый уровень проходит собственную проверку по своей схеме.
Схемы могут объединяться:
const base = Joi.object({
id: Joi.number()
});
const extended = base.keys({
name: Joi.string()
});
Также возможно использование .concat():
const schema = base.concat(
Joi.object({
name: Joi.string()
})
);
При проверке объекта используется:
const { error, value } = schema.validate(data);
error содержит описание ошибокvalue содержит преобразованные данныеПри включённых преобразованиях Joi может:
Комбинация .required(), .unknown(false) и
.stripUnknown(true) формирует строгую схему:
const schema = Joi.object({
id: Joi.number().required(),
name: Joi.string().required()
})
.unknown(false)
.prefs({ stripUnknown: true });
Такая конфигурация используется для API, где структура данных должна быть полностью предсказуемой.