tutorial

32 Setup ORM (gorm) di graphql-go

32 Setup ORM (gorm) di graphql-go: Panduan Terpadu untuk Engineer Backend

Bagi engineer backend di ekosistem Go (Golang), membangun API yang robust seringkali memerlukan integrasi antara database, ORM, dan schema GraphQL. Dua tools populer di dunia Go, yaitu gorm sebagai ORM dan graphql-go sebagai server GraphQL, menjadi pilihan utama banyak tim. Artikel ini akan membahas setup gorm dalam proyek graphql-go secara mendalam, dilengkapi contoh kode, simulasi, diagram alur, serta tips-tips engineer yang sudah matang.


πŸ›  Persiapan: Instalasi Dependency

Sebelum menulis kode, pastikan package berikut sudah terpasang:

go get github.com/jinzhu/gorm
go get github.com/go-sql-driver/mysql
go get github.com/graph-gophers/graphql-go
go get github.com/graph-gophers/graphql-go/relay

Kita akan menggunakan MySQL pada contoh ini. Silakan ganti dengan driver lain sesuai kebutuhan (postgres, sqlite, dll).


πŸ‘©β€πŸ’» Skema & Requirement di Proyek

Kita bakal mensimulasikan skenario sederhana:

Use Case: Mengelola daftar user.

  • Setiap user punya: id, name, email.

Skema Database

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100),
  email VARCHAR(100) UNIQUE
);

Skema GraphQL

type User {
  id: ID!
  name: String!
  email: String!
}

type Query {
  users: [User!]!
  user(id: ID!): User
}
type Mutation {
  createUser(name: String!, email: String!): User
}

πŸ‘¨β€πŸ”¬ Integrasi gorm ke graphql-go, Step-by-step

Let’s break it down!

1. Model GORM untuk User

// models/user.go
package models

import "github.com/jinzhu/gorm"

type User struct {
    gorm.Model
    Name  string `gorm:"type:varchar(100)"`
    Email string `gorm:"type:varchar(100);unique"`
}

2. Setup Database & Auto Migrate

// db/db.go
package db

import (
    "github.com/jinzhu/gorm"
    _ "github.com/go-sql-driver/mysql"
    "log"
    "user-gql/models"
)

func InitDB() *gorm.DB {
    db, err := gorm.Open("mysql", "root:password@/userdb?charset=utf8&parseTime=True")
    if err != nil {
        log.Fatal(err)
    }
    db.AutoMigrate(&models.User{})
    return db
}

3. Resolver GraphQL

Resolver adalah β€˜jembatan’ antara query/mutation GraphQL dan kode Go (termasuk ORM-nya).

// resolver/resolver.go
package resolver

import (
    "context"
    "user-gql/models"
    "github.com/jinzhu/gorm"
)

type Resolver struct {
    DB *gorm.DB
}

// Untuk users query
func (r *Resolver) Users(ctx context.Context) ([]*UserResolver, error) {
    var users []models.User
    if err := r.DB.Find(&users).Error; err != nil {
        return nil, err
    }
    resolvers := make([]*UserResolver, len(users))
    for i, user := range users {
        resolvers[i] = &UserResolver{user}
    }
    return resolvers, nil
}

// Query tunggal berdasarkan ID
func (r *Resolver) User(ctx context.Context, args struct{ ID int32 }) (*UserResolver, error) {
    var user models.User
    if err := r.DB.First(&user, args.ID).Error; err != nil {
        return nil, err
    }
    return &UserResolver{user}, nil
}

// Mutation
func (r *Resolver) CreateUser(ctx context.Context, args struct{ Name string; Email string }) (*UserResolver, error) {
    user := models.User{Name: args.Name, Email: args.Email}
    if err := r.DB.Create(&user).Error; err != nil {
        return nil, err
    }
    return &UserResolver{user}, nil
}

// Resolver untuk User type
type UserResolver struct {
    models.User
}

