cyclosproject / ng-openapi-gen

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

Service method not generated when tags case don't match #190

Open Fabiencdp opened 2 years ago

Fabiencdp commented 2 years ago

Hi,

I just noticed some strange problem with tags. With the below simplified spec, notice the difference about the tag case (Export vs export) :

openapi: 3.0.3
info:
  title: demo API
  version: 1.0.0
externalDocs:
  description: Find out more about Swagger
  url: http://swagger.io
servers:
  - url: /api/v1
paths:
  /export:
    get:
      operationId: ExportListGet
      tags:
        - export
      summary: list all project exports
      responses:
        '500':
          description: Internal Error
    post:
      operationId: ExportPost
      tags:
        - Export
      summary: Create a new export
      responses:
        '500':
          description: Internal Error

When running the generator with this example, you will get the following service ts file :

/* tslint:disable */
/* eslint-disable */
import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { BaseService } from '../base-service';
import { ApiConfiguration } from '../api-configuration';
import { StrictHttpResponse } from '../strict-http-response';
import { RequestBuilder } from '../request-builder';
import { Observable } from 'rxjs';
import { map, filter } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class ExportApiService extends BaseService {
  constructor(
    config: ApiConfiguration,
    http: HttpClient
  ) {
    super(config, http);
  }

  /**
   * Path part for operation exportPost
   */
  static readonly ExportPostPath = '/export';

  /**
   * Create a new export.
   *
   *
   *
   * This method provides access to the full `HttpResponse`, allowing access to response headers.
   * To access only the response body, use `exportPost()` instead.
   *
   * This method doesn't expect any request body.
   */
  exportPost$Response(params?: {
  }): Observable<StrictHttpResponse<void>> {

    const rb = new RequestBuilder(this.rootUrl, ExportApiService.ExportPostPath, 'post');
    if (params) {
    }

    return this.http.request(rb.build({
      responseType: 'text',
      accept: '*/*'
    })).pipe(
      filter((r: any) => r instanceof HttpResponse),
      map((r: HttpResponse<any>) => {
        return (r as HttpResponse<any>).clone({ body: undefined }) as StrictHttpResponse<void>;
      })
    );
  }

  /**
   * Create a new export.
   *
   *
   *
   * This method provides access to only to the response body.
   * To access the full response (for headers, for example), `exportPost$Response()` instead.
   *
   * This method doesn't expect any request body.
   */
  exportPost(params?: {
  }): Observable<void> {

    return this.exportPost$Response(params).pipe(
      map((r: StrictHttpResponse<void>) => r.body as void)
    );
  }

}

Result a missing method (operationId ExportListGet).

If you set both tag to lower case (or any matching case), the issue is solved and the two methods are generated in one service file. If you set two completely different tags, two services are generated, that seems to be coherent.

The issue append with the version 0.19.4. I didn't tried other versions.

Fabiencdp commented 2 years ago

I can make a merge request to fix this if you're interested.

I saw two options : 1 - Forcing the tags property of Operation class to be lowercase in the constructor. 2 - Detect service.fileName duplicates in the generate method of NgOpenApiGen class, and add a suffix "service-name-X.service" (where X = number of duplicates)

The first could be more clean but i didn't check all the code.

luisfpg commented 2 years ago

It would be great if you could contribute a PR. Option 1 would be the way to go, but not lowercasing the entire tag, as it could be something like MyService, which would generate the a service with the same casing. I think that lowercasing the first character would be the way to go in this case.

Fabiencdp commented 2 years ago

here is it:

192

I also edited the "all-operation" test spec file to validate the change. Feel free to tell me if the code is not suitable.

EDIT This PR only fix partially the tag typo problem, example:

But if you make a typo like this:

Because the script that write the service files will try to write two file with the same name, so only one is generated at end. Hope it's clear enough.

luisfpg commented 2 years ago

After releasing in 0.21.0, I noticed there were broker clients, so I reverted the commit. To be honest, a typo is an error, and shouldn't be handled at generator-level - If you make such typo in code, it won't compile or give you runtime errors.