Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Avro no Node.js: schemas e integração com Kafka

Atualizado em: 25 de outubro de 2026

Terminal Linux usado em desenvolvimento e administração de aplicações Node.js

Avro no Node.js oferece serialização binária orientada por schema para eventos, arquivos e integração entre serviços. O formato é comum em pipelines de dados e Kafka porque separa o contrato do payload, suporta evolução e produz mensagens menores que JSON em muitos cenários.

Avro não é apenas compactação. O schema define nomes, tipos, valores padrão e regras de compatibilidade. Produtores e consumidores precisam coordenar versões para que mensagens antigas continuem legíveis durante deploys independentes.

Schema básico

{
  "type": "record",
  "name": "OrderCreated",
  "namespace": "com.codigofacil.events",
  "fields": [
    { "name": "eventId", "type": "string" },
    { "name": "orderId", "type": "string" },
    { "name": "amountCents", "type": "long" },
    { "name": "currency", "type": "string", "default": "BRL" }
  ]
}

Campos com default facilitam consumidores antigos e novos. O valor padrão deve ser válido para o tipo e representar uma semântica real.

Compilando um schema

import avro from 'avsc';

const type = avro.Type.forSchema(schema);

const event = {
  eventId: crypto.randomUUID(),
  orderId: 'ord-123',
  amountCents: 12990,
  currency: 'BRL'
};

const buffer = type.toBuffer(event);

A biblioteca valida o objeto durante a serialização. Ainda assim, valide regras de negócio antes de codificar.

Decodificando

const decoded = type.fromBuffer(buffer);
console.log(decoded.orderId);

O consumidor precisa conhecer o schema do escritor ou usar um envelope que indique a versão registrada.

Schema Registry

Em Kafka, um padrão comum é registrar schemas e enviar um ID pequeno junto ao payload. O consumidor busca e armazena o schema em cache.

[magic byte][schema id][avro payload]

O registry centraliza compatibilidade, mas vira parte da infraestrutura crítica. Configure cache, timeout, autenticação e comportamento quando ele estiver indisponível.

Compatibilidade backward

Um novo consumidor consegue ler eventos produzidos pelo schema antigo. Adicionar campo com default costuma ser compatível.

{ "name": "source", "type": "string", "default": "unknown" }

Compatibilidade forward

Um consumidor antigo consegue ler dados do schema novo. Remover campos usados pelo leitor ou mudar tipos pode quebrar essa direção.

Compatibilidade full

Exige backward e forward. É mais restritiva e apropriada para ecossistemas com deploys independentes.

Tipos opcionais

Avro representa opcionalidade com union.

{
  "name": "couponCode",
  "type": ["null", "string"],
  "default": null
}

A ordem do union influencia o default. Teste a biblioteca usada pelo produtor e pelo consumidor.

Long e JavaScript

O tipo long pode exceder o inteiro seguro de Number. Para IDs ou valores grandes, configure suporte a BigInt, tipos customizados ou represente como string quando o contrato permitir.

if (!Number.isSafeInteger(value)) {
  throw new Error('Valor excede o intervalo seguro');
}

Valores financeiros inteiros em centavos normalmente cabem, mas limites precisam ser explícitos.

Logical types

Datas, timestamps e decimais são representados sobre tipos primitivos.

{
  "name": "createdAt",
  "type": {
    "type": "long",
    "logicalType": "timestamp-millis"
  }
}

Confirme como a biblioteca converte o logical type. Evite misturar segundos, milissegundos e microssegundos.

Envelope de evento

{
  "eventId": "...",
  "eventType": "order.created.v1",
  "occurredAt": 1792840000000,
  "tenantId": "t-1",
  "data": { }
}

Mesmo com Avro, IDs e tipos versionados ajudam idempotência, roteamento e auditoria.

Kafka

Serializar antes de publicar:

const value = type.toBuffer(event);

await producer.send({
  topic: 'orders',
  messages: [{ key: event.orderId, value }]
});

Consulte Kafka no Node.js.

Validação no consumidor

try {
  const event = readerType.fromBuffer(message.value);
  await handleOrderCreated(event);
} catch (error) {
  await deadLetter.publish({
    reason: 'avro_decode_failed',
    messageId: message.id
  });
}

Não faça retry infinito para payload inválido. Encaminhe a uma DLQ com metadados seguros.

Schema versus regras de negócio

O schema valida estrutura, não todas as invariantes. Um valor pode ser do tipo correto e ainda assim ser inválido, como moeda desconhecida ou total negativo.

Evolução de eventos

Prefira mudanças aditivas. Quando o significado muda, publique novo tipo de evento ou nova versão.

Veja API Versioning no Node.js e Testes de Contrato no Node.js.

Arquivos Avro

Object Container Files armazenam schema e blocos de dados, sendo úteis para exportações e processamento em lote. Para dados não confiáveis, limite tamanho, quantidade de registros e memória durante a leitura.

Desempenho

Compile schemas uma vez e reutilize tipos. Não faça parsing do schema a cada mensagem.

const types = new Map([
  ['order.created.v1', avro.Type.forSchema(orderCreatedSchema)]
]);

Meça serialização, tamanho, CPU e garbage collection com payloads reais.

Segurança

  • limite bytes antes de decodificar;
  • não aceite schema arbitrário do cliente;
  • confie apenas em registries autenticados;
  • valide ID do schema;
  • limite arrays, maps e strings;
  • não registre payloads sensíveis;
  • trate schemas como código de contrato revisado.

Observabilidade

Monitore versão do schema, falhas de encoding e decoding, cache do registry, latência, tamanho das mensagens e DLQ. Inclua schema ID em logs técnicos.

Testes

  • round trip;
  • leitor novo com escritor antigo;
  • leitor antigo com escritor novo;
  • campos com default;
  • union com null;
  • long acima do limite;
  • timestamp;
  • payload truncado;
  • schema desconhecido;
  • registry indisponível.

Erros comuns

  • mudar tipo de campo;
  • adicionar campo sem default;
  • usar Number para qualquer long;
  • compilar schema por mensagem;
  • não testar compatibilidade;
  • confiar apenas na validação estrutural;
  • não limitar payload;
  • acoplar consumidores ao deploy do produtor.

Checklist

  • schema versionado;
  • compatibilidade definida;
  • registry protegido;
  • tipos compilados e reutilizados;
  • longs tratados;
  • defaults revisados;
  • regras de negócio validadas;
  • DLQ configurada;
  • testes de contrato;
  • métricas por schema.

Conclusão

Avro no Node.js oferece contratos binários compactos e evolução controlada para eventos e dados em lote. O maior benefício não é apenas tamanho: é tornar compatibilidade uma regra verificável.

Use schemas revisados, defaults seguros, registry autenticado e testes entre versões. Com limites e observabilidade, Avro permite que produtores e consumidores evoluam de forma independente sem transformar eventos antigos em dados ilegíveis.

Consulte a especificação oficial do Apache Avro.

10 melhores cursos de programação em 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita