Go8
Go + Postgres + Chi Router + sqlx + ent + authentication + testing + opentelemetry Starter Kit for API Development
Install / Use
/learn @gmhafiz/Go8README
Introduction
.,*/(#####(/*,. .,*((###(/*.
.*(%%%%%%%%%%%%%%#/. .*#%%%%####%%%%#/.
./#%%%%#(/,,...,,***. ....... *#%%%#*. ,(%%%#/.
.(#%%%#/. .*(#%%%%%%%##/,. ,(%%%#* ,(%%%#*.
.*#%%%#/. .......... .*#%%%%#(/((#%%%%(, ,/#%%%#(/#%%%#(,
./#%%%(* ,#%%%%%%%%(* .*#%%%#* .*#%%%#, *(%%%%%%%#(,.
./#%%%#* ,(((##%%%%(* ,/%%%%/. .(%%%#/ .*#%%%#(*/(#%%%#/,
,#%%%#(. ,#%%%(* ,/%%%%/. .(%%%#/ ,/%%%#/. .*#%%%(,
*#%%%%(*. ,#%%%(* .*#%%%#* ./#%%%#, ,(%%%#* .(%%%#*
,(#%%%%%##(((##%%%%(* .*#%%%%#(((##%%%%(, .*#%%%##(///(#%%%#/.
.*/###%%%%%%%###(/, .,/##%%%%%##(/,. .*(##%%%%%%##(*,
......... ...... .......
A starter kit for Go API development. Inspired by How I write HTTP services after eight years.
However, I wanted to use chi router which is more common in the community, sqlx for database operations and design towards layered architecture (handler -> business logic -> database).
In short, this kit is a Go + Postgres + Chi Router + sqlx + ent + authentication + testing starter kit for API development.
Motivation
On the topic of API development, there are two opposing camps between using framework (like echo, gin, buffalo) and starting small and only adding features you need through various libraries.
However, the second option isn't that straightforward. you will want to structure your project in such a way that there are clear separation of functionalities for your controller, business logic and database operations. Dependencies need to be injected from outside to inside. Being modular, swapping a library like a router or database library to a different one becomes much easier.
Features
This kit is composed of standard Go library together with some well-known libraries to manage things like router, database query and migration support.
- [x] Framework-less and net/http compatible handlers
- [x] Router/Mux with Chi Router
- [x] Database Operations with sqlx
- [x] Database Operations with ent
- [x] Database migration with goose
- [x] Input validation that returns multiple error strings
- [x] Read all configurations using a single
.envfile or environment variable - [x] Clear directory structure, so you know where to find the middleware, domain, server struct, handle, business logic, store, configuration files, migrations etc.
- [x] (optional) Request log that logs each user uniquely based on host address
- [x] CORS
- [x] Scans and auto-generate Swagger docs using a declarative comments format
- [x] Custom model JSON output
- [x] Filters (input DTO), Resource (output DTO) for pagination parsing and custom response respectively.
- [x] Cache layer
- [x] Authentication using cookie-based session
- [x] Uses Task to simplify various tasks like mocking, linting, test coverage, hot reload etc
- [x] Unit testing of repository, use case, and handler using mocks and dockertest
- [x] Integration testing
- [x] End-to-end test using ephemeral docker containers
- [x] OpenTelemetry with Grafana, otel-collector, Prometheus, Loki, and Jaeger
Quick Start
It is advisable to use the latest supported Go version (>= v1.24). Optionally docker and docker-compose for easier start up. There is a quick guide for Debian in the appendix.
Get it
git clone https://codeberg.com/gmhafiz/go8
cd go8
The application depends on a database. Ideally applications load configurations from environment variable (Method A) or from a vault.
(Method A)
Set values by exporting them into environment variables
export DB_DRIVER=postgres
export DB_HOST=localhost
export DB_PORT=5432
export DB_USER=postgres
export DB_PASS=password
export DB_NAME=go8_db
(Method B)
It is also possible to set them in an .env file. Just make sure this file is ignored in .gitignore because it should never be checked into source control.
Fill in your database credentials in .env by making a copy of env.example first.
cp env.example .env
vim .env
Database
Have a database ready either by installing them yourself or use the following command. The docker-compose-infra.yml will use database credentials set in either .env file or environment variables which is initialized in the previous step. In addition, creating database this way will also create an integration database as well.
docker-compose -f docker-compose-infra.yml up -d postgres
Once the database is up, tables and seed data needs to be created using a migration system with the following command. The seed data is needed for authentication later.
go run cmd/migrate/main.go
go run cmd/seed/main.go
You will see a bunch of dependencies download for a first time run followed by the sql migration files
2023/09/16 19:06:56 connecting to database...
2023/09/16 19:06:56 database connected
2023/09/16 19:06:56 OK 20221213140051_create_books.sql (28.26ms)
2023/09/16 19:06:56 OK 20221213140144_create_authors.sql (19.26ms)
2023/09/16 19:06:56 OK 20221213140219_create_book_authors.sql (13.34ms)
2023/09/16 19:06:56 OK 20230409004013_create_users_table.sql (14.13ms)
2023/09/16 19:06:56 OK 20230409004420_create_sessions_table.sql (9.67ms)
2023/09/16 19:06:56 goose: successfully migrated database to version: 20230409004420
Run the API with the following command.
go run cmd/go8/main.go
You will see the address of the API is running at.
2024/08/20 12:52:43 Starting API version: v0.1.0
{"time":"2024-08-20T12:52:43.809953984+10:00","level":"INFO","msg":"connecting to database... "}
{"time":"2024-08-20T12:52:43.820974939+10:00","level":"INFO","msg":"database connected"}
.,*/(#####(/*,. .,*((###(/*.
.*(%%%%%%%%%%%%%%#/. .*#%%%%####%%%%#/.
./#%%%%#(/,,...,,***. ....... *#%%%#*. ,(%%%#/.
.(#%%%#/. .*(#%%%%%%%##/,. ,(%%%#* ,(%%%#*.
.*#%%%#/. .......... .*#%%%%#(/((#%%%%(, ,/#%%%#(/#%%%#(,
./#%%%(* ,#%%%%%%%%(* .*#%%%#* .*#%%%#, *(%%%%%%%#(,.
./#%%%#* ,(((##%%%%(* ,/%%%%/. .(%%%#/ .*#%%%#(*/(#%%%#/,
,#%%%#(. ,#%%%(* ,/%%%%/. .(%%%#/ ,/%%%#/. .*#%%%(,
*#%%%%(*. ,#%%%(* .*#%%%#* ./#%%%#, ,(%%%#* .(%%%#*
,(#%%%%%##(((##%%%%(* .*#%%%%#(((##%%%%(, .*#%%%##(///(#%%%#/.
.*/###%%%%%%%###(/, .,/##%%%%%##(/,. .*(##%%%%%%##(*,
......... ...... .......
{"time":"2024-08-20T12:52:43.821753831+10:00","level":"INFO","msg":"Serving at 0.0.0.0:3080"}
To use, open a new terminal and follow examples in the examples/ folder
Create a book:
curl -v --request POST 'http://localhost:3080/api/v1/book' \
--header 'Content-Type: application/json' \
--data-raw '{
"title": "Test title",
"image_url": "https://example.com",
"published_date": "2020-07-31T15:04:05.123499999Z",
"description":
"test description"
}'
Retrieve all books:
curl --request GET 'http://localhost:3080/api/v1/book'
To see all available routes, run
go run cmd/route/main.go

To run both unit and integration tests,
go test ./...
For end-to-end tests, run the following docker-compose command. It will run a database, a server, and its table migrations. Then it runs end-to-end program (located in e2e/main.go) against it — all in a self-contained container environment.
docker-compose -f e2e/docker-compose.yml up --build
You will see a bunch of containers being built before the tests are run. The e2e test ends with the following message
go8_e2e_test | 2023/12/30 03:08:04 api is up
go8_e2e_test | 2023/12/30 03:08:04 testEmptyBook passes
go8_e2e_test | 2023/12/30 03:08:04 testAddOneBook passes
go8_e2e_test | 2023/12/30 03:08:04 testGetBook passes
go8_e2e_test | 2023/12/30 03:08:04 testUpdateBook passes
go8_e2e_test | 2023/12/30 03:08:04 testDeleteOneBook passes
go8_e2e_test | 2023/12/30 03:08:04 all tests have passed.
go8_e2e_test exited with code 0
Press Ctrl+C to quit the e2e test and stop all e2e containers.
To remove the containers,
docker-compose -f e2e/docker-compose.yml down
Table of Contents
Related Skills
gh-issues
338.7kFetch GitHub issues, spawn sub-agents to implement fixes and open PRs, then monitor and address PR review comments. Usage: /gh-issues [owner/repo] [--label bug] [--limit 5] [--milestone v1.0] [--assignee @me] [--fork user/repo] [--watch] [--interval 5] [--reviews-only] [--cron] [--dry-run] [--model glm-5] [--notify-channel -1002381931352]
node-connect
338.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
oracle
338.7kBest practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns).
tmux
338.7kRemote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output.
