HTTP Clients — RestClient & WebClient

Overview

Three HTTP clients ship with Spring. RestTemplate is in maintenance mode. RestClient (Spring 6.1+) replaces it for blocking code. WebClient is the reactive option.

Official: RestClient, WebClient.


Table of contents

  1. Which client to pick
  2. RestClient (blocking)
  3. WebClient (reactive)
  4. RestTemplate (legacy)
  5. Timeouts and pooling
  6. Retries & circuit breakers
  7. Interview questions
  8. Summary

1. Which client to pick

Client Style Use when
RestClient Blocking, fluent New blocking code in Spring MVC
WebClient Reactive WebFlux stack or you need non-blocking I/O
RestTemplate Blocking, legacy Existing code only — don’t pick for new work

2. RestClient (blocking)

@Bean
RestClient ordersClient(RestClient.Builder builder) {
    return builder
        .baseUrl("https://api.example.com")
        .defaultHeader("Authorization", "Bearer " + token)
        .build();
}

Order order = restClient.get()
    .uri("/orders/{id}", 42)
    .retrieve()
    .body(Order.class);

Fluent and synchronous. Backed by Java’s HttpClient or Apache HttpComponents.


3. WebClient (reactive)

Mono<Order> order = webClient.get()
    .uri("/orders/{id}", 42)
    .retrieve()
    .bodyToMono(Order.class);

Non-blocking. Needs Reactor on the classpath. Fits the WebFlux stack but can be used from Spring MVC too — just don’t .block() casually.


4. RestTemplate (legacy)

Still in the codebase everywhere. No active development — migrate to RestClient for new blocking code.


5. Timeouts and pooling

The single most common production bug: no read timeout → one slow upstream hangs your threads forever.

Always set:

  • Connect timeout — how long to wait for the TCP/TLS handshake.
  • Read/response timeout — how long to wait for the response.
  • Connection pool size — match expected concurrency.
HttpClient httpClient = HttpClient.newBuilder()
    .connectTimeout(Duration.ofSeconds(2))
    .build();

RestClient client = RestClient.builder()
    .requestFactory(new JdkClientHttpRequestFactory(httpClient))
    .build();

6. Retries & circuit breakers

Use Resilience4j (or Spring Cloud Circuit Breaker) for:

  • Retry with exponential backoff + jitter — only on idempotent operations (GET, PUT). Retrying a POST without idempotency keys can charge a card twice.
  • Circuit breaker — stop calling a failing dependency to give it time to recover.

7. Interview questions

Q: RestClient vs WebClient? A: RestClient is blocking and synchronous. WebClient is reactive and non-blocking. Pick based on your stack and concurrency model.

Q: Why avoid RestTemplate in new code? A: It’s in maintenance mode — no new features. Use RestClient for blocking work.

Q: What timeouts must you set on outbound HTTP? A: Connect, read/response, and pool max. Default infinite read timeout is the most common production landmine.

Q: When is retrying safe? A: When the operation is idempotent. Use idempotency keys for unsafe verbs like POST.


8. Summary

Client Model
RestClient Blocking, modern
WebClient Reactive
RestTemplate Legacy
Always set Connect + read timeouts

Next steps


Happy Learning

Next: Boot 3 — Jakarta, Virtual Threads & Native