Spring RestClient vs RestTemplate

Visarut Sae-Pueng
Ascend Developers
Published in
4 min readApr 9, 2024

--

RestTemplate is the tool that Spring developers have used to communicate with REST APIs. RestClient is now a new option introduced in Spring Framework 6.1. This article will compare and contrast these two HTTP clients to help you choose the one that best fits your project.

It has been designed to be a modern replacement for the older RestTemplate class. Here’s a quick rundown of what RestClient offers.

RestClient

  • Fluent API: Makes code look like natural language by chaining methods together.
  • More concise and readable.
  • Requires Spring Framework 6.1 or above.

RestTemplate

  • Template method API defines a skeleton for operations with specific steps, allowing subclasses to customize the behaviors.
  • You have an existing code heavily reliant on RestTemplate, which requires minimal changes.

RestTemplate and RestClient offer versatile options for building HTTP requests, handling responses, and customizing interactions with external services. Let’s see how to create HTTP requests using RestTemplate and RestClient, focusing on common scenarios such as making GET and POST requests, setting headers, handling errors, and processing responses.

I’ll walk you through practical examples to showcase the similarities and differences between RestTemplate and RestClient. This will help you decide which option best fits your project needs.

Creating a RestTemplate

// Creating a ClientHttpRequestFactory using Apache HttpComponents HttpClient for HTTP requests.
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

// Creating a custom RestTemplate instance using the specified requestFactory.
RestTemplate customTemplate = new RestTemplate(requestFactory);

// Adding an interceptor to the RestTemplate. This interceptor modifies the outgoing request by adding a custom header ("My-Header": "Foo").
customTemplate.getInterceptors().add((request, body, execution) -> {
request.getHeaders().add("My-Header", "Foo"); // Adding custom header to the request
return execution.execute(request, body); // Proceeding with the execution of the request
});

Creating a RestClient

// Building a custom RestClient using RestClient.builder() method
RestClient customClient = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory()) // Setting the request factory to use Apache HttpComponents HttpClient for HTTP requests
.defaultHeader("My-Header", "Foo") // Adding a default header to all requests made by the RestClient
.requestInterceptor(myCustomInterceptor) // Adding a request interceptor to the RestClient to intercept and modify requests
.build(); // Building the RestClient instance

Creating a GET request with RestTemplate

// Sending a GET request using restTemplate
RestTemplate restTemplate = new RestTemplate();

// Set up the headers
HttpHeaders headers = new HttpHeaders();
headers.set("Correlation", correlationId);

// Build the entity with headers
HttpEntity<Void> entity = new HttpEntity<>(headers);

try {
// Perform the GET request with error handling
ResponseEntity<MyResponse> response = restTemplate.exchange(
"https://developers.ascendcorp.com", // Specify the URL to connect to
HttpMethod.GET,
entity,
MyResponse.class);

// Process the successful response
MyResponse myResponse = response.getBody();

} catch (RestClientResponseException e) {
// Check for 4xx errors
if (e.getStatusCode().is4xxClientError()) {
throw new MyCustomRuntimeException(e.getStatusCode(), e.getResponseHeaders());
} else {
// Handle other errors
throw e;
}
}

Creating a GET request with RestClient

// Sending a GET request using customClient RestClient
MyResponse response = customClient.get()
.uri(URI.create("https://developers.ascendcorp.com")) // Specify the URL to connect to
.header("Correlation", correlationId) // Set up a header
.retrieve() // Retrieve the response
.onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { // Set up a status handler for all 4xx status codes
// Throw a custom exception when encountering a 4xx client error
throw new MyCustomRuntimeException(response.statusCode(), response.headers());
})
.body(MyResponse.class); // Convert the JSON response into a MyResponse domain objectdy(MyResponse.class); // Convert the JSON response into a MyResponse domain object

Creating a POST request with RestTemplate

// Creating an HttpEntity containing the request data
HttpEntity<MyRequest> requestEntity = new HttpEntity<>(request);

// Creating HttpHeaders object to hold HTTP headers
HttpHeaders headers = new HttpHeaders();
// Adding custom headers "my-header-a" and "my-header-b" with their respective values
headers.add("my-header-a", headerA);
headers.add("my-header-b", headerB);

// Sending a POST request to "https://developers.ascendcorp.com" with the specified HttpEntity and HttpHeaders,
// and expecting the response to be mapped to MyResponse.class
MyResponse response = restTemplate.postForEntity(
"https://developers.ascendcorp.com",
requestEntity,
MyResponse.class,
headers
).getBody();

Creating a POST request with RestClient

// Sending a POST request using customClient RestClient
MyResponse response = customClient.post()
.uri(URI.create("https://developers.ascendcorp.com")) // Specify the URL to connect to
.body(request) // Set up a request body
.header("my-header-a", headerA) // Set up custom header "my-header-a"
.header("my-header-b", headerB) // Set up custom header "my-header-b"
.retrieve() // Retrieve the response
.toEntity(MyResponse.class) // Convert the response into a ResponseEntity
.getBody(); // Get the body of this entity

RestClient vs RestTemplate Performance?

For most use cases, choosing between RestClient and RestTemplate does not affect the performance. My team has already migrated some of our services to RestClient. There are no differences in the results. Both are synchronous clients, meaning they wait for a response from the server before proceeding. The key factors influencing performance are the underlying HTTP client library, the network conditions, the request complexity, and the caching strategies.

The Spring RestClient has a fluent API but uses blocking I/O. For truly high concurrent scenarios, consider Spring WebClient non-blocking approach for handling multiple requests simultaneously without waiting for each response. This can significantly improve the performance compared to synchronous clients like RestClient and RestTemplate.

Choosing the Right Tool for the Job

RestClient is a powerful addition to Spring HTTP client. Its fluent API and abstraction features make it a solid choice for new projects, especially those targeting Spring Framework 6.1 or above. However, RestTemplate remains a reliable option for existing codebases that don’t require a rewrite. By understanding their strengths and weaknesses, you can make an informed decision about which client best suits your development needs.

--

--