tutorial

  1. Studi Kasus: API Gateway untuk gRPC Service

75. Studi Kasus: API Gateway untuk gRPC Service

Kebutuhan akan sistem yang scalable, maintainable, dan performa tinggi mendorong banyak perusahaan untuk mengadopsi pendekatan microservices. Salah satu teknologi komunikasi antar service yang populer adalah gRPC, terutama untuk interaksi internal yang mengutamakan efisiensi dan contract-first API. Namun, gRPC belum terlalu ramah bagi konsumsi publik atau oleh client tradisional, seperti web browser atau mobile app, yang terbiasa dengan protokol HTTP/JSON. Masalah lain yang sering dihadapi adalah mengontrol akses, otentikasi, transformasi data, monitoring, dan sebagainya di satu pintu (API Gateway). Pada studi kasus kali ini, kita akan membahas rancangan dan implementasi sederhana API Gateway untuk gRPC Service.


Problem Statement

Misalkan Anda membangun sistem core banking dengan beberapa microservices, salah satunya adalah AccountService berbasis gRPC. Client eksternal (seperti front-end web atau mobile) hanya bisa berkomunikasi via REST. Anda butuh sebuah API Gateway yang:

  • Mengkonversi permintaan REST menjadi request gRPC.
  • Menyediakan endpoint RESTful agar dapat dengan mudah diintegrasikan ke front-end/client publik.
  • Melakukan authentication/authorization di gateway.
  • Mudah di-scale dan di-monitor.

Diagram Alur Sistem

flowchart LR
    A[Client (Web/Mobile)] -- HTTP/JSON --> B(API Gateway)
    B -- gRPC --> C[gRPC AccountService]
    C -- Response gRPC --> B
    B -- HTTP/JSON --> A

Pendekatan: Skenario dan Tools

Untuk studi kasus ini, kita akan menggunakan:

  • gRPC: Sebagai backend service utama.
  • Envoy Proxy atau grpc-gateway: Sebagai API Gateway.
  • Go: Bahasa untuk implementasi karena dukungan tool yang solid untuk gRPC dan grpc-gateway.
  • JWT Auth: Untuk simulasi autentikasi.

Definisi Service: AccountService

Mari mulai dengan mendefinisikan contract (protobuf) untuk AccountService.

// account.proto
syntax = "proto3";

package account;

service AccountService {
  rpc GetAccount(GetAccountRequest) returns (GetAccountResponse) {}
}

message GetAccountRequest {
  string account_id = 1;
}

message GetAccountResponse {
  string account_id = 1;
  string name = 2;
  double balance = 3;
}

Setelah menulis file account.proto, generate stub server (dan client) menggunakan plugin protoc.


1. Implementasi gRPC Service

Buat implementasi server sederhana menggunakan Go.

// account_server.go
package main

import (
	"context"
	pb "path/to/accountpb"
)

type server struct {
	pb.UnimplementedAccountServiceServer
}

func (s *server) GetAccount(ctx context.Context, req *pb.GetAccountRequest) (*pb.GetAccountResponse, error) {
	// Simulasi database lookup
	if req.GetAccountId() == "123" {
		return &pb.GetAccountResponse{
			AccountId: "123",
			Name:      "Jane Doe",
			Balance:   2500000.0,
		}, nil
	}
	return nil, status.Error(codes.NotFound, "account not found")
}

2. Kenapa Tidak REST Langsung?

Pertanyaan umum: Kenapa tidak expose gRPC service ini langsung sebagai REST?
Jawabannya adalah: gRPC lebih efisien (binary, multiplexing), lebih mudah contract-first, dan mendukung streaming. Namun, tidak semua client bisa native gRPC. Maka, API Gateway adalah solusi jembatan yang clean.


3. API Gateway dengan grpc-gateway

gRPC-Gateway adalah proyek open-source yang meng-generate proxy “reverse-proxy” HTTP RESTful ke gRPC endpoints.

Tambahan pada Proto File

Tambahkan annotation HTTP di proto:

import "google/api/annotations.proto";

service AccountService {
  rpc GetAccount(GetAccountRequest) returns (GetAccountResponse) {
    option (google.api.http) = {
      get: "/v1/accounts/{account_id}"
    };
  }
}

Menjalankan Gateway

  • Jalankan gRPC server di port misal :9090.
  • Jalankan grpc-gateway server di port misal :8080 yang akan meneruskan request ke gRPC server.

main.go:

package main

