The service uses PostgreSQL to store its state
The service uses Kafka to produce events for other services
Kafka Topic | Message Type |
---|---|
UserCreated | UserCreated |
UserUpdated | UserUpdated |
Message and RPC definitions. To generate the go specific source code type:
make gen-proto
Output directory of gRPC and messages specific go source code.
Contains files to dockerize the application
GRPC Server that serves the user management API
HTTP Infra server exposes health check endpoints(readiness, liveness)
Kafka producer
Core application logic (config, services, repositories, models)
Utilities to used for integration tests with the help of docker api
classDiagram
class userStorage {
<<interface>>
InsertUser(user models.User) (uuid.UUID, error)
UpdateUser(userID uuid.UUID, user models.User) error
DeleteUser(userID uuid.UUID) error
GetUsersByFilter(opts models.GetUsersOptions) ([]models.User, error)
GetUserByID(userID uuid.UUID) (models.User, error)
ExistsByID(userID uuid.UUID) (bool, error)
}
class Repository {
db *sql.DB
}
userStorage <.. Repository : Satisfies
class eventPublisher {
<<interface>>
Publish(topic string, key string, pbMessage proto.Message) error
}
class EventPublisher {
client sarama.Client
}
eventPublisher <.. EventPublisher : Satisfies
class UserService{
repo userStorage
eventPublisher eventPublisher
}
Repository <|-- UserService : Uses
EventPublisher <|-- UserService : Uses
class userService {
<<interface>>
CreateUser(nu models.NewUser) (uuid.UUID, error)
UpdateUser(userID uuid.UUID, uu models.UpdateUser) error
DeleteUser(userID uuid.UUID) error
GetUsers(qu models.GetUsersOptions) ([]models.User, error)
}
userService <.. UserService : Satisfies
class GRPC {
svc userService
}
UserService <|-- GRPC : Uses
proto_UnimplementedUserServer <.. GRPC : Satisfies
class proto_UnimplementedUserServer {
<<interface>>
CreateUser(*CreateUserRequest) (*CreateUserResponse, error)
UpdateUser(*UpdateUserRequest) (*UpdateUserResponse, error)
DeleteUser(*DeleteUserRequest) (*DeleteUserResponse, error)
QueryUsers(*QueryUsersRequest) (*QueryUsersResponse, error)
}
To start the service type
make serve
To view logs of the service type
make logs
Usage examples:
Create user
$ grpcurl -d '{"email":"[email protected]","first_name":"user1_name","last_name":"user1_lname","nickname":"user1_nkname","password":"secret","country":"GR"}' -plaintext localhost:50000 services.user.User/CreateUser
{
"userId": "166f7137-8884-42ab-90b2-1c2d77fc1037"
}
Listing all users (default page size = 10)
$ grpcurl -d '{}' -plaintext localhost:50000 services.user.User/QueryUsers
{
"users": [
{
"id": "166f7137-8884-42ab-90b2-1c2d77fc1037",
"email": "[email protected]",
"firstName": "user1_name",
"lastName": "user1_lname",
"nickname": "user1_nkname",
"country": "GR",
"password": "$2a$10$LpgLzRcXkxU45Wwqgd.d9evdJ0wAV63LCFeLm.J78k2d1FBbnPNXG",
"createdAt": "2022-08-16T22:54:06.419671Z"
},
{
"id": "b3ce8fed-d5e8-4583-8783-b95969b5bc0c",
"email": "[email protected]",
"firstName": "user2_name",
"lastName": "user2_lname",
"nickname": "user2_nkname",
"country": "GR",
"password": "$2a$10$wNV.oRXIaAjPCbZp01zrf.KBwCq98AZZ1lEAEq/0VMEaEMlUSHiN6",
"createdAt": "2022-08-16T22:54:34.134916Z"
},
{
"id": "5631dc46-54a4-4f00-a296-faa248a98e8d",
"email": "[email protected]",
"firstName": "user3_name",
"lastName": "user3_lname",
"nickname": "user3_nkname",
"country": "UK",
"password": "$2a$10$KaIyJrMd3.o.KCSIQSV2MOdeIney1ejjdAcspFyLT3ysJwAraV.D.",
"createdAt": "2022-08-16T22:54:58.116917Z"
}
]
}
Listing all users in UK
$ grpcurl -d '{"filter":{"country":"UK"}}' -plaintext localhost:50000 services.user.User/QueryUsers
{
"users": [
{
"id": "5631dc46-54a4-4f00-a296-faa248a98e8d",
"email": "[email protected]",
"firstName": "user3_name",
"lastName": "user3_lname",
"nickname": "user3_nkname",
"country": "UK",
"password": "$2a$10$KaIyJrMd3.o.KCSIQSV2MOdeIney1ejjdAcspFyLT3ysJwAraV.D.",
"createdAt": "2022-08-16T22:54:58.116917Z"
}
]
}
Listing users in GR (1st page)
$ grpcurl -d '{"page_size":1, "page_number":1 ,"filter":{"country":"GR"}}' -plaintext localhost:50000 services.user.User/QueryUsers
{
"users": [
{
"id": "166f7137-8884-42ab-90b2-1c2d77fc1037",
"email": "[email protected]",
"firstName": "user1_name",
"lastName": "user1_lname",
"nickname": "user1_nkname",
"country": "GR",
"password": "$2a$10$LpgLzRcXkxU45Wwqgd.d9evdJ0wAV63LCFeLm.J78k2d1FBbnPNXG",
"createdAt": "2022-08-16T22:54:06.419671Z"
}
]
}
Listing users in GR (2nd page)
$ grpcurl -d '{"page_size":1, "page_number":2 ,"filter":{"country":"GR"}}' -plaintext localhost:50000 services.user.User/QueryUsers
{
"users": [
{
"id": "b3ce8fed-d5e8-4583-8783-b95969b5bc0c",
"email": "[email protected]",
"firstName": "user2_name",
"lastName": "user2_lname",
"nickname": "user2_nkname",
"country": "GR",
"password": "$2a$10$wNV.oRXIaAjPCbZp01zrf.KBwCq98AZZ1lEAEq/0VMEaEMlUSHiN6",
"createdAt": "2022-08-16T22:54:34.134916Z"
}
]
}
Delete user
$ grpcurl -d '{"user_id":"166f7137-8884-42ab-90b2-1c2d77fc1037"}' -plaintext localhost:50000 services.user.User/DeleteUser
{
"success": true
}
Update user
$ grpcurl -d '{"user_id":"b3ce8fed-d5e8-4583-8783-b95969b5bc0c", "fields":{"nickname":"batman"}}' -plaintext localhost:50000 services.user.User/UpdateUser
{
"success": true
}
To stop the service type
make stop
To run tests type
make test
To run tests with coverage report type
make report
then open the generated html file cover.html