This repository contains a microservices-based application built with Golang. The application demonstrates how to use microservices to create a scalable and maintainable architecture. It includes services for authentication, logging, mailing, and a listener service that processes events from RabbitMQ.
The architecture is composed of multiple services that communicate with each other through REST APIs and message queues. The services are:
- API Gateway: The entry point for all client requests.
- Authentication Service: Handles user authentication.
- Logger Service: Page application events.
- Mailer Service: Sends emails.
- Listener Service: Listens for events from RabbitMQ and processes them.
- Payment Service: Listens for gRPC calls from api-gateway to Process payments using credit card.
Before you begin, ensure you have the following installed:
-
Clone the repository:
git clone https://github.com/Meenachinmay/microservices-golang.git cd microservices-golang
-
Create an
.env
file in the root directory and set the necessary environment variables. An example.env
file is provided as.env.example
.cp .env.example .env
-
Build and run the services using Docker Compose using Makefile:
make up_build
-
The services will be available at the following ports:
- API Gateway:
http://localhost:8080
- Authentication Service:
http://localhost:8081
- Logger Service:
http://localhost:8082
- Mailer Service:
http://localhost:8083
- Listener Service:
http://localhost:8084
- Payment Service:
http://localhost:8085
- API Gateway:
The API Gateway is the main entry point for all incoming requests. It routes requests to the appropriate service based on the action specified.
The Authentication Service handles user authentication. It provides endpoints for login, signup, and password reset. (as of now just login is there for simulation, I will add more like signup, session, cookies and everything)
The Logger Service logs application events. It listens for log events from RabbitMQ and stores them in a log file.
The Mailer Service sends emails. It listens for mail events from RabbitMQ and sends emails using the configured SMTP server. (I am using mailhog as of now, later I will use sendgrid)
The Listener Service listens for events from RabbitMQ and processes them. It handles log and mail events, delegating tasks to the appropriate services.
The payment service uses stripe payment gateway API to enable credit card payment for now. Payment service need to communicate with async calls with api-gateway and api-gateway with client, so for the communication between api-gateway and Payment service I am enabling gRPC calls, rather than using RabbitMQ. In this service I planned to use rabbitMQ to generate email invoices for payments on a completion of successful payments from users.
- Golang: The primary language used for building the services.
- Docker: Used for containerizing the services.
- Docker Compose: Used for orchestrating the multi-container Docker application.
- RabbitMQ: Used for messaging between services.
- PostgreSQL: The database used by the Authentication Service.
- MongoDB: The database used by the Logger Service.
- gRPC: Communication method between api-gateway and other services where it needs async calls.
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative <name of file>.proto
- Api-gateway
- Enquiry-service -> Postgres DB
- Mail-service
- Logger-service -> Postgres DB
- Listener-service
- frontend
- users table
- enquiry tables
- schedules table
- logs tables
- http
- gRPC
- Rabbitmq message broker
- Docker
- Postgres -> data store
- Redis -> Cache, Rate Limiting
- Sendgrid
func HandleSubmission(c *gin.Context)
func (lac *LocalApiConfig) FetchAllProperties(c *gin.Context)
func connect() (*amqp.Connection, error)
func EnquiryViaGRPC(c *gin.Context, enquiryPayload types.EnquiryPayload)
func (lac *LocalApiConfig) GetAllLogs(c *gin.Context)
func (lac *LocalApiConfig) WriteLog(c *gin.Context)
func (lac *LocalApiConfig) CreateNewUser(c *gin.Context, userPayload types.UserPayload)
func (localApiConfig *LocalApiConfig) HandleFetchAllProperties(c *gin.Context)
func StartGrpcServer(localApiConfig *handlers.LocalApiConfig)
func connect() (*amqp.Connection, error)
func connectToDB() *sql.DB
func ProcessScheduledTasks(s *handlers.EnquiryServer)
func StartGrpcUserServer(localApiConfig *handlers.LocalApiConfig)
func (e *EnquiryServer) HandleCustomerEnquiry(ctx context.Context, request *enquiries.CustomerEnquiryRequest) (*enquiries.CustomerEnquiryResponse, error)
func (e *EnquiryServer) getTotalEnquiriesLastWeek(c context.Context, updatedUser database.User) (int, error)
func (e *EnquiryServer) SendEmail(payload EnquiryMailPayloadUsingSendgrid) error
func (e *EnquiryServer) notifyUserAboutEnquiry(input *enquiries.CustomerEnquiry, totalEnquiries int, mailPayload EnquiryMailPayloadUsingSendgrid) error
func (e *EnquiryServer) executeTask(input *enquiries.CustomerEnquiry, mailPayload EnquiryMailPayloadUsingSendgrid) error
func (e *EnquiryServer) scheduleTask(input *enquiries.CustomerEnquiry, mailPayload EnquiryMailPayloadUsingSendgrid) error
func (u *UserServer) CreateNewUser(ctx context.Context, request *users.CreateUserRequest) (*users.CreateUserResponse, error)
func (e *Emitter) declareExchange(ch *amqp.Channel) error
func (e *Emitter) Emit(event string) error
func NewEmitter(conn *amqp.Connection, exchange, routingKey string) (*Emitter, error)
func DeclareExchange(ch *amqp.Channel) error
func DeclareRandomQueue(ch *amqp.Channel) (amqp.Queue, error)
func DeclareMailExchange(ch *amqp.Channel) error
func DeclareMailQueue(ch *amqp.Channel) (amqp.Queue, error)
func DeclareEnquiryMailQueue(ch *amqp.Channel) (amqp.Queue, error)
func NewLogConsumer(conn *amqp.Connection) (*LogConsumer, error)
func (consumer *LogConsumer) ConsumeLogs(topics []string) error
func logEvent(log LogPayload) error
func NewMailConsumer(conn *amqp.Connection) (*MailConsumer, error)
func (consumer *MailConsumer) ConsumeMails() error
func (consumer *MailConsumer) ConsumeEnquiryMails() error
func sendEnquiryMail(payload EnquiryMailPayloadUsingSendgrid) (time.Duration, error)
func logMailSendingResult(payload EnquiryMailPayloadUsingSendgrid, elapsed time.Duration, err error) error
func startLogConsumer(conn *amqp.Connection)
func startMailConsumer(conn *amqp.Connection)
func startEnquiryMailConsumer(conn *amqp.Connection)
func (apiConfig *LocalApiConfig) WriteLog(c *gin.Context)
func (l *LogServer) WriteLog(ctx context.Context, req *logs.LogRequest) (*logs.LogResponse, error)
func (l *LogServer) GetAllLogs(ctx context.Context, request *logs.GetAllLogsRequest) (*logs.GetAllLogsResponse, error)
func GRPCListener(localApiConfig *LocalApiConfig)
func (app *Config) SendMailViaSendGrid(w http.ResponseWriter, r *http.Request)
Contributions are welcome! Please read the CONTRIBUTING.md file for more information on how to contribute to this project.
This project is licensed under the MIT License. See the LICENSE file for details.