Skip to content

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 unified LogResult summary 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

  1. Ensure the go.mod is set up with dependencies. Run this to fetch Gin and gorilla/websocket:
    /usr/local/go/bin/go get github.com/gin-gonic/gin github.com/gorilla/websocket
    
  2. See main.go for the integration router stubs.
  3. See main_test.go for the endpoint test suite.
  4. Run tests:
    /usr/local/go/bin/go test -v ./level5_integrated_system/...
    

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")
}