Desarrollo gRPC con Claude Code: Protobuf, transmisión y operación
Crea un servicio gRPC ejecutable con Claude Code, Protobuf, plazos, transmisión, autenticación y observabilidad.
Empieza por el contrato, no por el servidor
gRPC es un marco de llamadas remotas: el cliente invoca un método de otro servicio como si fuera una función local, pero la comunicación ocurre por red. Protocol Buffers define el contrato: servicios, métodos, mensajes de petición, mensajes de respuesta y números de campo. Claude Code puede escribir mucho código rápido, pero si ese contrato queda ambiguo, también quedarán ambiguos el servidor, el cliente y las pruebas.
Trabaja con documentación oficial abierta: gRPC Introduction, Core concepts, Node basics, Deadlines, Status Codes, Authentication, OpenTelemetry Metrics y la guía de Protocol Buffers proto3.
Para ampliar dentro de ClaudeCodeLab, combina esta guía con desarrollo de API de producción, microservicios con Claude Code, versionado de API y estrategias de prueba.
Casos de uso reales
No elijas gRPC solo porque “es rápido”. Elige gRPC cuando el contrato tipado, los fallos explícitos y la coherencia entre lenguajes aportan valor.
| Caso | Por qué encaja gRPC | Qué pedir a Claude Code |
|---|---|---|
| Servicios internos de pedidos, inventario y facturación | El contrato reduce desalineación entre equipos | Crear .proto, servidor, cliente y tabla de códigos |
| Exportaciones grandes | La transmisión del servidor evita una respuesta gigante | Diseñar returns (stream Item) y cancelación |
| Equipos con Go, Node y Python | Un esquema puede guiar varios clientes | Documentar generación, carpetas y CI |
| Herramientas internas y agentes de IA | Los métodos explícitos reducen llamadas ambiguas | Añadir cliente de ejemplo, metadatos de autenticación, plazos y registros |
La lección práctica de Masa es que un método Search demasiado amplio parece cómodo al principio, pero se vuelve difícil de versionar. Separar lectura, creación y transmisión antes de pedir código a Claude Code deja revisiones más pequeñas.
Ejemplo gRPC en Node listo para copiar
Este ejemplo usa @grpc/proto-loader, así que no necesita protoc para la primera prueba local.
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;
});
En una terminal:
npm run server
En otra terminal:
npm run client
Evolución, seguridad y fallos
En Protocol Buffers, no reutilices números de campo. Si eliminas un campo, reserva su número y su nombre. Para nuevos datos, añade un número nuevo; si necesitas distinguir “no enviado” de “vacío”, usa presencia explícita.
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";
}
Los plazos son parte del diseño, no un detalle final. La documentación de gRPC indica que, sin plazo, un cliente puede esperar indefinidamente. La transmisión sirve para exportaciones y progreso, pero debe manejar cancelación y no acumular todo en memoria.
El ejemplo usa createInsecure() solo para la prueba local. En producción usa TLS: grpc.ServerCredentials.createSsl(...) en el servidor y grpc.credentials.createSsl(rootCert) en el cliente. Un token en metadatos no protege nada si el canal no está cifrado.
La observabilidad debe incluir método, estado, duración, cancelación, vencimiento de plazo y backend no disponible. Los indicadores gRPC de OpenTelemetry son una base práctica. No conviertas todos los errores en UNKNOWN; separa INVALID_ARGUMENT, NOT_FOUND, UNAUTHENTICATED, DEADLINE_EXCEEDED, UNAVAILABLE y RESOURCE_EXHAUSTED. Reintenta escrituras solo con clave de idempotencia.
Prompt para Claude Code
Implementa gRPC TaskService.
Condiciones:
- Crear primero proto/task.proto
- Usar Node.js, @grpc/grpc-js y @grpc/proto-loader
- Implementar CreateTask, GetTask y ListTasks con transmisión del servidor
- Añadir deadline a todos los RPC del cliente
- Validar authorization metadata
- Documentar que producción debe sustituir createInsecure por TLS
- Ejecutar npm run client y reportar la salida
Archivos editables:
- proto/task.proto
- server.js
- client.js
- package.json
Para revisión:
Revisa esta implementación gRPC con findings first.
Comprueba reutilización de números de campo, evolución del esquema,
deadline, cancellation, status code, memoria en transmisión,
TLS/auth y observability. Ordena por gravedad y cita archivos.
CTA y resultado verificado
Si estás aprendiendo solo, empieza con la chuleta gratuita de Claude Code y adapta este ejemplo en un proyecto desechable. Si tu equipo necesita gobernanza de .proto, puertas de CI, prompts de revisión, TLS y observabilidad, revisa formación y consultoría Claude Code. Para material reutilizable, usa productos ClaudeCodeLab.
Para esta actualización, el ejemplo se ejecutó en un directorio temporal con Node v24.14.1 y npm 11.11.0. npm install, node server.js y node client.js terminaron bien, y el cliente mostró created, fetched y streamed: 1. En esta máquina no estaban disponibles go, protoc ni los complementos Protobuf para Go, así que el artículo se limita al camino Node que sí pudo verificarse.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Workflow de Obsidian a CLAUDE.md con Claude Code
Convierte notas de trabajo de Obsidian en notas operativas de CLAUDE.md para no repetir contexto.
Claude Code Revenue CTA Routing: de artículos a PDF, Gumroad y consulta
Un flujo con Claude Code para dirigir lectores a PDF gratis, Gumroad o consulta según intención.
Reglas de handoff para equipos con Claude Code: evidencia, permisos, rollback e ingresos
Formato práctico para entregar trabajo de Claude Code con pruebas, permisos, rollback, PDF gratis, Gumroad y consulta.