Israel77
Israel77

Reputation: 1

How to use the RestClient asynchronously in Quarkus with Mutiny?

I'm still new to Reactive programming and trying to learn how to use mutiny's Unis and Multis properly in web services.

Let's say that I have a RestClient that I can use to access multiple endpoints, each one of them returning a different data type:

@ApplicationScoped
@RegisterRestClient(config-key = "some-external-service")
public interface MyRestClient {
    
    @GET
    @Path("/endpoint-1")
    public Uni<String> getStringData();
    
    @GET
    @Path("/endpoint-2")
    public Uni<CustomResponseType> getCustomData();
    
    @GET
    @Path("/endpoint-3")
    public Uni<AnotherResponseType> getAnotherData();
}

And I need to combine some data from each request to build my own response:

public class MyResponseType {
    private String someString;
    private Integer someInteger;
    private Integer someOtherInteger;
    
    // getters and setters...
}

I can do it synchronously, like this:

@Path("my-endpoint")
public class MyService {
    @Inject
    @RestClient
    MyRestClient myRestClient;
    
    private MyResponseType myResponse;
    
    // Timeout for each request
    private static final Duration TIMEOUT = Duration.ofSeconds(2);
    
    @GET
    public MyResponseType getData() {
        myResponse = new MyResponseType();

        // Suppose that I might do some complex manipulation on the data
        // returned by the client, so I'd like to keep it in
        // separate methods
        fetchStringData();
        fetchIntegerData();
        fetchOtherIntegerData();
        
        return myResponse;
    }
    
    private void fetchStringData() {
        String stringData = myRestClient.getStringData().await().atMost(TIMEOUT);
        
        myResponse.setSomeString(stringData);
    }
    
    private void fetchIntegerData() {
        Integer integerData = myRestClient.getCustomData()
                                  .await().atMost(TIMEOUT)
                                  .getInteger();
        
        myResponse.setSomeInteger(integerData);
    }
    
    private void fetchOtherIntegerData() {
        Integer otherIntegerData = myRestClient.getSomeOtherData()
                                    .await().atMost(TIMEOUT)
                                    .getInteger();
        
        myResponse.setSomeOtherInteger(otherIntegerData);
    }
}

However this doesn't scale well, of course, because the application waits for each response before making the next request, even though they are independent of each other.

I think I could make it so that each method returns a Uni rather than being void, and then use Uni.join() to wait for them to complete before returning the response. However, I don't know how I would do it in this case, because each of the responses is of a different data type.

I did not find many examples on the Mutiny documentation about combining heterogeneous data types, which is a must when you need to consume from multiple http servers or databases.

Upvotes: 0

Views: 380

Answers (1)

geoand
geoand

Reputation: 64059

You can use Uni.combine() like so:

    Uni<Tuple3<String, CustomResponseType, AnotherResponseType>> tuple3 = Uni.combine().all()
            .unis(getStringData(), getCustomData(), getAnotherData()).asTuple();
    Uni<MyResponseType> = tuple3.map(t3 -> new MyResponseType(...))

Upvotes: 1

Related Questions