Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
25 Jun 2025 · 5 mnt baca ·Artikel 17 / 110
Go

17 Menambahkan Metadata pada gRPC Request

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

gRPC telah menjadi standar de facto untuk komunikasi service-to-service di banyak perusahaan yang mengadopsi microservices. Sifatnya yang efisien membuatnya sangat cocok untuk sistem berskala besar. Namun, dalam praktik, kebutuhan akan komunikasi yang lebih “kontekstual” seringkali muncul—misal, pengiriman token otentikasi, trace id, atau custom header di setiap request. Disinilah pentingnya metadata pada gRPC: memberikan medium ekstra untuk mengirim data luar-band tanpa memodifikasi definisi protokol utama.

Pada artikel kali ini, saya akan membahas tuntas metadata pada gRPC request, mulai teori dasar, simulasi arsitektur, hingga contoh kode di Node.js dan Go. Tidak hanya contoh, saya juga akan share praktik terbaik dan kendala yang perlu diwaspadai. Yuk, kita mulai!


Apa Itu Metadata pada gRPC?

Serupa HTTP header, metadata pada gRPC adalah pasangan key-value yang dikirim sebagai bagian dari setiap permintaan atau respons RPC. Mereka digunakan untuk informasi tambahan seperti:

  • Token otentikasi
  • Trace/Correlation ID untuk observabilitas
  • Opsi konten
  • Info tenant (multi tenant apps)
  • Dan informasi eksternal lain yang tidak ingin ‘mencemari’ payload utama

Diagram Alur Metadata pada gRPC

Mari kita visualisasikan alurnya lewat diagram mermaid berikut:

MERMAID
sequenceDiagram
    participant Client
    participant Network
    participant Server

    Client->>Network: gRPC Request (Metadata + Payload)
    Network->>Server: gRPC Request (Metadata + Payload)
    Server-->>Network: gRPC Response (Metadata + Payload)
    Network-->>Client: gRPC Response (Metadata + Payload)

Seperti terlihat, baik request maupun response dapat membawa metadata.


Use Case Nyata: Skenario “User Authentication”

Salah satu skenario paling umum adalah passing token JWT (JSON Web Token) pada setiap request sebagai bukti otentikasi. Di gRPC, ini tidak dilakukan lewat parameter di protokol, tapi dengan header/metadata.


Contoh Skema Protobuf

Misal kita punya service berikut:

proto
 1// protos/user.proto
 2syntax = "proto3";
 3
 4service UserService {
 5    rpc GetProfile(Empty) returns (UserProfile);
 6}
 7
 8message Empty {}
 9
10message UserProfile {
11    string user_id = 1;
12    string name = 2;
13    string email = 3;
14}

Tidak ada kolom token auth, karena akan dikirim lewat metadata.


Implementasi gRPC Metadata

Mari lihat implementasi di dua bahasa populer:

1. Node.js (menggunakan @grpc/grpc-js)

a) Client: Mengirim Request Bersama Metadata

js
 1const grpc = require('@grpc/grpc-js');
 2const protoLoader = require('@grpc/proto-loader');
 3
 4// Load proto
 5const packageDefinition = protoLoader.loadSync('./protos/user.proto');
 6const userProto = grpc.loadPackageDefinition(packageDefinition).UserService;
 7
 8// Buat client
 9const client = new userProto('localhost:50051', grpc.credentials.createInsecure());
10
11// Buat metadata
12const metadata = new grpc.Metadata();
13metadata.add('authorization', 'Bearer eyJhbGciOiJI...');  // JWT misalnya
14
15// Call RPC dengan metadata
16client.GetProfile({}, metadata, (err, response) => {
17  if (err) console.error(err);
18  else console.log(response);
19});

b) Server: Membaca Metadata Request

js
 1const grpc = require('@grpc/grpc-js');
 2
 3function getProfile(call, callback) {
 4  // Ambil nilai 'authorization'
 5  const authToken = call.metadata.get('authorization')[0];
 6  console.log('Received JWT:', authToken);
 7
 8  // TODO: Verifikasi token
 9  // Simulasikan user profile
10  if (authToken) {
11    callback(null, {
12      user_id: 'u-123',
13      name: 'Rizky',
14      email: 'rizky@example.com'
15    });
16  } else {
17    callback({
18      code: grpc.status.UNAUTHENTICATED,
19      message: 'Auth token required'
20    });
21  }
22}

2. Go: Server & Client

a) Client: Mengirim Metadata

