quarkusresteasymutinyquarkus-reactive

What is the point of returning a Multi instead of a Uni with RestEasy?


I am using RESTEasy Reactive with a MongoDB / Panache and I am trying to understand what the point of the .stream() methods (when using REST).

In several examples (quarkus docs, video, medium article, etc.) a Multi is used as a return value for a GET Request. How does this make sense, since the HTTP call is a one-shot call?

I tried to delay each item of the Multi stream, but as I expected I only get the response after the 5 seconds are over:

@GET
@Path("stream")
public Multi<Integer> streamTest() {
    return Multi.createFrom()
            .items(1, 2, 3, 4, 5)
            .onItem().call(i -> {
                Duration delay = Duration.ofSeconds(1);
                return Uni.createFrom().nullItem().onItem().delayIt().by(delay);
            });
}

What am I missing? 🤔


Solution

  • I've tested your code with one of the quickstarts and I think the reason you don't see it as a stream is because of the header and the client you are using to read the response.

    It works fine for me when I open it in Firefox, but not when I read it in the terminal with Httpie.

    If you change the code and add an empty @Produces annotation on top of it, it should work as expected with all clients because the response header now will be text/event-stream:

        @GET
        @Path("stream")
        @Produces(MediaType.SERVER_SENT_EVENTS) // or just @Produces
        public Multi<Integer> getStream() {
            return Multi.createFrom()
                    .items( 1, 2, 3, 4, 5 )
                    .onItem().call( i -> {
                        Duration delay = Duration.ofSeconds( 2 );
                        return Uni.createFrom().nullItem().onItem().delayIt().by( delay );
                    } );
        }
    

    So, it's really about making sure that the response uses the right header for your use case.

    That said, everything else you say makes sense. At the moment, running a query on the database doesn't return a stream and therefore returning a Multi is usually not helpful. That's why the API in Panache and Hibernate Reactive for queries return a Uni.

    One use case I can think of for Multi is when you have a message driven application. In this case you might want to update a web page or some other component as soon as a message is received on a channel. There is an example of this in the guide that uses Quarkus and Kafka.

    There are also a couple of guides with an introduction to Mutiny and how you can use it for Flow control and backpressure