Skip to content

devituz/golang-example

Repository files navigation

go-lang-example

A production-ready Go API template — Gin for HTTP, lagodev for the ORM/migrations, with batteries included: PostgreSQL, Redis cache, MinIO storage, WebSocket events, API versioning, Swagger docs and a hardened Docker setup.

Designed to be copied into a real project and renamed in minutes.

Features

  • Gin HTTP framework with versioned route groups (/api/v1, /api/v2).
  • lagodev ORM, migrations, and schema DSL (PostgreSQL via pgx).
  • Redis transparent read-through cache (pkg/cache) with automatic invalidation.
  • MinIO S3-compatible object storage (pkg/storage) with size + MIME validation.
  • WebSocket topic-based pub/sub hub (pkg/ws) — order events broadcast in real time.
  • Swagger / OpenAPI auto-generated from handler annotations (swaggo).
  • DTO layer keeps DB models out of the wire format, with gin-validator rules.
  • Per-request middleware: request ID, structured slog access logs, panic recovery, security headers, allowlist CORS, body size limit, request timeout, IP token-bucket rate limit, admin API-key auth (constant-time compare).
  • Graceful shutdown with configurable boot / shutdown windows.
  • Multi-stage Dockerfile (pure-Go, non-root, distroless-style) + docker compose (postgres + redis + minio + app).
  • Fail-closed production checks: refuses to start with CORS=* or default admin key in APP_ENV=production.

Project layout

.
├── main.go                       # entrypoint + Swagger header + graceful shutdown
├── lago.json                     # lagodev generator paths
├── api/
│   ├── v1/                       # first-generation API
│   │   ├── controllers/          # Gin handlers (with @Swagger annotations)
│   │   ├── services/             # business logic, lagodev ORM
│   │   ├── dto/                  # request/response structs + validation
│   │   └── routes.go             # mounts under <API_PREFIX>/v1
│   └── v2/                       # starter stub for the next version
├── routes/api.go                 # top-level orchestrator (health, swagger, v1, v2)
├── models/                       # shared DB models (lagodev orm.Model)
├── migrations/                   # schema migrations (lagodev schema DSL)
├── middleware/                   # cross-cutting Gin middleware
├── pkg/
│   ├── apperror/                 # typed application errors
│   ├── response/                 # consistent JSON envelope
│   ├── cache/                    # Cache interface + Redis + Noop drivers
│   ├── storage/                  # Storage interface + MinIO driver
│   └── ws/                       # WebSocket hub
├── config/                       # env loaders (uses lagodev/config)
├── docs/                         # generated by `make swagger`
├── factories/  seeders/  tests/  # lagodev convention dirs
├── Dockerfile  docker-compose.yml
└── Makefile

Quick start

# 1. Clone and prep .env
cp .env.example .env

# 2. Boot the data plane (postgres + redis + minio)
make docker-up        # or: docker compose up -d

# 3. Run the API locally
make run              # http://localhost:8080

Swagger UI: http://localhost:8080/swagger/index.html
MinIO console: http://localhost:9001

Sample requests

APIKEY="local-dev-admin-key"

# Public read
curl http://localhost:8080/api/v1/products

# Admin write (requires X-API-Key)
curl -X POST http://localhost:8080/api/v1/admin/categories \
  -H "X-API-Key: $APIKEY" -H 'Content-Type: application/json' \
  -d '{"name":"Espresso","slug":"espresso"}'

# Place an order (public)
curl -X POST http://localhost:8080/api/v1/orders \
  -H 'Content-Type: application/json' \
  -d '{"customer_name":"Ali","phone":"+998901112233","items":[{"product_id":1,"quantity":2}]}'

# Upload an image
curl -X POST http://localhost:8080/api/v1/admin/uploads/image \
  -H "X-API-Key: $APIKEY" -F "file=@photo.png;type=image/png"

# Subscribe to real-time order events
websocat ws://localhost:8080/api/v1/ws?topics=orders

Configuration

Everything is .env-driven. See .env.example for the full annotated list. Highlights:

Variable Purpose
APP_ENV local or production (production triggers fail-closed checks)
APP_HOST / APP_PORT Network bind
API_PREFIX Mount point for versioned routes (default /api)
ADMIN_API_KEY Required for any /admin/* route
CORS_ALLOWED_ORIGINS Comma-separated origins; * blocked in production
RATE_LIMIT_RPS / _BURST Per-client-IP token bucket
DB_* PostgreSQL connection + pool + logging
REDIS_* Cache (set REDIS_ENABLED=false to fall back to noop)
MINIO_* Object storage (set MINIO_ENABLED=false to disable uploads)

Adding a new API version

  1. Copy api/v1/{controllers,services,dto} into api/v2/.
  2. Adjust imports to api/v2/....
  3. Edit api/v2/routes.go to register the new endpoints.
  4. Nothing else changes — routes/api.go already calls v2.Register.

Both versions ship from the same binary; clients migrate at their own pace.

Make targets

make help          # list targets
make run           # local dev
make build         # generate Swagger + build ./bin/app
make swagger       # regenerate OpenAPI docs from annotations
make test          # go test -race
make docker-up     # docker compose up -d --build
make docker-down   # docker compose down
make docker-logs   # tail app logs

Renaming for your own project

  1. Replace the module path in go.mod and re-run go mod tidy:
    sed -i '' "s|github.com/devituz/go-lang-example|github.com/your-org/your-app|g" $(grep -rEl 'github.com/devituz/go-lang-example' .)
  2. Update APP_NAME, POSTGRES_DB, REDIS_PREFIX, MINIO_BUCKET in .env.
  3. Drop or rename the example Category / Product / Order models to match your domain.
  4. Regenerate Swagger: make swagger.

License

MIT.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors