swagger-codegen 不会生成查询参数对象

swagger-codegen wont generate query parameter objects

我尝试根据来自 loopback4 的 openapi 规范生成一个 typescript-angular sdk,但是 swagger-codegen 一直忽略我的查询参数对象。

在下面的规范中,您会看到路径 GET /plans 可以有一个过滤器查询参数。 在生成的 class 中,生成的方法 planControllerFind(?:, observe: ...) 仅将 ?: 作为第一个参数而不是 planControllerFind(filter?: FilterClass, observe: ...)

我尝试了一些不同的规范结构,还尝试了 swagger-codegen 的不同版本(3.0.11、3.0.16、3.0.18),但似乎没有任何效果。在线版本还会生成不完整的代码。

谁能给我提示?

代码是通过以下方式生成的:

swagger-codegen generate -i http://localhost:3000/explorer/openapi.json -l typescript-angular -o app/src/app/core/lb4-sdk -c ./swagger-sdk.options.json

其中 /swagger-sdk.options.json 文件如下所示:

{
  "npmName": "@ilem0n/ng-budget-api",
  "npmVersion": "0.0.1",
  "snapshot": true,
  "ngVersion": "5.0.0"
}

这是我从 loopback4 生成的规范:

openapi: 3.0.0
info:
  title: ngbm-api - NGBM API v1.0
  version: 1.0.0
  contact: {}
paths:
  /plans:
    post:
      x-controller-name: PlanController
      x-operation-name: create
      tags:
        - PlanController
      responses:
        '200':
          description: User model instance
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Plan'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanNew'
      operationId: PlanController.create
    get:
      x-controller-name: PlanController
      x-operation-name: find
      tags:
        - PlanController
      responses:
        '200':
          description: Array of User has many Plan
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Plan'
      parameters:
        - name: filter
          in: query
          content:
            application/json:
              schema:
                type: object
                title: Plan.Filter
                properties:
                  offset:
                    type: integer
                    minimum: 0
                  limit:
                    type: integer
                    minimum: 1
                    example: 100
                  skip:
                    type: integer
                    minimum: 0
                  order:
                    type: array
                    items:
                      type: string
                  where:
                    title: Plan.WhereFilter
                    type: object
                    additionalProperties: true
                  fields:
                    title: Plan.Fields
                    type: object
                    properties:
                      id:
                        type: boolean
                      name:
                        type: boolean
                      ownerId:
                        type: boolean
                    additionalProperties: false
                  include:
                    title: Plan.IncludeFilter
                    type: array
                    items:
                      title: Plan.IncludeFilter.Items
                      type: object
                      properties:
                        relation:
                          type: string
                        scope:
                          properties:
                            offset:
                              type: integer
                              minimum: 0
                            limit:
                              type: integer
                              minimum: 1
                              example: 100
                            skip:
                              type: integer
                              minimum: 0
                            order:
                              type: array
                              items:
                                type: string
                            where:
                              type: object
                              additionalProperties: true
                            fields:
                              type: object
                              properties: {}
                              additionalProperties: true
                          additionalProperties: false
                          title: Plan.ScopeFilter
                additionalProperties: false
      operationId: PlanController.find
  /users/login:
    post:
      x-controller-name: UserController
      x-operation-name: login
      tags:
        - UserController
      responses:
        '200':
          description: Auth & User data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Auth'
      requestBody:
        description: The input of login function
        required: true
        content:
          application/json:
            schema:
              title: Credentials
              type: object
              required:
                - email
                - password
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
                  minLength: 8
      operationId: UserController.login
  /users/me:
    get:
      x-controller-name: UserController
      x-operation-name: getUserData
      tags:
        - UserController
      security:
        - name:
            - Bearer
      responses:
        '200':
          description: Current user data
          content:
            application/json:
              schema:
                title: User
                type: object
                required:
                  - id
                  - name
                  - email
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  email:
                    type: string
      operationId: UserController.getUserData
  /users:
    post:
      x-controller-name: UserController
      x-operation-name: create
      tags:
        - UserController
      responses:
        '200':
          description: User model instance
          content:
            application/json:
              schema:
                title: User
                type: object
                required:
                  - id
                  - name
                  - email
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  email:
                    type: string
      requestBody:
        description: The input of register function
        required: true
        content:
          application/json:
            schema:
              title: NewUser
              type: object
              required:
                - name
                - email
                - password
              properties:
                name:
                  type: string
                  minLength: 3
                email:
                  type: string
                  format: email
                password:
                  type: string
                  minLength: 8
      operationId: UserController.create
servers:
  - url: /
