skip to content

RestClient (Fluent Sync Client)

RestClient is the current synchronous client, with a fluent builder, retrieve() for the common case and exchange() when you need the raw response. Knowing it replaced RestTemplate is itself a signal that you follow the framework.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is Spring's RestClient and how does its fluent API differ from the older RestTemplate?

level: juniorimportance: must knowfreq 70%

answer

  1. Spring 6.1 / Boot 3.2 fluent sync client
  2. get().uri().retrieve().body(Class)
  3. replaces RestTemplate (maintenance mode)
  4. same ClientHttpRequestFactory + message converters
  5. WebClient ergonomics, no reactor needed

basics

~10 s

RestClient is a synchronous HTTP client (Spring 6.1+) with a modern fluent, chained API — client.get().uri(...).retrieve().body(Type.class). RestTemplate is the older template-method client it's meant to replace for blocking calls.

solid answer

~40 s

RestClient, introduced in Spring Framework 6.1 (Spring Boot 3.2), is a synchronous, blocking HTTP client offering a fluent, chained builder API: you pick a method (get/post), set the uri, headers and body, then call retrieve() and extract the result with body(Class) or toEntity(Class). It replaces RestTemplate for most new blocking code — RestTemplate is now in maintenance mode. RestClient borrows the ergonomic method-chaining style of WebClient but stays fully synchronous, so no reactive/WebFlux dependency is needed. It's created via RestClient.create() or RestClient.builder(), and can even wrap an existing RestTemplate to reuse its configured ClientHttpRequestFactory, message converters and interceptors. Under the hood it uses the same ClientHttpRequestFactory abstraction as RestTemplate.

code

java · 10 lines
java
RestClient restClient = RestClient.builder()
        .baseUrl("https://api.example.com")
        .defaultHeader("Accept", "application/json")
        .build();

// Fluent, synchronous GET
User user = restClient.get()
        .uri("/users/{id}", 42)
        .retrieve()
        .body(User.class);

go deeper

for a junior

Know it's the new fluent synchronous client that replaces RestTemplate; recognize the get().uri().retrieve().body() chain.

for a middle

Explain builder vs create(), baseUrl/default headers, and that it shares message converters and request factory with RestTemplate.

for a senior

Discuss migration strategy, maintenance-mode status of RestTemplate, and choosing RestClient vs WebClient by blocking-vs-reactive need.

for a principal

Frame client selection across the org: standardize on RestClient for servlet stacks, reserve WebClient for reactive/streaming, and centralize request-factory/timeouts/observability in a shared builder bean.

