Search code examples
spring-bootmonoreactive-programmingspring-webflux

webflux Mono response empty


I have a very simple spring webflux rest endpoint in my project.

@Bean
public RouterFunction authRoute() {
    return RouterFunctions.route(POST("/auth/signin").and(accept(APPLICATION_JSON)), this::signIn)
            .andRoute(POST("/auth/signup").and(accept(APPLICATION_JSON)), this::signUp)
            .andRoute(POST("/auth/test").and(accept(APPLICATION_JSON)), this::test);
}

And /auth/test endpoint just reply back with the username supplied.

public Mono<ServerResponse> test(ServerRequest request) {
    System.out.println("Start test ");
    Mono<JwtRequest> jwtRequestMono = request.bodyToMono(JwtRequest.class);
    jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));
    return jwtRequestMono
            .flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));
}

terminal

The problem I am facing is that the response body is empty, it should be the username. I also verified that when I return the hardcoded string, it passes. It fails when I depend on jwtRequestMono.flatMap(...

![postman


Solution

  • This line is almost certainly your downfall:

    jwtRequestMono.subscribe(v -> System.out.println(v.getUsername() + ":" + v.getPassword()));
    

    Your request can't be subscribed to multiple times - so you subscribe to it on this line (which works and prints out the values as expected), then the framework subscribes to it, and it blows up. I'd expect to see an exception and a 500 response returned when this happens by default, so chances are you're swallowing an exception somewhere.

    Never subscribe within your own application. That's the frameworks job.

    Instead, if you want to have a "side-effect" where you print the values as they come in, then use doOnNext() as part of your reactive chain:

    return jwtRequestMono
            .doOnNext(v -> System.out.println(v.getUsername() + ":" + v.getPassword()))
            .flatMap(j -> ServerResponse.ok().contentType(APPLICATION_JSON).bodyValue(j.getUsername()));