Результат проверки
Что возвращают validate, parse и остальные функции: из чего состоит результат, что происходит с данными и как устроены ошибки. Все примеры ниже — настоящий вывод tinyval.
Из чего состоит результат
validate и validateAsync возвращают объект из четырёх полей:
| Поле | Если данные верны | Если есть ошибки |
|---|---|---|
valid | true | false |
data | Очищенные данные | undefined |
errors | {} | Первая ошибка каждого поля: { 'items.0.qty': '...' } |
issues | [] | Все ошибки подробно: код, путь, параметры, текст |
parse и parseAsync возвращают сразу data или бросают ValidationError.
Данные проверены — что в data
data — это не входные данные, а то, что получилось после схемы. Пример:
const Order = object({
name: pipe(string(), trim(), minLength(2)),
email: pipe(string(), trim(), toLowerCase(), email()),
age: optional(pipe(coerce.number(), min(18))),
comment: optional(string()),
middleName: optional(nullable(string())),
newsletter: optional(coerce.boolean(), false),
items: array(object({ title: string(), qty: pipe(coerce.number(), min(1)) })),
});
validate(Order, {
name: ' Ivan ',
email: ' IVAN@Mail.RU ',
age: '30',
comment: '',
middleName: null,
items: [{ title: 'Book', qty: '2' }],
isAdmin: true,
});{
"valid": true,
"data": {
"name": "Ivan",
"email": "ivan@mail.ru",
"age": 30,
"middleName": null,
"newsletter": false,
"items": [{ "title": "Book", "qty": 2 }]
},
"errors": {},
"issues": []
}| Поле | На входе | В data | Почему |
|---|---|---|---|
name | ' Ivan ' | 'Ivan' | trim |
email | ' IVAN@Mail.RU ' | 'ivan@mail.ru' | trim + toLowerCase |
age | '30' | 30 | coerce.number — строка стала числом |
comment | '' | нет поля | Пустая строка в optional — «не передано», поле не попадает в data |
middleName | null | null | nullable сохраняет null |
newsletter | нет | false | Значение по умолчанию из optional(…, false) |
items[0].qty | '2' | 2 | coerce.number внутри массива |
isAdmin | true | нет поля | Лишнее поле удалено (object в режиме strip) |
Итого data можно сразу сохранять в базу: типы приведены, лишнего нет, тип TypeScript выведен из схемы.
Есть ошибки — errors и issues
validate(Order, { name: 'I', email: 'bad', age: '15', items: [{ title: 'Book', qty: '0' }, { qty: '1' }] });{
"valid": false,
"data": undefined,
"errors": {
"name": "Must be at least 2 characters long",
"email": "Invalid email",
"age": "Must be at least 18",
"items.0.qty": "Must be at least 1",
"items.1.title": "Required"
},
"issues": [
{ "code": "minLength", "path": ["name"], "params": { "min": 2 }, "message": "Must be at least 2 characters long" },
{ "code": "email", "path": ["email"], "params": {}, "message": "Invalid email" },
{ "code": "min", "path": ["age"], "params": { "min": 18 }, "message": "Must be at least 18" },
{ "code": "min", "path": ["items", 0, "qty"], "params": { "min": 1 }, "message": "Must be at least 1" },
{ "code": "required", "path": ["items", 1, "title"], "params": {}, "message": "Required" }
]
}errors
Объект «путь → текст первой ошибки». Удобен, чтобы показать ошибку рядом с полем: errors.email, errors['items.0.qty'].
- Путь склеен через точку, индексы массивов — числа:
items.1.title. - Ошибка самого значения (схема не объект) — под ключом
'':validate(string(), 42).errors→{ '': 'Must be a string' }. - На каждое поле — одна ошибка, первая по порядку правил в
pipe.
issues
Массив всех ошибок в порядке полей схемы. У каждой:
| Поле | Пример | Зачем |
|---|---|---|
code | 'minLength' | Код ошибки — для своей логики и перевода. Все коды — в Сообщениях |
path | ['items', 0, 'qty'] | Путь массивом: индексы — числа, удобно для вложенных форм |
params | { min: 1 } | Параметры правила — чтобы собрать свой текст на клиенте |
message | 'Must be at least 1' | Готовый текст с учётом языка, label и своих сообщений |
Все ошибки поля и формат Laravel
По умолчанию у поля одна ошибка. С опцией { all: true } в issues попадают все, а flatten собирает их по полям:
const r = validate(object({ password: pipe(string(), minLength(8), email()) }), { password: 'abc' }, { all: true });
r.errors; // { password: 'Must be at least 8 characters long' }
flatten(r.issues); // { password: ['Must be at least 8 characters long', 'Invalid email'] }parse и ValidationError
parse при ошибке бросает ValidationError — в нём те же errors и issues, а message собран в одну строку для логов:
try {
parse(Order, { name: 'I' });
} catch (e) {
e instanceof ValidationError; // true
e.message; // 'name: Must be at least 2 characters long; email: Required; items: Required'
e.errors; // { name: 'Must be at least 2 characters long', email: 'Required', items: 'Required' }
e.issues; // [{ code, path, params, message }, …]
}Standard Schema
Через schema['~standard'].validate результат в формате стандарта — { value } или { issues } только с message и path:
{
"issues": [
{ "message": "Must be at least 2 characters long", "path": ["name"] },
{ "message": "Required", "path": ["email"] },
{ "message": "Required", "path": ["items"] }
]
}Тип результата в TypeScript
Result<T> — объединение: после проверки valid TypeScript знает, есть ли data. Подробнее — TypeScript.
const r = validate(Order, input);
if (r.valid) r.data.items[0].qty; // number
else r.errors; // Record<string, string>См. также
- validate, parse, flatten
- Пустые значения — почему
''не попадает вdata - Сообщения и локализация — тексты в
message