OpenAPITools / OpenAPITools/openapi-generator
[BUG][JAVA] Generated ApiClient does not respect 'encoding' object for multipart request bodies, uses hard-coded application/octet-stream for all file form-data
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Description
The OpenAPI Specification v3 (3.0.0) describes an encoding object for multipart request bodies. The openapi-generator does not honor this in its Java client generation, and instead uses a hard-coded application/octet-stream. I've taken a peek at the generator templates for Java and determined this is indeed hard-coded and could be set dynamically.
Source: v3 encoding-object
This is most important for file-upload use-cases, but should ideally be supported for all form-data parameters.
openapi-generator version
v6.6.0 of the generator (via the openapi-generator-cli)
OpenAPI declaration file content or url
post:
operationId: uploadPdf
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- pdfFile
properties:
pdfFile:
type: string
format: binary
encoding:
pdfFile:
contentType: application/pdf
Note: I've stripped my form data down to just the file, but in my actual use-case there are several parameters other than pdfFile.
Steps to reproduce
Using the yaml provided above, observe a request from a generated client does not set the Content-Type header of the individual form data parameters based on the encoding object, but instead uses the hard-coded application/octet-stream. Looking at the generated ApiClient.java file's serialize method definition reveals the hard-coded value as well.
Related issues/PRs
- #724
- #1646
Suggest a fix
For all the Java clients, I suggest passing in a Map<String, String> with the key being the form param name, and the value being the value found in the encoding object in the yaml. Then use Map.getOrDefault(param.getKey(), MediaType.APPLICATION_OCTET_STREAM_TYPE) rather than the hard-coded octet stream type.
The functional code fix:
ApiClient.mustache in the serialize(...) method:
} else if (param.getValue() instanceof File) {
File file = (File) param.getValue();
String fileContentType = formParamContentTypes.getOrDefault(param.getKey(), MediaType.APPLICATION_OCTET_STREAM_TYPE)
mp.bodyPart(new FileDataBodyPart(param.getKey(), file, fileContentType));
}
The following methods would need to pass an additional Map<String, String> to support this change:
ApiClient::invokeAPIApiClient::getAPIResponse
The api.mustache template would need to add something like this:
Map<String, Object> localVarFormParams = new HashMap<String, Object>();
Map<String, String> localVarFormParamContentTypes = new HashMap<String, String>();
Note: Changing the serialize, invokeAPI, and getAPIResponse methods would result in a breaking change if ApiClient is considered part of the public API of the generated client.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with modules/openapi-generator/src/main/resources/Java/ApiClient.mustache and api.mustache, then generate a Java client from the YAML reproduction and inspect ApiClient.java. Done means multipart file parts use each property’s encoding contentType, fall back to application/octet-stream when absent, and pass that information through invokeAPI and getAPIResponse.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, openapi
- Domain
- api, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100