OpenAPITools / OpenAPITools/openapi-generator

[BUG][JS] Generated JS SDK result in the following error when called : end() was called twice. This is not supported in superagent

Open
#12,073 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue: Bug
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Bug Report Checklist
  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

I use FastAPI to generate my routes, and the following command to produce the sdk:

docker run --network=host --rm \
        -v $(pwd)/clients:/tmp \
        openapitools/openapi-generator-cli:v4.0.0 generate \
        -i localhost:8080/openapi.json \
        -o /tmp/{language} \
        -D modelDocs=false \
        -D apiDocs=false \
        -D apiTests=false \
        -D modelTests=false \
        -D npmVersion=3.5.2 \
        -D supportsES6=true \
        -g javascript

When producing the following code it result into this error message : .end() was called twice. This is not supported in superagent

Executed code:

useEffect(() => {

    const api =  new MyApi()

    api.apiClient.basePath = 'http://localhost:8080'

    api.produceSomethigGet().then(res => {
      console.log(res)
    })
  }, [])
openapi-generator version

V4.0.0

OpenAPI declaration file content or url

https://gist.github.com/Thytu/517d892fadd685c921e7b0d780b1cd21

Generation Details
Steps to reproduce

Generate SDK:

docker run --network=host --rm \
        -v $(pwd)/clients:/tmp \
        openapitools/openapi-generator-cli:v4.0.0 generate \
        -i localhost:8080/openapi.json \
        -o /tmp/{language} \
        -D modelDocs=false \
        -D apiDocs=false \
        -D apiTests=false \
        -D modelTests=false \
        -D npmVersion=3.5.2 \
        -D supportsES6=true \
        -g javascript

Call SDK:

useEffect(() => {

    const api =  new MyApi()

    api.apiClient.basePath = 'http://localhost:8080'

    api.produceSomethigGet().then(res => {
      console.log(res)
    })
  }, [])
Related issues/PRs
Suggest a fix

I saw that if I change a bit the client code it does word:

Unchanged callApi function:

callApi(path, httpMethod, pathParams,
        queryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts,
        returnType, apiBasePath, callback) {

        var url = this.buildUrl(path, pathParams, apiBasePath);
        var request = superagent(httpMethod, url);

        if (this.plugins !== null) {
            for (var index in this.plugins) {
                if (this.plugins.hasOwnProperty(index)) {
                    request.use(this.plugins[index])
                }
            }
        }

        // apply authentications
        this.applyAuthToRequest(request, authNames);

        // set query parameters
        if (httpMethod.toUpperCase() === 'GET' && this.cache === false) {
            queryParams['_'] = new Date().getTime();
        }

        request.query(this.normalizeParams(queryParams));

        // set header parameters
        request.set(this.defaultHeaders).set(this.normalizeParams(headerParams));

        // set requestAgent if it is set by user
        if (this.requestAgent) {
          request.agent(this.requestAgent);
        }

        // set request timeout
        request.timeout(this.timeout);

        var contentType = this.jsonPreferredMime(contentTypes);
        if (contentType) {
            // Issue with superagent and multipart/form-data (https://github.com/visionmedia/superagent/issues/746)
            if(contentType != 'multipart/form-data') {
                request.type(contentType);
            }
        } else if (!request.header['Content-Type']) {
            request.type('application/json');
        }

        if (contentType === 'application/x-www-form-urlencoded') {
            request.send(querystring.stringify(this.normalizeParams(formParams)));
        } else if (contentType == 'multipart/form-data') {
            var _formParams = this.normalizeParams(formParams);
            for (var key in _formParams) {
                if (_formParams.hasOwnProperty(key)) {
                    if (this.isFileParam(_formParams[key])) {
                        // file field
                        request.attach(key, _formParams[key]);
                    } else {
                        request.field(key, _formParams[key]);
                    }
                }
            }
        } else if (bodyParam !== null && bodyParam !== undefined) {
            request.send(bodyParam);
        }

        var accept = this.jsonPreferredMime(accepts);
        if (accept) {
            request.accept(accept);
        }

        if (returnType === 'Blob') {
          request.responseType('blob');
        } else if (returnType === 'String') {
          request.responseType('string');
        }

        // Attach previously saved cookies, if enabled
        if (this.enableCookies){
            if (typeof window === 'undefined') {
                this.agent._attachCookies(request);
            }
            else {
                request.withCredentials();
            }
        }

        request.end((error, response) => {
            if (callback) {
                var data = null;
                if (!error) {
                    try {
                        data = this.deserialize(response, returnType);
                        if (this.enableCookies && typeof window === 'undefined'){
                            this.agent._saveCookies(response);
                        }
                    } catch (err) {
                        error = err;
                    }
                }

                callback(error, data, response);
            }
        });

        return request;
    }

