Home > Back-end >  How to write Update API in Spring web flux?
How to write Update API in Spring web flux?

Time:12-18

I am pretty new to Spring web flux reactive programming. So this is little confusing.

I am writing update API with spring web flux. Passed request body tp the update method is a Mono of request. So My problem is How can I get the request body and perform with? . Please check the commented line in following code.

public Mono<User> updateUser(String userId, Mono<UserRequest> user){

    return userRepository.findById(userId)
        .switchIfEmpty(Mono.error(new NotFoundException("User not found")))
        .flatMap(foundUser -> {
            // How to get passed user object from Mono<UserRequest>
            modelMapper.map(source, foundUser);
            return Mono.just(userRepository.save(foundUser))
        })
}

Thank you.

CodePudding user response:

You can add .zipWith(user, (foundUser, user) -> ... (or simples .zipWith(user) that returns Tuple).

Samples:

    @Test
    void x1() {
        Mono<String> m1 = Mono.just("S1");
        Mono<String> m2 = Mono.just("S2");

        m1
            .switchIfEmpty(Mono.error(new NotFoundException("User not found")))
            .zipWith(m2, (s1, s2) -> s1.concat(s2)) // can be simplified to 'String::concat'
            .as(StepVerifier::create)
            .assertNext(s -> assertThat(s)
                .isEqualTo("S1S2")
            )
            .verifyComplete();
    }

    @Test
    void x2() {
        Mono<String> m1 = Mono.just("S1");
        Mono<String> m2 = Mono.error(new RuntimeException("some-error"));

        m1
            .switchIfEmpty(Mono.error(new NotFoundException("User not found")))
            .zipWith(m2, String::concat)
            .as(StepVerifier::create)
            .expectErrorSatisfies(throwable -> assertThat(throwable)
                .isInstanceOf(RuntimeException.class)
                .hasMessage("some-error")
            )
            .verify();
    }

    @Test
    void x3() {
        Mono<String> m1 = Mono.error(new RuntimeException("some-error"));
        Mono<String> m2 = Mono.just("S2");

        m1
            .switchIfEmpty(Mono.error(new NotFoundException("User not found")))
            .zipWith(m2, String::concat)
            .as(StepVerifier::create)
            .expectErrorSatisfies(throwable -> assertThat(throwable)
                .isInstanceOf(RuntimeException.class)
                .hasMessage("some-error")
            )
            .verify();
    }

    @Test
    void x4() {
        Mono<String> m1 = Mono.empty();
        Mono<String> m2 = Mono.just("S2");

        m1
            .switchIfEmpty(Mono.error(new NotFoundException("User not found")))
            .zipWith(m2, String::concat)
            .as(StepVerifier::create)
            .expectErrorSatisfies(throwable -> assertThat(throwable)
                .isInstanceOf(NotFoundException.class)
                .hasMessage("User not found")
            )
            .verify();
    }

Btw, there is a super-handy documentation from reactor: https://projectreactor.io/docs/core/release/reference/#which-operator

I am also wondering why you pass Mono<UserRequest> user - where does it come from and why you cannot use plain UserRequest user?

Also, your repository is suspicious - why findById returns a reactive object, while save does not? It looks like a blocking call, hence you loose benefits of webflux/reactor.

CodePudding user response:

// How to get passed user object from Mono

Start with that Mono (the repository calls are non-reactive operations anyway):

public Mono<User> updateUser(String userId, Mono<UserRequest> user){
    return user.map(request -> ...);
}
  • Related