RestClient in Spring 6 introduces a synchronous HTTP client with a modern, fluent API. This new client provides a convenient way to convert between Java objects and HTTP requests/responses, offering an abstraction over various HTTP libraries. In this guide, we’ll explore how to create and use RestClient with simple, easy-to-understand examples.
Adding Dependencies
To get started with RestClient
, you need to add the spring-boot-starter-web
dependency to your pom.xml
file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Gradle
For a Gradle-based project, include the following dependency in your build.gradle
file:
implementation 'org.springframework.boot:spring-boot-starter-web'
Configuring RestClient as a Spring Bean
To use RestClient
effectively in your Spring application, it is recommended to define it as a Spring bean. This allows you to inject it into your services or controllers easily.
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() {
return RestClient.builder().build();
}
}
Using the RestClient
To make an HTTP request with RestClient
, start by specifying the HTTP method. This can be done using method(HttpMethod)
or convenience methods like get()
, post()
, etc.
1. GET Request Example
First, let’s see how to perform a simple GET request.
Example: GET Request
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class ApiService {
@Autowired
private RestClient restClient;
public String fetchData() {
String response = restClient.get()
.uri("https://api.example.com/data")
.retrieve()
.body(String.class);
System.out.println(response);
return response;
}
}
In this example, we create a RestClient
bean and inject it into our ApiService
. We then use it to make a GET request to fetch data from https://api.example.com/data
.
2. POST Request Example
Next, let’s see how to perform a POST request with a request body.
Example: POST Request
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import java.util.Map;
@Service
public class OrderService {
@Autowired
private RestClient restClient;
public ResponseEntity<Void> createOrder(Map<String, String> order) {
return restClient.post()
.uri("https://api.example.com/orders")
.contentType(MediaType.APPLICATION_JSON)
.body(order)
.retrieve()
.toBodilessEntity();
}
}
In this example, we send a POST request to create a new order. The order data is passed as a Map<String, String>
and converted to JSON automatically.
3. PUT Request Example
Let’s see how to perform a PUT request with a request body.
Example: PUT Request
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import java.util.Map;
@Service
public class UpdateService {
@Autowired
private RestClient restClient;
public ResponseEntity<Void> updateResource(int resourceId, Map<String, Object> updatedData) {
return restClient.put()
.uri("https://api.example.com/resources/{id}", resourceId)
.contentType(MediaType.APPLICATION_JSON)
.body(updatedData)
.retrieve()
.toBodilessEntity();
}
}
In this example, we send a PUT request to update a resource identified by resourceId
. The updated data is passed as a Map<String, Object>
and converted to JSON automatically.
4. DELETE Request Example
Now, let’s see how to perform a DELETE request.
Example: DELETE Request
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class DeleteService {
@Autowired
private RestClient restClient;
public ResponseEntity<Void> deleteResource(int resourceId) {
return restClient.delete()
.uri("https://api.example.com/resources/{id}", resourceId)
.retrieve()
.toBodilessEntity();
}
}
In this example, we send a DELETE request to delete a resource identified by resourceId
.
Handling Responses
You can access the HTTP response status code, headers, and body using ResponseEntity
.
Example: Accessing ResponseEntity
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class UserService {
@Autowired
private RestClient restClient;
public void getUserDetails() {
ResponseEntity<String> responseEntity = restClient.get()
.uri("https://api.example.com/users/1")
.retrieve()
.toEntity(String.class);
System.out.println("Status code: " + responseEntity.getStatusCode());
System.out.println("Headers: " + responseEntity.getHeaders());
System.out.println("Body: " + responseEntity.getBody());
}
}
RestClient in Spring 6: Error Handling
By default, RestClient
throws a subclass of RestClientException
for responses with 4xx or 5xx status codes. You can customize this behavior using onStatus
.
Example: Custom Error Handling
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import org.springframework.web.client.RestClientException;
@Service
public class ErrorHandlingService {
@Autowired
private RestClient restClient;
public String fetchDataWithErrorHandling() {
try {
return restClient.get()
.uri("https://api.example.com/nonexistent")
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, response -> {
throw new CustomClientException("Client error: " + response.getStatusCode());
})
.body(String.class);
} catch (RestClientException e) {
e.printStackTrace();
return "An error occurred";
}
}
}
Advanced Scenarios with Exchange
For advanced scenarios, RestClient
provides access to the underlying HTTP request and response through the exchange()
method. Status handlers are not applied when using exchange()
, allowing for custom error handling.
Example: Advanced GET Request
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@Service
public class AdvancedService {
@Autowired
private RestClient restClient;
public Map<String, Object> getUser(int id) {
return restClient.get()
.uri("https://api.example.com/users/{id}", id)
.accept(MediaType.APPLICATION_JSON)
.exchange((request, response) -> {
if (response.getStatusCode().is4xxClientError()) {
throw new CustomClientException("Client error: " + response.getStatusCode());
} else {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(response.getBody(), new TypeReference<Map<String, Object>>() {});
}
});
}
}
Choosing Between RestTemplate vs RestClient vs WebClient
1. RestTemplate
- Use Case:
- Traditional Synchronous Applications: Use
RestTemplate
if you are working in a traditional Spring MVC application where synchronous HTTP calls suffice. - Simple CRUD Operations: For straightforward HTTP interactions such as fetching data from RESTful services using blocking calls.
- Traditional Synchronous Applications: Use
- Key Features:
- Template-based API (
getForObject
,postForObject
, etc.). - Synchronous blocking calls.
- Well-established, widely used in existing Spring applications.
- Template-based API (
- Example Scenario:
- Integrating with legacy systems or existing codebases using synchronous HTTP communication.
2. RestClient
- Use Case:
- Modern Synchronous Applications: Choose
RestClient
for applications requiring more flexibility and control over HTTP requests and responses. - Enhanced Error Handling: When you need to handle specific HTTP status codes or exceptions with
onStatus
.
- Modern Synchronous Applications: Choose
- Key Features:
- Fluent API (
get
,post
,put
,delete
) with method chaining. - Built-in support for content negotiation and message converters.
- Configurable request and response handling.
- Fluent API (
- Example Scenario:
- Building new applications in Spring Framework 6 that benefit from a modern, flexible synchronous HTTP client.
- Customizing HTTP headers, request bodies, and error handling mechanisms.
3. WebClient
- Use Case:
- Reactive and Non-blocking Applications: Opt for
WebClient
in reactive applications leveraging Spring WebFlux. - High-Concurrency: When handling high volumes of requests concurrently with asynchronous processing.
- Reactive and Non-blocking Applications: Opt for
- Key Features:
- Non-blocking and reactive API.
- Functional style with operators like
flatMap
,map
, etc., for composing requests and handling responses. - Supports both synchronous (blocking) and asynchronous (reactive) modes.
- Example Scenario:
- Developing microservices architectures or event-driven systems where responsiveness and scalability are critical.
- Implementing real-time data streaming or processing pipelines using reactive programming principles.
Conclusion
RestClient
in Spring Framework 6.1 offers a modern, fluent API for interacting with RESTful services. Its flexibility and ease of use make it a powerful tool for any Spring developer. Whether making simple GET requests or handling complex scenarios, RestClient
provides the capabilities you need for efficient and effective HTTP communication.
By following this guide, you should now be well-equipped to use RestClient
in your Spring applications, making your development process smoother and more efficient.
Related Articles
- What is Spring Boot and Its Features
- Spring Boot Starter
- Spring Boot Packaging
- Spring Boot Custom Banner
- 5 Ways to Run Spring Boot Application
- @ConfigurationProperties Example: 5 Proven Steps to Optimize
- Mastering Spring Boot Events: 5 Best Practices
- Spring Boot Profiles Mastery: 5 Proven Tips
- CommandLineRunners vs ApplicationRunners
- Spring Boot Actuator: 5 Performance Boost Tips
- Spring Boot API Gateway Tutorial
- Apache Kafka Tutorial
- Spring Boot MongoDB CRUD Application Example
- ChatGPT Integration with Spring Boot
Stay Updated!
Subscribe to our newsletter for more insightful articles on Spring Boot and Java development. Stay informed about the latest trends and best practices directly in your inbox.