Skip to content

Commit 4803c44

Browse files
committed
fix: dates are only allowed to be Dates in query parameters and request payloads
1 parent d034768 commit 4803c44

File tree

7 files changed

+52
-8
lines changed

7 files changed

+52
-8
lines changed

lib/build/index.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,14 @@ export function generateClientType(server: Server) {
9292
name: queryTypeName,
9393
required: isRequired(route.settings.validate.query as ExtendedSchema),
9494
};
95-
statements.push(typeAliasDeclaration(queryTypeName, generateType(route.settings.validate.query as ExtendedObjectSchema), true));
95+
statements.push(
96+
typeAliasDeclaration(
97+
queryTypeName,
98+
// allow dates in query parameters, they'll get stringified appropriately
99+
generateType(route.settings.validate.query as ExtendedObjectSchema, { allowDates: true }),
100+
true,
101+
),
102+
);
96103
}
97104

98105
if (route.settings.validate?.payload) {
@@ -101,7 +108,14 @@ export function generateClientType(server: Server) {
101108
name: payloadTypeName,
102109
required: true,
103110
};
104-
statements.push(typeAliasDeclaration(payloadTypeName, generateType(route.settings.validate.payload as ExtendedObjectSchema), true));
111+
statements.push(
112+
typeAliasDeclaration(
113+
payloadTypeName,
114+
// allow dates in payloads, they'll get stringified appropriately
115+
generateType(route.settings.validate.payload as ExtendedObjectSchema, { allowDates: true }),
116+
true,
117+
),
118+
);
105119
}
106120

107121
// the result type is the type of the actual response from the api

lib/build/nodes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export type Options = {
2828
comments?: boolean;
2929
export?: boolean;
3030
expression?: boolean;
31+
allowDates?: boolean;
3132
};
3233

3334
export type Property = {

lib/build/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ export function generateType(schema: Schema, options?: Options): TypeNode {
6161
node = booleanTypeNode();
6262
break;
6363
case "date":
64-
node = unionTypeNode([dateTypeNode(), stringTypeNode()]);
64+
node = options?.allowDates
65+
? unionTypeNode([dateTypeNode(), stringTypeNode()])
66+
: stringTypeNode();
6567
break;
6668
case "number":
6769
node = numberTypeNode();

lib/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ export class Client<T extends Route> {
7070
// it handles actually calling .toString() on the values for us
7171
if (Array.isArray(value)) {
7272
for (const v of value) {
73-
query.append(key, v as string);
73+
query.append(key, v instanceof Date ? v.toISOString() : v as string);
7474
}
7575
} else {
76-
query.set(key, value as string);
76+
query.set(key, value instanceof Date ? value.toISOString() : value as string);
7777
}
7878
}
7979
}

test/fetch.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ await test("fetch()", async (t) => {
6565
t.assert.equal(multiRes.status, 200);
6666
t.assert.equal(multiRes.url, `${server.info.uri}/query?multi=one&multi=three+four`);
6767
t.assert.deepStrictEqual<SpecificBodyType<routeType, 200>>(multiRes.body, { flag: false, multi: ["one", "three four"] });
68+
69+
const now = new Date();
70+
const stringDateRes = await client.get("/query", { query: { date: now.toISOString() } });
71+
t.assert.equal(stringDateRes.status, 200);
72+
t.assert.equal(stringDateRes.url, `${server.info.uri}/query?date=${encodeURIComponent(now.toISOString())}`);
73+
t.assert.deepStrictEqual<SpecificBodyType<routeType, 200>>(stringDateRes.body, { flag: false, date: now.toISOString() });
74+
75+
const dateDateRes = await client.get("/query", { query: { date: now } });
76+
t.assert.equal(dateDateRes.status, 200);
77+
t.assert.equal(dateDateRes.url, `${server.info.uri}/query?date=${encodeURIComponent(now.toISOString())}`);
78+
t.assert.deepStrictEqual<SpecificBodyType<routeType, 200>>(dateDateRes.body, { flag: false, date: now.toISOString() });
6879
});
6980

7081
await t.test("GET /param/{param}", async (t: TestContext) => {

test/fixture.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,20 @@ server.route([
3030
query: Joi.object({
3131
flag: Joi.boolean().default(false),
3232
multi: Joi.array().items(Joi.string()),
33+
date: Joi.date(),
3334
}),
3435
},
3536
response: {
3637
status: {
37-
200: Joi.object({ flag: Joi.boolean().required(), multi: Joi.array().items(Joi.string()) }),
38+
200: Joi.object({
39+
flag: Joi.boolean().required(),
40+
multi: Joi.array().items(Joi.string()),
41+
date: Joi.date(),
42+
}),
3843
},
3944
},
40-
handler(request: Request<{ Query: { flag: boolean; multi?: string[] } }>) {
41-
return { flag: request.query.flag, multi: request.query.multi };
45+
handler(request: Request<{ Query: { flag: boolean; multi?: string[]; date?: Date } }>) {
46+
return { flag: request.query.flag, multi: request.query.multi, date: request.query.date };
4247
},
4348
},
4449
},

test/inject.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ await test("server.inject()", async (t) => {
3333
t.assert.equal(multiRes.status, 200);
3434
t.assert.equal(multiRes.url, "/query?multi=one&multi=three+four");
3535
t.assert.deepStrictEqual<SpecificBodyType<routeType, 200>>(multiRes.body, { flag: false, multi: ["one", "three four"] });
36+
37+
const now = new Date();
38+
const stringDateRes = await client.get("/query", { query: { date: now.toISOString() } });
39+
t.assert.equal(stringDateRes.status, 200);
40+
t.assert.equal(stringDateRes.url, `/query?date=${encodeURIComponent(now.toISOString())}`);
41+
t.assert.deepStrictEqual<SpecificBodyType<routeType, 200>>(stringDateRes.body, { flag: false, date: now.toISOString() });
42+
43+
const dateDateRes = await client.get("/query", { query: { date: now } });
44+
t.assert.equal(dateDateRes.status, 200);
45+
t.assert.equal(dateDateRes.url, `/query?date=${encodeURIComponent(now.toISOString())}`);
46+
t.assert.deepStrictEqual<SpecificBodyType<routeType, 200>>(dateDateRes.body, { flag: false, date: now.toISOString() });
3647
});
3748

3849
await t.test("GET /param/{param}", async (t: TestContext) => {

0 commit comments

Comments
 (0)