67 Menghubungkan Beberapa Service GraphQL di Go
Ketika skala sistem microservices mulai meningkat, biasanya muncul kebutuhan untuk mengintegrasikan beberapa service agar mampu memberikan pengalaman API yang konsisten. Salah satu pendekatan yang sedang naik daun adalah federasi GraphQL, di mana beberapa service dengan GraphQL API masing-masing digabungkan ke dalam satu gateway terpadu. Pada artikel kali ini, saya akan membahas cara menghubungkan beberapa service GraphQL di Go, lengkap dengan contoh kode, simulasi request, dan diagram alur untuk membangun federasi sederhana.
Mengapa Federasi GraphQL?
Sebelum masuk ke implementasi, mari pahami dulu why-nya. Berikut beberapa alasan popularitas federasi GraphQL:
Keuntungan | Penjelasan |
---|---|
Konsistensi API | Konsumen hanya perlu terhubung ke satu endpoint GraphQL. |
Pengembangan Terpisah | Tiap team dapat membangun dan merilis schema GraphQL secara independen. |
Scalability | Service bisa dipisah dan diskalakan secara mandiri. |
Satu Sumber Kebenaran | Gateway bisa menyatukan data dari berbagai sumber menjadi satu graph besar. |
Landscape Library GraphQL di Go
Sampai artikel ini ditulis, library GraphQL di Go yang paling populer antara lain:
graphql-go
gqlgen
— lebih feature-rich dan diadopsi luas di production.graph-gophers/graphql-go
Untuk federasi, ekosistem Go belum sematang Node.js. Namun, dengan trik dan orchestrator ringan, solusi federasi tetap bisa dibangun. Pendekatan yang kita pakai di sini adalah Gateway BFF Pattern.
Studi Kasus: Menggabungkan user-service
dan post-service
Bayangkan kita memiliki dua service:
- user-service: menyajikan data user.
- post-service: menyajikan data post, dengan referensi ke user.
Kita ingin agar di gateway satu endpoint GraphQL yang bisa mengakses data gabungan, misal: mendapatkan daftar posts beserta nama authors.
1. Struktur Arsitektur
flowchart TD subgraph Backend US(User Service) PS(Post Service) end GQ[GraphQL Gateway] --> US GQ --> PS CLIENTS((Clients)) --> GQ
1. Membuat Schema Microservice
Mari mulai dengan mendefinisikan skema di tiap service.
user-service/schema.graphqls
type User {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
users: [User!]!
}
post-service/schema.graphqls
type Post {
id: ID!
title: String!
content: String!
authorID: ID!
}
type Query {
post(id: ID!): Post
posts: [Post!]!
}
2. Membuat Layanan GraphQL di Go (gqlgen)
Contoh implementasi sederhana untuk user-service
(file hanya penting saja, ringkas demi kejelasan):
user-service/main.go
package main
import (
"log"
"net/http"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
"user-service/graph"
"user-service/graph/generated"
)
func main() {
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))
http.Handle("/", playground.Handler("GraphQL playground", "/query"))
http.Handle("/query", srv)
log.Println("connect to http://localhost:8081/ for user service playground")
log.Fatal(http.ListenAndServe(":8081", nil))
}
Isi resolver bisa dengan in-memory data sederhana, begitu juga untuk post-service.
3. Membuat GraphQL Gateway (API-Orchestrator)
Inti artikel ini: menghubungkan dua (atau lebih) GraphQL service ke dalam satu orchestrator. Pada Go, kita belum punya Apollo Federation sepenuhnya, jadi kita akan menggunakan Schema Stitching ala BFF.
Skema Gateway
Kita ingin pengguna bisa melakukan query seperti berikut:
{
posts {
id
title
author {
id
name
}
}
}
Artinya, kita perlu menambah field virtual “author” di graph Post pada gateway, yang resolvenya adalah remote call ke user-service.
Contoh Kode Gateway
Instalasi package pendukung:
go get github.com/99designs/gqlgen
go get github.com/machinebox/graphql
gateway/schema.graphqls
type User {
id: ID!
name: String!
email: String!
}
type Post {
id: ID!
title: String!
content: String!
author: User!
}
type Query {
posts: [Post!]!
post(id: ID!): Post
}
gateway/resolver.go (inti pola stitch)
package graph
import (
"context"
"github.com/machinebox/graphql"
)
type Resolver struct{}
type Post struct {
ID string
Title string
Content string
AuthorID string
}
func (r *queryResolver) Posts(ctx context.Context) ([]*Post, error) {
// call post-service
client := graphql.NewClient("http://localhost:8082/query")
req := graphql.NewRequest(`
query { posts { id title content authorID } }
`)
var resp struct {
Posts []*Post
}
if err := client.Run(ctx, req, &resp); err != nil {
return nil, err
}
return resp.Posts, nil
}
func (r *postResolver) Author(ctx context.Context, obj *Post) (*User, error) {
// call user-service
client := graphql.NewClient("http://localhost:8081/query")
req := graphql.NewRequest(`
query ($id: ID!) { user(id: $id) { id name email } }
`)
req.Var("id", obj.AuthorID)
var resp struct {
User *User
}
if err := client.Run(ctx, req, &resp); err != nil {
return nil, err
}
return resp.User, nil
}
Penjelasan :
Posts
query mengambil data ke post-service secara remote.- Di setiap
author
, resolver melakukan remote GraphQL ke user-service.
4. Simulasi Request
query {
posts {
id
title
author {
id
name
}
}
}
Diagram Alur
sequenceDiagram participant CLIENT participant GATEWAY participant POST_SERVICE participant USER_SERVICE CLIENT->>GATEWAY: Query posts { id title author { id name } } GATEWAY->>POST_SERVICE: Query posts { id title content authorID } POST_SERVICE-->>GATEWAY: Posts Data loop For each Post GATEWAY->>USER_SERVICE: Query user { id name email } (with authorID) USER_SERVICE-->>GATEWAY: User Data end GATEWAY-->>CLIENT: Daftar posts & author
5. Implikasi dan Keterbatasan
Aspek | Penjelasan |
---|---|
Performa | Untuk setiap post, ada call ke user-service. Batasi N+1, idealnya pakai batching (DataLoader). |
Error Handling | Error pada salah satu service harus di-handle dengan baik di orchestrator. |
Schema Management | Perubahan schema di masing-masing service harus selalu di-sync gateway. |
Auth & Resilience | Gateway menjadi central point untuk security dan throttle. |
6. Towards Production
Langkah di atas adalah minimal viable architecture. Untuk production:
- Gunakan DataLoader untuk menghindari N+1 remote call.
- Perhatikan timeout dan circuit breaker.
- Implement cache untuk kebutuhan spesifik.
- Amati latency agregat.
- Untuk federasi penuh (apollo federation style), pantau gqlgen feature request 980.
Kesimpulan
Dengan sedikit schema stitching, kita bisa menghubungkan beberapa service GraphQL di Go tanpa framework federasi berat. Pola orchestrator BFF ini sangat cocok untuk team kecil hingga mid-size yang ingin kenyamanan dan konsistensi API global.
Jika kebutuhan semakin kompleks (subgraph ratusan, skema sangat dinamis), lebih baik memantau perkembangan federasi GraphQL native di Go atau, jika memungkinkan, mix dengan Node.js untuk gateway federasi.
Selamat mencoba dan semoga kode Anda lebih terorkestrasi! 🚀
Referensi
89. Performance Benchmarking dengan `ghz`
Artikel Terhangat
89. Performance Benchmarking dengan `ghz`
09 Sep 2025
66 Pengenalan Federated GraphQL Architecture
09 Sep 2025
65 Skema Dinamis dan Custom Scalar Types
09 Sep 2025
87. Studi Kasus: Debugging Masalah Streaming
09 Sep 2025
64 Aliases dan Directives di Query
09 Sep 2025

89. Performance Benchmarking dengan `ghz`

66 Pengenalan Federated GraphQL Architecture

65 Skema Dinamis dan Custom Scalar Types

87. Studi Kasus: Debugging Masalah Streaming
