Skip to content

Commit ce31bf7

Browse files
committed
fix(rest): improve route sorting to group by path and verb
1 parent 17adc7a commit ce31bf7

File tree

3 files changed

+29
-39
lines changed

3 files changed

+29
-39
lines changed

packages/rest/src/router/route-sort.ts

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,41 +28,30 @@ export function compareRoute(
2828
route1: Pick<RouteEntry, 'verb' | 'path'>,
2929
route2: Pick<RouteEntry, 'verb' | 'path'>,
3030
): number {
31-
// First check verb
32-
const verb1 = HTTP_VERBS[route1.verb.toLowerCase()] || HTTP_VERBS.get;
33-
const verb2 = HTTP_VERBS[route2.verb.toLowerCase()] || HTTP_VERBS.get;
34-
if (verb1 !== verb2) return verb1 - verb2;
35-
36-
// Then check the path tokens
31+
// First check the path tokens
3732
const path1 = route1.path.replace(/{([^}]*)}(\/|$)/g, ':$1$2');
3833
const path2 = route2.path.replace(/{([^}]*)}(\/|$)/g, ':$1$2');
3934
const tokensForPath1: pathToRegExp.Token[] = parse(path1);
4035
const tokensForPath2: pathToRegExp.Token[] = parse(path2);
4136

42-
// Longer path comes before shorter path
43-
if (tokensForPath1.length < tokensForPath2.length) {
44-
return 1;
45-
} else if (tokensForPath1.length > tokensForPath2.length) {
46-
return -1;
47-
}
37+
const length =
38+
tokensForPath1.length > tokensForPath2.length
39+
? tokensForPath1.length
40+
: tokensForPath2.length;
4841

49-
// Now check token by token
50-
for (let i = 0; i < tokensForPath1.length; i++) {
42+
for (let i = 0; i < length; i++) {
5143
const token1 = tokensForPath1[i];
5244
const token2 = tokensForPath2[i];
53-
if (typeof token1 === 'string' && typeof token2 === 'string') {
54-
if (token1 < token2) return -1;
55-
else if (token1 > token2) return 1;
56-
} else if (typeof token1 === 'string' && typeof token2 === 'object') {
57-
// token 1 is a literal while token 2 is a parameter
58-
return -1;
59-
} else if (typeof token1 === 'object' && typeof token2 === 'string') {
60-
// token 1 is a parameter while token 2 is a literal
61-
return 1;
62-
} else {
63-
// Both token are parameters. Treat as equal weight.
64-
}
45+
if (token1 === token2) continue;
46+
if (token1 === undefined) return 1;
47+
if (token2 === undefined) return -1;
48+
if (token1 < token2) return -1;
49+
if (token1 > token2) return 1;
6550
}
51+
// Then check verb
52+
const verb1 = HTTP_VERBS[route1.verb.toLowerCase()] || HTTP_VERBS.get;
53+
const verb2 = HTTP_VERBS[route2.verb.toLowerCase()] || HTTP_VERBS.get;
54+
if (verb1 !== verb2) return verb1 - verb2;
6655
return 0;
6756
}
6857

@@ -77,7 +66,8 @@ function parse(path: string) {
7766
// The string can be /orders/count
7867
tokens.push(...p.split('/').filter(Boolean));
7968
} else {
80-
tokens.push(p);
69+
// Use `{}` for wildcard as they are larger than any other ascii chars
70+
tokens.push(`{}`);
8171
}
8272
});
8373
return tokens;

packages/rest/test/unit/router/route-sort.unit.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ describe('route sorter', () => {
1414
compareRoute(a[1], b[1]),
1515
);
1616
expect(sortedEndpoints).to.eql([
17-
['create', {verb: 'post', path: '/orders'}],
17+
['count', {verb: 'get', path: '/orders/count'}],
18+
['exists', {verb: 'get', path: '/orders/{id}/exists'}],
1819
['replaceById', {verb: 'put', path: '/orders/{id}'}],
1920
['updateById', {verb: 'patch', path: '/orders/{id}'}],
20-
['updateAll', {verb: 'patch', path: '/orders'}],
21-
['exists', {verb: 'get', path: '/orders/{id}/exists'}],
22-
['count', {verb: 'get', path: '/orders/count'}],
2321
['findById', {verb: 'get', path: '/orders/{id}'}],
24-
['findAll', {verb: 'get', path: '/orders'}],
2522
['deleteById', {verb: 'delete', path: '/orders/{id}'}],
23+
['create', {verb: 'post', path: '/orders'}],
24+
['updateAll', {verb: 'patch', path: '/orders'}],
25+
['findAll', {verb: 'get', path: '/orders'}],
2626
['deleteAll', {verb: 'delete', path: '/orders'}],
2727
]);
2828
});

packages/rest/test/unit/router/trie-router.unit.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,19 @@ describe('trie router', () => {
5656

5757
it('lists routes by order', () => {
5858
expect(router.list().map(getVerbAndPath)).to.eql([
59-
{verb: 'post', path: '/orders'},
59+
{verb: 'get', path: '/orders/count'},
60+
{verb: 'get', path: '/orders/{id}/exists'},
6061
{verb: 'put', path: '/orders/{id}'},
6162
{verb: 'patch', path: '/orders/{id}'},
63+
{verb: 'get', path: '/orders/{id}'},
64+
{verb: 'delete', path: '/orders/{id}'},
65+
{verb: 'post', path: '/orders'},
6266
{verb: 'patch', path: '/orders'},
63-
{verb: 'get', path: '/orders/{id}/exists'},
67+
{verb: 'get', path: '/orders'},
68+
{verb: 'delete', path: '/orders'},
6469
{verb: 'get', path: '/users/{userId}/orders'},
6570
{verb: 'get', path: '/users/{id}/products'},
66-
{verb: 'get', path: '/orders/count'},
67-
{verb: 'get', path: '/orders/{id}'},
6871
{verb: 'get', path: '/users/{id}'},
69-
{verb: 'get', path: '/orders'},
70-
{verb: 'delete', path: '/orders/{id}'},
71-
{verb: 'delete', path: '/orders'},
7272
]);
7373
});
7474

0 commit comments

Comments
 (0)