I have recently started using WebFlux and need suggestion on how to chain multiple services and aggregate responses on the way. The 4 services and their Response POJO are similar to following example:
class Response1{
String a1;
String a2;
}
class Response2{
String b1;
}
class Response3{
String c1;
}
class Response4{
String d1;
}
and the signature of 4 services:
Flux<Response1> service1();
Flux<Response2> service2(String a1); //output field of Response1(service 1)
Flux<Response3> service3(String b1); //output field of Response2(service 2)
Mono<Response4> service4(String a2); //output field of Response1(service 1)
So service2 needs to invoked for each Response1 in Flux, and service3 for each Response2. Relationship between models is:
Response1 <1-----*>Response2 (1 to many),
Response2 <1-----*>Response3 (1 to many),
Response1 <1-----1>Response4 (1 to 1)
Aggregated final response should look like (JSON):
[
{
"a1": "",
"a2": "",
"d1": "",
"response2s": [
{
"b1": "",
"response3s": [
{
"c1": ""
}
]
}
]
}
]
So first I need to call Service1 and then call service2 for each Response1, then call service3 for each Response2(returned by service2). Also, call service4 for each response1 returned by service1 (could be called in parallel to service2 and service3 calls). In order to update Aggregated final Response, I have added two additional POJOs to allow storing child responses, e.g. (relevant bits):
public class AggResponse extends Response1{
List<AggResponse2> response2s;// populated from service2 response
String d1; // populated from service4 response
public void add(AggResponse2 res2){
if(response2s == null)
response2s = new ArrayList<>();
response2s.add(res2);
}
}
and
public class AggResponse2 extends Response2{
List<Response3> response3s;// populated from service3 response
public void add(Response3 res3) {
if (response3s == null)
response3s = new ArrayList<>();
response3s.add(res3);
}
}
How best to do chaining so that I retain previous response data and while combining operators retain all data in the AggResponse object? I tried following:
public Flux<AggResponse> aggregate() {
return services.service1()
.map(res1 -> new AggResponse(res1.getA1(), res1.getA2()))
.flatMap(aggRes -> services.service2(aggRes.getA1())
.map(res2 -> {
AggResponse2 aggRes2 = new AggResponse2(res2.getB1());
aggRes.add(aggRes2);
return aggRes2;
})
.flatMap(aggRes2 -> services.service3(aggRes2.getB1())
.map(res3 -> {
aggRes2.add(res3);
return res3;
})
.reduce(aggRes2, (a, aggRes3) -> aggRes2)
)
.reduce(aggRes, (a, aggRes2) -> aggRes)
)
.flatMap(aggRes -> services.service4(aggRes.getA1())
.map(res4 -> {
aggRes.setD1(res4.getD1());
return aggRes;
})
);
}
however, I get following incomplete response:
[ {
"a1" : "a1v1",
"a2" : "a2v1"
} ]
I see all services being called out as I see logs. Two questions: 1. why don't see aggregated response, could reduce be loosing it? 2. is there a better approach of achieving this?