A production-ready, containerized Go microservice for managing services and their versions. Built with PostgreSQL, JWT auth, and Swagger.
- RESTful API (CRUD for services & versions)
- Pagination, sorting, filtering
- JWT-based authentication
- OpenAPI docs with Swagger UI
- SQL migrations and seed data
- Dockerized setup (Postgres + Go app)
- Graceful shutdown, health check
- Makefile automation
- Golang 1.24+
- PostgreSQL 15
- Docker + Compose
- JWT (HS256)
- Swaggo (OpenAPI generation)
- sqlx + pq (DB access)
.
├── cmd/server/ # Main Go entrypoint
├── internal/ # Handlers, services, repos, middleware
├── migrations/ # SQL migration files
├── scripts/ # Seeder and token generator
├── docs/ # Auto-generated Swagger files
├── Dockerfile
├── docker-compose.yml
├── Makefile
└── README.md
Make sure you have:
- Docker & Docker Compose
- Go 1.24+
make setupThis will:
- Build and start Postgres
- Run DB migrations
- Seed with 10 services and versions
- Start the Go API
This API uses JWT via Authorization: Bearer <token>.
make tokenCopy the output and use it in:
- Swagger Authorize
curlrequests
http://localhost:8080/swagger/index.htmlGET /healthz → 200 OKmake setup # Full startup: db + migrations + seed + app
make stop # Stop all containers
make token # Generate JWT token
make swag # Regenerate Swagger docs
make run # Run Go app locally (not in Docker)
make test # Run Go testsmake stop
docker volume rm service_catalog_pgdata- Modularity: The app is broken into
handler,service, andrepositorylayers to follow clean architecture principles. This separation simplifies testing and future extension. - Postgres in Docker: Chosen for portability and consistency across environments.
- Seed and Migration Ordering: Managed via
depends_onand health checks in Docker Compose to ensure the database is ready before seeding(idempotent). - Swagger over Postman: Swagger UI provides both documentation and an interactive way to test APIs.
- JWT over sessions: Simpler for stateless microservices and scales better in distributed systems.
- Not all CRUD covered yet: For simplicity, only read endpoints were initially implemented : creation and deletion can be added in a real-world build.
- No ORM: Uses
sqlxfor lighter version and explicit SQL over heavier ORMs like GORM. - Minimal dependencies: To keep the image lean, everything is built into Alpine containers.
