OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.35k stars 6.46k forks source link

[typescript-axios] doesn't serialize deepObject query params #7564

Open wamujlb opened 3 years ago

wamujlb commented 3 years ago

Bug Report Checklist

Description

I'm using [typescript-axios] api client generator. Some of the properties I pass to it specified as deepObject. It looks that it doesn't support this type of args at all. Is there any possible ways to fix it?

openapi-generator version

v4.3.1 v5.0.0-beta

OpenAPI declaration file content or url
YearRange:
      in: query
      name: year
      required: false
      style: deepObject
      schema:
        type: object
        properties:
          min:
            type: string
            example: 2010
          max:
            type: string
            example: 2019
Generation Details

[typescript-axios] generator

Steps to reproduce
Related issues/PRs

https://github.com/OpenAPITools/openapi-generator/pull/6075

Suggest a fix

Replace old deprecated url API with URLSearchParams.

auto-labeler[bot] commented 3 years ago

👍 Thanks for opening this issue! 🏷 I have applied any labels matching special text in your issue.

The team will review the labels and make any necessary changes.

tsraza commented 3 years ago

@wamujlb do you have a snippet to work around this?

tsraza commented 3 years ago

i did this on the generated file

sed -i "s/localVarQueryParameter\['filter'\] \= filter/localVarQueryParameter\['filter'\] \= JSON.stringify(filter)/g" api.ts
wamujlb commented 3 years ago

@tsraza this will not work in my case. API expects something like this:

{date: 'desc'} => ?sort[date]=desc.

wamujlb commented 3 years ago

I have made a workaround but I think that it will be good to add it to the generator.

export const setSearchParams = function (url: URL, ...objects: any[]) {
    const searchParams = new URLSearchParams(url.search);
    for (const object of objects) {
        for (const key in object) {
            /**
             * @workaround
             * Convert object value to the string
             * {sort: {date: 'desc', order: 'asc'}} => 'sort[date]=desc&sort[order]=asc'
             */
            const value = object[key];

            if(typeof value === 'object'){
                Object.entries(value).forEach(([entryKey, entryValue]) => {
                    searchParams.set(`${key}[${entryKey}]`, String(entryValue));
                })
            } else {
                searchParams.set(key, value);
            }
        }
    }
    url.search = searchParams.toString();
}
ruiaraujo012 commented 2 years ago

Any update on this?

kamilkn commented 2 years ago

Any update on this?

++, nothing changed

talss89 commented 2 years ago

I've just had a similar problem. Loopback 4 expects filter parameters as serialised JSON.

It can be solved in a 'nice' way using template overrides.

I modified the template to serialise any object passed as a parameter to JSON:

if(typeof {{paramName}} === 'object' && {{paramName}} !== null)
    localVarQueryParameter['{{baseName}}'] = JSON.stringify({{paramName}});
else
    localVarQueryParameter['{{baseName}}'] = {{paramName}};

@wamujlb - In your case, you could probably add your code to the template.

RapGeneral commented 2 years ago

In my case I updated the common.mustache template with @wamujlb's answer. Its working as expected. But it really would be great to add this to the default templates.

tokidoki11 commented 1 year ago

FYI since array is not being handled well, i updated based on @wamujlb answer

export const setSearchParams = function (url: URL, ...objects: any[]) {
    const searchParams = new URLSearchParams(url.search);
    for (const object of objects) {
        for (const key in object) {
            /**
             * @workaround for deep object
             * Convert object value to the string
             * {sort: {date: 'desc', order: 'asc', multiple: ['1','2']}} => 'sort[date]=desc&sort[order]=asc&multiple[]=1&multiple[]=2'
             */
            const value = object[key];

            if(typeof value === 'object'){
                Object.entries(value).forEach(([entryKey, entryValue]) => {
                    if(Array.isArray(entryValue)){
                        entryValue.forEach((item) => {
                            searchParams.append(`${key}[${entryKey}][]`, String(item));
                        })
                    }
                    else {
                        searchParams.set(`${key}[${entryKey}]`, String(entryValue));
                    } 
                })
            } else {
                searchParams.set(key, value);
            }
        }
    }
    url.search = searchParams.toString();
}