Что такое Yup и зачем он нужен

Yup представляет собой библиотеку для валидации данных в JavaScript, основанную на схемах (schema-based validation). Основная идея заключается в том, что структура и правила проверки данных описываются декларативно, после чего эти правила применяются к входящим значениям автоматически и единообразно.

В реальных приложениях данные редко поступают в «чистом» виде. Формы, API-запросы, внешние сервисы и пользовательский ввод неизбежно требуют проверки:

  • обязательные поля могут быть пустыми;
  • строки могут не соответствовать формату (email, URL, телефон);
  • числа могут выходить за допустимые диапазоны;
  • объекты могут иметь неполную структуру;
  • вложенные данные требуют каскадной проверки.

Без централизованного инструмента валидации логика проверки обычно расползается по коду: часть находится в обработчиках форм, часть — в API-слое, часть — в бизнес-логике. Это приводит к дублированию и усложнению поддержки.

Yup решает эту проблему за счёт описания правил в одном месте — в схеме данных.

Схемный подход к валидации

В основе Yup лежит понятие схемы. Схема описывает структуру данных и правила их проверки. Например:

  • строка должна быть не пустой;
  • число должно быть положительным;
  • объект должен содержать определённые поля;
  • массив должен содержать элементы определённого типа.

Схема становится единственным источником правды о том, какие данные считаются корректными.

Пример базовой схемы:

import * as yup from "yup";

const schema = yup.object({
  name: yup.string().required(),
  age: yup.number().positive().integer(),
  email: yup.string().email().required()
});

Такая схема описывает объект, где:

  • name — обязательная строка;
  • age — положительное целое число;
  • email — строка в формате email и обязательное поле.

Декларативный стиль описания правил

Ключевая особенность Yup — цепочечный (chaining) и декларативный стиль описания правил. Каждое правило добавляется как метод:

  • required() — обязательное значение;
  • min() и max() — ограничения длины или диапазона;
  • email() — проверка формата email;
  • matches() — проверка по регулярному выражению;
  • nullable() — разрешение значения null.

Пример:

const passwordSchema = yup.string()
  .min(8)
  .max(32)
  .matches(/[A-Z]/, "Должна быть хотя бы одна заглавная буква")
  .required();

Такой подход делает валидацию читаемой и предсказуемой: структура правил соответствует порядку их применения.

Основные типы схем

Yup предоставляет набор базовых типов, на основе которых строятся проверки:

  • string() — строки;
  • number() — числа;
  • boolean() — логические значения;
  • date() — даты;
  • array() — массивы;
  • object() — объекты;
  • mixed() — универсальный тип.

Каждый тип имеет собственный набор методов валидации.

Пример массива:

const schema = yup.array()
  .of(yup.string().min(3))
  .min(1)
  .required();

Здесь описан массив строк, где каждая строка должна содержать минимум 3 символа, а сам массив не может быть пустым.

Вложенные структуры данных

Одним из ключевых сценариев является валидация сложных объектов с вложенностью.

const schema = yup.object({
  user: yup.object({
    name: yup.string().required(),
    address: yup.object({
      city: yup.string().required(),
      zip: yup.string().matches(/^\d{5}$/)
    })
  })
});

Валидация распространяется рекурсивно, что позволяет описывать сложные структуры без дополнительного кода.

Асинхронная валидация

Yup поддерживает асинхронные проверки, что важно при работе с серверными данными, например проверкой уникальности email.

const schema = yup.string().test(
  "check-email",
  "Email уже используется",
  async (value) => {
    const response = await fetch(`/api/check-email?email=${value}`);
    const data = await response.json();
    return data.available;
  }
);

Асинхронные тесты позволяют интегрировать валидацию с внешними сервисами без изменения общей структуры схемы.

Унификация ошибок

При валидации Yup возвращает структурированные ошибки. Это позволяет стандартизировать обработку и отображение ошибок в интерфейсе.

Ошибки могут быть:

  • привязаны к конкретному полю;
  • содержать пользовательские сообщения;
  • агрегироваться для всего объекта.

Пример получения ошибок:

try {
  await schema.validate(data);
} catch (err) {
  console.log(err.errors);
}

Для сложных объектов можно получить детализированную информацию о каждом поле.

Переиспользование и композиция схем

Одним из сильных свойств Yup является возможность повторного использования схем.

const nameSchema = yup.string().min(2).required();

const userSchema = yup.object({
  firstName: nameSchema,
  lastName: nameSchema
});

Схемы можно комбинировать, расширять и переопределять, что делает их удобными для масштабируемых приложений.

Интеграция с формами и приложениями

Yup часто используется совместно с библиотеками управления формами, где выступает как слой валидации.

Схема становится единым описанием правил для всего жизненного цикла данных:

  • начальное значение формы;
  • проверка на лету;
  • финальная валидация перед отправкой.

Такой подход снижает количество ручной логики и уменьшает вероятность несоответствий между фронтендом и сервером.

Отложенная и условная валидация

Yup позволяет задавать условные правила в зависимости от значений других полей.

const schema = yup.object({
  isCompany: yup.boolean(),
  companyName: yup.string().when("isCompany", {
    is: true,
    then: (schema) => schema.required(),
    otherwise: (schema) => schema.notRequired()
  })
});

Это делает возможным описание бизнес-логики прямо в схеме без внешних условий.

Стандартизация структуры данных

Использование Yup приводит к тому, что структура данных становится формализованной и предсказуемой. Это особенно важно в приложениях, где данные проходят через несколько слоёв:

  • клиентский интерфейс;
  • API;
  • бизнес-логика;
  • база данных.

Схема выступает как контракт, описывающий допустимые формы данных и ограничения на них.

Поведение при валидации

Yup предоставляет несколько режимов проверки:

  • проверка первого найденного нарушения;
  • сбор всех ошибок сразу;
  • строгая или мягкая валидация;
  • преобразование данных перед проверкой (casting).

Например, строка "42" может быть автоматически приведена к числу при необходимости.

yup.number().cast("42"); // 42

Это позволяет одновременно валидировать и нормализовать данные.

Роль Yup в архитектуре приложений

В архитектурном смысле Yup выполняет функцию слоя контроля входных данных. Он снижает зависимость бизнес-логики от формата входящих значений и уменьшает количество защитного кода.

В результате:

  • правила валидации централизуются;
  • упрощается сопровождение;
  • уменьшается дублирование;
  • повышается предсказуемость обработки данных.