OpenAPITools / OpenAPITools/openapi-generator

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

Open
#8,322 1 comment 1 reaction 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

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

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

Reproduce the issue with the supplied spec.yaml and Go generator command, then inspect the generated api_default.go and the Go generator templates or entry points responsible for multipart file parameters. Done means the generated client treats the files property as a collection, builds successfully, and handles multiple uploaded files rather than one file.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.