Production-minded Go REST API for movie catalog management with token authentication, role-based permissions, optimistic locking, Swagger docs, database migrations, and end-to-end test coverage.
ScadrialAPI is a backend engineering portfolio project focused on the parts of API development that matter in real systems: clean HTTP boundaries, reliable database workflows, access control, validation, graceful shutdown, background email tasks, and honest operational tradeoffs.
Swagger • Quick Start • Architecture
Many tutorial APIs stop at CRUD. This project goes further and models the kinds of concerns teams actually care about when shipping backend systems:
- token-based authentication with hashed tokens stored in PostgreSQL
- role-based permissions for protected movie endpoints
- request validation and consistent JSON error responses
- optimistic locking to prevent silent overwrite conflicts
- rate limiting, CORS, panic recovery, and graceful shutdown
- activation email delivery via SMTP background jobs
- migration-driven schema management and Swagger-backed API exploration
- Movie CRUD with pagination, filtering, and sorting
- User registration and activation workflow
- Authentication token issuance for API access
- Permission-gated movie read/write actions
- PostgreSQL models with query-level optimistic locking
- Structured runtime configuration via flags and environment variables
expvarmetrics endpoint for basic observability- Generated Swagger docs served by the API at
/swagger/index.html - Unit, handler, and E2E tests already present in the repository
cmd/api/ main application, handlers, routes, middleware, Swagger wiring
internal/data/ models, filters, tokens, permissions, validation helpers
internal/mailer/ SMTP mail delivery
internal/validator/ reusable validation primitives
internal/vcs/ build/version metadata
migrations/ sequential PostgreSQL schema migrations
cmd/api/docs/ generated Swagger JSON/YAML/docs package
metrics -> recoverPanic -> enableCORS -> rateLimit -> authenticate -> router
- API layer:
net/httpplushttprouterhandlers incmd/api - Data layer: PostgreSQL-backed models in
internal/data - Mail delivery: SMTP mailer and activation template in
internal/mailer - Schema evolution: SQL migrations in
migrations - API reference: generated Swagger spec in
cmd/api/docs/swagger.yaml
- Go
1.26.3 - PostgreSQL
migrateCLI- Optional:
direnvfor automatic.envrcloading
Use .env.example as the reference and create or update your local .envrc:
export SCADRIAL_DB_DSN="postgres://username:password@localhost/scadrial?sslmode=disable"
export SMTP_HOST="sandbox.smtp.mailtrap.io"
export SMTP_PORT="25"
export SMTP_USERNAME="your-smtp-username"
export SMTP_PASSWORD="your-smtp-password"
export SMTP_SENDER="ScadrialApi <no-reply@example.com>"Load it with one of these:
source .envrcdirenv allowCreate a local PostgreSQL database named scadrial and make sure SCADRIAL_DB_DSN points to it.
make db/migrations/upThis target asks for confirmation before applying migrations.
make run/apiOnce the server is running, open:
- Swagger UI:
http://localhost:4000/swagger/index.html - Healthcheck:
http://localhost:4000/v1/healthcheck
GET /v1/healthcheckPOST /v1/usersPUT /v1/users/activatedPOST /v1/tokens/authenticationGET /v1/moviesPOST /v1/moviesGET /v1/movies/{id}PATCH /v1/movies/{id}DELETE /v1/movies/{id}
- Register a user with
POST /v1/users - Activate the account with
PUT /v1/users/activated - Obtain a bearer token from
POST /v1/tokens/authentication - Call protected movie endpoints with
Authorization: Bearer <token>
curl -X POST http://localhost:4000/v1/tokens/authentication \
-H "Content-Type: application/json" \
-d '{
"email": "vin@example.com",
"password": "supersecret123"
}'curl http://localhost:4000/v1/movies?page=1&page_size=10 \
-H "Authorization: Bearer YOUR_TOKEN_HERE"For the full request/response schema and interactive exploration, use Swagger at /swagger/index.html or inspect cmd/api/docs/swagger.yaml.
Swagger UI exposes the available route groups, authentication-aware endpoints, and generated request/response models directly from the Go annotations.
The repo already includes a practical Makefile for common tasks.
make run/api
make db/migrations/up
make db/migrations/new name=add_some_feature
make audit
make build/apiKey notes:
make run/apistarts the API usingSCADRIAL_DB_DSNmake db/migrations/new name=...creates paired SQL migration filesmake auditruns dependency checks, vetting, static analysis, and testsmake build/apibuilds local and Linux AMD64 binaries underbin/- this repo vendors dependencies, so dependency changes should be followed by
go mod vendor
Run the normal package tests with:
go test ./...Or run the broader quality pipeline:
make auditE2E tests live under cmd/api and use the e2e build tag plus a dedicated database DSN.
export TEST_DB_DSN="postgres://test:test@localhost/scadrial_test?sslmode=disable"
go test -tags=e2e ./cmd/api/...Notes:
- if
TEST_DB_DSNis not set, the E2E suite falls back topostgres://test:test@localhost/scadrial_test?sslmode=disable - the E2E test harness applies migrations automatically before running
- the suite truncates and reseeds database tables between tests
| Variable | Required | Purpose | Current behavior |
|---|---|---|---|
SCADRIAL_DB_DSN |
Yes | PostgreSQL connection string | Read from environment and used by make run/api |
SMTP_HOST |
No | SMTP host | Defaults to sandbox.smtp.mailtrap.io if unset |
SMTP_PORT |
No | SMTP port | Documented in .env.example, but the app currently defaults to 25 in code |
SMTP_USERNAME |
Yes for email | SMTP username | Read from environment |
SMTP_PASSWORD |
Yes for email | SMTP password | Read from environment |
SMTP_SENDER |
No | From-address for outgoing email | Defaults to ScadrialApi <no-reply@scadrialapi.abdulmoiz.net> |
Reference files:
- graceful shutdown with background task coordination
- panic recovery middleware
- hashed authentication tokens stored in PostgreSQL
- permission checks for protected movie routes
- optimistic locking via model version fields
- per-IP rate limiting
expvarmetrics exposed at/debug/vars- generated Swagger docs exposed through the running API
- rate limiting is in-memory, so it does not coordinate across multiple instances
SMTP_PORTis not yet wired from environment and currently defaults in code/debug/varsis useful for development but should be protected before a public deployment- the project is production-minded, but it does not yet include containerization, CI/CD, or distributed observability
High-value next steps that fit the current architecture:
- tighten security around operational endpoints like
/debug/vars - expand automated test coverage beyond the current handler and E2E footprint
- improve deployment ergonomics with containerization and CI
- evolve observability from
expvarinto more production-friendly metrics - add account lifecycle features such as password reset and token revocation
This repository currently does not include an explicit license file.
The project follows idiomatic Go backend patterns and reflects a strong influence from production-oriented Go API design practices, especially around clear layering, request validation, and operational safety.

