ecyrbe / zodios

typescript http client and server with zod validation
https://www.zodios.org/
MIT License
1.59k stars 44 forks source link

Array type in query parameters #589

Closed MalpenZibo closed 1 month ago

MalpenZibo commented 4 months ago

Hi, I'm currently trying to use Zodios to specify a GET endpoint that receives an array of values as a query parameter. I have to respect an existing open API spec that defines that query parameter as a style: form, explode: false format (https://swagger.io/docs/specification/serialization/) so I have to accept a query string like /endpointName?id=3,4,5.

I defined the endpoint with the following code

...
{
    name: "id",
    type: "Query",
    schema: z.array(z.string()).optional().default([]),
},
...

but it works only with query strings like /endpointName?id=1&id=2&id=3 or /endpointName?id=[1,2,3].

I tried with the following code

...
{
    name: "id",
    type: "Query",
    schema: z.string().transform((v) => v.split(",")).pipe(z.array(z.string()).optional().default([])),
},
...

but then the generated client accepts only a string as an id parameter, not an array.

There's a way to make this work?

Ackincolor commented 3 months ago

You can try to configure paramsSerializer of axios. paramsSerializer Option

MalpenZibo commented 3 months ago

Changing the axios paramsSerializer doesn't change only how the zodios client sends the request? Because in my case the zodios client is not used

stale[bot] commented 2 months ago

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.

ecamellini commented 1 month ago

I'm having the same issue, could this issue be reopened/discussed @ecyrbe ?

@Ackincolor I don't think this is related to Axios. When the open-api specifies explode: false and style: form, as far as I understand, /endpointName?id=3,4,5 is the expected format. So, it should be supported by the Zodios-generated decoder.

In these cases Zodios should generate a decoder like:

z.string().transform((s: string) => s.split(",")).pipe(z.array(z.string()).optional().default([]));

Or maybe a union of the two approaches to accept them both, like:

z.union([
   z.string().transform((s: string) => s.split(",")).pipe(z.array(z.string()).optional().default([])),
   z.array(z.string()).optional().default([])
])