Валидация входящих данных на сервере с использованием Yup строится вокруг схем, описывающих структуру и ограничения объектов. Каждая схема определяет набор правил, по которым проверяются данные, поступающие из внешних источников — HTTP-запросов, очередей сообщений или интеграционных сервисов. Основной принцип заключается в том, что структура данных описывается декларативно, после чего Yup выполняет проверку на соответствие без необходимости ручной реализации условий.
Схема в Yup представляет собой объект, созданный на основе базовых типов: строк, чисел, булевых значений, массивов и объектов. Каждый тип обладает набором методов для уточнения правил проверки.
Пример базовой схемы:
import * as yup from 'yup';
const userSchema = yup.object({
email: yup.string().email().required(),
password: yup.string().min(8).required(),
age: yup.number().min(18).required()
});
Такая структура позволяет описывать требования к данным без привязки к конкретному фреймворку. На сервере это особенно важно, поскольку одна и та же схема может использоваться в разных слоях приложения.
Yup поддерживает асинхронную валидацию, что критично для серверной среды. Это позволяет подключать проверки, зависящие от внешних источников: базы данных, API или кэш-систем.
const schema = yup.object({
username: yup.string().test(
'check-unique',
'Username already exists',
async (value) => {
const user = await database.findUser(value);
return !user;
}
)
});
Асинхронные тесты возвращают Promise, что делает возможным интеграцию с любыми I/O операциями. При обработке запросов это позволяет блокировать дальнейшую обработку до завершения проверки.
В Node.js-окружении Yup чаще всего интегрируется в middleware-слой. Например, в Express валидация может выполняться до передачи управления обработчику маршрута.
const validate = (schema) => async (req, res, next) => {
try {
req.body = await schema.validate(req.body, { abortEarly: false });
next();
} catch (err) {
res.status(400).json({
errors: err.errors
});
}
};
Данный подход позволяет централизовать проверку входных данных и исключить дублирование логики в контроллерах.
Yup формирует структурированные ошибки, содержащие список всех
нарушений. При использовании параметра abortEarly: false
происходит полное сканирование объекта, что особенно полезно в серверной
валидации, где важно предоставить полный список проблем.
try {
await schema.validate(req.body, { abortEarly: false });
} catch (err) {
console.log(err.inner);
}
Каждый элемент inner содержит путь к полю и описание
нарушения. Это позволяет формировать стандартизированные ответы API.
Серверные данные часто имеют сложную структуру с вложенными объектами и массивами. Yup предоставляет инструменты для глубокой проверки таких структур.
const orderSchema = yup.object({
user: yup.object({
id: yup.string().required(),
email: yup.string().email().required()
}),
items: yup.array().of(
yup.object({
productId: yup.string().required(),
quantity: yup.number().min(1).required()
})
)
});
Такая модель позволяет гарантировать целостность данных на всех уровнях вложенности.
Серверная логика часто требует бизнес-правил, которые невозможно
выразить стандартными методами. Yup предоставляет механизм
test, позволяющий реализовывать произвольные проверки.
const passwordSchema = yup.string().test(
'strong-password',
'Password is too weak',
(value) => {
const hasNumber = /\d/.test(value);
const hasLetter = /[a-zA-Z]/.test(value);
return hasNumber && hasLetter;
}
);
Кастомные проверки могут использовать контекст, что позволяет
передавать дополнительные параметры через .context().
Одним из ключевых преимуществ Yup в серверной архитектуре является возможность композиции схем. Базовые структуры могут расширяться и комбинироваться без дублирования кода.
const baseUser = yup.object({
email: yup.string().email().required()
});
const adminUser = baseUser.shape({
role: yup.string().oneOf(['admin']).required()
});
Подход с наследованием схем упрощает поддержку сложных доменных моделей.
В серверных приложениях важно различать синхронную и асинхронную валидацию. Синхронная проверка выполняется мгновенно и используется для простых ограничений. Асинхронная применяется при необходимости обращения к внешним системам.
await schema.validate(req.body); // может быть async
При высокой нагрузке асинхронные проверки могут влиять на производительность, поэтому часто применяется разделение на уровни: быстрая локальная проверка и отложенная бизнес-валидация.
В API, поддерживающих PATCH-запросы, данные поступают частично. Yup
позволяет адаптировать схемы под такие сценарии с помощью
.noUnknown() и nullable().
const updateSchema = yup.object({
email: yup.string().email(),
age: yup.number().min(18)
}).noUnknown();
Отсутствие required() делает поля необязательными, что
соответствует логике частичного обновления.
В TypeScript-среде Yup может использоваться совместно с типизацией, обеспечивая согласованность между временем компиляции и выполнения. Хотя Yup не генерирует типы автоматически, схемы могут выступать источником истины для структуры данных.
type User = {
email: string;
password: string;
};
Схема при этом повторяет структуру типа, что снижает вероятность расхождения между логикой и контрактом данных.
Валидация на сервере выполняет не только функцию проверки корректности, но и служит механизмом защиты от некорректных или вредоносных данных. Ограничение типов, диапазонов и форматов снижает поверхность атак и предотвращает попадание неконсистентных данных в бизнес-логику.
Особое значение имеет строгая проверка входных JSON-объектов, поскольку отсутствие структуры может приводить к непредсказуемому поведению системы.
Несмотря на гибкость, Yup не предназначен для высокопроизводительных потоков валидации с миллионами операций в секунду. Глубокие схемы с большим количеством асинхронных тестов могут создавать нагрузку на event loop. В таких случаях применяются более легковесные решения или предварительная фильтрация данных до применения схем.
Также сложные условные зависимости между полями требуют аккуратного проектирования схем, поскольку чрезмерная вложенность ухудшает читаемость и поддержку.