I have a situation where I call an external API A and use its response to feed to request of API B and call it and afterwards return the response to caller of API A. Something like below
method(){
response = call API A
}
method_for_API_A(){
handler() ->{
API_B
}
return response;
}
method_for_API_B(){
//code to call API B
}
What I am facing here is that API A method is returning response without waiting for getting response from B.
I checked about executeBlocking method of vert.x and also tried of using 'blocking queue' but unable to achieve what I am intended to do. Can someone please direct me to correct way of doing it.Thanks in advance.
EDIT: Just to explain the exact scenario
Class MyClass{
public Response method_A (Request request){
String respFromApiA = Call_API_A(request) ; // STEP 1
Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2
Print(respFromApiB) // PRINT FINAL Response
return respFromApiB; // STEP 3
}
String Call_API_A(Request request){
// Implementation
Print(string); // PRINT API A response
return string
}
Response Call_API_B(Response response){
// Implementation
Print(response); // PRINT API B response
return response;
}
}
I am using vert.x framework with Java. Now what happens during execution is, flow comes to STEP 1, initiate API A call. Goes to STEP 2 (without waiting for 'respFromApiA') and makes call to API B (which fails eventually because respFromApiA is NULL). And finally flow goes to STEP 3 and return from here. (without waiting for outcomes of API A and API B). If we see the print order it will be something like this
PRINT FINAL Response
PRINT API A response
PRINT API B response
What I am trying to achieve?
Wait for API A response.
Make call to API B. Wait for API B response.
Return response got from API B.
I hope I am able to make clear this time. Please let me know if you need further inputs.
Vert.x is highly asynchronous. Most operations will in fact return immediately but their results will be available to a Handler
at a later point in time. So far so good. If I understand you correctly than you need to call B
in the Handler
of A
. In this case A
needs to be finished and the result would be available before you call B
:
callA(asyncResultA -> {
System.out.println("Result A: " + asyncResultA.result());
callB(asyncResultB -> {
System.out.println("Result B:" + asyncResultB.result());
});
});
But what you are trying is to make something asynchronous synchron. You can not and should not try to make a asynchronous result available in the main program flow — that wouldn't work.
String respFromApiA = Call_API_A(request); // STEP 1
Response respFromApiB = Call_API_B(request, respFromApiA); // STEP 2
Print(respFromApiB); // PRINT FINAL Response
return respFromApiB; // STEP 3
Call_API_A
can't really return a result because it's calculated asynchronously. The result is only available for the Handler
of Call_API_A
(see my example above). Same for Call_API_B
– so you can't return the result of Call_API_B
. The caller of your class would also need to call your class with a Handler
.
Now some additional information. In your case you have the problem that multiple asynchronous results depend on each other. Vert.x provides a much more convenient way to handle asynchronous results — the so called Futures
. A Future
(sometimes called Promise
but in the Java world they are called Future
) is a placeholder for results of asynchronous calls. Read about them in the documentation.
With a Future
you can do something like this:
Future<...> callAFuture = Future.future();
callA(asyncResultA -> {
if (asyncResultA.succeeded()) {
System.out.println("A finished!");
callAFuture.complete(asyncResultA.result());
} else {
callAFuture.fail(asyncResultA.cause());
}
});
So instead of trying to return the asynchronous result of B
in a synchronous way you should return a Future
so the callee of your class could register for the asynchronous result of both A
and B
.
I hope this helps.
Edit: Future as return value
Lets say you want to wrap callA
with so you can work with a Future
. You could do it this way:
public Future<String> doSomethingAsync() {
Future<String> callAFuture = Future.future();
// do the async stuff
callA(asyncResultA -> {
if (asyncResultA.succeeded()) {
System.out.println("A finished!");
callAFuture.complete(asyncResultA.result());
} else {
callAFuture.fail(asyncResultA.cause());
}
});
// return Future with the asyncResult of callA
return callAFuture;
}
The Caller of this function can use the Future like this:
Future<String> doSomethingFuture = doSomethingAsync();
doSomethingFuture.setHandler(somethingResult -> {
// ... doSomethingAsync finished
});
It also possible to compose multiple Future
if you want to do them concurrently but they don't dependent on each other:
CompositeFuture.all(futureA, futureB).setHandler(connections -> {
// both Futures completed
});
If you work in a asynchronous environment like Vert.x most of time you work with a soon-to-be-available-result aka Future
. And in the Handler
of a Future
you often do another asynchronous call. You wrap a Future
with a Future
like the example of callB
in callA
's Handler
.
How would you return the asynchronous result of a Future
as an HTTP Response? Like this:
router.route("/").handler(routingContext -> {
HttpServerResponse response = routingContext.response();
Future<String> future = doSomethingAsync();
future.setHandler(somethingResult -> {
if (somethingResult.succeeded()) {
response
.end(somethingResult.result());
} else {
routingContext.fail(500);
}
});
});