tutorial

18 Membaca Metadata di Server gRPC

gRPC telah menjadi salah satu framework komunikasi antar layanan paling populer di era cloud-native. Berkat performanya yang tinggi dan dukungannya terhadap berbagai bahasa pemrograman, gRPC sering diadopsi di berbagai proyek skala besar. Salah satu fitur gRPC yang powerful namun sering dianggap sepele adalah metadata. Metadata adalah pasangan key-value yang bisa dikirim bersama setiap permintaan (request) atau respons (response) dalam RPC, mirip dengan HTTP headers, namun lebih terintegrasi di level protokol gRPC.

Pada artikel kali ini, kita akan mengupas tuntas bagaimana membaca metadata pada sisi server gRPC dengan menggunakan contoh implementasi pada bahasa Go (Golang). Kita juga akan melihat contoh dan simulasi praktek, tabel, serta diagram alur untuk memudahkan pemahaman.


Mengenal Metadata di gRPC

Sebelum masuk ke implementasi, mari pahami dulu konsep metadata pada gRPC. Metadata memungkinkan kita untuk menyampaikan informasi tambahan seperti authentication token, request id, custom context, dan sebagainya yang sifatnya tidak rigid terikat pada protokol data utama (protobuf message).

Pada HTTP/2 (yang menjadi transport utama di gRPC), metadata biasanya diterjemahkan menjadi header. Namun, di gRPC, client dan server memiliki API khusus untuk berinteraksi dengan metadata.

Secara umum, metadata terdiri dari key-value pair sebagai berikut:

KeyValueKeterangan
authorizationBearer xxxxxToken otorisasi
client-id12345ID unik client
custom-datasome-informationData custom sesuai kebutuhan


Diagram Alur Membaca Metadata di Server gRPC

Pengolahan metadata pada sisi server gRPC dapat digambarkan seperti berikut:

flowchart TD
    A[Client] -- Kirim RPC + Metadata --> B[gRPC Server]
    B -- Interceptor/Handler Baca Metadata --> C[Business Logic]
    C -- Response + Metadata Opsional --> A

Pada alur di atas, ketika client mengirim request, metadata ikut terkirim. Server bisa membaca metadata tersebut baik di handler biasa maupun lewat interceptor untuk kebutuhan cross-cutting seperti otentikasi atau logging.


Struktur Metadata di Go

Di Go, package utama untuk berinteraksi dengan metadata adalah google.golang.org/grpc/metadata.

Berikut fungsi-fungsi pentingnya:

  • md, ok := metadata.FromIncomingContext(ctx)
    Mendapatkan metadata yang dikirim client dari context.
  • metadata.Pairs(“key”, “value”)
    Membuat metadata baru untuk outbound.

Membaca Metadata di Server Handler

Mari kita buat sebuah service sederhana yang dapat membaca metadata yang dikirimkan oleh client.

Definisi Service (Protobuf)

syntax = "proto3";

package hello;

service Greeter {
   rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
    string name = 1;
}

message HelloResponse {
    string message = 1;
}

Implementasi Server di Go

Inti dari membaca metadata bisa dilakukan di dalam masing-masing RPC handler.

import (
    "context"
    "fmt"
    "google.golang.org/grpc"
    "google.golang.org/grpc/metadata"
    pb "path/to/your/proto"
)

type server struct {
    pb.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
    // Membaca metadata dari context
    md, ok := metadata.FromIncomingContext(ctx)
    if !ok {
        fmt.Println("Tidak ada metadata yang dikirim")
    } else {
        // Menampilkan seluruh metadata yang diterima
        for k, v := range md {
            fmt.Printf("Metadata %s: %v\n", k, v)
        }
    }

    // Ambil nilai tertentu
    clientIds := md.Get("client-id")
    if len(clientIds) > 0 {
        fmt.Println("Client ID:", clientIds[0])
    }

    return &pb.HelloResponse{
        Message: fmt.Sprintf("Hello, %s!", req.Name),
    }, nil
}

