Universal Router — это гибкая библиотека маршрутизации для JavaScript, позволяющая организовывать маршруты как на клиентской, так и на серверной части приложения. Одним из ключевых инструментов для серверной архитектуры является поддержка middleware — функций, которые выполняются на этапе обработки запроса и могут изменять контекст, управлять потоком выполнения или выполнять вспомогательные задачи.
Middleware в Universal Router представляют собой функции, которые вызываются перед обработкой конечного маршрута. Они позволяют:
Функция middleware получает на вход контекст запроса
и функцию next, вызывая которую можно передать управление
следующему middleware или маршруту.
Простейший пример структуры middleware:
async function logger(context, next) {
console.log(`Запрос к пути: ${context.path}`);
return next();
}
Здесь context.path содержит путь запроса, а вызов
next() передаёт управление следующему middleware или
маршруту.
Universal Router позволяет прикреплять middleware на уровне отдельных маршрутов или для всей маршрутизируемой структуры.
На уровне маршрута:
import UniversalRouter from 'universal-router';
const routes = [
{
path: '/admin',
async action(context) {
return 'Страница администратора';
},
middleware: [
async function checkAdmin(context, next) {
if (!context.user?.isAdmin) {
throw new Error('Доступ запрещен');
}
return next();
}
]
}
];
const router = new UniversalRouter(routes);
В этом примере middleware checkAdmin выполняется перед
action. Если условие не выполняется, next() не
вызывается, и маршрут не будет обработан.
Глобальное middleware можно реализовать через вложенные маршруты или через обертку над Universal Router:
const router = new UniversalRouter(routes, {
context: {},
resolveRoute(context, route) {
if (route.middleware) {
const chain = route.middleware.reduceRight(
(next, fn) => () => fn(context, next),
() => route.action ? route.action(context) : null
);
return chain();
}
return route.action ? route.action(context) : null;
}
});
Контекст (context) — это объект, который передается
через цепочку middleware и до конечного маршрута. Он может
содержать:
path — путь запроса.query — объект с параметрами запроса.user — данные о текущем пользователе.Middleware может добавлять новые свойства или модифицировать существующие:
async function attachRequestId(context, next) {
context.requestId = Date.now().toString();
return next();
}
После выполнения этого middleware все последующие функции и маршруты
будут иметь доступ к context.requestId.
Middleware в Universal Router поддерживают асинхронные операции. Это позволяет обращаться к базе данных, выполнять запросы к API или проверять авторизацию:
async function fetchUser(context, next) {
context.user = await getUserFromToken(context.token);
return next();
}
Ошибки можно обрабатывать на уровне middleware или на глобальном
уровне через try/catch:
async function errorHandler(context, next) {
try {
return await next();
} catch (err) {
console.error(err);
return { status: 500, message: err.message };
}
}
Порядок middleware имеет критическое значение:
next() передает управление следующему
middleware.next() не вызывается, цепочка останавливается, и
действие маршрута не выполняется.На серверной стороне Universal Router часто используют в связке с
Node.js и фреймворками вроде Express или Koa.
В этом случае middleware Universal Router интегрируется с серверным
циклом обработки запроса:
import express from 'express';
import UniversalRouter from 'universal-router';
const app = express();
const router = new UniversalRouter(routes);
app.use(async (req, res) => {
const context = { path: req.path, query: req.query };
try {
const result = await router.resolve(context);
res.send(result);
} catch (err) {
res.status(500).send(err.message);
}
});
app.listen(3000);
Middleware Universal Router позволяют централизованно обрабатывать авторизацию, логирование и подготовку данных, сохраняя чистую структуру серверных маршрутов.
try/catch, чтобы предотвратить необработанные ошибки.Middleware в Universal Router — это мощный инструмент, позволяющий строить серверную архитектуру с прозрачным управлением потоком выполнения, эффективной обработкой ошибок и централизованной подготовкой данных для маршрутов.