What is the correct reactive pattern in Java Spring WebFlux to return a (large) file from the REST controller?
Asked Answered
M

1

3

Situation:

  • I have a non-reactive legacy library which expects an OutputStream and writes its output into it, the method signature is something like void produceData(OutputStream stream)
  • I want to expose the output from the method via a web service as a PDF file
  • The file can be sometimes very large
  • I am using the reactive framework Spring WebFlux

Motivation:

  • I want my code to stay "as reactive as possible"
  • I do not want to allocate a byte array for all the data at once, I want to maximally exploit the fact that the legacy method writes the output to OutputStream

Question:

  • What is the correct reactive pattern in WebFlux to return a large file in general?
  • What is the correct reactive pattern in WebFlux to return a large file when the source of the data is a non-reactive method writing to a given OutputStream?
  • I should also be able to let the client understand that the output from the web service is a PDF file with a proper name.

What I am considering:

  • Mono<ByteArrayResource> getData() - I don't want to use it because I would have to allocate the byte array for the whole content.
  • In the non-reactive world, I would just inject the ServletResponse object into the controller method and passed its output stream ServletResponse.getOutputStream() to my legacy method, but I don't know how to do this in the reactive world and if it is even recommended at all.
  • Mono<DataBuffer> getData() - In the controller code, I can easily obtain a new DataBuffer from a DefaultDataBufferFactory and use its asOutputStream() method, but then I don't know how to handle properly so the DataBuffer is released after the data are consumed by the client.

What is the correct reactive pattern to handle situations like this?

Mercier answered 12/9, 2022 at 14:19 Comment(0)
H
0

Its completely ok to call a no reactive method . Its only important to keep the reactive flow reactive instead of blocking it

for example

someRepository.findById( id )
               .map( entity -> entity.setValue( value ) )
               .filter( entity -> entity.someCondition > other condition )
               .map( entity -> someNonReactiveLibrary.function(entity.getAttribute())) //non-reactive method
                .collect( Collectors.toList());

If you see the this entire block executes in one thread and it is going to be sequential. In this particular flow, you can including non-reactive method and it is completely normal.

Hydantoin answered 21/9, 2022 at 6:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.