88 Struktur Project graphql-go yang Scalable: Panduan Untuk Backend Engineer
Membangun API dengan GraphQL di Go menawarkan keunggulan pada skalabilitas, maintainability, dan developer experience. Namun, struktur project yang keliru dapat membuat codebase sulit di-maintain bahkan sebelum traffic naik. Maka dari situ, kita membutuhkan strategi struktur project yang solid.
Artikel ini membahas secara praktis tentang 88 struktur project GraphQL-Go yang scalable dan maintainable, berdasarkan pengalaman dan skenario proyek skala menengah hingga perusahaan. Saya juga sajikan contoh snippet, simulasi flow, hingga diagram mermaid agar konsepnya mudah dicerna.
Why Structure Matters?
Kontrak GraphQL yang dinamis dan nested memaksa kita untuk mempunyai struktur kode yang modular dan mudah dikustomasi. Di Go, kita juga harus memperhatikan prinsip separation of concern dan type safety. Kalau tidak hati-hati, Anda akan cepat terjebak pada file resolver yang gemuk, file model atau schema yang bercampur aduk, hingga dependency yang tidak jelas.
Struktur yang baik memberikan:
- Enkapsulasi & isolasi business logic
- Kemudahan testing dan pengembangan fitur baru
- Skalabilitas menambah tim/engineer
- Integrasi mudah ke sistem lain (REST, gRPC, message bus, dll)
Anatomy: Struktur Project GraphQL-Go Modern
Di bawah ini adalah struktur direktori (simbol 📁
untuk folder, 📄
untuk file):
📁 graph
📁 schema
📄 schema.graphqls
📄 directives.graphqls
📁 resolver
📄 user_resolver.go
📄 product_resolver.go
📁 generated
📄 generated.go
📄 handler.go
📄 loader.go
📁 domain
📁 user
📄 model.go
📄 repository.go
📄 service.go
📄 service_test.go
📁 product
📄 model.go
📄 repository.go
📄 service.go
📁 pkg
📄 logger.go
📄 config.go
📄 middleware.go
📄 util.go
📁 cmd
📄 main.go
📁 migration
📄 001_init.sql
📄 002_add_user.sql
....
Tabel 1: Penjelasan Folder
Folder | Penjelasan singkat |
---|---|
graph | Semua berhubungan langsung dengan GraphQL (schema, loader, handler) |
domain | Modular business logic per entitas/fungsi |
pkg | Shared library/fungsi utilitas |
cmd | Entry point aplikasi |
migration | Database migration SQL |
Struktur ini sangat scalable karena setiap flow (GraphQL, domain bisnis, utilitas, dan migrasi) terpisah dengan jelas.
Flow Eksekusi Query me
(Simulasi)
Bagan berikut membantu memahami flow permintaan GraphQL me
(get current user):
graph LR A[Client] --> B(GraphQL Handler) B --> C(Auth Middleware) C --> D(UserResolver.me) D --> E(UserService.GetUserByID) E --> F(UserRepository.FindByID) F --> |Database| G((Postgres)) G --> F F --> E E --> D D --> C C --> B B --> A
Deep Dive: Pembahasan Struktur
1. graph/schema/*.graphqls
Pisahkan definisi schema dan directive. Contoh:
# graph/schema/schema.graphqls
type User {
id: ID!
name: String!
email: String!
}
type Query {
me: User!
}
type Mutation {
register(name: String!, email: String!, password: String!): User!
}
2. graph/resolver/*.go
Resolver jangan sampai kebanyakan business logic. Fungsinya hanya mapping dan sedikit validasi.
// graph/resolver/user_resolver.go
func (r *queryResolver) Me(ctx context.Context) (*model.User, error) {
userID := GetUserIDFromContext(ctx)
user, err := r.UserService.GetUserByID(ctx, userID)
if err != nil {
return nil, err
}
return user, nil
}
3. domain/user/model.go
Definisi model entity. Tidak boleh ada dependency dengan paket GraphQL.
type User struct {
ID string
Name string
Email string
Password string
}
4. domain/user/repository.go
Abstraction ke database. Idealnya menggunakan interface agar testable.
type UserRepository interface {
FindByID(ctx context.Context, id string) (*User, error)
FindByEmail(ctx context.Context, email string) (*User, error)
Create(ctx context.Context, user *User) error
}
5. domain/user/service.go
Tempatkan business logic di sini.
type UserService struct {
repo UserRepository
}
func (s *UserService) GetUserByID(ctx context.Context, id string) (*User, error) {
return s.repo.FindByID(ctx, id)
}
6. pkg/
Tempatkan shared lib, contoh config dengan env, logger, dan middleware.
// pkg/logger.go
func NewLogger() *zap.Logger {
logger, _ := zap.NewProduction()
return logger
}
Saran Modularisasi Untuk 88+ Endpoints
Kenapa saya sebut 88 struktur? Karena setiap domain bisa mewakili 1 atau beberapa GraphQL endpoint. Praktik bagus, pisahkan resolver, service, repository, dan model per domain. Untuk API bisnis rumit (misal, e-commerce: user, product, order, payment, shipping, dst), bisa terus-menerus tambah folder di dalam domain/*
.
Contoh penambahan domain baru
📁 domain
📁 payment
📄 model.go
📄 repository.go
📄 service.go
...
Code Generation: Otomatisasi Dengan gqlgen
gqlgen sangat populer untuk generate kode GraphQL di Go dengan type safety. Letakkan konfigurasi di root (gqlgen.yml
), dan gunakan folder graph/generated
.
Perlu diingat:
Folder generated
dan file-file di dalamnya jangan diubah manual. Semua logic custom di letakkan pada resolver/service/domain.
Life-cycle Deploy Production
Diagram alur umum deployment pipeline:
graph LR A[Engineer Push Code] --> B[Run Unit Test] B --> C[Build Binary] C --> D[Run Integration Test] D --> E[Create Container Image] E --> F[Deploy ke Kubernetes/VM]
Testing: Layered Unit Test
- Test logic bisnis (di
/domain/*/service_test.go
) - Test integration resolver (pakai test client, e.g. gqlgen)
- Test middleware dan utility (di
/pkg
)
Simulasi Unit Test sederhana
func TestUserService_GetUserByID(t *testing.T) {
mockRepo := new(MockUserRepo)
mockRepo.On("FindByID", mock.Anything, "123").Return(&User{ID:"123", Name:"Budi"}, nil)
s := NewUserService(mockRepo)
user, err := s.GetUserByID(context.TODO(), "123")
require.NoError(t, err)
require.Equal(t, "Budi", user.Name)
}
Checklist Good GraphQL-Go Project Structure
Cek | Penjelasan |
---|---|
Schema terpisah | Pisah file .graphqls per domain |
Resolver thin | Resolver minim logic bisnis, hanya delegasi |
Domain modular | Setiap domain punya model, repo, service |
Pkg reusable | Lib utilities tidak tergantung domain spesifik |
Dependency inj. | Service, repo gunakan injection untuk kemudahan test/migrasi |
Automated test | Tersedia test unit dan integrasi |
Configurable | Konfigurasi (env) terpusat dan mudah diubah |
CI/CD | Support pipeline build/test/deploy |
Penutup
Struktur project yang scalable bukan hanya soal “banyak folder”, namun tentang disiplin pemisahan concern sekaligus menjaga codebase tetap practical maintainable. Dengan struktur 88 domain modular, Anda bisa mengatasi kompleksitas API GraphQL-Go dengan tim besar, sekaligus tetap bisa iterasi cepat di development.
Tips dari saya: Awali dengan struktur minimal tapi siap berkembang, dan selalu refactor jika ada pain point baru.
Sudahkah struktur project GraphQL-Go Anda seperti ini?
Rangkuman
- Modularity & separation of concern adalah fondasi skalabilitas
- Pisahkan resolver, domain logic, utilities, dan schema
- Coverage testing dan otomasi deployment mutlak wajib
- Jangan ragu untuk split domain bila jumlah resolver sudah tinggi
Yuk berdiskusi:
Bagaimana pengalaman Anda dengan struktur project GraphQL di Go?
Tulis di kolom komentar!
Artikel Terhangat
90 Strategi Pengujian dan CI/CD graphql-go
09 Sep 2025
88 Struktur Project graphql-go yang Scalable
09 Sep 2025
87 Tips Debugging Resolver dan Query GraphQL
09 Sep 2025

90 Strategi Pengujian dan CI/CD graphql-go

88 Struktur Project graphql-go yang Scalable
