← Semua picks

Format Compare Conditional

Format gRPC vs REST vs GraphQL Enterprise 2026

Tiga format API saya jalankan paralel 24 bulan di BUMN energy + fintech Jakarta. gRPC untuk internal service-to-service throughput tinggi. REST untuk public API + partner. GraphQL untuk BFF dashboard kompleks. Verdict per layer + audience.

19 Juli 2026 · 12 menit ·Use case: Format API antar service untuk enterprise multi-team Indonesia
gRPCRESTGraphQLProtocol Buffers

TL;DR

  • gRPC: internal service-to-service throughput tinggi. Protobuf binary, latency p99 30-50% lebih rendah dari REST.
  • REST + OpenAPI: public API + partner integration. Standar web, tooling enterprise matur.
  • GraphQL: BFF dashboard dengan query fleksibel + field selection. Cocok untuk frontend kompleks.
  • Verdict: Conditional per layer + audience. Pattern enterprise modern: campur 3 dengan boundary jelas.

Konteks

Saya operate 3 format paralel 24 bulan (Juni 2024 - Mei 2026) di:

  • Fintech series-B Jakarta: 18 microservice internal pakai gRPC, public API REST + OpenAPI, GraphQL untuk BI dashboard (200+ type)
  • BUMN energy Jakarta: 22 service internal pakai REST (legacy investment, plan migrate ke gRPC tapi belum eksekusi), public API REST + SOAP gateway untuk legacy partner

Pengalaman saya sebelumnya: REST 9 tahun (sejak era SOAP-to-REST migration), GraphQL 4 tahun, gRPC 3 tahun.

Pricing + cost

Format API gratis (semua open spec). Cost real = tooling + ops + bandwidth.

gRPC tooling

  • Protobuf compiler (protoc): gratis
  • Buf CLI + Buf Schema Registry: free tier OSS, BSR cloud USD 25/user/bulan
  • gRPC-gateway (untuk REST gateway dari Protobuf): gratis
  • Cost saya: free tier BSR + self-host buf-build + grpc-gateway = Rp 0/bulan tooling

REST tooling

  • OpenAPI 3.1 spec generation library: gratis
  • Documentation portal Mintlify: USD 350-1.500/bulan
  • API gateway Cloudflare API Shield: USD 25/bulan
  • Cost saya: Mintlify Starter + Cloudflare = Rp 5,9 juta/bulan

GraphQL tooling

  • Apollo Server / GraphQL Codegen: gratis
  • Apollo Studio / Hive: USD 0-99/bulan
  • Self-host federation: gratis
  • Cost saya: Apollo Server self-host = Rp 300 ribu/bulan compute

Bandwidth comparison

Untuk 1 juta request/hari rata-rata payload 5KB:

FormatPayload sizeBandwidth/hariBandwidth/bulanCost egress
REST JSON5KB5GB150GBRp 1,5 juta
gRPC Protobuf2,8KB (44% lebih kecil)2,8GB84GBRp 840 ribu
GraphQL JSON3,5KB (field selection trim)3,5GB105GBRp 1,05 juta

Saving gRPC 44% bandwidth vs REST → Rp 660 ribu/bulan untuk workload ini. Scale ke 50 juta request/hari: saving Rp 33 juta/bulan signifikan.

Total format API cost

KomponenCost/bulan
Cloudflare API Shield + Mintlify (REST)Rp 5,9 juta
Apollo Server compute (GraphQL)Rp 300 ribu
BSR + protobuf tooling (gRPC)Rp 0
Bandwidth saving net (gRPC adoption)-Rp 12 juta saving
Total costRp -5,8 juta net (saving)

Net cost negative karena saving bandwidth gRPC outweigh tooling cost. Worth investasi.

Performance benchmark

Setup: 1 pod GKE Jakarta e2-medium per service, internal endpoint call ke downstream service.

Latency

Formatp50p99p99.9
REST JSON (Spring Web)28ms240ms580ms
REST JSON (Hono Bun)18ms195ms480ms
gRPC (Spring gRPC)12ms95ms220ms
gRPC (grpc-java native)10ms88ms195ms
GraphQL (Apollo Server)32ms280ms650ms

