0

I am trying to update the token when I get a response with 401 status code.

In order to do that, I used web client. I know that this mainly used to do reactive development but since resttemplate will soon be deprecated I went for this option.

The issue I am facing is that when it does call the api endpoint to get the new token, it throws a 'java.lang.IllegalStateException: block()/blockFirst()/blockLast() '. And make sense as it stated in the exception message It is not supported in thread reactor-http-nio-3.

I saw that there is a map and flatmap option, but I couldn't figure out how to use it inside the doBeforeRetry() to make it process in a different stream.

I need to have that new token before retrying.

So the question is : How can I get the token via another call and then still do the retry ?

I was able to make it work by using a try catch but I would like to find the solution how to use it inside that retry method.

I also try to block the token request by replacing the token response by a Mono and block it by using myMono.toFuture().get() as stated here block()/blockFirst()/blockLast() are blocking error when calling bodyToMono AFTER exchange()

Here is the code :

Method responsible for the call :

public String getValueFromApi(HashMap<String, Object> filter) {
        String response = "";

        response = webclient
                .post()
                .uri(endpoint)
                .header("token", token.getToken())
                .bodyValue(filter)
                .retrieve()
                .bodyToMono(String.class)
                .retryWhen(Retry.max(3).doBeforeRetry(
                        retrySignal -> tokenService.getTokenFromApi(env)
                ).filter(InvalidTokenException.class::isInstance))
                .block();

        return response;
    }

Method that retrieve the token :

public void getTokenFromApi(Environment env) {
        HashMap<String, String> requestBody = new HashMap<>();
        requestBody.put("name", "name");
        requestBody.put("password", "password");

        String response = WebClient
                .builder()
                .baseUrl(BASE_PATH)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
                .build()
                .post()
                .uri(tokenUri)
                .body(BodyInserters.fromValue(requestBody))
                .retrieve()
                .bodyToMono(String.class)
                .block();


        getTokenFromResponse(response);
    }

    private void getTokenFromResponse(String reponse) {
        JsonObject tokenObject = new Gson().fromJson(reponse, JsonObject.class);
        setToken(tokenObject.get("token").getAsString());
    }

WebClient Builder :

 @Bean
    public WebClient webClientForApi(WebClient.Builder webClientBuilder) {
        return webClientBuilder
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .filter(errorHandler())
                .filter(logRequest())
                .clone()
                .baseUrl(BASE_PATH)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader(HttpHeaders.ACCEPT, "application/json")
                .build();
    }

    public ExchangeFilterFunction errorHandler() {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            if (clientResponse.statusCode().equals(HttpStatus.UNAUTHORIZED)) {
                return Mono.error(InvalidTokenException::new);
            } else if (clientResponse.statusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
                return Mono.error(ApiInternalServerException::new);
            } else {
                return Mono.just(clientResponse);
            }
        });
    }

    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            logger.info("Request: {} {}", clientRequest.method(), clientRequest.url());
            clientRequest.headers().forEach((name, values) -> values.forEach(value -> logger.info("{}={}", name, value)));
            return Mono.just(clientRequest);
        });
    }
Gus_2106
  • 11
  • 2

0 Answers0