1. Project Overview & Quickstart (gin-gonic/gin)
File: README.md
Gin Web Framework
📰 Gin 1.12.0 is now available!
We're excited to announce the release of Gin 1.12.0! This release brings new features, performance improvements, and important bug fixes. Check out the release announcement on our official blog for the full details.
Gin is a high-performance HTTP web framework written in Go. It provides a Martini-like API but with significantly better performance—up to 40 times faster—thanks to httprouter. Gin is designed for building REST APIs, web applications, and microservices where speed and developer productivity are essential.
Why choose Gin?
Gin combines the simplicity of Express.js-style routing with Go's performance characteristics, making it ideal for:
- Building high-throughput REST APIs
- Developing microservices that need to handle many concurrent requests
- Creating web applications that require fast response times
- Prototyping web services quickly with minimal boilerplate
Gin's key features:
- Zero allocation router - Extremely memory-efficient routing with no heap allocations
- High performance - Benchmarks show superior speed compared to other Go web frameworks
- Middleware support - Extensible middleware system for authentication, logging, CORS, etc.
- Crash-free - Built-in recovery middleware prevents panics from crashing your server
- JSON validation - Automatic request/response JSON binding and validation
- Route grouping - Organize related routes and apply common middleware
- Error management - Centralized error handling and logging
- Built-in rendering - Support for JSON, XML, HTML templates, and more
- Extensible - Large ecosystem of community middleware and plugins
Getting Started
Prerequisites
- Go version: Gin requires Go version 1.25 or above
- Basic Go knowledge: Familiarity with Go syntax and package management is helpful
Installation
With Go's module support, simply import Gin in your code and Go will automatically fetch it during build:
import "github.com/gin-gonic/gin"Your First Gin Application
Here's a complete example that demonstrates Gin's simplicity:
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
// Create a Gin router with default middleware (logger and recovery)
r := gin.Default()
// Define a simple GET endpoint
r.GET("/ping", func(c *gin.Context) {
// Return JSON response
c.JSON(http.StatusOK, gin.H{
"message": "pong",
})
})
// Start server on port 8080 (default)
// Server will listen on 0.0.0.0:8080 (localhost:8080 on Windows)
if err := r.Run(); err != nil {
log.Fatalf("failed to run server: %v", err)
}
}Running the application:
Save the code above as
main.goRun the application:
shgo run main.goOpen your browser and visit
http://localhost:8080/pingYou should see:
{"message":"pong"}
What this example demonstrates:
- Creating a Gin router with default middleware
- Defining HTTP endpoints with simple handler functions
- Returning JSON responses
- Starting an HTTP server
Next Steps
After running your first Gin application, explore these resources to learn more:
📚 Learning Resources
- Gin Quick Start Guide - Comprehensive tutorial with API examples and build configurations
- Example Repository - Ready-to-run examples demonstrating various Gin use cases:
- REST API development
- Authentication & middleware
- File uploads and downloads
- WebSocket connections
- Template rendering
📖 Documentation
API Reference
- Go.dev API Documentation - Complete API reference with examples
User Guides
The comprehensive documentation is available on gin-gonic.com in multiple languages:
Official Tutorials
⚡ Performance Benchmarks
Gin demonstrates exceptional performance compared to other Go web frameworks. It uses a custom version of HttpRouter for maximum efficiency. View detailed benchmarks →
Gin vs. Other Go Frameworks (GitHub API routing benchmark):
| Benchmark name | (1) | (2) | (3) | (4) |
|---|---|---|---|---|
| BenchmarkGin_GithubAll | 43550 | 27364 ns/op | 0 B/op | 0 allocs/op |
| BenchmarkAce_GithubAll | 40543 | 29670 ns/op | 0 B/op | 0 allocs/op |
| BenchmarkAero_GithubAll | 57632 | 20648 ns/op | 0 B/op | 0 allocs/op |
| BenchmarkBear_GithubAll | 9234 | 216179 ns/op | 86448 B/op | 943 allocs/op |
| BenchmarkBeego_GithubAll | 7407 | 243496 ns/op | 71456 B/op | 609 allocs/op |
| BenchmarkBone_GithubAll | 420 | 2922835 ns/op | 720160 B/op | 8620 allocs/op |
| BenchmarkChi_GithubAll | 7620 | 238331 ns/op | 87696 B/op | 609 allocs/op |
| BenchmarkDenco_GithubAll | 18355 | 64494 ns/op | 20224 B/op | 167 allocs/op |
| BenchmarkEcho_GithubAll | 31251 | 38479 ns/op | 0 B/op | 0 allocs/op |
| BenchmarkGocraftWeb_GithubAll | 4117 | 300062 ns/op | 131656 B/op | 1686 allocs/op |
| BenchmarkGoji_GithubAll | 3274 | 416158 ns/op | 56112 B/op | 334 allocs/op |
| BenchmarkGojiv2_GithubAll | 1402 | 870518 ns/op | 352720 B/op | 4321 allocs/op |
| BenchmarkGoJsonRest_GithubAll | 2976 | 401507 ns/op | 134371 B/op | 2737 allocs/op |
| BenchmarkGoRestful_GithubAll | 410 | 2913158 ns/op | 910144 B/op | 2938 allocs/op |
| BenchmarkGorillaMux_GithubAll | 346 | 3384987 ns/op | 251650 B/op | 1994 allocs/op |
| BenchmarkGowwwRouter_GithubAll | 10000 | 143025 ns/op | 72144 B/op | 501 allocs/op |
| BenchmarkHttpRouter_GithubAll | 55938 | 21360 ns/op | 0 B/op | 0 allocs/op |
| BenchmarkHttpTreeMux_GithubAll | 10000 | 153944 ns/op | 65856 B/op | 671 allocs/op |
| BenchmarkKocha_GithubAll | 10000 | 106315 ns/op | 23304 B/op | 843 allocs/op |
| BenchmarkLARS_GithubAll | 47779 | 25084 ns/op | 0 B/op | 0 allocs/op |
| BenchmarkMacaron_GithubAll | 3266 | 371907 ns/op | 149409 B/op | 1624 allocs/op |
| BenchmarkMartini_GithubAll | 331 | 3444706 ns/op | 226551 B/op | 2325 allocs/op |
| BenchmarkPat_GithubAll | 273 | 4381818 ns/op | 1483152 B/op | 26963 allocs/op |
| BenchmarkPossum_GithubAll | 10000 | 164367 ns/op | 84448 B/op | 609 allocs/op |
| BenchmarkR2router_GithubAll | 10000 | 160220 ns/op | 77328 B/op | 979 allocs/op |
| BenchmarkRivet_GithubAll | 14625 | 82453 ns/op | 16272 B/op | 167 allocs/op |
| BenchmarkTango_GithubAll | 6255 | 279611 ns/op | 63826 B/op | 1618 allocs/op |
| BenchmarkTigerTonic_GithubAll | 2008 | 687874 ns/op | 193856 B/op | 4474 allocs/op |
| BenchmarkTraffic_GithubAll | 355 | 3478508 ns/op | 820744 B/op | 14114 allocs/op |
| BenchmarkVulcan_GithubAll | 6885 | 193333 ns/op | 19894 B/op | 609 allocs/op |
- (1): Total Repetitions achieved in constant time, higher means more confident result
- (2): Single Repetition Duration (ns/op), lower is better
- (3): Heap Memory (B/op), lower is better
- (4): Average Allocations per Repetition (allocs/op), lower is better
🔌 Middleware Ecosystem
Gin has a rich ecosystem of middleware for common web development needs. Explore community-contributed middleware:
- gin-contrib - Official middleware collection including:
- Authentication (JWT, Basic Auth, Sessions)
- CORS, Rate limiting, Compression
- Logging, Metrics, Tracing
- Static file serving, Template engines
- gin-gonic/contrib - Additional community middleware
🏢 Production Usage
Gin powers many high-traffic applications and services in production:
- gorush - High-performance push notification server
- fnproject - Container-native, serverless platform
- photoprism - AI-powered personal photo management
- lura - Ultra-performant API Gateway framework
- picfit - Real-time image processing server
- dkron - Distributed job scheduling system
🤝 Contributing
Gin is the work of hundreds of contributors from around the world. We welcome and appreciate your contributions! See the full list of contributors.
How to Contribute
- 🐛 Report bugs - Help us identify and fix issues
- 💡 Suggest features - Share your ideas for improvements
- 📝 Improve documentation - Help make our docs clearer
- 🔧 Submit code - Fix bugs or implement new features
- 🧪 Write tests - Improve our test coverage
Getting Started with Contributing
- Check out our CONTRIBUTING.md for detailed guidelines
- Join our community discussions and ask questions
All contributions are valued and help make Gin better for everyone!
File: examples/README.md
Gin Examples
⚠️ NOTICE: All gin examples have been moved as standalone repository to here.
File: ginS/README.md
Gin Default Server
This is API experiment for Gin.
package main
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/ginS"
)
func main() {
ginS.GET("/", func(c *gin.Context) { c.String(200, "Hello World") })
ginS.Run()
}2. Official Technical Reference & Guides (gin-gonic/website)
File: README.md
Gin website
Welcome! This repository houses all the assets required to build the Gin website and documentation. We're pleased that you want to contribute! The website is hosted at https://gin-gonic.com.
We use Astro to format and generate our website, the Starlight template for styling and site structure. Thanks!.
Contribution
- Fork the repository
You can click the Fork button in the upper-right area of the screen to create a copy of this repository in your GitHub account. This copy is called as fork.
- Create one pull request
Make any changes you want in your fork, and when you are ready to send those changes to us, go to your fork and create a new pull request to let us know about it.
- Merge the pull request
Once your pull request is created, a Gin reviewer will take responsibility for providing clear, actionable feedback, re-improve and merge.
Running
See the official Astro documentation for Astro installation instructions. and Starlight documentation for Starlight installation instructions.
To run the site locally when you have Hugo installed:
git clone https://github.com/<your-username>/website.git # your fork url
cd website
# ensure you have node installed
node -v
# else https://nodejs.org/en/download
npm install
npm run devThis will start the local Astro server on port 4321. Open up your browser to http://localhost:4321 to view the site. As you make changes to the source files, Astro updates the site and forces a browser refresh.
🚀 Project Structure
Inside of your Astro + Starlight project, you'll see the following folders and files:
.
├── public/
├── src/
│ ├── assets/
│ ├── content/
│ │ ├── docs/
│ └── content.config.ts
├── astro.config.mjs
├── package.json
└── tsconfig.jsonStarlight looks for .md or .mdx files in the src/content/docs/ directory. Each file is exposed as a route based on its file name.
Images can be added to src/assets/ and embedded in Markdown with a relative link.
Static assets, like favicons, can be placed in the public/ directory.
🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
|---|---|
npm install |
Installs dependencies |
npm run dev |
Starts local dev server at localhost:4321 |
npm run build |
Build your production site to ./dist/ |
npm run preview |
Preview your build locally, before deploying |
npm run astro ... |
Run CLI commands like astro add, astro check |
npm run astro -- --help |
Get help using the Astro CLI |
Thanks
Gin thrives on community participation, and we really appreciate your contributions to our site and our documentation!
File: src/content/docs/id/docs/faq/index.md
title: "Pertanyaan Umum" sidebar: order: 15
Pertanyaan Umum
Bagaimana cara mengaktifkan live reload selama pengembangan?
Gunakan Air untuk live reloading otomatis selama pengembangan. Air memantau file Anda dan membangun ulang/memulai ulang aplikasi Anda ketika perubahan terdeteksi.
Instalasi:
go install github.com/air-verse/air@latestPengaturan:
Buat file konfigurasi .air.toml di root proyek Anda:
air initLalu jalankan air di direktori proyek Anda alih-alih go run:
airAir akan memantau file .go Anda dan secara otomatis membangun ulang/memulai ulang aplikasi Gin Anda saat ada perubahan. Lihat dokumentasi Air untuk opsi konfigurasi.
Bagaimana cara menangani CORS di Gin?
Gunakan middleware resmi gin-contrib/cors:
package main
import (
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Default CORS configuration
r.Use(cors.Default())
// Or customize CORS settings
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
r.Run()
}Untuk gambaran keamanan lengkap, lihat Praktik terbaik keamanan.
Bagaimana cara menyajikan file statis?
Gunakan Static() atau StaticFS() untuk menyajikan file statis:
func main() {
r := gin.Default()
// Serve files from ./assets directory at /assets/*
r.Static("/assets", "./assets")
// Serve a single file
r.StaticFile("/favicon.ico", "./resources/favicon.ico")
// Serve from embedded filesystem (Go 1.16+)
r.StaticFS("/public", http.FS(embedFS))
r.Run()
}Lihat Menyajikan data dari file untuk detail lebih lanjut.
Bagaimana cara menangani upload file?
Gunakan FormFile() untuk file tunggal atau MultipartForm() untuk banyak file:
// Single file upload
r.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
c.SaveUploadedFile(file, "./uploads/"+file.Filename)
c.String(200, "File %s uploaded successfully", file.Filename)
})
// Multiple files upload
r.POST("/upload-multiple", func(c *gin.Context) {
form, _ := c.MultipartForm()
files := form.File["files"]
for _, file := range files {
c.SaveUploadedFile(file, "./uploads/"+file.Filename)
}
c.String(200, "%d files uploaded", len(files))
})Lihat dokumentasi Upload file untuk detail lebih lanjut.
Bagaimana cara mengimplementasikan autentikasi dengan JWT?
Gunakan gin-contrib/jwt atau implementasikan middleware kustom. Berikut contoh minimal:
package main
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("your-secret-key")
type Claims struct {
Username string `json:"username"`
jwt.RegisteredClaims
}
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing authorization token"})
c.Abort()
return
}
// Remove "Bearer " prefix if present
if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
tokenString = tokenString[7:]
}
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil || !token.Valid {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
c.Abort()
return
}
if claims, ok := token.Claims.(*Claims); ok {
c.Set("username", claims.Username)
c.Next()
}
}
}Untuk autentikasi berbasis session, lihat Manajemen session.
Bagaimana cara mengatur logging permintaan?
Gin menyertakan middleware logger default melalui gin.Default(). Untuk logging JSON terstruktur di produksi, lihat Logging terstruktur.
Untuk kustomisasi log dasar:
r := gin.New()
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{
SkipPaths: []string{"/healthz"},
}))
r.Use(gin.Recovery())Lihat bagian Logging untuk semua opsi termasuk format kustom, output file, dan melewati query string.
Bagaimana cara menangani shutdown graceful?
Lihat Restart atau stop graceful untuk panduan lengkap dengan contoh kode.
Mengapa saya mendapatkan "404 Not Found" alih-alih "405 Method Not Allowed"?
Secara default, Gin mengembalikan 404 untuk rute yang tidak mendukung metode HTTP yang diminta. Atur HandleMethodNotAllowed = true untuk mengembalikan 405 sebagai gantinya:
r := gin.Default()
r.HandleMethodNotAllowed = true
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
r.Run()$ curl -X POST localhost:8080/ping
HTTP/1.1 405 Method Not Allowed
Allow: GETBagaimana cara mengikat parameter query dan data POST bersamaan?
Gunakan ShouldBind() yang secara otomatis memilih binding berdasarkan tipe konten:
type User struct {
Name string `form:"name" json:"name"`
Email string `form:"email" json:"email"`
Page int `form:"page"`
}
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBind(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, user)
})Lihat bagian Binding untuk semua opsi binding.
Bagaimana cara memvalidasi data permintaan?
Gin menggunakan go-playground/validator untuk validasi. Tambahkan tag validasi ke struct Anda:
type User struct {
Name string `json:"name" binding:"required,min=3,max=50"`
Email string `json:"email" binding:"required,email"`
Age int `json:"age" binding:"gte=0,lte=130"`
}
r.POST("/user", func(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"message": "User is valid"})
})Lihat Binding dan validasi untuk validator kustom dan penggunaan lanjutan.
Bagaimana cara menjalankan Gin dalam mode produksi?
Atur variabel lingkungan GIN_MODE ke release:
export GIN_MODE=release
# or
GIN_MODE=release ./your-appAtau atur secara programatis:
gin.SetMode(gin.ReleaseMode)Mode release menonaktifkan logging debug dan meningkatkan performa.
Bagaimana cara menangani koneksi database dengan Gin?
Lihat Integrasi database untuk panduan lengkap yang mencakup database/sql, GORM, connection pooling, dan pola dependency injection.
Bagaimana cara menguji handler Gin?
Gunakan net/http/httptest untuk menguji rute Anda:
func TestPingRoute(t *testing.T) {
router := gin.Default()
router.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/ping", nil)
router.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
assert.Contains(t, w.Body.String(), "pong")
}Lihat dokumentasi Pengujian untuk contoh lebih lanjut.
Pertanyaan Performa
Bagaimana cara mengoptimalkan Gin untuk lalu lintas tinggi?
- Use Release Mode: Set
GIN_MODE=release - Disable unnecessary middleware: Only use what you need
- Use
gin.New()instead ofgin.Default()for manual middleware control - Connection pooling: Configure database connection pools (see Database integration)
- Caching: Implement caching for frequently accessed data
- Load balancing: Use reverse proxy (nginx, HAProxy)
- Profiling: Use Go's pprof to identify bottlenecks
- Monitoring: Set up metrics and monitoring to track performance
Apakah Gin siap produksi?
Ya. Gin digunakan di produksi oleh banyak perusahaan dan telah teruji dalam skala besar. Lihat Pengguna untuk contoh proyek yang menggunakan Gin di produksi.
Pemecahan Masalah
Mengapa parameter rute saya tidak berfungsi?
Pastikan parameter rute menggunakan sintaks : dan diekstrak dengan benar:
// Correct
r.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
c.String(200, "User ID: %s", id)
})
// Not: /user/{id} or /user/Lihat Parameter di path untuk detail.
Mengapa middleware saya tidak dieksekusi?
Middleware harus didaftarkan sebelum rute atau grup rute:
// Correct order
r := gin.New()
r.Use(MyMiddleware()) // Register middleware first
r.GET("/ping", handler) // Then routes
// For route groups
auth := r.Group("/admin")
auth.Use(AuthMiddleware()) // Middleware for this group
{
auth.GET("/dashboard", handler)
}Lihat Menggunakan middleware untuk detail.
Mengapa binding permintaan gagal?
Alasan umum:
- Tag binding hilang: Tambahkan tag
json:"field"atauform:"field" - Content-Type tidak cocok: Pastikan klien mengirim header Content-Type yang benar
- Error validasi: Periksa tag validasi dan persyaratan
- Field yang tidak diekspor: Hanya field struct yang diekspor (huruf kapital) yang diikat
type User struct {
Name string `json:"name" binding:"required"` // ✓ Correct
Email string `json:"email"` // ✓ Correct
age int `json:"age"` // ✗ Won't bind (unexported)
}Lihat Binding dan validasi untuk detail.
File: src/content/docs/id/docs/deployment/index.md
title: "Deployment" sidebar: order: 10
Proyek Gin dapat di-deploy dengan mudah di penyedia cloud mana pun.
[Railway](https://www.railway.com)
Railway is a cutting-edge cloud development platform for deploying, managing, and scaling applications and services. It simplifies your infrastructure stack from servers to observability with a single, scalable, easy-to-use platform.
Follow the Railway guide to deploy your Gin projects.
[Seenode](https://seenode.com)
Seenode is a modern cloud platform designed specifically for developers who want to deploy applications quickly and efficiently. It offers git-based deployment, automatic SSL certificates, built-in databases, and a streamlined interface that gets your Gin applications live in minutes.
Follow the Seenode guide to deploy your Gin projects.
[Koyeb](https://www.koyeb.com)
Koyeb is a developer-friendly serverless platform to deploy apps globally with git-based deployment, TLS encryption, native autoscaling, a global edge network, and built-in service mesh & discovery.
Follow the Koyeb guide to deploy your Gin projects.
[Qovery](https://www.qovery.com)
Qovery provides free Cloud hosting with databases, SSL, a global CDN, and automatic deploys with Git.
See Qovery for more information.
[Render](https://render.com)
Render is a modern cloud platform that offers native support for Go, fully managed SSL, databases, zero-downtime deploys, HTTP/2, and websocket support.
Follow the Render guide to deploying Gin projects.
[Google App Engine](https://cloud.google.com/appengine/)
GAE has two ways to deploy Go applications. The standard environment is easier to use but less customizable and prevents syscalls for security reasons. The flexible environment can run any framework or library.
Learn more and pick your preferred environment at Go on Google App Engine.
Self Hosted
Proyek Gin juga dapat di-deploy secara self-hosted. Arsitektur deployment dan pertimbangan keamanan bervariasi tergantung pada lingkungan target. Bagian berikut hanya menyajikan gambaran tingkat tinggi dari opsi konfigurasi yang perlu dipertimbangkan saat merencanakan deployment.
Opsi Konfigurasi
Deployment proyek Gin dapat disesuaikan menggunakan variabel lingkungan atau langsung dalam kode.
Variabel lingkungan berikut tersedia untuk mengonfigurasi Gin:
| Variabel Lingkungan | Deskripsi |
|---|---|
| PORT | Port TCP untuk didengarkan saat memulai server Gin dengan router.Run() (yaitu tanpa argumen apa pun). |
| GIN_MODE | Atur ke salah satu dari debug, release, atau test. Menangani manajemen mode Gin, seperti kapan mengeluarkan output debug. Juga dapat diatur dalam kode menggunakan gin.SetMode(gin.ReleaseMode) atau gin.SetMode(gin.TestMode) |
Kode berikut dapat digunakan untuk mengonfigurasi Gin.
// Don't specify the bind address or port for Gin. Defaults to binding on all interfaces on port 8080.
// Can use the `PORT` environment variable to change the listen port when using `Run()` without any arguments.
router := gin.Default()
router.Run()
// Specify the bind address and port for Gin.
router := gin.Default()
router.Run("192.168.1.100:8080")
// Specify only the listen port. Will bind on all interfaces.
router := gin.Default()
router.Run(":8080")
// Set which IP addresses or CIDRs, are considered to be trusted for setting headers to document real client IP addresses.
// See the documentation for additional details.
router := gin.Default()
router.SetTrustedProxies([]string{"192.168.1.2"})Untuk informasi tentang mengonfigurasi proxy tepercaya, lihat Proxy Tepercaya.
File: src/content/docs/id/docs/build-tags/index.md
title: "Tag Build" sidebar: order: 11
Go build tags (juga disebut build constraints) adalah direktif yang memberitahu compiler Go untuk menyertakan atau mengecualikan file selama kompilasi. Gin menggunakan build tags untuk memungkinkan Anda mengganti implementasi internal atau menonaktifkan fitur opsional pada waktu kompilasi, tanpa mengubah kode aplikasi apa pun.
Ini berguna dalam beberapa skenario:
- Optimasi performa -- Ganti paket
encoding/jsondefault dengan encoder pihak ketiga yang lebih cepat untuk mempercepat serialisasi JSON di API Anda. - Pengurangan ukuran binary -- Hapus fitur yang tidak Anda gunakan, seperti rendering MsgPack, untuk menghasilkan binary yang lebih kecil.
- Penyesuaian deployment -- Pilih encoder berbeda untuk lingkungan berbeda (mis., build produksi throughput tinggi vs. build pengembangan standar).
Tag build diteruskan ke toolchain Go dengan flag -tags:
go build -tags=<tag_name> .You can combine multiple tags by separating them with commas:
go build -tags=nomsgpack,go_json .Tag build yang tersedia
| Tag | Effect |
|---|---|
go_json |
Replaces encoding/json with go-json |
jsoniter |
Replaces encoding/json with jsoniter |
sonic avx |
Replaces encoding/json with sonic (requires AVX CPU instructions) |
nomsgpack |
Disables MsgPack rendering support |
:::note
Tag build hanya memengaruhi cara Gin dikompilasi. Kode aplikasi Anda (handler rute, middleware, dll.) tidak perlu berubah saat Anda berganti tag.
:::
Dalam bagian ini
Halaman-halaman di bawah ini membahas setiap tag build secara detail:
- Build dengan penggantian JSON -- Ganti encoder JSON default dengan go-json, jsoniter, atau sonic untuk serialisasi yang lebih cepat.
- Build tanpa MsgPack -- Nonaktifkan rendering MsgPack dengan tag build
nomsgpackuntuk mengurangi ukuran binary.
File: src/content/docs/id/docs/build-tags/json-replacement.md
title: "Build dengan penggantian JSON" sidebar: order: 1
Gin menggunakan paket encoding/json pustaka standar untuk serialisasi dan deserialisasi JSON secara default. Encoder pustaka standar telah diuji dengan baik dan sepenuhnya kompatibel, tetapi bukan opsi tercepat yang tersedia. Jika performa JSON menjadi bottleneck dalam aplikasi Anda -- misalnya, dalam API throughput tinggi yang menyerialisasi payload respons besar -- Anda dapat mengganti dengan pengganti drop-in yang lebih cepat pada waktu build menggunakan tag build. Tidak diperlukan perubahan kode.
Pengganti yang tersedia
Gin mendukung tiga encoder JSON alternatif. Masing-masing mengimplementasikan antarmuka yang sama yang diharapkan Gin, sehingga handler, middleware, dan logika binding Anda terus bekerja tanpa modifikasi.
go-json
go-json is a pure-Go JSON encoder that offers significant performance improvements over encoding/json while maintaining full compatibility. It works on all platforms and architectures.
go build -tags=go_json .jsoniter
jsoniter (json-iterator) is another pure-Go, high-performance JSON library. It is API-compatible with encoding/json and provides a flexible configuration system for advanced use cases.
go build -tags=jsoniter .sonic
sonic is a blazing-fast JSON encoder developed by ByteDance. It uses JIT compilation and SIMD instructions to achieve maximum throughput, making it the fastest option among the three.
go build -tags="sonic avx" .:::note
Sonic requires a CPU with AVX instruction support. This is available on most modern x86_64 processors (Intel Sandy Bridge and later, AMD Bulldozer and later), but it will not work on ARM architectures or older x86 hardware. If your deployment target does not support AVX, use go-json or jsoniter instead.
:::
Memilih pengganti
| Encoder | Platform support | Key strength |
|---|---|---|
encoding/json (default) |
All | Maximum compatibility, no extra dependency |
| go-json | All | Good speedup, pure Go, broad compatibility |
| jsoniter | All | Good speedup, flexible configuration |
| sonic | x86_64 with AVX only | Highest throughput via JIT and SIMD |
Untuk sebagian besar aplikasi, go-json adalah pilihan yang aman dan efektif -- bekerja di mana saja dan memberikan peningkatan performa yang berarti. Pilih sonic ketika Anda membutuhkan throughput JSON maksimum dan server Anda berjalan pada hardware x86_64. Pilih jsoniter jika Anda membutuhkan fitur konfigurasi spesifiknya atau sudah menggunakannya di tempat lain dalam kode Anda.
Memverifikasi pengganti
Anda dapat mengonfirmasi bahwa pengganti aktif dengan membandingkan performa serialisasi dengan benchmark sederhana, atau dengan memeriksa tabel simbol binary:
# Build with go-json
go build -tags=go_json -o myapp .
# Check that go-json symbols are present
go tool nm myapp | grep goccyThe build tag also works with other Go commands:
go run -tags=go_json .
go test -tags=go_json ./...:::note
Only use one JSON replacement tag at a time. If you specify multiple JSON tags (e.g., -tags=go_json,jsoniter), the behavior is undefined. The nomsgpack tag can be safely combined with any JSON replacement tag.
:::
File: src/content/docs/id/docs/build-tags/nomsgpack.md
title: "Build tanpa MsgPack" sidebar: order: 2
MsgPack (MessagePack) adalah format serialisasi binary yang ringkas -- anggap saja sebagai alternatif JSON yang lebih cepat dan lebih kecil. Gin menyertakan dukungan rendering dan binding MsgPack secara default, yang berarti aplikasi Anda dapat menerima dan mengembalikan data berenkode MsgPack langsung menggunakan c.Bind() dan c.Render() dengan tipe konten yang sesuai.
Namun, banyak aplikasi hanya menggunakan JSON dan tidak pernah membutuhkan MsgPack. Dalam kasus tersebut, dependensi MsgPack menambah bobot yang tidak perlu ke binary yang dikompilasi. Anda dapat menghapusnya dengan tag build nomsgpack.
Building without MsgPack
Pass the nomsgpack tag to go build:
go build -tags=nomsgpack .This also works with other Go commands:
go run -tags=nomsgpack .
go test -tags=nomsgpack ./...What changes
When you build with nomsgpack, Gin excludes the MsgPack rendering and binding code at compile time. This has a few practical effects:
- The compiled binary is smaller because the MsgPack serialization library is not linked in.
- Any handler that attempts to render or bind MsgPack data will no longer work. If you use
c.ProtoBuf()or other non-MsgPack renderers, those are unaffected. - All JSON, XML, YAML, TOML, and ProtoBuf features continue to work normally.
:::note
If your API does not serve MsgPack responses and you do not call c.MsgPack() anywhere, it is safe to use this tag. Your existing JSON and HTML handlers will behave identically.
:::
Verifying the result
You can confirm the binary size reduction by comparing builds:
# Standard build
go build -o gin-app .
ls -lh gin-app
# Build without MsgPack
go build -tags=nomsgpack -o gin-app-nomsgpack .
ls -lh gin-app-nomsgpackThe exact savings depend on your application, but removing MsgPack typically shaves a small amount off the final binary. For more background, see the original pull request.
File: src/content/docs/id/docs/binding/bind-body-into-different-structs.md
title: "Mencoba bind body ke struct berbeda" sidebar: order: 13
Metode binding standar seperti c.ShouldBind mengonsumsi c.Request.Body, yang merupakan io.ReadCloser — setelah dibaca, tidak dapat dibaca lagi. Ini berarti Anda tidak dapat memanggil c.ShouldBind berkali-kali pada request yang sama untuk mencoba bentuk struct yang berbeda.
Untuk mengatasi ini, gunakan c.ShouldBindBodyWith. Metode ini membaca body sekali dan menyimpannya di context, memungkinkan binding berikutnya menggunakan kembali body yang sudah di-cache.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
type formA struct {
Foo string `json:"foo" xml:"foo" binding:"required"`
}
type formB struct {
Bar string `json:"bar" xml:"bar" binding:"required"`
}
func main() {
router := gin.Default()
router.POST("/bind", func(c *gin.Context) {
objA := formA{}
objB := formB{}
// This reads c.Request.Body and stores the result into the context.
if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil {
c.JSON(http.StatusOK, gin.H{"message": "matched formA", "foo": objA.Foo})
return
}
// At this time, it reuses body stored in the context.
if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
c.JSON(http.StatusOK, gin.H{"message": "matched formB", "bar": objB.Bar})
return
}
c.JSON(http.StatusBadRequest, gin.H{"error": "request body did not match any known format"})
})
router.Run(":8080")
}Uji coba
# Body matches formA
curl -X POST http://localhost:8080/bind \
-H "Content-Type: application/json" \
-d '{"foo":"hello"}'
# Output: {"foo":"hello","message":"matched formA"}
# Body matches formB
curl -X POST http://localhost:8080/bind \
-H "Content-Type: application/json" \
-d '{"bar":"world"}'
# Output: {"bar":"world","message":"matched formB"}:::notec.ShouldBindBodyWith menyimpan body di context sebelum melakukan binding. Ini memiliki sedikit dampak pada performa, jadi gunakan hanya ketika Anda perlu melakukan bind body lebih dari sekali. Untuk format yang tidak membaca body — seperti Query, Form, FormPost, FormMultipart — Anda dapat memanggil c.ShouldBind() berkali-kali tanpa masalah.
:::
Lihat juga
File: src/content/docs/id/docs/binding/bind-custom-unmarshaler.md
title: "Bind unmarshaler kustom" sidebar: order: 8
Untuk mengganti logika binding default Gin, definisikan fungsi pada tipe Anda yang memenuhi antarmuka encoding.TextUnmarshaler dari pustaka standar Go. Kemudian tentukan parser=encoding.TextUnmarshaler dalam tag uri/form dari field yang diikat.
package main
import (
"encoding"
"strings"
"github.com/gin-gonic/gin"
)
type Birthday string
func (b *Birthday) UnmarshalText(text []byte) error {
*b = Birthday(strings.Replace(string(text), "-", "/", -1))
return nil
}
var _ encoding.TextUnmarshaler = (*Birthday)(nil)
func main() {
route := gin.Default()
var request struct {
Birthday Birthday `form:"birthday,parser=encoding.TextUnmarshaler"`
Birthdays []Birthday `form:"birthdays,parser=encoding.TextUnmarshaler" collection_format:"csv"`
BirthdaysDefault []Birthday `form:"birthdaysDef,default=2020-09-01;2020-09-02,parser=encoding.TextUnmarshaler" collection_format:"csv"`
}
route.GET("/test", func(ctx *gin.Context) {
_ = ctx.BindQuery(&request)
ctx.JSON(200, request)
})
_ = route.Run(":8088")
}Uji dengan:
curl 'localhost:8088/test?birthday=2000-01-01&birthdays=2000-01-01,2000-01-02'Hasil:
{"Birthday":"2000/01/01","Birthdays":["2000/01/01","2000/01/02"],"BirthdaysDefault":["2020/09/01","2020/09/02"]}Catatan: Jika
parser=encoding.TextUnmarshalerditentukan untuk tipe yang tidak mengimplementasikanencoding.TextUnmarshaler, Gin akan mengabaikannya dan melanjutkan dengan logika binding default-nya.
Menggunakan BindUnmarshaler
Jika sebuah tipe sudah mengimplementasikan encoding.TextUnmarshaler tetapi Anda ingin menyesuaikan cara Gin mengikat tipe tersebut secara berbeda (mis., untuk mengubah pesan error yang dikembalikan), Anda dapat mengimplementasikan antarmuka BindUnmarshaler yang khusus.
package main
import (
"strings"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
type Birthday string
func (b *Birthday) UnmarshalParam(param string) error {
*b = Birthday(strings.Replace(param, "-", "/", -1))
return nil
}
var _ binding.BindUnmarshaler = (*Birthday)(nil)
func main() {
route := gin.Default()
var request struct {
Birthday Birthday `form:"birthday"`
Birthdays []Birthday `form:"birthdays" collection_format:"csv"`
BirthdaysDefault []Birthday `form:"birthdaysDef,default=2020-09-01;2020-09-02" collection_format:"csv"`
}
route.GET("/test", func(ctx *gin.Context) {
_ = ctx.BindQuery(&request)
ctx.JSON(200, request)
})
_ = route.Run(":8088")
}Catatan: Jika sebuah tipe mengimplementasikan baik
encoding.TextUnmarshalermaupunBindUnmarshaler, Gin akan menggunakanBindUnmarshalersecara default kecuali Anda menentukanparser=encoding.TextUnmarshalerdalam tag binding.
File: src/content/docs/id/docs/binding/bind-default-values.md
title: "Bind nilai default untuk field form" sidebar: order: 5
Terkadang Anda ingin sebuah field kembali ke nilai default ketika klien tidak mengirim nilai. Binding form Gin mendukung default melalui opsi default dalam tag struct form. Ini bekerja untuk skalar dan, mulai Gin v1.11, untuk koleksi (slice/array) dengan format koleksi eksplisit.
Poin penting:
- Letakkan default tepat setelah kunci form:
form:"name,default=William". - Untuk koleksi, tentukan cara memisahkan nilai dengan
collection_format:"multi|csv|ssv|tsv|pipes". - Untuk
multidancsv, gunakan titik koma dalam default untuk memisahkan nilai (mis.,default=1;2;3). Gin mengonversinya ke koma secara internal agar parser tag tetap tidak ambigu. - Untuk
ssv(spasi),tsv(tab), danpipes(|), gunakan pemisah alami dalam default.
Contoh:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type Person struct {
Name string `form:"name,default=William"`
Age int `form:"age,default=10"`
Friends []string `form:"friends,default=Will;Bill"` // multi/csv: use ; in defaults
Addresses [2]string `form:"addresses,default=foo bar" collection_format:"ssv"`
LapTimes []int `form:"lap_times,default=1;2;3" collection_format:"csv"`
}
func main() {
r := gin.Default()
r.POST("/person", func(c *gin.Context) {
var req Person
if err := c.ShouldBind(&req); err != nil { // infers binder by Content-Type
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, req)
})
_ = r.Run(":8080")
}Jika Anda POST tanpa body apapun, Gin merespons dengan nilai default:
curl -X POST http://localhost:8080/personRespons (contoh):
{
"Name": "William",
"Age": 10,
"Friends": ["Will", "Bill"],
"Addresses": ["foo", "bar"],
"LapTimes": [1, 2, 3]
}Catatan dan peringatan:
- Koma digunakan oleh sintaks tag struct Go untuk memisahkan opsi; hindari koma di dalam nilai default.
- Untuk
multidancsv, titik koma memisahkan nilai default; jangan sertakan titik koma di dalam default individual untuk format ini. - Nilai
collection_formatyang tidak valid akan menghasilkan error binding.
Perubahan terkait:
- Format koleksi untuk binding form (
multi,csv,ssv,tsv,pipes) ditingkatkan sekitar v1.11. - Nilai default untuk koleksi ditambahkan di v1.11 (PR #4048).
File: src/content/docs/id/docs/binding/bind-form-data-custom-struct-tag.md
title: "Bind form-data dengan tag struct kustom" sidebar: order: 14
Secara default, Gin menggunakan tag struct form untuk melakukan bind data form. Ketika Anda perlu melakukan bind struct yang menggunakan tag berbeda — misalnya, tipe eksternal yang tidak dapat Anda modifikasi — Anda dapat membuat binding kustom yang membaca dari tag Anda sendiri.
Ini berguna saat berintegrasi dengan pustaka pihak ketiga yang struct-nya menggunakan tag seperti url, query, atau nama kustom lainnya sebagai pengganti form.
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
const (
customerTag = "url"
defaultMemory = 32 << 20
)
type customerBinding struct{}
func (customerBinding) Name() string {
return "form"
}
func (customerBinding) Bind(req *http.Request, obj any) error {
if err := req.ParseForm(); err != nil {
return err
}
if err := req.ParseMultipartForm(defaultMemory); err != nil {
if err != http.ErrNotMultipart {
return err
}
}
if err := binding.MapFormWithTag(obj, req.Form, customerTag); err != nil {
return err
}
return validate(obj)
}
func validate(obj any) error {
if binding.Validator == nil {
return nil
}
return binding.Validator.ValidateStruct(obj)
}
// FormA is an external type that we can't modify its tag
type FormA struct {
FieldA string `url:"field_a"`
}
func main() {
router := gin.Default()
router.GET("/list", func(c *gin.Context) {
var urlBinding = customerBinding{}
var opt FormA
if err := c.MustBindWith(&opt, urlBinding); err != nil {
return
}
c.JSON(http.StatusOK, gin.H{"field_a": opt.FieldA})
})
router.Run(":8080")
}Uji coba
# The custom binding reads from the "url" struct tag instead of "form"
curl "http://localhost:8080/list?field_a=hello"
# Output: {"field_a":"hello"}
# Missing parameter -- empty string
curl "http://localhost:8080/list"
# Output: {"field_a":""}:::note
Binding kustom mengimplementasikan interface binding.Binding, yang memerlukan metode Name() string dan metode Bind(*http.Request, any) error. Helper binding.MapFormWithTag melakukan pekerjaan sebenarnya untuk memetakan nilai form ke field struct menggunakan tag kustom Anda.
:::