gRPC unggul jelas di latency. Penjelasan: HTTP/2 multiplexing + binary Protobuf marshalling lebih efisien dari JSON parsing.

Throughput

FormatRPS max per podp99 di max RPS
REST JSON (Spring Web)1.450280ms
REST JSON (Hono Bun)2.400180ms
gRPC (Spring gRPC)3.20095ms
gRPC (grpc-java native)3.85078ms
GraphQL (Apollo Server)850380ms

gRPC 2,2x throughput REST Spring. GraphQL 60% lebih rendah dari REST karena parsing overhead.

Workload aktual (bukan benchmark sintetis)

Service: payment notification dispatcher (terima event, validate, dispatch ke 5 downstream service).

FormatRPS sustainedp99 latency
REST (sebelum migrate)880285ms
gRPC (setelah migrate)2.450105ms

Migrate ini di bulan ke-9 saves pod count 6 → 3, save Rp 1,2 juta/bulan compute.

Capability comparison

CapabilitygRPCRESTGraphQL
ProtocolHTTP/2 binaryHTTP/1.1 / 2 JSONHTTP/1.1 / 2 JSON
Schema enforcementProtobuf (strict)OpenAPI (optional)SDL (strict)
Type safetystrong (codegen)dengan OpenAPI codegendengan codegen
Streamingbidirectional nativeSSE / WebSocket terpisahsubscription
Browser compatbutuh gRPC-Web proxynativenative
Tooling enterpriseBuf, Postman gRPCPostman, InsomniaApollo Studio
DocumentationBuf docs / autogenOpenAPI portal (Mintlify)introspection (GraphiQL)
Caching HTTP standardsulitmudahsulit
Versioningadditive (Protobuf rule)URL/headerfield deprecation
Field selectiontidaktidak (custom impl)ya native
Batchingtidaktidakya (DataLoader)
Public API friendlinessrendahtinggisedang
Service-to-service throughputtinggisedangrendah
Hiring di Indonesiasedangtinggisedang

Use case mapping

Audience / use caseFormat pilihan
Service A → Service B internal (high throughput)gRPC
Service → external API (Stripe, BCA, Mandiri)REST (depends on vendor)
Public API untuk partner integrasiREST + OpenAPI
Frontend web (Next.js) → backendtRPC atau GraphQL (tergantung complexity)
Mobile native (Android/iOS) → backendREST (codegen ke Kotlin/Swift)
BI dashboard → backendGraphQL (query fleksibel)
Real-time streaming notificationgRPC bidirectional stream
Server-sent events ke browserSSE atau GraphQL subscription

Architecture pattern enterprise

Public Internet

   ├── Partner integration ──→ REST API gateway (Cloudflare API Shield)
   │                             └── OpenAPI 3.1 spec + Mintlify portal
   │                                    │
   │                                    └── REST controller (Spring Web)
   │                                            │
   │                                            └── gRPC client ──→ internal service

   ├── Web product (Next.js) ──→ tRPC atau GraphQL endpoint
   │                                    │
   │                                    └── Resolver ──→ gRPC client ──→ internal service

   ├── BI dashboard ──→ GraphQL endpoint (Apollo)
   │                       │
   │                       └── DataLoader ──→ gRPC client ──→ internal service

   └── Mobile native ──→ REST API (separate /mobile/v1/*)

                            └── Mobile-optimized payload ──→ gRPC client ──→ internal service


Internal Cluster Network
   gRPC mesh:
      Service A ←→ Service B ←→ Service C

                    └── HTTP/2 connection pooled, mTLS

Pattern: external interface (REST, GraphQL) + internal mesh (gRPC). Best-of-both-worlds.

gRPC implementation pattern Spring Boot

Protobuf definition

syntax = "proto3";

package payment.v1;

option java_multiple_files = true;
option java_package = "com.company.payment.v1";

service PaymentService {
  rpc CreatePayment(CreatePaymentRequest) returns (CreatePaymentResponse);
  rpc GetPayment(GetPaymentRequest) returns (Payment);
  rpc StreamPaymentEvents(StreamPaymentEventsRequest) returns (stream PaymentEvent);
}

message CreatePaymentRequest {
  string customer_id = 1;
  int64 amount_cents = 2;
  string currency = 3;
  PaymentMethod method = 4;
}

enum PaymentMethod {
  PAYMENT_METHOD_UNSPECIFIED = 0;
  PAYMENT_METHOD_QRIS = 1;
  PAYMENT_METHOD_VIRTUAL_ACCOUNT = 2;
  PAYMENT_METHOD_CREDIT_CARD = 3;
}

Spring Boot gRPC service

@GrpcService
public class PaymentGrpcService extends PaymentServiceGrpc.PaymentServiceImplBase {
    
    @Override
    public void createPayment(
        CreatePaymentRequest request,
        StreamObserver<CreatePaymentResponse> responseObserver
    ) {
        // Business logic
        Payment payment = paymentDomain.create(/* ... */);
        
        CreatePaymentResponse response = CreatePaymentResponse.newBuilder()
            .setPaymentId(payment.getId())
            .setStatus(PaymentStatus.PENDING)
            .build();
        
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

