Pengembangan gRPC dengan Claude Code: Protobuf, streaming, operasi
Bangun layanan gRPC yang bisa dijalankan dengan Claude Code, Protobuf, tenggat, streaming, auth, dan observability.
Mulai Dari Kontrak, Bukan Dari Server
gRPC adalah kerangka panggilan prosedur jarak jauh. Klien memanggil metode di layanan lain seperti fungsi lokal, tetapi komunikasi sebenarnya berjalan melalui jaringan. Protocol Buffers mendefinisikan kontrak: layanan, metode, pesan permintaan, pesan respons, dan nomor field. Claude Code sebaiknya memahami kontrak ini sebelum menulis server dan klien.
Gunakan dokumentasi resmi sebagai acuan: gRPC Introduction, Core concepts, Node basics, Deadlines, Status Codes, Authentication, OpenTelemetry Metrics, dan Protocol Buffers proto3 guide.
Untuk konteks ClaudeCodeLab, lanjutkan dengan pengembangan API produksi, microservices dengan Claude Code, strategi versi API, dan strategi testing.
Kasus Penggunaan Nyata
Jangan memilih gRPC hanya karena terdengar cepat. Pilih ketika kontrak bertipe, status gagal yang jelas, dan konsistensi lintas bahasa benar-benar membantu.
| Kasus | Mengapa gRPC cocok | Tugas untuk Claude Code |
|---|---|---|
| Layanan internal pesanan, stok, tagihan | Kontrak mengurangi perbedaan antar tim | Menulis .proto, server, klien, dan tabel status |
| Ekspor data besar | Streaming server menghindari satu respons raksasa | Merancang returns (stream Item) dan pembatalan |
| Tim dengan Go, Node, Python | Satu skema memandu beberapa klien | Mendokumentasikan perintah generasi, folder, dan CI |
| Alat internal dan agen AI | Metode eksplisit mengurangi panggilan ambigu | Menambah klien contoh, metadata auth, tenggat, dan log |
Catatan praktik dari Masa: metode Search yang terlalu luas terasa mudah pada awalnya, tetapi cepat sulit diubah. Pisahkan baca, buat, dan streaming lebih awal, lalu minta Claude Code mengikuti kontrak itu.
Contoh Node gRPC Yang Bisa Dijalankan
Contoh ini memakai @grpc/proto-loader, sehingga bukti lokal pertama tidak membutuhkan protoc.
mkdir claude-grpc-demo
cd claude-grpc-demo
npm init -y
npm install @grpc/grpc-js @grpc/proto-loader
mkdir proto
package.json:
{
"type": "commonjs",
"scripts": {
"server": "node server.js",
"client": "node client.js"
},
"dependencies": {
"@grpc/grpc-js": "latest",
"@grpc/proto-loader": "latest"
}
}
proto/task.proto:
syntax = "proto3";
package tasks.v1;
service TaskService {
rpc CreateTask(CreateTaskRequest) returns (Task);
rpc GetTask(GetTaskRequest) returns (Task);
rpc ListTasks(ListTasksRequest) returns (stream Task);
}
message Task {
string id = 1;
string title = 2;
string status = 3;
int64 created_at_unix = 4;
}
message CreateTaskRequest {
string title = 1;
}
message GetTaskRequest {
string id = 1;
}
message ListTasksRequest {
int32 limit = 1;
}
server.js:
const path = require("node:path");
const { randomUUID } = require("node:crypto");
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const PROTO_PATH = path.join(__dirname, "proto", "task.proto");
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: false,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const taskProto = grpc.loadPackageDefinition(packageDefinition).tasks.v1;
const token = process.env.DEMO_TOKEN || "dev-token";
const tasks = new Map();
function grpcError(code, message) {
const error = new Error(message);
error.code = code;
return error;
}
function assertAuthenticated(call) {
const value = call.metadata.get("authorization")[0];
if (value !== `Bearer ${token}`) {
throw grpcError(grpc.status.UNAUTHENTICATED, "UNAUTHENTICATED");
}
}
function createTask(call, callback) {
try {
assertAuthenticated(call);
const title = String(call.request.title || "").trim();
if (!title) {
return callback(grpcError(grpc.status.INVALID_ARGUMENT, "INVALID_ARGUMENT: title"));
}
const task = {
id: randomUUID(),
title,
status: "OPEN",
createdAtUnix: String(Math.floor(Date.now() / 1000)),
};
tasks.set(task.id, task);
callback(null, task);
} catch (error) {
callback(error);
}
}
function getTask(call, callback) {
try {
assertAuthenticated(call);
const task = tasks.get(call.request.id);
if (!task) {
return callback(grpcError(grpc.status.NOT_FOUND, "NOT_FOUND: task"));
}
callback(null, task);
} catch (error) {
callback(error);
}
}
function listTasks(call) {
try {
assertAuthenticated(call);
const limit = Math.min(Math.max(Number(call.request.limit) || 10, 1), 100);
for (const task of Array.from(tasks.values()).slice(0, limit)) {
call.write(task);
}
call.end();
} catch (error) {
call.destroy(error);
}
}
const server = new grpc.Server();
server.addService(taskProto.TaskService.service, { createTask, getTask, listTasks });
server.bindAsync("127.0.0.1:50051", grpc.ServerCredentials.createInsecure(), (error, port) => {
if (error) throw error;
console.log(`TaskService listening on ${port}`);
});
client.js:
const path = require("node:path");
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const PROTO_PATH = path.join(__dirname, "proto", "task.proto");
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: false,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const taskProto = grpc.loadPackageDefinition(packageDefinition).tasks.v1;
const client = new taskProto.TaskService("127.0.0.1:50051", grpc.credentials.createInsecure());
const metadata = new grpc.Metadata();
metadata.set("authorization", `Bearer ${process.env.DEMO_TOKEN || "dev-token"}`);
function deadline(ms) {
return new Date(Date.now() + ms);
}
function createTask(title) {
return new Promise((resolve, reject) => {
client.createTask({ title }, metadata, { deadline: deadline(1000) }, (error, task) => {
if (error) return reject(error);
resolve(task);
});
});
}
function getTask(id) {
return new Promise((resolve, reject) => {
client.getTask({ id }, metadata, { deadline: deadline(1000) }, (error, task) => {
if (error) return reject(error);
resolve(task);
});
});
}
function listTasks(limit) {
return new Promise((resolve, reject) => {
const rows = [];
const stream = client.listTasks({ limit }, metadata, { deadline: deadline(1000) });
stream.on("data", (task) => rows.push(task));
stream.on("error", reject);
stream.on("end", () => resolve(rows));
});
}
async function main() {
const created = await createTask("Claude Code gRPC");
const fetched = await getTask(created.id);
const rows = await listTasks(10);
console.log(JSON.stringify({ created, fetched, streamed: rows.length }, null, 2));
client.close();
}
main().catch((error) => {
console.error(error.code, error.details || error.message);
client.close();
process.exitCode = 1;
});
Terminal pertama:
npm run server
Terminal kedua:
npm run client
Evolusi Skema, Keamanan, Dan Kegagalan
Dalam Protocol Buffers, kesalahan paling berbahaya adalah memakai ulang nomor field. Nomor yang sudah dirilis jangan diubah. Jika field dihapus, simpan nomor dan namanya dengan reserved.
message Task {
string id = 1;
string title = 2;
string status = 3;
int64 created_at_unix = 4;
optional string assignee_email = 5;
reserved 6, 7;
reserved "owner_email";
}
Tenggat harus eksplisit. Dokumentasi gRPC menjelaskan bahwa klien tanpa tenggat dapat menunggu tanpa batas yang realistis. Streaming berguna untuk ekspor dan progres, tetapi harus menangani pembatalan dan tidak boleh menahan seluruh hasil di memori.
Contoh memakai createInsecure() hanya untuk lokal. Produksi harus memakai TLS: grpc.ServerCredentials.createSsl(...) di server dan grpc.credentials.createSsl(rootCert) di klien. Token pada metadata tidak cukup jika kanal tidak terenkripsi.
Observability perlu menunjukkan metode, status, durasi, pembatalan, tenggat habis, dan backend tidak tersedia. Metrik gRPC OpenTelemetry adalah dasar yang baik. Jangan mengubah semua kegagalan menjadi UNKNOWN; bedakan INVALID_ARGUMENT, NOT_FOUND, UNAUTHENTICATED, DEADLINE_EXCEEDED, UNAVAILABLE, dan RESOURCE_EXHAUSTED. Panggilan tulis sebaiknya diulang otomatis hanya jika ada idempotency key.
Prompt Untuk Claude Code
Implementasikan gRPC TaskService.
Syarat:
- Buat proto/task.proto terlebih dahulu
- Gunakan Node.js, @grpc/grpc-js, dan @grpc/proto-loader
- Implementasikan CreateTask, GetTask, dan ListTasks server streaming
- Tambahkan deadline pada semua RPC klien
- Validasi authorization metadata
- Dokumentasikan bahwa produksi harus mengganti createInsecure dengan TLS
- Jalankan npm run client dan laporkan output
File yang boleh diubah:
- proto/task.proto
- server.js
- client.js
- package.json
Untuk peninjauan:
Tinjau implementasi gRPC ini dengan findings first.
Periksa reuse nomor field, schema evolution, deadline, cancellation,
status code, perilaku memori saat streaming, TLS/auth, dan observability.
Urutkan berdasarkan tingkat bahaya dan sertakan file.
CTA Dan Hasil Verifikasi
Jika belajar sendiri, mulai dari cheatsheet Claude Code gratis lalu ubah contoh ini menjadi proyek latihan kecil. Tim yang perlu mengatur .proto, gerbang CI, prompt review, TLS, dan observability bisa melanjutkan ke pelatihan dan konsultasi Claude Code. Materi yang bisa dipakai ulang tersedia di produk ClaudeCodeLab.
Dalam pembaruan ini, contoh dijalankan di direktori sementara dengan Node v24.14.1 dan npm 11.11.0. npm install, node server.js, dan node client.js berhasil, lalu klien menampilkan created, fetched, dan streamed: 1. Mesin ini tidak memiliki go, protoc, atau plugin Protobuf untuk Go, sehingga artikel memakai jalur Node yang benar-benar dapat diverifikasi di sini.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.
Artikel terkait
Workflow Obsidian ke CLAUDE.md untuk Claude Code
Ubah catatan kerja Obsidian menjadi operating note CLAUDE.md agar konteks tidak dijelaskan ulang.
Claude Code Revenue CTA Routing: dari artikel ke PDF, Gumroad, dan konsultasi
Workflow Claude Code untuk mengarahkan pembaca ke PDF gratis, Gumroad, atau konsultasi sesuai intent.
Aturan handoff tim Claude Code: bukti review, permission, rollback, dan jalur revenue
Format handoff Claude Code untuk tim: bukti, permission rule, rollback, PDF gratis, Gumroad, dan konsultasi.