When working with APIs, there may be a need to send a request with JSON data and receive a response in multipart/form-data format containing a file. In this article, we will discuss how to configure RestTemplate to handle such data. Create a class for serializing JSON to send import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class JsonRequest { String field1; int field2; } Configure RestTemplate, prepare, and send a POST request public Optional<Resource> postSomeReq(JsonRequest rq) { String url = "http://somehost/services/retrieve-multipart"; try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(List.of(MediaType.MULTIPART_FORM_DATA)); RestTemplate restClient = new RestTemplate(); ResponseEntity<byte[]> response = restClient.postForEntity(url, getRequestData(rq, headers), byte[].class); return getResource(response.getBody()); } catch (RestClientException | MessagingException | IOException e) { return Optional.empty(); } } private HttpEntity<String> getRequestData(Object request, HttpHeaders headers) { String requestBody; try { requestBody = new ObjectMapper().writeValueAsString(request); } catch (JsonProcessingException e) { throw new RuntimeException(e); } return new HttpEntity<>(removeShielding(requestBody), headers); } private Optional<Resource> getResource(byte[] responseBody) throws MessagingException, IOException { ByteArrayDataSource dataSource = new ByteArrayDataSource(responseBody, "multipart/form-data"); MimeMultipart multipart = new MimeMultipart(dataSource); int count = multipart.getCount(); for (int i = 0; i < count; i++) { BodyPart bodyPart = multipart.getBodyPart(i); String[] contentType = bodyPart.getHeader("Content-Type"); if ("application/octet-stream".equals(contentType[0])) { SharedByteArrayInputStream inputStream = (SharedByteArrayInputStream) bodyPart.getContent(); final String filename = bodyPart.getFileName(); Resource resource = new ByteArrayResource(inputStream.readAllBytes()) { @Override public String getFilename() { return filename; } }; return Optional.of(resource); } } return Optional.empty(); } Alternative Approach You can also use a third-party converter MultipartMessageConverter (GitHub Repository). It provides a simple implementation of HttpMessageConverter that can read multipart/form-data and prepare a DTO model, even if a part contains either application/json or application/octet-stream. public Optional<Resource> postSomeReq(JsonRequest rq) { String url = "http://somehost/services/retrieve-multipart"; try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(List.of(MediaType.MULTIPART_FORM_DATA)); RestTemplate restClient = new RestTemplate(); restClient.getMessageConverters().add(new MultiPartMessageConverter(objectMapper)); ResponseEntity<ResultModel> responseEntity = restClient.postForEntity(url, getRequestData(rq, headers), ResultModel.class); final ResultModel resultModel = responseEntity.getBody(); return Optional.of(resultModel.fileModel.resource); } catch (RestClientException | MessagingException | IOException e) { return Optional.empty(); } } Conclusion We have reviewed how to use RestTemplate to send a JSON request and receive a response in multipart/form-data format. The approach presented allows for effective handling of multipart responses, which is useful in various scenarios, such as downloading files from a server. An alternative approach using a third-party converter was also presented. You can now use these methods in your applications to work with multipart data, enhancing the functionality and flexibility of your code. When working with APIs , there may be a need to send a request with JSON data and receive a response in multipart/form-data format containing a file. In this article, we will discuss how to configure RestTemplate to handle such data. APIs JSON Create a class for serializing JSON to send import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class JsonRequest { String field1; int field2; } import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class JsonRequest { String field1; int field2; } Configure RestTemplate, prepare, and send a POST request public Optional<Resource> postSomeReq(JsonRequest rq) { String url = "http://somehost/services/retrieve-multipart"; try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(List.of(MediaType.MULTIPART_FORM_DATA)); RestTemplate restClient = new RestTemplate(); ResponseEntity<byte[]> response = restClient.postForEntity(url, getRequestData(rq, headers), byte[].class); return getResource(response.getBody()); } catch (RestClientException | MessagingException | IOException e) { return Optional.empty(); } } private HttpEntity<String> getRequestData(Object request, HttpHeaders headers) { String requestBody; try { requestBody = new ObjectMapper().writeValueAsString(request); } catch (JsonProcessingException e) { throw new RuntimeException(e); } return new HttpEntity<>(removeShielding(requestBody), headers); } private Optional<Resource> getResource(byte[] responseBody) throws MessagingException, IOException { ByteArrayDataSource dataSource = new ByteArrayDataSource(responseBody, "multipart/form-data"); MimeMultipart multipart = new MimeMultipart(dataSource); int count = multipart.getCount(); for (int i = 0; i < count; i++) { BodyPart bodyPart = multipart.getBodyPart(i); String[] contentType = bodyPart.getHeader("Content-Type"); if ("application/octet-stream".equals(contentType[0])) { SharedByteArrayInputStream inputStream = (SharedByteArrayInputStream) bodyPart.getContent(); final String filename = bodyPart.getFileName(); Resource resource = new ByteArrayResource(inputStream.readAllBytes()) { @Override public String getFilename() { return filename; } }; return Optional.of(resource); } } return Optional.empty(); } public Optional<Resource> postSomeReq(JsonRequest rq) { String url = "http://somehost/services/retrieve-multipart"; try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(List.of(MediaType.MULTIPART_FORM_DATA)); RestTemplate restClient = new RestTemplate(); ResponseEntity<byte[]> response = restClient.postForEntity(url, getRequestData(rq, headers), byte[].class); return getResource(response.getBody()); } catch (RestClientException | MessagingException | IOException e) { return Optional.empty(); } } private HttpEntity<String> getRequestData(Object request, HttpHeaders headers) { String requestBody; try { requestBody = new ObjectMapper().writeValueAsString(request); } catch (JsonProcessingException e) { throw new RuntimeException(e); } return new HttpEntity<>(removeShielding(requestBody), headers); } private Optional<Resource> getResource(byte[] responseBody) throws MessagingException, IOException { ByteArrayDataSource dataSource = new ByteArrayDataSource(responseBody, "multipart/form-data"); MimeMultipart multipart = new MimeMultipart(dataSource); int count = multipart.getCount(); for (int i = 0; i < count; i++) { BodyPart bodyPart = multipart.getBodyPart(i); String[] contentType = bodyPart.getHeader("Content-Type"); if ("application/octet-stream".equals(contentType[0])) { SharedByteArrayInputStream inputStream = (SharedByteArrayInputStream) bodyPart.getContent(); final String filename = bodyPart.getFileName(); Resource resource = new ByteArrayResource(inputStream.readAllBytes()) { @Override public String getFilename() { return filename; } }; return Optional.of(resource); } } return Optional.empty(); } Alternative Approach You can also use a third-party converter MultipartMessageConverter ( GitHub Repository ). It provides a simple implementation of HttpMessageConverter that can read multipart/form-data and prepare a DTO model, even if a part contains either application/json or application/octet-stream . MultipartMessageConverter GitHub Repository HttpMessageConverter multipart/form-data application/json application/octet-stream public Optional<Resource> postSomeReq(JsonRequest rq) { String url = "http://somehost/services/retrieve-multipart"; try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(List.of(MediaType.MULTIPART_FORM_DATA)); RestTemplate restClient = new RestTemplate(); restClient.getMessageConverters().add(new MultiPartMessageConverter(objectMapper)); ResponseEntity<ResultModel> responseEntity = restClient.postForEntity(url, getRequestData(rq, headers), ResultModel.class); final ResultModel resultModel = responseEntity.getBody(); return Optional.of(resultModel.fileModel.resource); } catch (RestClientException | MessagingException | IOException e) { return Optional.empty(); } } public Optional<Resource> postSomeReq(JsonRequest rq) { String url = "http://somehost/services/retrieve-multipart"; try { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(List.of(MediaType.MULTIPART_FORM_DATA)); RestTemplate restClient = new RestTemplate(); restClient.getMessageConverters().add(new MultiPartMessageConverter(objectMapper)); ResponseEntity<ResultModel> responseEntity = restClient.postForEntity(url, getRequestData(rq, headers), ResultModel.class); final ResultModel resultModel = responseEntity.getBody(); return Optional.of(resultModel.fileModel.resource); } catch (RestClientException | MessagingException | IOException e) { return Optional.empty(); } } Conclusion We have reviewed how to use RestTemplate to send a JSON request and receive a response in multipart/form-data format. The approach presented allows for effective handling of multipart responses, which is useful in various scenarios, such as downloading files from a server. An alternative approach using a third-party converter was also presented. multipart/form-data You can now use these methods in your applications to work with multipart data, enhancing the functionality and flexibility of your code.