Skip to content

Commit e131e23

Browse files
authored
fix(node): handle node mount path in Request URL (#32)
1 parent 5ea5ddf commit e131e23

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

src/adapters/node/request.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,12 @@ export function getRequest({
9595
bodySizeLimit?: number;
9696
request: IncomingMessage;
9797
}) {
98-
return new Request(base + request.url, {
98+
// In Express subrouters, `request.url` is relative to the mount path (e.g., '/auth/xxx'),
99+
// and `request.baseUrl` holds the mount path (e.g., '/api').
100+
// Build the full path as baseUrl + url when available to preserve the full route.
101+
const baseUrl = (request as any)?.baseUrl as string | undefined;
102+
const fullPath = baseUrl ? baseUrl + request.url : request.url;
103+
return new Request(base + fullPath, {
99104
// @ts-expect-error
100105
duplex: "half",
101106
method: request.method,

src/router.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createEndpoint, type Endpoint } from "./endpoint";
33
import { createRouter } from "./router";
44
import { z } from "zod";
55
import { APIError } from "./error";
6+
import { getRequest } from "./adapters/node/request";
67

78
describe("router", () => {
89
it("should be able to return simple response", async () => {
@@ -202,6 +203,33 @@ describe("router", () => {
202203
const text = await response.text();
203204
expect(text).toBe("/test/api/v1/test");
204205
});
206+
207+
it("node adapter getRequest should include Express baseUrl when present", async () => {
208+
const base = "http://localhost:3000";
209+
const fakeReq: any = {
210+
headers: { host: "localhost:3000" },
211+
method: "GET",
212+
url: "/auth/callback",
213+
baseUrl: "/api",
214+
httpVersionMajor: 1,
215+
destroyed: false,
216+
};
217+
const req = getRequest({ base, request: fakeReq });
218+
expect(new URL(req.url).href).toBe("http://localhost:3000/api/auth/callback");
219+
});
220+
221+
it("node adapter getRequest should fall back to url when baseUrl is missing", async () => {
222+
const base = "http://localhost:3000";
223+
const fakeReq: any = {
224+
headers: { host: "localhost:3000" },
225+
method: "GET",
226+
url: "/auth/callback",
227+
httpVersionMajor: 1,
228+
destroyed: false,
229+
};
230+
const req = getRequest({ base, request: fakeReq });
231+
expect(new URL(req.url).href).toBe("http://localhost:3000/auth/callback");
232+
});
205233
});
206234

207235
describe("route middleware", () => {

0 commit comments

Comments
 (0)