'Spring Gatewayfilter (AUTH) How to Catch Error 500 and return the response from Auth-Service

Is there a way to catch the 500 Error and return the auth/userservice response instead of throwing?

eg. "Token invalid" / "Token expired" - the userservice already provides the correct response

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {

            String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

            String[] parts = authHeader.split(" ");

            return webClientBuilder.build()
                    .post()
                    .uri("http://USER-SERVICE/user/validateToken?token=" + parts[1])
                    .retrieve()
                    .bodyToMono(UserDto.class)
                    .map(userDto -> {
                        exchange.getRequest()
                                .mutate()
                                .header("X-auth-user-id", String.valueOf(userDto.getId()));
                        return exchange;
                    }).flatMap(chain::filter);
        };
    }

On successful auth, it works like a charm. But i want to get the response from my userservice if anything goes wrong.

I havent worked with webclient before... its driving me crazy.

Edit: I also tried to get the response before to test it, unsuccessful. I used a Dto which should reflect the Error Response from my userservice.

     var test = webClientBuilder.build()
                    .post()
                    .uri("http://USER-SERVICE/user/validateToken?token=" + parts[1])
                    .retrieve()
                    .bodyToMono(ApiExceptionDto.class);

            var y = test.subscribe(p -> {
                System.out.println(p.getMessage());
            });

I just get a

reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.web.reactive.function.client.WebClientResponseException$NotFound: 404 Not Found from POST http://192.168.0.69:9001/user/validateToken?token=xx
Caused by: org.springframework.web.reactive.function.client.WebClientResponseException$NotFound: 404 Not Found from POST http://192.168.0.69:9001/user/validateToken?token=xx
    at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:202) ~[spring-webflux-5.3.9.jar:5.3.9]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ 404 from POST http://USER-SERVICE/user/validateToken?token=xx [DefaultWebClient]

The Expected Response: (Postman)

POST : http://192.168.0.69:9001/user/validateToken?token=xx
{
    "message": "The token was expected to have 3 parts, but got 1.",
    "status": "NOT_FOUND",
    "time": "Wed, 18 Aug 2021 01:05:21 GMT",
    "path": "/user/validateToken"
}


Solution 1:[1]

I'll found a better solution, which will be more accurate:

@Override
public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {

        String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");

        String[] parts = authHeader.split(" ");

        return webClientBuilder.build()
                .post()
                .uri("http://USER-SERVICE/user/validateToken?token=" + parts[1])
                .retrieve()
                .bodyToMono(UserDto.class)
                .onErrorResume(e -> Mono.just(new RuntimeException())
                .map(userDto -> {
                    exchange.getRequest()
                            .mutate()
                            .header("X-auth-user-id", String.valueOf(userDto.getId()));
                    return exchange;
                }).flatMap(chain::filter);
    };
}

It's after bodyToMono() and before map(). In onErrorResume() you will throw a new exception, if your downstream service will report any error (code >= 300). If you subclass RuntimeException and annotate it with HttpStatus.UNAUTHORIZED your client will receive the correct status and can react to it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mars3142