This repository is an attempt to combine pragmatic design patterns for developing http servers in Go into an example that can be easily adapted in other projects.
This project follows Hexagonal Architecture (also known as Ports and Adapters). The goal is to decouple the core business logic from external concerns like the database, the HTTP transport layer, or configuration.
- Domain (
internal/todo): This is the heart of the application. It defines theTodoentity and the interfaces (ServiceandRepository) that the rest of the application uses. It has no dependencies on the database or HTTP server. - Service (
internal/todo/service.go): Implements the business logic. It relies on theRepositoryinterface to persist data, but doesn't know how that data is persisted. - Server (
internal/server): The HTTP "Driving Adapter". It handles incoming HTTP requests, parses JSON, validates input, and calls theService. It doesn't know about SQL or database connections. - Storage (
internal/todo/postgres,internal/todo/memory): The "Driven Adapters". These implement theRepositoryinterface defined in the domain. - Composition Root (
cmd/main.go): This is where everything is wired together. It reads config, initializes the database connection, creates the repository, injects it into the service, and injects the service into the HTTP server.
- Dependency Injection: Dependencies are explicitly passed to constructors (e.g.,
NewServer(service),NewService(repo)). This makes testing easier by allowing mocks to be swapped in. - Graceful Shutdown: The server listens for OS interrupt signals and ensures that active requests are completed before shutting down.
- Structured Logging: Uses Go's
log/slogfor structured, context-aware logging. Request IDs are generated in middleware and threaded through the context. - Configuration: 12-factor app style configuration using environment variables.
- Go 1.24+
- Docker (for PostgreSQL)
- Make
-
Setup Configuration:
cp .env_example .env
-
Start the Database:
make build-db
-
Run the Application:
make run
The server will start on
http://localhost:8080. -
Run Tests:
make test
I'm heavily indebted to Mat Ryer for the ideas and patterns in this repository. He was a host of Go Time, has written copiously, and has given a number of talks. That said, I am not proceeding religiously with his suggestions, and there may be aspects of the template that he would agree with. I would love to know what you think about particular decisions, and I'd love to talk about alternatives. As he mentions in this episode of Go Time, his blog posts and talks are meant to be places to draw ideas from, not things to be followed to the letter. The patterns should only be used if they work for you.
