Chapter 12.4☕ 32 min read

Project 4: E-Commerce Microservice System

This is the ultimate capstone. Instead of one JAR, we build a mini E-Commerce system with two microservices: <code>product-service</code> and <code>order-service</code>. This ties together Phase 10 (Eureka, Gateway, Feign, Resilience4j).

01The Concept: Distributed Commerce

The Amazon Hyderabad Warehouses Analogy:

Amazon doesn't keep orders and inventory in the same building.

  1. The Order Warehouse takes the customer's request.
  2. But the Order Warehouse doesn't know the stock. It calls the Inventory Warehouse via phone (Feign Client) to check if the item is available.
  3. If the Inventory Warehouse's phone line is dead (Circuit Breaker), the Order Warehouse stops calling and tells the customer to try later, rather than holding the phone forever.
02Technical Explanation & Tied Concepts
  1. Eureka Server: A discovery server running on port 8761.
  2. API Gateway: A gateway on port 8080 routing traffic to the services.
  3. OpenFeign: order-service uses a Feign Client to call product-service to check stock.
  4. Resilience4j: If product-service is down, the Feign call fails gracefully via a fallback method.
03Full Working Code (The Order Service Flow)

Assume eureka-server and product-service are running and registered in Eureka.

1. The Feign Client (in order-service)

package com.devinhyderabad;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

// 1. Feign will look up PRODUCT-SERVICE in Eureka
@FeignClient(name = "PRODUCT-SERVICE")
public interface ProductClient {

// Calls the endpoint in the product-service
@GetMapping("/api/products/{id}/stock")
Boolean checkStock(@PathVariable Long id);
}

2. The Order Service with Circuit Breaker (OrderService.java)

package com.devinhyderabad;

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

private final ProductClient productClient;

public OrderService(ProductClient productClient) {
this.productClient = productClient;
}

// 1. If this method fails 3 times, the circuit opens
@CircuitBreaker(name = "productServiceCB", fallbackMethod = "handleProductServiceDown")
public String placeOrder(Long productId) {
// 2. Feign calls the Product Microservice
Boolean inStock = productClient.checkStock(productId);

if (inStock) {
return "Order placed successfully!";
} else {
return "Product is out of stock.";
}
}

// 3. Fallback executed if product-service is down or circuit is open
public String handleProductServiceDown(Long productId, Exception e) {
return "Our inventory system is currently unavailable. Please try again later. (Fallback)";
}
}

3. The Order Controller (OrderController.java)

package com.devinhyderabad;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderService orderService;

public OrderController(OrderService orderService) {
this.orderService = orderService;
}

@PostMapping("/{productId}")
public String createOrder(@PathVariable Long productId) {
return orderService.placeOrder(productId);
}
}
04Why It Matters

In a real E-Commerce system, you would never use synchronous Feign calls for the actual payment processing. You would use RabbitMQ or Kafka to ensure the order is processed asynchronously. However, for a quick stock check before placing an order, Feign + Resilience4j is the standard enterprise pattern to ensure a fast, responsive user experience without cascading failures.

05Interview Note

Interview Note: This project demonstrates Polyglot Persistence — product-service could use MongoDB (for flexible product catalogs) while order-service uses PostgreSQL (for strict ACID transactions). The services don't care about each other's databases; they only communicate through REST APIs (Feign). This is the core of microservices architecture.

Key Takeaways

  • ✅ Eureka Server enables dynamic discovery — services find each other without hardcoded IPs
  • ✅ Feign Client makes inter-service HTTP calls look like local Java method invocations
  • ✅ @CircuitBreaker with fallbackMethod prevents cascading failures when a downstream service is down
  • ✅ API Gateway provides a single entry point, centralizing routing, load balancing, and security