I try to make sequential API calls and merge the result in a mono . The first API contains a List of Id for the second API.
@Service @AllArgsConstructor public class AggregateService { private OperationClient operationClient; private OuvrageClient ouvrageClient; public Mono<OperationDetailDto> getDetails(String operationId){ final Mono<OperationFullDto> operationMono = operationClient.getOperation(operationId); return operationMono .flatMap(operation -> { final OperationDetailDto detail = new OperationDetailDto(); final Mono<List<OuvrageDto>> ouvrageMono = ouvrageClient.getOuvrages(operation.getOuvrageIds()); Mono<Tuple2<OperationFullDto, List<OuvrageDto>>> tuple2 = Mono.zip(operationMono,ouvrageMono); tuple2.map(result ->{ detail.setId(ServiceUtils.formatUuid(operationId)); detail.setTitre(result.getT1().getTitre()); detail.setOuvrages(result.getT2()); return detail; }); return Mono.just(detail); } ); } }
My functional WebClient
@Service public class OperationClient { private final WebClient webClient; public OperationClient(WebClient.Builder builder) { this.webClient = builder.baseUrl("lb://operation-microservice/operation/").build(); } public Mono<OperationFullDto> getOperation(String operationId){ return webClient .get() .uri("{id}" , operationId) .retrieve() .bodyToMono(OperationFullDto.class) .subscribeOn(Schedulers.parallel()) .log() .onErrorResume(ex->Mono.empty()); } }
The ouvrageClient was invoked but I don’t see log
public class OuvrageClient { private final WebClient webClient; public OuvrageClient(WebClient.Builder builder) { this.webClient = builder.baseUrl("lb://ouvrage-microservice/ouvrage/").build(); } public Mono<List<OuvrageDto>> getOuvrages(List<Long> ids){ System.out.println("the void getOuvrages was invoked " + ids ); return webClient .get() .uri("multi/{ids}",ids) .retrieve() .bodyToFlux(OuvrageDto.class) .subscribeOn(Schedulers.parallel()) .collectList() .onErrorReturn(Collections.emptyList()) .log(); } }
Log
2022-06-21 10:54:37.872 INFO 252 --- [ctor-http-nio-3] reactor.Mono.SubscribeOn.1 : onSubscribe(MonoSubscribeOn.SubscribeOnSubscriber) 2022-06-21 10:54:37.875 INFO 252 --- [ctor-http-nio-3] reactor.Mono.SubscribeOn.1 : request(unbounded) 2022-06-21 10:54:38.724 INFO 252 --- [ctor-http-nio-1] reactor.Mono.SubscribeOn.1 : onNext(OperationFullDto(id=c4f62ea6-0387-4021-b5de-d056105612ce, titre=test3, ouvrageIds=[2])) the void getOuvrages was invoked [2] 2022-06-21 10:54:38.796 INFO 252 --- [ctor-http-nio-1] reactor.Mono.SubscribeOn.1 : onComplete()
The ouvrageClient was invoked but I don’t see log for the ouvrageClient …. and the global result of my AggregateService is empty
{"id": null,"titre": null,"ouvrages": null}
Thanks
Thanks for the answer ! what do you think of this piece of code?
public Mono<OperationDetailDto> getDetails(String operationId){ final Mono<OperationFullDto> operationMono = operationClient.getOperation(operationId); return operationMono.zipWhen( operation -> ouvrageClient.getOuvrages(operation.getOuvrageIds()) ) .map( tuple2 -> { OperationDetailDto detail = new OperationDetailDto(); detail.setId(ServiceUtils.formatUuid(operationId)); detail.setTitre(tuple2.getT1().getTitre()); detail.setOuvrages(tuple2.getT2()); return detail; }); }
Advertisement
Answer
You could return the tuple2.map
to the flatMap
operation directly, but make sure you create and return the OperationDetailDto
inside the map
‘s lambda.
.flatMap(operation -> { final Mono<List<OuvrageDto>> ouvrageMono = ouvrageClient.getOuvrages(operation.getOuvrageIds()); Mono<Tuple2<OperationFullDto, List<OuvrageDto>>> tuple2 = Mono.zip(operationMono, ouvrageMono); return tuple2.map(result -> { final OperationDetailDto detail = new OperationDetailDto(); detail.setId(ServiceUtils.formatUuid(operationId)); detail.setTitre(result.getT1().getTitre()); detail.setOuvrages(result.getT2()); return detail; }); })