Go Food Delivery Microservicesis an imaginary and practical food delivery microservices, built with Golang and different software architecture and technologies like Microservices Architecture, Vertical Slice Architecture , CQRS Pattern, Domain Driven Design (DDD), Event Sourcing, Event Driven Architecture and Dependency Injection. For communication between independent services, We use asynchronous messaging using RabbitMQ, and sometimes we use synchronous communication for real-time communications using REST and gRPC calls.
You can use this project as a template to build your backend microservice project in the Go language
π‘ This application is not business-oriented and my focus is mostly on the technical part, I just want to implement a sample using different technologies, software architecture design, principles, and all the things we need for creating a microservices app.
π This Application is in progress and I will add new features and technologies over time.
For your simplest Golang projects, you can use my go-vertical-slice-template project:
For more advanced projects, with two microservices and modular monolith architecture, check the C# version:
Vertical Slice Architecture as a high-level architectureEvent Driven Architecture on top of RabbitMQ Message Broker with a custom Event BusData-Centric Architecture based on CRUD in Catalogs Read ServiceEvent Sourcing in Audit Based services like Orders ServiceCQRS Pattern and Mediator Patternon top of Go-MediatR libraryDependency Injection and Inversion of Controlon top of uber-go/fx libraryPostgres and EventStoreDB to write databases with fully supported transactions(ACID)MongoDB and Elastic Search for read databases (NOSQL)OpenTelemetry for collection Distributed Tracing using Jaeger and ZipkinOpenTelemetry for collection Metrics with using Prometheus and GrafanaUnit Test for testing small units with mocking dependent classes and using Mockery for mocking dependenciesEnd2End Test and Integration Test for testing features with all of their real dependencies using docker containers (cleanup tests) and testcontainers-go libraryZap and structured loggingViper for configuration managementdocker-compose for deploymentDomain Driven Design in some of the services like Catalogs Write Service and Orders ServiceHelm and Kubernetes for deploymentOutbox Pattern for all microservices for Guaranteed Delivery or At-least-once DeliveryInbox Pattern for handling Idempotency in reciver side and Exactly-once Deliverylabstack/echo - High performance, minimalist Go web frameworkuber-go/zap - Blazing fast, structured, leveled logging in Go.emperror/errors - Drop-in replacement for the standard library errors package and github.com/pkg/errorsopen-telemetry/opentelemetry-go - OpenTelemetry Go API and SDKopen-telemetry/opentelemetry-go-contrib - Collection of extensions for OpenTelemetry-Go.rabbitmq/amqp091-go - An AMQP 0-9-1 Go client maintained by the RabbitMQ team. Originally by @streadway: streadway/amqpstretchr/testify - A toolkit with common assertions and mocks that plays nicely with the standard librarymehdihadeli/go-mediatr - Mediator pattern implementation in Golang and helpful in creating CQRS based applications.grpc-ecosystem/go-grpc-middleware - Golang gRPC Middlewares: interceptor chaining, auth, logging, retries and moregrpc/grpc-go - The Go language implementation of gRPC. HTTP/2 based RPCelastic/go-elasticsearch - The official Go client for Elasticsearchavast/retry-go - Simple golang library for retry mechanismahmetb/go-linq - .NET LINQ capabilities in GoEventStore/EventStore-Client-Go - Go Client for Event Store version 20 and above.olivere/elastic/v7 - Deprecated: Use the official Elasticsearch client for Go atswaggo/swag - Automatically generate RESTful API documentation with Swagger 2.0 for Go.prometheus/client_golang - Prometheus instrumentation library for Go applicationsmongodb/mongo-go-driver - The Go driver for MongoDBgo-redis/redis - Type-safe Redis client for Golanggo-gorm/gorm - The fantastic ORM library for Golang, aims to be developer friendlygo-playground/validator - Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array divinggo-ozzo/ozzo-validation - Validate data of different types include, provide a rich set of validation rules right out of box.spf13/viper - Go configuration with fangscaarlos0/env - A simple and zero-dependencies library to parse environment variables into structs.joho/godotenv - A Go port of Ruby's dotenv library (Loads environment variables from .env files)mcuadros/go-defaults - Go structures with default values using tagsuber-go/fx - A dependency injection based application framework for Go.testcontainers/testcontainers-go - Testcontainers for Go is a Go package that makes it simple to create and clean up container-based dependencies for automated integration/smoke tests.Each microservices are based on these project structures:
In this project I used vertical slice architecture or Restructuring to a Vertical Slice Architecture also I used feature folder structure in this project.
Minimize coupling between slices, and maximize coupling in a slice.Also here I used CQRS to decompose my features into very small parts that make our application:
By using CQRS, our code will be more aligned with SOLID principles, especially with:
Here instead of some Technical Splitting for example a folder or layer for our services, controllers, and data models which increase dependencies between our technical splitting and also jump between layers or folders, We cut each business functionality into some vertical slices, and inner each of these slices we have Technical Folders Structure specific to that feature (command, handlers, infrastructure, repository, controllers, data models, ...).
Usually, when we work on a given functionality we need some technical things for example:
Now we could have all of these things beside each other and it decrease jumping and dependencies between some layers or folders.
Keeping such a split works great with CQRS. It segregates our operations and slices the application code vertically instead of horizontally. In Our CQRS pattern each command/query handler is a separate slice. This is where you can reduce coupling between layers. Each handler can be a separated code unit, even copy/pasted. Thanks to that, we can tune down the specific method to not follow general conventions (e.g. use custom SQL query or even different storage). In a traditional layered architecture, when we change the core generic mechanism in one layer, it can impact all methods.
TODO
In this app, I use Conventional Commit and for enforcing its rule I use conventional-changelog/commitlint and typicode/husky with a pre-commit hook. To read more about its setup see commitlint docs and this article and this article.
For applying golangci-lint in IDE level I use intellij-plugin-golangci-lint plugin.
For formatting, I used mvdan/gofumpt, goimports-reviser, golines and golangci-lint in my GoLand and for each package, there is a guide for how to set it up in your IDE, for example. here is the configuration for goimports-reviser.
Also, you can control this formatting with husky automatically before any commit by installing husky in your dev environment:
make install-tools
npm init
npm install --save-dev @commitlint/config-conventional @commitlint/cli
commitlint.config.js file with this content:module.exports = { extends: '@commitlint/config-conventional']};
npm install husky --save-dev
prepare command for installing and activating husky hooks that we will add in the next steps, in the package.json file:npm pkg set scripts.prepare="husky install"
mkdir .husky
npx husky add .husky/pre-commit "make format && git add -A ."
npx husky add .husky/pre-commit "make lint && git add -A ."
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'
npm run prepare
For live reloading in dev mode I use air library. for a guide about using these tools, you can read this article.
For running each microservice in live reload mode, inner each service folder type the bellow command after installing air:
air
The application is in development status. You are feel free to submit a pull request or create the issue according to Contribution Guid.
The project is under MIT license.