Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • O openapi-generator
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 3,476
    • Issues 3,476
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 402
    • Merge requests 402
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • OpenAPI Tools
  • openapi-generator
  • Issues
  • #4404
Closed
Open
Issue created Nov 07, 2019 by Administrator@rootContributor

[REQ] [typescript-angular]: support for object as query parameters

Created by: aanno2

Is your feature request related to a problem? Please describe.

At present, typescript-angular only supports arrays and simple types (string, number, Date) as query parameters. However, when you use openapi-generator in conjuction with springdoc and (java) spring, you wish to have support for objects as query parameters as well.

In spring-data, there is REST support for an idea called Pageable. This would be the openapi schema for it:

      "Pageable": {
        "nullable": false,
        "type": "object",
        "required": [
          "size",
          "page"
        ],
        "properties": {
          "size": {
            "format": "int32",
            "type": "integer"
          },
          "sort": {"$ref": "#/components/schemas/Sort"},
          "page": {
            "format": "int32",
            "type": "integer"
          }
        }
      },
      "Sort": {
        "nullable": false,
        "type": "array",
        "items": {"type": "string"}
      },

The items of Sort are the names of the properties to sort the data with. Optionally, there could be a sort direction (ASC, DESC) appended like in ansatz,DESC. The comma (,) should not be urlencoded.

What I want is sane support for Pageable and other objects.

Describe the solution you'd like

Lets think about a (GET) REST endpoint that takes an Pageable and a map with parameters as query parameters. openapi-generator will emits something like:

    public getAllAnsatz(pageable: Pageable, map: { [key: string]: Array<string>; }, observe?: 'body', reportProgress?: boolean): Observable<Array<AnsatzDTO>>;
    public getAllAnsatz(pageable: Pageable, map: { [key: string]: Array<string>; }, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<Array<AnsatzDTO>>>;
    public getAllAnsatz(pageable: Pageable, map: { [key: string]: Array<string>; }, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Array<AnsatzDTO>>>;
    public getAllAnsatz(pageable: Pageable, map: { [key: string]: Array<string>; }, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
        if (pageable === null || pageable === undefined) {
            throw new Error('Required parameter pageable was null or undefined when calling getAllAnsatzfreigabes.');
        }
        if (map === null || map === undefined) {
            throw new Error('Required parameter map was null or undefined when calling getAllAnsatzfreigabes.');
        }

        let queryParameters = new HttpParams({encoder: this.encoder});
        if (pageable !== undefined && pageable !== null) {
            queryParameters = queryParameters.set('pageable', <any>pageable);
        }
        if (map !== undefined && map !== null) {
            queryParameters = queryParameters.set('map', <any>map);
        }

Certainly, this will not lead to the desired result, as implicit toString is called on pageable and map.

The idea is to have a method that will act according to the dynamic type of the variable that should be added to queryParameters:

        let queryParameters = new HttpParams({encoder: this.encoder});
        if (pageable !== undefined && pageable !== null) {
            queryParameters = this.addToHttpParams(queryParameters, <any>pageable, 'pageable')
        }
        if (map !== undefined && map !== null) {
            queryParameters = this.addToHttpParams(queryParameters, <any>map, 'map')
        }

Proposed implementation of addToHttpParams

    private addToHttpParams(httpParams: HttpParams, value: any, key?: string): HttpParams {
        if (typeof value === "object") {
            httpParams = this.addToHttpParams1(httpParams, value);
        } else {
            httpParams = this.addToHttpParams1(httpParams, value, key);
        }
        return httpParams;
    }

    private addToHttpParams1(httpParams: HttpParams, value: any, key?: string): HttpParams {
        if (typeof value === "object") {
            if (this.isArrayLike(value)) {
                (value as []).forEach( elem => httpParams = this.addToHttpParams1(httpParams, elem, key));
            } else if (value instanceof Date) {
                if (key != null) {
                    httpParams = httpParams.append(key,
                        (value as Date).toISOString().substr(0, 10));
                } else {
                   throw Error("key may not be null if value is Date");
                }
            } else {
                Object.keys(value).forEach( k => httpParams = this.addToHttpParams1(
                    httpParams, value[k], key != null ? `${key}.${k}` : k));
            }
        } else if (key != null) {
            httpParams = httpParams.append(key, value);
        } else {
            throw Error("key may not be null if value is not object or array");
        }
        return httpParams;
    }

    private isArrayLike(obj: any): boolean {
        return (Array.isArray(obj) ||
            typeof obj === "object" &&
            typeof (obj.length) === "number" &&
            (obj.length === 0 ||
                (obj.length > 0 && (obj.length - 1) in obj))
        );
  }

The implementation will flatten the top level object to properties, but nested are added with . Syntax to the key (like in toplevelProperty.propertyOfNestedObject). Arrays and simple types are treated like before (no change). The advantage of the new solution is that REST endpoints from spring-data are supported out of the box.

Assignee
Assign to
Time tracking