## What RestClient is `RestClient` is a **synchronous** (blocking) HTTP client added in **Spring Framework 6.1** (shipped with **Spring Boot 3.2**). "Synchronous" means each call blocks the calling thread until the HTTP response arrives — there are no `Mono`/`Flux` reactive types involved. It lives in package `org.springframework.web.client` (same package as `RestTemplate`). ## The fluent API "Fluent" means you build a request by **chaining method calls**, each returning the next builder step, ending in a terminal call. A typical call reads top-to-bottom like a sentence: ``` String body = restClient.get() .uri("/users/{id}", 42) .accept(MediaType.APPLICATION_JSON) .retrieve() .body(String.class); ``` Steps: **method** (`get()`, `post()`, `put()`, `delete()`, `patch()`, `head()`, `options()`, or the generic `method(HttpMethod)`) → **`uri(...)`** → optional headers/body → **`retrieve()`** or **`exchange(...)`** → **extraction** (`body(...)`, `toEntity(...)`, `toBodilessEntity()`). ## How it differs from RestTemplate `RestTemplate` (the pre-6.1 blocking client) uses **overloaded template methods** like `getForObject(url, Class, uriVars...)`, `postForEntity(...)`, `exchange(...)`. There are dozens of overloads, and combining custom headers with a body historically meant building a `RequestEntity` or `HttpEntity`. RestClient collapses all of that into one discoverable, chainable API. Key points: - Both are **blocking** and both sit on the **`ClientHttpRequestFactory`** abstraction (so JDK `HttpClient`, Apache HttpComponents, Jetty, Reactor Netty via factories, etc.). - Both share the **`HttpMessageConverter`** infrastructure (Jackson for JSON, etc.). - RestTemplate is now effectively in **maintenance mode**: still supported, no new features expected; RestClient is the recommended replacement for new blocking code. - `WebClient` remains the choice when you actually need **reactive/async** or streaming; RestClient is the synchronous cousin sharing WebClient's fluent ergonomics. ## Creating one ```java RestClient plain = RestClient.create(); // defaults RestClient withBase = RestClient.create("https://api.example.com"); RestClient built = RestClient.builder() .baseUrl("https://api.example.com") .defaultHeader("X-App", "katajob") .build(); RestClient fromTemplate = RestClient.create(existingRestTemplate); // reuse config ``` Builder options include `baseUrl`, `defaultHeader`, `defaultUriVariables`, `requestInterceptor`, `requestFactory`, `messageConverters`, and `defaultStatusHandler`. ## When to use - **New blocking HTTP calls** in a servlet (Spring MVC) app → RestClient. - **Need reactive/non-blocking** → WebClient. - **Existing RestTemplate code** → keep it or migrate incrementally (RestClient can wrap the RestTemplate's config). ## Gotcha RestClient does **not** require the WebFlux/reactive dependency — a common misconception is that its WebClient-like API drags in reactor. It's pure `spring-web`, synchronous.

  • Is RestClient reactive? Does it need spring-webflux?
    No. It's fully synchronous/blocking and lives in spring-web. It borrows WebClient's fluent style but pulls in no reactor/WebFlux dependency.
  • Can you migrate from RestTemplate without rewriting all its configuration?
    Yes — RestClient.create(restTemplate) or RestClient.builder(restTemplate) reuses the RestTemplate's request factory, message converters and interceptors.

saying these in an interview costs you the question

  • Claiming RestClient is asynchronous/reactive or returns Mono/Flux
  • Saying it requires the WebFlux dependency
  • Thinking RestClient and WebClient are the same class
  • Believing RestTemplate was removed/deleted in Spring 6.1

context

open as a page

How do you send a POST request with a JSON body and custom headers using RestClient, and how is the request body serialized?

level: middleimportance: must knowfreq 60%

basics

~10 s

Use restClient.post().uri(...).contentType(MediaType.APPLICATION_JSON).header(...).body(payloadObject).retrieve().body(ResponseType.class). The payload object is serialized to JSON by an HttpMessageConverter (Jackson).

open as a page

What is the difference between retrieve() and exchange() on RestClient, and how does error/status handling differ between them?

level: seniorimportance: must knowfreq 55%

basics

~10 s

retrieve() is the high-level path that auto-throws on 4xx/5xx and lets you extract body/entity; exchange() gives you the raw request+response to inspect status/headers/body yourself and, by default, does NOT throw on error status.

open as a page

How do you configure the underlying transport (connection/read timeouts, connection pooling) for RestClient via ClientHttpRequestFactory?

level: seniorimportance: should knowfreq 45%

basics

~10 s

Set a ClientHttpRequestFactory on the builder: RestClient.builder().requestFactory(factory).build(). Use e.g. JdkClientHttpRequestFactory, HttpComponentsClientHttpRequestFactory, or SimpleClientHttpRequestFactory, and configure connect/read timeouts (and pooling) on that factory.

open as a page

In a Spring MVC (servlet) application, when would you choose RestClient over WebClient, and what are the concurrency/thread implications?

level: principalimportance: should knowfreq 35%

basics

~10 s

In a blocking servlet app, prefer RestClient: it's synchronous, needs no reactive stack, and matches the thread-per-request model. Use WebClient only when you genuinely need non-blocking/async/streaming or high fan-out concurrency.

open as a page