← semua materi
05:00 Arsitektur Β· 27 Oct 2026 Β· 05:13

πŸ“š Topik

REST vs GraphQL vs gRPC: memilih berdasarkan beban nyata, bukan hype


🎯 Tujuan Belajar

Setelah sesi ini, keputusan berikut menjadi lebih baik:


🧠 Penjelasan Inti

REST

REST memakai resource dan HTTP semantics:

GET    /orders/123
POST   /orders
PATCH  /orders/123
DELETE /orders/123

Kekuatan utama:

Kelemahan:

GraphQL

GraphQL memberi client kemampuan menentukan shape response:

query {
  order(id: "123") {
    id
    status
    customer {
      name
    }
    items {
      productName
      quantity
    }
  }
}

Kekuatan utama:

Kelemahan:

gRPC

gRPC memakai RPC method dan Protocol Buffers:

service OrderService {
  rpc GetOrder(GetOrderRequest) returns (Order);
  rpc CreateOrder(CreateOrderRequest) returns (Order);
}

Kekuatan utama:

Kelemahan:


πŸ“Š Perbandingan

Aspek REST GraphQL gRPC
Model Resource Query graph Remote procedure
Payload umum JSON JSON Protobuf binary
Consumer utama Public API, browser, partner Frontend kompleks Internal services
Contract OpenAPI/documentation Schema .proto
Code generation Opsional Opsional Umumnya dipakai
Caching HTTP Mudah Sulit, perlu strategi tambahan Bukan kekuatan utama
Streaming Terbatas; SSE/WebSocket terpisah Subscription Native
Debugging manual Mudah Sedang Lebih sulit
Query flexibility Rendah–sedang Tinggi Rendah
Latency predictability Tinggi Bisa rendah bila query kompleks Tinggi untuk RPC terkontrol
Browser support Native Native Perlu adapter
Coupling Resource/schema coupling Schema dan query coupling Strong contract coupling
Operasional Paling sederhana Resolver/router kompleks Proxy, timeout, channel, schema kompleks
Cocok untuk Public boundary UI aggregation Backend-to-backend

βš™οΈ Cara Kerja Internal

REST request flow

Client
  β”‚ HTTP request
  β–Ό
Load Balancer / API Gateway
  β”‚ route berdasarkan method + path
  β–Ό
REST Handler
  β”‚ validate input
  β–Ό
Application Service
  β”‚ business rule
  β–Ό
Database / external service
  β”‚
  β–Ό
HTTP status + JSON response

HTTP semantics menjadi bagian penting kontrak:

Status code bukan dekorasi. Client memakai status tersebut untuk memutuskan retry, fallback, atau menampilkan error.

GraphQL request flow

Client query
  β”‚
  β–Ό
GraphQL parser
  β”‚ parse + validate terhadap schema
  β–Ό
Auth + query depth/complexity check
  β”‚
  β–Ό
Resolver execution plan
  β”œβ”€β”€ User service
  β”œβ”€β”€ Order service
  └── Product service
  β”‚
  β–Ό
DataLoader / batching
  β”‚
  β–Ό
Response sesuai selection set

Contoh masalah N+1:

Query orders
  β”œβ”€β”€ resolve order 1 β†’ query customer 1
  β”œβ”€β”€ resolve order 2 β†’ query customer 2
  β”œβ”€β”€ resolve order 3 β†’ query customer 3
  └── ...

Dengan batching:

resolve orders
  └── DataLoader([customer_id_1, customer_id_2, customer_id_3])
        β†’ satu query batch

DataLoader mengurangi jumlah query, tetapi tidak otomatis menyelesaikan:

gRPC request flow

Client stub
  β”‚ generated method
  β–Ό
HTTP/2 connection
  β”‚ protobuf frames
  β–Ό
gRPC server interceptor
  β”‚ auth, deadline, tracing
  β–Ό
Service method
  β”‚
  β–Ό
Database / dependency
  β”‚
  β–Ό
Status code + protobuf response + trailers

Kontrak Protobuf harus berevolusi secara kompatibel:

message Order {
  string id = 1;
  string status = 2;
}

Aturan penting:

message Order {
  reserved 3;
  string id = 1;
  string status = 2;
  string currency = 4;
}

