Integração e API

Protocol Buffers

O escopo de Protocol Buffers cobre definição de mensagens, serialização binária e geração de código; não define sozinho transporte, autenticação nem RPC, embora seja a base comum do gRPC. Arquivos .proto atribuem números de campo, tipos e regras de evolução. A edição proto3 tornou-se amplamente usada desde 2016, e o modelo Editions passou a organizar recursos recentes. O ganho é payload compacto e parsing rápido. A limitação é menor legibilidade direta e disciplina obrigatória: números removidos não podem ser reutilizados.


🔀 Tipos de Comunicação
.proto
IDL e geração de código
O arquivo .proto declara package, messages, enums, services e opções. O compilador protoc e plugins geram classes para C++, Java, Python, Go, C#, JavaScript, Kotlin, Swift e outras linguagens. A mensagem se torna uma API tipada. Isso reduz parsing manual, mas cria artefatos gerados que precisam acompanhar a versão do runtime. O schema deve ficar em repositório e ser publicado como dependência. O package e namespace evitam colisão. Importações devem ser fixadas. Um firmware pequeno pode usar nanopb ou implementação leve, com subconjunto e limites. O código gerado não valida regras de negócio como temperatura mínima, autorização ou unidade; apenas representa tipos e presença conforme o schema.
Wire
Wire format binário por tags
Cada campo recebe um número, chamado tag, usado no fio. Tipos inteiros pequenos usam varint; fixed32/fixed64 possuem tamanho fixo; strings e mensagens aninhadas usam length-delimited. O nome do campo não é transmitido. Isso reduz payload em relação a JSON. O custo é que bytes não são autodescritivos sem o .proto. Ferramentas precisam do descriptor. Números 1–15 custam menos no key que números maiores, por isso campos frequentes podem ocupar tags baixas. A otimização deve ser equilibrada com legibilidade. A ordem de serialização não deve ser usada como contrato. Um parser pode reordenar. A representação binária não é criptografia; dados continuam acessíveis a quem possui schema ou faz engenharia reversa.
Evolution
Compatibilidade por campos desconhecidos
Consumidores novos podem ler mensagens antigas e vice-versa quando mudanças seguem regras. Adicionar campo opcional com novo número é geralmente compatível. Parsers preservam ou ignoram campos desconhecidos conforme linguagem e operação. Remover um campo exige reservar seu número e, idealmente, o nome para impedir reutilização. Alterar tipo só é seguro em combinações específicas e pode mudar interpretação. Não se muda significado mantendo a tag. Um campo temperature_c não deve virar Fahrenheit. Enums precisam de valor zero e consumidores devem tratar valores desconhecidos. A compatibilidade binária não garante compatibilidade semântica. A política de rollout precisa considerar produtores offline e gateways antigos.
Presence
Presence, optional e well-known types
Proto3 inicialmente simplificou presença de escalares, usando valores padrão; o keyword optional foi reintroduzido para distinguir ausente de zero. Editions organiza recursos de forma explícita. Mensagens possuem presença naturalmente. google.protobuf.Timestamp, Duration, Any, Struct, FieldMask e wrappers oferecem tipos comuns. Any carrega tipo dinâmico, mas aumenta complexidade e pode criar riscos se instanciar tipos não autorizados. FieldMask expressa atualização parcial. Em automação, distinguir brightness ausente de brightness 0 é essencial: ausente significa não alterar; zero, apagar. O schema precisa representar. Defaults não são enviados necessariamente. A aplicação deve conhecer.
RPC
Serviços gRPC e outros transportes
A seção service de um .proto define métodos unary, client streaming, server streaming e bidirectional streaming para gRPC. O mesmo formato também pode circular em MQTT, Kafka, arquivos, WebSocket ou serial. Protocol Buffers não define QoS, roteamento, framing externo, autenticação nem retry. Em MQTT, o payload binário precisa de content type ou versão e os consumidores precisam do schema. Em gRPC, HTTP/2 e o framework fornecem framing e status. Comparar protobuf a REST é incorreto: um é formato/IDL; REST é estilo de API. Pode haver API REST que usa protobuf, embora JSON seja mais comum.
✅ Vantagens Arquiteturais
Payloads compactos e parsing eficiente
Tags numéricas e varints eliminam nomes repetidos. Telemetria de milhares de dispositivos pode consumir menos banda e armazenamento que JSON. O ganho real depende dos dados: blobs grandes mudam pouco; objetos com nomes longos ganham mais. Compressão HTTP pode reduzir a diferença, mas custa CPU e latência. Em microcontroladores, implementações como nanopb permitem buffers estáticos. O projeto deve medir com mensagens reais. Um payload de poucos bytes em MQTT talvez não justifique a complexidade se humanos precisam depurar. Para redes celulares ou LoRaWAN, protobuf pode ajudar, porém LoRaWAN possui limites tão restritos que um codec bit a bit específico pode ser ainda menor.
Tipos consistentes entre linguagens
O gerador define int32, uint64, sint64, bytes, enum e mensagens. Isso reduz divergência de nomes e parsing. Algumas linguagens não representam uint64 ou int64 de forma nativa em JSON/JavaScript sem cuidado, mas o runtime protobuf resolve por objetos ou strings conforme biblioteca. A API precisa documentar. O código gerado oferece builders e métodos. O ganho é maior em equipes multilíngues. A limitação é a necessidade de atualizar runtimes e plugins. Um compilador novo pode gerar código incompatível com runtime antigo. A toolchain é fixada por lockfiles e CI.
Evolução tolerante quando as regras são respeitadas
Novos campos podem chegar antes de todos os consumidores. Isso é valioso em dispositivos que permanecem anos. Reservar tags reduz acidentes. Testes de compatibilidade podem comparar descriptors. Buf e outras ferramentas fazem lint e breaking checks. A política precisa definir pacote e versão. A evolução é menos flexível para mudanças semânticas. Um enum removido pode quebrar lógica mesmo que parseie. Campos required de proto2 dificultavam rollout; proto3 evita, mas a aplicação ainda pode exigir. A validação de negócio deve produzir erros claros. Nunca reutilize tag de dado antigo para outra coisa, pois mensagens armazenadas serão interpretadas incorretamente.
Integração natural com gRPC e streaming
Definições de service geram cliente e servidor. A mesma mensagem é usada em unary e streaming. Isso simplifica gateways de automação, serviços de vídeo, telemetria e controle. gRPC acrescenta deadlines, metadata, status e interceptors. A eficiência é boa em links persistentes HTTP/2. Navegadores precisam de gRPC-Web ou ponte. Redes corporativas podem bloquear. Para dispositivos muito pequenos, um transporte simples pode ser melhor. O contrato deve separar operações idempotentes. Deadlines são obrigatórios para não acumular chamadas. O formato não resolve descoberta.
Descriptors habilitam reflexão e ferramentas
FileDescriptorSet descreve o schema de forma binária. Servidores podem oferecer reflection para ferramentas como grpcurl. Registries armazenam. Isso ajuda depuração e geração dinâmica. Expor reflexão em produção pode revelar APIs internas; controle de acesso é necessário. Descriptors também permitem converter para JSON, validar políticas e decodificar eventos. A conversão JSON oficial possui regras específicas para nomes, enums, bytes e 64-bit. Não invente uma representação incompatível. Quando mensagens circulam em broker, publicar schema por versão facilita consumers. A governança precisa evitar que descriptor mutável altere dados históricos.