Merging routes with same paths to improve performance a tiny bit.
MODIFY
packages/core/src/router/router.helpers.ts
packages/core/src/router/router.helpers.ts
-import { ParametricRegExp, RouteGroup, Routing, RouteCombinerConfig } from './router.interface';
+import { ParametricRegExp, RouteCombinerConfig, RouteGroup, Routing } from './router.interface';
+
export { Routing };
export const isRouteGroup = (item): item is RouteGroup =>
@@ -25,6 +26,6 @@ export const createRegExpWithParams = (path: string): ParametricRegExp => {
.replace(/([/\\])$/, '$1?'); /* Last slash/backslash is always optional */
return {
regExp: new RegExp('^' + pattern + '$'),
- parameters,
+ parameters: parameters.length > 0 ? parameters : undefined,
};
};

MODIFY
packages/core/src/router/router.interface.ts
packages/core/src/router/router.interface.ts
@@ -22,15 +22,20 @@ export interface RouteGroup {
export interface ParametricRegExp {
regExp: RegExp;
- parameters: string[];
+ parameters?: string[] | undefined;
}
-export interface RoutingRoute extends ParametricRegExp {
- method: HttpMethod;
+export interface RoutingMethod {
+ parameters?: string[] | undefined;
middleware?: Middleware | undefined;
effect: Effect;
}
+export interface RoutingRoute {
+ regExp: RegExp;
+ methods: Partial<Record<HttpMethod, RoutingMethod>>;
+}
+
export interface RouteMatched {
middleware?: Middleware | undefined;
effect: Effect;

MODIFY
packages/core/src/router/router.spec.ts
packages/core/src/router/router.spec.ts
@@ -17,7 +17,7 @@ describe('Router', () => {
const route1: RouteConfig = { path: '/', method: 'GET', effect: e1$ };
const route2: RouteConfig = { path: '/', method: 'GET', effect: e2$ };
const route3: RouteConfig = { path: '/', method: 'GET', effect: e3$ };
- const route4: RouteConfig = { path: '/', method: 'GET', effect: e4$ };
+ const route4: RouteConfig = { path: '/', method: 'POST', effect: e4$ };
const routeGroupNested: RouteGroup = {
path: '/nested',
@@ -40,16 +40,14 @@ describe('Router', () => {
// then
expect(factorizedRouting).toEqual([
- { regExp: /^\/?$/, parameters: [], middleware: null, method: 'GET', effect: e1$ },
- { regExp: /^\/group\/?$/, parameters: [], middleware: m$, method: 'GET', effect: e2$ },
+ { regExp: /^\/?$/, methods: { GET: { effect: e1$ }, POST: { effect: e4$ } } },
+ { regExp: /^\/group\/?$/, methods: { GET: { middleware: m$, effect: e2$ } } },
{
regExp: /^\/group\/nested\/?$/,
- parameters: [],
- middleware: factorizedRouting[2].middleware,
- method: 'GET',
- effect: e3$
+ methods: {
+ GET: { middleware: factorizedRouting[2].methods.GET!.middleware, effect: e3$ }
+ },
},
- { regExp: /^\/?$/, parameters: [], middleware: null, method: 'GET', effect: e4$ },
] as Routing);
});
@@ -60,15 +58,14 @@ describe('Router', () => {
const e3$: Effect = req$ => req$.pipe(mapTo({ body: 'test' }));
const e4$: Effect = req$ => req$.pipe(mapTo({ body: 'test' }));
const routing: Routing = [
- { regExp: /^\/?$/, parameters: [], method: 'GET', effect: e1$ },
- { regExp: /^\/group\/?$/, parameters: [], method: 'GET', effect: e2$ },
- { regExp: /^\/group\/nested\/foo\/?$/, parameters: [], method: 'POST', effect: e3$ },
- { regExp: /^\/foo\/?$/, parameters: [], method: 'GET', effect: e4$ },
+ { regExp: /^\/?$/, methods: { GET: { effect: e1$ }, POST: { effect: e4$ } } },
+ { regExp: /^\/group\/?$/, methods: { GET: { effect: e2$ } } },
+ { regExp: /^\/group\/nested\/foo\/?$/, methods: { POST: { effect: e3$ } } },
];
// when
- const route1 = findRoute(routing, '/group/nested/foo', 'POST', {});
- const route2 = findRoute(routing, '/group/nested/fo', 'POST', {});
+ const route1 = findRoute(routing, '/group/nested/foo', 'POST');
+ const route2 = findRoute(routing, '/group/nested/fo', 'POST');
// then
expect(route1).toEqual({ effect: e3$, middleware: undefined, params: {} });

MODIFY
packages/core/src/router/router.ts
packages/core/src/router/router.ts
@@ -9,6 +9,7 @@ import {
RouteGroup,
RouteMatched,
Routing,
+ RoutingMethod,
RoutingRoute
} from './router.interface';
import { queryParamsFactory } from '../router/queryParams.factory';
@@ -37,15 +38,27 @@ export const routingFactory = (
[...middleware, ...route.middlewares]
));
} else {
- routing.push({
- ...createRegExpWithParams(parentPath + route.path),
- method: route.method,
+ const { regExp, parameters } = createRegExpWithParams(parentPath + route.path);
+ const foundRoute = routing.find(route => route.regExp.source === regExp.source);
+ const method: RoutingMethod = {
+ effect: route.effect,
middleware: middleware.length > 0
? middleware.length > 1 ? combineMiddlewareEffects(middleware) : middleware[0]
- : null,
- effect: route.effect
+ : undefined,
+ parameters,
+ };
+ if (foundRoute) {
+ if (foundRoute.methods[route.method]) {
+ throw new Error(`Redefinition of route at "${route.method}: ${parentPath + route.path}"`);
+ }
+ foundRoute.methods[route.method] = method;
+ } else {
+ routing.push({
+ regExp,
+ methods: { [route.method]: method },
} as RoutingRoute);
}
+ }
});
return routing;
};
@@ -53,27 +66,29 @@ export const routingFactory = (
export const findRoute = (
routing: Routing,
url: string,
- method: HttpMethod,
- params: Record<string, string> = {}
+ method: HttpMethod
): RouteMatched | undefined => {
for (let i = 0; i < routing.length; ++i) {
- const { regExp, parameters, method: routeMethod, middleware, effect } = routing[i];
-
- if (routeMethod !== method) {
- continue;
- }
+ const { regExp, methods } = routing[i];
const match = url.match(regExp);
if (!match) {
continue;
}
+ const routingMethod = methods[method];
+ if (!routingMethod) {
+ return undefined;
+ }
+ const { parameters, effect, middleware } = routingMethod;
+ const params = {};
+ if (parameters) {
for (let p = 0; p < parameters.length; p++) {
params[parameters[p]] = decodeURIComponent(match[p + 1]);
}
+ }
return { middleware, effect, params };
}
-
return undefined;
};

Merging routes with same paths to improve performance a tiny bit.