Membangun REST API dengan Gin Framework dan Golang


Gin adalah framework HTTP untuk Golang yang sangat ringan dan cepat. Ia populer karena kemudahan routing, integrasi JSON, serta dukungan middleware yang kuat. Artikel ini membahas langkah demi langkah membangun REST API CRUD berbasis Gin + GORM, lengkap dengan validasi, struktur proyek modular, serta tips deployment production.
Visualisasi Arsitektur
Gambar di atas memperlihatkan alur kerja REST API dengan pattern layered architecture. Request masuk ke router Gin, melewati middleware (seperti logger, recovery), lalu dikirim ke handler yang memanggil service. Service memproses logika bisnis dan berinteraksi dengan repository (GORM) untuk CRUD data.
1️⃣ Inisialisasi Proyek dan Dependensi
Pertama, buat folder proyek baru, inisialisasi module Go, dan install dependensi utama (Gin, GORM, validator, dotenv).
mkdir gin-books-api && cd gin-books-api
go mod init example.com/gin-books-api
go get github.com/gin-gonic/gin gorm.io/gorm gorm.io/driver/postgres
go get github.com/go-playground/validator/v10 github.com/joho/godotenv
Gin untuk routing HTTP, GORM untuk ORM ke database, validator untuk validasi payload, dan godotenv untuk memuat variabel lingkungan dari file `.env`.
2️⃣ Struktur Folder Proyek
.
├─ cmd/server/main.go # entry point
├─ internal/
│ ├─ config/ # konfigurasi aplikasi
│ ├─ database/ # koneksi DB
│ ├─ domain/book/ # model + DTO
│ ├─ handler/ # controller HTTP
│ ├─ middleware/ # logging & recovery
│ ├─ repository/ # query DB via GORM
│ └─ service/ # logika bisnis
└─ pkg/response/response.go # helper JSON response
Struktur ini memisahkan concern: handler fokus HTTP, service untuk logic, repository untuk akses data. Pendekatan ini menjaga maintainability proyek besar.
3️⃣ File Konfigurasi dan Environment
# .env
APP_PORT=8080
DB_DSN=host=localhost user=postgres password=secret dbname=booksdb port=5432 sslmode=disable
// internal/config/config.go
package config
import ("os"; "log"; "github.com/joho/godotenv")
type Config struct {
AppPort string
DBDsn string
}
func Load() *Config {
_ = godotenv.Load()
cfg := &Config{
AppPort: os.Getenv("APP_PORT"),
DBDsn: os.Getenv("DB_DSN"),
}
if cfg.DBDsn == "" { log.Fatal("DB_DSN kosong") }
return cfg
}
File ini bertanggung jawab membaca environment variable dan menyiapkan konfigurasi. Dengan cara ini, kamu bisa menjalankan aplikasi di berbagai environment tanpa hardcode credential.
4️⃣ Koneksi Database dengan GORM
// internal/database/postgres.go
package database
import ("gorm.io/gorm"; "gorm.io/driver/postgres"; "log")
func NewPostgres(dsn string) *gorm.DB {
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil { log.Fatalf("Gagal konek DB: %v", err) }
return db
}
Fungsi ini membuat instance koneksi database dengan driver Postgres. Jika gagal, program berhenti agar tidak melanjutkan dengan koneksi rusak.
5️⃣ Model dan DTO (Data Transfer Object)
// internal/domain/book/model.go
package book
import "time"
type Book struct {
ID uint `gorm:"primaryKey"`
Title string
Author string
Year int
CreatedAt time.Time
UpdatedAt time.Time
}
type CreateBookDTO struct {
Title string `validate:"required"`
Author string `validate:"required"`
Year int `validate:"gte=0"`
}
Struct `Book` adalah representasi tabel database. DTO digunakan untuk validasi input dari pengguna agar tidak langsung memakai entity database mentah.
6️⃣ Repository Layer
// internal/repository/book_repo.go
package repository
import ("gorm.io/gorm"; "example.com/gin-books-api/internal/domain/book")
type BookRepo struct { DB *gorm.DB }
func (r *BookRepo) FindAll() ([]book.Book, error) {
var books []book.Book
return books, r.DB.Find(&books).Error
}
Repository menyimpan fungsi CRUD yang berinteraksi langsung dengan database. Dengan layer ini, logika data terpisah dari handler dan service.
7️⃣ Service Layer
// internal/service/book_service.go
package service
import ("example.com/gin-books-api/internal/domain/book"; "example.com/gin-books-api/internal/repository")
type BookService struct { Repo *repository.BookRepo }
func (s *BookService) GetAllBooks() ([]book.Book, error) {
return s.Repo.FindAll()
}
Service layer mengelola logika bisnis, seperti validasi tambahan atau transformasi data sebelum dikirim ke handler. Dengan layer ini, unit test menjadi lebih mudah.
8️⃣ Handler & Routing
// internal/handler/book_handler.go
package handler
import ("github.com/gin-gonic/gin"; "net/http"; "example.com/gin-books-api/internal/service")
type BookHandler struct { Service *service.BookService }
func (h *BookHandler) GetBooks(c *gin.Context) {
books, _ := h.Service.GetAllBooks()
c.JSON(http.StatusOK, gin.H{"data": books})
}
Handler menerima request HTTP, memanggil service, dan mengirimkan response JSON ke client. Gin membuat binding data dan response JSON sangat mudah.
9️⃣ Middleware dan Server Entry Point
// cmd/server/main.go
package main
import ("github.com/gin-gonic/gin"; "example.com/gin-books-api/internal/config"; "example.com/gin-books-api/internal/database"; "example.com/gin-books-api/internal/handler"; "example.com/gin-books-api/internal/repository"; "example.com/gin-books-api/internal/service")
func main() {
cfg := config.Load()
db := database.NewPostgres(cfg.DBDsn)
repo := &repository.BookRepo{DB: db}
svc := &service.BookService{Repo: repo}
h := &handler.BookHandler{Service: svc}
r := gin.Default()
r.GET("/books", h.GetBooks)
r.Run(":" + cfg.AppPort)
}
File utama ini menginisialisasi semua komponen (config, DB, repo, service, handler) dan menjalankan server Gin. Rute `/books` menampilkan semua data buku dari database.
🔟 Kesimpulan
Dengan arsitektur modular ini, REST API berbasis Gin menjadi scalable dan mudah diuji. Setiap lapisan punya tanggung jawab terpisah, memudahkan pengembangan tim besar. Langkah selanjutnya bisa menambahkan fitur JWT Auth, pagination, logging, dan caching.