Repository navigation
protobuf
Home > Protocol Buffers 🚧
Important
Em desenvolvimento (2.0). Ainda não está numa versão lançada e pode mudar.
Vale para a 2.0 · Delphi XE em diante e Lazarus/FPC 3.2 em diante · Nível: intermediário
Em uma frase: a partir de um arquivo .proto, o ralprotoc escreve uma unit Pascal com uma
classe por mensagem, que lê e escreve o formato binário do Protocol Buffers e o JSON canônico do
proto3, sem RTTI.
Você vai precisar: o pacote RALModuleProtobufPackage (units RALProtobuf,
RALProtobufWKT, RALProtoSchema e RALProtoCodeGen) e o programa ralprotoc
(tools/ralprotoc/ralprotoc.dpr), que você compila uma vez. Para serviços, veja gRPC.
ralprotoc [-I<pasta>]... [-out=<pasta>] [-unit=<Nome>] [-nogrpc] [-imports] arquivo.proto...| opção | o que faz |
|---|---|
-I<pasta> |
pasta onde procurar os imports (pode repetir) |
-out=<pasta> |
onde gravar as units (a pasta atual, se faltar) |
-unit=<Nome> |
nome da unit de um arquivo (sem isso, o nome do arquivo em PascalCase) |
-imports |
grava também as units dos arquivos importados (nunca as de google/protobuf) |
-nogrpc |
deixa os serviços de fora |
São aceitos proto2, proto3 e edition 2023. Os import "google/protobuf/..." já vêm de
dentro do RAL (RALProtobufWKT): não precisa ter esses arquivos na máquina.
syntax = "proto3";
package loja;
message Pedido {
string cliente = 1;
repeated int32 itens = 2;
}uses RALProtobuf, Loja;
var
vPedido, vOutro: TPedido;
vBytes: TBytes;
begin
vPedido := TPedido.Create;
vOutro := TPedido.Create;
try
vPedido.Cliente := 'Ana';
RALProtoAddInt32(vPedido.Itens, 10);
vBytes := vPedido.Encode; // formato binário
vOutro.Decode(vBytes);
WriteLn(vPedido.ToJSON); // {"cliente":"Ana","itens":[10]}
vOutro.FromJSON('{"cliente":"Bia"}');
finally
vOutro.Free;
vPedido.Free;
end;
end;Toda mensagem descende de TRALProtoMessage: Encode/Decode (bytes), EncodeToStream/
DecodeFromStream, ToJSON/FromJSON, Clone, Assign, Clear e ProtoName (o nome completo,
loja.Pedido). Campos repeated de números e textos são arrays dinâmicos (RALProtoAdd... acrescenta);
repeated de mensagens é uma lista (TPedidoList, com Add e Items).
no .proto
|
em Pascal |
|---|---|
message |
uma classe T<Nome> (aninhada: T<Pai>_<Nome>) |
enum |
type Integer mais constantes (Pai_VALOR); um número fora da lista continua sendo guardado |
oneof |
os campos viram propriedades, e <Nome>Case diz qual está preenchido (..._NotSet se nenhum); Clear<Nome> esvazia |
map<K, V> |
uma lista de entradas com Find(chave) (nil se não tem) e Put(chave) (cria se não tem) |
optional (e campos de mensagem) |
Has<Campo> diz se foi preenchido; Clear<Campo> desfaz |
Campos que a classe não conhece (a mensagem veio de um .proto mais novo) são guardados e
escritos de volta (UnknownFields): um programa feito sobre um .proto velho repassa a
mensagem sem perder nada.
ToJSON e FromJSON seguem o mapeamento JSON canônico do proto3: nomes em lowerCamelCase,
int64/uint64 como texto, bytes em base64, enum pelo nome.
opção (TRALProtoJSONOptions) |
efeito |
|---|---|
rpjEmitDefaults |
escreve também os campos com valor padrão |
rpjEnumsAsNumbers |
enum como número, não como nome |
rpjOriginalNames |
usa os nomes do .proto (sleep_ms), não sleepMs
|
rpjIgnoreUnknown |
ao ler, ignora campo ou nome de enum desconhecido, em vez de dar erro |
Texto := vPedido.ToJSON([rpjEmitDefaults, rpjOriginalNames]);
vPedido.FromJSON(Texto, [rpjIgnoreUnknown]);Estão em RALProtobufWKT, com o JSON que o mapeamento define para cada um:
| tipo | classe | em Pascal |
|---|---|---|
Timestamp |
TProtoTimestamp |
AsDateTime / FromDateTime (UTC); no JSON, texto RFC 3339 |
Duration |
TProtoDuration |
AsMilliseconds / FromMilliseconds
|
BoolValue, StringValue, DoubleValue... |
TProtoBoolValue... |
propriedade Value; no JSON, o próprio valor |
Struct, Value, ListValue
|
TProtoStruct, TProtoValue, TProtoListValue
|
qualquer JSON; Value é um oneof (KindCase) |
FieldMask |
TProtoFieldMask |
Paths |
Empty |
TProtoEmpty |
sem campos |
Any |
TProtoAny |
Pack(mensagem), Unpack (cria a mensagem), UnpackTo(mensagem)
|
vAny := TProtoAny.Create;
vAny.Pack(vPedido); // TypeUrl + bytes
vPedido2 := TPedido(vAny.Unpack); // quem chama liberaO Unpack acha a classe pelo nome do tipo, então ela precisa estar registrada: as units que
o ralprotoc gera registram suas mensagens sozinhas (RALProtoRegisterMessage), basta tê-las no
uses.
- O binário foi conferido contra o protobufjs: os mesmos bytes nos dois sentidos.
- Não são tratados: grupos e extensões (são pulados, não dão erro), e
Anyde um tipo que nenhuma unit registrou. - A leitura limita o aninhamento (100 níveis,
TRALProtoReader.MaxDepth).
| O que acontece | Causa | O que fazer |
|---|---|---|
Unpack não acha o tipo |
a unit do tipo não está no uses, então não se registrou |
ponha a unit gerada no uses
|
unknown option no ralprotoc
|
opção escrita errada | veja a tabela acima |
| import não encontrado | falta o -I da pasta |
passe -I<pasta> (e -imports para gerar as units dele) |
| erro ao ler JSON com campo novo | o JSON tem um campo que a classe não conhece | FromJSON(Texto, [rpjIgnoreUnknown]) |
| unit gerada não compila | falta o pacote | inclua RALModuleProtobufPackage (e o de gRPC se há serviços) |
- gRPC: serviços sobre estas mensagens.
- JSON-RPC 2.0 e Servidor MCP: outros protocolos de chamada.
Começar
Servidor
- Rotas e parâmetros
- Rotas avançadas: tipos, grupos, versões 🚧
- Ler o pedido e responder
- Objetos no corpo 🚧
- Resposta em fluxo 🚧
- Plugins 🚧
- Serviços (contêiner de dependências) 🚧
- Barramento de eventos 🚧
- Autenticação
- Banco de dados (DBWare)
- Servir site e arquivos
- JSON-RPC 2.0 🚧
- Servidor MCP (IA) 🚧
-
Protocol Buffers 🚧
- gRPC 🚧
- WebSocket 🚧
- Hubs (WebSocket) 🚧
- Swagger e Postman
- Servidor SOAP 🚧
- WS-Security 🚧
- HTTPS
- Criptografia ponto a ponto
- Segurança para produção
- Colocar no ar
- Desempenho
- Testes em memória 🚧
MQTT 🚧
- O que é e quando usar 🚧
- Cliente MQTT 🚧
- Broker MQTT 🚧
- MQTT-SN 🚧
- Ponte REST 🚧
- Segurança 🚧
- Rede ruim 🚧
E-mail 🚧
- Mensagens 🚧
- Enviar 🚧
- Receber 🚧
- Ler a caixa postal 🚧
- Verificar o que chega 🚧
- Servir caixas postais 🚧
- S/MIME 🚧
- OpenPGP 🚧
Chatbot 🚧
- O robô e os canais 🚧
- Telegram 🚧
- Gateways REST (WhatsApp não oficial) 🚧
- Discord 🚧
- Slack 🚧
- Microsoft Teams 🚧
- Conversa em etapas 🚧
Cliente
Motores
- Qual motor escolher?
- Compatibilidade
- Recursos
- QUIC
- Motor NgHttp2 (HTTP/2) 🚧
- Motor XSocket 🚧
- Motor AdvancedHTTP (experimental) 🚧
Avançado
Ajuda
- Problemas comuns
- Atualizar o Indy
- Várias versões do Delphi
- Vídeos e guias
- Módulos de terceiros
- Licenças
- Contribuir
- Roadmap e changelog
🚧 = em desenvolvimento, pode mudar