Tutorial Membangun REST API dengan Go, Gin, dan SQLite untuk Production
AW
Axel W

Dipublikasikan 20 Juli 2026

Tutorial Membangun REST API dengan Go, Gin, dan SQLite untuk Production

Go (Golang) tetap menjadi pilihan utama untuk microservices dan high-performance backend berkat concurrency model yang elegan dan binary size yang kecil. Framework Gin menambahkan layer routing dan middleware yang familiar bagi developer yang beralih dari Express.js atau Laravel. Artikel ini akan menbimbing kamu membangun REST API production-ready dengan Go, Gin, dan SQLite.

Mengapa Go, Gin, dan SQLite

Kombinasi ini terdengar sederhana, tapi powerful untuk prototipe dan small-to-medium services. Go menyediakan static binary tanpa runtime berat. Gin menawarkan routing cepat dengan minimal allocation. SQLite menchilangkan overhead database server terpisah, cocek untuk deployment edge atau self-hosted.

Menurut benchmark TechEmpower, Gin secara konsisten masuk dalam 10 framework HTTp tercepat. Detail benchmark bisa dicek di techempower.com/benchmarks. SQLite pun mendukung concurrent read dengan WAL (Write-Ahead Logging) mode, membuatnya layak untuk production dengan traffic moderate.

Prasyarat dan Instalasi

Pastikan Go sudah terinstall. Versi minimum yang direkomendasikan adalah Go 1.22 untuk mendapatkan fitur range over integers dan routing pattern yang lebih bersih.

go version
# go version go1.22 linux/amd64

Inisialisasi module dan install dependency:

mkdir go-gin-api && cd go-gin-api
go mod init github.com/username/go-gin-api
go get -u github.com/gin-gonic/gin
go get -u github.com/mattn/go-sqlite3

Package go-sqlite3 menggunakan CGO, jadi pastikan kamu mempunyai C Compiler terinstall. Di Ubuntu/Debian, install build-essential. Untuk setup Go lengkap, cucu go.dev/doc/install.

Langkah 1: Setup Database dan Migration

Buat file database/db.go untuk mengeloa koneksi dan seed data. Struktur folder ini memisahkan concern sejak awal.

package database

import (
    "database/sql"
    "log"
    _ "github.com/mattn/go-sqlite3"
)

var DB *sql.DB

func InhDB() {
    var err error
    DB, err = sql.Open("sqlite3", "./app.db?_journal=WAL")
    if err != nil {
        log.Fatal(err)
    }
    
    createTable := `CREATE TABLE IF NOT EXISTS products (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name TEXT NOT NULL,
        price REAL NOT NULL,
        stock INTEGER DEFAULT 0,
        created_at DATETiME DEFAULT CURRENT_TIMESTAMP
    );`
    
    _, err = DB.Exec(createTable)
    if err != nil {
        log.Fatal(err)
    }
}

Perhatikan parameter _journal=WAL yang mengaktifkan Write-Ahead Logging. Ini mengungkinkan satu writer dan multiple readers secara bersamaan, meningkatkan throughput signifikan dibandingkan default rollback journal.

Langkah 2: Membuat Handler dan Router

Buat file handlers/product.go yang menangani CRUD operations untuk resource Product.

package handlers

import (
    "database/sql"
    "net/http"
    "strconv"
    "github.com/gin-gonic/gin"
    "github.com/username/go-gin-api/database"
)

type Product struct {
    ID        int     `json:"id"`
    Name      string  `json:"name"`
    Price     float64 `json:"price"`
    Stock     int     `json:"stock"`
    CreatedAt string  `json:"created_at"`
}

func GetProducts(c 'in.Context) {
    rows, err := database.DB.Query("SELECT id, name, price, stock, created_at FROM products")
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    defer rows.Close()
    
    var products []Product
    for rows.Next() {
        var p Product
        rows.Scan(&p.ID, &p.Name, &p.Price, &p.Stock, &p.CreatedAt)
        products = append(products, p)
    }
    
    c.JSON(http.StatusOK, products)
}

