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?