Валидация входных данных

Universal Router — это библиотека для маршрутизации в JavaScript, ориентированная на гибкость и поддержку асинхронных действий. Важной частью работы с маршрутизатором является валидация входных данных, которая позволяет контролировать корректность параметров URL и предотвращать ошибки на раннем этапе обработки запроса.

Проверка параметров маршрута

Каждый маршрут в Universal Router определяется объектом с полями path и action. Часто требуется убедиться, что параметры пути соответствуют определённым условиям. Например:

import UniversalRouter from 'universal-router';

const routes = [
  {
    path: '/user/:id',
    action: ({ params }) => {
      if (!/^\d+$/.test(params.id)) {
        throw new Error('ID пользователя должен быть числом');
      }
      return `Пользователь с ID ${params.id}`;
    }
  }
];

const router = new UniversalRouter(routes);

router.resolve({ pathname: '/user/42' }).then(console.log);

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

Использование схем для структурной валидации

Для более сложной проверки параметров маршрутов и query-параметров часто применяются JSON-схемы или библиотеки вроде yup или joi. Универсальный подход заключается в том, чтобы валидировать объект context перед выполнением action.

import * as yup from 'yup';
import UniversalRouter from 'universal-router';

const schema = yup.object({
  params: yup.object({
    id: yup.number().required()
  }),
  query: yup.object({
    page: yup.number().min(1).default(1)
  })
});

const routes = [
  {
    path: '/user/:id',
    action: async ({ params, query }) => {
      await schema.validate({ params, query });
      return `Пользователь ${params.id}, страница ${query.page}`;
    }
  }
];

const router = new UniversalRouter(routes);

router.resolve({ pathname: '/user/10', query: { page: 2 } }).then(console.log);

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

Валидация query-параметров

Query-параметры не обязательно включать в path, но их часто необходимо проверять. Universal Router передаёт query как часть context, что позволяет выполнять следующие действия:

const routes = [
  {
    path: '/search',
    action: ({ query }) => {
      if (!query.q || query.q.length < 3) {
        throw new Error('Поисковый запрос должен быть минимум 3 символа');
      }
      return `Результаты поиска для "${query.q}"`;
    }
  }
];

router.resolve({ pathname: '/search', query: { q: 'js' } }).catch(console.error);

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

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

В реальных приложениях валидация может требовать асинхронных операций: проверка наличия записи в базе данных, авторизации пользователя, проверки токенов. Universal Router поддерживает асинхронные функции в action, что делает интеграцию с промисами естественной:

const routes = [
  {
    path: '/profile/:id',
    action: async ({ params }) => {
      const user = await getUserById(params.id);
      if (!user) {
        throw new Error('Пользователь не найден');
      }
      return user;
    }
  }
];

router.resolve({ pathname: '/profile/123' }).then(console.log).catch(console.error);

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

Централизованный подход к валидации

Для крупных приложений рекомендуется выносить логику валидации в отдельные функции или middleware, что упрощает поддержку и повторное использование. Пример:

function validateUserId(params) {
  const id = Number(params.id);
  if (isNaN(id) || id <= 0) {
    throw new Error('Некорректный ID пользователя');
  }
  return id;
}

const routes = [
  {
    path: '/user/:id',
    action: ({ params }) => {
      const validId = validateUserId(params);
      return `Пользователь с ID ${validId}`;
    }
  }
];

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

Обработка ошибок валидации

Universal Router не блокирует приложение при ошибках — их можно перехватывать и обрабатывать через catch или глобальные обработчики ошибок:

router.resolve({ pathname: '/user/abc' })
  .then(console.log)
  .catch(err => console.error('Ошибка валидации:', err.message));

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

Рекомендации по лучшим практикам

  • Разделять валидацию параметров пути и query-параметров для прозрачности.
  • Использовать схемы и специализированные библиотеки для сложной структурной валидации.
  • Поддерживать асинхронную проверку данных, если маршруты зависят от внешних источников.
  • Централизовать валидацию для повторного использования и упрощения тестирования.
  • Обрабатывать ошибки гибко и информативно, чтобы маршруты возвращали корректные сообщения о проблемах с данными.

Эти методы создают основу безопасной и устойчивой маршрутизации в приложениях на JavaScript с использованием Universal Router, обеспечивая строгий контроль над входными данными и предотвращая потенциальные ошибки.