Библиотека Validator.js предоставляет набор функций для проверки строковых значений: email, URL, длина строки, числовые диапазоны, форматы дат и множество других предикатов. Однако сама библиотека не занимается формированием сообщений для пользовательского интерфейса. Она возвращает булевы значения или вспомогательные результаты, оставляя задачу интерпретации и представления ошибок на уровне приложения.
При построении интерфейсов критически важным становится не только факт наличия ошибки, но и способ её отображения: текст, структура, локализация, контекст поля и формат передачи в UI-слой.
На уровне бизнес-логики валидация часто строится как набор независимых проверок:
import validator from "validator";
function validateUser(data) {
return {
email: validator.isEmail(data.email),
password: validator.isLength(data.password, { min: 8 }),
age: validator.isInt(data.age, { min: 18 })
};
}
Такой подход удобен для вычислений, но непригоден для интерфейса, поскольку:
Для UI требуется преобразование булевых результатов в структурированный формат.
Практика фронтенд-разработки использует унифицированную модель ошибок:
{
field: "email",
code: "INVALID_EMAIL",
message: "Некорректный формат email",
value: "test@"
}
Такая структура позволяет:
При использовании Validator.js обычно формируется слой преобразования:
import validator from "validator";
function validate(data) {
const errors = [];
if (!validator.isEmail(data.email)) {
errors.push({
field: "email",
code: "INVALID_EMAIL",
message: "Некорректный формат email"
});
}
return errors;
}
В интерфейсах формы ошибок важно группировать по ключу поля. Это упрощает рендеринг и позволяет компонентам работать независимо.
function groupErrors(errors) {
return errors.reduce((acc, error) => {
if (!acc[error.field]) {
acc[error.field] = [];
}
acc[error.field].push(error);
return acc;
}, {});
}
Результат:
{
email: [
{ code: "INVALID_EMAIL", message: "Некорректный формат email" }
],
password: [
{ code: "TOO_SHORT", message: "Минимум 8 символов" }
]
}
Такой формат напрямую используется UI-компонентами форм.
Validator.js возвращает только boolean, поэтому необходимо явно сопоставлять правила с кодами ошибок.
const errorMap = {
email: {
invalid: "INVALID_EMAIL"
},
password: {
tooShort: "PASSWORD_TOO_SHORT"
}
};
Пример преобразования:
function validate(data) {
const errors = [];
if (!validator.isEmail(data.email)) {
errors.push({
field: "email",
code: errorMap.email.invalid,
message: "Некорректный email"
});
}
if (!validator.isLength(data.password, { min: 8 })) {
errors.push({
field: "password",
code: errorMap.password.tooShort,
message: "Пароль должен содержать минимум 8 символов"
});
}
return errors;
}
Жёсткое связывание текста ошибки с логикой валидации приводит к проблемам локализации и поддержки. Поэтому используется разделение:
Пример:
const messages = {
ru: {
INVALID_EMAIL: "Некорректный формат электронной почты",
PASSWORD_TOO_SHORT: "Минимальная длина пароля — 8 символов"
},
en: {
INVALID_EMAIL: "Invalid email format",
PASSWORD_TOO_SHORT: "Password must be at least 8 characters"
}
};
Функция локализации:
function formatError(error, lang = "ru") {
return {
...error,
message: messages[lang][error.code] || error.message
};
}
Некоторые правила Validator.js требуют параметров (например, длина строки или диапазоны чисел). Эти параметры полезно включать в структуру ошибки.
{
field: "password",
code: "PASSWORD_TOO_SHORT",
message: "Минимум 8 символов",
meta: {
min: 8,
actual: 5
}
}
Это позволяет UI отображать более информативные сообщения:
В сложных формах важно иметь как плоский список ошибок, так и агрегированное представление.
[
{ field: "email", code: "INVALID_EMAIL" },
{ field: "password", code: "TOO_SHORT" }
]
{
email: { code: "INVALID_EMAIL" },
password: { code: "TOO_SHORT" }
}
Плоский формат удобен для логирования и API, структурированный — для UI.
При использовании Validator.js на сервере (например, в Node.js) формат ошибок должен совпадать с фронтендом.
Пример Express-обработчика:
app.post("/register", (req, res) => {
const errors = validate(req.body);
if (errors.length > 0) {
return res.status(400).json({
errors: errors.map(formatError)
});
}
res.sendStatus(200);
});
Единый формат позволяет фронтенду не различать источник ошибок.
UI-слои часто ожидают стабильную структуру независимо от источника данных. Поэтому вводится слой нормализации:
function normalizeApiErrors(response) {
return response.errors.reduce((acc, error) => {
acc[error.field] = formatError(error);
return acc;
}, {});
}
Это упрощает интеграцию с формами React, Vue или других фреймворков.
При нескольких нарушениях одного поля важно определить порядок отображения.
const priority = {
REQUIRED: 1,
INVALID_FORMAT: 2,
TOO_SHORT: 3
};
Сортировка:
function sortErrors(errors) {
return errors.sort((a, b) => priority[a.code] - priority[b.code]);
}
UI отображает только наиболее критичную ошибку или список в порядке значимости.
Для оптимизации можно хранить не готовый текст, а функцию генерации сообщения:
const messages = {
PASSWORD_TOO_SHORT: (meta) =>
`Минимум ${meta.min} символов, сейчас ${meta.actual}`
};
Использование:
function formatError(error) {
const msg = messages[error.code];
return {
...error,
message: typeof msg === "function" ? msg(error.meta) : msg
};
}
Такой подход особенно полезен при динамических ограничениях.
Формат данных напрямую влияет на структуру компонентов формы.
Пример состояния формы:
{
values: {
email: "",
password: ""
},
errors: {
email: { message: "Некорректный email" },
password: { message: "Минимум 8 символов" }
}
}
Компонент поля использует только собственный ключ:
Помимо UI-отображения, структурированные ошибки Validator.js используются для аналитики:
{
field: "email",
code: "INVALID_EMAIL",
timestamp: 1710000000,
route: "/register"
}
Это позволяет:
Единая модель ошибок упрощает архитектуру:
Согласованность достигается через единый контракт:
{
field,
code,
message,
meta
}
Такой подход устраняет разрыв между слоями приложения и обеспечивает предсказуемое поведение интерфейса при любых сценариях валидации.