Example Go Rest API with a PostgreSQL database
This repository demonstrates how to fully wire up and deploy a Golang REST API with a PostgreSQL database backend.
The application demonstrates:
REST API
using Echo
PostgreSQL integration
using PGX
Database migrations
using Atlas
Technology Choices
The author of this repository carries opinions about how to best organize an application / repository. Those opinions / choices are described below:
- No ORM (Object Relational Mapper) - Golang has a few ORMs that are popular, in particular GORM and Ent. However, the mapping ability in tools like Scany take care of a lot of tedious work of working with databases (mapping rows to structs). Declaritive SQL in code (imo) is preferable to code generation and clunky SQL-esque APIs.
- Atlas for database migrations. There are 1000 ways to run migrations in golang, and unfortunately there doesn't seem to be a lot of consensus. However, what I enjoy about Atlas is that it includes Terraform support and it allows you to define your schema in an HCL file and it magically figures out how to update your target database. You can see this in
database/schema.hcl
and just a simple atlas schema apply
and your database is now in sync.
- Echo for the REST API - There are a lot of http frameworks in the golang echosystem, including Echo and Gin. Honestly, I found using the docs with Echo simpler, but don't have a strong opinion on the web framework side.
net/http
might be just as good as the other choices, Gin
being pretty popular.
- PGX for database aaccess -
database/sql
would be fine as well, but PGX is PostgreSQL optimized and is a good choice when tied to Postgres.
- Taskfile instead of Makefile - There is nothing inherently wrong with Makefile, Taskfile is a reasonable alternative with simple, validatable YAML syntax
- Pre-commit - makes sure that users cannot commit / push code that isn't up to standards. In this project we check formatting, linting, golang critic, among others to keep the repo tidy.
Pre-requisites
- Install Docker. Used for testing
- Install Taskfile, required to do pretty much anything
- Install Pre-Commit. This project uses pre-commit to ensure code is all nice and tidy before others can see it.
- Install the pre-commit hooks by running
pre-commit install
- Optionally install Atlas. Atlas is used for database migrations. Note: you can skip this step and just rely on docker, as atlas is only needed to explore its abilities
Quick Start
Make sure you have Docker and Taskfile installed...
- Run
task server.run
- Starts up the postgres docker database
- Runs migrations so the database is ready
- Performs a build of the REST API
- Starts the REST API on port 1323. Access on http://localhost:1323
Project Structure
cmd
- this is where the default config and the main app lives
database
- this is where the schema.hcl file lives. Modify this file to alter the database
pkg
- this is where most of the code lives
common
config
- for loading the config file / incorporating environment variable overrides
db
- the underlying database in PGX, and domain specific Repositories
handler
- for handling each of the type of echo requests / routes
models
- core domain model classes, surfaced in the API and used in the Repositories
router
- where we map echo routes to handlers
Running tasks
This project uses Taskfile for running tasks. The following tasks are available
build
- Builds a local executable, outputs to out/bin/gomin
clean
- Cleans up build artifacts, including out, bin, and test reports
d.build
- Builds the docker iamge, marks it as latest
d.down
- Shuts down all docker containers in the docker compose file
d.up
- Starts up all docker containers, builds and runs the API as well
db.migrate
- Runs the database migration, ensures that the local postgres database is running
db.up
- Starts the database WITHOUT migrations
server.run
- Starts the database, runs migrations, builds the server, and starts the server
test
- Runs all of the tests in all of the go source directories
Writing Tests
This project primarily uses E2E tests hitting the API directly and using the docker postres database.
Tests live in pkg/common/router
- create a new xxx_test.go
file as needed
Roadmap
- - Simple REST API
- - Add initial Makefile
- - Add pre-commit
- - Initial database setup
- - Incorpoate database into REST API
- - Integration tests for database
- - E2E tests for REST API
- - Add github build for golang
- - Add docker packaging
- - Add docker image build in Github Actions on Tag
- - Terraform plan for RDS
- - Terraform plan for ECS
- - Github Actions to run terraform and deploy to AWS