swagger-api / swagger-api/swagger-client

multipart/form-data arrays with one element are not sent as arrays

Open
#1,728 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: bug version: 3.x
Dominant language
JavaScript
Stars
2.7k
Forks
765
Avg merge
1d 1h
Merged PRs (30d)
6

Description

Q&A
  • Swagger-Client version: 3.10.2
  • Swagger/OpenAPI version: OpenAPI 3.0
Content & configuration

Swagger/OpenAPI definition:

paths:
  /test:
    post:
      requestBody:
        content:
          multipart/form-data:
            schema:
              title: Test
              type: object
              properties:
                photos:
                  type: array
                  items:
                    type: string
                    format: binary
      responses:
        "201":
          description: something
Describe the bug you're encountering

When you have a path definition of a multipart/form-data with a schema that contains an array and you pass just one element in this array, the backend receives a single value and not an array with just one element. This causes an exception by the openapi validator.
The problem lays in the function in the file http.js

function buildFormData(reqForm) {
  /**
   * Build a new FormData instance, support array as field value
   * OAS2.0 - when collectionFormat is multi
   * OAS3.0 - when explode of Encoding Object is true
   * @param {Object} reqForm - ori req.form
   * @return {FormData} - new FormData instance
   */
  return Object.entries(reqForm).reduce((formData, [name, input]) => {
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, value] of formatKeyValue(name, input, true)) {
      if (Array.isArray(value)) {
        // eslint-disable-next-line no-restricted-syntax
        for (const v of value) {
          formData.append(key, v);
        }
      } else {
        formData.append(key, value);
      }
    }
    return formData;
  }, new FormData());
}

if in formData a fieldname is repeated more than once, then it is sent as an array, which is the actual behaviour of the function buildFormData. This curl, as an example, sends correctly photos as an array

curl --location --request POST 'http://localhost/route' \
--header 'Content-Type: multipart/form-data' \
--form 'photos=@something.png' \
--form 'photos=@somehingelse.png'

But, if you have just one element in your array, the equivalent curl "produced" by the function buildFormData just sends a single value and not an array

curl --location --request POST 'http://localhost/route' \
--header 'Content-Type: multipart/form-data' \
--form 'photos=@something.png' 

The correct form to send an array is with the [] after the name of the field. The following curl sends an array even if there is just one element:

curl --location --request POST 'http://localhost/route' \
--header 'Content-Type: multipart/form-data' \
--form 'photos[]=@something.png' 
How to fix it

The simplest way to fix it I think is to add '[]' to the name of the field in case it's an array:

function buildFormData(reqForm) {
  /**
   * Build a new FormData instance, support array as field value
   * OAS2.0 - when collectionFormat is multi
   * OAS3.0 - when explode of Encoding Object is true
   * @param {Object} reqForm - ori req.form
   * @return {FormData} - new FormData instance
   */
  return Object.entries(reqForm).reduce((formData, [name, input]) => {
    // eslint-disable-next-line no-restricted-syntax
    for (const [key, value] of formatKeyValue(name, input, true)) {
      if (Array.isArray(value)) {
        // eslint-disable-next-line no-restricted-syntax
        for (const v of value) {
          formData.append(key + '[]', v);
        }
      } else {
        formData.append(key, value);
      }
    }
    return formData;
  }, new FormData());
}

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 in http.js at buildFormData and inspect how formatKeyValue handles the photos array from the supplied OpenAPI multipart/form-data definition. Reproduce the request with one photos element, then verify that the generated multipart field preserves array semantics as shown by the issue's single-element curl example.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, openapi
Domain
api
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.