0
votes

I am unable to get values filled in the map after making a web client call and using the response of the previous Mono.Here is the code I have tried.The value of parameters.size() comes out to zero.Not able to get the reason as to why the value is not filled.I basically want to return age ( and not Mono object) from this method.Using block gives an error block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3.

Map<String, String> parameters = new HashMap<String,String>();
 Mono<Person> obj = webClient
    .post()
    .uri("dummy url")
    .accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)
    .retrieve()
    .bodyToMono(Person.class)
 .flatMap(resp -> {
 parameters.put("name", resp.getName());
 parameters.put("age", resp.getAge());
 return Mono.just(new Person(resp.getName(),resp.getAge()));        
 }

     );

System.out.println(parameters.size());

Please suggest where I am wrong and solution to fix the same.

1
could you provide more context about why you'd need those parameters for? I can explain why this doesn't work but can't give a solution to that without understanding the use case you're trying to solve.Brian Clozel
This is just a dummy example I have used to simulate the real use Case.In general I would need a verification token to be returned from this method which will be used to make future webClient calls using the token returned from this method in the headers.So basically another method calls this method to get the token and use that in future get/post requests.I can get a Mono Object with this call but need to extract token out of it to return it and use ituser3847425

1 Answers

1
votes

Since this is about collecting and using a token of some sort collected from a previous HTTP call, your best bet is to delegate all that to an ExchangeFilterFunction.

An ExchangeFilterFunction is a filter that is executed on the client side for each outgoing request. Here is a very, very naïve implementation of such a filter:

class TokenFilterFunction implements ExchangeFilterFunction {

    private final AtomicReference<String> token = new AtomicReference<>();

    @Override
    public Mono<ClientResponse> filter(ClientRequest req, ExchangeFunction next) {
        if (this.token.get() == null) {
            return fetchToken(next).then(sendRequest(req, next));
        }
        else {
            return sendRequest(req, next);
        }
    }

    private Mono<ClientResponse> sendRequest(ClientRequest req, ExchangeFunction next) {
        ClientRequest request = ClientRequest.from(req)
                .header("Token", this.token.get()).build();
        return next.exchange(request);
    }

    private Mono<Void> fetchToken(ExchangeFunction next) {
        ClientRequest tokenRequest = ClientRequest.create(HttpMethod.GET,
                URI.create("https://example.com/token")).build();
        return next.exchange(tokenRequest).doOnNext(res -> {
            this.token.set(res.headers().header("Token").get(0));
        }).then();
    }
}

This could automatically call the token endpoint to fetch a token when needed and directly chain with the request you asked in the first place. Again, such an implementation should be much more complex than that, handling domains, errors, and more.

If you're using some authentication technology, such a filter might be implemented already in Spring Security in a much, much better way.

You can configure it on your client during the building phase, like:

WebClient webClient = WebClient.builder().filter(new TokenFilterFunction()).build();