Different Ways to Consume REST APIs in Spring Boot Microservices
In Spring Boot, we can integrate external or internal services mainly using:
Different Ways to Consume REST APIs in Spring Boot Microservices
In Spring Boot, we can integrate external or internal services mainly using:
- REST APIs
- WebClient
- Feign Client
- Messaging queues (Kafka)
1. RestTemplate (Traditional Approach)
RestTemplate is the older synchronous client provided by Spring.
- Blocking call
- Easy to use
- Suitable for simple applications
- Officially in maintenance mode (not preferred for new projects)
Dependency
Usually available with Spring Web dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Example
Performing HTTP GET Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public UserDTO getUser(Integer userId) {
String url = "http://localhost:8081/api/users/{userId}";
UserDTO userDTO = restTemplate.getForObject(url, UserDTO.class, userId);
}
}
Performing HTTP POST Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public String addUser(User user) {
String url = "http://localhost:8081/api/users";
String response = restTemplate.postForObject(url, user, String.class);
}
}
Performing HTTP PUT Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public void updateUser(UserDTO userDTO) {
String url = "http://localhost:8081/api/users/{userId}";
restTemplate.put(url, UserDTO, UserDTO.getUserId());
}
}
Performing HTTP DELETE Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public UserDTO deleteUser(Integer userId) {
String url = "http://localhost:8081/api/users/{userId}";
restTemplate.delete(url, userId);
}
}
RestTemplate Bean Configuration
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Common Methods
- getForObject() -> GET API
- postForObject() -> POST API
- put() -> PUT API
- delete() -> DELETE API
- exchange() -> Custom request
Pros
- Simple and beginner friendly
- Easy implementation
- Good for small projects
Cons
- Blocking/ synchronous
- Lower performance in high traffic systems
- Deprecated for modern reactive applications
2. WebClient (Recommended Modern Approach)
Drawbacks of Rest Template:
- Rest Template is synchronous and blocking, meaning, it waits for the HTTP request to complete before moving on to the next task. This can cause delays because it holds up the execution of other tasks until the current HTTP request finishes.
- Not suitable for non-blocking environments (for example, WebFlux)
WebClient is introduced in Spring WebFlux.
- Non-blocking
- Reactive
- Better performance
- Recommended by Spring
Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
GET API Example
@Service
public class UserService {
private final WebClient webClient;
public UserService(WebClient.Builder builder) {
this.webClient = builder.baseUrl("http://localhost:8081").build();
}
public UserDTO getUser() {
WebClient webClient = WebClient.create();
return webClient.get()
.uri("/api/users/{userId}")
.retrieve()
.bodyToMono(UserDTO.class)
.block();
}
}
Different Ways to Consume REST APIs in Spring Boot Microservices
In Spring Boot, we can integrate external or internal services mainly using:
- REST APIs
- WebClient
- Feign Client
- Messaging queues (Kafka)
1. RestTemplate (Traditional Approach)
RestTemplate is the older synchronous client provided by Spring.
- Blocking call
- Easy to use
- Suitable for simple applications
- Officially in maintenance mode (not preferred for new projects)
Dependency
Usually available with Spring Web dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Example
Performing HTTP GET Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public UserDTO getUser(Integer userId) {
String url = "http://localhost:8081/api/users/{userId}";
UserDTO userDTO = restTemplate.getForObject(url, UserDTO.class, userId);
}
}
Performing HTTP POST Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public String addUser(User user) {
String url = "http://localhost:8081/api/users";
String response = restTemplate.postForObject(url, user, String.class);
}
}
Performing HTTP PUT Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public void updateUser(UserDTO userDTO) {
String url = "http://localhost:8081/api/users/{userId}";
restTemplate.put(url, UserDTO, UserDTO.getUserId());
}
}
Performing HTTP DELETE Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public UserDTO deleteUser(Integer userId) {
String url = "http://localhost:8081/api/users/{userId}";
restTemplate.delete(url, userId);
}
}
RestTemplate Bean Configuration
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Common Methods
- getForObject() -> GET API
- postForObject() -> POST API
- put() -> PUT API
- delete() -> DELETE API
- exchange() -> Custom request
Pros
- Simple and beginner friendly
- Easy implementation
- Good for small projects
Cons
- Blocking/ synchronous
- Lower performance in high traffic systems
- Deprecated for modern reactive applications
2. WebClient (Recommended Modern Approach)
Drawbacks of Rest Template:
- Rest Template is synchronous and blocking, meaning, it waits for the HTTP request to complete before moving on to the next task. This can cause delays because it holds up the execution of other tasks until the current HTTP request finishes.
- Not suitable for non-blocking environments (for example, WebFlux)
WebClient is introduced in Spring WebFlux.
- Non-blocking
- Reactive
- Better performance
- Recommended by Spring
Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
GET API Example
@Service
public class UserService {
private final WebClient webClient;
public UserService(WebClient.Builder builder) {
this.webClient = builder.baseUrl("http://localhost:8081").build();
}
public UserDTO getUser() {
WebClient webClient = WebClient.create();
return webClient.get()
.uri("/api/users/{userId}")
.retrieve()
.bodyToMono(UserDTO.class)
.block();
}
}
POST API Example
public String getUser(User user) {
WebClient webClient = WebClient.create();
return webClient.post()
.uri("/api/users")
.bodyValue(user)
.retrieve()
.bodyToMono(String.class)
.block();
}
Different Ways to Consume REST APIs in Spring Boot Microservices
In Spring Boot, we can integrate external or internal services mainly using:
- REST APIs
- WebClient
- Feign Client
- Messaging queues (Kafka)
1. RestTemplate (Traditional Approach)
RestTemplate is the older synchronous client provided by Spring.
- Blocking call
- Easy to use
- Suitable for simple applications
- Officially in maintenance mode (not preferred for new projects)
Dependency
Usually available with Spring Web dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Example
Performing HTTP GET Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public UserDTO getUser(Integer userId) {
String url = "http://localhost:8081/api/users/{userId}";
UserDTO userDTO = restTemplate.getForObject(url, UserDTO.class, userId);
}
}
Performing HTTP POST Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public String addUser(User user) {
String url = "http://localhost:8081/api/users";
String response = restTemplate.postForObject(url, user, String.class);
}
}
Performing HTTP PUT Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public void updateUser(UserDTO userDTO) {
String url = "http://localhost:8081/api/users/{userId}";
restTemplate.put(url, UserDTO, UserDTO.getUserId());
}
}
Performing HTTP DELETE Request
@Service
public class UserService {
@Autowired
private RestTemplate restTemplate;
public UserDTO deleteUser(Integer userId) {
String url = "http://localhost:8081/api/users/{userId}";
restTemplate.delete(url, userId);
}
}
RestTemplate Bean Configuration
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Common Methods
- getForObject() -> GET API
- postForObject() -> POST API
- put() -> PUT API
- delete() -> DELETE API
- exchange() -> Custom request
Pros
- Simple and beginner friendly
- Easy implementation
- Good for small projects
Cons
- Blocking/ synchronous
- Lower performance in high traffic systems
- Deprecated for modern reactive applications
2. WebClient (Recommended Modern Approach)
Drawbacks of Rest Template:
- Rest Template is synchronous and blocking, meaning, it waits for the HTTP request to complete before moving on to the next task. This can cause delays because it holds up the execution of other tasks until the current HTTP request finishes.
- Not suitable for non-blocking environments (for example, WebFlux)
WebClient is introduced in Spring WebFlux.
- Non-blocking
- Reactive
- Better performance
- Recommended by Spring
Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
GET API Example
@Service
public class UserService {
private final WebClient webClient;
public UserService(WebClient.Builder builder) {
this.webClient = builder.baseUrl("http://localhost:8081").build();
}
public UserDTO getUser() {
WebClient webClient = WebClient.create();
return webClient.get()
.uri("/api/users/{userId}")
.retrieve()
.bodyToMono(UserDTO.class)
.block();
}
}
POST API Example
public String getUser(User user) {
WebClient webClient = WebClient.create();
return webClient.post()
.uri("/api/users")
.bodyValue(user)
.retrieve()
.bodyToMono(String.class)
.block();
}
PUT API Example
public String getUser(UserDTO userDTO) {
WebClient webClient = WebClient.create();
return webClient.put()
.uri("/api/users/{userId}", userDTO.getUserId())
.bodyValue(user)
.retrieve();
}
DELETE API Example
public String getUser(Integer userId) {
WebClient webClient = WebClient.create();
return webClient.delete()
.uri("/api/users/{userId}")
.exchange().subscribe(response -> {
if(response.statusCode().value() == 200){
logger.info("User deleted successfully");
}else {
logger.info("Failed to delete user");
}
})
.retrieve()
.bodyToMono(String.class)
.block();
}
Pros
- Non-blocking
- High performance
- Reactive support
- Better resource utilization
Cons
- Slightly complex
- Reactive programming learning curve
3. OpenFeign Client (Declarative REST Client)
Feign makes REST API calls very clean and developer friendly.
Instead of writing HTTP client code manually, we define interfaces.
Mostly used in microservices architecture.
Dependency
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Enable Feign
@SpringBootApplication
@EnableFeignClients
public class Application {
}
Feign Client Example
@FeignClient(name = "user-service", url = "http://localhost:8081")
public interface UserClient {
@GetMapping("/api/users/1")
String getUser();
}
Service Layer
@Service
public class UserService {
@Autowired
private UserClient userClient;
public String getUser() {
return userClient.getUser();
}
}
Pros
- Very clean code
- Less boilerplate
- Easy integration with Eureka
- Load balancing support
- Best for microservices communication
Cons
- Less control compared to WebClient
- Mostly synchronous
4. Kafka / Event Driven Communication (Asynchronous)
Sometimes microservices should not communicate directly using REST.
Instead, they communicate asynchronously using Kafka.
Example:
- Order Service publishes event
- Payment Service consumes event
- Notification Service sends email
This improves:
- Scalability
- Decoupling
- Reliability
Kafka Producer Example
@Service
public class KafkaProducerService {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String message) {
kafkaTemplate.send("order-topic", message);
}
}
Kafka Consumer Example
@Service
public class KafkaConsumerService {
@KafkaListener(topics = "order-topic", groupId = "group-1")
public void consume(String message) {
System.out.println("Message received: " + message);
}
}
Pros
- Asynchronous communication
- Highly scalable
- Better fault tolerance
- Loose coupling
Cons
- More setup required
- Debugging complexity
- Eventual consistency challenges
Real-Time Industry Usage
Common Enterprise Architecture
- WebClient → External APIs / reactive systems
- Feign → Service-to-service communication
- Kafka → Async event processing
Example:
Order Service
↓
Payment Service (Feign)
Order Service
↓
Kafka Event
↓
Notification Service
Conclusion
Spring Boot provides multiple ways to consume REST APIs:
RestTemplate→ Simple but oldWebClient→ Modern and reactiveOpenFeign→ Best for clean microservice communicationKafka→ Best for asynchronous communication
In modern microservices:
- Prefer
Feignfor internal communication - Prefer
WebClientfor external APIs/reactive systems - Use
Kafkafor event-driven architecture
메타데이터
- post_id
- e28c2b6bdf8b
- slug
- different-ways-to-consume-rest-apis-in-spring-boot-microservices-e28c2b6bdf8b
- url
- https://medium.com/@vandanavaishnav333/different-ways-to-consume-rest-apis-in-spring-boot-microservices-e28c2b6bdf8b
- canonical_url
- https://medium.com/@vandanavaishnav333/different-ways-to-consume-rest-apis-in-spring-boot-microservices-e28c2b6bdf8b
- author_url
- https://medium.com/@vandanavaishnav333
- status
- ok
- fetched_at
- 2026-06-09 15:37:30