Spring Boot - using RestTamplate to invoke RESTful Services
RestTemplate is a Spring utility for making REST calls to other services.
Register RestTemplate Bean
To use RestTemplate, you need to define it as a Spring Bean, ideally using the RestTemplateBuilder. This is the currently best way to initialize a RestTemplate as can be seen in this post written by Tim van Baarsen.
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.build();
}
}
For asynchronous and streaming scenarios, consider the reactive WebClient.
We will create our ProductServiceClient:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ProductServiceClient {
@Autowired
private RestTemplate restTemplate;
private final String productServiceBaseUrl = "http://localhost:8080/api/products";
// Get All Products
public String getAllProducts() {
return restTemplate.getForObject(productServiceBaseUrl, String.class);
}
// Get Product by ID
public String getProductById(int id) {
return restTemplate.getForObject(productServiceBaseUrl + "/" + id, String.class);
}
// Create Product
public String createProduct(String product) {
return restTemplate.postForObject(productServiceBaseUrl, product, String.class);
}
// Update Product
public void updateProduct(int id, String updatedProduct) {
restTemplate.put(productServiceBaseUrl + "/" + id, updatedProduct);
}
// Delete Product
public void deleteProduct(int id) {
restTemplate.delete(productServiceBaseUrl + "/" + id);
}
}
This example service centralizes communication with the external product service. It abstracts HTTP calls behind simple method invocations, making it easier for other parts of the application to interact with the product service without dealing with HTTP request details.
- Annotations and Dependencies:
- @Service: Marks this class as a Spring-managed service component.
- @Autowired: Injects a RestTemplate bean, which is used to perform HTTP requests to the product service.
- private final String productServiceBaseUrl: The base URL of the product service API (localhost/api/products).
- Methods:
- getAllProducts():
- Sends a GET request to the base URL to retrieve all products.
- Returns the response as a String.
- getProductById(int id):
- Sends a GET request to fetch a specific product by its ID.
- The URL becomes localhost/api/products/{id}.
- Returns the product details as a String.
- createProduct(String product):
- Sends a POST request to create a new product.
- The product parameter contains the new product's data.
- Returns the response (e.g., confirmation or created product details) as a String.
- updateProduct(int id, String updatedProduct):
- Sends a PUT request to update an existing product.
- The URL includes the product ID (localhost/api/products/{id}).
- No response is returned since RestTemplate.put() has a void return type.
- deleteProduct(int id):
- Sends a DELETE request to remove a product by its ID.
- The URL becomes localhost/api/products/{id}.
- No response is returned, so RestTemplate.delete() also has a void return type.
- getAllProducts():
Using our RestTemplate
We will create a component which implements the CommandLineRunner interface. It runs, similar to the ApplicationRunner, when the application starts and uses the previously defined ProductServiceClient to interact with the product service API. The usage is a somewhat arbitrary, but it serves as an example usage.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements CommandLineRunner {
private final ProductServiceClient productServiceClient;
@Autowired
public AppRunner(ProductServiceClient productServiceClient) {
this.productServiceClient = productServiceClient;
}
@Override
public void run(String... args) throws Exception {
// Create Product
String response = productServiceClient.createProduct("Laptop");
System.out.println(response);
// Get All Products
String products = productServiceClient.getAllProducts();
System.out.println("Products: " + products);
// Update Product
productServiceClient.updateProduct(1, "Updated Laptop");
// Get Product by ID
String product = productServiceClient.getProductById(1);
System.out.println("Product with ID 1: " + product);
// Delete Product
productServiceClient.deleteProduct(1);
System.out.println("Product with ID 1 deleted.");
}
}
Best Practices for REST and RestTemplate
- Use @RestController for REST endpoints and keep controllers lightweight.
- Encapsulate Business Logic in Service Layer.
- Handle Exceptions properly in REST controllers.
- Use Environment Variables for external service URLs (avoid hardcoding them).
- Consider Using WebClient:
- RestTemplate is synchronous. For non-blocking, reactive applications, use WebClient from Spring WebFlux.
