Microservice architecture has become very popular due to it's aglity, scalability, resilience and maintainability. In this article, I have briefly explained and demonstrated important design patterns and principles that are mostly used in microservice style architecture.
-
- Database per Service
Database PatternOne important criteria of microservice is must be loosely coupled so that it can be built, maintained and deployed independently. Sometime, each service may have different data storage requirement and easy replication is also a client ask in order to scale. To mange these, database per service is a good approach where restriction of the database can be controlled by only specific service, can be scaled based on the demand, size of the database will be small as compare as database per application which turns easy maintenance.
- API Gateway
Integration PatternMost of the cases an application can contains more than thousand of microservices and each microservice have diffrent end points so managing all servicess a common access point is necessary. API Gateway creates an common entry gate for all microservices of the application or for group of microservices of the application and routes the traffic to concerned services as a proxy. Additionally, it provides features like aggregation of services, caching, authentication and rate limiting etc
- Externalized Configuration
Cross-Cutt Aling Concern PatternOften services need to be run in diffrent environment like DEV, ST, UAT etc and to manage those environments different configurations are required in various properties file. A change in any of those properties a new build and re-deployment is required to be reflected. Externalize configuration helps to overcome the problem of rebuilding and redeployment when configuration of the application are changed.
- Circuit Breaker
Cross-Cutting Concern PatternIn a microservice based architecture, most of the services are inter dependent and lot of time they communicate internally to fulfill user's need. It is obvious that any time any downstearm service can move to non responding state or down state due to system issue. At that moment, requests are coming to a service can be sent to downsteam service that is in down state and unnecessarily uses system resources.If this process continues for longer period of time for lerge of request then there may be high chance that working service cane also be moved to down state due to to the unavailabilty of the system resouces. Circuit Breaker is used to detect the failure and prevent cascading effect
- Service Discovery
Cross-Cutting Concern PatternNow a days services are deployed in distributed system and sometime IP and Port are dynamically assigned to the services so it is very difficult to remeber the end point of services by consumer and most importantly every time address changes will break consumer service. So, services registry needs to be created to store all metadata of the producer services and everytime time new service added in network must be registered in service registry during start or de register during shutdown. All consumer service must query in service registry to pull correct producer service location before calling
- Distributed Tracing
Observability PatternsIn microservice architecture, request often span across different services to perform various operations. It is quite difficult to trace the request and response of service call for quick troubleshooting. Distributed Tracing patterns help to associate Trace Id and Span Id in each service call and Trace Id will be same for entire round trip of the request but Span Id will be diffrent for any intermediary service call. So using Trace Id entire journey/call stack can be idetified.
- Health Check
Observability PatternsTo detect correct status of the service is very important so that request will not be routed to any unhealth service. /health API is used to validate the status of the service and based on that instance can be declared as healthy or unhealthy.
- Authentication and Authorization
Security Patternssecurity is an important aspect of microservice architecture and we should follow standard Oauth2.0 process for securing our APIs to avoid any unauthorize access of data, function and system. This can be acheived by authenticating user and authorize their access of APIs based on defined role/authority.
- Database per Service
I have considered a simple use case to demonstrate the above said design patterns and principles. A educational society has decided to launch few model schools for children to provide better way of learning. They are looking for a "School Management Software" to perform most operations though online processes.
-
Society can add new school in system and also can update various parameters of existing school like location, school governance details.
-
Society has the the authority to delete school from the list.
-
Society can add/update/delete student in a school.
-
School Fees for student can be generated monthly basis.
-
Studdent can view their details and correct in case necessary.
-
Student can make payment of the fees.
Here, I have used spring boot framework to implement "School Managment Software" by considering above design patterns. Below are the technology stacks involved:
-
java 17 (JDK 17)
-
Spring Boot 3.1.3
-
Spring Cloud 2022.0.4
-
Maven 3.9.2
I have provided an overall architecture diagram for better undertanding and clarity purpose. Definitely there is scope for improvement and I will be adding more features to make it robust further.