go
 1import (
 2    "context"
 3    "google.golang.org/grpc"
 4    "google.golang.org/grpc/metadata"
 5)
 6
 7func main() {
 8    conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
 9    defer conn.Close()
10    client := pb.NewUserServiceClient(conn)
11
12    // Buat metadata
13    md := metadata.New(map[string]string{"authorization": "Bearer abcd1234"})
14    ctx := metadata.NewOutgoingContext(context.Background(), md)
15
16    // RPC call dgn metadata
17    resp, err := client.GetProfile(ctx, &pb.Empty{})
18    // Handle resp / err
19}

b) Server Handler: Membaca Metadata

go
 1import (
 2    "context"
 3    "google.golang.org/grpc/metadata"
 4)
 5
 6func (s *server) GetProfile(ctx context.Context, req *pb.Empty) (*pb.UserProfile, error) {
 7    md, ok := metadata.FromIncomingContext(ctx)
 8    if !ok {
 9        return nil, status.Error(codes.Unauthenticated, "No metadata found")
10    }
11    tokens := md["authorization"]
12    if len(tokens) == 0 {
13        return nil, status.Error(codes.Unauthenticated, "No authorization token")
14    }
15    // Verifikasi token, dst
16    return &pb.UserProfile{
17        UserId: "u-456",
18        Name: "Dewi",
19        Email: "dewi@example.com",
20    }, nil
21}

Tipe Metadata: Default vs Custom

Metadata KeyContohPenjelasan
authorizationBearer eyJhbG…Token JWT/OAuth2
x-trace-id3f4a…Correlation untuk tracing
localeid-IDKustomisasi multi-bahasa
content-typeapplication/grpcBiasanya dikelola otomatis

Catatan:

  • Key standard biasanya lowercase semua.
  • Setiap “binary” value (bukan string) harus diberi suffix -bin.

Best Practice Penggunaan Metadata

1. Jangan Overload Metadata

Metadata sangat berguna, namun pastikan tetap kecil—idealnya puluhan hingga ratusan bytes. Metadata terlalu besar dapat menurunkan performa dan merusak semantik layanan.

2. Standardisasi Key

Gunakan penamaan yang konsisten dan dokumentasikan key yang digunakan seluruh tim/layanan.

3. Minimal Satu-Way

Gunakan metadata berbeda untuk request dan response sesuai standar gRPC.
Misal, otentikasi client -> server, sedangkan error detail dalam response.

4. Jangan Simpan State Penting

Metadata bersifat stateless. Jangan gunakan untuk menyimpan informasi yang seharusnya ada di database atau session.

5. Interceptor/Middleware

Implementasikan pemeriksaan, logging, atau inject metadata lewat interceptor/middleware. Modular dan scalable.


Interceptor: Inject Otomatis di Setiap Request (Node.js Example)

js
 1function authInterceptor(options, nextCall) {
 2  return new grpc.InterceptingCall(nextCall(options), {
 3    start: function(metadata, listener, next) {
 4      // Inject token setiap request
 5      metadata.add('authorization', 'Bearer juragan_secret');
 6      next(metadata, listener);
 7    }
 8  });
 9}
10
11// Gunakan di client
12const client = new userProto('localhost:50051', grpc.credentials.createInsecure(), {
13  interceptors: [authInterceptor]
14});

Troubleshooting Umum

  • Metadata tidak sampai ke server: Cek key spelling, implementasi interceptor, dan perhatikan bahwa size metadata berlebihan bisa jadi ditolak middleware/network.
  • Metadata hilang di stream (bidirectional): Beberapa implementasi perlu memperhatikan initial vs trailing metadata.
  • Kesalahan binary header: Key dengan suffix -bin wajib untuk data buffer/binary, sebaliknya akan terjadi error parsing.

Kesimpulan

Dengan pemahaman dan best practice seputar metadata, layanan gRPC Anda bisa lebih aman, traceable, dan future-proof. Komunikasi service-to-service yang membawa context kini menjadi nyata tanpa harus “merusak” protokol, hanya dengan sentuhan metadata.

Jangan lupa untuk menguji skenario edge case dan buat util/interceptor untuk konsistensi pengiriman dan eksekusi metadata. Metadata bukan cuma “header”, tapi juga kunci interoperabilitas dan observabilitas pada ekosistem distributed system modern.

Sumber Lain & Referensi:


Selamat mencoba, semoga service-mu makin robust dan scalable! 🚀

Artikel Terkait

💬 Komentar