Go Server/API boilerplate using best practices DDD CQRS ES gRPC
Clone or download


Golang API Starter Kit

Build Status Go Report Card codecov license Beerpay Beerpay

Go Server/API boilerplate using best practices, DDD, CQRS, ES, gRPC.


Key concepts:

  1. Rest API
  2. Docker
  3. Kubernetes
  4. Helm chart
  5. gRPC
  6. Domain Driven Design (DDD)
  7. CQRS
  8. Event Sourcing
  9. Hexagonal, Onion, Clean Architecture

Worth getting to know packages used in this boilerplate:

  1. gorouter
  2. message-bus


This repository was created for personal use and needs, may contain bugs. If found please report. If you think some things could be done better, or if this repository is missing something feel free to contribute and create pull request.


Want to contribute ? Feel free to send pull requests!

Have problems, bugs, feature ideas? We are using the github issue tracker to manage them.


Getting started


In order to run this project you need to have Docker > 1.17.05 for building the production image and Kubernetes cluster > 1.11 for running pods installed.


➜  go-api-boilerplate git:(master) ✗ make help
version                        Show version
key                            [HTTP] Generate key
cert                           [HTTP] Generate self signed certificate
docker-build                   [DOCKER] Build given container. Example: `make docker-build BIN=user`
docker-run                     [DOCKER] Run container on given port. Example: `make docker-run BIN=user PORT=3000`
docker-stop                    [DOCKER] Stop docker container. Example: `make docker-stop BIN=user`
docker-rm                      [DOCKER] Stop and then remove docker container. Example: `make docker-rm BIN=user`
docker-publish                 [DOCKER] Docker publish. Example: `make docker-publish BIN=user REGISTRY=https://your-registry.com`
docker-tag                     [DOCKER] Tag current container. Example: `make docker-tag BIN=user REGISTRY=https://your-registry.com`
docker-release                 [DOCKER] Docker release - build, tag and push the container. Example: `make docker-release BIN=user REGISTRY=https://your-registry.com`
helm-install                   [HELM] Deploy the Helm chart for service. Example: `make helm-install BIN=user`
helm-upgrade                   [HELM] Update the Helm chart for service. Example: `make helm-upgrade BIN=user`
helm-history                   [HELM] See what revisions have been made to the service's helm chart. Example: `make helm-history BIN=user`
helm-dependencies              [HELM] Update helm chart's dependencies for service. Example: `make helm-dependencies BIN=user`
helm-delete                    [HELM] Delete helm chart for service. Example: `make helm-delete BIN=user`
helm-install-app               [HELM] Deploy the Helm chart for application. Example: `make helm-install-app`
helm-upgrade-app               [HELM] Update the Helm chart for application. Example: `make helm-upgrade-app`
helm-history-app               [HELM] See what revisions have been made to the application's helm chart. Example: `make helm-history-app`
helm-dependencies-app          [HELM] Update helm chart's dependencies for application. Example: `make helm-dependencies-app`
helm-delete-app                [HELM] Delete helm chart for application. Example: `make helm-delete-app`
telepresence-swap-local        [TELEPRESENCE] Replace the existing deployment with the Telepresence proxy for local process. Example: `make telepresence-swap-local BIN=user PORT=3000 DEPLOYMENT=go-api-boilerplate-user`
telepresence-swap-docker       [TELEPRESENCE] Replace the existing deployment with the Telepresence proxy for local docker image. Example: `make telepresence-swap-docker BIN=user PORT=3000 DEPLOYMENT=go-api-boilerplate-user`
aws-repo-login                 [HELPER] login to AWS-ECR


The Dashboard UI is not deployed by default. To deploy it, run the following command:

kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml

You can access Dashboard using the kubectl command-line tool by running the following command:

kubectl proxy

Kubectl will handle authentication and make Dashboard available at http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/. The UI can only be accessed from the machine where the command is executed. See kubectl proxy --help for more options.

Helm charts

Helm chart are used to automate the application deployment in a Kubernetes cluster. Once the application is deployed and working, it also explores how to modify the source code for publishing a new application release and how to perform rolling updates in Kubernetes using the Helm CLI.

To deploy application on Kubernetes using Helm you will typically follow these steps:

