Search code examples
quarkus-panachemutinyvertx-eventbusquarkus-reactivequarkus-hibernate-reactive

What is the correct way to call an external service (API) in a quarkus reactive application using vertx & mutiny?


I am new to reactive programming with vertx & muntiny (quarkus). I have the below requirement:

Structure: External API call returns -> Response

class Response {String abc; List<AnotherClass> another; ...}
class AnotherClass { List<Role>> roles ...}

DB call returns Uni<List<RoleFromDB>> rolesDB

I want the below call to be done in a reactive way in a chain. Can someone please guide me how to correctly do this.

  1. Call external API. 2. Call DB (postgres with reactive Hibernate & Panache) with some id value received from the API. 3. Add the DB query result to the result from API and return as a new Uni<Response>

Also can you please show me an example of calling the external API in a reactive way? I am not able to find any proper material for this online.

This is what I am currently doing.

 Uni<List<RolesfromDB>> roles == db call returning Uni<List<RoleFromDB>>
    
roles.chain(role -> {
    Response res = Unirest.get(url).header(...);
//Is calling external endpoint this way fine?

  Uni<Response> uniRes = Uni.createFrom().item(res);
//do some operation with uniRes to assign role to the response object and return a new Uni<Response> ...
    });

Is this correct or I need to use other means like

    io.vertx.axle.ext.web.client.WebClient?

An example on right way to call external API will be very much appreciated.


Solution

  • I would recommend two approaches.

    1. using the reactive REST client

    When using the reactive REST client (see https://quarkus.io/guides/rest-client-reactive), you create a Java interface that abstracts the HTTP interactions. A proxy is generated for you, so you don't need a low-level HTTP client. This reactive client supports both blocking and non-blocking. So, in your case, you will have something like:

    @GET
    Uni<Response> invokeMyService(Role role)
    

    And then, in your pipeline, you do:

    roles.chain(role -> client.invokeMyService(role));
    
    1. using the Vert.x Web client

    This is more low-level, and it should only be used if the reactive rest client cannot handle your specific case. In this case, you will do something like this:

    public MyClass(Vertx vertx) {  // io.vertx.mutiny.core.Vertx
        this.client = WebClient.create(vertx); // io.vertx.mutiny.ext.web.client.WebClient
    }
    
    // ...
    roles.chain(role -> {
       var req = this.client.getAbs(url); // using GET, use the method you need
       // Add headers and so on
       return req.send()
          .map(resp -> resp.bodyAsJsonObject().mapTo(Response.class);
        });