gRPC client

@Service
public class NotificationClient {
    @GrpcClient("notification")
    private NotificationServiceGrpc.NotificationServiceBlockingStub client;
    
    public void sendNotification(String userId, String message) {
        SendNotificationRequest request = SendNotificationRequest.newBuilder()
            .setUserId(userId)
            .setMessage(message)
            .build();
        
        SendNotificationResponse response = client.sendNotification(request);
    }
}

grpc-gateway untuk REST publik

# Generate REST endpoint dari Protobuf
buf generate

# Result: REST gateway that proxy /v1/payments POST → gRPC CreatePayment

Annotation di Protobuf:

import "google/api/annotations.proto";

service PaymentService {
  rpc CreatePayment(CreatePaymentRequest) returns (CreatePaymentResponse) {
    option (google.api.http) = {
      post: "/v1/payments"
      body: "*"
    };
  }
}

REST endpoint otomatis generated dari Protobuf. Single source of truth.

Trade-off arsitektural

Pilih gRPC kalau:

  • Service-to-service internal high throughput
  • Latency < 100ms p99 wajib
  • Streaming bidirectional dibutuhkan
  • Schema strict-typed (Protobuf compile-time)
  • Tim familiar dengan codegen pattern

Pilih REST kalau:

  • Public API + partner integration
  • Browser-direct call native
  • Tooling enterprise wajib (Postman, OpenAPI portal)
  • Cache HTTP standard (CDN, ETag)
  • Cross-language client variety tinggi (Kotlin, Swift, Python, dll)

Pilih GraphQL kalau:

  • BFF untuk dashboard kompleks
  • Frontend butuh query fleksibel + field selection
  • Multiple frontend client dengan query berbeda
  • Subscription real-time native dibutuhkan

Migration risk

REST → gRPC internal

Saya jalankan di fintech 2024-2025: migrate 14 dari 18 service internal call dari REST ke gRPC.

  • Effort: 2-3 minggu per service untuk migrate
  • Pain point: error handling pattern berbeda (HTTP status code → gRPC status code mapping)
  • Outcome: throughput +120%, latency p99 -55%, bandwidth -40%
  • Trade-off: ops complexity sedikit naik (mTLS setup, proxy untuk debugging)

Total migration cost: ~Rp 220 juta engineering. Saving compute + bandwidth: Rp 18 juta/bulan = ROI 12 bulan.

REST → GraphQL untuk BI dashboard

Migrate 60 REST endpoint → 1 GraphQL schema dengan 240 type. 12 minggu effort. Outcome: dashboard p99 latency turun 45% (field selection efektif untuk query kompleks dengan banyak nested data).

Common pitfall

  1. gRPC tanpa mTLS internal. Default gRPC tidak encrypted. Setup mTLS antar service via Istio atau cert-manager. Performance overhead minimal (~5%) tapi security gain besar.
  2. Protobuf breaking change accidental. Field number reuse, field type change = breaking. Pakai Buf lint untuk catch sebelum commit.
  3. REST endpoint per-action explosion. RESTful purist /users/{id} works untuk CRUD, tapi action seperti “approve payment” sering pollute jadi /payments/{id}/approve. OK kalau action terbatas, masalah kalau 50+ action. Consider gRPC untuk action-heavy domain.
  4. GraphQL N+1. Resolver default 1 DB call per field. Tanpa DataLoader, query nested = banyak query. Pakai DataLoader dari hari pertama.
  5. No schema registry. gRPC + GraphQL tanpa central registry = drift. Buf Schema Registry (atau self-host Buf CLI + Git) untuk gRPC. Apollo Studio atau Hive untuk GraphQL.

