Skip to content
Beranda Blog CRUD Sederhana dengan GoFiber
Development 6 menit baca

CRUD Sederhana dengan GoFiber

Nurul

Nurul

Lead & Fullstack Engineer · 23 Desember 2023

Panduan praktis membangun REST API yang rapi di Go memakai GoFiber, GORM, dan arsitektur berlapis — route, handler, usecase, dan repository.

Membangun web API dengan Go itu lugas, dan memakai framework seperti GoFiber membuatnya lebih cepat lagi. Artikel ini membahas API CRUD produk sederhana — mulai dari struktur proyek, tiap lapisan arsitekturnya, sampai bagaimana semuanya terhubung.

Kode sumber lengkapnya tersedia di github.com/uhkrowi/go-simple-crud.

Persiapan

Pastikan environment Anda sudah terpasang Go. Proyek ini memakai MySQL untuk penyimpanan — Anda bisa menggantinya dengan database lain, tapi driver GORM dan konfigurasi .env perlu disesuaikan.

Titik Masuk

Di /cmd/app/main.go, fungsi main() menginisialisasi aplikasi dan menjalankan server. Fungsi setup() terpisah merangkai database, validator, dan route:

func main() {
    defer config.CloseDBConnection()

    app := fiber.New(fiber.Config{
        AppName: "CRUD",
    })

    app.Use(cors.New())

    setup(app)

    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }

    err := app.Listen(":" + port)
    if err != nil {
        panic(err)
    }
}

func setup(app *fiber.App) {
    config.InitDB()
    db := config.DBConn
    validate := validator.New()

    apiV1 := app.Group("/api/v1")
    route.ProductRoute(apiV1.Group("/product"), db, validate)
}

Modelnya

Model Product berada di /internal/app/model/product.go. Sebuah produk punya sejumlah record Variant. Tag gorm:"-" memberi tahu GORM untuk mengabaikan Variants saat operasi database langsung — field itu diisi manual di lapisan usecase.

type Product struct {
    ID       uuid.UUID  `gorm:"primaryKey;column:id" json:"id"`
    Name     string     `gorm:"column:name" json:"name"`
    IsActive bool       `gorm:"column:is_active" json:"is_active"`
    Variants []Variant  `gorm:"-" json:"variants"`
}

type Variant struct {
    ID          uuid.UUID `gorm:"primaryKey;column:id" json:"id"`
    Name        string    `gorm:"column:name" json:"name"`
    ProductID   uuid.UUID `gorm:"column:product_id" json:"product_id"`
    ProductName string    `gorm:"column:product_name" json:"product_name"`
    Price       float64   `gorm:"column:price" json:"price"`
    Stock       int       `gorm:"column:stock" json:"stock"`
}

Arsitektur Berlapis

Proyek ini mengikuti struktur berlapis yang rapi. Setiap lapisan punya satu tanggung jawab:

  • Route — memetakan endpoint HTTP ke handler yang tepat. Misalnya, GET /api/v1/product memanggil ProductHandler.GetAll.
  • Handler — menerima request HTTP, mem-parsing dan memvalidasi input, memanggil usecase, lalu mengembalikan response. Ia mengurus bentuk request/response, bukan logika bisnis.
  • Usecase — lapisan logika inti. Ia mengorkestrasi pemanggilan ke repository, menerapkan aturan bisnis (misalnya, "produk hanya bisa dinonaktifkan kalau tidak punya varian aktif"), dan bisa memanggil usecase lain.
  • Repository — semua interaksi database ada di sini. Usecase memanggil repository lewat interface, sehingga logika bisnisnya tetap bisa diuji secara terpisah.

Alur Create (Contoh)

Ketika klien mengirim POST /api/v1/product:

  1. Router mengarahkan request ke ProductHandler.Create.
  2. Handler mem-parsing body JSON menjadi struct Product dan menjalankan validasi lewat go-playground/validator. Kalau validasi gagal, ia langsung mengembalikan 400 beserta detailnya.
  3. Usecase membuat UUID untuk produk baru, lalu memanggil ProductRepository.Create.
  4. Repository menjalankan db.Create(&product) lewat GORM dan mengembalikan error bila ada.
  5. Handler menerima hasilnya dan mengembalikan 201 beserta produk yang dibuat, atau 500 bila ada yang gagal.

Kenapa Struktur Ini?

Memisahkan lapisan-lapisan ini mungkin terasa seperti boilerplate berlebih untuk aplikasi CRUD kecil, tapi manfaatnya cepat terasa seiring proyek membesar:

  • Anda bisa menguji usecase tanpa database sungguhan dengan mengganti repository-nya memakai mock.
  • Mengganti database (misalnya dari MySQL ke PostgreSQL) hanya menyentuh lapisan repository.
  • Menambah lapisan transport kedua (misalnya gRPC berdampingan dengan HTTP) bisa memakai ulang kode usecase dan repository yang sama.

Untuk API kecil ini opsional. Untuk apa pun yang menghadap produksi, biaya penyiapannya sepadan sejak hari pertama.

Penulis

Nurul

Nurul

Lead & Fullstack Engineer

Bagian dari tim SimpleFunc yang membangun solusi bersih dan skalabel untuk bisnis di seluruh Indonesia.

Kerja Sama

Punya proyek? Mari kita diskusikan bagaimana kami bisa membantu membangunnya.

Hubungi Kami