-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Zod Validator #98
Comments
Which target do you want to validate? |
Sorry in my case I wanted to validate
Which works as expected. But the coerce Version is so much nicer. Escpially when you throw in stuff like |
HI @clarknova Thanks for your response. The behavior is expected because the validation target should be a "string" if it's |
Thank you for your reply. |
The expected behavior that I mentioned is for TypeScript types, not values. If you set the first argument of |
@yusukebe I wanted to bump this issue specifically because of the recent openapi middleware. When using zod as a source of truth of the All of the types for everything are fine until you get to the types for Is there a solution that you'd recommend for dealing with this, or perhaps I've missed something? Thanks! edit: looking through more of the source, I'm not sure why we're defining the return types in |
I can't understand what you mean well, please give me some snippets as examples. |
@yusukebe I can make a full repro if you'd like, but this should get the point across. Let me know how I can help more :) export const exampleApp = new OpenAPIHono();
const exampleRoute = createRoute({
operationId: "getSomeThings",
method: "get",
path: "/things",
request: {
query: z
.object({
page: z.number().min(1), // 👈 this is important for proper openapi doc generation
limit: z.number().min(1),
})
.partial(),
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({ banana: z.boolean() }),
},
},
description: "woohoo",
},
},
});
exampleApp.openapi(
exampleRoute,
async (c) => {
// These come back as`never` due to the type for ValidationTargets.
// If you set query: unknown in that type, this works as expected.
const { page, limit } = c.req.valid("query"); // 👈👈👈👈👈
return c.jsonT({
ok: true,
});
}
); As of today, this is the type for export type ValidationTargets = {
json: any
form: Record<string, string | File>
query: Record<string, string | string[]>
queries: Record<string, string[]> // Deprecated. Will be obsolete in v4.
param: Record<string, string>
header: Record<string, string>
cookie: Record<string, string>
} to export type ValidationTargets = {
json: unknown
form: unknown
query: unknown
queries: Record<string, string[]> // Deprecated. Will be obsolete in v4.
param: unknown
header: unknown
cookie: unknown
} |
Thanks! I can understood well. But, the input value of query is In this OpenAPI case, it is confused because it confuses whether this is a nemeric value or a |
I don't exactly follow there. When you're in the handler, you've already parsed the param/query/headers/etc otherwise it would've thrown an error. What I'm ultimately saying is that there is currently no way to use zod with openapi to generate an expected openapi spec, unless i'm totally missing something. It's extremely common to define page/pageSize/limit/etc as For more context, what I'm trying to do is switch from using this hono-based wrapper for ts-rest I made and just the openapi middleware, but I don't see how it's possible today. As a reference, you wouldn't be able to create the stripe spec... {
"description": "A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 10.",
"in": "query",
"name": "limit",
"required": false,
"schema": {
"type": "integer"
},
"style": "form"
}, Maybe I'm not understanding something? 🤔 |
In that case, please use const QuerySchema = z.object({
page: z.coerce.number().openapi({
description: 'the page number',
}),
}) |
You don't have to do that. Use this code with the fix in #164. const ParamsSchema = z.object({
id: z
.string()
.transform((val, ctx) => {
const parsed = parseInt(val)
if (isNaN(parsed)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Not a number',
})
return z.NEVER
}
return parsed
})
.openapi({
param: {
name: 'id',
in: 'path',
},
example: 123,
type: 'integer',
}),
}) |
thanks @yusukebe! This works. The only thing worth noting here is that in some cases (like mine), this is still going to be problematic. As an example, this is what I'm doing:
There's more to it, but that's the gist... lots of code generation and trying to get types and schemas to play nicely. All of that to say, it's just easier to deal with things if you can use Thank you for all of this work!!! 🥇 |
Hi! Just wanted to chime in: we're using the OpenAPI middleware, and running into this issue. Defining types as a I'm not sure if I'd ever expect |
When I use zValidator for validation I encounter a typescript bug.
When I coerce something inside the validator the resulting type is always never.
z.object({quality: z.coerce.number().min(1).max(100)})
So the validation works and the incoming c.req.valid is also correct. It is just the typescript definition that breaks.
The text was updated successfully, but these errors were encountered: