How to properly get InputStreamResource to ResponseEntity in Webflux?

Viewed 294

I have a method that fetches a PDF from another web service, but we have to fetch a cross reference ID before we can make the call:

PdfService.groovy

@Service
class PdfService {
  @Autowired
  WebClient webClient

  @Autowired
  CrossRefService crossRefService

  InputStreamResource getPdf(String userId, String pdfId) {
      def pdf = return crossRefService
                .getCrossRefId(userId)
                .flatMapMany(crossRefResponse -> {
                    return webClient
                                .get()
                                .uri("https://some-url/${pdfId}.pdf", {
                                    it.queryParam("crossRefId", crossRefResponse.id)
                                    it.build(pdfId)
                                 })
                                .accept(MediaType.APPLICATION_PDF)
                                .retrieve()
                                .bodyToFlux(DataBuffer)                            
                })
                
        convertDataBufferToInputStreamResource(pdf)    
  }

  // https://manhtai.github.io/posts/flux-databuffer-to-inputstream/
  InputStreamResource getInputStreamFromFluxDataBuffer(Flux<DataBuffer> data) throws IOException {
    PipedOutputStream osPipe = new PipedOutputStream();
    PipedInputStream isPipe = new PipedInputStream(osPipe);

    DataBufferUtils.write(data, osPipe)
            .subscribeOn(Schedulers.elastic())
            .doOnComplete(() -> {
                try {
                    osPipe.close();
                } catch (IOException ignored) {
                }
            })
            .subscribe(DataBufferUtils.releaseConsumer());


    new InputStreamResource(isPipe);
    }
}

PdfController.groovy

@RestController
@RequestMapping("/pdf/{pdfId}.pdf")
class PdfController {
    
    @Autowired
    PdfService service

    @GetMapping
    Mono<ResponseEntity<Resource>> getPdf(@AuthenticationPrincipal Jwt jwt, @PathVariable String pdfId) {
        def pdf = service.getPdf(jwt.claims.userId, pdfId)
        Mono.just(ResponseEntity.ok().body(pdf))
    }
}

When I run my service class as an integration test, everything work fine, and the InputStreamResource has a content length of 240,000. However, when I try to make this same call from the controller, it seems as if the internal cross reference call is never made.

What is the correct way to place an InputStreamResource into a Publisher? Or is it even needed?

0 Answers
Related