Tutorial

Lengkap Membuat REST API dengan Go

Lengkap Membuat REST API dengan Go

Go telah menjadi pilihan utama banyak developer untuk membangun REST API backend karena kombinasi performa tinggi, type safety, dan tooling yang sederhana. Banyak developer yang sebelumnya menulis API dengan Node.js dan Express — setiap project baru membutuhkan setup middleware, error handling, validasi, dan konfigurasi database secara manual. Setelah berpindah ke Go, seluruh proses tersebut menjadi lebih ringkas. Go bersifat statically typed dan compiled, sehingga cocok untuk microservice yang harus menangani ribuan request per detik.

Tutorial ini membahas cara membuat REST API lengkap dengan Go dan PostgreSQL — mulai dari setup project, pembuatan model, penanganan request, hingga deployment ke production. Pembaca diharapkan memiliki pemahaman dasar Go; tutorial ini tetap dijelaskan langkah demi langkah agar mudah diikuti.

Kenapa Memilih Go untuk Backend API?

Sebelum masuk ke coding, penting untuk memahami mengapa Go menjadi pilihan tepat untuk REST API. Pertama, performa — Go adalah compiled language yang mampu menangani jauh lebih banyak concurrent connections dibanding Node.js. Kedua, syntax yang clean — tidak ada callback hell atau pyramid of doom. Ketiga, standard library yang powerful — HTTP server sudah built-in, tidak perlu framework yang berat.

Type safety Go membuat maintenance jangka panjang menjadi lebih mudah, terutama untuk API production. Error handling-nya juga eksplisit — tidak ada error yang terlewat. Error sering menjadi masalah terbesar di production, dan Go memaksa developer untuk menangani setiap error secara eksplisit.

Benchmark yang banyak dibagikan komunitas menunjukkan API Go mampu menangani sekitar 45.000 request per detik di VPS 4 core, dibanding Node.js sekitar 8.000 di spesifikasi yang sama. Angka ini sangat bergantung pada skenario, payload, dan konfigurasi — dan belum termasuk connection pooling atau optimasi lanjutan. Data benchmark perlu divalidasi ulang di lingkungan masing-masing (lihat catatan di bagian Sumber & Validasi).

Setup Project dan Dependencies

Langkah pertama, buat folder project baru dan inisialisasi module Go:

mkdir go-rest-api && cd go-rest-api
go mod init github.com/username/go-rest-api

Install dependencies yang dibutuhkan. Untuk HTTP framework, Gin dipilih karena ringan dan performanya tinggi:

go get github.com/gin-gonic/gin
go get gorm.io/gorm
go get gorm.io/driver/postgres

Gin dipilih karena route handling yang cepat dan dukungan middleware yang lengkap. GORM menjadi pilihan ORM karena API-nya intuitif dan mendukung PostgreSQL dengan baik. Kombinasi kedua library ini sudah teruji di banyak production system.

Struktur Project yang Rapi

Struktur project yang baik sangat penting, terutama jika project akan di-scale. Struktur umum yang banyak digunakan:

go-rest-api/
├── main.go
├── config/
│   └── database.go
├── models/
│   └── user.go
├── handlers/
│   └── user_handler.go
├── middleware/
│   └── auth.go
├── routes/
│   └── routes.go
└── .env

Struktur ini memisahkan concerns dengan jelas: konfigurasi di folder config, data models di models, request handlers di handlers, autentikasi di middleware, dan definisi route di routes. Setiap file memiliki satu tanggung jawab — prinsip Single Responsibility yang membuat codebase mudah di-maintain. Pendekatan modular seperti ini juga disarankan dalam praktik arsitektur Go modern.

Folder tambahan seperti utils untuk helper functions, validators untuk request validation, dan DTOs untuk data transfer objects bisa ditambahkan sesuai kebutuhan. Untuk tutorial ini, struktur sederhana sudah cukup.

Koneksi Database PostgreSQL

Buat config database di config/database.go. Yang penting di sini adalah connection pooling — jangan pernah membuat koneksi baru di tiap request:

package config

import (
    "fmt"
    "os"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

var DB *gorm.DB

func ConnectDatabase() {
    dsn := fmt.Sprintf(
        "host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
        os.Getenv("DB_HOST"),
        os.Getenv("DB_USER"),
        os.Getenv("DB_PASS"),
        os.Getenv("DB_NAME"),
        os.Getenv("DB_PORT"),
    )
    
    database, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("Failed to connect to database!")
    }
    
    DB = database
    DB.AutoMigrate(&models.User{})
}

Gunakan environment variables untuk data sensitif. Jangan pernah hardcode credentials di source code — itu anti-pattern yang berbahaya. Pengelolaan secret yang aman bisa dipelajari lebih lanjut di artikel OneCLI Credential Gateway: Amankan Secret AI Agent. GORM AutoMigrate juga memudahkan schema management tanpa perlu raw SQL migration files di awal development.

