DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
MediumTheory

Gin Framework: Production Web APIs in Go

41 views

Problem Statement

Build a production-ready REST API using Gin, the most popular Go web framework used by companies like Uber and Twitch.

Basic Gin Setup

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func main() {
    // Production: use gin.New() for manual middleware control
    r := gin.New()
    r.Use(gin.Logger(), gin.Recovery())
    
    // Routes
    r.GET("/health", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"status": "healthy"})
    })
    
    r.Run(":8080")
}

Request Binding with Validation

type RegisterRequest struct {
    Email    string `json:"email" binding:"required,email"`
    Password string `json:"password" binding:"required,min=8"`
    Age      int    `json:"age" binding:"gte=18,lte=120"`
}

func Register(c *gin.Context) {
    var req RegisterRequest
    
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }
    
    // Process registration...
    c.JSON(http.StatusCreated, gin.H{
        "message": "User created",
        "email":   req.Email,
    })
}

Custom Middleware

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        
        if token == "" {
            c.JSON(http.StatusUnauthorized, gin.H{
                "error": "missing authorization header",
            })
            c.Abort()
            return
        }
        
        // Validate token...
        userID := validateToken(token)
        c.Set("userID", userID)
        
        c.Next()
    }
}

// Apply to route group
admin := r.Group("/admin")
admin.Use(AuthMiddleware())
{
    admin.GET("/users", ListUsers)
    admin.DELETE("/users/:id", DeleteUser)
}

Async Handler (Critical!)

func AsyncHandler(c *gin.Context) {
    // ❌ WRONG: Using c directly in goroutine
    // go func() {
    //     c.JSON(200, result) // RACE CONDITION!
    // }()
    
    // ✅ CORRECT: Copy context for goroutine
    cCopy := c.Copy()
    go func() {
        result := expensiveOperation()
        // Use cCopy, not c
        log.Printf("Processed for %s", cCopy.ClientIP())
    }()
    
    c.JSON(http.StatusAccepted, gin.H{"status": "processing"})
}

Structured Logging Middleware

func JSONLogger() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        
        c.Next()
        
        log.Printf(`{"method":"%s","path":"%s","status":%d,"latency":"%v"}`,
            c.Request.Method,
            c.Request.URL.Path,
            c.Writer.Status(),
            time.Since(start),
        )
    }
}

Testing with httptest

func TestRegister(t *testing.T) {
    r := setupRouter()
    
    body := `{"email":"test@example.com","password":"secret123","age":25}`
    req := httptest.NewRequest("POST", "/register", strings.NewReader(body))
    req.Header.Set("Content-Type", "application/json")
    
    w := httptest.NewRecorder()
    r.ServeHTTP(w, req)
    
    assert.Equal(t, http.StatusCreated, w.Code)
}

Sample Test Cases

Case 1
Input
GET /users/:id
Expected Output
Returns user JSON with id parameter
Case 2
Input
POST /users with JSON body
Expected Output
Binds JSON, creates user, returns 201

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
41
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go