https://github.com/mariocarrion/todo-api-microservice-example
Go microservice tutorial project using Domain Driven Design and Onion Architecture!
https://github.com/mariocarrion/todo-api-microservice-example
domain-driven-design golang microservices onion-architecture tutorial
Last synced: 9 months ago
JSON representation
Go microservice tutorial project using Domain Driven Design and Onion Architecture!
- Host: GitHub
- URL: https://github.com/mariocarrion/todo-api-microservice-example
- Owner: MarioCarrion
- License: mit
- Created: 2021-02-14T18:28:08.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2025-05-07T03:38:21.000Z (9 months ago)
- Last Synced: 2025-05-07T04:30:06.421Z (9 months ago)
- Topics: domain-driven-design, golang, microservices, onion-architecture, tutorial
- Language: Go
- Homepage:
- Size: 4.8 MB
- Stars: 1,235
- Watchers: 15
- Forks: 174
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# "ToDo API" Microservice Example
[](https://codecov.io/gh/MarioCarrion/todo-api-microservice-example)
## Introduction
Welcome! 👋
This is an educational repository that includes a microservice written in Go. It is used as the principal example of my video series: [Building Microservices in Go](https://www.youtube.com/playlist?list=PL7yAAGMOat_Fn8sAXIk0WyBfK_sT1pohu).
This repository **is not** a template **nor** a framework, it's a **collection of patterns and guidelines** I've successfully used to deliver enterprise microservices when using Go, and just like with everything in Software Development some trade-offs were made.
My end goal with this project is to help you learn another way to structure your Go project with 3 final goals:
1. It is _enterprise_, meant to last for years,
1. It allows a team to collaborate efficiently with little friction, and
1. It is as idiomatic as possible.
Join the fun at [https://youtube.com/MarioCarrion](https://www.youtube.com/c/MarioCarrion).
## Domain Driven Design
This project uses a lot of the ideas introduced by Eric Evans in his book [Domain Driven Design](https://www.domainlanguage.com/), I do encourage reading that book but before I think reading [Domain-Driven Design Distilled](https://smile.amazon.com/Domain-Driven-Design-Distilled-Vaughn-Vernon/dp/0134434420/) makes more sense, also there's a free to download [DDD Reference](https://www.domainlanguage.com/ddd/reference/) available as well.
On YouTube I created [a playlist](https://www.youtube.com/playlist?list=PL7yAAGMOat_GJqfTdM9PBdTRSH7jXs6mI) that includes some of my favorite talks and webinars, feel free to explore that as well.
## Project Structure
Talking specifically about microservices **only**, the structure I like to recommend is the following, everything using `<` and `>` depends on the domain being implemented and the bounded context being defined.
- [ ] `build/`: defines the code used for creating infrastructure as well as docker containers.
- [ ] `/`: define concrete cloud provider.
- [ ] `/`: contains a Dockerfile used for building the binary.
- [ ] `cmd/`
- [ ] `/`: uses primary database.
- [ ] `/`: uses readonly databases.
- [ ] `/`
- [X] `db/`
- [X] `migrations/`: contains database migrations.
- [ ] `seeds/`: contains file meant to populate basic database values.
- [ ] `internal/`: defines the _core domain_.
- [ ] `/`: a concrete _repository_ used by the domain, for example `postgresql`
- [ ] `http/`: defines HTTP Handlers.
- [ ] `service/`: orchestrates use cases and manages transactions.
- [X] `pkg/` public API meant to be imported by other Go package.
There are cases where requiring a new bounded context is needed, in those cases the recommendation would be to
define a package like `internal/` that then should follow the same structure, for example:
* `internal//`
* `internal//`
* `internal//http`
* `internal//service`
## Tools
Please refer to the documentation in [internal/tools/](internal/tools/README.md).
## Features
Icons meaning:
*
means a link to Youtube video.
*
means a link to Blog post.
In no particular order:
- [X] Project Layout [
](https://youtu.be/LUvid5TJ81Y) [
](https://mariocarrion.com/2021/03/21/golang-microservices-domain-driven-design-project-layout.html)
- [X] Dependency Injection [
](https://youtu.be/Z89UU4vSayY)
- [X] [Secure Configuration](docs/SECURE\_CONFIGURATION.md)
- [X] Using [Hashicorp Vault](https://www.hashicorp.com/products/vault) [
](https://youtu.be/7UmJR0dOkjM)
- [X] Using [AWS SSM](https://aws.amazon.com/systems-manager/features/#Parameter_Store) [
](https://mariocarrion.com/2019/11/20/golang-aws-ssm-env-vars-package.html)
- [ ] Infrastructure as code
- [X] [Metrics, Traces and Logging using OpenTelemetry](docs/METRICS\_TRACES\_LOGGING.md) [
](https://youtu.be/bytCFQJ43DE)
- [ ] Caching
- [X] Memcached [
](https://youtu.be/yKI-sy70PwA) [
](https://mariocarrion.com/2021/01/30/tips-building-microservices-in-go-golang-caching-memcached.html)
- [ ] Redis [
](https://youtu.be/wj6-w0DLKRw)
- [X] Persistent Storage
- [X] Repository Pattern [
](https://youtu.be/Z89UU4vSayY) [
](https://mariocarrion.com/2021/04/04/golang-microservices-repository-pattern.html)
- [X] Database migrations [
](https://youtu.be/EavdaeUmn64) [
](https://mariocarrion.com/2021/01/10/golang-tools-for-database-schema-migrations.html)
- [ ] MySQL
- [X] [PostgreSQL](docs/PERSISTENT\_STORAGE.md) [
](https://mariocarrion.com/2021/03/02/tips-building-microservices-in-go-golang-databases-postgresql-conclusion.html)
- [`jmoiron/sqlx`](https://github.com/jmoiron/sqlx), [`jackc/pgx`](https://github.com/jackc/pgx) and [`database/sql`](https://pkg.go.dev/database/sql) [
](https://youtu.be/l8t6UKM1kro) [
](https://mariocarrion.com/2021/02/05/tips-building-microservices-in-go-golang-databases-postgresql-part1.html)
- [`go-gorm/gorm`](https://github.com/go-gorm/gorm) and [`volatiletech/sqlboiler`](https://github.com/volatiletech/sqlboiler) [
](https://youtu.be/CT2v0Xas8Sc) [
](https://mariocarrion.com/2021/02/10/tips-building-microservices-in-go-golang-databases-postgresql-gorm-orm.html)
- [`Masterminds/squirrel`](https://github.com/Masterminds/squirrel) and [`kyleconroy/sqlc`](https://github.com/kyleconroy/sqlc) [
](https://youtu.be/CT2v0Xas8Sc) [
](https://mariocarrion.com/2021/02/23/tips-building-microservices-in-go-golang-databases-postgresql-sqlc-squirrel.html)
- [ ] REST APIs
- [X] HTTP Handlers [
](https://youtu.be/CLdxwJCvTZE) [
](https://mariocarrion.com/2021/04/18/golang-microservices-rest-api-http-handlers.html)
- [X] Custom JSON Types [
](https://youtu.be/UmVYkEYm4hw) [
](https://mariocarrion.com/2021/04/28/golang-microservices-rest-api-custom-json-type.html)
- [ ] Versioning [
](https://youtu.be/4THy4iBQpFA)
- [X] Error Handling [
](https://youtu.be/uQOfXL6IFmQ)
- [X] [OpenAPI 3 and Swagger-UI](docs/OPENAPI3\_SWAGGER.md) [
](https://youtu.be/HwtOAc0M08o) [
](https://mariocarrion.com/2021/05/02/golang-microservices-rest-api-openapi3-swagger-ui.html)
- [ ] Authorization
- [ ] Events and Messaging
- [ ] [Apache Kafka](https://kafka.apache.org/) [
](https://youtu.be/jr7OULxYm0A)
- [ ] [RabbitMQ](https://www.rabbitmq.com/) [
](https://youtu.be/L0yJxCKrkIY)
- [ ] [Redis](https://redis.io/) [
](https://youtu.be/uzuwZNiN4Y8)
- [ ] Testing
- [X] Type-safe mocks with [`maxbrunsfeld/counterfeiter`](https://github.com/maxbrunsfeld/counterfeiter) [
](https://youtu.be/ENqwq64TsDk) [
](https://mariocarrion.com/2019/06/24/golang-tools-counterfeiter.html)
- [X] Equality with [`google/go-cmp`](https://github.com/google/go-cmp) [
](https://youtu.be/ae15DzSwNnU) [
](https://mariocarrion.com/2021/01/22/go-package-equality-google-go-cmp.html)
- [X] Integration tests for Datastores with [`ory/dockertest`](https://github.com/ory/dockertest) [
](https://youtu.be/a-CCceqerhg) [
](https://mariocarrion.com/2021/03/14/golang-package-testing-datastores-ory-dockertest.html)
- [X] REST APIs [
](https://youtu.be/lMrWO7OUMdY) [
](https://mariocarrion.com/2021/04/25/golang-microservices-rest-api-testing.html)
- [ ] Containerization using Docker [
](https://youtu.be/u_ayzie9pAQ)
- [ ] Graceful Shutdown [
](https://youtu.be/VXxe7-b5euo)
- [ ] Search Engine using [ElasticSearch](https://www.elastic.co/elasticsearch/) [
](https://youtu.be/ZrdbQRYst5E)
- [ ] Documentation
- [C4 Model](https://c4model.com/) [
](https://youtu.be/pZ2z2tZkMsE)
- [ ] Cloud Design Patterns
* Reliability
- [ ] [Circuit Breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) [
](https://youtu.be/UnL2iGcD7vE)
- [ ] Tools as Dependencies [
](https://youtu.be/g_5n0W27XcY)
- [ ] Whatever else I forgot to include
## More ideas
* [2016: Peter Bourgon's: Repository structure](https://peter.bourgon.org/go-best-practices-2016/#repository-structure)
* [2016: Ben Johnson's: Standard Package Layout](https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1)
* [2017: William Kennedy's: Design Philosophy On Packaging](https://www.ardanlabs.com/blog/2017/02/design-philosophy-on-packaging.html)
* [2017: Jaana Dogan's: Style guideline for Go packages](https://rakyll.org/style-packages/)
* [2018: Kat Zien - How Do You Structure Your Go Apps](https://www.youtube.com/watch?v=oL6JBUk6tj0)
## Running project locally using Docker Compose
Originally added as part of [Building Microservices In Go: Containerization with Docker](https://youtu.be/u_ayzie9pAQ), `docker compose` has evolved and with it the way to run everything locally. Make sure you are running a recent version of Docker Compose. The configuration in this repository and the instructions below are known to work for at least the following versions:
* Engine: **27.4.0**, and
* Compose: **v2.31.0-desktop.2**
This project takes advantage of [Go's build constrains](https://pkg.go.dev/go/build) and [Docker's arguments](https://docs.docker.com/reference/dockerfile/#arg) to build the ElasticSearch indexers and to run the [rest-server](cmd/rest-server) using any of the following types of message broker:
* Redis (**default one**)
* RabbitMQ
* Kafka
The `docker compose` instructions are executed in the form of:
```
docker compose -f compose.yml -f compose..yml
```
Where:
* ``: Indicates what message broker to use, and effectively match the compose filename itself. The three supported values are:
1. `rabbitmq`,
1. `kafka`, and
1. `redis` (default value when building the `rest-server` binary).
* ``: Indicates the docker compose command to use.
For example to build images using RabbitMQ as the message broker you execute:
```
docker compose -f compose.yml -f compose.rabbitmq.yml build
```
Then to start the containers you execute:
```
docker compose -f compose.yml -f compose.rabbitmq.yml up
```
Once you all the containers are `up` you can access the Swagger UI at http://127.0.0.1:9234/static/swagger-ui/ .
## Diagrams
To start a local HTTP server that serves a graphical editor:
```
mdl serve github.com/MarioCarrion/todo-api/internal/doc -dir docs/diagrams/
```
To generate JSON artifact for uploading to [structurizr](https://structurizr.com/):
```
stz gen github.com/MarioCarrion/todo-api/internal/doc
```