title: 121 Studi Kasus: API GraphQL Produk & Kategori dengan gqlgen
subtitle: Membongkar Arsitektur, Implementasi, dan Studi Kasus API Product-Categories dengan gqlgen di Golang
author: insinyursoftware
date: 2024-06-22
tags: [graphql, golang, gqlgen, backend, studi-kasus, api]
GraphQL semakin populer sebagai solusi API yang fleksibel, terutama untuk skenario relasi data yang kompleks. Di antara sekian banyak tools di ekosistem Go, gqlgen muncul sebagai salah satu framework paling solid untuk membangun GraphQL API di Golang.
Dalam artikel ini, saya akan membagikan pengalaman membangun API sederhana untuk produk dan kategori, lengkap dengan studi kasus, simulasi query, dan pembahasan arsitektur kode menggunakan gqlgen. Untuk pemahaman lebih baik, saya sertai contoh kode, skema database sederhana, dan visualisasi flow pengambilan data antar entitas.
1. Studi Kasus
Anggap saja kita membangun sebuah sistem e-commerce sederhana yang hanya memiliki dua entitas utama:
- Produk
- Memiliki
id,nama,harga, dankategori_id.
- Memiliki
- Kategori
- Memiliki
iddannama.
- Memiliki
Hubungan antar entitas:
- Produk dimiliki oleh satu Kategori.
- Kategori bisa memiliki banyak Produk.
Kita ingin menyediakan API yang mampu:
- Query daftar produk beserta detail kategorinya.
- Query daftar kategori beserta produk-produknya.
- Mendukung filter dan relasi.
2. Struktur Database
Berikut ini tabel relasional yang digunakan:
| produk | kategori |
|---|---|
| id (int) | id (int) |
| nama (string) | nama (string) |
| harga (int) | |
| kategori_id |
3. Merancang Schema GraphQL
Kita mulai dari mendefinisikan schema GraphQL (schema.graphqls):
type Produk {
id: ID!
nama: String!
harga: Int!
kategori: Kategori! # ini relasi Kategori (One-to-Many)
}
type Kategori {
id: ID!
nama: String!
produk: [Produk!]! # ini relasi Produk (Many-to-One)
}
type Query {
produkList: [Produk!]!
kategoriList: [Kategori!]!
produkByKategori(kategoriId: ID!): [Produk!]!
}
4. Struktur Proyek
Pastikan struktur project kurang lebih seperti ini:
.
├── gqlgen.yml
├── go.mod
├── main.go
├── graph
│ ├── model
│ │ └── models_gen.go
│ ├── resolver.go
│ ├── schema.graphqls
│ ├── schema.resolvers.go
│ └── database.go
5. Implementasi dengan gqlgen
a. Generate Code Skeleton
Install dulu:
go get github.com/99designs/gqlgen
go run github.com/99designs/gqlgen generate
Setelah itu, gqlgen akan mengenerate boilerplate untuk resolver dan model.
b. Membuat Mock Database
Untuk studi kasus, kita cukup in-memory data store sederhana saja.
// graph/database.go
package graph
import "graph/model"
var kategoriData = []*model.Kategori{
{ID: "1", Nama: "Elektronik"},
{ID: "2", Nama: "Fashion"},
}
var produkData = []*model.Produk{
{ID: "1", Nama: "Laptop", Harga: 10000000, KategoriID: "1"},
{ID: "2", Nama: "HP", Harga: 4000000, KategoriID: "1"},
{ID: "3", Nama: "Celana Jeans", Harga: 250000, KategoriID: "2"},
}
Tambahkan field KategoriID ke model. Jika auto-generation belum mendukung, edit langsung modelnya:
// graph/model/models_gen.go
type Produk struct {
ID string `json:"id"`
Nama string `json:"nama"`
Harga int `json:"harga"`
KategoriID string `json:"kategoriId"` // penting untuk relasi!
Kategori *Kategori `json:"kategori"`
}
c. Implementasi Resolver
Query produkList
// graph/schema.resolvers.go
func (r *queryResolver) ProdukList(ctx context.Context) ([]*model.Produk, error) {
return produkData, nil
}
func (r *queryResolver) KategoriList(ctx context.Context) ([]*model.Kategori, error) {
return kategoriData, nil
}
func (r *queryResolver) ProdukByKategori(ctx context.Context, kategoriID string) ([]*model.Produk, error) {
var result []*model.Produk
for _, p := range produkData {
if p.KategoriID == kategoriID {
result = append(result, p)
}
}
return result, nil
}
Resolver Field Relasi
Karena di schema Produk punya field kategori, kita perlu resolver custom untuk ini:
func (r *produkResolver) Kategori(ctx context.Context, obj *model.Produk) (*model.Kategori, error) {
for _, k := range kategoriData {
if k.ID == obj.KategoriID {
return k, nil
}
}
return nil, errors.New("kategori not found")
}
Dan pada Kategori ada field produk (many-to-one):
func (r *kategoriResolver) Produk(ctx context.Context, obj *model.Kategori) ([]*model.Produk, error) {
var result []*model.Produk
for _, p := range produkData {
if p.KategoriID == obj.ID {
result = append(result, p)
}
}
return result, nil
}
6. Simulasi Query
Query Produk beserta Kategori
query {
produkList {
id
nama
harga
kategori {
id
nama
}
}
}
Response:
{
"data": {
"produkList": [
{
"id": "1",
"nama": "Laptop",
"harga": 10000000,
"kategori": {
"id": "1",
"nama": "Elektronik"
}
},
...
]
}
}
Query Kategori dan Daftar Produk-nya
query {
kategoriList {
id
nama
produk {
id
nama
harga
}
}
}
Response:
{
"data": {
"kategoriList": [
{
"id": "1",
"nama": "Elektronik",
"produk": [
{ "id": "1", "nama": "Laptop", "harga": 10000000 },
{ "id": "2", "nama": "HP", "harga": 4000000 }
]
},
// dst
]
}
}
7. Diagram Alur Query Produk dan Kategori
Penting untuk memahami flow resolver dan resolusi antar entitas. Berikut diagram mermaid sederhana.
graph TD
A[Client] -- produkList query --> B[Query Resolver]
B -- return array produk --> C[Produk Resolver]
C -- resolve kategori field --> D[Kategori Resolver]
D -- fetch Kategori dari produk.KategoriID --> E[KategoriData]
8. Tabel Relasional Produk-Kategori
| Produk | Kategori |
|---|---|
| Laptop | Elektronik |
| HP | Elektronik |
| Celana Jeans | Fashion |
9. Tips Production
- Untuk data riil, ganti storage jadi database (PostgreSQL, MySQL, dsb), lalu abstract logic query di resolver.
- Gunakan pattern DataLoader agar field resolver tidak N+1 (lihat gqlgen dataloader).
- Error handling dan validasi input pada mutation/query wajib ditingkatkan.
- Pisahkan layer service & repository untuk scalability.
10. Kesimpulan
Kasus API produk-kategori ini adalah template yang sangat sering ditemukan di aplikasi nyata. Dengan gqlgen, kita bisa dengan mudah menyusun schema, resolvers, dan implementasi relasi data di GraphQL. Studi kasus singkat ini telah memperlihatkan struktur kode rapi, mock data sederhana, hingga simulasi query dan visualisasi data flow, yang bisa dengan mudah diadaptasi ke project yang lebih besar.
Semoga penjelasan ini membuka insight baru tentang pengaplikasian GraphQL di Golang untuk kebutuhan relasional data yang fleksibel dan skalabel.
Referensi
Bonus — Temukan repo kode contoh di sini (*if repo available)