Microservices development for managing your list of preferred mythical beasts. This multimodule Maven project is built with Reactive Programming, Hexagonal Arch, CQRS, Event Sourcing, and Kafka for synchronizing databases. RSocket for communication between microservices and Redis to store relevant information from other components.
Components
- Kafka [9092] + [9093]
- Kafka-UI [8081]
- Eureka server as service registry and discovery service [8761]
- API Gateway with centralized OpenApi Swagger-UI [8080]
- REST API ms-area with OpenApi Swagger-UI [0]
- REST API ms-creature with OpenApi Swagger-UI [0]
- REST API oauth2-server with OpenApi Swagger-UI working as JWT Token Authorization Server [9000]
graph BT
subgraph KafkaUI
Kafka-UI
end
subgraph Kafka
Kafka-Server
end
subgraph oauth2-server
oauth2server{{JWT Authorization Server}}
end
subgraph ms-area
A{{Area}}
end
subgraph ms-area-db["Databases for ms-area"]
direction RL
A1[(Sql Read Db)]
A2[(NoSql Write Db)]
A3[(Redis Backup Db)]
end
subgraph ms-creature
C{{Creature}}
end
subgraph ms-creature-db["Databases for ms-creature"]
direction RL
C1[(Sql Read Db)]
C2[(NoSql Write Db)]
C3[(Redis Backup Db)]
end
ms-area-db <--> ms-area
ms-creature-db <--> ms-creature
A1 <-. Synchro .-> A2
C1 <-. Synchro .-> C2
ms-area <-->|Publish-Subscriber| Kafka
ms-creature <-->|Publish-Subscriber| Kafka
ms-area <-.->| | oauth2-server
ms-creature <-.->| | oauth2-server
KafkaUI <--> | | Kafka
classDef canvas_basic fill:#82C0CC,stroke:#333;
classDef ms_basic fill:#FFB703,stroke:#333;
classDef db_basic fill:#FD9E02,stroke:#333;
classDef redis_basic fill:#FB8500,stroke:#333
class ms-area-db,ms-creature-db canvas_basic
class A,C,Kafka-UI,oauth2server,Kafka-Server ms_basic
class A1,A2,C1,C2, db_basic
class A3,C3 redis_basic
class ms-area,ms-creature,oauth2-server,Kafka,KafkaUI canvas_basic
-
First of all clone or download the project.
-
Inside the main folder, you could find two docker-compose yaml files.
-
From there use the command line to start the project in dev or production mode
**Developer mode**
docker-compose -f docker-compose-dev.yml up -d
**Production mode**
docker-compose -f docker-compose-prod.yml up -d
The dev environment is ready for using with your IDE. The microservice attempts to communicate with Kafka using the local host. In production, it uses the archive Dockerfile to build an image of the project, so you wont need the IDE.
- You could stop the project and free resources with any of these orders
**Developer mode**
docker-compose -f docker-compose-dev.yml down --rmi local -v
**Production mode**
docker-compose -f docker-compose-prod.yml down --rmi local -v
First of all, please visit the centralized REST API documentation on the Api-Gateway server. You can change the selection on the upper dropdown menu.
http://localhost:8080/swagger-ui.html
In this context, unexpected behavior may occur due to the different network settings when using Swagger requests directly from Api-Gateway centralized Swagger-UI. To prevent some of these issues, CORS and CSRF have been disabled in Spring Security settings. Alternatively if you want use the Swagger-UI dashboard for REST operations, it is recommended to call the microservice directly:
http://localhost:${port}/swagger-ui.html.
API Rest Endpoints have dynamic ports but Api Gateway responds on 8080 port, so you could use a program like SoapUI or curl and call them with the following nomenclature http://${hostname}:8080/api/v1/${entity}. For instance:
** Get a List of Area entities **
curl -v http://localhost:8080/api/v1/areas
** Get a Creature according to an Id **
curl -v http://localhost:8080/api/v1/creatures/22000000-0000-0000-0000-000000000003
** Create Area **
curl -v -H "Content-Type: application/json" -d '{"areaName":"Delfos"}' http://localhost:8080/api/v1/areas
** Update Creature **
curl -v -X "PUT" -H "Content-Type: application/json" -d '{"creatureName":"Harpy", "creatureDescription":"half-human and half-bird", "areaId":"11000000-0000-0000-0000-000000000001"}' http://localhost:8080/api/v1/creatures/22000000-0000-0000-0000-000000000008
** Delete a Creature according to an Id **
curl -v -X "DELETE" http://localhost:8080/api/v1/creatures/22000000-0000-0000-0000-000000000005
The initial data load is performed by the kafka-data-init microservice. It uses Kafka to publish events, which the other microservices then use to update their databases.
Kafka-UI allow you to check your Kafka server using a practical dashboard, so visit the following url:
http://localhost:8081
A good way for checking the JWT generation and validation flow, is reading this and following these steps:
- First you should register an user using the method POST and the URL
http://localhost:9000/register
. Here is an example of the info you need to send:
{
"name":"Marco",
"lastname":"Polo",
"email":"[email protected]",
"password":"passpasspass"
}
- Next, since form-based login authorization is active, we need to use a browser. Navigate to
http://localhost:9000/login
and use the credentials you have just created. Ignore any NoResourceFoundException error. - Then we will request the authorization code with the same browser. The authorization server will respond with a code, which the client can exchange for tokens over a secure channel.
http://localhost:9000/oauth2/authorize
?client_id=client
&redirect_uri=http://localhost:9000/callback
&scope=openid
&response_type=code
&response_mode=query
&state=k13gsri3gw
&nonce=njumydikqj
- We use the POST method to request our JWT token sending the authorization code and the rest of parameters
- Now we can use the retrieved JWT token to reach the unique protected URL in the rest of microservices at http://{host}:{port}/actuator/metrics
This project has my own profile of SoapUI with the endpoints configured. Everything is in the file Proy-nano-bestiary-soapui-project.xml at the root folder.
If you want to test the project in a Kubernetes environment, you can use the contents of k8s-manifest folder. The manifests are configured for development profile, so you need your IDE to deploy the microservice infrastructure. You can run all manifest files with:
kubectl -apply ./k8s-manifest
Just me, Iván 😅