Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/content/docs/id/docs/introduction/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: "Pengantar"
title: "Pendahuluan"
sidebar:
order: 1
---
Expand Down Expand Up @@ -27,28 +27,28 @@ Gin dapat menangkap panic yang terjadi selama permintaan HTTP dan memulihkannya.

### Validasi JSON

Gin dapat mem-parse dan memvalidasi JSON dari sebuah permintaan - misalnya, memeriksa keberadaan nilai yang wajib diisi.
Gin dapat melakukan parse dan memvalidasi JSON dari sebuah permintaan - misalnya, memeriksa keberadaan nilai yang wajib diisi.

### Pengelompokan Rute

Organisasikan rute Anda lebih baik. Memerlukan otorisasi vs tidak memerlukan, versi API berbeda... Selain itu, grup dapat disusun bertingkat tanpa batas tanpa menurunkan performa.

### Manajemen Error
### Manajemen Eror

Gin menyediakan cara praktis untuk mengumpulkan semua error yang terjadi selama permintaan HTTP. Pada akhirnya, middleware dapat menulisnya ke file log, ke database, dan mengirimnya melalui jaringan.
Gin menyediakan cara praktis untuk mengumpulkan semua eror yang terjadi selama permintaan HTTP. Pada akhirnya, middleware dapat menulisnya ke file log, ke database, dan mengirimnya melalui jaringan.

### Rendering Bawaan

Gin menyediakan API yang mudah digunakan untuk rendering JSON, XML, dan HTML.

### Dapat Diperluas
### Dapat Diekspansi

Membuat middleware baru sangat mudah, cukup lihat contoh kodenya.

## Gin v1. Stabil

- Router tanpa alokasi.
- Masih menjadi router dan framework HTTP tercepat. Dari routing hingga penulisan.
- Rangkaian lengkap pengujian unit.
- Teruji dalam pertempuran.
- Paket lengkap pengujian unit.
- Teruji di lapangan.
- API dibekukan, rilis baru tidak akan merusak kode Anda.
52 changes: 26 additions & 26 deletions src/content/docs/id/docs/routing/api-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ sidebar:
order: 10
---

Membangun API RESTful dengan Gin tidak hanya sekadar mendefinisikan rute. API yang dirancang dengan baik menggunakan format respons yang konsisten, paginasi yang dapat diprediksi, versioning yang jelas, dan penanganan error yang terstruktur. Panduan ini membahas pola-pola praktis yang dapat Anda terapkan pada aplikasi Gin produksi.
Membangun API RESTful dengan Gin tidak hanya sekadar mendefinisikan rute. API yang dirancang dengan baik menggunakan format respons yang konsisten, paginasi yang dapat diprediksi, pembuatan versi yang jelas, dan penanganan eror yang terstruktur. Panduan ini membahas pola-pola praktis yang dapat Anda terapkan pada aplikasi Gin produksi.

## Format respons yang konsisten

Membungkus setiap respons dalam envelope standar memudahkan konsumen API. Mereka selalu tahu di mana menemukan data, error, dan metadata.
Membungkus setiap respons dalam envelope standar memudahkan konsumen API. Mereka selalu tahu di mana menemukan data, eror, dan metadata.

```go
package main
Expand All @@ -19,7 +19,7 @@ import (
"github.com/gin-gonic/gin"
)

// Response is the standard API envelope.
// Response merupakan pembungkus API standar.
type Response struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Expand All @@ -39,15 +39,15 @@ type Meta struct {
TotalPages int `json:"total_pages,omitempty"`
}

// OK sends a success response.
// OK mengirimkan respons sukses.
func OK(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, Response{
Success: true,
Data: data,
})
}

// Fail sends an error response.
// Fail mengirimkan respons eror.
func Fail(c *gin.Context, status int, code, message string) {
c.JSON(status, Response{
Success: false,
Expand All @@ -60,7 +60,7 @@ func main() {

r.GET("/api/users/:id", func(c *gin.Context) {
id := c.Param("id")
// Simulate a lookup
// Simulasi pencarian
if id == "0" {
Fail(c, http.StatusNotFound, "USER_NOT_FOUND", "no user with that ID")
return
Expand Down Expand Up @@ -96,7 +96,7 @@ func main() {
offset, _ := strconv.Atoi(c.DefaultQuery("offset", "0"))

if limit > 100 {
limit = 100 // cap the page size
limit = 100 // batasi ukuran halaman
}

// articles, total := db.ListArticles(limit, offset)
Expand Down Expand Up @@ -134,7 +134,7 @@ func main() {
r := gin.Default()

r.GET("/api/events", func(c *gin.Context) {
cursor := c.Query("cursor") // e.g. last event ID
cursor := c.Query("cursor") // contoh: ID event terakhir
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))

if limit > 100 {
Expand All @@ -147,7 +147,7 @@ func main() {
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": []gin.H{}, // events
"next_cursor": "", // nextCursor (empty string means no more pages)
"next_cursor": "", // nextCursor (string kosong berarti tidak ada halaman lagi)
})
})

Expand Down Expand Up @@ -179,7 +179,7 @@ func main() {
sortBy := c.DefaultQuery("sort", "created_at")
order := c.DefaultQuery("order", "desc")

// Validate the sort field against an allow-list to prevent injection.
// Validasi field sort terhadap allow-list untuk mencegah injeksi.
allowed := map[string]bool{"created_at": true, "price": true, "name": true}
if !allowed[sortBy] {
sortBy = "created_at"
Expand All @@ -188,7 +188,7 @@ func main() {
order = "desc"
}

// Build and execute your query using these filters...
// Bangun dan jalankan query Anda menggunakan filter ini...
_ = category
_ = minPrice
_ = maxPrice
Expand All @@ -210,11 +210,11 @@ func main() {
}
```

