Skip to content

12.4.1 GETting resources

As an example of WebClient usage, suppose that you need to fetch an Ingredient object by its ID from the Taco Cloud API. Using RestTemplate, you might use the getForObject() method. But with WebClient, you build the request, retrieve a response, and then extract a Mono that publishes the Ingredient object, as shown here:

java
Mono<Ingredient> ingredient = WebClient.create()
  .get()
  .uri("http://localhost:8080/ingredients/{id}", ingredientId)
  .retrieve()
  .bodyToMono(Ingredient.class);
  
ingredient.subscribe(i -> { ... });

Here you create a new WebClient instance with create(). Then you use get() and uri() to define a GET request to http://localhost:8080/ingredients/{id}, where the {id} placeholder will be replaced by the value in ingredientId. The retrieve() method executes the request. Finally, a call to bodyToMono() extracts the response’s body payload into a Mono<Ingredient> on which you can continue applying additional Mono operations.

To apply additional operations on the Mono returned from bodyToMono(), it’s important to subscribe to it before the request will even be sent. Making requests that can return a collection of values is easy. For example, the following snippet of code fetches all ingredients:

java
Flux<Ingredient> ingredients = WebClient.create()
  .get()
  .uri("http://localhost:8080/ingredients")
  .retrieve()
  .bodyToFlux(Ingredient.class);
ingredients.subscribe(i -> { ... });

For the most part, fetching multiple items is the same as making a request for a single item. The big difference is that instead of using bodyToMono() to extract the response’s body into a Mono, you use bodyToFlux() to extract it into a Flux.

As with bodyToMono(), the Flux returned from bodyToFlux() hasn’t yet been subscribed to. This allows additional operations (filters, maps, and so forth) to be applied to the Flux before the data starts flowing through it. Therefore, it’s important to subscribe to the resulting Flux, or else the request will never even be sent.

MAKING REQUESTS WITH A BASE URI

You may find yourself using a common base URI for many different requests. In that case, it can be useful to create a WebClient bean with a base URI and inject it anywhere it’s needed. Such a bean could be declared like this (in any @Configurationannotated class):

java
@Bean
public WebClient webClient() {
  return WebClient.create("http://localhost:8080");
}

Then, anywhere you need to make requests using that base URI, the WebClient bean can be injected and used like this:

java
@Autowired
WebClient webClient;
public Mono<Ingredient> getIngredientById(String ingredientId) {
  Mono<Ingredient> ingredient = webClient
    .get()
    .uri("/ingredients/{id}", ingredientId)
    .retrieve()
    .bodyToMono(Ingredient.class);

  ingredient.subscribe(i -> { ... });
}

Because the WebClient had already been created, you’re able to get right to work by calling get(). As for the URI, you need to specify only the path relative to the base URI when calling uri().

TIMING OUT ON LONG-RUNNING REQUESTS

One thing that you can count on is that networks aren’t always reliable or as fast as you’d expect them to be. Or maybe a remote server is sluggish in handling a request. Ideally, a request to a remote service will return in a reasonable amount of time. But if not, it would be great if the client didn’t get stuck waiting on a response for too long.

To avoid having your client requests held up by a sluggish network or service, you can use the timeout() method from Flux or Mono to put a limit on how long you’ll wait for data to be published. As an example, consider how you might use timeout() when fetching ingredient data, as shown in the next code sample:

java
Flux<Ingredient> ingredients = webclient
  .get()
  .uri("/ingredients")
  .retrieve()
  .bodyToFlux(Ingredient.class);

ingredients
  .timeout(Duration.ofSeconds(1))
  .subscribe(
    i -> { ... },
    e -> {
    //handle timeout error
  });

As you can see, before subscribing to the Flux, you called timeout(), specifying a duration of 1 second. If the request can be fulfilled in less than 1 second, then there’s no problem. But if the request is taking longer than 1 second, it’ll time-out, and the error handler given as the second parameter to subscribe() is invoked。

Released under the MIT License.