javaspringspring-cloud-gatewaywebflux

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

  • Guess i did it.

    If someone has improvements to offer i would appreciate any input.

    return webClientBuilder.build()
                        .post()
                        .uri("http://USER-SERVICE/user/validateToken?token=" + parts[1])
                        .exchangeToMono(clientResponse -> {
                            if (clientResponse.statusCode().isError()) {
                                return clientResponse.bodyToMono(AuthResponseDto.class);
                            }
                            return clientResponse.bodyToMono(UserDto.class);
                        }).flatMap(dto -> {
                            if (dto.getClass() != UserDto.class) {
                                AuthResponseDto authResponseDto = (AuthResponseDto) dto;
                                // returns the response to from userservice
                                return writeResponse(exchange.getResponse(), ApiExceptionDto.builder()
                                        .message(authResponseDto.getMessage())
                                        .status(authResponseDto.getStatus())
                                        .time(Instant.now())
                                        .path(authResponseDto.getPath())
                                        .build()
                                        .getJsonAsBytes());
                            }
                            return chain.filter(exchange);
                        });