1

The aim of my code is to retrieve an image from a third-party service.

I struggled a little for endpoint of download to work and only partially succeeded. When I call the endpoint via postman the answer is a .bin file, but what I need is to have a .png file. The greatest success is being able to get a .png file being able to customize the name as well. But personalization of the is not strictly necessary.

The project is built with the initializer and has the following dependencies:

  • spring-boot-starter-web;
  • lombok
  • spring-boot-starter-webflux
  • reactor-spring

Below is the source code of my endpoint:

@GetMapping("/retrieve-image")
public Mono<byte[]> retrieveImage(ImageRequest request) throws ExecutionException, InterruptedException, IOException {
    MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
    queryParams.add("attribute", request.getAttribute()); // fake for query string setting.
    Mono<byte[]> image = webClient
            .get()
            .uri(uriBuilder -> uriBuilder
                    .path(Endpoint.THIRD_PARTY_SERVICE_URI)
                    .queryParams(queryParams)
                    .build())
            .accept(MediaType.valueOf(String.valueOf(MediaType.IMAGE_PNG)))
            .exchange()
            .flatMap(clientResponse -> clientResponse.bodyToMono(byte[].class)
                    .doOnSuccess(body -> {
                        if (clientResponse.statusCode().isError()) {
                            log.error("HttpStatusCode = {}", clientResponse.statusCode());
                            log.error("HttpHeaders = {}", clientResponse.headers().asHttpHeaders());
                            log.error("ResponseBody = {}", body);
                        }
                    }));
    return image;
}
Stoic Lion
  • 470
  • 2
  • 14
  • AFAIK, the `spring-web` is not recommended to use with `spring-webflux` in the same app. https://stackoverflow.com/questions/53883037/can-i-use-springmvc-and-webflux-together – Vladimir Shefer Oct 01 '20 at 11:44
  • https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#webflux . a cite from the documentation: If you have a Spring MVC application with calls to remote services, try the reactive WebClient. You can return reactive types (Reactor, RxJava, or other) directly from Spring MVC controller methods. @VladimirShefer – Stoic Lion Oct 01 '20 at 12:08
  • What do you mean by "pear tree" and what is "call the pear by mail"? – meberhard Oct 02 '20 at 13:38
  • @meberhard I'm sorry. It's a typo. – Stoic Lion Oct 02 '20 at 14:15

1 Answers1

1

You can also add the mime type of the file to the produces section of the @GetMapping annotation, it should look something like this:

@GetMapping(path = "/retrieve-image",
        produces = "image/png")

Additionally, instead of returning a Mono<byte[]>, you can wrap your response in a ResponseEntity<Resource>. This gives you the possibility to add Headers and tell the browser the name of your file. For example:

HttpHeaders header = new HttpHeaders();
header.add(HttpHeaders.CONTENT_DISPOSITION,
        "attachment; filename=image.png");
header.add("Access-Control-Expose-Headers", "Content-Disposition");

return ResponseEntity.ok().
        .headers(header)
        .contentLength(Files.size(path))
        .body(<<YOUR_FILE_HERE>>);

One last thought: If you add both spring-boot-starter-web and spring-boot-starter-webflux to your dependencies, the app will work, but it doesn't use Netty from Webflux, instead the usual Tomcat. So you don't benefit from the reactive features.

meberhard
  • 1,797
  • 1
  • 19
  • 24
  • thanks for the fix. in my endpoint I use Mono<>, with pojo or byte[]. Can you write the whole endpoint in your example? what are the benefits of your solution? .. I'm writing a web server with rest controller, but I need WebClient to do call to third-party service; RestTemplate is very old and unfit... how would you rearrange dependencies? What are the benefits? thanks. – Stoic Lion Oct 06 '20 at 10:32