components:
  schemas:
    Plan:
      title: Plan
      description: '(Schema options: { title: ''Plan'', exclude: [ ''ownerId'' ] })'
      properties:
        id:
          type: string
        name:
          type: string
      required:
        - name
      additionalProperties: false
    PlanNew:
      title: PlanNew
      description: '(Schema options: { title: ''PlanNew'', exclude: [ ''id'', ''ownerId'' ] })'
      properties:
        name:
          type: string
      required:
        - name
      additionalProperties: false
    Auth:
      title: Auth
      properties:
        token:
          type: string
        expiresAt:
          type: number
        user:
          type: object
      required:
        - token
        - expiresAt
        - user
      additionalProperties: false

从这个规范中我得到了 planController 的以下 class:

/**
 * ngbm-api - NGBM API v1.0
 * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
 *
 * OpenAPI spec version: 1.0.0
 * 
 *
 * NOTE: This class is auto generated by the swagger code generator program.
 * https://github.com/swagger-api/swagger-codegen.git
 * Do not edit the class manually.
 *//* tslint:disable:no-unused-variable member-ordering */

import { Inject, Injectable, Optional }                      from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
         HttpResponse, HttpEvent }                           from '@angular/common/http';
import { CustomHttpUrlEncodingCodec }                        from '../encoder';

import { Observable }                                        from 'rxjs/Observable';

import { Plan } from '../model/plan';
import { PlanNew } from '../model/planNew';

import { BASE_PATH, COLLECTION_FORMATS }                     from '../variables';
import { Configuration }                                     from '../configuration';


@Injectable()
export class PlanControllerService {

    protected basePath = 'http://localhost:3000/';
    public defaultHeaders = new HttpHeaders();
    public configuration = new Configuration();

    constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
        if (basePath) {
            this.basePath = basePath;
        }
        if (configuration) {
            this.configuration = configuration;
            this.basePath = basePath || configuration.basePath || this.basePath;
        }
    }

    /**
     * @param consumes string[] mime-types
     * @return true: consumes contains 'multipart/form-data', false: otherwise
     */
    private canConsumeForm(consumes: string[]): boolean {
        const form = 'multipart/form-data';
        for (const consume of consumes) {
            if (form === consume) {
                return true;
            }
        }
        return false;
    }


    /**
     * 
     * 
     * @param body 
     * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
     * @param reportProgress flag to report request and response progress.
     */
    public planControllerCreate(body?: PlanNew, observe?: 'body', reportProgress?: boolean): Observable<Plan>;
    public planControllerCreate(body?: PlanNew, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<Plan>>;
    public planControllerCreate(body?: PlanNew, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Plan>>;
    public planControllerCreate(body?: PlanNew, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {


        let headers = this.defaultHeaders;

        // to determine the Accept header
        let httpHeaderAccepts: string[] = [
            'application/json'
        ];
        const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
        if (httpHeaderAcceptSelected != undefined) {
            headers = headers.set('Accept', httpHeaderAcceptSelected);
        }

        // to determine the Content-Type header
        const consumes: string[] = [
            'application/json'
        ];
        const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
        if (httpContentTypeSelected != undefined) {
            headers = headers.set('Content-Type', httpContentTypeSelected);
        }

        return this.httpClient.request<Plan>('post',`${this.basePath}/plans`,
            {
                body: body,
                withCredentials: this.configuration.withCredentials,
                headers: headers,
                observe: observe,
                reportProgress: reportProgress
            }
        );
    }

    /**
     * 
     * 
     * @param  
     * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
     * @param reportProgress flag to report request and response progress.
     */
    public planControllerFind(?: , observe?: 'body', reportProgress?: boolean): Observable<Array<Plan>>;
    public planControllerFind(?: , observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<Array<Plan>>>;
    public planControllerFind(?: , observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Array<Plan>>>;
    public planControllerFind(?: , observe: any = 'body', reportProgress: boolean = false ): Observable<any> {


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

        let headers = this.defaultHeaders;

        // to determine the Accept header
        let httpHeaderAccepts: string[] = [
            'application/json'
        ];
        const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
        if (httpHeaderAcceptSelected != undefined) {
            headers = headers.set('Accept', httpHeaderAcceptSelected);
        }

        // to determine the Content-Type header
        const consumes: string[] = [
        ];

        return this.httpClient.request<Array<Plan>>('get',`${this.basePath}/plans`,
            {
                params: queryParameters,
                withCredentials: this.configuration.withCredentials,
                headers: headers,
                observe: observe,
                reportProgress: reportProgress
            }
        );
    }

}

我在 swagger-api/swagger-codegen https://github.com/swagger-api/swagger-codegen/issues/10158 提出了一个问题,但还没有找到解决方案。

我已经切换到 https://github.com/OpenAPITools/openapi-generator,它解决了我的问题。其实没问题。