A production-ready RESTful API for equipment rental management built with Go's standard library.
goapi.mp4
This API enables users to list equipment for rent, make reservations, and manage the complete rental lifecycle.
- Features
- Architecture
- Tech Stack
- Getting Started
- API Documentation
- API Endpoints
- Authentication
- Database Schema
- Configuration
- Testing
- Project Structure
- Contributing
- License
- User Management: Registration and authentication with JWT tokens
- Equipment Catalog: Full CRUD operations with photo uploads, search, and filtering
- Reservation System: Complete workflow with approval, rejection, cancellation, and completion
- Notification System: Real-time notifications for reservation updates
- API Documentation: Interactive Scalar UI with OpenAPI 3.1 specification
- Pagination: Built-in pagination support for list endpoints
- CORS Support: Configurable cross-origin resource sharing
- Structured Logging: JSON-formatted logs with request tracing
- Graceful Shutdown: Proper handling of server shutdown signals
The project follows a clean architecture pattern with clear separation of concerns:
┌─────────────────────────────────────────────────────────────┐
│ HTTP Layer │
│ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
│ │ CORS │→ │ Logger │→ │ Recovery │→ │ Auth │ │
│ └─────────┘ └──────────┘ └──────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Handler Layer │
│ ┌────────┐ ┌──────┐ ┌───────────┐ ┌─────────────┐ ┌─────┐ │
│ │ Auth │ │ User │ │ Equipment │ │ Reservation │ │Notif│ │
│ └────────┘ └──────┘ └───────────┘ └─────────────┘ └─────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Service Layer │
│ (Business Logic, Validation, Notifications) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Repository Layer │
│ (Data Access, SQL Queries) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PostgreSQL │
└─────────────────────────────────────────────────────────────┘
| Technology | Purpose |
|---|---|
| Go 1.24 | Primary language using standard library net/http |
| PostgreSQL 16 | Relational database for data persistence |
| JWT (HS256) | Stateless authentication |
| Docker | Containerization and deployment |
| Scalar | Interactive API documentation UI |
| OpenAPI 3.1 | API specification format |
- Go 1.24 or higher
- Docker and Docker Compose (recommended)
- PostgreSQL 16 (if running locally without Docker)
- Clone the repository:
git clone https://github.com/abneribeiro/goapi.git
cd goapi- Install dependencies:
go mod downloadThe easiest way to run the application is using Docker Compose:
# Start all services (API + PostgreSQL)
docker-compose up -d
# View logs
docker-compose logs -f api
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -vThe API will be available at http://localhost:8080.
- Start PostgreSQL (using Docker):
docker-compose up -d postgres- Set environment variables:
export DB_HOST=localhost
export DB_PORT=5432
export DB_USER=postgres
export DB_PASSWORD=postgres
export DB_NAME=equipment_rental
export JWT_SECRET=your-secure-secret-key- Run the application from the project root:
# Make sure you're in the project root directory
cd /path/to/goapi
go run ./cmd/apiImportant: Always run the server from the project root directory, not from cmd/api, to ensure proper path resolution for static files (docs, uploads).
- (Optional) Seed the database with sample data:
go run ./scripts/seed/main.goThis creates test users:
| Password | Role | |
|---|---|---|
| owner@example.com | Password123 | owner |
| renter@example.com | Password123 | renter |
| owner2@example.com | Password123 | owner |
Interactive API documentation is available at:
- Scalar UI: http://localhost:8080/docs
- OpenAPI Spec: http://localhost:8080/docs/openapi.yaml
The documentation includes:
- Complete endpoint descriptions
- Request/response examples
- Authentication details
- Try-it-out functionality
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
API health status |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/register |
Register new user |
| POST | /api/v1/auth/login |
Login user |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/users/me |
Required | Get current user profile |
| PUT | /api/v1/users/me |
Required | Update current user profile |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/equipment |
- | List equipment (paginated, filterable) |
| GET | /api/v1/equipment/search |
- | Search equipment |
| GET | /api/v1/equipment/categories |
- | Get available categories |
| GET | /api/v1/equipment/{id} |
- | Get equipment by ID |
| GET | /api/v1/equipment/{id}/availability |
- | Get availability calendar |
| POST | /api/v1/equipment |
Required | Create equipment |
| PUT | /api/v1/equipment/{id} |
Required | Update equipment |
| DELETE | /api/v1/equipment/{id} |
Required | Delete equipment |
| POST | /api/v1/equipment/{id}/photos |
Required | Upload equipment photo |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/reservations |
Required | List my reservations |
| GET | /api/v1/reservations/owner |
Required | List reservations for my equipment |
| GET | /api/v1/reservations/{id} |
Required | Get reservation by ID |
| POST | /api/v1/reservations |
Required | Create reservation |
| PUT | /api/v1/reservations/{id}/approve |
Required | Approve reservation (owner) |
| PUT | /api/v1/reservations/{id}/reject |
Required | Reject reservation (owner) |
| PUT | /api/v1/reservations/{id}/cancel |
Required | Cancel reservation |
| PUT | /api/v1/reservations/{id}/complete |
Required | Complete reservation (owner) |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /api/v1/notifications |
Required | List notifications |
| GET | /api/v1/notifications/unread-count |
Required | Get unread count |
| PUT | /api/v1/notifications/{id}/read |
Required | Mark as read |
| PUT | /api/v1/notifications/read-all |
Required | Mark all as read |
| DELETE | /api/v1/notifications/{id} |
Required | Delete notification |
The API uses JWT (JSON Web Tokens) for authentication. After successful login, include the token in the Authorization header:
Authorization: Bearer <your_token>
Token expiration: 24 hours (configurable via JWT_EXPIRATION_HOURS)
# Login
TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "owner@example.com", "password": "Password123"}' \
| jq -r '.data.token')
# Use token for authenticated requests
curl http://localhost:8080/api/v1/users/me \
-H "Authorization: Bearer $TOKEN"┌─────────────────┐ ┌─────────────────────┐
│ users │ │ equipment │
├─────────────────┤ ├─────────────────────┤
│ id (PK) │◄────│ owner_id (FK) │
│ email (UNIQUE) │ │ id (PK) │
│ password_hash │ │ name │
│ name │ │ description │
│ phone │ │ category │
│ role │ │ price_per_hour │
│ verified │ │ price_per_day │
│ created_at │ │ price_per_week │
│ updated_at │ │ location │
└─────────────────┘ │ latitude/longitude │
│ │ available │
│ │ auto_approve │
│ └─────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────┐
│ reservations │
├─────────────────────────────────────────────┤
│ id (PK) │
│ equipment_id (FK) ─────────────────────────►│
│ renter_id (FK) ─────────────────────────────│
│ start_date, end_date │
│ status (pending/approved/rejected/...) │
│ total_price │
│ cancellation_reason │
└─────────────────────────────────────────────┘
All configuration is done via environment variables:
| Variable | Description | Default |
|---|---|---|
SERVER_HOST |
Server host address | 0.0.0.0 |
SERVER_PORT |
Server port | 8080 |
DB_HOST |
PostgreSQL host | localhost |
DB_PORT |
PostgreSQL port | 5432 |
DB_USER |
Database user | postgres |
DB_PASSWORD |
Database password | postgres |
DB_NAME |
Database name | equipment_rental |
DB_SSLMODE |
PostgreSQL SSL mode | disable |
JWT_SECRET |
JWT signing secret | - |
JWT_EXPIRATION_HOURS |
Token expiration (hours) | 24 |
LOG_LEVEL |
Logging level (debug/info/warn/error) | debug |
UPLOAD_PATH |
File upload directory | ./uploads |
DOCS_PATH |
Documentation files directory | ./docs |
MAX_FILE_SIZE |
Max upload size (bytes) | 10485760 |
You can also create a .env file in the project root for local development.
Run all tests:
go test ./... -vRun tests with coverage:
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out -o coverage.htmlRun specific package tests:
go test ./internal/handler/... -v
go test ./internal/middleware/... -vgoapi/
├── cmd/
│ └── api/
│ └── main.go # Application entry point
├── internal/
│ ├── config/ # Configuration management
│ │ └── config.go
│ ├── database/ # Database connection & migrations
│ │ ├── postgres.go
│ │ └── migrations.go
│ ├── handler/ # HTTP handlers (controllers)
│ │ ├── auth.go
│ │ ├── user.go
│ │ ├── equipment.go
│ │ ├── reservation.go
│ │ ├── notification.go
│ │ └── docs.go
│ ├── middleware/ # HTTP middleware
│ │ ├── auth.go
│ │ ├── cors.go
│ │ ├── logger.go
│ │ └── recovery.go
│ ├── model/ # Data models & DTOs
│ │ ├── user.go
│ │ ├── equipment.go
│ │ ├── reservation.go
│ │ ├── notification.go
│ │ └── response.go
│ ├── pkg/ # Internal packages
│ │ ├── jwt/ # JWT utilities
│ │ ├── logger/ # Structured logging
│ │ ├── pagination/ # Pagination helpers
│ │ └── validator/ # Input validation
│ ├── repository/ # Data access layer
│ │ ├── user.go
│ │ ├── equipment.go
│ │ ├── reservation.go
│ │ └── notification.go
│ ├── router/ # Route configuration
│ │ └── router.go
│ └── service/ # Business logic layer
│ ├── auth.go
│ ├── user.go
│ ├── equipment.go
│ ├── reservation.go
│ └── notification.go
├── docs/
│ └── openapi.yaml # OpenAPI 3.1 specification
├── scripts/
│ └── seed/ # Database seeding
│ └── main.go
├── requests/ # HTTP request test files
├── uploads/ # File upload directory
├── Dockerfile
├── docker-compose.yml
├── go.mod
├── go.sum
└── README.md
┌─────────────┐
│ PENDING │
└──────┬──────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ APPROVED │ │ REJECTED │ │CANCELLED │
└────┬─────┘ └──────────┘ └──────────┘
│
▼
┌───────────┐
│ COMPLETED │
└───────────┘
All API responses follow a consistent format:
Success Response:
{
"success": true,
"data": { ... }
}Paginated Response:
{
"success": true,
"data": [ ... ],
"meta": {
"page": 1,
"per_page": 10,
"total": 100,
"total_pages": 10
}
}Error Response:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human readable message"
}
}- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Built with Go by Abner Ribeiro