Proof of Concept for a RESTful API built with Go and Gin. Manage football player data with SQLite, GORM, Swagger documentation, and in-memory caching.
- Features
- Tech Stack
- Project Structure
- Architecture
- API Reference
- Prerequisites
- Quick Start
- Testing
- Docker
- Releases
- Environment Variables
- Command Summary
- Contributing
- Legal
- ποΈ Idiomatic Go patterns - Clean architecture with middleware, dependency injection, and concurrency safety
- π Interactive API exploration - Auto-generated Swagger docs with Postman collection and health monitoring
- β‘ Performance optimizations - In-memory caching, connection pooling, and efficient GORM queries
- π§ͺ Comprehensive integration tests - Full endpoint coverage with automated reporting to Codecov and SonarCloud
- π Token-efficient documentation - AGENTS.md + auto-loaded Copilot instructions for AI-assisted development
- π³ Full containerization - Optimized Docker builds with Docker Compose orchestration
- π Complete CI/CD pipeline - Automated testing with race detection, Docker publishing, and GitHub releases
- ποΈ Player-themed semantic versioning - Memorable, alphabetical release names honoring football legends
| Category | Technology |
|---|---|
| Language | Go 1.25 |
| Web Framework | Gin |
| ORM | GORM |
| Database | SQLite |
| Caching | gin-contrib/cache |
| API Documentation | Swagger/OpenAPI |
| Testing | testify |
| Containerization | Docker & Docker Compose |
/
βββ main.go # Entry point: DB connection, route setup, server start
βββ controller/ # HTTP handlers (request/response logic)
β βββ player_controller.go
βββ service/ # Business logic (ORM interactions)
β βββ player_service.go
βββ route/ # Route configuration and middleware
β βββ player_route.go # Route setup with caching middleware
β βββ path.go # Path constants
βββ model/ # Data structures
β βββ player_model.go
βββ data/ # Database connection
β βββ player_data.go
βββ swagger/ # Swagger configuration
β βββ swagger.go
βββ docs/ # Auto-generated Swagger docs (DO NOT EDIT)
β βββ docs.go
β βββ swagger.json
β βββ swagger.yaml
βββ tests/ # Integration tests
β βββ main_test.go
β βββ player_fake.go
β βββ players.json
βββ storage/ # SQLite database file (pre-seeded)
βββ scripts/ # Container entrypoint & healthcheck
βββ .github/workflows/ # CI/CD pipelines
%%{init: {
"theme": "default",
"themeVariables": {
"fontFamily": "Fira Code, Consolas, monospace",
"textColor": "#555",
"lineColor": "#555",
"lineWidth": 2
}
}}%%
graph LR
%% Core application packages
main[main]
route[route]
controller[controller]
service[service]
data[data]
model[model]
%% Supporting features
docs[docs]
swagger[swagger]
%% External dependencies
gin[Gin]
gorm[GORM]
%% Test coverage
tests[tests]
%% Module dependencies (solid arrows = imports)
main --> data
main --> service
main --> controller
main --> route
main --> swagger
main --> docs
route --> controller
controller --> service
service --> data
data --> model
data --> gorm
route --> gin
tests --> main
%% Runtime composition (dotted arrows = main creates/wires)
main -.-> gin
main -.-> service
main -.-> controller
%% Node styling
classDef core fill:#b3d9ff,stroke:#6db1ff,stroke-width:2px,color:#555,font-family:monospace;
classDef support fill:#ffffcc,stroke:#fdce15,stroke-width:2px,color:#555,font-family:monospace;
classDef deps fill:#ffcccc,stroke:#ff8f8f,stroke-width:2px,color:#555,font-family:monospace;
classDef test fill:#ccffcc,stroke:#53c45e,stroke-width:2px,color:#555,font-family:monospace;
class main,route,controller,service,data,model core
class docs,swagger support
class gin,gorm deps
class tests test
Arrow Semantics:
- Solid arrows represent compile-time module dependencies (imports). For example,
controller β servicemeans the controller package imports and uses the service package. - Dotted arrows represent runtime composition. The
mainpackage creates instances (database connection, service, controller, Gin router) and wires them together at startup.
Composition Root Pattern: The main package acts as the composition root, creating all dependencies and the Gin router instance. It registers player routes through the route package and adds Swagger/health routes directly. This pattern enables dependency injection, improves testability, and maintains clear separation of concerns.
Layered Architecture: HTTP requests flow through distinct layers: route β controller β service β data β model. Each layer has a specific responsibility - routes handle HTTP mapping, controllers manage request/response, services contain business logic, data handles persistence, and models define data structures.
Color Coding: Core packages (blue) implement the application logic, supporting features (yellow) provide documentation and utilities, external dependencies (red) are third-party frameworks and ORMs, and tests (green) ensure code quality.
Interactive API documentation is available via Swagger UI at http://localhost:9000/swagger/index.html when the server is running.
π‘ The Swagger documentation is automatically generated from code annotations using swaggo/swag. To regenerate after making changes, run
swag init.
%%{init: {
"theme": "default",
"themeVariables": {
"fontFamily": "Fira Code, Consolas, monospace",
"textColor": "#555",
"lineColor": "#555",
"lineWidth": 2
}
}}%%
graph LR
%% HTTP Request Flow
Client[Client] -->|"HTTP Request"| Route[route]
Route --> Controller[controller]
Controller --> Service[service]
Service --> Data[data]
Data --> DB[(SQLite)]
%% Response Flow
DB --> Data
Data --> Service
Service --> Controller
Controller --> Route
Route -->|"HTTP Response"| Client
%% Middleware
Route -.->|"cache check"| Cache[(In-Memory<br/>Cache)]
Cache -.->|"cached response"| Route
%% Node styling
classDef core fill:#e6ccff,stroke:#9966ff,stroke-width:2px,color:#555,font-family:monospace;
classDef client fill:#ffe6cc,stroke:#ff9933,stroke-width:2px,color:#555,font-family:monospace;
classDef storage fill:#f5f5f5,stroke:#cccccc,stroke-width:2px,color:#555,font-family:monospace;
class Route,Controller,Service,Data core
class Client client
class DB,Cache storage
HTTP request-response cycle: Client β Route β Controller β Service β Data β Database. Responses flow back through the same layers. GET requests are cached for 1 hour to improve performance.
Quick Reference:
GET /players- List all playersGET /players/:id- Get player by IDGET /players/squadnumber/:squadnumber- Get player by squad numberPOST /players- Create new playerPUT /players/:id- Update playerDELETE /players/:id- Remove playerGET /health- Health check
For complete endpoint documentation with request/response schemas, explore the interactive Swagger UI. You can also access the OpenAPI JSON specification at http://localhost:9000/swagger.json.
A pre-configured Postman collection is available at postman-collections/go-samples-gin-restful.postman_collection.json.
Before you begin, ensure you have the following installed:
- Go 1.25 or higher
- Docker & Docker Compose (optional, for containerized deployment)
git clone https://github.com/nanotaboada/go-samples-gin-restful.git
cd go-samples-gin-restfulgo mod downloadgo run .The server will start on http://localhost:9000.
- API:
http://localhost:9000 - Swagger Documentation:
http://localhost:9000/swagger/index.html - Health Check:
http://localhost:9000/health
Run the test suite with coverage:
# Run all tests
go test ./...
# Run tests with coverage
go test -v ./... -coverprofile=coverage.out
# Run tests with detailed coverage for specific packages
go test -v ./... \
-coverpkg=github.com/nanotaboada/go-samples-gin-restful/service,github.com/nanotaboada/go-samples-gin-restful/controller,github.com/nanotaboada/go-samples-gin-restful/route \
-covermode=atomic \
-coverprofile=coverage.out
# View coverage report
go tool cover -html=coverage.outTests are located in the tests/ directory and use testify for integration testing. Coverage reports are generated for controllers, services, and routes only.
Coverage targets: 80% minimum for service, controller, and route packages.
This project includes full Docker support with multi-stage builds and Docker Compose for easy deployment.
docker compose builddocker compose upπ‘ On first run, the container copies a pre-seeded SQLite database into a persistent volume. On subsequent runs, that volume is reused and the data is preserved.
docker compose downTo remove the volume and reinitialize the database from the built-in seed file:
docker compose down -vThe containerized application runs on port 9000 and includes health checks that monitor the /health endpoint every 30 seconds.
This project uses famous football players as release codenames ποΈ, inspired by Ubuntu, Android, and macOS naming conventions.
Releases follow the pattern: v{SEMVER}-{PLAYER} (e.g., v1.0.0-ademir)
- Semantic Version: Standard versioning (MAJOR.MINOR.PATCH)
- Player Name: Alphabetically ordered codename from the famous player list
To create a new release, follow this workflow:
First, document your changes in CHANGELOG.md:
# Move items from [Unreleased] to new release section
# Example: [1.0.0 - Ademir] - 2026-02-15
git add CHANGELOG.md
git commit -m "docs: prepare changelog for v1.0.0-ademir release"
git pushThen create and push the version tag:
git tag -a v1.0.0-ademir -m "Release 1.0.0 - Ademir"
git push origin v1.0.0-ademirThis triggers the CD workflow which automatically:
- Validates the player name
- Builds and tests the project with race detector
- Publishes Docker images to GitHub Container Registry with three tags
- Creates a GitHub Release with auto-generated changelog from commits
π‘ Always update CHANGELOG.md before creating the tag. See CHANGELOG.md for detailed release instructions.
Each release publishes multiple tags for flexibility:
# By semantic version (recommended for production)
docker pull ghcr.io/nanotaboada/go-samples-gin-restful:1.0.0
# By player name (memorable alternative)
docker pull ghcr.io/nanotaboada/go-samples-gin-restful:ademir
# Latest release
docker pull ghcr.io/nanotaboada/go-samples-gin-restful:latestπ‘ See CHANGELOG.md for the complete player list (A-Z) and release history.
The application can be configured using the following environment variables (declared in compose.yaml):
# Database storage path (default: ./storage/players-sqlite3.db)
# In Docker: /storage/players-sqlite3.db
STORAGE_PATH=./storage/players-sqlite3.db
# Gin framework mode: debug, release, or test (default: debug)
# In Docker: release
GIN_MODE=release| Command | Description |
|---|---|
go run . |
Start development server |
go build |
Build the application |
go test ./... |
Run all tests |
go test -v ./... -coverpkg=github.com/nanotaboada/go-samples-gin-restful/service,github.com/nanotaboada/go-samples-gin-restful/controller,github.com/nanotaboada/go-samples-gin-restful/route -covermode=atomic -coverprofile=coverage.out |
Run tests with coverage |
go tool cover -html=coverage.out |
View coverage report |
go fmt ./... |
Format code |
go mod tidy |
Clean up dependencies |
swag init |
Regenerate Swagger documentation |
docker compose build |
Build Docker image |
docker compose up |
Start Docker container |
docker compose down |
Stop Docker container |
docker compose down -v |
Stop and remove Docker volume |
Contributions are welcome! Please read CONTRIBUTING.md for details on the code of conduct and the process for submitting pull requests.
Key guidelines:
- Follow Conventional Commits for commit messages
- Ensure all tests pass (
go test ./...) - Run
go fmtbefore committing - Keep changes small and focused
This project is provided for educational and demonstration purposes and may be used in production environments at your discretion. All referenced trademarks, service marks, product names, company names, and logos are the property of their respective owners and are used solely for identification or illustrative purposes.