func (u *UserResolver) ID() graphql.ID     { return graphql.ID(fmt.Sprint(u.User.ID)) }
func (u *UserResolver) Name() string       { return u.User.Name }
func (u *UserResolver) Email() string      { return u.User.Email }

4. Schema GraphQL

Buat file schema.graphql dengan isi:

type User {
  id: ID!
  name: String!
  email: String!
}

type Query {
  users: [User!]!
  user(id: ID!): User
}
type Mutation {
  createUser(name: String!, email: String!): User
}

5. Integrasi Handler HTTP

// main.go
package main

import (
    "io/ioutil"
    "net/http"
    "user-gql/db"
    "user-gql/resolver"

    "github.com/graph-gophers/graphql-go"
    "github.com/graph-gophers/graphql-go/relay"
)

func main() {
    // Setup DB
    database := db.InitDB()
    defer database.Close()

    // Load schema
    schemaBytes, err := ioutil.ReadFile("schema.graphql")
    if err != nil {
        panic(err)
    }

    // Buat schema GraphQL
    schema := graphql.MustParseSchema(
        string(schemaBytes),
        &resolver.Resolver{DB: database},
    )

    http.Handle("/query", &relay.Handler{Schema: schema})

    // Live!
    http.ListenAndServe(":8080", nil)
}

πŸƒ Simulasi Query ke Server

1. Query Seluruh User

query {
  users {
    id
    name
    email
  }
}

Respons:

{
  "data": {
    "users": [
      {"id": "1", "name": "Ridwan", "email": "ridwan@contoh.com"},
      {"id": "2", "name": "Rahma", "email": "rahma@company.com"}
    ]
  }
}

2. Mutation: Tambah User

mutation {
  createUser(name: "Bimo", email: "bimo@team.com") {
    id
    name
  }
}

πŸ“Š Tabel: Perbandingan GORM vs Raw SQL

FiturGORMRaw SQL
Query BuilderYES (ORM style)NO
Auto MigrationYESNO
RelationsYES (Preload, Joins)Manual (Join)
Struct MappingYES (Struct to Table)Handcrafted
Error HandlingTengah (ada error type)Manual/Error bawaan
ReadabilityLebih clean & idiomaticKadang verbose

πŸ”– Diagram Alur Setup

flowchart TD
    A[Inisiasi: Load Schema GraphQL] --> B[Init GORM DB]
    B --> C[Bind Resolver ke GORM DB]
    C --> D[GraphQL HTTP Handler aktif]
    D --> E[Receive HTTP Request /query]
    E --> F{Jenis Query}
    F -- Query user/users --> G[GORM query ke DB]
    F -- Mutation --> H[GORM transaksi ke DB]
    G & H --> I[Json Response via GraphQL]

⚑️ Engineering Tips

  • Connection Pool: Gunakan db.DB().SetMaxOpenConns(...) untuk optimasi performance.
  • Env Config: Simpan credential database di environment variable, bukan hardcoded.
  • Validation: Validasi input di mutation sebelum commit ke DB (jangan terlalu percaya kepada client!).
  • Migration: Jalankan migration secara terpisah di production, jangan dari main app.
  • Testing: Gunakan test DB untuk integration test, mocking GORM dengan library seperti go-sqlmock.

πŸ’¬ Penutup

Dengan setup seperti di atas, kamu dapat menghubungkan orm GORM dan graphql-go dengan clean, rapi, dan maintainable. Kuncinya: selalu treat resolver sebagai lapisan bersih yang menghubungkan dunia GraphQL dengan ORM/db-mu.

Jangan ragu untuk mengadaptasi pattern ini ke kebutuhan proyekmu, baik untuk e-commerce, SaaS, atau skala enterprise. Jika ada pertanyaan atau butuh penjelasan lebih lanjut, drop di komentar πŸ˜‰


References:

Selamat ngoding, backend warriors! πŸš€

comments powered by Disqus