πŸ—οΈ Decision Framework

Pilih berdasarkan pertanyaan ini:

1. Siapa consumer API?

Consumer Default awal
Browser publik REST atau GraphQL
Mobile dengan kebutuhan screen kompleks REST+BFF atau GraphQL
Internal backend gRPC atau REST
External partner heterogen REST
Data streaming gRPC streaming, SSE, atau WebSocket
Banyak bahasa dan tooling sederhana REST/JSON
Controlled polyglot environment gRPC/Protobuf

2. Apakah response shape berubah cepat?

3. Apakah latency dan throughput sangat penting?

4. Siapa memiliki aggregation logic?

REST tanpa BFF

Mobile β†’ /user
Mobile β†’ /orders
Mobile β†’ /recommendations

Banyak round trip dan client memegang orchestration.

REST dengan BFF

Mobile β†’ Mobile BFF
             β”œβ”€β”€ User service
             β”œβ”€β”€ Order service
             └── Recommendation service

GraphQL gateway

Frontend β†’ GraphQL Router
                 β”œβ”€β”€ User subgraph
                 β”œβ”€β”€ Order subgraph
                 └── Product subgraph

BFF lebih eksplisit dan biasanya lebih mudah dikontrol. GraphQL memberi flexibility lebih besar, tetapi menambah runtime query engine.


βš–οΈ Trade-off & Kapan JANGAN Dipakai

Jangan memilih REST jika

Namun, jangan menganggap GraphQL satu-satunya solusi. REST+BFF sering cukup.

Jangan memilih GraphQL jika

GraphQL bukan database query proxy. Membiarkan client mengirim query bebas ke database adalah desain buruk.

Jangan memilih gRPC jika

Jangan membuat tiga API style tanpa boundary jelas

Contoh buruk:

Frontend β†’ GraphQL
Mobile   β†’ REST
Service  β†’ gRPC
Partner  β†’ REST
Semua endpoint memiliki business logic sendiri

Risiko:

Gunakan satu application/domain core bila beberapa transport memang diperlukan:

REST Handler ─┐
GraphQL Resolver ─┼── Application Service ── Domain
gRPC Handler β”€β”€β”€β”˜

Transport adapter boleh berbeda. Business rule jangan.


πŸ” Idempotency dan Retry

Retry aman hanya jika operasi idempotent atau server memiliki mekanisme deduplikasi.

Masalah

Client β†’ POST /payments
Server β†’ payment berhasil
Network β†’ response hilang
Client β†’ retry POST /payments
Server β†’ payment kedua dibuat

Solusi idempotency key

POST /payments
Idempotency-Key: payment-attempt-7f3a

Server menyimpan:

(idempotency_key, request_hash, status, response)

Alur:

key belum ada
  β†’ proses transaksi
  β†’ simpan response berdasarkan key
  β†’ kirim response

key sama + request sama
  β†’ kembalikan response tersimpan

key sama + request berbeda
  β†’ 409 Conflict

Pseudocode:

def create_payment(req, key):
    previous = idempotency_store.get(key)

    if previous:
        if previous.request_hash != hash_request(req):
            raise Conflict("idempotency key reused with different request")
        return previous.response

    with transaction():
        reserve_key(key, hash_request(req))
        payment = charge(req)
        response = serialize(payment)
        save_result(key, response)

    return response

Hal penting:

Stripe mendokumentasikan pola idempotency key: request ulang dengan key yang sama dapat mengembalikan response sebelumnya. [1]


🏭 Contoh Produksi & Failure Mode

REST public API

Arsitektur

Client
  β”‚
API Gateway
  β”‚
REST API
  β”œβ”€β”€ Auth
  β”œβ”€β”€ Rate limit
  β”œβ”€β”€ OpenAPI contract
  └── Application services

Failure mode

Untuk dataset yang berubah cepat, cursor pagination lebih stabil:

GET /orders?limit=50&after=eyJpZCI6IjEwMCJ9

GraphQL frontend aggregation

Failure mode

Mitigasi:

gRPC internal services

Failure mode

Mitigasi:

deadline
+ bounded retry
+ jitter
+ circuit breaker
+ connection health check
+ tracing
+ load balancing

