trpc-openapi
trpc-openapi copied to clipboard
RFC: Support `number`, `boolean`, `Date` in query params
Right now it's not possible to have z.number()
's in your input schema for GET requests.
That makes sense since query params are strings (so you get an error like Input parser key: "limit" must be ZodString
).
But often (I'm thinking especially of pagination), you need numbers. Right now, you can recreate similar functionality with z.string().transform((s) => parseInt(s)
, but it's not ideal since you lose, for example, Zod's built-in min/max validation.
At a minimum, this deserves a mention in the documentation. If we're feeling more ambitious, we can introduce autoconversions to number
/date
for common types.
I'm happy to open a PR, but first wanted to hear what you think, @jlalmes.
Hi @jqhoogland!
You can use z.preprocess
(https://github.com/colinhacks/zod#preprocess) to transform an input type while keeping Zod's built-in validations (i.e. min/max).
I do like the proposal to support number
, Date
AND boolean
out of the box - this will help with frictionless trpc-openapi
adoption.
I suggest using the following preprocessors. Let me know if you're keen to open a PR 🙌
// number
z.preprocess((arg) => {
if (typeof arg === 'string') {
return parseInt(arg);
}
return arg;
}, z.number() /* 👈 you can use .min()/max() validations here */)
// Date
z.preprocess((arg) => {
if (typeof arg === "string") {
return new Date(arg);
}
return arg;
}, z.date())
// boolean
z.preprocess((arg) => {
if (typeof arg === "string") {
if (arg === 'true' || arg === '1') {
return true;
}
if (arg === 'false' || arg === '0') {
return false;
}
}
return arg;
}, z.boolean())
Awesome, I'll take a look this weekend!
Wait I see you've already opened a branch and gone crazy. You are a hero with those edge cases!
So I've taken a stab at implementing this (not entirely sure I want to ship this feature yet). Would be great if you could take a look at the PR + code review.
https://github.com/jlalmes/trpc-openapi/pull/53
I have published the current state, you can try it out by upgrading to [email protected]
Hey there! Loving this project and it's already been super useful for me.
I wanted to comment that I think this would be an awesome feature - I was very confused coming in that these other types were not supported out of the box. The z.preprocess
workaround will work great in the meantime though, I'm happy to have some way around it.
Thanks for all that you're doing!
The z.preprocess
needs to be inside the resolve or in the input schema?
Example:
.query('getUsers', {
input: z.object({
limit: z.preprocess((arg) => (typeof arg === 'string' ? parseInt(arg) : arg), z.number().min(1).max(50)),
}),
/* ... */
})
Note to self: https://twitter.com/ecyrbedev/status/1567953183120699392
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.