Search code examples
javaasynchronousfuturevert.xweb-client

How to use futures in Vertx routers with WebClient in Java


I have a Vertx application with a router endpoint:

router.route(HttpMethod.GET, Constants.ENDPOINT).blockingHandler(this::getItems);

This router calls a method, that is supposed to return a JSON object in the browser, or whatever client is calling this endpoint. The JSON object actually comes from a completely different service. I am using Vert.x's WebClient library to call this service.

    private void getItems(RoutingContext routingContext) {
    HttpServerResponse response = routingContext.response();
    response.setChunked(true);
    response.putHeader("content-type", "text/plain");
    response.putHeader("Access-Control-Allow-Origin", "*");
    JsonObject data = new JsonObject();
    WebClient webClient = WebClient.create(vertx);
    webClient.post(80, "my-site.com", "/api/items")
        .as(BodyCodec.jsonArray())
        .putHeader("Accept", "application/json")
        .putHeader("Content-Type", "application/json")
        .sendJsonObject(new JsonObject().put("mutator", "*"), ar -> {
            if (ar.succeeded()) {
                HttpResponse<JsonArray> result = ar.result();
                JsonArray body = result.body();
                System.out.println(body);
                data.put("data", body.getJsonObject(0));
            } else {
                data.put("data", ar.cause().getMessage());
            }
        }); 
    response.write(data.encode());
    routingContext.response().end();
}

The data I get from my-site.com is fine and displays in the console with my System.out command. The problem is that I cannot get it into response.write.

Reading up, I see that this is related to futures. I don't really understand the concept, so I've been doing a lot of reading but cannot find any examples that fit my particular code.

How would I go about implementing futures so that the data I receive from my-site.com gets put into my Json object (data), and then can be used in response.write?


Solution

  • In your impl data will be an empty JSON object because Webclient is async. You are writing the response to the client before the response from Webclient is ready.

    Move the write into the webclient response and end the context there. E.g:

    ...
    
    if (ar.succeeded()) { 
        HttpResponse<JsonArray> result = ar.result();
        JsonArray body = result.body();
        System.out.println(body); 
        data.put("data", body.getJsonObject(0));
    } else { 
        data.put("data", ar.cause().getMessage());
    }
    
    response.write(data.encode());
    routingContext.response().end();
    
    ...