Changed callApi function:

   callApi(path, httpMethod, pathParams,
        queryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts,
        returnType, apiBasePath, callback) {

        var url = this.buildUrl(path, pathParams, apiBasePath);
        var request = superagent(httpMethod, url);

        if (this.plugins !== null) {
            for (var index in this.plugins) {
                if (this.plugins.hasOwnProperty(index)) {
                    request.use(this.plugins[index])
                }
            }
        }

        // apply authentications
        this.applyAuthToRequest(request, authNames);

        // set query parameters
        if (httpMethod.toUpperCase() === 'GET' && this.cache === false) {
            queryParams['_'] = new Date().getTime();
        }

        request.query(this.normalizeParams(queryParams));

        // set header parameters
        request.set(this.defaultHeaders).set(this.normalizeParams(headerParams));

        // set requestAgent if it is set by user
        if (this.requestAgent) {
          request.agent(this.requestAgent);
        }

        // set request timeout
        request.timeout(this.timeout);

        var contentType = this.jsonPreferredMime(contentTypes);
        if (contentType) {
            // Issue with superagent and multipart/form-data (https://github.com/visionmedia/superagent/issues/746)
            if(contentType != 'multipart/form-data') {
                request.type(contentType);
            }
        } else if (!request.header['Content-Type']) {
            request.type('application/json');
        }

        if (contentType === 'application/x-www-form-urlencoded') {
            request.send(querystring.stringify(this.normalizeParams(formParams)));
        } else if (contentType == 'multipart/form-data') {
            var _formParams = this.normalizeParams(formParams);
            for (var key in _formParams) {
                if (_formParams.hasOwnProperty(key)) {
                    if (this.isFileParam(_formParams[key])) {
                        // file field
                        request.attach(key, _formParams[key]);
                    } else {
                        request.field(key, _formParams[key]);
                    }
                }
            }
        } else if (bodyParam !== null && bodyParam !== undefined) {
            request.send(bodyParam);
        }

        var accept = this.jsonPreferredMime(accepts);
        if (accept) {
            request.accept(accept);
        }

        if (returnType === 'Blob') {
          request.responseType('blob');
        } else if (returnType === 'String') {
          request.responseType('string');
        }

        // Attach previously saved cookies, if enabled
        if (this.enableCookies){
            if (typeof window === 'undefined') {
                this.agent._attachCookies(request);
            }
            else {
                request.withCredentials();
            }
        }

        // request.end((error, response) => {
        //     if (callback) {
        //         var data = null;
        //         if (!error) {
        //             try {
        //                 data = this.deserialize(response, returnType);
        //                 if (this.enableCookies && typeof window === 'undefined'){
        //                     this.agent._saveCookies(response);
        //                 }
        //             } catch (err) {
        //                 error = err;
        //             }
        //         }

        //         callback(error, data, response);
        //     }
        // });

        return request;
    }

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the issue with the provided FastAPI schema, the v4.0.0 Docker command, and the generated JavaScript client's callApi entry point. Compare the generated request behavior with the shown version that omits request.end(); done means the generated SDK no longer reports that superagent end() was called twice.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, javascript
Domain
api, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.