├── .gitignore ├── notification-service ├── target │ └── classes │ │ ├── com │ │ └── programming │ │ │ └── techie │ │ │ ├── OrderPlacedEvent.class │ │ │ └── NotificationServiceApplication.class │ │ └── application.properties ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── programming │ │ │ └── techie │ │ │ ├── OrderPlacedEvent.java │ │ │ └── NotificationServiceApplication.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── order-service ├── target │ ├── classes │ │ ├── com │ │ │ └── programmingtechie │ │ │ │ └── orderservice │ │ │ │ ├── model │ │ │ │ ├── Order.class │ │ │ │ └── OrderLineItems.class │ │ │ │ ├── dto │ │ │ │ ├── OrderRequest.class │ │ │ │ ├── InventoryResponse.class │ │ │ │ ├── OrderLineItemsDto.class │ │ │ │ └── InventoryResponse$InventoryResponseBuilder.class │ │ │ │ ├── service │ │ │ │ └── OrderService.class │ │ │ │ ├── OrderServiceApplication.class │ │ │ │ ├── config │ │ │ │ └── WebClientConfig.class │ │ │ │ ├── event │ │ │ │ └── OrderPlacedEvent.class │ │ │ │ ├── controller │ │ │ │ └── OrderController.class │ │ │ │ └── repository │ │ │ │ └── OrderRepository.class │ │ └── application.properties │ └── test-classes │ │ └── com │ │ └── programmingtechie │ │ └── orderservice │ │ └── OrderServiceApplicationTests.class ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── programmingtechie │ │ │ │ └── orderservice │ │ │ │ ├── repository │ │ │ │ └── OrderRepository.java │ │ │ │ ├── event │ │ │ │ └── OrderPlacedEvent.java │ │ │ │ ├── dto │ │ │ │ ├── OrderRequest.java │ │ │ │ ├── InventoryResponse.java │ │ │ │ └── OrderLineItemsDto.java │ │ │ │ ├── OrderServiceApplication.java │ │ │ │ ├── config │ │ │ │ └── WebClientConfig.java │ │ │ │ ├── model │ │ │ │ ├── OrderLineItems.java │ │ │ │ └── Order.java │ │ │ │ ├── controller │ │ │ │ └── OrderController.java │ │ │ │ └── service │ │ │ │ └── OrderService.java │ │ └── resources │ │ │ └── application.properties │ └── test │ │ └── java │ │ └── com │ │ └── programmingtechie │ │ └── orderservice │ │ └── OrderServiceApplicationTests.java └── pom.xml ├── api-gateway ├── target │ └── classes │ │ ├── com │ │ └── programming │ │ │ └── techie │ │ │ └── apigateway │ │ │ └── ApiGatewayApplication.class │ │ └── application.properties ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── programming │ │ │ └── techie │ │ │ └── apigateway │ │ │ └── ApiGatewayApplication.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── product-service ├── target │ ├── classes │ │ ├── com │ │ │ └── programmingtechie │ │ │ │ └── productservice │ │ │ │ ├── model │ │ │ │ ├── Product.class │ │ │ │ └── Product$ProductBuilder.class │ │ │ │ ├── dto │ │ │ │ ├── ProductRequest.class │ │ │ │ ├── ProductResponse.class │ │ │ │ ├── ProductRequest$ProductRequestBuilder.class │ │ │ │ └── ProductResponse$ProductResponseBuilder.class │ │ │ │ ├── service │ │ │ │ └── ProductService.class │ │ │ │ ├── ProductServiceApplication.class │ │ │ │ ├── controller │ │ │ │ └── ProductController.class │ │ │ │ └── repository │ │ │ │ └── ProductRepository.class │ │ └── application.properties │ └── test-classes │ │ └── com │ │ └── programmingtechie │ │ └── productservice │ │ └── ProductServiceApplicationTests.class ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── programmingtechie │ │ │ │ └── productservice │ │ │ │ ├── repository │ │ │ │ └── ProductRepository.java │ │ │ │ ├── dto │ │ │ │ ├── ProductRequest.java │ │ │ │ └── ProductResponse.java │ │ │ │ ├── ProductServiceApplication.java │ │ │ │ ├── model │ │ │ │ └── Product.java │ │ │ │ ├── controller │ │ │ │ └── ProductController.java │ │ │ │ └── service │ │ │ │ └── ProductService.java │ │ └── resources │ │ │ └── application.properties │ └── test │ │ └── java │ │ └── com │ │ └── programmingtechie │ │ └── productservice │ │ └── ProductServiceApplicationTests.java └── pom.xml ├── inventory-service ├── target │ ├── classes │ │ ├── com │ │ │ └── programmingtechie │ │ │ │ └── inventoryservice │ │ │ │ ├── model │ │ │ │ └── Inventory.class │ │ │ │ ├── dto │ │ │ │ ├── InventoryResponse.class │ │ │ │ └── InventoryResponse$InventoryResponseBuilder.class │ │ │ │ ├── service │ │ │ │ └── InventoryService.class │ │ │ │ ├── InventoryServiceApplication.class │ │ │ │ ├── controller │ │ │ │ └── InventoryController.class │ │ │ │ └── repository │ │ │ │ └── InventoryRepository.class │ │ └── application.properties │ └── test-classes │ │ └── com │ │ └── programmingtechie │ │ └── inventoryservice │ │ └── InventoryServiceApplicationTests.class ├── src │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── programmingtechie │ │ │ └── inventoryservice │ │ │ └── InventoryServiceApplicationTests.java │ └── main │ │ ├── java │ │ └── com │ │ │ └── programmingtechie │ │ │ └── inventoryservice │ │ │ ├── dto │ │ │ └── InventoryResponse.java │ │ │ ├── repository │ │ │ └── InventoryRepository.java │ │ │ ├── model │ │ │ └── Inventory.java │ │ │ ├── controller │ │ │ └── InventoryController.java │ │ │ ├── InventoryServiceApplication.java │ │ │ └── service │ │ │ └── InventoryService.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── discovery-server ├── target │ └── classes │ │ ├── com │ │ └── programming │ │ │ └── techie │ │ │ └── discoveryserver │ │ │ └── DiscoveryServerApplication.class │ │ └── application.properties ├── src │ └── main │ │ ├── resources │ │ └── application.properties │ │ └── java │ │ └── com │ │ └── programming │ │ └── techie │ │ └── discoveryserver │ │ └── DiscoveryServerApplication.java └── pom.xml ├── docker-compose.yml ├── README.md └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .metals 2 | .vscode 3 | .idea 4 | 5 | product-service/src/main/resources/.env 6 | product-service/target/classes/.env 7 | -------------------------------------------------------------------------------- /notification-service/target/classes/com/programming/techie/OrderPlacedEvent.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/notification-service/target/classes/com/programming/techie/OrderPlacedEvent.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/model/Order.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/model/Order.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/dto/OrderRequest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/dto/OrderRequest.class -------------------------------------------------------------------------------- /api-gateway/target/classes/com/programming/techie/apigateway/ApiGatewayApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/api-gateway/target/classes/com/programming/techie/apigateway/ApiGatewayApplication.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/model/Product.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/model/Product.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/dto/InventoryResponse.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/dto/InventoryResponse.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/dto/OrderLineItemsDto.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/dto/OrderLineItemsDto.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/model/OrderLineItems.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/model/OrderLineItems.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/service/OrderService.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/service/OrderService.class -------------------------------------------------------------------------------- /inventory-service/target/classes/com/programmingtechie/inventoryservice/model/Inventory.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/classes/com/programmingtechie/inventoryservice/model/Inventory.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/OrderServiceApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/OrderServiceApplication.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/config/WebClientConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/config/WebClientConfig.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/event/OrderPlacedEvent.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/event/OrderPlacedEvent.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/dto/ProductRequest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/dto/ProductRequest.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/dto/ProductResponse.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/dto/ProductResponse.class -------------------------------------------------------------------------------- /notification-service/target/classes/com/programming/techie/NotificationServiceApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/notification-service/target/classes/com/programming/techie/NotificationServiceApplication.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/controller/OrderController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/controller/OrderController.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/repository/OrderRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/repository/OrderRepository.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/service/ProductService.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/service/ProductService.class -------------------------------------------------------------------------------- /inventory-service/target/classes/com/programmingtechie/inventoryservice/dto/InventoryResponse.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/classes/com/programmingtechie/inventoryservice/dto/InventoryResponse.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/ProductServiceApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/ProductServiceApplication.class -------------------------------------------------------------------------------- /discovery-server/target/classes/com/programming/techie/discoveryserver/DiscoveryServerApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/discovery-server/target/classes/com/programming/techie/discoveryserver/DiscoveryServerApplication.class -------------------------------------------------------------------------------- /inventory-service/target/classes/com/programmingtechie/inventoryservice/service/InventoryService.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/classes/com/programmingtechie/inventoryservice/service/InventoryService.class -------------------------------------------------------------------------------- /order-service/target/test-classes/com/programmingtechie/orderservice/OrderServiceApplicationTests.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/test-classes/com/programmingtechie/orderservice/OrderServiceApplicationTests.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/controller/ProductController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/controller/ProductController.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/model/Product$ProductBuilder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/model/Product$ProductBuilder.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/repository/ProductRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/repository/ProductRepository.class -------------------------------------------------------------------------------- /inventory-service/target/classes/com/programmingtechie/inventoryservice/InventoryServiceApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/classes/com/programmingtechie/inventoryservice/InventoryServiceApplication.class -------------------------------------------------------------------------------- /inventory-service/target/classes/com/programmingtechie/inventoryservice/controller/InventoryController.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/classes/com/programmingtechie/inventoryservice/controller/InventoryController.class -------------------------------------------------------------------------------- /inventory-service/target/classes/com/programmingtechie/inventoryservice/repository/InventoryRepository.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/classes/com/programmingtechie/inventoryservice/repository/InventoryRepository.class -------------------------------------------------------------------------------- /product-service/target/test-classes/com/programmingtechie/productservice/ProductServiceApplicationTests.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/test-classes/com/programmingtechie/productservice/ProductServiceApplicationTests.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/dto/ProductRequest$ProductRequestBuilder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/dto/ProductRequest$ProductRequestBuilder.class -------------------------------------------------------------------------------- /inventory-service/target/test-classes/com/programmingtechie/inventoryservice/InventoryServiceApplicationTests.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/test-classes/com/programmingtechie/inventoryservice/InventoryServiceApplicationTests.class -------------------------------------------------------------------------------- /order-service/target/classes/com/programmingtechie/orderservice/dto/InventoryResponse$InventoryResponseBuilder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/order-service/target/classes/com/programmingtechie/orderservice/dto/InventoryResponse$InventoryResponseBuilder.class -------------------------------------------------------------------------------- /product-service/target/classes/com/programmingtechie/productservice/dto/ProductResponse$ProductResponseBuilder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/product-service/target/classes/com/programmingtechie/productservice/dto/ProductResponse$ProductResponseBuilder.class -------------------------------------------------------------------------------- /inventory-service/target/classes/com/programmingtechie/inventoryservice/dto/InventoryResponse$InventoryResponseBuilder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adeniyi-Bella/spring-boot-microservices/HEAD/inventory-service/target/classes/com/programmingtechie/inventoryservice/dto/InventoryResponse$InventoryResponseBuilder.class -------------------------------------------------------------------------------- /notification-service/src/main/java/com/programming/techie/OrderPlacedEvent.java: -------------------------------------------------------------------------------- 1 | package com.programming.techie; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class OrderPlacedEvent { 11 | private String orderNumber; 12 | } -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.repository; 2 | 3 | import com.programmingtechie.orderservice.model.Order; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface OrderRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/event/OrderPlacedEvent.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.event; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class OrderPlacedEvent { 11 | private String orderNumber; 12 | } -------------------------------------------------------------------------------- /order-service/src/test/java/com/programmingtechie/orderservice/OrderServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class OrderServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /product-service/src/main/java/com/programmingtechie/productservice/repository/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice.repository; 2 | 3 | import com.programmingtechie.productservice.model.Product; 4 | import org.springframework.data.mongodb.repository.MongoRepository; 5 | 6 | public interface ProductRepository extends MongoRepository { 7 | } 8 | -------------------------------------------------------------------------------- /inventory-service/src/test/java/com/programmingtechie/inventoryservice/InventoryServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.inventoryservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class InventoryServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /discovery-server/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | eureka.instance.hostname=localhost 2 | # We do not want the discovery server to register itself as a client on eureka 3 | eureka.client.register-with-eureka=false 4 | eureka.client.fetch-registry=false 5 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 6 | server.port=8761 7 | spring.zipkin.base-url=http://localhost:9411 8 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /discovery-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | eureka.instance.hostname=localhost 2 | # We do not want the discovery server to register itself as a client on eureka 3 | eureka.client.register-with-eureka=false 4 | eureka.client.fetch-registry=false 5 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 6 | server.port=8761 7 | spring.zipkin.base-url=http://localhost:9411 8 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/dto/OrderRequest.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class OrderRequest { 13 | private List orderLineItemsDtoList; 14 | } 15 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/dto/InventoryResponse.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class InventoryResponse { 13 | private String skuCode; 14 | private boolean isInStock; 15 | } -------------------------------------------------------------------------------- /product-service/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | spring.data.mongodb.database=${env.MONGO_DATABASE} 2 | spring.data.mongodb.uri=mongodb+srv://${env.MONGO_USER}:${env.MONGO_PASSWORD}@${env.MONGO_CLUSTER} 3 | # name to be used on eureka client 4 | spring.application.name=product-service 5 | # Set to 0 to make random selection as api gateway uses 8080 automatically 6 | server.port=0 7 | 8 | spring.zipkin.base-url=http://localhost:9411 9 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /inventory-service/src/main/java/com/programmingtechie/inventoryservice/dto/InventoryResponse.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.inventoryservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class InventoryResponse { 13 | private String skuCode; 14 | private boolean isInStock; 15 | } 16 | -------------------------------------------------------------------------------- /product-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.data.mongodb.database=${env.MONGO_DATABASE} 2 | spring.data.mongodb.uri=mongodb+srv://${env.MONGO_USER}:${env.MONGO_PASSWORD}@${env.MONGO_CLUSTER} 3 | # name to be used on eureka client 4 | spring.application.name=product-service 5 | # Set to 0 to make random selection as api gateway uses 8080 automatically 6 | server.port=0 7 | 8 | spring.zipkin.base-url=http://localhost:9411 9 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /inventory-service/src/main/java/com/programmingtechie/inventoryservice/repository/InventoryRepository.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.inventoryservice.repository; 2 | 3 | import com.programmingtechie.inventoryservice.model.Inventory; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface InventoryRepository extends JpaRepository { 9 | List findBySkuCodeIn(List skuCode); 10 | } 11 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/dto/OrderLineItemsDto.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.math.BigDecimal; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class OrderLineItemsDto { 13 | private Long id; 14 | private String skuCode; 15 | private BigDecimal price; 16 | private Integer quantity; 17 | } 18 | -------------------------------------------------------------------------------- /product-service/src/main/java/com/programmingtechie/productservice/dto/ProductRequest.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.math.BigDecimal; 9 | 10 | @Data 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class ProductRequest { 15 | private String name; 16 | private String description; 17 | private BigDecimal price; 18 | } 19 | -------------------------------------------------------------------------------- /product-service/src/main/java/com/programmingtechie/productservice/dto/ProductResponse.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.math.BigDecimal; 9 | 10 | @Data 11 | @Builder 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | public class ProductResponse { 15 | private String id; 16 | private String name; 17 | private String description; 18 | private BigDecimal price; 19 | } 20 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/programming/techie/apigateway/ApiGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.programming.techie.apigateway; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaClient 9 | public class ApiGatewayApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(ApiGatewayApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/OrderServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaClient 9 | public class OrderServiceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(OrderServiceApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /inventory-service/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url=jdbc:mysql://localhost:3306/inventory-service 3 | spring.datasource.username=root 4 | spring.datasource.password=password 5 | spring.jpa.hibernate.ddl-auto=create-drop 6 | # run instances on random free ports in your machine 7 | server.port=0 8 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 9 | spring.application.name=inventory-service 10 | spring.zipkin.base-url=http://localhost:9411 11 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /inventory-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url=jdbc:mysql://localhost:3306/inventory-service 3 | spring.datasource.username=root 4 | spring.datasource.password=password 5 | spring.jpa.hibernate.ddl-auto=create-drop 6 | # run instances on random free ports in your machine 7 | server.port=0 8 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 9 | spring.application.name=inventory-service 10 | spring.zipkin.base-url=http://localhost:9411 11 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /product-service/src/main/java/com/programmingtechie/productservice/ProductServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaClient 9 | public class ProductServiceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ProductServiceApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /discovery-server/src/main/java/com/programming/techie/discoveryserver/DiscoveryServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.programming.techie.discoveryserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer //to create discovery server 9 | public class DiscoveryServerApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(DiscoveryServerApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /inventory-service/src/main/java/com/programmingtechie/inventoryservice/model/Inventory.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.inventoryservice.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import javax.persistence.*; 9 | 10 | @Entity 11 | @Table(name = "t_inventory") 12 | @Getter 13 | @Setter 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class Inventory { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | private String skuCode; 22 | private Integer quantity; 23 | } 24 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/config/WebClientConfig.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.reactive.function.client.WebClient; 7 | 8 | @Configuration 9 | public class WebClientConfig { 10 | 11 | @Bean 12 | @LoadBalanced //to be able to select one server if multiple server instances have been instatianted 13 | public WebClient.Builder webClientBuilder() { 14 | return WebClient.builder(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/model/OrderLineItems.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import javax.persistence.*; 9 | import java.math.BigDecimal; 10 | 11 | @Entity 12 | @Table(name = "t_order_line_items") 13 | @Getter 14 | @Setter 15 | @AllArgsConstructor 16 | @NoArgsConstructor 17 | public class OrderLineItems { 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | private String skuCode; 22 | private BigDecimal price; 23 | private Integer quantity; 24 | } 25 | -------------------------------------------------------------------------------- /product-service/src/main/java/com/programmingtechie/productservice/model/Product.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import org.springframework.data.annotation.Id; 8 | import org.springframework.data.mongodb.core.mapping.Document; 9 | 10 | import java.math.BigDecimal; 11 | 12 | @Document(value = "product") 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Builder 16 | @Data 17 | public class Product { 18 | 19 | @Id 20 | private String id; 21 | private String name; 22 | private String description; 23 | private BigDecimal price; 24 | } 25 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/model/Order.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import javax.persistence.*; 9 | import java.util.List; 10 | 11 | @Entity 12 | @Table(name = "t_orders") 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | @AllArgsConstructor 17 | public class Order { 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | private Long id; 21 | private String orderNumber; 22 | @OneToMany(cascade = CascadeType.ALL) 23 | private List orderLineItemsList; 24 | } 25 | -------------------------------------------------------------------------------- /notification-service/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | eureka.client.serviceUrl.defaultZone=http://eureka:password@localhost:8761/eureka 2 | spring.application.name=notification-service 3 | server.port=0 4 | 5 | spring.sleuth.integration.enabled=true 6 | spring.zipkin.base-url=http://localhost:9411/ 7 | spring.sleuth.sampler.probability=1 8 | 9 | # Kafka Properties 10 | spring.kafka.bootstrap-servers=localhost:9092 11 | spring.kafka.template.default-topic=notificationTopic 12 | spring.kafka.consumer.group-id= notificationId 13 | spring.kafka.consumer.key-serializer=org.apache.kafka.common.serialization.StringSerializer 14 | spring.kafka.consumer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer 15 | spring.kafka.consumer.properties.spring.json.trusted.packages=* 16 | spring.kafka.consumer.properties.spring.json.type.mapping=event:com.programming.techie.OrderPlacedEvent -------------------------------------------------------------------------------- /notification-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | eureka.client.serviceUrl.defaultZone=http://eureka:password@localhost:8761/eureka 2 | spring.application.name=notification-service 3 | server.port=0 4 | 5 | spring.sleuth.integration.enabled=true 6 | spring.zipkin.base-url=http://localhost:9411/ 7 | spring.sleuth.sampler.probability=1 8 | 9 | # Kafka Properties 10 | spring.kafka.bootstrap-servers=localhost:9092 11 | spring.kafka.template.default-topic=notificationTopic 12 | spring.kafka.consumer.group-id= notificationId 13 | spring.kafka.consumer.key-serializer=org.apache.kafka.common.serialization.StringSerializer 14 | spring.kafka.consumer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer 15 | spring.kafka.consumer.properties.spring.json.trusted.packages=* 16 | spring.kafka.consumer.properties.spring.json.type.mapping=event:com.programming.techie.OrderPlacedEvent -------------------------------------------------------------------------------- /inventory-service/src/main/java/com/programmingtechie/inventoryservice/controller/InventoryController.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.inventoryservice.controller; 2 | 3 | import com.programmingtechie.inventoryservice.dto.InventoryResponse; 4 | import com.programmingtechie.inventoryservice.service.InventoryService; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | @RequestMapping("/api/inventory") 13 | @RequiredArgsConstructor 14 | public class InventoryController { 15 | 16 | private final InventoryService inventoryService; 17 | 18 | @GetMapping 19 | @ResponseStatus(HttpStatus.OK) 20 | public List isInStock(@RequestParam List skuCode) { 21 | return inventoryService.isInStock(skuCode); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /notification-service/src/main/java/com/programming/techie/NotificationServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.programming.techie; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.kafka.annotation.KafkaListener; 7 | 8 | @SpringBootApplication 9 | @Slf4j 10 | public class NotificationServiceApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(NotificationServiceApplication.class, args); 14 | } 15 | 16 | // name of the topic in order service 17 | // listens to the notification from order service 18 | @KafkaListener(topics = "notificationTopic") 19 | public void handleNotification(OrderPlacedEvent orderPlacedEvent) { 20 | // send out an email notification 21 | log.info("Received Notification for Order - {}", orderPlacedEvent.getOrderNumber()); 22 | } 23 | } -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: '3' 3 | # downloading 2 services. zookeeper and broker 4 | 5 | services: 6 | # to orchestrate kafka clusters 7 | zookeeper: 8 | image: confluentinc/cp-zookeeper:7.3.2 9 | container_name: zookeeper 10 | environment: 11 | ZOOKEEPER_CLIENT_PORT: 2181 12 | ZOOKEEPER_TICK_TIME: 2000 13 | broker: 14 | image: confluentinc/cp-kafka:7.3.2 15 | container_name: broker 16 | ports: 17 | # To learn about configuring Kafka for access across networks see 18 | # https://www.confluent.io/blog/kafka-client-cannot-connect-to-broker-on-aws-on-docker-etc/ 19 | - "9092:9092" 20 | depends_on: 21 | - zookeeper 22 | environment: 23 | KAFKA_BROKER_ID: 1 24 | KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181' 25 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_INTERNAL:PLAINTEXT 26 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092,PLAINTEXT_INTERNAL://broker:29092 27 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 28 | KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 29 | KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 -------------------------------------------------------------------------------- /product-service/src/main/java/com/programmingtechie/productservice/controller/ProductController.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice.controller; 2 | 3 | import com.programmingtechie.productservice.dto.ProductRequest; 4 | import com.programmingtechie.productservice.dto.ProductResponse; 5 | import com.programmingtechie.productservice.service.ProductService; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import java.util.List; 11 | 12 | @RestController 13 | @RequestMapping("/api/product") 14 | @RequiredArgsConstructor 15 | public class ProductController { 16 | 17 | private final ProductService productService; 18 | 19 | @PostMapping 20 | @ResponseStatus(HttpStatus.CREATED) 21 | public void createProduct(@RequestBody ProductRequest productRequest) { 22 | productService.createProduct(productRequest); 23 | } 24 | 25 | @GetMapping 26 | @ResponseStatus(HttpStatus.OK) 27 | public List getAllProducts() { 28 | return productService.getAllProducts(); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /discovery-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | microservices-new 7 | com.programming.techie 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | discovery-server 13 | 14 | 15 | 17 16 | 17 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-starter-netflix-eureka-server 23 | 24 | 25 | org.springframework.cloud 26 | spring-cloud-starter-sleuth 27 | 28 | 29 | org.springframework.cloud 30 | spring-cloud-sleuth-zipkin 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /inventory-service/src/main/java/com/programmingtechie/inventoryservice/InventoryServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.inventoryservice; 2 | 3 | import com.programmingtechie.inventoryservice.model.Inventory; 4 | import com.programmingtechie.inventoryservice.repository.InventoryRepository; 5 | import org.springframework.boot.CommandLineRunner; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @SpringBootApplication 12 | @EnableEurekaClient 13 | public class InventoryServiceApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(InventoryServiceApplication.class, args); 17 | } 18 | 19 | @Bean 20 | public CommandLineRunner loadData(InventoryRepository inventoryRepository) { 21 | return args -> { 22 | Inventory inventory = new Inventory(); 23 | inventory.setSkuCode("iphone_13"); 24 | inventory.setQuantity(100); 25 | 26 | Inventory inventory1 = new Inventory(); 27 | inventory1.setSkuCode("iphone_13_red"); 28 | inventory1.setQuantity(0); 29 | 30 | inventoryRepository.save(inventory); 31 | inventoryRepository.save(inventory1); 32 | }; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /inventory-service/src/main/java/com/programmingtechie/inventoryservice/service/InventoryService.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.inventoryservice.service; 2 | 3 | import com.programmingtechie.inventoryservice.dto.InventoryResponse; 4 | import com.programmingtechie.inventoryservice.repository.InventoryRepository; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.SneakyThrows; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import java.util.List; 12 | 13 | @Service 14 | @RequiredArgsConstructor 15 | @Slf4j 16 | public class InventoryService { 17 | 18 | private final InventoryRepository inventoryRepository; 19 | 20 | @Transactional(readOnly = true) 21 | // To create a slow behaviour inside the network 22 | /*@SneakyThrows*/ 23 | public List isInStock(List skuCode) { 24 | /*log.info("Wait started"); 25 | Thread.sleep(10000); 26 | log.info("Wait Ended");*/ 27 | return inventoryRepository.findBySkuCodeIn(skuCode).stream() 28 | .map(inventory -> 29 | InventoryResponse.builder() 30 | .skuCode(inventory.getSkuCode()) 31 | .isInStock(inventory.getQuantity() > 0) 32 | .build() 33 | ).toList(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 2 | spring.application.name=api-gateway 3 | logging.level.root= INFO 4 | logging.level.org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator= INFO 5 | logging.level.org.springframework.cloud.gateway= TRACE 6 | 7 | ## Product Service Route 8 | spring.cloud.gateway.routes[0].id=product-service 9 | spring.cloud.gateway.routes[0].uri=lb://product-service 10 | spring.cloud.gateway.routes[0].predicates[0]=Path=/api/product 11 | 12 | ## Order Service Route. lb = loadbalancing 13 | spring.cloud.gateway.routes[1].id=order-service 14 | spring.cloud.gateway.routes[1].uri=lb://order-service 15 | spring.cloud.gateway.routes[1].predicates[0]=Path=/api/order 16 | 17 | ## Discover Server Route localhost:8080/eureka/web 18 | spring.cloud.gateway.routes[2].id=discovery-server 19 | spring.cloud.gateway.routes[2].uri=http://localhost:8761 20 | spring.cloud.gateway.routes[2].predicates[0]=Path=/eureka/web 21 | spring.cloud.gateway.routes[2].filters[0]=SetPath=/ 22 | 23 | ## Discover Server Static Resources Route. 24 | ## Loads static documents e.g js, css 25 | spring.cloud.gateway.routes[3].id=discovery-server-static 26 | spring.cloud.gateway.routes[3].uri=http://localhost:8761 27 | spring.cloud.gateway.routes[3].predicates[0]=Path=/eureka/** 28 | 29 | ## Port from docker image from zipkin.io 30 | spring.zipkin.base-url=http://localhost:9411 31 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /api-gateway/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 2 | spring.application.name=api-gateway 3 | logging.level.root= INFO 4 | logging.level.org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator= INFO 5 | logging.level.org.springframework.cloud.gateway= TRACE 6 | 7 | ## Product Service Route 8 | spring.cloud.gateway.routes[0].id=product-service 9 | spring.cloud.gateway.routes[0].uri=lb://product-service 10 | spring.cloud.gateway.routes[0].predicates[0]=Path=/api/product 11 | 12 | ## Order Service Route. lb = loadbalancing 13 | spring.cloud.gateway.routes[1].id=order-service 14 | spring.cloud.gateway.routes[1].uri=lb://order-service 15 | spring.cloud.gateway.routes[1].predicates[0]=Path=/api/order 16 | 17 | ## Discover Server Route localhost:8080/eureka/web 18 | spring.cloud.gateway.routes[2].id=discovery-server 19 | spring.cloud.gateway.routes[2].uri=http://localhost:8761 20 | spring.cloud.gateway.routes[2].predicates[0]=Path=/eureka/web 21 | spring.cloud.gateway.routes[2].filters[0]=SetPath=/ 22 | 23 | ## Discover Server Static Resources Route. 24 | ## Loads static documents e.g js, css 25 | spring.cloud.gateway.routes[3].id=discovery-server-static 26 | spring.cloud.gateway.routes[3].uri=http://localhost:8761 27 | spring.cloud.gateway.routes[3].predicates[0]=Path=/eureka/** 28 | 29 | ## Port from docker image from zipkin.io 30 | spring.zipkin.base-url=http://localhost:9411 31 | spring.sleuth.sampler.probability= 1.0 -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/controller/OrderController.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.controller; 2 | 3 | import com.programmingtechie.orderservice.dto.OrderRequest; 4 | import com.programmingtechie.orderservice.service.OrderService; 5 | import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; 6 | import io.github.resilience4j.retry.annotation.Retry; 7 | import io.github.resilience4j.timelimiter.annotation.TimeLimiter; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | import java.util.concurrent.CompletableFuture; 13 | 14 | @RestController 15 | @RequestMapping("/api/order") 16 | @RequiredArgsConstructor 17 | public class OrderController { 18 | 19 | private final OrderService orderService; 20 | 21 | @PostMapping 22 | @ResponseStatus(HttpStatus.CREATED) 23 | // name is same as in application properties file 24 | /*@CircuitBreaker(name="inventory", fallbackMethod = "fallbackMethod") 25 | @TimeLimiter(name="inventory") 26 | @Retry(name = "inventory")*/ 27 | // completeablefuture as it is an asynchronous call 28 | public String placeOrder(@RequestBody OrderRequest orderRequest) { 29 | return orderService.placeOrder(orderRequest); 30 | 31 | } 32 | 33 | public CompletableFuture fallbackMethod(OrderRequest orderRequest, RuntimeException runtimeException) { 34 | return CompletableFuture.supplyAsync(()-> "Oops! Something went wrong, please try again later!"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /api-gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.programming.techie 8 | microservices-new 9 | 1.0-SNAPSHOT 10 | 11 | 12 | api-gateway 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-starter-gateway 24 | 25 | 26 | org.springframework.cloud 27 | spring-cloud-starter-netflix-eureka-client 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-sleuth 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-sleuth-zipkin 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /product-service/src/main/java/com/programmingtechie/productservice/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice.service; 2 | 3 | import com.programmingtechie.productservice.dto.ProductRequest; 4 | import com.programmingtechie.productservice.dto.ProductResponse; 5 | import com.programmingtechie.productservice.model.Product; 6 | import com.programmingtechie.productservice.repository.ProductRepository; 7 | import lombok.RequiredArgsConstructor; 8 | import lombok.extern.slf4j.Slf4j; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.util.List; 12 | 13 | @Service 14 | @RequiredArgsConstructor 15 | @Slf4j 16 | public class ProductService { 17 | 18 | private final ProductRepository productRepository; 19 | 20 | public void createProduct(ProductRequest productRequest) { 21 | Product product = Product.builder() 22 | .name(productRequest.getName()) 23 | .description(productRequest.getDescription()) 24 | .price(productRequest.getPrice()) 25 | .build(); 26 | 27 | productRepository.save(product); 28 | log.info("Product {} is saved", product.getId()); 29 | } 30 | 31 | public List getAllProducts() { 32 | List products = productRepository.findAll(); 33 | 34 | return products.stream().map(this::mapToProductResponse).toList(); 35 | } 36 | 37 | private ProductResponse mapToProductResponse(Product product) { 38 | return ProductResponse.builder() 39 | .id(product.getId()) 40 | .name(product.getName()) 41 | .description(product.getDescription()) 42 | .price(product.getPrice()) 43 | .build(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /order-service/target/classes/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url=jdbc:mysql://localhost:3306/order-service 3 | spring.datasource.username=root 4 | spring.datasource.password=password 5 | spring.jpa.hibernate.ddl-auto=update 6 | 7 | server.port=8081 8 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 9 | spring.application.name=order-service 10 | 11 | ## Circuit breakers requirement 12 | management.health.circuitbreakers.enabled=true 13 | management.endpoints.web.exposure.include=* 14 | management.endpoint.health.show-details=always 15 | 16 | ## Resilience 4j properties 17 | resilience4j.circuitbreaker.instances.inventory.registerHealthIndicator=true 18 | resilience4j.circuitbreaker.instances.inventory.event-consumer-buffer-size=10 19 | resilience4j.circuitbreaker.instances.inventory.slidingWindowType=COUNT_BASED 20 | resilience4j.circuitbreaker.instances.inventory.slidingWindowSize=5 21 | resilience4j.circuitbreaker.instances.inventory.failureRateThreshold=50 22 | resilience4j.circuitbreaker.instances.inventory.waitDurationInOpenState=5s 23 | resilience4j.circuitbreaker.instances.inventory.permittedNumberOfCallsInHalfOpenState=3 24 | resilience4j.circuitbreaker.instances.inventory.automaticTransitionFromOpenToHalfOpenEnabled=true 25 | 26 | resilience4j.timelimiter.instances.inventory.timeout-duration=3s 27 | resilience4j.retry.instances.inventory.max-attempts=3 28 | resilience4j.retry.instances.inventory.wait-duration=5s 29 | 30 | spring.zipkin.base-url=http://localhost:9411 31 | spring.sleuth.sampler.probability= 1.0 32 | 33 | # Kafka Properties 34 | spring.kafka.bootstrap-servers=localhost:9092 35 | spring.kafka.template.default-topic=notificationTopic 36 | spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer 37 | spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer 38 | spring.kafka.producer.properties.spring.json.type.mapping=event:com.programmingtechie.orderservice.event.OrderPlacedEvent 39 | -------------------------------------------------------------------------------- /order-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url=jdbc:mysql://localhost:3306/order-service 3 | spring.datasource.username=root 4 | spring.datasource.password=password 5 | spring.jpa.hibernate.ddl-auto=update 6 | 7 | server.port=8081 8 | eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka 9 | spring.application.name=order-service 10 | 11 | ## Circuit breakers requirement 12 | management.health.circuitbreakers.enabled=true 13 | management.endpoints.web.exposure.include=* 14 | management.endpoint.health.show-details=always 15 | 16 | ## Resilience 4j properties 17 | resilience4j.circuitbreaker.instances.inventory.registerHealthIndicator=true 18 | resilience4j.circuitbreaker.instances.inventory.event-consumer-buffer-size=10 19 | resilience4j.circuitbreaker.instances.inventory.slidingWindowType=COUNT_BASED 20 | resilience4j.circuitbreaker.instances.inventory.slidingWindowSize=5 21 | resilience4j.circuitbreaker.instances.inventory.failureRateThreshold=50 22 | resilience4j.circuitbreaker.instances.inventory.waitDurationInOpenState=5s 23 | resilience4j.circuitbreaker.instances.inventory.permittedNumberOfCallsInHalfOpenState=3 24 | resilience4j.circuitbreaker.instances.inventory.automaticTransitionFromOpenToHalfOpenEnabled=true 25 | 26 | resilience4j.timelimiter.instances.inventory.timeout-duration=3s 27 | resilience4j.retry.instances.inventory.max-attempts=3 28 | resilience4j.retry.instances.inventory.wait-duration=5s 29 | 30 | spring.zipkin.base-url=http://localhost:9411 31 | spring.sleuth.sampler.probability= 1.0 32 | 33 | # Kafka Properties 34 | spring.kafka.bootstrap-servers=localhost:9092 35 | spring.kafka.template.default-topic=notificationTopic 36 | spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer 37 | spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer 38 | spring.kafka.producer.properties.spring.json.type.mapping=event:com.programmingtechie.orderservice.event.OrderPlacedEvent 39 | -------------------------------------------------------------------------------- /inventory-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | microservices-new 7 | com.programming.techie 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | inventory-service 13 | 14 | 15 | 17 16 | 17 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-jpa 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.springframework.cloud 30 | spring-cloud-starter-netflix-eureka-client 31 | 32 | 33 | mysql 34 | mysql-connector-java 35 | runtime 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | true 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | org.springframework.cloud 49 | spring-cloud-starter-sleuth 50 | 51 | 52 | org.springframework.cloud 53 | spring-cloud-sleuth-zipkin 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /product-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | microservices-new 7 | com.programming.techie 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | product-service 13 | 14 | 15 | 17 16 | 17 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-mongodb 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.springframework.cloud 30 | spring-cloud-starter-netflix-eureka-client 31 | 32 | 33 | org.projectlombok 34 | lombok 35 | true 36 | 37 | 38 | 39 | me.paulschwarz 40 | spring-dotenv 41 | 2.5.4 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 49 | 50 | org.testcontainers 51 | mongodb 52 | test 53 | 54 | 55 | org.testcontainers 56 | junit-jupiter 57 | test 58 | 59 | 60 | 61 | org.springframework.cloud 62 | spring-cloud-starter-sleuth 63 | 64 | 65 | org.springframework.cloud 66 | spring-cloud-sleuth-zipkin 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /product-service/src/test/java/com/programmingtechie/productservice/ProductServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.productservice; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import com.programmingtechie.productservice.dto.ProductRequest; 5 | import com.programmingtechie.productservice.repository.ProductRepository; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.http.MediaType; 12 | import org.springframework.test.context.DynamicPropertyRegistry; 13 | import org.springframework.test.context.DynamicPropertySource; 14 | import org.springframework.test.web.servlet.MockMvc; 15 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 16 | import org.testcontainers.containers.MongoDBContainer; 17 | import org.testcontainers.junit.jupiter.Container; 18 | import org.testcontainers.junit.jupiter.Testcontainers; 19 | 20 | import java.math.BigDecimal; 21 | 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 23 | 24 | @SpringBootTest 25 | @Testcontainers 26 | @AutoConfigureMockMvc 27 | class ProductServiceApplicationTests { 28 | 29 | @Container 30 | static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:4.4.2"); 31 | @Autowired 32 | private MockMvc mockMvc; 33 | @Autowired 34 | private ObjectMapper objectMapper; 35 | @Autowired 36 | private ProductRepository productRepository; 37 | 38 | @DynamicPropertySource 39 | static void setProperties(DynamicPropertyRegistry dymDynamicPropertyRegistry) { 40 | dymDynamicPropertyRegistry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl); 41 | } 42 | 43 | @Test 44 | void shouldCreateProduct() throws Exception { 45 | ProductRequest productRequest = getProductRequest(); 46 | String productRequestString = objectMapper.writeValueAsString(productRequest); 47 | mockMvc.perform(MockMvcRequestBuilders.post("/api/product") 48 | .contentType(MediaType.APPLICATION_JSON) 49 | .content(productRequestString)) 50 | .andExpect(status().isCreated()); 51 | Assertions.assertEquals(1, productRepository.findAll().size()); 52 | } 53 | 54 | private ProductRequest getProductRequest() { 55 | return ProductRequest.builder() 56 | .name("iPhone 13") 57 | .description("iPhone 13") 58 | .price(BigDecimal.valueOf(1200)) 59 | .build(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-boot-microservices 2 | A real time microservices supply monitoring project utilizing spring cloud technologies framework. Services can connect/interact with each other or can also connect with external tools as shown in the Architectural layer below. 3 | 4 | ## Services and their functionality 5 | - Event driven activity such as notifying customers when order has been made was implemented with kafka. The kafka broker was set up using [Docker](https://developer.confluent.io/quickstart/kafka-docker/?utm_medium=sem&utm_source=google&utm_campaign=ch.sem_br.nonbrand_tp.prs_tgt.dsa_mt.dsa_rgn.emea_lng.eng_dv.all_con.confluent-developer&utm_term=&creative=&device=c&placement=&gclid=Cj0KCQjwiZqhBhCJARIsACHHEH-xX9qtTC87qTy6cshJ2Xg9Q9Is-G7lbOuU7w50jUVTDxAwrVW4VY8aAmXLEALw_wcB) and [Spring for Apache kafka](https://spring.io/projects/spring-kafka). 6 | 7 | - Distributed Tracing was implemented with [spring-cloud-sleuth](https://spring.io/projects/spring-cloud-sleuth) and [Zipkin](https://zipkin.io/pages/quickstart) for the UI. This helps to track the performance of our app by adding traces and spans id for every api call made to all the services. 8 | 9 | - Circuit breaker was implemented using Resilience 4j depency from Spring Cloud circuit breaker framework. This helps to degrade functionality when a method call fails. Since we are implementing a synchronous call to the inventory service, a circuit breaker would ensure clients are routed to a new page when a service fails or takes longer time to respond. More information [here](https://spring.io/projects/spring-cloud-circuitbreaker). 10 | 11 | - Service discovery was implemented with spring cloud discovery Eureka server/client. This helps to persist services on the eureka client side acting as a caching solution when the server is down. This can be seen as an SSG solution for rendering the browser DOM. 12 | 13 | - API gateway was implemented with spring cloud gateway to route and filter incoming requests to micro services. 14 | 15 | - Order service: Built on mySQL DB. Makes synchronous call to Inventory service to confirm if goods are available and asynchronous call to notification service notifying customers if order was successful. 16 | 17 | - Product service: Built on mongoDB. An endpoint to display goods. The frontend would be built on this end point. 18 | 19 | - Inventory service: Built on mySQL DB. Takes count of the quantity of goods in stock. 20 | 21 | - Notification service: Serveless API to notify cutomers about their orders. 22 | 23 | ## Architecture Layer 24 | 25 | ![architecture](https://user-images.githubusercontent.com/37347588/227748019-5f854bc5-8454-412b-bc23-ac3c4512ba58.png) 26 | 27 | ## Logic Layer for each service 28 | ![logic layer](https://user-images.githubusercontent.com/37347588/227748037-b6576358-4221-4177-ae0f-23b4e7941270.png) 29 | -------------------------------------------------------------------------------- /notification-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | microservices-new 7 | com.programming.techie 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | notification-service 13 | 14 | 15 | 17 16 | 17 17 | 17 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | org.springframework.kafka 27 | spring-kafka 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-sleuth-zipkin 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-starter-netflix-eureka-client 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-starter-sleuth 40 | 41 | 42 | 43 | org.projectlombok 44 | lombok 45 | true 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-test 50 | test 51 | 52 | 53 | org.springframework.kafka 54 | spring-kafka-test 55 | test 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-maven-plugin 64 | 65 | 66 | 67 | org.projectlombok 68 | lombok 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | org.springframework.boot 9 | spring-boot-starter-parent 10 | 2.6.6 11 | 12 | 13 | 14 | com.programming.techie 15 | microservices-new 16 | pom 17 | 1.0-SNAPSHOT 18 | 19 | product-service 20 | order-service 21 | inventory-service 22 | discovery-server 23 | api-gateway 24 | notification-service 25 | 26 | 27 | 28 | 17 29 | 17 30 | 2021.0.2 31 | 32 | 33 | 34 | 35 | 36 | org.testcontainers 37 | testcontainers-bom 38 | 1.16.3 39 | pom 40 | import 41 | 42 | 43 | org.springframework.cloud 44 | spring-cloud-dependencies 45 | ${spring-cloud.version} 46 | pom 47 | import 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-maven-plugin 57 | 58 | 59 | 60 | org.projectlombok 61 | lombok 62 | 63 | 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-compiler-plugin 69 | 70 | 16 71 | 16 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /order-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | microservices-new 7 | com.programming.techie 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | order-service 13 | 14 | 15 | 17 16 | 17 17 | 18 | 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-jpa 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-webflux 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-starter-netflix-eureka-client 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-circuitbreaker-resilience4j 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-actuator 43 | 44 | 45 | mysql 46 | mysql-connector-java 47 | runtime 48 | 49 | 50 | org.projectlombok 51 | lombok 52 | true 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-test 57 | test 58 | 59 | 60 | org.springframework.cloud 61 | spring-cloud-starter-sleuth 62 | 63 | 64 | org.springframework.cloud 65 | spring-cloud-sleuth-zipkin 66 | 67 | 68 | org.springframework.kafka 69 | spring-kafka 70 | 2.9.0 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /order-service/src/main/java/com/programmingtechie/orderservice/service/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.programmingtechie.orderservice.service; 2 | 3 | import com.programmingtechie.orderservice.dto.InventoryResponse; 4 | import com.programmingtechie.orderservice.dto.OrderLineItemsDto; 5 | import com.programmingtechie.orderservice.dto.OrderRequest; 6 | import com.programmingtechie.orderservice.event.OrderPlacedEvent; 7 | import com.programmingtechie.orderservice.model.Order; 8 | import com.programmingtechie.orderservice.model.OrderLineItems; 9 | import com.programmingtechie.orderservice.repository.OrderRepository; 10 | import lombok.RequiredArgsConstructor; 11 | import org.springframework.kafka.core.KafkaTemplate; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.transaction.annotation.Transactional; 14 | import org.springframework.web.reactive.function.client.WebClient; 15 | 16 | import java.util.Arrays; 17 | import java.util.List; 18 | import java.util.UUID; 19 | 20 | @Service 21 | @RequiredArgsConstructor 22 | @Transactional 23 | public class OrderService { 24 | 25 | private final OrderRepository orderRepository; 26 | private final WebClient.Builder webClientBuilder; 27 | // String because we are passing notification as a string and class orderplace event in line 58 28 | private final KafkaTemplate kafkaTemplate; 29 | public String placeOrder(OrderRequest orderRequest) { 30 | Order order = new Order(); 31 | order.setOrderNumber(UUID.randomUUID().toString()); 32 | 33 | List orderLineItems = orderRequest.getOrderLineItemsDtoList() 34 | .stream() 35 | .map(this::mapToDto) 36 | .toList(); 37 | 38 | order.setOrderLineItemsList(orderLineItems); 39 | 40 | List skuCodes = order.getOrderLineItemsList().stream() 41 | .map(OrderLineItems::getSkuCode) 42 | .toList(); 43 | 44 | // Call Inventory Service, and place order if product is in 45 | // stock 46 | InventoryResponse[] inventoryResponsArray = webClientBuilder.build().get() 47 | .uri("http://inventory-service/api/inventory", 48 | uriBuilder -> uriBuilder.queryParam("skuCode", skuCodes).build()) 49 | .retrieve() 50 | .bodyToMono(InventoryResponse[].class) 51 | .block(); 52 | 53 | boolean allProductsInStock = Arrays.stream(inventoryResponsArray) 54 | .allMatch(InventoryResponse::isInStock); 55 | 56 | if(allProductsInStock){ 57 | orderRepository.save(order); 58 | kafkaTemplate.send("notificationTopic", new OrderPlacedEvent(order.getOrderNumber())); 59 | return "Order placed successfully"; 60 | } else { 61 | throw new IllegalArgumentException("Product is not in stock, please try again later"); 62 | } 63 | } 64 | 65 | private OrderLineItems mapToDto(OrderLineItemsDto orderLineItemsDto) { 66 | OrderLineItems orderLineItems = new OrderLineItems(); 67 | orderLineItems.setPrice(orderLineItemsDto.getPrice()); 68 | orderLineItems.setQuantity(orderLineItemsDto.getQuantity()); 69 | orderLineItems.setSkuCode(orderLineItemsDto.getSkuCode()); 70 | return orderLineItems; 71 | } 72 | } 73 | --------------------------------------------------------------------------------