diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index add37053a28..9bd33ffcf55 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -5771,7 +5771,6 @@ public class DefaultCodegen implements CodegenConfig { CodegenParameter codegenParameter = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); // key => property name // value => property schema - String collectionFormat = null; Schema s = entry.getValue(); // array of schema if (ModelUtils.isArraySchema(s)) { @@ -5795,6 +5794,7 @@ public class DefaultCodegen implements CodegenConfig { } //TODO fix collectformat for form parameters //collectionFormat = getCollectionFormat(s); + String collectionFormat = getCollectionFormat(codegenParameter); // default to csv: codegenParameter.collectionFormat = StringUtils.isEmpty(collectionFormat) ? "csv" : collectionFormat; @@ -6669,4 +6669,15 @@ public class DefaultCodegen implements CodegenConfig { protected static boolean isJsonVendorMimeType(String mime) { return mime != null && JSON_VENDOR_MIME_PATTERN.matcher(mime).matches(); } + + /** + * Returns null by default but can be overwritten to return a valid collectionFormat + * for the {@link CodegenParameter}. + * + * @param codegenParameter parameter + * @return string for a collectionFormat. + */ + protected String getCollectionFormat(CodegenParameter codegenParameter) { + return null; + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavascriptClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavascriptClientCodegen.java index bf7468424d8..c3fa812bcab 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavascriptClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavascriptClientCodegen.java @@ -1220,4 +1220,16 @@ public class JavascriptClientCodegen extends DefaultCodegen implements CodegenCo } } } + + @Override + protected String getCollectionFormat(CodegenParameter codegenParameter) { + // This method will return `passthrough` when the parameter data format is binary and an array. + // `passthrough` is not part of the OAS spec. However, this will act like a flag that we should + // not do any processing on the collection type (i.e. convert to tsv, csv, etc..). This is + // critical to support multi file uploads correctly. + if (codegenParameter.isArray && Objects.equals(codegenParameter.dataFormat, "binary")) { + return "passthrough"; + } + return super.getCollectionFormat(codegenParameter); + } } diff --git a/modules/openapi-generator/src/main/resources/Javascript/ApiClient.mustache b/modules/openapi-generator/src/main/resources/Javascript/ApiClient.mustache index 8182d519770..f4f2024f4c6 100644 --- a/modules/openapi-generator/src/main/resources/Javascript/ApiClient.mustache +++ b/modules/openapi-generator/src/main/resources/Javascript/ApiClient.mustache @@ -316,6 +316,8 @@ case 'multi': // return the array directly as SuperAgent will handle it as expected return param.map(this.paramToString, this); + case 'passthrough': + return param; default: throw new Error('Unknown collection format: ' + collectionFormat); } @@ -489,11 +491,16 @@ var _formParams = this.normalizeParams(formParams); for (var key in _formParams) { if (_formParams.hasOwnProperty(key)) { - if (this.isFileParam(_formParams[key])) { + let _formParamsValue = _formParams[key]; + if (this.isFileParam(_formParamsValue)) { // file field - request.attach(key, _formParams[key]); + request.attach(key, _formParamsValue); + } else if (Array.isArray(_formParamsValue) && _formParamsValue.length + && this.isFileParam(_formParamsValue[0])) { + // multiple files + _formParamsValue.forEach(file => request.attach(key, file)); } else { - request.field(key, _formParams[key]); + request.field(key, _formParamsValue); } } } diff --git a/modules/openapi-generator/src/main/resources/Javascript/es6/ApiClient.mustache b/modules/openapi-generator/src/main/resources/Javascript/es6/ApiClient.mustache index 445073d5c01..91728cd6ea9 100644 --- a/modules/openapi-generator/src/main/resources/Javascript/es6/ApiClient.mustache +++ b/modules/openapi-generator/src/main/resources/Javascript/es6/ApiClient.mustache @@ -282,6 +282,8 @@ class ApiClient { case 'multi': //return the array directly as SuperAgent will handle it as expected return param.map(this.paramToString, this); + case 'passthrough': + return param; default: throw new Error('Unknown collection format: ' + collectionFormat); } @@ -451,11 +453,16 @@ class ApiClient { var _formParams = this.normalizeParams(formParams); for (var key in _formParams) { if (_formParams.hasOwnProperty(key)) { - if (this.isFileParam(_formParams[key])) { + let _formParamsValue = _formParams[key]; + if (this.isFileParam(_formParamsValue)) { // file field - request.attach(key, _formParams[key]); + request.attach(key, _formParamsValue); + } else if (Array.isArray(_formParamsValue) && _formParamsValue.length + && this.isFileParam(_formParamsValue[0])) { + // multiple files + _formParamsValue.forEach(file => request.attach(key, file)); } else { - request.field(key, _formParams[key]); + request.field(key, _formParamsValue); } } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/javascript/JavascriptClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/javascript/JavascriptClientCodegenTest.java index 1d46f10a731..f81ba9f22a8 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/javascript/JavascriptClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/javascript/JavascriptClientCodegenTest.java @@ -17,9 +17,13 @@ package org.openapitools.codegen.javascript; +import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.MediaType; import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.RequestBody; import org.openapitools.codegen.*; import org.openapitools.codegen.languages.JavascriptClientCodegen; import org.testng.Assert; @@ -113,4 +117,18 @@ public class JavascriptClientCodegenTest { } + @Test(description = "test multiple file upload collection is correct") + public void testMultipleFileUpload() throws Exception { + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/form-multipart-binary-array.yaml"); + final JavascriptClientCodegen codegen = new JavascriptClientCodegen(); + codegen.setOpenAPI(openAPI); + + final String requestPath = "/multipart-array"; + Operation textOperation = openAPI.getPaths().get(requestPath).getPost(); + CodegenOperation operation = codegen.fromOperation(requestPath, "post", textOperation, null); + CodegenParameter codegenParameter = operation.allParams.get(0); + + Assert.assertEquals(codegenParameter.collectionFormat, "passthrough"); + } + } diff --git a/samples/client/petstore/javascript-es6/src/ApiClient.js b/samples/client/petstore/javascript-es6/src/ApiClient.js index fa308c73adc..947a9e05217 100644 --- a/samples/client/petstore/javascript-es6/src/ApiClient.js +++ b/samples/client/petstore/javascript-es6/src/ApiClient.js @@ -280,6 +280,8 @@ class ApiClient { case 'multi': //return the array directly as SuperAgent will handle it as expected return param.map(this.paramToString, this); + case 'passthrough': + return param; default: throw new Error('Unknown collection format: ' + collectionFormat); } @@ -439,11 +441,16 @@ class ApiClient { var _formParams = this.normalizeParams(formParams); for (var key in _formParams) { if (_formParams.hasOwnProperty(key)) { - if (this.isFileParam(_formParams[key])) { + let _formParamsValue = _formParams[key]; + if (this.isFileParam(_formParamsValue)) { // file field - request.attach(key, _formParams[key]); + request.attach(key, _formParamsValue); + } else if (Array.isArray(_formParamsValue) && _formParamsValue.length + && this.isFileParam(_formParamsValue[0])) { + // multiple files + _formParamsValue.forEach(file => request.attach(key, file)); } else { - request.field(key, _formParams[key]); + request.field(key, _formParamsValue); } } } diff --git a/samples/client/petstore/javascript-promise-es6/src/ApiClient.js b/samples/client/petstore/javascript-promise-es6/src/ApiClient.js index cd449f850c4..dbf723afbf0 100644 --- a/samples/client/petstore/javascript-promise-es6/src/ApiClient.js +++ b/samples/client/petstore/javascript-promise-es6/src/ApiClient.js @@ -280,6 +280,8 @@ class ApiClient { case 'multi': //return the array directly as SuperAgent will handle it as expected return param.map(this.paramToString, this); + case 'passthrough': + return param; default: throw new Error('Unknown collection format: ' + collectionFormat); } @@ -431,11 +433,16 @@ class ApiClient { var _formParams = this.normalizeParams(formParams); for (var key in _formParams) { if (_formParams.hasOwnProperty(key)) { - if (this.isFileParam(_formParams[key])) { + let _formParamsValue = _formParams[key]; + if (this.isFileParam(_formParamsValue)) { // file field - request.attach(key, _formParams[key]); + request.attach(key, _formParamsValue); + } else if (Array.isArray(_formParamsValue) && _formParamsValue.length + && this.isFileParam(_formParamsValue[0])) { + // multiple files + _formParamsValue.forEach(file => request.attach(key, file)); } else { - request.field(key, _formParams[key]); + request.field(key, _formParamsValue); } } }