Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] [typescript-fetch] Request Parameter Interfaces Conflict with remove-operation-id-prefix #1998

Closed
5 of 6 tasks
bradenmacdonald opened this issue Jan 28, 2019 · 10 comments · Fixed by #3695 or #3740
Closed
5 of 6 tasks

Comments

@bradenmacdonald
Copy link

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • What's the version of OpenAPI Generator used?
  • Have you search for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Bounty to sponsor the fix (example)
Description

When an API spec contains two similarly named operations that differ only in prefix:

      operationId: tag_new_create
...
      operationId: unit_new_create

then generating the typescript-fetch client with the --remove-operation-id-prefix option will result in an error like:

apis/index.ts:2:1 - error TS2308: Module './TagApi' has already exported a member named 'NewCreateRequest'. Consider explicitly re-exporting to resolve the ambiguity.
openapi-generator version

This is in 4.0.0beta. The same error did not occur with the old 3.x typescript-fetch, though this new implementation is generally much better.

OpenAPI declaration file content or url

https://gist.github.com/bradenmacdonald/061c37b42af22832a14574e4aeaa5c59

Command line used for generation
java -jar openapi-generator-cli-4.0.0-beta.jar generate \
    --input-spec api-spec.yaml \
    --generator-name typescript-fetch \
    --output api_client \
    --config openapi-generator-config.json \
    --remove-operation-id-prefix
Steps to reproduce

Simply generate the typescript-fetch client using the sample gist and the command above, then run cd api_client; npm install; npm run build

Related issues/PRs

I couldn't find any existing reports of this issue.

Suggest a fix

