cyclosproject / ng-openapi-gen

An OpenAPI 3.0 codegen for Angular
MIT License
397 stars 132 forks source link

Explicit Params types for query parameters #107

Open jeremyhayes opened 4 years ago

jeremyhayes commented 4 years ago

Currently migrating from swagger/v2 to openapi/v3 for a few services, and discovered we're no longer getting explicit *Params types generated for methods with query parameters, but defined inline. We're currently using these for search/paging on "list" pages like the examples below, but there are other use cases as well.

Was this due to some limitation (change in the openapi spec maybe)? Are you opposed to restoring these explicit types, perhaps with a config switch?

Also open to suggestions on better ways to manage these objects to remove the need.

Previous, from ng-swagger-gen:

class CustomerService extends __BaseService {
  getApiV1Customers(params: CustomerService.GetApiV1CustomersParams): __Observable<CustomerListModelPaginatedResponseModel> {
    // ...
  }

module CustomerService {
  export interface GetApiV1CustomersParams {
    Page: number;
    Limit: number;
    SortAsc?: boolean;
    Order?: string;
  }
}

New, from ng-openapi-gen:

export class CustomerService extends BaseService {
  apiV1CustomersGet(params: {
    Page: number;
    Limit: number;
    SortAsc?: boolean;
    Order?: null | string;
  }): Observable<CustomerListModelPaginatedResponseModel> {
    // ...
  }
luisfpg commented 4 years ago

The decision to make the parameters inline was because it is easier. In OpenAPI 3 a single operation can have multiple variants, depending on the content type of both request and response bodies. If a parameters interface would be generated, we'd have to generate one per request body variant (the response doesn't affect the input, of course). In this example, there are 3 request body variants and all return string, but receive application/json, text/plain and a file upload (*/*):

export class GeneratedService extends BaseService {
  operationPost$Json(params: OperationPost$Json$Params): Observable<string> {
    // ...
  }
  operationPost$Text(params: OperationPost$Text$Params): Observable<string> {
    // ...
  }
  operationPost$Text(params: OperationPost$Any$Params): Observable<string> {
    // ...
  }

module GeneratedService {
  export interface OperationPost$Json$Params {
    param: string;
    body: ObjectRef;
  }
  export interface OperationPost$Text$Params {
    param: string;
    body: string;
  }
  export interface OperationPost$Any$Params {
    param: string;
    body: Blob;
  }
}

It is doable, but so far was not requested. I'm overloaded with work in many fronts, so it might take a while to show up.

gravbox commented 1 year ago

I am in agreement with @jeremyhayes above. If there were some sort of flag, it would be great. I understand the multiple overload scenario and the limitations of the language, but a flag would be ideal. That would allow those who have single, unique method names to have the actual class generated. We, and I am sure others, have parameters that differentiate methods like apiV1WidgetGet, apiV1WidgetIdGet, etc. So the GET methods are unique via parameter names and could take in a strongly typed object name. The main issue for us is that the object is not generated at all since it is not used in any generated code. We have defined the objects manually that could easily be generated, If nothing else, perhaps a generated flag to create "unused" objects by pattern might help like "*QueryModel". Or the easiest would be a flag to generate all objects used in the GET methods but not use them in any generated code. This would essentially leave the generated code as-is with no side effects and allow developers to use these objects if desired.