| Spring Libraries/Components | Purpose | Reference |
|---|---|---|
| Spring Cloud Config | Config server is used for externalize the configurations. Group Id org.springframework.cloud and Artifact Id spring-cloud-config-server is added for enabling config server and all client applications have Group Id spring-cloud-config-server and Artifact Id spring-cloud-starter-config |
Config Server |
| Spring Cloud Circuit Breaker | Resilience4j library used for fault tolerance and circuitbreaker.Group Id org.springframework.cloud and artifact ID spring-cloud-starter-circuitbreaker-reactor-resilience4j is added as dependency for circuitbreaker |
Circuit Breaker |
| Spring Cloud Netflix Eureka | This is client side service discovery allows services to find and communicate with each other without hard-coding the hostname and port. Group Id org.springframework.cloud and Artifact Id spring-cloud-starter-netflix-eureka-server is added in discovery server application and Group Id org.springframework.cloud and Artifact Id spring-cloud-starter-netflix-eureka-client is added in client applications for registering in eureka |
Service Discovery |
| Spring Cloud Gateway | This is an API Gateway. Group Id org.springframework.cloud and artifact ID spring-cloud-starter-gateway is added in dependency for API Gateway feature |
Gateway |
| Spring Boot Actuator | This is used for health check of the application. Group Id org.springframework.boot and Artifact Id spring-boot-starter-actuator is added for the same. |
Health Check |
| H2 Database | Dedicated H2 database is used for every microservices involved in this project. this is being used for demo purpose but for real application it should be any RDBMS or NoSQL database. Group Id com.h2database and Artifact Id h2 is added in POM file |
|
| Spring Authorization Server | This framework is used for authentication and authorization purpose. Group Id org.springframework.boot and Artifact Id spring-boot-starter-oauth2-authorization-server is added in dependency for authorization process. |
Auth Server |
| Spring Resource Server | This is used for validating user's access and takes permit/deny actions while user tries to access APIs/resources. Group Id org.springframework.boot and Artifact Id spring-boot-starter-oauth2-resource-server is added in dependency. As this works on top of spring security so spring securtity dependency Group Id org.springframework.boot and Artifact Id spring-boot-starter-security is also added. |
Resource Server |
-
config-server- This application is used for storing all configuration of client applications. In this case, api-gateway, school-service, student-service, payment-service are client application and these application access HTTP resource-based API for external configuration from config-server. There can be various source of configuration supported. It supports loading configuration files from classpath, git, database, vault etc. I have loaded external configuration of client applications from classpath. I have created a properties file for each of corresponding client application for better clarity.[Single application.yml file can also be used instead]. To enable spring config server below action has been taken@EnableConfigServerannotation is added in spring boot startup application class.- Added profiles.active=native properties in application.yml file
- Created a
{client-appliaction-name}.yml[for gateway application configuartion file is api-gateway.yml] for every client application and kept under /resources/config location - Config server dependency is added in POM.xml file
<dependency> <groupId>org.springframework.cloud</groupId> <artifactIdspring-cloud-config-server</artifactId> </dependency>
-
service-discovery- This application works as service registry and service discovery. When instance of client the application is started, immediately registered itself in service registry so that other application can find it for inter communication. Here api-gateway, school-service, payment-service, student-service are considered as client application. To enable service discovery below actions have been taken@EnableEurekaServerannotation is added in spring boot startup application class.- Config server dependency is added in POM.xml file
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> - Application name (service-discovery) is added
application.ymlfile service-discovery.ymlproperties file is added in config-server application for storing all configuration required to run service-discovery application.-
-
auth-server- This is spring boot based application works as authorization server for authenticating the user and issues an access token for accessing the resource of resouce server. I have user in memory users for demo purpose. For auth-server below actions have been taken. -
I have used postman as resource client and used auth_code flow for retriving the access token.
- Set auth details in postman
- Auth Type- Oauth2.0
- Grant type- Authorization Code
- Callback URL- http://test []
- Auth URL- http://localhost:9999/oauth2/authorize
- Access Token URL- http://localhost:9999/oauth2/token
- Client ID-
- Client Secret-
- Scope- read write
- Client Authentication- Set as Basic Auth header
- Set auth details in postman
-
school-service|student-service|payment-service- These are all microservices for managing business capabilities of school management software. These microservices exposed various REST supported APIs to communicate with other services.
| Microservice | Business Capabilites | HTTP Method & API endpoint |
|---|---|---|
| School Service | To Add new school for society | POST http://{host}:{port}/school/ |
| School Service | To Edit school information | PUT http://{host}:{port}/school/{id} |
| School Service | To Delete school from society | DELETE http://{host}:{port}/school/{id} |
| School Service | To fetch all of the school details | GET http://{host}:{port}/school/ |
| School Service | To Fetch specific school details | GET http://{host}:{port}/school/{id} |
| Student Service | To Add new student to specific school | POST http://{host}:{port}/student/ |
| Student Service | To Edit student information | PUT http://{host}:{port}/student/{id} |
| Student Service | To Delete student from school | DELETE http://{host}:{port}/student/{id} |
| Student Service | To Fetch all of the student details of a school | GET http://{host}:{port}/student/ |
| Student Service | To Fetch specific student details | GET http://{host}:{port}/student/{id} |
| Student Service | To Fetch specific school details | GET http://{host}:{port}/school/{id} |
| Payment Service | To Add new payment for student | POST http://{host}:{port}/payment/ |
| Payment Service | To make payment | PUT http://{host}:{port}/payment/{id} |
| Payment Service | To Delete payment | DELETE http://{host}:{port}/payment/{id} |
| Payment Service | To Fetch a specific payment of student | GET http://{host}:{port}/payment/{id} |
| Payment Service | To Fetch paid/unpaid payment of a student | GET http://{host}:{port}/payment/student/{studentid} |
student-service or school-service or payment-service have almost similar configuration and dpendency, so I have explained only school-service configuration and dependency here.
-
config client dependency is added in POM for fetching configuration from config server.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> -
I have set server.port=0 (This was being set for dynamic port assignment as we may need to run multiple instances of same application.), spring.application.name = school-service and spring.config.import (url of
config-serverapplication) for config server connectivity in application.yml properties file.
-
service discovery client dependency is added in POM discovery and registry purpose.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> -
school-service.yml file is added in /resources/config of
config-serverapplication for keeping all external configuration.
-
Added few important properties for service discovery like, eureka.client-service-url (url of service discovery), eureka.instnace (I have created unique id for each instance of application due to existance of multiple instances of sample application for managing load of incoming request. combination of application name, instance id and random value).
-
Also added resilience4j dependeny for fault tolerance. Any of the service i.e., student-service, school-service or payment-service is down then request will not be sent to service rather end user can get customize message. I have defined fallback method to manage the same.
-
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId> </dependency> -
Added corrsponding configuration in school-service.yml file for resilience4j.circuitbreaker.