HTTP/2 menghilangkan application-level head-of-line blocking antar request, tetapi TCP tetap dapat menahan stream lain ketika packet loss terjadi. [2]


⚠️ Miskonsepsi Umum

  1. β€œGraphQL selalu lebih cepat daripada REST.”
    Salah. GraphQL mengurangi round trip atau payload berlebih, tetapi resolver chain dapat lebih lambat.

  2. β€œgRPC selalu lebih cepat karena binary.”
    Salah. Network latency, database, serialization, queueing, dan dependency biasanya lebih dominan daripada format payload.

  3. β€œREST berarti tanpa schema.”
    Salah. REST tetap membutuhkan kontrak; OpenAPI dapat menjadi source of truth.

  4. β€œGraphQL menghilangkan over-fetching.”
    Hanya pada response selection. Resolver bisa tetap mengambil kolom atau data berlebih dari database.

  5. β€œgRPC cocok untuk browser karena HTTP/2.”
    Tidak otomatis. Browser tidak memberi aplikasi kontrol penuh atas trailers dan transport yang diperlukan gRPC native. Gunakan gRPC-Web, Connect, atau gateway. [3]

  6. β€œStatus 200 dengan {error: ...} lebih sederhana.”
    Tidak. Ini merusak retry, monitoring, client behavior, dan alerting.

  7. β€œFederation sama dengan microservices.”
    Tidak. Federation mengatur composition API/schema. Itu tidak otomatis memberi autonomous deployment, isolated data ownership, atau independent scalability.

  8. β€œSatu endpoint GraphQL berarti satu backend call.”
    Tidak. Satu request dapat memicu puluhan atau ratusan resolver/dependency call.

  9. β€œPOST tidak bisa idempotent.”
    Semantics default-nya tidak idempotent, tetapi dapat dibuat idempotent dengan idempotency key dan deduplication.


πŸ” Status Pengetahuan

DIKETAHUI

DIINFERENSI

BELUM PASTI TANPA DATA SISTEM

Benchmark harus memakai traffic, payload, dependency, network topology, dan failure scenario nyata. Angka dari benchmark vendor tidak cukup.


🧭 Decision Tree

Public API atau partner eksternal?
  β”œβ”€β”€ Ya
  β”‚   β”œβ”€β”€ Resource stabil β†’ REST
  β”‚   └── Banyak client dengan kebutuhan shape berbeda β†’ GraphQL atau REST+BFF
  β”‚
  └── Internal service?
      β”œβ”€β”€ Streaming / strict typed contract / polyglot controlled β†’ gRPC
      β”œβ”€β”€ Simple CRUD / debugging mudah / tooling umum β†’ REST
      └── Belum jelas β†’ mulai REST; ukur kebutuhan sebelum menambah protocol

Default bukan keputusan final. Default adalah titik awal murah untuk validasi.


βœ… Cek Pemahaman

  1. Sebuah payment API kehilangan response setelah charge sukses. Mengapa retry biasa berbahaya, dan bagaimana idempotency key mencegah double charge?

  2. GraphQL query mengambil 100 order, masing-masing customer berbeda. Failure mode apa yang mungkin muncul, dan mekanisme apa yang menguranginya?

  3. Backend internal memiliki service Go, Java, dan Rust; browser adalah consumer utama. Apakah gRPC native menjadi pilihan tepat? Jelaskan boundary protocol yang lebih masuk akal.


πŸ”‘ Poin Kunci


➑️ Eksplorasi Lanjut

πŸ”— Sumber

[1] Stripe. β€œIdempotent requests” β€” Stripe API Documentation.
https://docs.stripe.com/api/idempotent_requests

[2] Salesforce Engineering. β€œThe Full Picture on HTTP/2 and HOL Blocking”.
https://engineering.salesforce.com/the-full-picture-on-http-2-and-hol-blocking-7f964b34d205/

[3] Connect RPC. β€œFAQs β€” Why do I need a proxy to call gRPC backends?”
https://connectrpc.com/docs/faq/

[4] Buf. β€œConnect-Web: It’s time for Protobuf and gRPC to be your first choice in the browser”.
https://buf.build/blog/connect-web-protobuf-grpc-in-the-browser