paint-brush
How to Receive Files from multipart/form-data Responses Using RestTemplate in Javaby@ndee80
424 reads
424 reads

How to Receive Files from multipart/form-data Responses Using RestTemplate in Java

by Andrei RogalenkoJuly 31st, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

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.
featured image - How to Receive Files from multipart/form-data Responses Using RestTemplate in Java
Andrei Rogalenko HackerNoon profile picture

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.