A Guide to RestClient in Spring Boot

Last Updated : 1 Nov, 2025

In Spring Boot applications, communication with external services through REST APIs is common. Traditionally, this was achieved using RestTemplate, but it is now deprecated as of Spring Framework 6.1 and Spring Boot 3.2. The new RestClient API has been introduced as its modern, fluent, and flexible alternative for making HTTP requests.

What is RestClient?

RestClient is a modern HTTP client introduced in Spring Framework 6.1. It provides a fluent, builder-based API for sending synchronous and asynchronous HTTP requests with cleaner syntax and improved readability. It supports features like request customization, status-based error handling, interceptors, and HTTP/2 communication.

Key Features of RestClient

1. Fluent API Design

The fluent API allows developers to build requests using method chaining, improving code clarity and reducing boilerplate.

Example:

Java
RestClient restClient = RestClient.builder().build();

String response = restClient.get()
                            .uri("https://api.example.com/resource")
                            .retrieve()
                            .body(String.class);

Explanation:

  • get(): defines the HTTP method.
  • uri(): specifies the target URL.
  • retrieve(): executes the request.
  • body(String.class): extracts the response as a String.

2. Synchronous and Asynchronous Requests

Synchronous Example:

Java
String response = restClient.get()
                            .uri("https://api.example.com/data")
                            .retrieve()
                            .body(String.class);

This blocks the thread until a response is received.

Asynchronous Example:

RestClient integrates with reactive and asynchronous types like CompletableFuture or Mono.

Java
import java.util.concurrent.CompletableFuture;

public CompletableFuture<String> getAsyncResponse(String url) {
    return CompletableFuture.supplyAsync(() -> 
        restClient.get()
                  .uri(url)
                  .retrieve()
                  .body(String.class)
    );
}

3. Error and Status Code Handling

RestClient provides built-in support for handling errors based on HTTP status codes using the onStatus() method.

Example:

Java
import org.springframework.http.HttpStatus;
import reactor.core.publisher.Mono;

String response = restClient.get()
                            .uri("https://api.example.com/resource")
                            .retrieve()
                            .onStatus(HttpStatus::is4xxClientError, res ->
                                Mono.error(new RuntimeException("Client error")))
                            .onStatus(HttpStatus::is5xxServerError, res ->
                                Mono.error(new RuntimeException("Server error")))
                            .body(String.class);

Explanation:

  • onStatus() handles responses based on HTTP status codes.
  • HttpStatus::is4xxClientError handles client-side errors.
  • HttpStatus::is5xxServerError handles server-side errors.

4. Request Customization

Developers can add headers, query parameters, and path variables directly through the fluent builder methods.

Java
String response = restClient.get()
                            .uri("https://api.example.com/users/{id}", 101)
                            .header("Authorization", "Bearer token123")
                            .queryParam("active", true)
                            .retrieve()
                            .body(String.class);

Explanation:

  • header(): adds custom HTTP headers.
  • queryParam(): appends query parameters.
  • {id}: path variable replaced dynamically.

5. Sending and Receiving Request Bodies

For methods like POST or PUT, RestClient supports serializing Java objects to JSON automatically (using Jackson).

Example – Sending JSON Request:

Java
User user = new User("John", "Doe");

String response = restClient.post()
                            .uri("https://api.example.com/users")
                            .body(user)
                            .retrieve()
                            .body(String.class);

Example – Receiving as Object:

Java
User responseUser = restClient.get()
                              .uri("https://api.example.com/users/101")
                              .retrieve()
                              .body(User.class);

6. Configuring the Timeout

You can configure connection or read timeouts by customizing the underlying Java HttpClient.

Java
import java.net.http.HttpClient;
import java.time.Duration;

HttpClient httpClient = HttpClient.newBuilder()
                                  .connectTimeout(Duration.ofSeconds(5))
                                  .build();

RestClient restClient = RestClient.builder()
                                  .httpClient(httpClient)
                                  .build();

This configuration ensures that requests fail gracefully if the connection cannot be established within 5 seconds.

7. Interceptors and Filters

Interceptors can modify requests or responses, ideal for logging or authentication.

Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;

@Configuration
public class RestClientConfig {
    @Bean
    public RestClient restClient(RestClient.Builder builder) {
        return builder.interceptor((request, next) -> {
            System.out.println("Request URI: " + request.getUri());
            return next.exchange(request);
        }).build();
    }
}

This interceptor logs the URI before sending the request.

8. Built-in Support for the HTTP/2

RestClient supports HTTP/2 when used with HttpClient from Java 11+.

Java
HttpClient httpClient = HttpClient.newBuilder()
                                  .version(HttpClient.Version.HTTP_2)
                                  .build();

RestClient restClient = RestClient.builder()
                                  .httpClient(httpClient)
                                  .build();

HTTP/2 improves communication speed and efficiency in distributed systems.

Setting up RestClient in Spring Boot

To use RestClient, you need Spring Boot 3.2 or later. Add the following Maven dependency.

XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Ensure your Spring Boot version is 3.2 or higher, as RestClient is part of Spring Framework 6.1+.

Creating a RestClient Bean

There are two ways to create and configure a RestClient instance in a Spring Boot application.

Define it inside a @Configuration class using RestClientBuilder.

Java
import org.springframework.boot.web.client.RestClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;

@Configuration
public class RestClientConfiguration {

    @Bean
    public RestClient restClient(RestClientBuilder builder) {
        return builder.build();
    }
}

Explanation:

  • This approach allows Spring to manage the RestClient lifecycle.
  • It supports dependency injection and centralized configuration.

2. Manually Creating the RestCleint

You can also create a standalone instance without Spring’s dependency injection.

Java
import org.springframework.web.client.RestClient;

public class ApiService {

    private final RestClient restClient;

    public ApiService() {
        this.restClient = RestClient.builder().build();
    }

    public String getData(String url) {
        return restClient.get()
                         .uri(url)
                         .retrieve()
                         .body(String.class);
    }
}

Explanation:

  • Use this when you need a lightweight or isolated instance.
  • Less flexible for configuration sharing across the application.

Using RestClient in a Service Class

Example – GET Request

Java
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;

@Service
public class ApiService {
    private final RestClient restClient;

    public ApiService(RestClient restClient) {
        this.restClient = restClient;
    }

    public String getApiResponse(String url) {
        return restClient.get()
                         .uri(url)
                         .retrieve()
                         .body(String.class);
    }
}

Example – POST Request

Java
public String sendPostRequest(String url, Object body) {
    return restClient.post()
                     .uri(url)
                     .body(body)
                     .retrieve()
                     .body(String.class);
}
Comment

Explore