A modern RESTful API for managing cars and engines built with Go, featuring distributed tracing, JWT authentication, and PostgreSQL database integration.
- Features
- Tech Stack
- Project Structure
- Prerequisites
- Installation
- Configuration
- Usage
- API Endpoints
- Authentication
- Database Schema
- Monitoring & Tracing
- Docker Deployment
- Development
- Contributing
- RESTful API for car and engine management
- JWT Authentication with middleware protection
- PostgreSQL database integration
- Distributed Tracing with OpenTelemetry and Jaeger
- Docker containerization with Docker Compose
- Clean Architecture with separation of concerns
- CRUD operations for cars and engines
- Foreign key relationships between cars and engines
- Input validation and error handling
- Automatic database schema initialization
- Backend: Go 1.24
- Database: PostgreSQL
- Authentication: JWT (JSON Web Tokens)
- Tracing: OpenTelemetry + Jaeger
- Containerization: Docker & Docker Compose
- HTTP Router: Gorilla Mux
- Database Driver: lib/pq (PostgreSQL driver)
carzone/
βββ main.go # Application entry point
βββ docker-compose.yml # Docker services configuration
βββ Dockerfile # Application container
βββ go.mod # Go module dependencies
βββ go.sum # Go module checksums
βββ driver/
β βββ postgres.go # Database connection
βββ handlers/
β βββ auth/
β β βββ login.go # Authentication handler
β βββ car/
β β βββ car.go # Car CRUD handlers
β βββ engine/
β βββ engine.go # Engine CRUD handlers
βββ middlewares/
β βββ auth.go # JWT authentication middleware
βββ models/
β βββ car.go # Car model and validation
β βββ engine.go # Engine model and validation
βββ services/
β βββ services.go # Service interfaces
β βββ car/
β β βββ car.go # Car business logic
β βββ engine/
β βββ engine.go # Engine business logic
βββ store/
βββ schema.sql # Database schema and seed data
βββ store.go # Store interfaces
βββ car/
β βββ car.go # Car data access layer
βββ engine/
βββ engine.go # Engine data access layer
- Go 1.24 or higher
- Docker and Docker Compose
- PostgreSQL (if running locally without Docker)
-
Clone the repository
git clone https://github.com/mustaphalimar/carzone.git cd carzone -
Start the services
docker-compose up -d
This will start:
- PostgreSQL database on port
1021 - CarZone API on port
8080 - Jaeger tracing UI on port
16686
- PostgreSQL database on port
-
Clone and install dependencies
git clone https://github.com/mustaphalimar/carzone.git cd carzone go mod download -
Set up environment variables
cp .env.example .env # Edit .env with your configuration -
Start PostgreSQL (using Docker)
docker run --name carzone_db -e POSTGRES_PASSWORD=root -e POSTGRES_DB=postgres -p 1021:5432 -d postgres
-
Run the application
go run main.go
Create a .env file in the root directory:
# Database Configuration
DB_HOST=localhost
DB_PORT=1021
DB_USER=postgres
DB_PASSWORD=root
DB_NAME=postgres
# Application Configuration
PORT=8080
# JWT Configuration (optional)
JWT_SECRET=your-secret-key
# Jaeger Configuration
JAEGER_AGENT_HOST=localhost
JAEGER_AGENT_PORT=4318When using Docker Compose, the environment variables are already configured in docker-compose.yml.
The API will be available at http://localhost:8080
-
Login to get JWT token
curl -X POST http://localhost:8080/login \ -H "Content-Type: application/json" \ -d '{"username": "admin", "password": "admin123"}'
-
Use the token for authenticated requests
curl -X GET http://localhost:8080/cars \ -H "Authorization: Bearer YOUR_JWT_TOKEN"
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /login |
User login | β |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /cars/{id} |
Get car by ID | β |
| GET | /cars |
Get cars by brand | β |
| POST | /cars |
Create new car | β |
| PUT | /cars/{id} |
Update car | β |
| DELETE | /cars/{id} |
Delete car | β |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /engines/{id} |
Get engine by ID | β |
| POST | /engines |
Create new engine | β |
| PUT | /engines/{id} |
Update engine | β |
| DELETE | /engines/{id} |
Delete engine | β |
Create a new engine:
curl -X POST http://localhost:8080/engines \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"displacement": 2000,
"numOfCylinders": 4,
"carRange": 600
}'Create a new car:
curl -X POST http://localhost:8080/cars \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Toyota Camry",
"year": "2024",
"brand": "Toyota",
"fuelType": "Gasoline",
"engine": {
"id": "engine-uuid-here"
},
"price": 28000.00
}'The API uses JWT (JSON Web Tokens) for authentication:
- Default credentials:
username: admin,password: admin123 - Token expiration: 24 hours
- Header format:
Authorization: Bearer <token>
All endpoints except /login require authentication.
CREATE TABLE cars (
id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
year VARCHAR(4) NOT NULL,
brand VARCHAR(255) NOT NULL,
fuel_type VARCHAR(50) NOT NULL,
engine_id UUID NOT NULL,
price DECIMAL(10, 2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (engine_id) REFERENCES engines(id) ON DELETE CASCADE
);CREATE TABLE engines (
id UUID PRIMARY KEY,
displacement INT NOT NULL,
num_of_cylinders INT NOT NULL,
car_range INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);The application automatically creates sample data:
- 4 sample engines with different specifications
- 4 sample cars (Honda Civic, Toyota Corolla, Ford Mustang, BMW 3 Series)
CarZone includes distributed tracing with OpenTelemetry and Jaeger:
- Jaeger UI: http://localhost:16686
- Service name:
carzone - Automatic instrumentation for HTTP requests and database operations
- HTTP request/response cycles
- Database queries and operations
- Business logic execution
- Error tracking and performance metrics
The docker-compose.yml includes:
-
PostgreSQL Database
- Image:
postgres:latest - Port:
1021:5432 - Volume:
postgres_data
- Image:
-
CarZone Application
- Built from
Dockerfile - Port:
8080:8080 - Depends on database
- Built from
-
Jaeger Tracing
- Image:
jaegertracing/all-in-one:latest - UI Port:
16686:16686 - Agent Port:
4318:4318
- Image:
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f app
# Stop services
docker-compose down
# Rebuild and restart
docker-compose up --build -dThe project follows Clean Architecture principles:
- Handlers - HTTP request/response handling
- Services - Business logic implementation
- Store - Data access layer
- Models - Domain entities and validation
- Driver - Database connection management
- Middlewares - Cross-cutting concerns (auth, logging)
- Define model in
models/ - Create store interface and implementation in
store/ - Implement service logic in
services/ - Add HTTP handlers in
handlers/ - Register routes in
main.go
# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run tests with coverage
go test -cover ./...Mustapha Limar
- GitHub: @mustaphalimar
- Gorilla Mux for HTTP routing
- OpenTelemetry for observability
- Jaeger for distributed tracing
- PostgreSQL for the database
Happy Coding! π