Pada contoh di atas, handler SayHello membaca semua metadata yang dikirimkan oleh client beserta value-nya.


Simulasi: Menjalankan Server dan Mengirim Metadata

Mari simulasikan client yang mengirimkan metadata.

Contoh Client

import (
    "context"
    "log"
    "google.golang.org/grpc"
    "google.golang.org/grpc/metadata"
    pb "path/to/your/proto"
    "time"
)

func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
    if err != nil {
        log.Fatalf("gagal terkoneksi: %v", err)
    }
    defer conn.Close()

    c := pb.NewGreeterClient(conn)
    md := metadata.New(map[string]string{
        "client-id":   "abc-123",
        "custom-data": "example-info",
    })
    ctx := metadata.NewOutgoingContext(context.Background(), md)

    resp, err := c.SayHello(ctx, &pb.HelloRequest{Name: "Budi"})
    if err != nil {
        log.Fatalf("Error saat request: %v", err)
    }
    log.Printf("Server reply: %s", resp.Message)
}

Output pada Server

Metadata client-id: [abc-123]
Metadata custom-data: [example-info]
Client ID: abc-123

Server berhasil menangkap metadata yang dikirim oleh client.


Penggunaan Interceptor untuk Metadata

Dalam skala besar, membaca metadata biasanya dilakukan pada interceptor—middleware yang dapat menjalankan logic di luar business core, seperti otentikasi atau audit logging.

Contoh Unary Interceptor di Go

func metadataInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    md, ok := metadata.FromIncomingContext(ctx)
    if ok {
        if tokens := md.Get("authorization"); len(tokens) > 0 {
            fmt.Println("Auth token:", tokens[0])
        }
    }
    // Melanjutkan ke handler utama
    return handler(ctx, req)
}

// Saat setup server
grpc.NewServer(
    grpc.UnaryInterceptor(metadataInterceptor),
)

Kapan menggunakan interceptor:

  • Validasi token sesi di seluruh method gRPC
  • Audit logging metadata
  • Monitoring dan tracing

Tabel: Perbandingan Cara Membaca Metadata

CaraKeunggulanKekuranganUse Case
Di HandlerJadi satu dengan business logicRedundant jika multi-methodUse-case spesifik per-RPC
Di InterceptorDRY, sekali implementasi globalTidak per-RPC customOtentikasi, logging semua RPC
KombinasiFleksibel, bisa pilih kebutuhanMungkin perlu koordinasiCrosscut + per-RPC kustom data parsing

Best Practices

  1. Prefix metadata custom dengan identifier unik untuk menghindari bentrok (misal: x-myapp-userid).
  2. Hindari metadata untuk payload besar—gunakan untuk data kecil seperti token, trace-id, dsb.
  3. Case insensitive – Key metadata tidak case sensitive, tapi konvensi lower-case lebih baik.
  4. Gunakan Interceptor untuk Crosscutting, handler untuk kebutuhan per-method.

Kesimpulan

Membaca metadata di server gRPC bukan hanya sekadar membaca key-value dari context, tapi merupakan pondasi pengembangan layanan yang aman, maintainable, dan scalable. Dengan memahami cara kerja dan praktik terbaik penggunaan metadata, kita bisa membangun aplikasi yang lebih modular, mudah diektensi, sekaligus aman.

Jangan ragu untuk mengeksplorasi fitur metadata lebih dalam, misal untuk implementasi rate limiting, distributed tracing, atau sistem monitoring terintegrasi di ekosistem microservices Anda!


Referensi


Selamat bereksperimen dengan metadata gRPC, demi keamanan & observabilitas sistem yang lebih baik!

comments powered by Disqus

Topik Terhangat

programming
173
tips-and-trick
43
tutorial
39
jaringan
28
hardware
11
linux
4
kubernetes
1