Для работы с Universal Router в среде Node.js необходимо сначала установить пакет через npm:
npm install universal-router
После установки можно импортировать библиотеку в проект:
const UniversalRouter = require('universal-router');
Создание маршрутизатора начинается с определения массива
маршрутов. Каждый маршрут — это объект с обязательным
полем path и функцией action, которая
вызывается при совпадении URL:
const routes = [
{
path: '/',
action: () => 'Главная страница'
},
{
path: '/about',
action: () => 'О нас'
}
];
const router = new UniversalRouter(routes);
Функция action может быть асинхронной, что особенно
удобно при работе с базой данных или внешними API:
const routes = [
{
path: '/users/:id',
async action({ params }) {
const user = await getUserFromDB(params.id);
if (!user) return 'Пользователь не найден';
return `Имя пользователя: ${user.name}`;
}
}
];
Маршрутизатор корректно обрабатывает промисы и возвращает результат после их выполнения.
Universal Router поддерживает динамические сегменты
в пути, которые определяются с помощью двоеточия :. Эти
параметры доступны внутри объекта params:
const routes = [
{
path: '/posts/:postId/comments/:commentId',
action({ params }) {
return `Пост: ${params.postId}, Комментарий: ${params.commentId}`;
}
}
];
Можно использовать регулярные выражения для более точного контроля параметров:
const routes = [
{
path: '/product/:id(\\d+)',
action({ params }) {
return `Продукт с ID: ${params.id}`;
}
}
];
Для сложных приложений часто требуется вложенность
маршрутов. Это реализуется через свойство
children:
const routes = [
{
path: '/dashboard',
action: () => 'Панель управления',
children: [
{
path: '/stats',
action: () => 'Статистика'
},
{
path: '/settings',
action: () => 'Настройки'
}
]
}
];
При запросе /dashboard/stats маршрутизатор автоматически
спустится по дереву маршрутов и вызовет соответствующий
action.
Universal Router предоставляет возможность задать
маршруты по умолчанию и обработку ошибок через специальный маршрут с
path: '(.*)':
const routes = [
{
path: '/home',
action: () => 'Главная'
},
{
path: '(.*)',
action: () => 'Страница не найдена'
}
];
Ошибки внутри action можно ловить через обычный
try/catch или обрабатывать глобально при вызове
router.resolve():
router.resolve('/unknown-path')
.then(result => console.log(result))
.catch(err => console.error('Ошибка маршрута:', err));
Каждый маршрут может использовать объект context,
который передается в action. Это полезно для передачи
глобальных зависимостей, настроек или сервисов:
const router = new UniversalRouter(routes, {
context: {
db: databaseInstance,
logger: console
}
});
const routes = [
{
path: '/users/:id',
async action({ params, context }) {
const user = await context.db.getUser(params.id);
context.logger.log(`Запрос пользователя ${params.id}`);
return user;
}
}
];
Universal Router не предоставляет встроенной функции генерации URL, но совместим с библиотеками вроде path-to-regexp, что позволяет создавать маршруты динамически и строить ссылки по шаблону:
const { compile } = require('path-to-regexp');
const toPath = compile('/posts/:id');
console.log(toPath({ id: 42 })); // /posts/42
Маршрутизатор легко интегрируется с любым HTTP-сервером, например с http модулем Node.js:
const http = require('http');
http.createServer(async (req, res) => {
try {
const result = await router.resolve(req.url);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(result);
} catch (err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Внутренняя ошибка сервера');
}
}).listen(3000);
Это позволяет строить полноценные серверные приложения с маршрутизацией без использования тяжелых фреймворков.
Для обработки промежуточных действий перед вызовом
action можно использовать кастомный middleware-подход,
оборачивая router.resolve:
async function loggingMiddleware(url) {
console.log('Запрос к URL:', url);
return router.resolve(url);
}
loggingMiddleware('/users/1').then(console.log);
Такой подход позволяет добавлять аутентификацию, логирование, кэширование и другие промежуточные слои без изменения маршрутов.
Порядок маршрутов имеет значение: первый совпавший маршрут обрабатывается первым. Поэтому маршруты с более специфичными путями следует размещать выше, а общие fallback маршруты — внизу массива.