-
Defined a fallback method getSystemFailure() in controller which will executed if when downstream service is down.
@RequestMapping(value = "/systemFailure", method = {RequestMethod.GET, RequestMethod.POST}) public ResponseEntity<String> getSystemFailure() { return ResponseEntity.status(HttpStatus.BAD_GATEWAY).body("Please try after sometime"); } -
Also, attached fallback method in relevent APIs using @CircuitBreaker annotation.

-
api-gateway- I have use this application as the gateway of all microservices. All APIs will be accessible through url of API gateway, only context root will be diffrent for each downstream microservices. For student api context root is used /student, for school APIs context root is /school and for payment it is /payment. Additionally this gateway works as Authorization resource server. So it is integrated withauth-serverfor validating incoming resource request if request header has valid bearer token then only it will forward request to downstearm i.e., student, payment or school service dpending on routing defined. -
gateway-service.yml file is added for external configuration in
config-serverapplication. -
Added netflix ureka discovery client dependency as like other applications and added corresponding service-url, eureka.instance.instance-id details.
-
Added dependency for resource server
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency>and<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> -
To connect to
auth-server, I have added issuer-url (url of auth-server) in gateway-service.yml. Where http://localhost:9999 is the value contained in the iss claim for JWT tokens that the authorization server will issue. Resource Server will use this property to further self-configure, discover the authorization server’s public keys, and subsequently validate incoming JWTs.
-
Additionally,
@EnableWebFluxSecurityannotation is added to take the dvantage of the ServerHttpSecurity class to build our security configuration for restricting authenticated request as per scope.
-
As
api-gatewayis the entry point, so this is the best place to add circuit breaker configuration in gateway-service.yml for building resilience in system. Also, added fallback method for handling incoming requuest while downstream service is down or not responding.
-
- Build Config server and Deploy config-server1.0.0.jar. Default port 9090 is used.
- Build Service discovery application and deploy the same. Default port 9091 is used.
- Build Student microservice and deploy it in port 9092.
- Build Payment microservice and deploy it in port 9094.
- finally build API Gateawy and deploy it in port 9093.
Only 3 APIs are available currently and can be added further
Add student - [POST] http://localhost:9093/api/1.0/student
curl -X POST -H "Content-Type: application/json" -d '{"orgId": 1, "firstName": "chandan", "lastName": "maity", "gender": "male"}' http://localhost:9093/api/1.0/student/Add fees to be paid for the student - [POST] http://localhost:9093/api/1.0/payment
curl -X POST -H "Content-Type: application/json" -d '{"studentId": 1, "description": "Semister Fees", "amount": 5000.0, "status": "pending"}' http://localhost:9093/api/1.0/payment/Get student with payments - [GET] http://localhost:9093/api/1.0/student/{id}/with-payments
curl -X GET -H "Content-Type: application/json" http://localhost:9093/api/1.0/student/{id}/with-paymentsMake payment by student - [PUT] http://localhost:9093/api/1.0/payment/{id}
curl -X PUT -H "Content-Type: application/json" -d '{"studentId": 1, "description": "Semister Fees", "amount": 5000.0, "status": "paid"}' http://localhost:9093/api/1.0/payment/1/