## Versioning API
## Pembuatan versi API

### Versioning path URL
### Pembuatan versi path URL

Versioning path URL adalah strategi yang paling umum. Ini eksplisit, mudah di-routing, dan sederhana untuk diuji dengan `curl`.
Pembuatan versi path URL adalah strategi yang paling umum. Ini eksplisit, mudah dilakukan routing, dan sederhana untuk diuji dengan `curl`.

```go
package main
Expand All @@ -238,7 +238,7 @@ func main() {
v2 := r.Group("/api/v2")
{
v2.GET("/users", func(c *gin.Context) {
// v2 returns a different shape
// v2 mengembalikan bentuk yang berbeda
c.JSON(http.StatusOK, gin.H{
"version": "v2",
"data": []gin.H{},
Expand All @@ -251,9 +251,9 @@ func main() {
}
```

### Versioning berbasis header
### Pembuatan versi berbasis header

Versioning header menjaga URL tetap bersih tetapi mengharuskan klien mengatur header kustom. Middleware dapat membaca header dan menyimpan versi dalam context.
Pembuatan versi header menjaga URL tetap bersih tetapi mengharuskan klien mengatur header tersuai. Middleware dapat membaca header dan menyimpan versi dalam context.

```go
package main
Expand All @@ -264,12 +264,12 @@ import (
"github.com/gin-gonic/gin"
)

// VersionMiddleware reads the API version from the Accept-Version header.
// VersionMiddleware membaca versi API dari header Accept-Version.
func VersionMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
version := c.GetHeader("Accept-Version")
if version == "" {
version = "v1" // default
version = "v1" // bawaan
}
c.Set("api_version", version)
c.Next()
Expand All @@ -295,11 +295,11 @@ func main() {
}
```

## Pola penanganan error
## Pola penanganan eror

### Tipe error kustom
### Tipe eror tersuai

Definisikan tipe error tingkat aplikasi sehingga handler dapat mengembalikan error yang bermakna dan terstruktur.
Definisikan tipe eror tingkat aplikasi sehingga handler dapat mengembalikan eror yang bermakna dan terstruktur.