Definisi Model

Model merepresentasikan struktur data di database. Untuk contoh ini, buat User model:

package models

import (
    "time"
    "gorm.io/gorm"
)

type User struct {
    ID        uint           `gorm:"primaryKey"`
    Name      string         `gorm:"size:100;not null"`
    Email     string         `gorm:"size:100;uniqueIndex;not null"`
    Password  string         `gorm:"size:255;not null"`
    CreatedAt time.Time
    UpdatedAt time.Time
}

Tag GORM seperti `gorm:"primaryKey"` menentukan perilaku kolom di database: size membatasi panjang kolom, uniqueIndex membuat index unik, dan not null mencegah nilai kosong. Kolom CreatedAt dan UpdatedAt diisi otomatis oleh GORM. Tag ini wajib ditulis menggunakan backtick (bukan tanda kutip biasa) karena merupakan raw string literal di Go.

Handler CRUD

Handler bertugas menerima request HTTP dan berkomunikasi dengan database. Buat handlers/user_handler.go dengan operasi dasar Create dan Read:

package handlers

import (
    "net/http"
    "github.com/gin-gonic/gin"
    "github.com/username/go-rest-api/config"
    "github.com/username/go-rest-api/models"
)

func CreateUser(c *gin.Context) {
    var user models.User
    if err := c.ShouldBindJSON(&user); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    if err := config.DB.Create(&user).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusCreated, user)
}

func GetUsers(c *gin.Context) {
    var users []models.User
    if err := config.DB.Find(&users).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusOK, users)
}

func GetUserByID(c *gin.Context) {
    id := c.Param("id")
    var user models.User
    if err := config.DB.First(&user, id).Error; err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
        return
    }
    c.JSON(http.StatusOK, user)
}

ShouldBindJSON memvalidasi payload JSON langsung ke struct, sementara config.DB.Create dan config.DB.Find adalah method GORM untuk operasi database. Setiap error dikembalikan sebagai respons JSON dengan status code yang sesuai — pola yang direkomendasikan agar API konsisten dan mudah di-debug oleh client.

Routes dan main.go

Definisikan route di routes/routes.go, lalu panggil dari main.go:

// routes/routes.go
package routes

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

func SetupRouter() *gin.Engine {
    r := gin.Default()
    api := r.Group("/api")
    {
        api.POST("/users", handlers.CreateUser)
        api.GET("/users", handlers.GetUsers)
        api.GET("/users/:id", handlers.GetUserByID)
    }
    return r
}
// main.go
package main

import (
    "github.com/username/go-rest-api/config"
    "github.com/username/go-rest-api/routes"
)

func main() {
    config.ConnectDatabase()
    r := routes.SetupRouter()
    r.Run(":8080")
}

Group /api memungkinkan penambahan middleware autentikasi (misalnya di folder middleware/auth.go) ke semua endpoint sekaligus tanpa mengubah tiap handler satu per satu. Setelah itu, API bisa dijalankan dengan go run main.go dan diuji dengan curl atau Postman.

Deploy ke Production

Binary Go adalah single executable — tidak ada runtime dependency yang harus diinstall di server. Build dengan perintah berikut:

GOOS=linux GOARCH=amd64 go build -o go-rest-api .
scp go-rest-api user@server:/opt/go-rest-api/

Jalankan sebagai service systemd agar restart otomatis saat server reboot, dan letakkan di belakang reverse proxy (Nginx atau Caddy) untuk SSL termination. Environment variables seperti DB_PASS disimpan di file .env yang tidak ikut di-commit ke repository. Pipeline build dan deployment yang otomatis bisa dibangun dengan GitHub Actions — panduan lengkapnya ada di artikel CI/CD Pipeline GitHub Actions: Panduan Lengkap Deploy Otomatis. Setelah live, pantau metrik server dan error rate dengan monitoring self-hosted Netdata, Grafana, dan Prometheus agar anomali terdeteksi lebih awal.

Sumber & Validasi

Catatan validasi: klaim benchmark "45.000 request per detik vs 8.000" pada artikel asli merupakan angka anekdotal yang banyak dibagikan komunitas, bukan hasil benchmark resmi yang terverifikasi — hasil aktual sangat bergantung pada hardware, payload, dan konfigurasi. Kode contoh di artikel ini diverifikasi secara sintaks terhadap versi Gin dan GORM terkini, tetapi tetap perlu diuji di lingkungan deployment masing-masing sebelum dipakai di production.

💬 Komentar (0)

Belum ada komentar. Jadilah yang pertama! 💬

Komentar akan muncul setelah moderasi.