Библиотека Yup позволяет полностью контролировать тексты ошибок валидации. Сообщения можно задавать:
Кастомизация сообщений особенно важна при разработке:
Каждый метод валидации принимает вторым аргументом сообщение об ошибке.
import * as yup from 'yup';
const schema = yup.string().required('Поле обязательно');
Если значение отсутствует:
await schema.validate('');
Yup выбросит:
ValidationError: Поле обязательно
.min(),
.max(), .length()const schema = yup
.string()
.min(5, 'Минимум 5 символов');
const schema = yup
.string()
.max(10, 'Максимум 10 символов');
const schema = yup
.string()
.length(6, 'Длина должна быть ровно 6 символов');
Yup поддерживает шаблонные параметры внутри сообщений.
Доступные переменные зависят от метода валидации.
${min}const schema = yup
.string()
.min(5, 'Минимум ${min} символов');
Результат:
Минимум 5 символов
${max}const schema = yup
.string()
.max(10, 'Максимум ${max} символов');
${length}const schema = yup
.string()
.length(8, 'Длина должна быть ${length}');
| Метод | Параметр |
|---|---|
| min | ${min} |
| max | ${max} |
| length | ${length} |
| matches | ${regex} |
| Метод | Параметр |
|---|---|
| min | ${min} |
| max | ${max} |
| lessThan | ${less} |
| moreThan | ${more} |
| Метод | Параметр |
|---|---|
| min | ${min} |
| max | ${max} |
${path}${path} содержит имя поля.
const schema = yup.object({
email: yup
.string()
.required('Поле ${path} обязательно')
});
Ошибка:
Поле email обязательно
${value}${value} содержит текущее значение.
const schema = yup
.number()
.min(18, 'Возраст ${value} слишком мал');
Вместо строки можно использовать функцию.
Это позволяет динамически формировать текст ошибки.
const schema = yup
.string()
.min(5, ({ min }) => {
return `Нужно минимум ${min} символов`;
});
Функция получает объект с параметрами.
Пример:
({
value,
originalValue,
path,
spec,
min,
max
})
const schema = yup
.number()
.min(18, ({ value }) => {
if (value < 10) {
return 'Слишком маленькое значение';
}
return 'Возраст должен быть не менее 18';
});
.matches()Метод .matches() используется для проверки регулярных
выражений.
const schema = yup
.string()
.matches(
/^[A-Z]+$/,
'Допустимы только заглавные буквы'
);
.matches()По умолчанию пустая строка тоже валидируется.
const schema = yup
.string()
.matches(
/^[A-Z]+$/,
{
message: 'Только заглавные буквы',
excludeEmptyString: true
}
);
.typeError().typeError() задаёт сообщение при неправильном типе
данных.
const schema = yup
.number()
.typeError('Ожидается число');
await schema.validate('abc');
Ошибка:
Ожидается число
.required()const schema = yup
.string()
.required('Поле не может быть пустым');
.nullable().nullable() разрешает null, но сообщения
можно комбинировать.
const schema = yup
.string()
.nullable()
.required('Значение обязательно');
.oneOf()const schema = yup
.string()
.oneOf(
['admin', 'user'],
'Недопустимая роль'
);
${values}В .oneOf() доступен параметр ${values}.
const schema = yup
.string()
.oneOf(
['red', 'blue'],
'Допустимые значения: ${values}'
);
Ошибка:
Допустимые значения: red, blue
.notOneOf()const schema = yup
.string()
.notOneOf(
['root'],
'Значение root запрещено'
);
.email()const schema = yup
.string()
.email('Некорректный email');
.url()const schema = yup
.string()
.url('Некорректный URL');
.uuid()const schema = yup
.string()
.uuid('Некорректный UUID');
.positive() и .negative()const schema = yup
.number()
.positive('Число должно быть положительным');
const schema = yup
.number()
.negative('Число должно быть отрицательным');
.integer()const schema = yup
.number()
.integer('Допустимы только целые числа');
.test().test() предоставляет максимальную гибкость.
const schema = yup.string().test(
'starts-with-a',
'Строка должна начинаться с A',
value => {
return value.startsWith('A');
}
);
.test()Можно использовать createError.
const schema = yup.string().test(
'custom-test',
'Ошибка',
function (value) {
if (!value.includes('@')) {
return this.createError({
message: 'Отсутствует символ @'
});
}
return true;
}
);
createErrorconst schema = yup.string().test(
'username',
'Ошибка',
function (value) {
return this.createError({
message: '${path}: неверное значение',
params: {
path: 'username'
}
});
}
);
label()label() заменяет имя поля в сообщениях.
const schema = yup.object({
email: yup
.string()
.label('Email пользователя')
.required('${label} обязателен')
});
Ошибка:
Email пользователя обязателен
setLocaleYup поддерживает глобальную настройку сообщений.
import { setLocale } from 'yup';
setLocale({
mixed: {
required: 'Поле обязательно'
}
});
Теперь все .required() используют это сообщение.
setLocale({
string: {
min: 'Минимум ${min} символов',
max: 'Максимум ${max} символов'
}
});
setLocale({
number: {
min: 'Минимальное значение: ${min}',
max: 'Максимальное значение: ${max}'
}
});
setLocalesetLocale({
mixed: {},
string: {},
number: {},
date: {},
object: {},
array: {},
boolean: {}
});
При abortEarly: false Yup собирает все ошибки.
try {
await schema.validate(data, {
abortEarly: false
});
} catch (error) {
console.log(error.errors);
}
[
'Поле email обязательно',
'Пароль слишком короткий'
]
innererror.inner содержит подробные объекты ошибок.
catch (error) {
error.inner.forEach(err => {
console.log(err.path);
console.log(err.message);
});
}
const schema = yup.object({
profile: yup.object({
name: yup
.string()
.required('Имя обязательно')
})
});
const schema = yup
.array()
.min(2, 'Минимум ${min} элемента');
const schema = yup
.array()
.max(5, 'Максимум ${max} элементов');
.when()Условная валидация может использовать разные сообщения.
const schema = yup.object({
isAdmin: yup.boolean(),
password: yup.string().when('isAdmin', {
is: true,
then: schema =>
schema.required(
'Пароль администратора обязателен'
),
otherwise: schema =>
schema.required(
'Пароль пользователя обязателен'
)
})
});
Контекст передаётся через validate.
await schema.validate(data, {
context: {
minAge: 21
}
});
const schema = yup.number().test(
'min-age',
'Ошибка',
function (value) {
const { minAge } = this.options.context;
if (value < minAge) {
return this.createError({
message: `Возраст должен быть не менее ${minAge}`
});
}
return true;
}
);
'field_invalid_value'
'Введите корректный email'
Желательно придерживаться одного формата:
'Введите email'
'Укажите пароль'
'Email обязателен'
'Пароль слишком короткий'
Крупные проекты часто выносят сообщения отдельно.
export const messages = {
required: 'Поле обязательно',
email: 'Некорректный email',
minPassword: 'Минимум 8 символов'
};
const schema = yup.object({
email: yup
.string()
.email(messages.email)
.required(messages.required)
});
Иногда удобнее использовать функции.
const messages = {
min: value => `Минимум ${value} символов`
};
const schema = yup
.string()
.min(5, messages.min(5));
Пример структуры:
src/
validation/
messages.js
locale.js
schemas/
Плохо:
.min(5, 'Минимум 5 символов')
Лучше:
.min(5, messages.min(5))
Плохо:
.required('Required')
Лучше:
.required(t('validation.required'))
Плохо:
'Введите email'
'Пароль обязателен'
'Минимум символов: 5'
import i18next from 'i18next';
const schema = yup.string().required(
i18next.t('validation.required')
);
setLocale({
mixed: {
required: () => 'Поле обязательно'
}
});
Иногда удобно возвращать структуру для i18n.
setLocale({
mixed: {
required: () => ({
key: 'field_required'
})
}
});
catch (error) {
error.errors.forEach(err => {
console.log(err.key);
});
}
const schema = yup
.string()
.min(
5,
'${path}: минимум ${min} символов'
);
При интеграции с UI-фреймворками сообщения иногда содержат HTML.
.required('<b>Поле обязательно</b>')
Такой подход требует осторожности из-за XSS.
Лучше хранить чистый текст:
.required('Поле обязательно')
А оформление выполнять на уровне интерфейса.
const message = `
Пароль должен содержать:
- цифру
- спецсимвол
- заглавную букву
`;
const min = 8;
const message = `
Минимальная длина пароля: ${min}
`;
Формат ошибок часто стандартизируют.
{
field: 'email',
message: 'Некорректный email'
}
catch (error) {
const formatted = error.inner.map(err => ({
field: err.path,
message: err.message
}));
console.log(formatted);
}
return this.createError({
message: 'Некорректный email',
params: {
code: 'INVALID_EMAIL'
}
});
catch (error) {
error.inner.forEach(err => {
console.log(err.params.code);
});
}
const schema = yup.object({
username: yup
.string()
.required('Введите имя пользователя')
.min(3, 'Минимум 3 символа'),
email: yup
.string()
.required('Введите email')
.email('Некорректный email'),
password: yup
.string()
.required('Введите пароль')
.min(
8,
'Пароль должен содержать минимум 8 символов'
)
});
[
'Введите email',
'Пароль должен содержать минимум 8 символов'
]
messages/common.js
Содержит:
messages/auth.js
messages/profile.js
messages/payment.js
Содержит сообщения конкретного домена.
export const authMessages = {
invalidPassword:
'Неверный логин или пароль'
};
.required(authMessages.invalidPassword)
Validation failed at path email
Введите корректный email