```go
package main
Expand All @@ -311,7 +311,7 @@ import (
"github.com/gin-gonic/gin"
)

// AppError represents a structured API error.
// AppError merepresentasikan eror API yang terstruktur.
type AppError struct {
Status int `json:"-"`
Code string `json:"code"`
Expand All @@ -328,7 +328,7 @@ var (
ErrBadRequest = &AppError{Status: 400, Code: "BAD_REQUEST", Message: "invalid request"}
)

// ErrorHandler is a middleware that catches errors set via c.Error().
// ErrorHandler adalah middleware yang menangkap set eror melalui c.Error().
func ErrorHandler() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
Expand Down Expand Up @@ -383,7 +383,7 @@ import (
"github.com/gin-gonic/gin"
)

// RegisterUserRoutes sets up all /users endpoints.
// RegisterUserRoutes mendaftarkan semua endpoint /users.
func RegisterUserRoutes(rg *gin.RouterGroup) {
users := rg.Group("/users")
{
Expand All @@ -395,7 +395,7 @@ func RegisterUserRoutes(rg *gin.RouterGroup) {
}
}

// RegisterOrderRoutes sets up all /orders endpoints.
// RegisterOrderRoutes mendaftarkan semua endpoint /orders.
func RegisterOrderRoutes(rg *gin.RouterGroup) {
orders := rg.Group("/orders")
{
Expand Down
14 changes: 7 additions & 7 deletions src/content/docs/id/docs/routing/grouping-routes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ sidebar:

Grup rute memungkinkan Anda mengorganisasi rute terkait di bawah prefix URL bersama. Ini berguna untuk:

- **Versioning API** -- mengelompokkan semua endpoint v1 di bawah `/v1` dan endpoint v2 di bawah `/v2`.
- **Pembuatan versi API** -- mengelompokkan semua endpoint v1 di bawah `/v1` dan endpoint v2 di bawah `/v2`.
- **Middleware bersama** -- menerapkan autentikasi, logging, atau rate-limiting ke seluruh set rute sekaligus alih-alih memasang middleware ke setiap rute satu per satu.
- **Organisasi kode** -- menjaga handler terkait terkelompok secara visual dalam kode sumber Anda.

Expand Down Expand Up @@ -36,15 +36,15 @@ func readEndpoint(c *gin.Context) {
func main() {
router := gin.Default()

// Simple group: v1
// Grup sederhana: v1
{
v1 := router.Group("/v1")
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}

// Simple group: v2
// Grup sederhana: v2
{
v2 := router.Group("/v2")
v2.POST("/login", loginEndpoint)
Expand All @@ -61,24 +61,24 @@ func main() {
Anda dapat meneruskan middleware ke `router.Group()` atau memanggil `Use()` pada grup. Setiap rute dalam grup tersebut akan menjalankan middleware sebelum handler-nya.

```go
// AuthRequired is a placeholder for your auth middleware.
// AuthRequired adalah placeholder untuk middleware autentikasi Anda.
func AuthRequired() gin.HandlerFunc {
return func(c *gin.Context) {
// ... check token, session, etc.
// ... periksa token, session, dll.
c.Next()
}
}

