Use Cases (Atualizado: 03/06/2026)

Desenvolvimento gRPC com Claude Code: Protobuf, transmissão e operação

Crie um serviço gRPC executável com Claude Code, Protobuf, prazos, transmissão, autenticação e observabilidade.

Desenvolvimento gRPC com Claude Code: Protobuf, transmissão e operação

Comece pelo contrato

gRPC é uma estrutura de chamada remota: o cliente chama um método de outro serviço como se fosse uma função local, mas a comunicação passa pela rede. Protocol Buffers define o contrato: serviços, métodos, mensagens de requisição, mensagens de resposta e números de campo. Com Claude Code, esse contrato precisa vir antes do servidor e do cliente.

Use a documentação oficial como base: gRPC Introduction, Core concepts, Node basics, Deadlines, Status Codes, Authentication, OpenTelemetry Metrics e o guia Protocol Buffers proto3.

Para continuar dentro do ClaudeCodeLab, leia também desenvolvimento de API em produção, microserviços com Claude Code, versionamento de API e estratégias de teste.

Casos de uso concretos

Não escolha gRPC só porque parece rápido. Ele é útil quando contrato tipado, falhas explícitas e consistência entre linguagens reduzem risco.

CasoPor que gRPC ajudaO que pedir ao Claude Code
Serviços internos de pedidos, estoque e cobrançaO contrato evita divergência silenciosaCriar .proto, servidor, cliente e tabela de status
Exportações grandesTransmissão do servidor evita uma resposta giganteImplementar returns (stream Item) e cancelamento
Equipes com Go, Node e PythonUm esquema orienta vários clientesDocumentar geração, pastas e CI
Ferramentas internas e agentes de IAMétodos explícitos reduzem chamadas ambíguasAdicionar cliente de exemplo, metadados de autenticação, prazos e logs

A experiência prática de Masa é que um método Search amplo demais parece simples no começo, mas dificulta evolução. Separar leitura, criação e transmissão antes de pedir código ao Claude Code deixa a revisão menor.

Exemplo gRPC em Node pronto para executar

Este exemplo usa @grpc/proto-loader, então a primeira prova local não precisa de 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;
});

Em um terminal:

npm run server

Em outro:

npm run client

Evolução, segurança e falhas

Em Protocol Buffers, o erro mais perigoso é reutilizar números de campo. Não mude números já publicados. Ao remover um campo, reserve o número e o nome.

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";
}

Prazos precisam ser explícitos. A documentação do gRPC alerta que, sem prazo, o cliente pode esperar indefinidamente. Transmissão ajuda em exportações e progresso, mas precisa lidar com cancelamento e não deve guardar tudo em memória.

O exemplo usa createInsecure() apenas localmente. Em produção, use TLS: grpc.ServerCredentials.createSsl(...) no servidor e grpc.credentials.createSsl(rootCert) no cliente. Token em metadados não protege se o canal não estiver cifrado.

Observabilidade deve mostrar método, status, duração, cancelamento, prazo estourado e backend indisponível. As métricas gRPC de OpenTelemetry são uma boa base. Não devolva tudo como UNKNOWN; separe INVALID_ARGUMENT, NOT_FOUND, UNAUTHENTICATED, DEADLINE_EXCEEDED, UNAVAILABLE e RESOURCE_EXHAUSTED. Chamadas de escrita só devem ser repetidas automaticamente com chave de idempotência.

Prompt para Claude Code

Implemente gRPC TaskService.
Condições:
- Criar primeiro proto/task.proto
- Usar Node.js, @grpc/grpc-js e @grpc/proto-loader
- Implementar CreateTask, GetTask e ListTasks com transmissão do servidor
- Adicionar deadline em todos os RPCs do cliente
- Validar authorization metadata
- Documentar que produção deve trocar createInsecure por TLS
- Executar npm run client e relatar a saída
Arquivos editáveis:
- proto/task.proto
- server.js
- client.js
- package.json

Para revisão:

Revise esta implementação gRPC com findings first.
Verifique reutilização de números de campo, evolução do esquema,
deadline, cancellation, status code, memória na transmissão,
TLS/auth e observability. Ordene por gravidade e cite arquivos.

CTA e resultado verificado

Se você está aprendendo sozinho, comece pela folha gratuita do Claude Code e adapte este exemplo em um projeto descartável. Equipes que precisam governar .proto, CI, prompts de revisão, TLS e observabilidade podem seguir para treinamento e consultoria Claude Code. Materiais reutilizáveis ficam em produtos ClaudeCodeLab.

Nesta atualização, o exemplo foi executado em um diretório temporário com Node v24.14.1 e npm 11.11.0. npm install, node server.js e node client.js funcionaram, e o cliente mostrou created, fetched e streamed: 1. Esta máquina não tinha go, protoc nem os plugins Protobuf para Go; por isso o artigo usa o caminho Node que pôde ser verificado localmente.

#Claude Code #gRPC #Protocol Buffers #microservices #backend
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.