A comprehensive RESTful API system for managing cars and engines, built with Go. This project demonstrates modern microservices architecture patterns including distributed tracing, metrics collection, and monitoring capabilities.
- Overview
- Features
- Architecture
- Tech Stack
- Project Structure
- Prerequisites
- Getting Started
- API Endpoints
- Observability
- Database Schema
- Environment Variables
- Usage Examples
The Car Management System is a Go-based REST API that provides comprehensive CRUD operations for managing cars and their associated engines. The system includes:
- Authentication: JWT-based authentication for secure API access
- Distributed Tracing: OpenTelemetry integration with Jaeger for request tracing
- Metrics Collection: Prometheus metrics for monitoring application performance
- Visualization: Grafana dashboards for metrics visualization
- Database: PostgreSQL for persistent data storage
- Docker: Containerized deployment with Docker Compose
- β Full CRUD operations for Cars and Engines
- β JWT-based authentication and authorization
- β Request tracing with OpenTelemetry and Jaeger
- β Prometheus metrics collection
- β Grafana dashboards for visualization
- β RESTful API design
- β Input validation
- β Database relationships (Cars β Engines)
- β Docker containerization
- β Middleware for authentication and metrics
The system follows a layered architecture pattern:
graph TB
Client[Client/API Consumer] --> Router[HTTP Router<br/>Gorilla Mux]
Router --> Middleware[Middleware Layer]
Middleware --> |OpenTelemetry| Tracing[Distributed Tracing]
Middleware --> |Prometheus| Metrics[Metrics Collection]
Middleware --> |JWT| Auth[Authentication]
Middleware --> HandlerLayer[Handler Layer]
HandlerLayer --> CarHandler[Car Handler]
HandlerLayer --> EngineHandler[Engine Handler]
HandlerLayer --> LoginHandler[Login Handler]
CarHandler --> CarService[Car Service]
EngineHandler --> EngineService[Engine Service]
CarService --> CarStore[Car Store]
EngineService --> EngineStore[Engine Store]
CarStore --> DB[(PostgreSQL<br/>Database)]
EngineStore --> DB
Tracing --> Jaeger[Jaeger<br/>Port: 16686]
Metrics --> Prometheus[Prometheus<br/>Port: 9090]
Prometheus --> Grafana[Grafana<br/>Port: 3000]
style Client fill:#4a90e2,stroke:#2c5282,stroke-width:2px,color:#fff
style Router fill:#f5a623,stroke:#b7791f,stroke-width:2px,color:#fff
style Middleware fill:#e94b8b,stroke:#b8325f,stroke-width:2px,color:#fff
style HandlerLayer fill:#50c878,stroke:#2d8659,stroke-width:2px,color:#fff
style CarService fill:#9b59b6,stroke:#6c3483,stroke-width:2px,color:#fff
style EngineService fill:#9b59b6,stroke:#6c3483,stroke-width:2px,color:#fff
style DB fill:#e74c3c,stroke:#a93226,stroke-width:2px,color:#fff
style Jaeger fill:#16a085,stroke:#0e6655,stroke-width:2px,color:#fff
style Prometheus fill:#f39c12,stroke:#b9770e,stroke-width:2px,color:#fff
style Grafana fill:#3498db,stroke:#21618c,stroke-width:2px,color:#fff
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Client/API Consumer β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β HTTP Router (Gorilla Mux) β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Middleware Layer β β
β β β’ OpenTelemetry Tracing β β
β β β’ Prometheus Metrics β β
β β β’ JWT Authentication β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Handler Layer β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Car Handler β βEngine Handlerβ βLogin Handler β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββββββββββ β
βββββββββββΌβββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Service Layer β
β ββββββββββββββββ ββββββββββββββββ β
β β Car Service β βEngine Serviceβ β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
βββββββββββΌββββββββββββββββββΌββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Store Layer (Repository) β
β ββββββββββββββββ ββββββββββββββββ β
β β Car Store β βEngine Store β β
β ββββββββ¬ββββββββ βββββββββ¬βββββββ β
βββββββββββΌβββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β β
ββββββββββββ¬ββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PostgreSQL Database β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Observability Stack β
β ββββββββββββββββ ββββββββββββββββ βββββββββββββββββ β
β β Jaeger β β Prometheus β β Grafana β β
β β (Tracing) β β (Metrics) β β(Visualization)β β
β ββββββββββββββββ ββββββββββββββββ βββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Handler Layer: HTTP request handlers that process incoming requests
- Service Layer: Business logic and validation
- Store Layer: Database access and data persistence
- Middleware: Cross-cutting concerns (auth, metrics, tracing)
- Observability: Distributed tracing, metrics, and visualization
- Language: Go 1.25.5
- Web Framework: Gorilla Mux
- Database: PostgreSQL
- Authentication: JWT (golang-jwt/jwt)
- Tracing: OpenTelemetry with Jaeger
- Metrics: Prometheus
- Visualization: Grafana
- Containerization: Docker & Docker Compose
- Environment Management: godotenv
Car-Management-System/
βββ db/
β βββ Dockerfile # PostgreSQL database Dockerfile
βββ driver/
β βββ postgres.go # Database connection driver
βββ handler/
β βββ car/
β β βββ car.go # Car HTTP handlers
β βββ engine/
β β βββ engine.go # Engine HTTP handlers
β βββ login/
β βββ login.go # Authentication handler
βββ middleware/
β βββ auth_middleware.go # JWT authentication middleware
β βββ metrices_middleware.go # Prometheus metrics middleware
βββ models/
β βββ car.go # Car data models and validation
β βββ engine.go # Engine data models
β βββ login.go # Login credentials model
βββ service/
β βββ car/
β β βββ car.go # Car business logic
β βββ engine/
β β βββ engine.go # Engine business logic
β βββ interface.go # Service interfaces
βββ store/
β βββ car/
β β βββ car.go # Car database operations
β βββ engine/
β β βββ engine.go # Engine database operations
β βββ interface.go # Store interfaces
β βββ schema.sql # Database schema and seed data
βββ observability_images/ # Observability screenshots
β βββ grafana_dashboard.png
β βββ jaeger_trace.png
β βββ jaeger_ui.png
βββ docker-compose.yml # Multi-container orchestration
βββ Dockerfile # Application Dockerfile
βββ prometheus.yml # Prometheus configuration
βββ go.mod # Go module dependencies
βββ go.sum # Go module checksums
βββ main.go # Application entry point
Before you begin, ensure you have the following installed:
- Go (version 1.25.5 or higher)
- Docker and Docker Compose
- PostgreSQL (if running locally without Docker)
- Git
git clone <repository-url>
cd Car-Management-SystemCreate a .env file in the root directory:
PORT=8080
DB_HOST=db
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=12345
DB_NAME=postgres
JAEGER_AGENT_HOST=jaeger
JAEGER_AGENT_PORT=4318The easiest way to run the entire stack:
docker-compose up --buildThis will start:
- Application on port
8080 - PostgreSQL on port
5432 - Jaeger UI on port
16686 - Prometheus on port
9090 - Grafana on port
3000
If you prefer to run locally:
-
Start PostgreSQL (or use Docker for DB only):
docker run -d \ --name postgres \ -e POSTGRES_USER=postgres \ -e POSTGRES_PASSWORD=12345 \ -e POSTGRES_DB=postgres \ -p 5432:5432 \ postgres:latest
-
Start Jaeger:
docker run -d \ --name jaeger \ -p 6831:6831/udp \ -p 4318:4318 \ -p 14268:14268 \ -p 16686:16686 \ jaegertracing/all-in-one:latest
-
Start Prometheus:
docker run -d \ --name prometheus \ -p 9090:9090 \ -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \ prom/prometheus:latest -
Start Grafana:
docker run -d \ --name grafana \ -p 3000:3000 \ -e GF_SECURITY_ADMIN_PASSWORD=admin \ grafana/grafana:latest
-
Run the Application:
go mod download go run main.go
POST /login
Content-Type: application/json
{
"username": "admin",
"password": "admin123"
}Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}Note: All endpoints below require authentication. Include the token in the Authorization header:
Authorization: Bearer <token>
GET /cars/{id}
Authorization: Bearer <token>GET /cars?brand={brand}&isEngine={true|false}
Authorization: Bearer <token>Query Parameters:
brand: Filter by car brand (required)isEngine: Include engine details (optional, default: false)
POST /cars
Authorization: Bearer <token>
Content-Type: application/json
{
"Name": "Honda Civic",
"year": "2023",
"brand": "Honda",
"fuel_type": "Petrol",
"engine": {
"engine_id": "e1f86b1a-0873-4c19-bae2-fc60329d0140",
"displacement": 2000,
"no_of_cylinders": 4,
"car_range": 600
},
"price": 25000.00
}PUT /cars/{id}
Authorization: Bearer <token>
Content-Type: application/json
{
"Name": "Honda Civic Updated",
"year": "2024",
"brand": "Honda",
"fuel_type": "Petrol",
"engine": {
"engine_id": "e1f86b1a-0873-4c19-bae2-fc60329d0140",
"displacement": 2000,
"no_of_cylinders": 4,
"car_range": 600
},
"price": 26000.00
}DELETE /cars/{id}
Authorization: Bearer <token>GET /engine/{id}
Authorization: Bearer <token>POST /engine
Authorization: Bearer <token>
Content-Type: application/json
{
"displacement": 2000,
"no_of_cylinders": 4,
"car_range": 600
}PUT /engine/{id}
Authorization: Bearer <token>
Content-Type: application/json
{
"displacement": 2500,
"no_of_cylinders": 6,
"car_range": 700
}DELETE /engine/{id}
Authorization: Bearer <token>GET /metricsReturns Prometheus-formatted metrics for monitoring.
The system includes comprehensive observability features:
All HTTP requests are automatically traced using OpenTelemetry and sent to Jaeger. You can view traces at:
Jaeger UI: http://localhost:16686
Prometheus collects metrics from the application:
Prometheus UI: http://localhost:9090
Available metrics:
http_requests_total: Total number of HTTP requestshttp_requests_duration_seconds: Request duration histogramhttp_response_status_total: Response status code counters
Grafana provides visual dashboards for metrics:
Grafana UI: http://localhost:3000
Default Credentials:
- Username:
admin - Password:
admin
- Login to Grafana at http://localhost:3000
- Go to Configuration β Data Sources
- Click Add data source
- Select Prometheus
- Set URL to
http://prometheus:9090(orhttp://localhost:9090if running locally) - Click Save & Test
CREATE TABLE engine (
id UUID PRIMARY KEY,
displacement INT NOT NULL,
no_of_cylinders INT NOT NULL,
car_range INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);CREATE TABLE car (
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 engine(id) ON DELETE CASCADE
);The schema includes seed data with sample cars and engines that are automatically loaded on startup.
| Variable | Description | Default |
|---|---|---|
PORT |
Application server port | 8080 |
DB_HOST |
PostgreSQL host | db |
DB_PORT |
PostgreSQL port | 5432 |
DB_USER |
Database username | postgres |
DB_PASSWORD |
Database password | 12345 |
DB_NAME |
Database name | postgres |
JAEGER_AGENT_HOST |
Jaeger agent host | jaeger |
JAEGER_AGENT_PORT |
Jaeger agent port | 4318 |
# 1. Login to get token
TOKEN=$(curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' \
| jq -r '.token')
# 2. Create an engine first
ENGINE_ID=$(curl -X POST http://localhost:8080/engine \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"displacement": 2000,
"no_of_cylinders": 4,
"car_range": 600
}' | jq -r '.id')
# 3. Create a car with the engine
curl -X POST http://localhost:8080/cars \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"Name\": \"Tesla Model 3\",
\"year\": \"2024\",
\"brand\": \"Tesla\",
\"fuel_type\": \"Electric\",
\"engine\": {
\"engine_id\": \"$ENGINE_ID\",
\"displacement\": 2000,
\"no_of_cylinders\": 4,
\"car_range\": 600
},
\"price\": 45000.00
}"# Get token
TOKEN=$(curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}' \
| jq -r '.token')
# Get all Honda cars with engine details
curl -X GET "http://localhost:8080/cars?brand=Honda&isEngine=true" \
-H "Authorization: Bearer $TOKEN"# View Prometheus metrics
curl http://localhost:8080/metrics# Test login endpoint
curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'
# Test protected endpoint (replace <token> with actual token)
curl -X GET http://localhost:8080/cars \
-H "Authorization: Bearer <token>"- Authentication: Default credentials are
admin/admin123. In production, use secure password management. - JWT Secret: The JWT secret key is hardcoded in the middleware. In production, use environment variables.
- Database: The schema is automatically executed on application startup.
- Tracing: All requests are automatically traced. Ensure Jaeger is running for tracing to work.
- Metrics: Metrics are exposed at
/metricsendpoint in Prometheus format.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is open source and available under the MIT License.


