По умолчанию Joi строго относится к структуре объекта.
Если схема описывает только определённые поля, любые дополнительные
ключи считаются ошибкой.
const Joi = require('joi');
const schema = Joi.object({
username: Joi.string().required(),
age: Joi.number()
});
const result = schema.validate({
username: 'alex',
age: 25,
role: 'admin'
});
console.log(result.error.message);
Результат:
"role" is not allowed
Поле role отсутствует в схеме, поэтому валидация
завершается ошибкой.
.unknown()Метод .unknown() разрешает наличие дополнительных полей,
которые не описаны в схеме.
const schema = Joi.object({
username: Joi.string().required()
}).unknown();
const result = schema.validate({
username: 'alex',
role: 'admin',
permissions: ['read', 'write']
});
console.log(result.error);
Результат:
undefined
Все лишние ключи сохраняются в объекте и не вызывают ошибку.
.unknown(false) явно запрещает неизвестные поля.
const schema = Joi.object({
username: Joi.string()
}).unknown(false);
const result = schema.validate({
username: 'alex',
role: 'admin'
});
console.log(result.error.message);
Результат:
"role" is not allowed
Фактически это поведение используется по умолчанию.
Вместо вызова .unknown() можно использовать опцию
allowUnknown.
const schema = Joi.object({
username: Joi.string()
});
const result = schema.validate(
{
username: 'alex',
role: 'admin'
},
{
allowUnknown: true
}
);
console.log(result.value);
Результат:
{
username: 'alex',
role: 'admin'
}
.unknown() и allowUnknown.unknown()Изменяет саму схему.
const schema = Joi.object({
name: Joi.string()
}).unknown();
Такая схема всегда будет разрешать дополнительные поля.
allowUnknownИзменяет поведение конкретной операции валидации.
schema.validate(data, {
allowUnknown: true
});
Одна и та же схема может использоваться с разными настройками.
Разрешение неизвестных ключей не распространяется автоматически на дочерние объекты.
const schema = Joi.object({
profile: Joi.object({
name: Joi.string()
})
}).unknown();
const result = schema.validate({
profile: {
name: 'Alex',
city: 'Berlin'
}
});
console.log(result.error.message);
Результат:
"profile.city" is not allowed
Внешний объект допускает дополнительные поля, но вложенный объект
profile остаётся строгим.
const schema = Joi.object({
profile: Joi.object({
name: Joi.string()
}).unknown()
});
const result = schema.validate({
profile: {
name: 'Alex',
city: 'Berlin'
}
});
console.log(result.error);
Результат:
undefined
.forbidden().forbidden() запрещает присутствие ключа в объекте.
const schema = Joi.object({
username: Joi.string(),
password: Joi.string(),
isAdmin: Joi.forbidden()
});
const result = schema.validate({
username: 'alex',
password: '123456',
isAdmin: true
});
console.log(result.error.message);
Результат:
"isAdmin" is not allowed
.forbidden() особенно полезен для блокировки полей,
которые не должны приходить от клиента.
const createUserSchema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(8).required(),
id: Joi.forbidden(),
createdAt: Joi.forbidden(),
updatedAt: Joi.forbidden(),
role: Joi.forbidden()
});
Такая схема защищает серверную логику от попыток подмены данных.
Без .forbidden() поведение зависит от настроек
unknown-ключей.
.forbidden()const schema = Joi.object({
username: Joi.string()
}).unknown();
schema.validate({
username: 'alex',
role: 'admin'
});
Поле role будет разрешено.
.forbidden()const schema = Joi.object({
username: Joi.string(),
role: Joi.forbidden()
}).unknown();
schema.validate({
username: 'alex',
role: 'admin'
});
Теперь поле запрещено даже при разрешённых unknown-ключах.
.forbidden() часто используется вместе с
when().
const schema = Joi.object({
type: Joi.string().valid('user', 'guest').required(),
password: Joi.when('type', {
is: 'guest',
then: Joi.forbidden(),
otherwise: Joi.string().required()
})
});
const result = schema.validate({
type: 'guest',
password: '123456'
});
console.log(result.error.message);
Результат:
"password" is not allowed
const result = schema.validate({
type: 'user',
password: '123456'
});
console.log(result.error);
Результат:
undefined
При обновлении данных некоторые поля обычно запрещены к изменению.
const updateSchema = Joi.object({
email: Joi.string().email(),
username: Joi.string(),
id: Joi.forbidden(),
role: Joi.forbidden(),
balance: Joi.forbidden()
});
.strip().strip() удаляет поле из результирующего объекта.
const schema = Joi.object({
username: Joi.string(),
password: Joi.string().strip()
});
const result = schema.validate({
username: 'alex',
password: '123456'
});
console.log(result.value);
Результат:
{
username: 'alex'
}
Поле прошло валидацию, но было удалено из результата.
.strip() и .forbidden().forbidden()Поле вообще не должно существовать.
Joi.string().forbidden()
.strip()Поле допускается, но удаляется после проверки.
Joi.string().strip()
.forbidden()const schema = Joi.object({
role: Joi.forbidden()
});
schema.validate({
role: 'admin'
});
Ошибка:
"role" is not allowed
.strip()const schema = Joi.object({
role: Joi.string().strip()
});
schema.validate({
role: 'admin'
});
Результат:
{}
.strip() часто используется для удаления внутренних
полей.
const schema = Joi.object({
username: Joi.string(),
password: Joi.string(),
internalToken: Joi.string().strip(),
debugInfo: Joi.any().strip()
});
Типичный сценарий регистрации пользователя.
const schema = Joi.object({
password: Joi.string().min(8).required(),
confirmPassword: Joi.string()
.valid(Joi.ref('password'))
.required()
.strip()
});
const result = schema.validate({
password: 'secret123',
confirmPassword: 'secret123'
});
console.log(result.value);
Результат:
{
password: 'secret123'
}
.strip() во вложенных объектахconst schema = Joi.object({
profile: Joi.object({
username: Joi.string(),
tempField: Joi.string().strip()
})
});
const result = schema.validate({
profile: {
username: 'alex',
tempField: 'temporary'
}
});
console.log(result.value);
Результат:
{
profile: {
username: 'alex'
}
}
.strip() помогает преобразовывать входные данные в
безопасную структуру.
const schema = Joi.object({
username: Joi.string().required(),
email: Joi.string().email().required(),
csrfToken: Joi.string().strip(),
trackingId: Joi.string().strip(),
analytics: Joi.any().strip()
});
После валидации остаются только полезные данные.
const schema = Joi.object({
username: Joi.string().required(),
role: Joi.forbidden(),
tempData: Joi.any().strip()
}).unknown();
const result = schema.validate({
username: 'alex',
tempData: {
cache: true
},
extraField: 'allowed',
role: 'admin'
});
console.log(result.error.message);
Результат:
"role" is not allowed
const result = schema.validate({
username: 'alex',
tempData: {
cache: true
},
extraField: 'allowed'
});
console.log(result.value);
Результат:
{
username: 'alex',
extraField: 'allowed'
}
Поле tempData удалено, extraField сохранён
благодаря .unknown().
Joi.object({
username: Joi.string(),
email: Joi.string().email()
})
Дополнительные поля запрещены.
Подходит для:
Joi.object({
username: Joi.string()
}).unknown()
Дополнительные поля разрешены.
Подходит для:
Joi.object({
password: Joi.string(),
confirmPassword: Joi.string().strip(),
role: Joi.forbidden()
})
Комбинация: