Level 5: Capstone Unified Service (API Integration & Gin)¶
Welcome to the final level! Here, you will integrate everything you have built in Levels 1 through 4 into a single, cohesive backend gateway using Gin.
This project simulates a professional, production-grade microservice gateway that handles HTTP requests, concurrent file parsing, shortlink redirection, database storage, and live WebSockets.
Architecture & Integration Diagram¶
graph TD
Client["Web & API Clients"] <-->|"HTTP & WebSockets"| Gin["Gin Router / API Gateway"]
subgraph CORE_MODULES ["Core Modules"]
Gin <-->|CRUD| Level1["Level 1: Task Manager"]
Gin --->|"Multipart Uploads"| Level2["Level 2: Log Analyzer"]
Gin <-->|"Shortening & Hits"| Level3["Level 3: URL Shortener"]
Gin <-->|"Event Dispatch"| Level4["Level 4: Real-time Websocket Hub"]
end
Level4 <-->|"Pub/Sub Sync"| Redis["Redis Broker"]
API Endpoints to Support¶
Your unified API server must handle:
1. Task Tracker CRUD (Level 1)¶
GET /tasks: Return all tasks in JSON.POST /tasks: Expects{"description": "Task Text"}. Adds task and publishes a WebSocket event notification:{"event": "task_created", "task": ...}.PUT /tasks/:id/complete: Marks task complete. Publishes WebSocket notification:{"event": "task_completed", "id": 1}.
2. Concurrent Log Analyzer (Level 2)¶
POST /logs/analyze: Expects multipart form file uploads. Parses all uploaded logs concurrently using your Level 2 concurrent engine, aggregates findings, and returns the unifiedLogResultsummary JSON.
3. URL Shortener (Level 3)¶
POST /shorten: Expects{"url": "https://..."}. Saves short link and publishes WebSocket notification:{"event": "url_shortened", "code": "abcde"}.GET /:short_code: Increments hit counter, redirects browser, and publishes WebSocket notification:{"event": "url_hit", "code": "abcde", "hits": 5}.
4. Live Event Feed (Level 4)¶
GET /ws: Upgrades the connection to WebSockets. Subscribes the client to the Level 4 Event Hub so they receive all the live event messages dispatched by the other endpoints.
Getting Started¶
- Ensure the
go.modis set up with dependencies. Run this to fetch Gin and gorilla/websocket: - See main.go for the integration router stubs.
- See main_test.go for the endpoint test suite.
- Run tests:
Unified Service Gateway (main.go)¶
package main
import (
"log"
"github.com/gin-gonic/gin"
tasktracker "github.com/ankush/implementation-practice/level1_task_tracker"
loganalyzer "github.com/ankush/implementation-practice/level2_log_analyzer"
urlshortener "github.com/ankush/implementation-practice/level3_url_shortener"
notification "github.com/ankush/implementation-practice/level4_notification_system"
)
// AppContainer holds all the dependencies across modules.
type AppContainer struct {
TaskManager *tasktracker.TaskManager
URLStore urlshortener.URLStore
Hub *notification.Hub
}
func SetupGatewayRouter(app *AppContainer) *gin.Engine {
r := gin.Default()
// 1. Task Tracker Endpoint (Integrates Level 1 + Level 4 Broadcast)
r.POST("/tasks", func(c *gin.Context) {
var req struct{ Description string `json:"description" binding:"required"` }
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// TODO:
// 1. Call app.TaskManager.AddTask(req.Description)
// 2. Broadcast event to app.Hub.Broadcast: "task_created: [description]"
// 3. Return status 201 with the created task.
})
r.GET("/tasks", func(c *gin.Context) {
// TODO: Call app.TaskManager.ListTasks()
})
// 2. Concurrent Log Analyzer (Integrates Level 2)
r.POST("/logs/analyze", func(c *gin.Context) {
// Hint: To handle log uploads:
// form, err := c.MultipartForm()
// files := form.File["logs"]
// Save them locally in temporary paths.
// Call loganalyzer.AnalyzeLogs(c.Request.Context(), tempFilePaths)
// Return the LogResult JSON.
})
// 3. URL Shortener (Integrates Level 3 + Level 4 Broadcast)
r.POST("/shorten", func(c *gin.Context) {
var req struct{ URL string `json:"url" binding:"required"` }
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// TODO:
// 1. Generate code and save using app.URLStore.Save.
// 2. Broadcast event to app.Hub.Broadcast: "url_shortened: [code]"
// 3. Return JSON with the short code and URL.
})
r.GET("/:short_code", func(c *gin.Context) {
// TODO:
// 1. Resolve using app.URLStore.Get.
// 2. Increment hits via app.URLStore.IncrementHits.
// 3. Broadcast event: "url_hit: [code]"
// 4. Redirect 307.
})
// 4. Real-time Event Feed WebSocket (Integrates Level 4 WebSockets)
r.GET("/ws", func(c *gin.Context) {
// TODO:
// 1. Upgrade request to websocket using standard upgrader:
// var upgrader = websocket.Upgrader{}
// conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
// 2. Create a client struct wrapping conn.
// 3. Register client: app.Hub.Register <- client
// 4. Run client.WritePump() in the background or foreground.
})
return r
}
func main() {
// 1. Instantiate level modules
tm := tasktracker.NewTaskManager("tasks.json")
store := urlshortener.NewMemoryStore()
hub := notification.NewHub()
// 2. Start the WebSocket hub event-loop
go hub.Run()
app := &AppContainer{
TaskManager: tm,
URLStore: store,
Hub: hub,
}
r := SetupGatewayRouter(app)
log.Println("Starting Integrated Gateway Service on :8080...")
r.Run(":8080")
}