naf
naf

Reputation: 147

How to perform sequential API calls and avoid deep nesting with Spring WebFlux?

I'm using Spring WebFlux to make some asynchronous API calls. The problem is these calls need to happen in sequential order because each call depends on the previous one.

In the end, I need the values of all calls (A, B, and C) to create a response DTO.

In order to achieve this, I'm using nested flatMaps like so:

public Flux<PersonDto> getPersons() {
    return service.callA()
            .flatMap(dtoCallA -> {
                String name = dtoCallA.getName();
                String addressId = dtoCallA.getAddressId();
                service.callB(addressId)
                    .flatMap(dtoCallB -> {
                            String address = dtoCallB.getAddress();
                            String postalCodeId = dtoCallB.getPostalCodeId();
                            service.callC(postalCodeId)
                                    .flatmap(dtoCallC -> {
                                        String postalCode = dtoCallC.getPostalCode();
                                        return PersonDto.builder()
                                                    .name(name)
                                                    .address(adress)
                                                    .postalCode(postalCode)
                                                    .build();
                                    });
                        });

            });
}

How can I improve this and maintain the single-responsibility principle? These calls can't happen simultaneously. Should I use context or zipWhen?

Upvotes: 2

Views: 763

Answers (1)

K.Nicholas
K.Nicholas

Reputation: 11551

I don't know about context but can you just rewrite the code?

Flux<DtoA> dtoA = service.callA();
Flux<DtoB> dtoB = dtoA.flatMap(dtoCallA-> ... );
Flux<DtoC> dtoC = dtoB.flatMap(dtoCallB-> .... );
Flux<PersonDto> = dtoC.flatMap(dtoCallC-> ... );

I suspect it will get compiled/optimized into the same byte code either way.

EDIT:

public class TuplePlay {
    public static void main(String[] args) {
        new TuplePlay().run();
    }
    
    @Data
    @Builder
    static class Person {
        String a;
        String b;
        String c;
    }
    private void run() {
        Mono<Tuple2<String, Person>> sar = sa.get().map(s1->Tuples.of(s1, Person.builder().a(s1).build()));
        Mono<Tuple2<String, Person>> sbr = sar.flatMap(t->sb.apply(t.getT1()).map(s2->{t.getT2().setB(s2); return Tuples.of(s2, t.getT2());}));
        Mono<Person> scr = sbr.flatMap(t->sc.apply(t.getT1()).map(s3->{t.getT2().setC(s3); return t.getT2();}));
        scr.subscribe(System.out::println);
    }
    
    Supplier<Mono<String>> sa = () -> Mono.just("A");
    Function<String, Mono<String>> sb = s->Mono.just("B of " + s);
    Function<String, Mono<String>> sc = s->Mono.just("C of " + s);

}

Upvotes: 1

Related Questions