Rename the module, proto service, and all identifiers from simple_bank/ SimpleBank to api_tmpl/ApiTmpl, and regenerate the gRPC/gateway/swagger/ mock code accordingly. - Scrub real secrets (SMTP password, auth token secret) from api.env/ api_test.env, untrack them, and add api.env.example/api_test.env.example - Remove committed build artifacts (tmp/main, tmp/build-errors.log, dbml-error.log) and gitignore them going forward - Fix Dockerfile paths (build target, migrations copy) that referenced a stale project layout - Rewrite README to match the actual cmd/ + internal/ structure and add a "using this as a template" section
6.5 KiB
6.5 KiB
api_tmpl
A Go backend service template with a working authentication flow (register, login, email verification, refresh tokens), built to be cloned and renamed for new projects rather than run as-is.
Included out of the box:
- Gin-based HTTP API (
internal/handlers/http) with an equivalent gRPC + grpc-gateway API (internal/handlers/grpc, currently wired up but disabled inmain.go— see below) - PostgreSQL persistence via
sqlc-generated queries (internal/db/sqlc) - Redis + Asynq background task queue, with an example "send verification email" task
- PASETO/JWT auth token issuance and middleware, with role-based access control
- Migrations via
golang-migrate - Swagger/OpenAPI docs, served both via
swaggo(Gin) andgrpc-gateway's generated spec - Bruno API collection for manual testing (
Bruno/)
Using this as a template
- Rename the module: replace
github.com/FernandoJVideira/api_tmplwith your own module path throughout the repo, and updatemodulein go.mod. - Copy the env templates and fill in real values:
At minimum, set a real
cp api.env.example api.env cp api_test.env.example api_test.envAUTH_TOKEN_SECRET(32+ random characters) and, if you plan to use the email-verification worker task, real SMTP credentials. Neitherapi.envnorapi_test.envis tracked in git (see.gitignore) — don't commit real secrets into their place. - If you rename the module or the gRPC service, regenerate the protobuf/gateway/swagger code:
This requires
make proto make mockprotoc,protoc-gen-go,protoc-gen-go-grpc,protoc-gen-grpc-gateway,protoc-gen-openapiv2, andstatikon yourPATH(brew install protobuf, thengo installthe rest — see Makefileprototarget for the exact plugins). - Update
PROJ_NAME/SERVICE_NAMEinapi.envandapi_test.env, and the Swagger metadata in cmd/api/main.go (@title,@description,@contact.email) and proto/service_api_tmpl.proto.
Prerequisites
- Go 1.25+
- PostgreSQL, Redis (or use
docker-compose.ymlfor local instances) sqlc,golang-migrate,air(hot reload) — all optional but expected by theMakefileprotoc+ Go plugins (only needed if you touchproto/*.proto— see above)
Quickstart (development)
- Copy env files and fill in secrets (see Using this as a template).
- Start local Postgres + Redis:
make up - Run DB migrations:
make migrate-up - Run the server with hot reload:
Or without
make serverair:go run ./cmd/api - Verify:
- HTTP API:
http://localhost:8080/api/v1/...(see routes in internal/handlers/http/server.go) - Swagger UI:
http://localhost:8080/swagger/index.html - Redis Commander (from
docker-compose.yml):http://localhost:8081
- HTTP API:
By default main.go only starts the Gin HTTP server and the Asynq task processor — the gRPC
server and grpc-gateway (runGrpcServer / runGatewayServer in
cmd/api/main.go) are implemented but commented out. Uncomment them if you want
the gRPC/gateway path running alongside the Gin server.
Background worker (Asynq)
- Tasks are enqueued by the app and processed by an Asynq server embedded in the same binary.
internal/worker/distributer.go— enqueues tasks (TaskDistributor).internal/worker/processor.go— consumes tasks, registers handlers, configures queue weights.internal/worker/task_send_verify_email.go— example task: sends a verification email after user registration.internal/worker/logger.goadapts Asynq's logger tozerolog; edit it to change log formatting.
Environment variables
See api.env.example for the full list with defaults. Notable ones:
- Server:
HTTP_SERVER_ADDR,GRPC_SERVER_ADDR,ENVIRONMENT,ALLOWED_ORIGINS - Database:
DB_ADDR,MIGRATIONS_URL - Redis:
REDIS_ADDR,REDIS_PASSWORD,REDIS_DB - Auth:
AUTH_TOKEN_SECRET,AUTH_TOKEN_MIN_KEY_SIZE,AUTH_TOKEN_EXP,REFRESH_TOKEN_EXP,AUTH_TOKEN_ISS,AUTH_TOKEN_AUD - Email:
EMAIL_FROM,EMAIL_FROM_NAME,EMAIL_SMTP_PASSWORD - Rate limiter:
RATE_LIMITER_REQS_COUNT,RATE_LIMITER_TIME_FRAME,RATE_LIMITER_ENABLED
Testing
make test # go test -v -cover -short ./...
internal/db/sqlc tests hit a real Postgres instance (make up && make migrate-up first).
Everything else runs against mocks generated with mockgen (make mock).
Project layout
cmd/api/main.go— application entrypoint (wires config, DB, Redis, servers)cmd/db/migrations,cmd/db/query— SQL migrations and queries consumed bysqlcinternal/handlers/http— Gin HTTP handlers, routes, middlewareinternal/handlers/grpc— gRPC server + grpc-gateway wiringinternal/service— business logic shared by both HTTP and gRPC handlersinternal/db/sqlc— generated DB access layer (Storeinterface + queries)internal/auth— PASETO/JWT token makersinternal/security— password hashinginternal/worker— Asynq task distributor/processorinternal/mailer— email sendinginternal/config— env-based configuration (viper)internal/val— request validatorsinternal/domain/role— role constants for RBACpb/— generated protobuf/gRPC/gateway code (regenerate viamake proto)docs/— Swagger/OpenAPI specs and thestatik-embedded swagger UIBruno/— Bruno collection for manually exercising the API
Makefile targets
Run make <target>:
| Target | Description |
|---|---|
test |
Run unit/integration tests |
mock |
Regenerate mocks (Store, TaskDistributor, services) |
up / down / reload |
Manage local Docker Compose infra (Postgres, Redis) |
server |
Run with hot reload (air) |
migration <name> |
Create a new migration file |
migrate-up / migrate-down |
Apply/rollback migrations |
sqlc |
Regenerate internal/db/sqlc from SQL queries |
proto |
Regenerate pb/, docs/swagger, docs/statik from proto/*.proto |
dbdocs / dbschema |
Generate DB docs / SQL schema from docs/db.dbml |
lint |
Run golangci-lint |
Contributing
- Keep changes small and focused; add/update unit tests where appropriate.