Spring Boot Multipart Upload: Combining JSON Data and File in One Request

Updated: 2025-04-09

When working with file uploads and accompanying JSON data, we often need to send a POST or PUT request from the frontend to the backend. But how do we handle this kind of "mixed" request?

Not all the Http Clients support this kind of request and we could get an error message like:

{ "message" : "Unexpected error: Content-Type 'application/octet-stream' is not supported"} 

for this reason in our first example we will use cURL and in a second example (to be done) we will use Angular.

The server side - Spring Boot

@Parameter(description = "Id of the existing Resume / CV", example = "1", required = true) 
@PutMapping(value = "/{documentId}", consumes = MULTIPART_FORM_DATA_VALUE) 
    @PathVariable Long documentId, 
    @Parameter(description = "Resume meta-data", required = true) 
    @Valid @RequestPart("data") ResumeDataInput data, 
    @Parameter(description = "File to update") MultipartFile file); 
 
public ResponseEntity<ResumeData> updateResume(Long id, ResumeDataInput resume, Multipartfile) { 
 ... 
} 

The client - cURL

We mentioned that not all the client can manage out-of-the box a mixed JSON and MultiPartFile, we can easily test the endpoint with cURL:

curl -X PUT "http://localhost:8080/123" \ 
 -H "Content-Type: multipart/form-data" \ 
 -F "data={ \"name\":\"yourName\", \"description\":\"yourDescription\"};type=application/json" \ 
 -F "file=@yourFilePath" 

-F (or --form) is used to emulate a web form, according to the documentation: emulate a filled-in form in which a user has pressed the submit button. This makes curl POST data using the Content-Type multipart/form-data according to RFC 2388.

With the previous configuration we can omit the file.

Backend alternative: @ModelAttribute

If all the fields are mandatory, the easiest solution is to use Spring's @ModelAttribute, you can simply use your DTO and Spring will do the magic.

The magic will break when you start to use complex types or try to have some optional fields.
Spring won't be able to bind anymore the form data with the object.

@PutMapping(value = "/{documentId}") 
public ResponseEntity<ResumeData> updateResume(@ModelAttribute ResumeDataInputWithFile resume) { 
    ... 
} 

With this solution, Spring maps automatically the request fields from the frontend to the backend DTO.

Problems can arise if you need, for example, to have some fields optionals. In this case you will get errors
like Content type 'multipart/form-data;boundary=---- error.


WebApp built by Marco using Java 21 - Hosted in Switzerland