Go Springfield Bank is a simple digital bank API. Its main purpose is to transfer amounts between internal accounts.
Written in Golang, this project aims to follow Go best practices and the clean architecture for better maintainability, extensibility and testability.
- RESTful endpoints using julienschmidt/httprouter
- JWT-based authentication using golang-jwt/jwt
- Postgres database connection pool using jackc/pgx
- Database migration golang-migrate/migrate
- Environment variables configuration using ilyakaznacheev/cleanenv
- Structured logging with contextual information zerolog
- Error handling with proper HTTP status code
- Idempotent requests
- Metrics/health endpoints with heptiolabs/healthcheck
- OpenAPI/Swagger 2.0 documentation generated with swaggo/swag
- Integration tests with the help of ory/dockertest
A GitHub Action is configured to compile, test, build a docker image and deploy to Heroku.
The application is accessible at https://go-springfield-bank.herokuapp.com/.
You can quickly build and run the application with its dependencies with this command ( requires docker-compose):
make start
You can stop it with:
make stop
The complete API documentation is available at /swagger
.
Demo: https://go-springfield-bank.herokuapp.com/swagger
POST /accounts
- Create an account- accepts the
X-Idempotency-Key
header.
- accepts the
GET /accounts
- Fetch all the accountsGET /accounts/:id/balance
- Get the balance of an account
POST /login
- Authenticate the user and return the access token- The returned
access_token
must be sent in theAuthorization
header for "protected" endpoints using the formatBearer <access_token>
.
- The returned
POST /transfers
- Protected. Transfer money to another account- requires the
Authorization
header. - accepts the
X-Idempotency-Key
header.
- requires the
GET /transfers
- Protected.Fetch all the transfers related to the logged-in account- requires the
Authorization
header.
- requires the
Idempotent requests are very useful to prevent accidentally processing the same request/operation twice.
Some endpoints accept the special header X-Idempotency-Key
.
The client should send a unique key per operation, and if retrying the same operation with the same values it should
send the same key. This application will cache the result of that operation and if another request with the
same X-Idempotency-Key
arrives the cached result will be returned.
Redis is used to cache the idempotent responses.
The monitoring endpoints listen on a different port for security reasons. The monitoring port number can be changed
using the MONITORING_PORT
environment variable.
GET /metrics
- Prometheus metricsGET /ready
- Readiness endpointGET /live
- Liveness endpoint
Here's a simple sequence diagram that shows the roles of Controllers, Use Cases and Repositories, and how they interact with each other:
The application depends on Postgres and Redis servers.
You can get a Postgres and a Redis server up and running quickly by running ( requires docker-compose):
make dev-up
You can shut them down later by running:
make dev-down
You can get the application dependencies by running (requires go 1.11+):
make setup
You can easily run the tests with:
make test
Check definitions and examples of configuration variables used by this app at config/.env.example .
- https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
- https://pusher.com/tutorials/clean-architecture-introduction
- https://dave.cheney.net/2016/08/20/solid-go-design
- https://medium.com/@jfeng45/go-micro-service-with-clean-architecture-application-layout-e6216dbb835a
- https://developpaper.com/go-microservices-with-clean-architecture-program-structure/
- https://medium.com/gdg-vit/clean-architecture-the-right-way-d83b81ecac6
- https://threedots.tech/post/ddd-cqrs-clean-architecture-combined/
- https://hackernoon.com/golang-clean-archithecture-efd6d7c43047
- https://medium.com/rungo/error-handling-in-go-f0125de052f0
- https://medium.com/spectro-cloud/decorating-go-error-d1db60bb9249
- https://marcofranssen.nl/go-webserver-with-graceful-shutdown/
- https://getgophish.com/blog/post/2018-12-02-building-web-servers-in-go/
- https://dev.to/stevensunflash/a-working-solution-to-jwt-creation-and-invalidation-in-golang-4oe4
- https://learn.vonage.com/blog/2020/03/13/using-jwt-for-authentication-in-a-golang-application-dr/
- https://dev.to/omnisyle/simple-jwt-authentication-with-golang-part-3-1ja3
- https://codeburst.io/using-jwt-for-authentication-in-a-golang-application-e0357d579ce2
- https://hackernoon.com/creating-a-middleware-in-golang-for-jwt-based-authentication-cx3f32z8
- https://dev.to/quii/learn-go-by-writing-tests-structs-methods-interfaces--table-driven-tests-1p01
- https://povilasv.me/go-advanced-testing-tips-tricks/
- https://dev.to/johndoe/integration-tests-with-dockertest-and-go-3eda
- https://www.ory.sh/dockertest-gaen-google-apple-exposure-notification-covid-19/
- https://blog.questionable.services/article/testing-http-handlers-go/
- https://medium.com/easyread/integration-test-database-in-golang-using-dockertest-59ed3b35240e
- https://jonnylangefeld.com/blog/how-to-write-a-go-api-part-3-testing-with-dockertest
- https://github.com/golang/go/wiki/CodeReviewComments
- https://github.com/uber-go/guide/blob/master/style.md
- https://12factor.net/
- https://peter.bourgon.org/go-in-production/
- http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/
- https://blog.learngoprogramming.com/gotchas-of-defer-in-go-1-8d070894cb01
- https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa
- https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-iii-36a1ab3d6ef1
- https://blog.learngoprogramming.com/go-functions-overview-anonymous-closures-higher-order-deferred-concurrent-6799008dde7b