import (
	"context"
	"log"
	"net/http"

	gw "path/to/accountpb"
	"google.golang.org/grpc"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
)

func main() {
	grpcEndpoint := "localhost:9090"
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{grpc.WithInsecure()}
	err := gw.RegisterAccountServiceHandlerFromEndpoint(ctx, mux, grpcEndpoint, opts)
	if err != nil {
		log.Fatalf("failed to start HTTP gateway: %v", err)
	}

	http.ListenAndServe(":8080", mux)
}

4. Simulasi Request

Bayangkan client mengirimkan permintaan HTTP GET /v1/accounts/123:

GET /v1/accounts/123
Authorization: Bearer <jwt_token>

API Gateway akan:

  • Men-translate request HTTP ke gRPC GetAccount.
  • Menambah atau memvalidasi authentikasi (di interceptors).
  • Mengembalikan hasil format JSON ke client.

Response example:

{
  "account_id": "123",
  "name": "Jane Doe",
  "balance": 2500000.0
}

5. Middleware: Auth & Logics di Gateway

Letakkan middleware secara sentral di API Gateway, supaya downstream service tetap simple.

// Middleware HTTP untuk validasi JWT
type AuthMiddleware struct {
	Next http.Handler
}

func (am *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	auth := r.Header.Get("Authorization")
	if !ValidateJWT(auth) {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	am.Next.ServeHTTP(w, r)
}

// Penambahan pada main.go
authHandler := &AuthMiddleware{Next: mux}
http.ListenAndServe(":8080", authHandler)

6. Penggunaan Envoy sebagai API Gateway Alternatif

Selain grpc-gateway (yang cocok untuk prototyping atau Go stack), Anda bisa menggunakan Envoy untuk production grade. Envoy dapat mengkonfigurasi HTTP->gRPC transcoding, mendaftarkan rate limit, JWT validation, dll.

# Config potongan Envoy untuk HTTP-GRPC transcoding
static_resources:
  listeners:
    - address:
        socket_address: { address: 0.0.0.0, port_value: 8080 }
      filter_chains:
        - filters:
            - name: envoy.filters.network.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                route_config:
                  #...
                http_filters:
                  - name: envoy.filters.http.grpc_json_transcoder
                    typed_config:
                      "@type": type.googleapis.com/envoy.extensions.filters.http.grpc_json_transcoder.v3.GrpcJsonTranscoder
                      proto_descriptor: "/etc/protos/account.pb"
                      services: ["account.AccountService"]
                      print_options:
                        add_whitespace: true

Tabel Perbandingan

Berikut ringkasan perbandingan API Gateway yang umum untuk gRPC service:

GatewayBahasaKeunggulanKekuranganFitur Advanced
grpc-gatewayGoSimpel, native GoTidak mendukung TLS kompleks, Hanya GoLogging, Auth (custom)
Envoy ProxyC++Performant, production provenKonfigurasi lebih rumitRate limit, JWT
KongLua/GoPlugin ekosistem luasResource lebih beratRate limit, Auth

7. Scaling dan Monitoring

Untuk kapasitas produksi:

  • Gateway bisa dibungkus di container, lalu di-scale horizontal via Kubernetes.
  • gRPC service bisa tetap di scale tersendiri.
  • Monitoring request masuk/keluar di gateway, audit log, metrik latensi dsb.

Kesimpulan

API Gateway untuk gRPC service memungkinkan kita:

  • Menggunakan gRPC secara internal untuk kinerja dan maintainability.
  • Menyediakan API REST untuk client eksternal tanpa perlu memodifikasi setiap microservice.
  • Menerapkan authentication, logging, monitoring, dan business logic di satu pintu.
  • Infrastructure-agnostic; bisa diganti Envoy atau implementasi lain sesuai kebutuhan.

Dengan pendekatan ini, developer dapat fokus pada core business logic di masing-masing service sementara security, observability, dan device compatibility tetap terjaga.


Kesimpulan

Studi kasus ini secara sederhana mencerminkan salah satu best-practice pattern pada modern backend architecture. Memanfaatkan API Gateway sebagai jembatan antara dunia RESTful dan gRPC, Anda dapat menjaga sistem tetap modular dan future-proof. Experiment dan eksplorasi dengan berbagai gateway, temukan trade off paling cocok untuk kebutuhan Anda. Semoga studi kasus ini memberi inspirasi desain arsitektur dan eksekusi proyek Anda berikutnya!

comments powered by Disqus