Belajar Gin - Middleware
Episode 6 of 23

Belajar Gin - Middleware

Episode ini membedah middleware Gin: menulis middleware sendiri dengan c.Next() dan c.Abort(), memasangnya dengan engine.Use(), memakai middleware bawaan seperti Logger, Recovery, BasicAuth, CORS, dan gzip, serta mengatur urutan eksekusi.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Middleware adalah salah satu alasan utama orang memilih Gin. Dengan middleware, kalian mengeksekusi logika sebelum dan sesudah handler tanpa mengubah kode handler itu sendiri: logging, autentikasi, CORS, recovery, kompresi — semuanya bisa di-encapsulate menjadi potongan yang bisa dipasang di rute mana pun.

Episode 6 membedah middleware dari dua sisi: bagaimana menulis middleware custom sendiri, dan bagaimana memanfaatkan middleware bawaan Gin yang paling sering dipakai. Pemahaman tentang urutan eksekusi akan menyelamatkan kalian dari bug yang sulit dilacak.

Middleware Dasar

Anatomi Middleware Gin

Middleware hanyalah HandlerFunc: fungsi yang menerima *gin.Context. Dua method kunci yang mengontrol alur:

  • c.Next(): lanjutkan eksekusi ke handler berikutnya; kode setelah c.Next() berjalan setelah handler selesai.
  • c.Abort(): hentikan chain; handler berikutnya tidak dipanggil.
Anatomi middleware
func myMiddleware(c *gin.Context) {
    // kode sebelum handler
    c.Next()
    // kode setelah handler selesai
}

Kode sebelum c.Next() menjalankan logika pra-proses, dan kode setelahnya menjalankan logika pasca-proses. Inilah yang dipakai middleware Logger untuk mencatat durasi request.

Mari tulis middleware logging sederhana yang mencatat method, path, dan durasi:

Middleware logging custom
func requestLogger() gin.HandlerFunc {
    return func(c *gin.Context) {
        start := time.Now()
        c.Next()
        duration := time.Since(start)
        log.Printf("%s %s -> %d (%s)",
            c.Request.Method,
            c.Request.URL.Path,
            c.Writer.Status(),
            duration,
        )
    }
}

Fungsi c.Writer.Status() mengembalikan status code yang ditulis handler. Middleware ini mencatat request setelah handler selesai karena panggilan c.Next() berada di tengah.

engine.Use dan Abort

Pasang middleware ke seluruh engine atau hentikan alur dengan Abort:

Use dan Abort
r := gin.New()
r.Use(requestLogger())
 
func requireToken(c *gin.Context) {
    token := c.GetHeader("Authorization")
    if token == "" {
        c.AbortWithStatusJSON(401, gin.H{"error": "token wajib"})
        return
    }
    c.Set("token", token)
    c.Next()
}

c.AbortWithStatusJSON(401, ...) menghentikan chain sekaligus menulis response JSON. Fungsi c.Set("token", token) menyimpan nilai yang bisa dibaca handler berikutnya dengan c.Get.

Middleware Bawaan

Logger dan Recovery

gin.Default() sudah menyertakan Logger dan Recovery. Logger menulis log akses untuk setiap request; Recovery menangkap panic di handler agar server tidak mati:

Logger dan Recovery eksplisit
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())

Jika tidak memakai gin.Default(), pasang keduanya secara eksplisit. Recovery sangat penting di production: panic yang tidak ditangani akan menghentikan proses server.

BasicAuth

Untuk proteksi sederhana, gin menyediakan middleware BasicAuth:

BasicAuth bawaan
r.Use(gin.BasicAuth(gin.Accounts{
    "arman": "rahasia123",
    "dev":   "rahasia456",
}))
 
r.GET("/admin", func(c *gin.Context) {
    user := c.MustGet(gin.AuthUserKey).(string)
    c.JSON(200, gin.H{"user": user})
})

Fungsi c.MustGet(gin.AuthUserKey).(string) mengambil username yang tervalidasi. Middleware ini membandingkan kredensial dengan cara yang aman dari timing attack. Untuk sistem yang lebih serius, episode 13 akan membahas JWT dan session.

CORS dengan gin-contrib/cors

Jika API kalian dipanggil dari browser di domain berbeda, CORS diperlukan:

Install middleware CORS
go get github.com/gin-contrib/cors
Konfigurasi CORS
import "github.com/gin-contrib/cors"
 
r.Use(cors.New(cors.Config{
    AllowOrigins:     []string{"https://app.example.com"},
    AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
    AllowHeaders:     []string{"Origin", "Content-Type", "Authorization"},
    AllowCredentials: true,
    MaxAge:           12 * time.Hour,
}))

Konfigurasi AllowOrigins membatasi domain mana yang boleh mengakses API. Jangan memakai wildcard * jika AllowCredentials aktif — kombinasi itu ditolak browser.

Untuk kompresi bandwidth, ekosistem gin-contrib menyediakan middleware gzip yang dipasang dengan r.Use(gzip.Gzip(gzip.DefaultCompression)). Response JSON dan teks dikompres otomatis ketika klien mengirim header Accept-Encoding: gzip.

Urutan Eksekusi

LIFO untuk Kode Pasca-Handler

Urutan Use menentukan urutan eksekusi. Kode setelah c.Next() berjalan dengan urutan terbalik (LIFO):

Urutan eksekusi middleware
r.Use(m1) // masuk pertama
r.Use(m2) // masuk kedua
r.GET("/ping", handler)
 
// alur: m1 -> m2 -> handler -> m2 (sisa) -> m1 (sisa)

Logika pra-proses berjalan dari middleware yang dipasang pertama ke terakhir, sedangkan logika pasca-proses berjalan terbalik. Contoh nyata: taruh Recovery paling luar agar bisa menangkap panic dari middleware di dalamnya.

Middleware per Group

Tidak semua middleware perlu berlaku global. Pasang middleware pada grup tertentu:

Middleware per group
api := r.Group("/api")
api.Use(requestLogger())
 
private := api.Group("/private")
private.Use(requireToken)
 
private.GET("/profile", func(c *gin.Context) {
    c.JSON(200, gin.H{"status": "profil dilindungi"})
})

Rute /api/private/profile mewarisi requestLogger dari grup api dan requireToken dari grup private. Hierarki ini menjaga middleware tetap sesuai cakupannya.

Penutup

Inti yang harus dibawa pulang:

  • Middleware adalah HandlerFunc: c.Next() melanjutkan, c.Abort() menghentikan.
  • Logika pasca-Next() berjalan setelah handler selesai.
  • gin.Default() = Logger + Recovery; pasang eksplisit jika memakai gin.New().
  • BasicAuth dan CORS adalah middleware bawaan/ekosistem yang wajib dikenal.
  • Urutan Use menentukan urutan eksekusi; pasca-proses berjalan LIFO.
  • Middleware bisa dipasang global, per grup, atau per rute.

Di episode 7 selanjutnya kita akan membedah response rendering & static files — mengembalikan JSON, XML, YAML, TOML, dan ProtoBuf, merender HTML template, redirect, file statis, upload file, dan streaming response.

Belajar Gin - Middleware | Belajar Gin