Skip to content

Commit

Permalink
fix(router): fallback for method-shadowed routes (#461)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 authored Jul 26, 2023
1 parent ac626c4 commit 7764b99
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
35 changes: 33 additions & 2 deletions src/router.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { createRouter as _createRouter } from "radix3";
import {
createRouter as _createRouter,
toRouteMatcher,
RouteMatcher,
} from "radix3";
import type { HTTPMethod, EventHandler } from "./types";
import { createError } from "./error";
import { eventHandler, toEventHandler } from "./event";
Expand Down Expand Up @@ -44,6 +48,8 @@ export function createRouter(opts: CreateRouterOptions = {}): Router {
const _router = _createRouter<RouteNode>({});
const routes: Record<string, RouteNode> = {};

let _matcher: RouteMatcher | undefined;

const router: Router = {} as Router;

// Utilities to add a new route
Expand Down Expand Up @@ -100,7 +106,32 @@ export function createRouter(opts: CreateRouterOptions = {}): Router {
const method = (
event.node.req.method || "get"
).toLowerCase() as RouterMethod;
const handler = matched.handlers[method] || matched.handlers.all;

let handler: EventHandler | undefined =
matched.handlers[method] || matched.handlers.all;

// Fallback to search for shadowed routes
if (!handler) {
if (!_matcher) {
_matcher = toRouteMatcher(_router);
}
// Default order is less specific to most specific
const _matches = _matcher.matchAll(path).reverse() as RouteNode[];
for (const _match of _matches) {
if (_match.handlers[method]) {
handler = _match.handlers[method];
matched.handlers[method] = matched.handlers[method] || handler;
break;
}
if (_match.handlers.all) {
handler = _match.handlers.all;
matched.handlers.all = matched.handlers.all || handler;
break;
}
}
}

// Method not matched
if (!handler) {
if (opts.preemptive || opts.preemtive) {
throw createError({
Expand Down
23 changes: 23 additions & 0 deletions test/router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,29 @@ describe("router", () => {
const res = await request.get("/404");
expect(res.status).toEqual(404);
});

it("Handle shadowed route", async () => {
router.post(
"/test/123",
eventHandler((event) => `[${event.method}] ${event.path}`)
);

router.use(
"/test/**",
eventHandler((event) => `[${event.method}] ${event.path}`)
);

// Loop to validate cached behavior
for (let i = 0; i < 5; i++) {
const postRed = await request.post("/test/123");
expect(postRed.status).toEqual(200);
expect(postRed.text).toEqual("[POST] /test/123");

const getRes = await request.get("/test/123");
expect(getRes.status).toEqual(200);
expect(getRes.text).toEqual("[GET] /test/123");
}
});
});

describe("router (preemptive)", () => {
Expand Down

0 comments on commit 7764b99

Please sign in to comment.