gRPC Interceptors no Node.js permitem executar lógica transversal ao redor das chamadas, como autenticação, logs, tracing, métricas, retries e enriquecimento de metadata. Eles evitam repetir o mesmo código em cada método do serviço.
Um interceptor deve ser pequeno, previsível e independente da regra de negócio. Ele não deve esconder fluxos complexos nem transformar todos os erros em um único status.
Interceptors no cliente
O cliente pode anexar um interceptor às opções do canal ou da chamada. Um interceptor recebe informações do método e cria uma chamada delegando ao próximo elemento da cadeia.
function loggingInterceptor(options, nextCall) {
const requester = {
start(metadata, listener, next) {
const startedAt = performance.now();
const wrappedListener = {
onReceiveStatus(status, nextStatus) {
const duration = performance.now() - startedAt;
logger.info({
method: options.method_definition.path,
code: status.code,
duration
});
nextStatus(status);
}
};
next(metadata, wrappedListener);
}
};
return new grpc.InterceptingCall(nextCall(options), requester);
}Configurando no cliente
const client = new CatalogService(address, credentials, {
interceptors: [loggingInterceptor, tracingInterceptor]
});A ordem importa. Um interceptor externo observa todos os internos. Documente a sequência.
Adicionando metadata
function authInterceptor(options, nextCall) {
return new grpc.InterceptingCall(nextCall(options), {
start(metadata, listener, next) {
metadata.set('authorization', `Bearer ${tokenProvider.get()}`);
metadata.set('x-request-id', crypto.randomUUID());
next(metadata, listener);
}
});
}Não registre a metadata completa, pois pode conter tokens e dados sensíveis.
Tracing
O interceptor pode criar um span por RPC e injetar o contexto:
const span = tracer.startSpan(options.method_definition.path);
propagation.inject(context.active(), metadataCarrier);
Finalize o span com status, duração e erro seguro. Preserve o trace recebido ao chamar serviços downstream.
Retries no interceptor
Retries centralizados são tentadores, mas precisam respeitar idempotência, status e deadline. Não repita automaticamente todos os métodos.
- permita apenas métodos aprovados;
- repita códigos transitórios;
- use backoff com jitter;
- pare quando o deadline não comportar outra tentativa;
- registre número da tentativa.
Credenciais por chamada
Quando o token varia por usuário, obtenha-o no contexto da requisição, não em variável global compartilhada. Em workers, use identidade técnica explícita.
Interceptors no servidor
O suporte e a forma de interceptação no servidor dependem da versão da biblioteca. Uma alternativa estável é envolver handlers durante o registro:
function withAuth(handler) {
return async function wrapped(call, callback) {
try {
call.auth = await authenticate(call.metadata);
authorize(call.auth, call.request);
return handler(call, callback);
} catch (error) {
callback(toGrpcError(error));
}
};
}
server.addService(service, {
getProduct: withMetrics(withAuth(getProduct))
});Centralize a composição para que nenhum método esqueça autenticação.
Contexto por chamada
Crie um objeto imutável com identidade, tenant, request ID, deadline e logger contextual:
call.context = Object.freeze({
requestId,
tenantId,
subject,
deadline: call.getDeadline()
});Não permita que o payload altere o tenant já autenticado.
Validação de metadata
Limite quantidade e tamanho. Rejeite chaves inesperadas quando o protocolo for restrito. Metadata binária usa convenções específicas e não deve ser convertida sem validação.
Mapeamento de erros
function toGrpcError(error) {
if (error instanceof ValidationError) {
return { code: grpc.status.INVALID_ARGUMENT, message: error.publicMessage };
}
if (error instanceof ForbiddenError) {
return { code: grpc.status.PERMISSION_DENIED, message: 'Acesso negado' };
}
logger.error({ error }, 'unhandled grpc error');
return { code: grpc.status.INTERNAL, message: 'Erro interno' };
}Um wrapper pode garantir tradução consistente sem ocultar erros conhecidos.
Métricas
Registre contadores e histogramas por serviço, método e status. Não use request ID ou usuário como label.
grpcDuration.observe(
{ service, method, code },
durationSeconds
);Logging
Um interceptor pode emitir log inicial e final. Evite registrar payloads por padrão; mensagens podem conter dados pessoais ou segredos.
Rate limiting
Rate limiting pode usar identidade e método. A decisão deve ocorrer antes da regra de negócio e retornar RESOURCE_EXHAUSTED. Em múltiplas instâncias, use armazenamento compartilhado quando necessário.
Interceptors e streaming
Streaming exige observar eventos de dados, encerramento e cancelamento. Não armazene todos os chunks para logar ou medir. Conte bytes e mensagens incrementalmente.
Backpressure
Um interceptor de transformação não deve ignorar o fluxo do stream. Processamento pesado deve respeitar pause, resume e sinais de drenagem.
Deadlines
Leia o deadline no início e inclua o tempo restante no contexto. Interceptors de retry e autenticação precisam consumir o mesmo orçamento.
Consulte gRPC Deadlines no Node.js.
Ordem recomendada
Uma cadeia possível:
- request ID;
- tracing;
- métricas;
- autenticação;
- rate limiting;
- validação;
- handler;
- mapeamento de erro.
A ordem exata depende de quais falhas precisam ser medidas e auditadas.
Falhas no interceptor
Qualquer interceptor pode impedir a chamada. Capture erros próprios e retorne status coerente. Não deixe exceções assíncronas escaparem de callbacks.
Testes unitários
Teste o interceptor com uma chamada falsa:
- metadata adicionada;
- token ausente;
- status preservado;
- span finalizado;
- deadline respeitada;
- retry apenas em método permitido;
- payload não registrado.
Testes de integração
Suba cliente e servidor reais e confirme que a cadeia funciona com TLS, streaming, cancelamento e erros.
Observabilidade do próprio interceptor
Meça falhas de autenticação, tempo gasto antes do handler e erros na instrumentação. Um interceptor lento afeta todos os métodos.
Erros comuns
- interceptor com regra de negócio;
- ordem não documentada;
- logar metadata sensível;
- retry genérico;
- token global entre usuários;
- engolir status original;
- ignorar streaming;
- labels de alta cardinalidade;
- instrumentação que lança erro.
Conclusão
gRPC Interceptors no Node.js centralizam preocupações transversais sem poluir handlers. Eles funcionam melhor quando cada componente tem uma responsabilidade clara e a ordem de execução é explícita.
Use interceptors para contexto, autenticação, métricas e tracing, mas preserve deadlines, streaming e status codes. Teste a cadeia completa para garantir que instrumentação e retries não alteram a semântica da API.
Consulte a documentação oficial de interceptors do gRPC e a referência de client interceptors do grpc-node.



