If you're very new to Clean Architecture, I recommend you check more simple demo.
This repo was built up with three services: Task, User and Auth. Each of them conforms Clean Architecture.
Let's focus on directories in /services
:
services
├── auth
│ ├── business
│ ├── entity
│ ├── repository
│ │ ├── mysql
│ │ └── rpc
│ └── transport
│ ├── api
│ └── rpc
├── task
│ ├── business
│ ├── entity
│ ├── repository
│ │ ├── mysql
│ │ └── rpc
│ └── transport
│ └── api
└── user
├── business
├── entity
├── repository
│ └── mysql
└── transport
├── api
└── rpc
Protobuf and generated files at proto folder:
├── auth.proto
├── pb
│ ├── auth.pb.go
│ ├── auth_grpc.pb.go
│ ├── user.pb.go
│ └── user_grpc.pb.go
└── user.proto
Instead of separating to 3 repos on GitHub, I merged them to a single repo to give more transparent and convenience to build up the demo. But the services are isolated with each others.
Service stacks:
- GIN (for HTTP service)
- gRPC (internal rpc)
- MySQL (with GORM)
- JWT
- REST API: CRUD Task (require authorization for all apis)
- gRPC: None
- REST API:
- Get user profile (require authorization)
- gRPC:
- Get public user info by ID
- Get many public user infos by IDs
- REST API:
- Register new user account
- Login (issue JWT)
- gRPC:
- Introspect Access Token
Some of main diagrams to demonstration how they work together:
Open your terminal/console:
git clone https://github.com/viettranx/microservices-clean-architecture-demo
cd microservices-clean-architecture-demo
docker compose up --force-recreate --detach --build app
If everything is ok, the service will be running at on localhost:3000
Print all ENV variables:
docker compose exec app ./demo_app outenv
- Register new account
curl --location 'http://localhost:3000/v1/register' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "demo@demo.com",
"password": "12345678",
"last_name": "Microservices",
"first_name": "Demo "
}'
{"data": true}
- Login
curl --location 'http://localhost:3000/v1/authenticate' \
--header 'Content-Type: application/json' \
--data-raw '{
"email": "demo@demo.com",
"password": "12345678"
}'
The access token will return like this
{
"data": {
"access_token": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlNTMycW9zOGpqTTIiLCJleHAiOjE2ODAyNTI0MDgsIm5iZiI6MTY3OTY0NzYwOCwiaWF0IjoxNjc5NjQ3NjA4LCJqdGkiOiI3OTEzYzhjYy05NmI0LTQ3ZmUtOWIzZi01MTUwZTk5NTM3MGUifQ.51d6zVuGtcAbw2poEWV4TffhEqJG8uxMOcGq7Mt8sZA",
"expire_in": 604800
}
}
}
- Create a new task
curl --location 'http://localhost:3000/v1/tasks' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlNTMycW9zOGpqTTIiLCJleHAiOjE2ODAyNTI0MDgsIm5iZiI6MTY3OTY0NzYwOCwiaWF0IjoxNjc5NjQ3NjA4LCJqdGkiOiI3OTEzYzhjYy05NmI0LTQ3ZmUtOWIzZi01MTUwZTk5NTM3MGUifQ.51d6zVuGtcAbw2poEWV4TffhEqJG8uxMOcGq7Mt8sZA' \
--header 'Content-Type: application/json' \
--data '{
"title": "This is a new task",
"description": "Build a simple demo clean architecture"
}'
New Task id will be returned
{"data":"e532sJ4XpCi8"}
- Fetch list tasks
curl --location 'http://localhost:3000/v1/tasks' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJnR3pUQlVScWhhakciLCJleHAiOjE2ODAwNjQzNzcsIm5iZiI6MTY3OTQ1OTU3NywiaWF0IjoxNjc5NDU5NTc3LCJqdGkiOiI5Y2U4ZjUwMC1hYTczLTQ1MTYtYmJhYy04OTBiNDBjNDVkMDAifQ.VsqU8_Gn_EMwKAYW-En3BG58nWTREG6s3zCVXu7sZgQ'
{
"data": [
{
"id": "e532sJ4XpCi8",
"created_at": "2023-03-24T08:50:07Z",
"updated_at": "2023-03-24T08:50:07Z",
"title": "This is a new task",
"description": "Build a simple demo clean architecture",
"status": "doing",
"user": {
"id": "e532qos8jjM2",
"last_name": "Microservices",
"first_name": "Demo",
"avatar": null
}
}
],
"paging": {
"page": 1,
"limit": 10,
"total": 1,
"cursor": "",
"next_cursor": ""
},
"extra": {}
}
Building services with Clean Architecture is difficult, especially in Microservices. I hope this repo help you. Enjoy it and feel free to create PRs or Issues.