func main() {
router := gin.Default()

// Public routes -- no auth required
// Rute publik -- tidak memerlukan autentikasi
public := router.Group("/api")
{
public.GET("/health", healthCheck)
}

// Private routes -- auth middleware applied to the whole group
// Rute privat -- middleware autentikasi diterapkan ke seluruh grup
private := router.Group("/api")
private.Use(AuthRequired())
{
Expand Down
24 changes: 12 additions & 12 deletions src/content/docs/id/docs/routing/http-method.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ func options(c *gin.Context) {
}

func main() {
// Creates a gin router with default middleware:
// logger and recovery (crash-free) middleware
// Membuat router Gin dengan middleware bawaan:
// logger dan middleware recovery (bebas crash)
router := gin.Default()

router.GET("/someGet", getting)
Expand All @@ -66,10 +66,10 @@ func main() {
router.HEAD("/someHead", head)
router.OPTIONS("/someOptions", options)

// By default it serves on :8080 unless a
// PORT environment variable was defined.
// Secara bawaan berjalan di :8080 kecuali
// variabel lingkungan PORT telah ditentukan.
router.Run()
// router.Run(":3000") for a hard coded port
// router.Run(":3000") menentukan port secara langsung di kode
}
```

Expand All @@ -78,25 +78,25 @@ func main() {
Setelah server berjalan, Anda dapat menguji setiap endpoint:

```sh
# GET request
# Permintaan GET
curl -X GET http://localhost:8080/someGet

# POST request
# Permintaan POST
curl -X POST http://localhost:8080/somePost

# PUT request
# Permintaan PUT
curl -X PUT http://localhost:8080/somePut

# DELETE request
# Permintaan DELETE
curl -X DELETE http://localhost:8080/someDelete

# PATCH request
# Permintaan PATCH
curl -X PATCH http://localhost:8080/somePatch

# HEAD request (returns headers only, no body)
# Permintaan HEAD (mengembalikan header saja, tanpa body)
curl -I http://localhost:8080/someHead

# OPTIONS request
# Permintaan OPTIONS
curl -X OPTIONS http://localhost:8080/someOptions
```

Expand Down
8 changes: 4 additions & 4 deletions src/content/docs/id/docs/routing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar:
order: 3
---

Gin menyediakan sistem routing yang powerful yang dibangun di atas [httprouter](https://github.com/julienschmidt/httprouter) untuk pencocokan URL berperforma tinggi. Di balik layar, httprouter menggunakan [radix tree](https://en.wikipedia.org/wiki/Radix_tree) (juga disebut compressed trie) untuk menyimpan dan mencari rute, yang berarti pencocokan rute sangat cepat dan tidak memerlukan alokasi memori per pencarian. Ini menjadikan Gin salah satu framework web Go tercepat yang tersedia.
Gin menyediakan sistem routing powerful yang dibangun di atas [httprouter](https://github.com/julienschmidt/httprouter) untuk pencocokan URL berperforma tinggi. Di balik layar, httprouter menggunakan [radix tree](https://en.wikipedia.org/wiki/Radix_tree) (juga disebut compressed trie) untuk menyimpan dan mencari rute, yang berarti pencocokan rute sangat cepat dan tidak memerlukan alokasi memori per pencarian. Ini menjadikan Gin salah satu framework web Go tercepat yang tersedia.

Rute didaftarkan dengan memanggil metode HTTP pada engine (atau grup rute) dan menyediakan pola URL beserta satu atau lebih fungsi handler:

Expand Down Expand Up @@ -38,11 +38,11 @@ func main() {
Halaman-halaman di bawah ini membahas setiap topik routing secara detail:

- [**Menggunakan metode HTTP**](./http-method/) -- Mendaftarkan rute untuk GET, POST, PUT, DELETE, PATCH, HEAD, dan OPTIONS.
- [**Parameter di path**](./param-in-path/) -- Menangkap segmen dinamis dari path URL (mis. `/user/:name`).
- [**Parameter di path**](./param-in-path/) -- Menangkap segmen dinamis dari path URL (misal `/user/:name`).
- [**Parameter querystring**](./querystring-param/) -- Membaca nilai query string dari URL permintaan.
- [**Query dan post form**](./query-and-post-form/) -- Mengakses data query string dan POST form dalam handler yang sama.
- [**Map sebagai querystring atau postform**](./map-as-querystring-or-postform/) -- Mengikat parameter map dari query string atau POST form.
- [**Form multipart/urlencoded**](./multipart-urlencoded-form/) -- Mem-parse body `multipart/form-data` dan `application/x-www-form-urlencoded`.
- [**Upload file**](./upload-file/) -- Menangani upload file tunggal dan banyak.
- [**Form multipart/urlencoded**](./multipart-urlencoded-form/) -- Melakukan parse body `multipart/form-data` dan `application/x-www-form-urlencoded`.
- [**Unggah file**](./upload-file/) -- Menangani unggahan file tunggal dan banyak.
- [**Mengelompokkan rute**](./grouping-routes/) -- Mengorganisasi rute di bawah prefix umum dengan middleware bersama.
- [**Redirect**](./redirects/) -- Melakukan redirect HTTP dan tingkat router.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ sidebar:
order: 6
---

Terkadang Anda perlu menerima sekumpulan pasangan kunci-nilai di mana kunci tidak diketahui sebelumnya — misalnya, filter dinamis atau metadata yang ditentukan pengguna. Gin menyediakan `c.QueryMap` dan `c.PostFormMap` untuk mem-parse parameter notasi bracket (seperti `ids[a]=1234`) menjadi `map[string]string`.
Terkadang Anda perlu menerima sekumpulan pasangan kunci-nilai dengan kunci yang tidak diketahui sebelumnya — misalnya, filter dinamis atau metadata yang ditentukan pengguna. Gin menyediakan `c.QueryMap` dan `c.PostFormMap` untuk melakukan parse parameter notasi braket (seperti `ids[a]=1234`) menjadi `map[string]string`.

- `c.QueryMap("key")` — mem-parse pasangan `key[subkey]=value` dari query string URL.
- `c.PostFormMap("key")` — mem-parse pasangan `key[subkey]=value` dari body request.
- `c.QueryMap("key")` — melakukan parse pasangan `key[subkey]=value` dari query string URL.
- `c.PostFormMap("key")` — melakukan parse pasangan `key[subkey]=value` dari body permintaan.

```go
package main
Expand Down Expand Up @@ -46,7 +46,7 @@ curl -X POST "http://localhost:8080/post?ids[a]=1234&ids[b]=hello" \
```

:::note
Notasi bracket `ids[a]=1234` adalah konvensi umum. Gin mem-parse bagian di dalam bracket sebagai kunci map. Hanya bracket satu tingkat yang didukung — bracket bersarang seperti `ids[a][b]=value` tidak diparsing sebagai map bersarang.
Notasi braket `ids[a]=1234` adalah konvensi umum. Gin melakukan parse bagian di dalam braket sebagai kunci map. Hanya braket satu tingkat yang didukung — braket bersarang seperti `ids[a][b]=value` tidak dilakukan parsing sebagai map bersarang.
:::

## Lihat juga
Expand Down
Loading
Loading