Декораторы для валидации

Декораторы представляют собой структурный приём, позволяющий оборачивать функции и методы дополнительным поведением без изменения их исходной реализации. В задачах валидации данных они используются как слой, который предваряет выполнение основной логики и обеспечивает проверку входных параметров.

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

Ключевая идея заключается в разделении ответственности:

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

Функциональные декораторы для валидации

Функциональный декоратор — это функция высшего порядка, принимающая исходную функцию и возвращающая её модифицированную версию.

Базовый шаблон

import validator from "validator";

function withValidation(rules) {
  return function (fn) {
    return function (...args) {
      for (const rule of rules) {
        const { validate, message } = rule;

        if (!validate(...args)) {
          throw new Error(message);
        }
      }

      return fn.apply(this, args);
    };
  };
}

Применение с Validator.js

const isEmailValid = (email) => validator.isEmail(email);

const createUser = withValidation([
  {
    validate: (email) => isEmailValid(email),
    message: "Некорректный email"
  }
])(function (email, name) {
  return { email, name };
});

В этом примере:

  • проверка отделена от логики создания пользователя;
  • правила легко расширяются;
  • используется функциональность Validator.js для проверки строковых значений.

Композиция декораторов

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

Реализация композиции

const composeValidators = (...decorators) =>
  (fn) =>
    decorators.reduceRight((acc, decorator) => decorator(acc), fn);

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

const isNotEmpty = (value) => !validator.isEmpty(value);
const isEmail = (value) => validator.isEmail(value);

const validateNotEmpty = (fn) =>
  (...args) => {
    args.forEach((arg) => {
      if (!isNotEmpty(arg)) throw new Error("Пустое значение");
    });
    return fn(...args);
  };

const validateEmail = (fn) =>
  (...args) => {
    if (!isEmail(args[0])) throw new Error("Email некорректен");
    return fn(...args);
  };

const createAccount = composeValidators(
  validateNotEmpty,
  validateEmail
)(function (email, password) {
  return { email, password };
});

Декораторы в TypeScript для классов

В среде TypeScript декораторы позволяют привязывать валидацию к методам и свойствам класса. Это особенно полезно в архитектуре сервисов и контроллеров.

Включение экспериментальных декораторов

{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

Декоратор метода

function ValidateEmail(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor
) {
  const original = descriptor.value;

  descriptor.value = function (email: string, ...args: any[]) {
    if (!validator.isEmail(email)) {
      throw new Error("Некорректный email");
    }

    return original.apply(this, [email, ...args]);
  };

  return descriptor;
}

Использование

class UserService {
  @ValidateEmail
  createUser(email: string, name: string) {
    return { email, name };
  }
}

Здесь Validator.js используется внутри декоратора как источник проверочной логики.


Декораторы свойств и валидация моделей

При работе с объектными моделями декораторы свойств позволяют описывать правила валидации декларативно.

Пример реализации

function IsEmail(target: any, propertyKey: string) {
  let value: string;

  Object.defineProperty(target, propertyKey, {
    get: () => value,
    set: (newValue: string) => {
      if (!validator.isEmail(newValue)) {
        throw new Error(`Некорректное значение в поле ${propertyKey}`);
      }
      value = newValue;
    }
  });
}

Использование в модели

class User {
  @IsEmail
  email: string;

  constructor(email: string) {
    this.email = email;
  }
}

Такой подход делает валидацию неотъемлемой частью модели данных.


Интеграция декораторов с правилами Validator.js

Библиотека Validator.js предоставляет набор функций, ориентированных на строковую валидацию:

  • проверка email;
  • проверка URL;
  • числовые ограничения;
  • форматирование и нормализация.

Декораторы позволяют:

  • объединять несколько проверок в одном слое;
  • переиспользовать правила;
  • создавать единый стиль валидации в проекте.

Пример универсального декоратора правил

function Rule(validatorFn, message) {
  return function (targetFn) {
    return function (...args) {
      if (!validatorFn(...args)) {
        throw new Error(message);
      }
      return targetFn(...args);
    };
  };
}

Условные и параметризованные декораторы

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

Параметризованный декоратор

function MinLength(min) {
  return function (fn) {
    return function (value, ...args) {
      if (!validator.isLength(value, { min })) {
        throw new Error(`Минимальная длина ${min}`);
      }
      return fn(value, ...args);
    };
  };
}

Использование

const saveUsername = MinLength(5)(function (username) {
  return username;
});

Декораторы как слой архитектуры валидации

В сложных системах декораторы формируют промежуточный слой между входными данными и бизнес-логикой:

  • принимают данные;
  • проверяют их через правила Validator.js;
  • блокируют некорректные значения;
  • передают валидированные данные дальше.

Такая архитектура уменьшает связанность кода и повышает предсказуемость обработки данных.


Расширяемость через пользовательские правила

Декораторы легко расширяются пользовательскими функциями, построенными поверх Validator.js.

const isStrongPassword = (password) =>
  validator.isStrongPassword(password, {
    minLength: 8,
    minNumbers: 2
  });

function StrongPassword(fn) {
  return function (password, ...args) {
    if (!isStrongPassword(password)) {
      throw new Error("Пароль слишком слабый");
    }
    return fn(password, ...args);
  };
}

Применение в прикладной архитектуре

Декораторы валидации часто используются в:

  • сервисах авторизации;
  • API-слоях;
  • формах обработки данных;
  • слоях DTO (Data Transfer Object).

Их основная роль — стандартизация проверки данных перед выполнением логики, опираясь на возможности Validator.js и функциональные композиции.