Ideally just never omit the prefixes when generating the request parameter interfaces, so that the interface is still called e.g. TagNewCreateRequest (instead of interface NewCreateRequest) regardless of the --remove-operation-id-prefix option (the main reason I use that option is for nicer method names; the names of the parameter interfaces aren't often used directly so it's fine if they're more verbose).

Alternately, put each module's interfaces into a namespace for that module, so that one must use e.g. TagApi.NewCreateRequest to get the interface after importing the overall API.

@auto-labeler
Copy link

auto-labeler bot commented Jan 28, 2019

👍 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.

@janbuchar
Copy link
Contributor

This conflict also happens when I already have a model definition that is accidentally named {operaitionId}Request

@jgiles
Copy link
Contributor

jgiles commented Aug 18, 2019

^ I was just constructing a repro case to file a fresh issue for what @Teyras mentioned above. We have some model definitions named Request by design, and that makes the typescript-fetch generation unusable for us (we're trying to move off of swagger-codegen and this blocks us).

@jgiles
Copy link
Contributor

jgiles commented Aug 19, 2019

Repro case:

example_spec.yaml

swagger: "2.0"
info:
  title: "Example Clash"
  version: "1.0"
schemes:
- https
host: http://localhost
consumes:
- application/json
produces:
- application/json
paths:
  /v1/foos:
    post:
      operationId: CreateFoo
      responses:
        "200":
          description: A successful response.
          schema:
            $ref: '#/definitions/Foo'
      parameters:
      - name: body
        in: body
        required: true
        schema:
          $ref: '#/definitions/CreateFooRequest'
      tags:
      - Example
definitions:
  CreateFooRequest:
    type: object
    properties:
      nickname:
        type: string
    required:
    - nickname
  Foo:
    type: object
    properties:
      id:
        type: string
      nickname:
        type: string
    required:
    - id
    - nickname

Snippet from generated src/api.ts:

import {
    CreateFooRequest,
    CreateFooRequestFromJSON,
    CreateFooRequestToJSON,
    Foo,
    FooFromJSON,
    FooToJSON,
} from '../models';

export interface CreateFooRequest {
    body: CreateFooRequest;
}

/**
 * no description
 */
export class ExampleApi extends runtime.BaseAPI {

    /**
     */
    async createFooRaw(requestParameters: CreateFooRequest): Promise<runtime.ApiResponse<Foo>> {
        if (requestParameters.body === null || requestParameters.body === undefined) {
            throw new runtime.RequiredError('body','Required parameter requestParameters.body was null or undefined when calling createFoo.');
        }

        const queryParameters: runtime.HTTPQuery = {};

        const headerParameters: runtime.HTTPHeaders = {};

        headerParameters['Content-Type'] = 'application/json';

        const response = await this.request({
            path: `/v1/foos`,
            method: 'POST',
            headers: headerParameters,
            query: queryParameters,
            body: CreateFooRequestToJSON(requestParameters.body),
        });

        return new runtime.JSONApiResponse(response, (jsonValue) => FooFromJSON(jsonValue));
    }

   /**
    */
    async createFoo(requestParameters: CreateFooRequest): Promise<Foo> {
        const response = await this.createFooRaw(requestParameters);
        return await response.value();
    }

}

(see that we both import and declare the type CreateFooRequest)

The generated code does not compile:

$ tsc
src/apis/ExampleApi.ts:37:31 - error TS2339: Property 'body' does not exist on type 'CreateFooRequest'.

37         if (requestParameters.body === null || requestParameters.body === undefined) {
                                 ~~~~

src/apis/ExampleApi.ts:37:66 - error TS2339: Property 'body' does not exist on type 'CreateFooRequest'.

37         if (requestParameters.body === null || requestParameters.body === undefined) {
                                                                    ~~~~

src/apis/ExampleApi.ts:52:60 - error TS2339: Property 'body' does not exist on type 'CreateFooRequest'.

52             body: CreateFooRequestToJSON(requestParameters.body),
                                                              ~~~~

src/index.ts:3:1 - error TS2308: Module './apis' has already exported a member named 'CreateFooRequest'. Consider explicitly re-exporting to resolve the ambiguity.

3 export * from './models';
  ~~~~~~~~~~~~~~~~~~~~~~~~~


Found 4 errors.

jgiles added a commit to jgiles/openapi-generator that referenced this issue Aug 19, 2019
Fix OpenAPITools#1998 by namespacing the generated request object types used in the
typescript-fetch client codegen.
@jgiles
Copy link
Contributor

jgiles commented Aug 19, 2019

#3695 is the start of a fix along the lines of the namespacing suggestion from @bradenmacdonald (which fixes both of the naming collision issues discussed in this thread).

Note that adding namespacing can be a breaking change for clients of the generated code. So that this does not have to wait for a major release (based on policies in https://github.com/OpenAPITools/openapi-generator/wiki/Git-Branches ), I think I should add an option to control this behavior?

macjohnny pushed a commit that referenced this issue Aug 22, 2019
* [typescript-fetch] Fix #1998: namespace reqs.

Fix #1998 by namespacing the generated request object types used in the
typescript-fetch client codegen.

* Update petstore samples.

* Add default-false namespacing config option.

* Re-run code sample generation.

* Add maven build configurations.

* Fix sample VERSION files.

* Update typescript-fetch docs.

* Emulate with-npm-version, adding package.json.

* Add Paxos to companies using.

* Prefix namespace with basename to avoid collisions.
@jgiles
Copy link
Contributor

jgiles commented Aug 22, 2019

Updated: change the namespacing flag to prefixing flag.

Starting with release 4.1.1 (which should be out soon), you can avoid this issue by passing

--additional-properties=prefixParameterInterfaces=true

on the command line with your generate command.

Or, adding "prefixParameterInterfaces": true to myconfig.json and passing -c myconfig.json with your generate command

@jgiles
Copy link
Contributor

jgiles commented Aug 23, 2019

So... @macjohnny @bradenmacdonald I discovered while trying to incorporate the new generated code into my team's build today that Typescript namespaces are not well-supported by Babel (often used in React projects like ours). I think the specific usage of namespaces added here actually would work with Babel after a slight tweak to add declare to the namespace declaration (according to https://babeljs.io/docs/en/babel-plugin-transform-typescript). But, the isolatedModules compiler option often added to .tsconfig files as a way to ensure Babel compatibility forbids all namespace usage (you get errors like Cannot compile namespaces when the '--isolatedModules' flag is provided. upon running tsc).

All of this could probably be worked around with some creative tooling setup, but I wonder if it would be better to abandon namespaces entirely and instead do ugly but tooling-friendly string prefixing/suffixing (e.g. PetApiAddPetRequest). This would "just work" with more tooling setups. The ugly names might not be so bad, because most of the time clients can just pass anonymous object literals, and otherwise they could alias the type.

I bring this up now because if we don't want to use namespaces here, it would be good not to release the current (new) behavior in 4.1.1.

@macjohnny
Copy link
Member

@jgiles thabks for the analysis, go ahead. It should be as easy as removing the dot, right?

@jgiles
Copy link
Contributor

jgiles commented Aug 23, 2019

Yeah it's simpler actually than the namespacing was. How close is the 4.1.1 release? I can try to make the change tomorrow.

@macjohnny
Copy link
Member

@wing328 can we wait for this change before releasing 4.1.1?

jgiles added a commit to jgiles/openapi-generator that referenced this issue Aug 23, 2019
Prefix generated request interface names with API classname rather than
using namespaces, because namespaces are not well-supported by some
tooling (in particular, Babel).
macjohnny pushed a commit that referenced this issue Aug 23, 2019
Prefix generated request interface names with API classname rather than
using namespaces, because namespaces are not well-supported by some
tooling (in particular, Babel).
jimschubert added a commit that referenced this issue Aug 25, 2019
* master: (45 commits)
  update python samples
  Two tiny fixes for Java Vertx client (#3683)
  Exclude "test" from packages so that it is not installed as top-level package when "pip installing" the generated sdk (#3731)
  [java-client] add unit test for JDK 11 HttpClient (#3735)
  [R] feat(r): handling error response for 3xx cases (#3571)
  [Dart] Avoid redundant null checking in fromJson (#3632)
  [core] Set isMultipart=true for multipart operations, fix possible NPE (#3750)
  reenable kotlin client tests in shippable ci (#3751)
  Fix null assignation to header/query param map (#3749)
  Mockito 3.0.0 (#3732)
  Update to swagger-parser to 2.0.14-OpenAPITools.org-1 (#3737)
  Add a link to a Qiita blog post (#3747)
  update csharp samples
  Simple spelling error in dotnet core comments (#3746)
  better support for multipart (#3736)
  [typescript-fetch] fix #1998: prefix req ifaces. (#3740)
  cpp-qt5-client: add valgrind memory test (#3663)
  [typescript-angular] Encode objects for multipart/form-data with json - fixes #2733 (#3738)
  [BUG] Https protocol schema is not handled correctly in java 11 native code #3729 (#3730)
  comment out kotlin client tests
  ...
andrzejwp added a commit to flotiq/flotiq-codegen-ts that referenced this issue Apr 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants