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:
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:
// protos/user.proto
syntax = "proto3";
service UserService {
rpc GetProfile(Empty) returns (UserProfile);
}
message Empty {}
message UserProfile {
string user_id = 1;
string name = 2;
string email = 3;
}
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
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
// Load proto
const packageDefinition = protoLoader.loadSync('./protos/user.proto');
const userProto = grpc.loadPackageDefinition(packageDefinition).UserService;
// Buat client
const client = new userProto('localhost:50051', grpc.credentials.createInsecure());
// Buat metadata
const metadata = new grpc.Metadata();
metadata.add('authorization', 'Bearer eyJhbGciOiJI...'); // JWT misalnya
// Call RPC dengan metadata
client.GetProfile({}, metadata, (err, response) => {
if (err) console.error(err);
else console.log(response);
});
b) Server: Membaca Metadata Request
const grpc = require('@grpc/grpc-js');
function getProfile(call, callback) {
// Ambil nilai 'authorization'
const authToken = call.metadata.get('authorization')[0];
console.log('Received JWT:', authToken);
// TODO: Verifikasi token
// Simulasikan user profile
if (authToken) {
callback(null, {
user_id: 'u-123',
name: 'Rizky',
email: 'rizky@example.com'
});
} else {
callback({
code: grpc.status.UNAUTHENTICATED,
message: 'Auth token required'
});
}
}
2. Go: Server & Client
a) Client: Mengirim Metadata
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func main() {
conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
defer conn.Close()
client := pb.NewUserServiceClient(conn)
// Buat metadata
md := metadata.New(map[string]string{"authorization": "Bearer abcd1234"})
ctx := metadata.NewOutgoingContext(context.Background(), md)
// RPC call dgn metadata
resp, err := client.GetProfile(ctx, &pb.Empty{})
// Handle resp / err
}
b) Server Handler: Membaca Metadata
import (
"context"
"google.golang.org/grpc/metadata"
)
func (s *server) GetProfile(ctx context.Context, req *pb.Empty) (*pb.UserProfile, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Error(codes.Unauthenticated, "No metadata found")
}
tokens := md["authorization"]
if len(tokens) == 0 {
return nil, status.Error(codes.Unauthenticated, "No authorization token")
}
// Verifikasi token, dst
return &pb.UserProfile{
UserId: "u-456",
Name: "Dewi",
Email: "dewi@example.com",
}, nil
}
Tipe Metadata: Default vs Custom
Metadata Key | Contoh | Penjelasan |
---|---|---|
authorization | Bearer eyJhbG… | Token JWT/OAuth2 |
x-trace-id | 3f4a… | Correlation untuk tracing |
locale | id-ID | Kustomisasi multi-bahasa |
content-type | application/grpc | Biasanya 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)
function authInterceptor(options, nextCall) {
return new grpc.InterceptingCall(nextCall(options), {
start: function(metadata, listener, next) {
// Inject token setiap request
metadata.add('authorization', 'Bearer juragan_secret');
next(metadata, listener);
}
});
}
// Gunakan di client
const client = new userProto('localhost:50051', grpc.credentials.createInsecure(), {
interceptors: [authInterceptor]
});
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! 🚀
16 Penanganan Error di Server gRPC
Artikel Terhangat
17 Menambahkan Metadata pada gRPC Request
06 Jun 2025
16 Penanganan Error di Server gRPC
06 Jun 2025
13 Implementasi Unary RPC
06 Jun 2025
12 Membuat Client gRPC Pertama Anda
06 Jun 2025
11 Membuat Server gRPC Pertama Anda
06 Jun 2025

17 Menambahkan Metadata pada gRPC Request

16 Penanganan Error di Server gRPC

13 Implementasi Unary RPC

12 Membuat Client gRPC Pertama Anda