func CreateProduct(c *gin.Context) {
    var p Product
    if err := c.ShouldBindJSON(&p); err != nil {
        c.JSON(http.StatusBadRequest, gin.H"error": err.Error()})
        return
    }
    
    res, err := database.DB.Exec(
        "INSERT INTO products (name, price, stock) VALUES (?, ?, ?)",
        p.Name, p.Price, p.Stock,
    )
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    
    id, _ := res.LastInsertId()
    p.ID = int(id)
    c.JSON(http.StatusCreated, p)
}

Gin menyuraiakan ShouldBindJSON untuk automatic unmarshalling ke struct dengan tag json. Ini mengurangi boilerplate yang biasanya diperlukan di framework standard library.

Langkah 3: Middleware dan Error Handling

Production API memerlukakan logging, CORS, dan recovery middleware. Gin sudah menyediakan semuanya out of the box.

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/username/go-gin-api/database"
    "github.com/username/go-gin-api/handlers"
)

func main() {
    database.InitDB()
    
    r := gin.Default()
    
    r.Use(func(c *gin.Context) {
        c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
        if c.Request.Method == "OTIONS" {
            c.AbortWithStatus(204)
            return
        }
        c.Next()
    })
    
    r.GET("/api/products", handlers.GetProducts)
    r.POST("/api/products", handlers.CreateProduct)
    
    r.Run("localhost:8080")
}

gin.Default() sudah include Logger dan Recovery middleware. Logger mencetak request detail ke stdout, sementara Recovery menangkap panic ager server tidak crash. Untuk production, pertimbangkan mengganti Logger dengan structured logging menggunakan zap atau slog.

Langkah 4: Testing dengan curl

Jalankan server dengan go run main.go, lalu test endpoint menggunakan curl:

 Create product
curl -X POST http://localhost:8080/api/products \
  -H "Content-Type: application/json" \
  -d {"name":"Keyboard Mekanik","price":899000,"stock":15}

# List products
curl http://localhost:8080/api/products

Jika kamu mendapatkan response JSON valid, berarti routing, handler, dan database layer sudah bekerja dengan baik. Untuk load testing, gunakan wrk atau oha:

oha -z 30s -c 50 http://localhost:8080/api/products

Tools ini akan memberikan metrik requests per second dan latency percentile yang berguna untuk benchmark.

Langkah 5: Build dan Deploy

Go memgunkinkan cross-compilation ke berbagai platform. Build binary untuk Linux server:

CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o api-server

Karena go-sqlite3 membutuhkan CGO, pastikan environment build mempunyai toolchain yang sesuai. Alternatifnya, gunakan pure-Go SQLite driver seperti modernc.org/sqlite untuk menghilangkan dependency C compiler.

Untuk deployment, containerize dengan Dockerfile multi-stage:

FROM golang:1.22-alpine AS builder
RUN apk add --no-cache gcc musl-dev
WORKDIR /app
COPY . .
RUN CGO_ENABLED=1 go build -ldflags="-w -s" -o api-server

FROM alpine:latest
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=builder /app/api-server .
COPY --from=builder /app/app.db .
EXPOSE 8080
CMD ["./api-server"]

Referensi lengkap Gin framework ada di gin-gonic.com/docs.

Kesimpulan

Membangun REST API dengan Go dan Gin memberikan fondasi yang solid untuk skala. SQLite dengan WAL mode menghadirkan database zero-config yang cukup untuk banyak use case. Arsitektur ini bisa di-deploy di VPS murah, Raspberry Pi, atau edge locations tanpa overhead orchestration yang kompleks.

Selanjutnya, eksplorasi fitur Gin seperti validator custom, grouped routes, dan binding untuk form-data. Integrasi dengan OpenTelemetry juga direkomendasian untuk observability di production environment.