Gin

Go's fastest web framework - httprouter-based, near-zero allocation, perfect for high-throughput APIs

TL;DR

One-liner: Gin is Go’s fastest web framework - Martini-like API with 40x better performance, perfect for high-throughput APIs.

Core Strengths:

  • Blazing fast - httprouter-based, near-zero allocation
  • Crash-free - built-in recovery from panics
  • JSON validation - struct tags for binding and validation
  • Middleware - extensible request/response pipeline

Core Concepts

Concept 1: Handlers

Handler functions receive a Context with request/response utilities:

func getUser(c *gin.Context) {
    id := c.Param("id")           // Path parameter
    name := c.Query("name")       // Query string
    page := c.DefaultQuery("page", "1")

    c.JSON(200, gin.H{
        "id": id,
        "name": name,
    })
}

r.GET("/users/:id", getUser)

Concept 2: Binding & Validation

Struct tags for automatic request parsing:

type CreateUser struct {
    Name  string `json:"name" binding:"required"`
    Email string `json:"email" binding:"required,email"`
    Age   int    `json:"age" binding:"gte=0,lte=130"`
}

func createUser(c *gin.Context) {
    var user CreateUser
    if err := c.ShouldBindJSON(&user); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    c.JSON(201, user)
}

Concept 3: Middleware

Functions that run before/after handlers:

// Custom middleware
func Logger() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        c.Next()  // Process request
        log.Printf("%s %s %v", c.Request.Method, c.Request.URL, time.Since(start))
    }
}

r.Use(Logger())
r.Use(gin.Recovery())  // Built-in panic recovery

Quick Start

Create Project

mkdir myapp && cd myapp
go mod init myapp
go get -u github.com/gin-gonic/gin

Create main.go

package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.Default()  // Includes Logger and Recovery

    r.GET("/", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "Hello Gin!"})
    })

    r.Run()  // Default :8080
}

Run

go run main.go
# Open http://localhost:8080

Gotchas

Route groups for organization

api := r.Group("/api")
{
    v1 := api.Group("/v1")
    {
        v1.GET("/users", getUsers)
        v1.POST("/users", createUser)
    }

    // With middleware
    admin := api.Group("/admin", AuthMiddleware())
    {
        admin.GET("/stats", getStats)
    }
}

Different response types

// JSON
c.JSON(200, gin.H{"key": "value"})

// String
c.String(200, "Hello %s", name)

// HTML template
c.HTML(200, "index.html", gin.H{"title": "Home"})

// File
c.File("./path/to/file.pdf")

// Redirect
c.Redirect(302, "/new-location")

Error handling

func getUser(c *gin.Context) {
    user, err := findUser(c.Param("id"))
    if err != nil {
        c.AbortWithStatusJSON(404, gin.H{"error": "User not found"})
        return  // Don't forget to return!
    }
    c.JSON(200, user)
}

gin.H is just a shortcut

// gin.H is map[string]any
c.JSON(200, gin.H{"message": "ok"})

// Same as
c.JSON(200, map[string]any{"message": "ok"})

// Or use structs for type safety
type Response struct {
    Message string `json:"message"`
}
c.JSON(200, Response{Message: "ok"})

When to Use

Best for:

  • High-performance REST APIs
  • Microservices
  • Real-time applications
  • Teams wanting simplicity + speed

Not ideal for:

  • Full-stack apps with templates (use Echo or standard library)
  • Teams new to Go
  • Projects needing heavy ORM (Gin is just routing)

Comparison:

FeatureGinEchoFiber
PerformanceVery fastVery fastFastest
APIMartini-likeCleanExpress-like
CommunityLargestLargeGrowing
FeaturesMinimalModerateModerate

Next Steps

Cheatsheet

PatternCode
GET router.GET("/path", handler)
POST router.POST("/path", handler)
Path paramc.Param("id")
Query paramc.Query("name")
Default queryc.DefaultQuery("page", "1")
JSON bodyc.ShouldBindJSON(&obj)
JSON responsec.JSON(200, gin.H{})
Route groupr.Group("/api")
Middlewarer.Use(middleware)
Run serverr.Run(":8080")