MarioCarrion/todo-api-microservice-example

Go microservice tutorial project using Domain Driven Design and Onion Architecture!

Go

1,345

675 commits

updated Oct 15, 2026

See the code

README

"ToDo API" Microservice Example

codecov

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.

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,
  2. It allows a team to collaborate efficiently with little friction, and
  3. It is as idiomatic as possible.

Join the fun at https://youtube.com/MarioCarrion.

Domain Driven Design

This project uses a lot of the ideas introduced by Eric Evans in his book Domain Driven Design, I do encourage reading that book but before I think reading Domain-Driven Design Distilled makes more sense, also there's a free to download DDD Reference available as well.

On YouTube I created a playlist 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.

  • dockerfiles/: defines all the Dockerfiles used by the different applications used in the project.
  • cmd/
    • <primary-server>/: uses primary database.
    • <replica-server>/: uses readonly databases.
    • <binaryN>/
  • db/
    • migrations/: contains database migrations.
    • seeds/: contains file meant to populate basic database values.
  • internal/: defines the core domain.
    • <datastoreN>/: a concrete repository used by the domain, for example postgresql
    • rest/: defines HTTP Handlers.
    • service/: orchestrates use cases and manages transactions.

There are cases where requiring a new bounded context is needed, in those cases the recommendation would be to define a package like internal/<bounded-context> that then should follow the same structure, for example:

  • internal/<bounded-context>/
    • internal/<bounded-context>/<datastoreN>
    • internal/<bounded-context>/http
    • internal/<bounded-context>/service

Tools

Please refer to the documentation in internal/tools/.

Features

Icons meaning:

  • YouTube video means a link to Youtube video.
  • Blog post means a link to Blog post.

In no particular order:

More ideas

Running project locally using Docker Compose

Originally added as part of Building Microservices In Go: Containerization with Docker, 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 and Docker's arguments to build the ElasticSearch indexers and to run the 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.<type>.yml <command>

Where:

  • <type>: Indicates what message broker to use, and effectively match the compose filename itself. The three supported values are:
    1. rabbitmq,
    2. kafka, and
    3. redis (default value when building the rest-server binary).
  • <command>: 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 all the containers are up you can access the Swagger UI at http://localhost:9234/static/swagger-ui/.

domain-driven-design
golang
microservices
onion-architecture
tutorial

MarioCarrion/todo-api-microservice-example

Go microservice tutorial project using Domain Driven Design and Onion Architecture!

Go

1,345

675 commits

updated Oct 15, 2026

See the code

README

"ToDo API" Microservice Example

codecov

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.

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,
  2. It allows a team to collaborate efficiently with little friction, and
  3. It is as idiomatic as possible.

Join the fun at https://youtube.com/MarioCarrion.

Domain Driven Design

This project uses a lot of the ideas introduced by Eric Evans in his book Domain Driven Design, I do encourage reading that book but before I think reading Domain-Driven Design Distilled makes more sense, also there's a free to download DDD Reference available as well.

On YouTube I created a playlist 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.

  • dockerfiles/: defines all the Dockerfiles used by the different applications used in the project.
  • cmd/
    • <primary-server>/: uses primary database.
    • <replica-server>/: uses readonly databases.
    • <binaryN>/
  • db/
    • migrations/: contains database migrations.
    • seeds/: contains file meant to populate basic database values.
  • internal/: defines the core domain.
    • <datastoreN>/: a concrete repository used by the domain, for example postgresql
    • rest/: defines HTTP Handlers.
    • service/: orchestrates use cases and manages transactions.

There are cases where requiring a new bounded context is needed, in those cases the recommendation would be to define a package like internal/<bounded-context> that then should follow the same structure, for example:

  • internal/<bounded-context>/
    • internal/<bounded-context>/<datastoreN>
    • internal/<bounded-context>/http
    • internal/<bounded-context>/service

Tools

Please refer to the documentation in internal/tools/.

Features

Icons meaning:

  • YouTube video means a link to Youtube video.
  • Blog post means a link to Blog post.

In no particular order:

More ideas

Running project locally using Docker Compose

Originally added as part of Building Microservices In Go: Containerization with Docker, 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 and Docker's arguments to build the ElasticSearch indexers and to run the 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.<type>.yml <command>

Where:

  • <type>: Indicates what message broker to use, and effectively match the compose filename itself. The three supported values are:
    1. rabbitmq,
    2. kafka, and
    3. redis (default value when building the rest-server binary).
  • <command>: 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 all the containers are up you can access the Swagger UI at http://localhost:9234/static/swagger-ui/.

domain-driven-design
golang
microservices
onion-architecture
tutorial

Significant stargazers

Adrian Hesketh

617 followers · starred Feb 2023

김준호

72 followers · starred Aug 2024

suchcodemuchwow

17 followers · starred May 2021

mustiikhalil

75 followers · starred Feb 2025