Synchronous REST Communication
BeginnerREST over HTTP is the most common inter-service protocol; use OpenFeign or RestTemplate/WebClient with service discovery to call downstream services.
Overview
Synchronous REST communication is the simplest way for microservices to interact — Service A calls Service B over HTTP and waits for a response. Spring Cloud provides three main clients: RestTemplate (blocking, legacy), WebClient (reactive, non-blocking), and OpenFeign (declarative interface with annotation-driven HTTP clients). Feign is the most expressive for microservices as it integrates naturally with Eureka service discovery, circuit breakers (Resilience4j), and request interceptors for auth token propagation.
OpenFeign Declarative Client
OpenFeign generates an HTTP client implementation from a Java interface. Annotate the interface with @FeignClient pointing to the target service name, then map methods to HTTP endpoints. Spring Cloud auto-integrates Eureka load balancing.
// Enable Feign clients on main class or @Configuration
@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication { ... }
// Feign client interface — maps to product-service
@FeignClient(
name = "product-service", // service name in Eureka
fallback = ProductClientFallback.class // circuit breaker fallback
)
public interface ProductClient {
@GetMapping("/api/products/{id}")
ProductDTO getById(@PathVariable("id") Long id);
@GetMapping("/api/products")
List<ProductDTO> listByCategory(@RequestParam("category") String category);
@PostMapping("/api/products/{id}/reserve")
ReservationDTO reserve(@PathVariable("id") Long id,
@RequestBody ReservationRequest req);
}
// Fallback class
@Component
public class ProductClientFallback implements ProductClient {
@Override
public ProductDTO getById(Long id) {
return ProductDTO.unavailable(id); // degraded response
}
// ... other fallback methods
}WebClient (Reactive)
WebClient is the modern non-blocking HTTP client from Spring WebFlux. Use it in reactive stacks or to avoid thread-blocking. Pair with @LoadBalanced for service-discovery-aware calls.
@Configuration
public class WebClientConfig {
@Bean
@LoadBalanced // enables service-discovery resolution
public WebClient.Builder webClientBuilder() {
return WebClient.builder()
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
}
}
@Service
public class ProductServiceClient {
private final WebClient webClient;
public ProductServiceClient(WebClient.Builder builder) {
this.webClient = builder.baseUrl("http://product-service").build();
}
public Mono<ProductDTO> getProduct(Long id) {
return webClient.get()
.uri("/api/products/{id}", id)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError,
resp -> Mono.error(new ProductNotFoundException(id)))
.bodyToMono(ProductDTO.class)
.timeout(Duration.ofSeconds(5))
.retryWhen(Retry.backoff(3, Duration.ofMillis(200)));
}
public Flux<ProductDTO> getByCategory(String category) {
return webClient.get()
.uri("/api/products?category={c}", category)
.retrieve()
.bodyToFlux(ProductDTO.class);
}
}Error Handling & Timeouts
Always set timeouts on synchronous inter-service calls. Without a timeout, a slow downstream can exhaust the thread pool and cascade failure. Add Resilience4j circuit breaker via @CircuitBreaker on Feign clients or WebClient chains.
# Feign timeout configuration
spring.cloud.openfeign.client.config.default.connect-timeout=2000
spring.cloud.openfeign.client.config.default.read-timeout=5000
# Per-client override (for product-service)
spring.cloud.openfeign.client.config.product-service.read-timeout=3000
# Resilience4j circuit breaker for Feign
spring.cloud.openfeign.circuitbreaker.enabled=true
resilience4j.circuitbreaker.instances.product-service.sliding-window-size=10
resilience4j.circuitbreaker.instances.product-service.failure-rate-threshold=50
resilience4j.circuitbreaker.instances.product-service.wait-duration-in-open-state=10s
// @CircuitBreaker annotation on service method (Resilience4j)
@Service
public class OrderService {
@CircuitBreaker(name = "product-service", fallbackMethod = "getProductFallback")
public ProductDTO getProduct(Long id) {
return productClient.getById(id);
}
public ProductDTO getProductFallback(Long id, Exception ex) {
log.warn("Circuit open for product-service, using cached data");
return productCache.get(id);
}
}Key Points to Remember
- 1OpenFeign generates HTTP client implementations from annotated interfaces — cleanest API for microservices.
- 2WebClient is non-blocking and preferred for reactive stacks or high-concurrency scenarios.
- 3Always set connect and read timeouts on inter-service HTTP calls.
- 4@LoadBalanced on WebClient/RestTemplate enables Eureka-based service discovery routing.
- 5Feign + Resilience4j provides declarative circuit breaking with fallback methods.
- 6Propagate security context (JWT, trace headers) via Feign RequestInterceptor or WebClient ExchangeFilterFunction.
Interview Questions
Sign in to ask AriaWhat is the difference between RestTemplate, WebClient, and OpenFeign?
How does OpenFeign integrate with Eureka for service discovery?
Why is it important to set timeouts on inter-service REST calls?
How does a Feign fallback work with a circuit breaker?
How would you propagate a JWT token across microservice REST calls using Feign?
Ask Aria about Synchronous REST Communication
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.