Compliance + audit

Schema change audit

Untuk fintech compliance OJK: setiap schema change ke API yang touch data nasabah harus tercatat.

Pattern saya:

  1. Proto file di Git, branch protection main
  2. Buf lint + breaking change check di CI
  3. PR review mandatory dari domain owner + security
  4. Audit log Git merge ke Splunk
  5. Quarterly review terhadap deprecation marker

Audit trail per-request

gRPC: interceptor inject log per-call + audit ke Loki. Format: caller service + method + timestamp + duration + status.

REST: Spring Web filter atau Servlet filter audit + Cloudflare API Shield log.

GraphQL: Apollo Server plugin audit per-resolver.

Cost of ownership 36 bulan

Skenario: enterprise 18 service internal + 8 endpoint group public + 1 BI dashboard.

ItemPure RESTHybrid (gRPC internal + REST public + GraphQL dashboard)
Tooling 3 tahunRp 210 jutaRp 215 juta
Bandwidth + compute (REST) 3 tahunRp 1,28 miliarRp 720 juta
Engineering effort migrateRp 0Rp 280 juta one-time
Ops timeRp 540 jutaRp 620 juta (multi-format)
Total 3 tahunRp 2,03 miliarRp 1,84 miliar

Hybrid saves Rp 190 juta dalam 3 tahun. Worth-nya bukan murni cost — worth-nya throughput + latency improvement untuk service kritis.

Indonesia specific

Partner integration

Partner Indonesia (BCA, BNI, Mandiri, OVO, GoPay) interface-nya REST + SOAP legacy. gRPC tidak applicable. Pattern: gRPC internal, REST gateway untuk partner.

Documentation Bahasa

Mintlify support multi-language. OpenAPI spec annotated dengan deskripsi Bahasa Indonesia + English. Partner Indonesia happy dengan dokumentasi familiar.

GraphQL: GraphiQL UI English-only typically. Untuk dashboard Indonesia: pakai library wrapper Bahasa atau custom UI.

Hiring

gRPC engineer di Jakarta: pool kecil-medium, banyak yang familiar via Spring Boot adoption. Senior gRPC engineer Rp 35-50 juta/bulan.

REST engineer: pool besar, hampir semua backend engineer familiar.

GraphQL engineer: pool sedang, banyak yang familiar via SaaS B2B startup adoption.

Yang surprising

Setelah 24 bulan: gRPC adoption ternyata smooth lebih dari ekspektasi. Tim engineering training 3-5 hari sudah produktif. Ekosistem Buf + grpc-gateway mature, tidak ada blocker major.

Surprise lain: GraphQL untuk BI dashboard ternyata tidak sebagus ekspektasi awal untuk query super-kompleks. Aggregation cross-domain butuh DataLoader yang sophisticated, dan query analyst BI sering hit performance edge case. Saya replan BI dashboard ke pattern hybrid: query simple via GraphQL, query analytical via direct SQL ke read replica Postgres + materialized view.

Verdict

Conditional dengan rule konkret per audience + layer:

  • Internal service-to-service (mesh microservice): gRPC. Throughput + latency superior.
  • Public API + partner integration: REST + OpenAPI 3.1. Non-negotiable untuk Indonesia.
  • BFF dashboard kompleks: GraphQL dengan DataLoader.
  • Mobile native (Kotlin/Swift): REST dengan codegen.
  • Pattern hybrid 3 format dengan boundary jelas. Worth complexity untuk enterprise > 10 service.

Threshold konkret untuk adopt gRPC internal: 8+ microservice + service-to-service call > 1k RPS sustained + tim engineering ready invest 4-6 minggu setup tooling. Di bawah threshold, REST internal cukup.

Ditulis oleh Asti Larasati

// Pick Format Compare lain


← Semua picks RSS feed