A production-ready Go API boilerplate built with Gin, GORM, and Uber FX. This skeleton provides a clean architecture, dependency injection, comprehensive middleware, and best practices for building scalable REST APIs.
📖 See ARCHITECTURE.md for detailed architectural patterns and best practices.
- 🏗️ Clean Architecture: Layered architecture with Handler → Service → Repository pattern
- 🔌 Dependency Injection: Uber FX for dependency management and lifecycle
- 🔐 Authentication: JWT-based authentication with access and refresh tokens
- 🛡️ Security: Input sanitization, CORS, rate limiting, XSS protection
- 📊 Database: PostgreSQL with GORM, migrations, and transaction support
- 📝 Logging: Structured logging with logrus and file rotation
- ✅ Validation: Request validation with go-playground/validator
- 🔄 Case Conversion: Automatic camelCase ↔ snake_case conversion
- 🏥 Health Checks: Database connectivity health endpoint
- 🎯 Request Tracing: Request ID middleware for distributed tracing
- ⚡ Performance: Connection pooling, optimized middleware, buffer pooling
- 📚 API Documentation: Interactive Swagger/OpenAPI documentation
gin-skeleton/
├── cmd/
│ └── api/
│ └── main.go # Application entry point
├── database/
│ └── migrations/ # Database migrations
├── docker/
│ └── web.Dockerfile # Docker configuration
├── internal/
│ ├── auth/ # Auth domain (handler, DTOs, requests)
│ ├── user/ # User domain (handler, DTOs, request, model)
│ ├── refresh_token/ # Refresh token domain (model, DTO)
│ ├── health/ # Health handler
│ ├── bootstrap/ # Application bootstrap with FX (modules wiring domains)
│ ├── config/ # Configuration management
│ ├── constant/ # Application constants
│ ├── logger/ # Logging utilities
│ ├── middleware/ # HTTP middlewares
│ ├── repository/ # Data access layer (domain-scoped subfolders)
│ ├── response/ # Response helpers
│ ├── router/ # Route definitions
│ ├── service/ # Business logic layer (domain-scoped subfolders)
│ ├── utils/ # Utility functions
│ └── validator/ # Validation logic
├── docker-compose.yml # Docker Compose configuration
├── env.example # Environment variables template
├── go.mod # Go module dependencies
├── Makefile # Build and migration commands
└── README.md # This file
The application follows a clean architecture pattern:
┌─────────────────────────────────────────┐
│ HTTP Handlers (API Layer) │
│ - Request validation │
│ - Response formatting │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Services (Business Logic) │
│ - Business rules │
│ - Transaction management │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Repositories (Data Access) │
│ - Database operations │
│ - Query optimization │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Database (PostgreSQL) │
└─────────────────────────────────────────┘
- Go 1.25.0 or higher
- PostgreSQL 12 or higher
- Make (optional, for using Makefile commands)
- golang-migrate CLI (for database migrations)
-
Clone the repository
git clone <repository-url> cd gin-skeleton
-
Install dependencies
go mod download
-
Set up environment variables
cp env.example .env # Edit .env with your configuration -
Install migration tool (if not already installed)
make install-migrate # Or manually: brew install golang-migrate (macOS) -
Run database migrations
make migrate-up
-
Start the application
go run cmd/api/main.go
The API will be available at http://localhost:8000
Generate repository, service, and fx module wiring from stubs:
make scaffold name=bookThis creates:
internal/repository/book/book_repository.go(+ interface)internal/service/book/book_service.go(+ interface)internal/bootstrap/modules/book_module.go
Notes:
- The
nameargument is converted to lower-case for packages and PascalCase for types. - You still need to add the model in
internal/modelsand, if needed, handlers/DTOs.
The application uses environment variables for configuration. Copy env.example to .env and configure:
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password
DB_NAME=your_database
DB_SSL_MODE=disableSERVER_PORT=8000
SERVER_READ_TIMEOUT=10s
SERVER_WRITE_TIMEOUT=10sJWT_SECRET_KEY=your-super-secret-jwt-key-change-in-production
JWT_ACCESS_EXPIRY=168h # 7 days
JWT_REFRESH_EXPIRY=720h # 30 daysInteractive API documentation is available at:
http://localhost:8000/swagger/index.html
The Swagger UI provides:
- Complete API endpoint documentation
- Request/response schemas
- Try-it-out functionality
- Authentication support (JWT Bearer tokens)
# Generate Swagger documentation
make swagger
# Or manually
swag init -g cmd/api/main.go -o ./docsGET /ping- Health check (simple)GET /health- Health check with database connectivityGET /swagger/*any- Swagger API documentationPOST /api/auth/login- User loginPOST /api/auth/refresh- Refresh access tokenGET /api/users- List users (paginated)GET /api/users/:id- Get user by IDPOST /api/users- Create new user
PUT /api/users/:id- Update userDELETE /api/users/:id- Delete user
make migrate-create NAME=create_products_tablemake migrate-upmake migrate-downmake migrate-down-allmake migrate-statusmake migrate-freshThe application includes the following middleware (executed in order):
- CORS Middleware - Handles Cross-Origin Resource Sharing
- Request ID Middleware - Generates unique request IDs for tracing
- Logging Middleware - Structured request/response logging
- Sanitize Middleware - XSS prevention through input sanitization
- Case Converter Middleware - Converts camelCase ↔ snake_case
- Error Handler Middleware - Centralized error handling
- Rate Limiting - Applied to authentication endpoints (10 req/min)
- JWT Auth Middleware - Validates JWT tokens for protected routes
The application uses JWT tokens for authentication:
-
Login:
POST /api/auth/loginwith email and password- Returns access token and refresh token
-
Protected Routes: Include token in Authorization header
Authorization: Bearer <access_token> -
Refresh Token:
POST /api/auth/refreshwith refresh token- Returns new access token
go run cmd/api/main.gogo build -o bin/api cmd/api/main.gogo test ./...make swagger
# Or
swag init -g cmd/api/main.go -o ./docsAfter generating, access the documentation at http://localhost:8000/swagger/index.html
go fmt ./...golangci-lint rundocker build -f docker/web.Dockerfile -t gin-skeleton .docker-compose upLogs are written to the logs/ directory:
app.log- General application logserrors.log- Error logs only
Logs are rotated daily and kept for 30 days. Logs are also rotated when they exceed 100MB.
The application uses structured error handling:
- Validation Errors (422): Invalid input data
- Not Found (404): Resource not found
- Unauthorized (401): Authentication required
- Forbidden (403): Insufficient permissions
- Internal Error (500): Server errors
All errors follow a consistent format:
{
"success": false,
"message": "Error message",
"description": "Detailed description",
"data": {}
}- Password Hashing: bcrypt with default cost
- JWT Tokens: HS256 signing with configurable expiry
- Input Sanitization: XSS prevention via bluemonday
- Rate Limiting: Protection against brute force attacks
- CORS: Configurable cross-origin resource sharing
- Request ID: Distributed tracing support
- Always use context.Context for cancellation and timeouts
- Use transactions for multi-step database operations
- Validate all inputs using the validator package
- Handle errors properly using the exception package
- Use structured logging with appropriate log levels
- Follow the repository pattern for data access
- Keep business logic in services, not handlers
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is open source and available under the MIT License.
For issues and questions, please open an issue on the repository.