Step 1: Add application to cmd directory Step 2: Build the Docker image Step 3: Publish the Docker image Step 4: Create the Helm Chart Step 5: Deploy the application in Kubernetes Step 6: Update the source code and the Helm chart

Install And Configure Helm And Tiller


Build the module. This will automatically add missing or unconverted dependencies as needed to satisfy imports for this particular build invocation

go build ./...

For more read: https://github.com/golang/go/wiki/Modules


To run services repeat following steps for each service defined in ./cmd/ directory. Changing BIN= value to directory name from ./cmd/{service_name} path.

STEP 1. Build docker image

make docker-build BIN=user

STEP 2. Deploy

  • Install dependencies
make helm-install-app
  • Deploy to kubernetes cluster
make helm-install-app

This will deploy every service to the kubernetes cluster using your local docker image (built in the first step). helm-{command}-app Uses global helm chart for the whole application that defines all requirements: each service defined in ./cmd/ directory and other external services required to run complete environment like mysql. For more details please see helm chart

STEP 3. Debug

To debug deployment you can simply use telepresence and swap kubernetes deployment for local go service or local docker image. For example to swap for local docker image run:

make telepresence-swap-docker BIN=user PORT=3001 DEPLOYMENT=go-api-boilerplate-user

This command should swap deployment giving similar output to the one below:

➜  go-api-boilerplate git:(master) ✗ make telepresence-swap-docker BIN=user PORT=3001 DEPLOYMENT=go-api-boilerplate-user
telepresence \
	--swap-deployment go-api-boilerplate-user \
	--docker-run -i -t --rm -p=3001:3001 --name="user" user:latest
T: Volumes are rooted at $TELEPRESENCE_ROOT. See https://telepresence.io/howto/volumes.html for
T: details.
2019/01/10 06:24:37.963250 INFO:  [user CommandBus|Subscribe]: *user.RegisterWithEmail
2019/01/10 06:24:37.963332 INFO:  [user CommandBus|Subscribe]: *user.RegisterWithGoogle
2019/01/10 06:24:37.963357 INFO:  [user CommandBus|Subscribe]: *user.RegisterWithFacebook
2019/01/10 06:24:37.963428 INFO:  [user CommandBus|Subscribe]: *user.ChangeEmailAddress
2019/01/10 06:24:37.963445 INFO:  [user EventBus|Subscribe]: *user.WasRegisteredWithEmail
2019/01/10 06:24:37.963493 INFO:  [user EventBus|Subscribe]: *user.WasRegisteredWithGoogle
2019/01/10 06:24:37.963540 INFO:  [user EventBus|Subscribe]: *user.WasRegisteredWithFacebook
2019/01/10 06:24:37.963561 INFO:  [user EventBus|Subscribe]: *user.EmailAddressWasChanged
2019/01/10 06:24:37.964452 INFO:  [user] running at
2019/01/10 06:30:16.266108 INFO:  [user] shutting down...
2019/01/10 06:30:16.283392 INFO:  [user] gracefully stopped
T: Exit cleanup in progress
# --docker-run --rm -it -v -p=3001:3001 user:latest

STEP 4. Test example

Send example JSON via POST request

curl -d '{"email":"test@test.com"}' -H "Content-Type: application/json" -X POST http://localhost:3000/users/dispatch/register-user-with-email

proxy pod logs should look something like:

2019/01/06 09:37:52.453329 INFO:  [POST Request|Start]: /dispatch/register-user-with-email
2019/01/06 09:37:52.461655 INFO:  [POST Request|End] /dispatch/register-user-with-email 8.2233ms

user pod logs should look something like:

2019/01/06 09:37:52.459095 DEBUG: [user CommandBus|Publish]: *user.RegisterWithEmail &{Email:test@test.com}
2019/01/06 09:37:52.459966 DEBUG: [user EventBus|Publish]: *user.WasRegisteredWithEmail {"id":"4270a1ca-bfba-486a-946d-9d7b8a893ea2","email":"test@test.com"}
2019/01/06 09:37:52 [user EventHandler] {"id":"4270a1ca-bfba-486a-946d-9d7b8a893ea2","email":"test@test.com"}