Skip to content

Commit 2576b77

Browse files
committed
fix: Properly store parsed query and path params in context
1 parent 8dd73c6 commit 2576b77

2 files changed

Lines changed: 64 additions & 2 deletions

File tree

src/__tests__/app.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,29 @@ describe("App", () => {
173173
);
174174
});
175175

176+
describe("path parameters parsing", () => {
177+
it("should coerce path parameters when using z.coerce.number()", async () => {
178+
let actual: any;
179+
const app = createApp().get(
180+
"/test/:id",
181+
{
182+
params: z.object({
183+
id: z.coerce.number(),
184+
}),
185+
},
186+
({ params }) => void (actual = params),
187+
);
188+
const client = createTestAppClient(app);
189+
190+
await client.fetch("GET", "/test/:id", {
191+
params: { id: "123" },
192+
});
193+
194+
expect(actual).toEqual({ id: 123 });
195+
expect(typeof actual.id).toBe("number");
196+
});
197+
});
198+
176199
describe("query parameters parsing", () => {
177200
it.each<{
178201
input: Record<string, string>;
@@ -213,6 +236,27 @@ describe("App", () => {
213236
expect(actual).toEqual(expected);
214237
},
215238
);
239+
240+
it("should coerce query parameters when using z.coerce.number()", async () => {
241+
let actual: any;
242+
const app = createApp().get(
243+
"/test",
244+
{
245+
query: z.object({
246+
limit: z.coerce.number(),
247+
}),
248+
},
249+
({ query }) => void (actual = query),
250+
);
251+
const client = createTestAppClient(app);
252+
253+
await client.fetch("GET", "/test", {
254+
query: { limit: "50" },
255+
});
256+
257+
expect(actual).toEqual({ limit: 50 });
258+
expect(typeof actual.limit).toBe("number");
259+
});
216260
});
217261

218262
describe("any", () => {

src/internal/context.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ export class Context {
1111

1212
matchedRoute: MatchedRoute<RouterData> | undefined;
1313

14+
// Private storage for overwritten values
15+
#params: Record<string, any> | undefined;
16+
#query: Record<string, any> | undefined;
17+
1418
constructor(
1519
public request: Request,
1620
public path: string,
@@ -21,14 +25,28 @@ export class Context {
2125
return new URL(this.request.url, this.origin);
2226
}
2327

24-
get params(): Record<string, string> {
28+
get params(): Record<string, any> {
29+
if (this.#params !== undefined) {
30+
return this.#params;
31+
}
2532
return this.matchedRoute?.params ? getRawParams(this.matchedRoute) : {};
2633
}
2734

28-
get query(): Record<string, string> {
35+
set params(value: Record<string, any>) {
36+
this.#params = value;
37+
}
38+
39+
get query(): Record<string, any> {
40+
if (this.#query !== undefined) {
41+
return this.#query;
42+
}
2943
return this.request.url.includes("?") ? getRawQuery(this.request) : {};
3044
}
3145

46+
set query(value: Record<string, any>) {
47+
this.#query = value;
48+
}
49+
3250
get route(): string | undefined {
3351
return this.matchedRoute?.data.route;
3452
}

0 commit comments

Comments
 (0)