OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
21.85k stars 6.59k forks source link

[BUG][golang] 'isCollectionFormatMulti' flag not being set to true on multiple file uploads #8322

Open akutz opened 3 years ago

akutz commented 3 years ago

Bug Report Checklist

Description

A generated Golang client for an OpenAPI 3 spec that includes multi-file uploads fails to build because the array of files is generated as a single file. For example, the following snippet is from the generated api_default.go:

    localVarFormFileName = "files"
    var localVarFile []*os.File
    if r.files != nil {
        localVarFile = *r.files
    }
    if localVarFile != nil {
        fbs, _ := _ioutil.ReadAll(localVarFile)
        localVarFileBytes = fbs
        localVarFileName = localVarFile.Name()
        localVarFile.Close()
    }
openapi-generator version

I have tried with the following versions:

Version Install Method
v0.5.0 Homebrew
Docker
v4.3.1 Docker
HEAD Homebrew
OpenAPI declaration file content or url
openapi: 3.0.1
info:
  title: API
  version: "1.0"
servers:
- url: https://example.com
tags:
- name: default
  description: Default namespace
paths:
  /bug/{bug_id}/attachment:
    post:
      tags:
      - default
      summary: Upload a file
      operationId: post_res_attach
      parameters:
      - name: bug_id
        in: path
        required: true
        schema:
          type: integer
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                files:
                  type: array
                  description: One or more files to upload
                  items:
                    type: string
                    format: binary
      responses:
        200:
          description: Success
          content: {}
        401:
          description: Unauthenticated
          content: {}
Generation Details
openapi-generator generate --input-spec spec.yaml \
  --generator-name go \
  --template-dir ./generator-template \
  --output ./openapi

The generator-template directory contains a single file, partial_header.mustache:

// Copyright (c) 2020 VMware, Inc. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

/*
 {{#appName}}
 * {{{appName}}}
 *
 {{/appName}}
 {{#appDescription}}
 * {{{appDescription}}}
 *
 {{/appDescription}}
 {{#version}}
 * API version: {{{version}}}
 {{/version}}
 {{#infoEmail}}
 * Contact: {{{infoEmail}}}
 {{/infoEmail}}
{{^withGoCodegenComment}}
 * Generated by: OpenAPI Generator (https://openapi-generator.tech)
{{/withGoCodegenComment}}
 */
{{#withGoCodegenComment}}

// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
{{/withGoCodegenComment}}
Steps to reproduce
  1. Switch to a temporary directory:

    cd $(mktemp -d)
  2. Create a spec file:

    cat <<EOF >spec.yaml
    openapi: 3.0.1
    info:
      title: API
      version: "1.0"
    servers:
    - url: https://example.com
    tags:
    - name: default
      description: Default namespace
    paths:
      /bug/{bug_id}/attachment:
        post:
          tags:
          - default
          summary: Upload a file
          operationId: post_res_attach
          parameters:
          - name: bug_id
            in: path
            required: true
            schema:
              type: integer
          requestBody:
            content:
              multipart/form-data:
                schema:
                  type: object
                  properties:
                    files:
                      type: array
                      description: One or more files to upload
                      items:
                        type: string
                        format: binary
          responses:
            200:
              description: Success
              content: {}
            401:
              description: Unauthenticated
              content: {}
    EOF
  3. Create a generator template:

    cat <<EOF >partial_header.mustache
    // Copyright (c) 2020 Company, Inc. All Rights Reserved.
    // SPDX-License-Identifier: Apache-2.0
    
    /*
     {{#appName}}
     * {{{appName}}}
     *
     {{/appName}}
     {{#appDescription}}
     * {{{appDescription}}}
     *
     {{/appDescription}}
     {{#version}}
     * API version: {{{version}}}
     {{/version}}
     {{#infoEmail}}
     * Contact: {{{infoEmail}}}
     {{/infoEmail}}
    {{^withGoCodegenComment}}
     * Generated by: OpenAPI Generator (https://openapi-generator.tech)
    {{/withGoCodegenComment}}
     */
    {{#withGoCodegenComment}}
    
    // Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
    {{/withGoCodegenComment}}
    EOF
  4. Generate the Golang code using the Open API Docker image:

    docker run --rm \
      -v $(pwd)/spec.yaml:/openapi/spec.yaml:ro \
      -v $(pwd):/openapi/output \
      -v $(pwd):/openapi/generator-template \
      openapitools/openapi-generator-cli:v5.0.0 \
      generate --input-spec /openapi/spec.yaml \
        --generator-name go \
        --template-dir /openapi/generator-template \
        --output /openapi/output
  5. Print lines 106-116 of api_default.go to see the incorrectly generated client:

    $ sed -n '106,116p' api_default.go
        localVarFormFileName = "files"
        var localVarFile []*os.File
        if r.files != nil {
            localVarFile = *r.files
        }
        if localVarFile != nil {
            fbs, _ := _ioutil.ReadAll(localVarFile)
            localVarFileBytes = fbs
            localVarFileName = localVarFile.Name()
            localVarFile.Close()
        }

I imagine the same lines should treat the property as a slice/collection similar to the related issue in the next section.

Related issues/PRs

The following issue and PR seemed promising:

However, it seems the fix was for the server-side handling only.

Suggest a fix

Issue https://github.com/OpenAPITools/openapi-generator/issues/8104 seems to be the same as this one, but for typescript. I believe the same fix, but for Go, should work.

Sponsorship

I'm willing to pay $100 for a quick fix on this and $150 if there's a subsequent v5.0.1 patch release with the fix (both for home-brew and the Docker image).

icubbon commented 3 years ago

This is may be a little late for you @akutz, but https://github.com/OpenAPITools/openapi-generator/pull/10843 should be the fix to this issue.