Repository navigation
grpc
Home > gRPC 🚧
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: avançado
Em uma frase: o TRALGrpcModule atende chamadas gRPC no seu servidor e o TRALGrpcClient (ou o
cliente que o ralprotoc gera) as faz, com mensagens Protocol Buffers.
Você vai precisar: o pacote RALModuleGrpcPackage, que requer o RALModuleProtobufPackage,
e o ralprotoc para gerar as units a partir do .proto. Para gRPC nativo, o motor
NgHttp2.
Protocol |
o que é | onde roda |
|---|---|---|
gpWeb (padrão do cliente) |
application/grpc-web: os trailers vão no corpo |
qualquer motor, até em HTTP/1.1; serve a navegadores |
gpWebText |
application/grpc-web-text: o mesmo em base64 |
idem, para clientes que não leem binário |
gpNative |
application/grpc, HTTP/2 com trailers de verdade |
só com o motor NgHttp2 no servidor; no cliente, EngineType := 'NgHttp2'
|
No servidor, AcceptProtocols escolhe o que o módulo aceita (as três, por padrão); outro tipo de
conteúdo gRPC volta 415.
syntax = "proto3";
package saudacao;
message OlaPedido { string nome = 1; int32 vezes = 2; }
message OlaResposta { string texto = 1; }
service Saudador {
rpc Dizer (OlaPedido) returns (OlaResposta);
rpc DizerVarias (OlaPedido) returns (stream OlaResposta);
rpc Juntar (stream OlaPedido) returns (OlaResposta);
rpc Conversar (stream OlaPedido) returns (stream OlaResposta);
}ralprotoc -out=gen saudacao.protoPara cada serviço, a unit traz:
-
TSaudadorClient: um método tipado porrpc; -
TSaudadorServiceBase: um métodovirtual; abstractporrpc, que você sobrescreve.
uses RALGrpcModule, Saudacao;
type
TSaudador = class(TSaudadorServiceBase)
protected
function Dizer(ARequest: TOlaPedido; ACall: TRALGrpcServerCall): TOlaResposta; override;
procedure DizerVarias(ARequest: TOlaPedido; ACall: TRALGrpcServerCall); override;
function Juntar(ACall: TRALGrpcServerCall): TOlaResposta; override;
procedure Conversar(ACall: TRALGrpcServerCall); override;
end;
function TSaudador.Dizer(ARequest: TOlaPedido; ACall: TRALGrpcServerCall): TOlaResposta;
begin
if ARequest.Nome = '' then
raise ERALGrpcError.CreateStatus(RAL_GRPC_INVALID_ARGUMENT, 'falta o nome');
Result := TOlaResposta.Create; // o serviço libera
Result.Texto := 'Olá, ' + ARequest.Nome;
end;
Modulo := TRALGrpcModule.Create(Self);
Modulo.AddService(TSaudador.Create); // o módulo libera o serviço
Modulo.Server := Servidor;As chamadas chegam em POST /<pacote>.<Serviço>/<Método> sob o Domain do módulo.
| tipo | no .proto
|
no serviço |
|---|---|---|
| unário | rpc A (X) returns (Y) |
devolve a resposta (novo objeto; o serviço o libera) |
| servidor em fluxo | returns (stream Y) |
ACall.Send(resposta) para cada uma; dá False se o cliente saiu ou o prazo passou |
| cliente em fluxo | rpc A (stream X) |
ACall.Receive até vir nil; devolve a resposta |
| os dois em fluxo | (stream X) returns (stream Y) |
Receive lê, Send responde |
O cliente e o bidirecional são half duplex: o cliente manda todos os pedidos e só então lê as respostas, que chegam ao vivo.
| membro | |
|---|---|
ReadRequest, Receive
|
a primeira / a próxima mensagem (quem chama libera; Receive dá nil no fim) |
Send, SendReply
|
uma resposta agora (fluxo) / a resposta de uma chamada unária |
Fail(status, mensagem) |
termina com esse status, sem exceção |
Status, StatusMessage
|
o status com que a chamada vai terminar |
Header(nome) |
cabeçalho (metadado) do pedido; vazio se faltar |
AddHeader, AddTrailer
|
metadado de resposta (antes do primeiro Send) / enviado com o status |
Deadline, Expired, TimeLeft
|
o prazo que o cliente pôs (grpc-timeout) |
Request, Response, Protocol, Method, ServiceName
|
acesso ao pedido do núcleo e à chamada |
Uma exceção qualquer vira RAL_GRPC_UNKNOWN; para escolher o status, levante
ERALGrpcError.CreateStatus(código, mensagem). Os códigos são as constantes RAL_GRPC_*
(OK, CANCELLED, INVALID_ARGUMENT, DEADLINE_EXCEEDED, NOT_FOUND, UNIMPLEMENTED,
UNAUTHENTICATED... os 17 do gRPC).
A coleção Methods do módulo declara métodos tratados por evento, no Object Inspector
(ServiceName, Method, Kind, OnCall); OnUnknownMethod atende o que não existe (sem ele, o
status é UNIMPLEMENTED). Dentro do evento, use ReadRequest(TClasse)/Receive(TClasse) e
SendReply/Send.
uses RALClient, RALGrpc, RALGrpcClient, Saudacao;
Cliente := TRALClient.Create(Self);
Cliente.BaseURL.Text := 'http://localhost:8000';
Saudador := TSaudadorClient.Create(Self);
Saudador.Client := Cliente;
Saudador.Protocol := gpWeb;
Saudador.Timeout := 5000; // grpc-timeout, em ms
Pedido := TOlaPedido.Create;
try
Pedido.Nome := 'Ana';
Resposta := Saudador.Dizer(Pedido); // quem chama libera
try
WriteLn(Resposta.Texto);
finally
Resposta.Free;
end;
except
on E: ERALGrpcError do
WriteLn(E.Status, ' ', E.StatusMessage);
end;Em fluxo do servidor, cada resposta vai a um evento (TRALGrpcMessageEvent), na sua thread, e
ACancel := True encerra a chamada:
procedure TForm1.AoResponder(ASender: TObject; AMessage: TRALProtoMessage; var ACancel: Boolean);
begin
Memo1.Lines.Add(TOlaResposta(AMessage).Texto); // não libere: o cliente libera
end;
Saudador.DizerVarias(Pedido, {$IFDEF FPC}@{$ENDIF}AoResponder);| propriedade do cliente | |
|---|---|
Client |
o TRALClient que leva as chamadas (motor, URL, TLS, autenticação) |
Protocol |
gpWeb (padrão), gpWebText ou gpNative
|
Prefix |
caminho posto antes de /pacote.Serviço/Método (o Domain do módulo) |
Timeout |
prazo de cada chamada em ms (grpc-timeout); 0 = sem prazo |
Metadata |
cabeçalhos mandados em toda chamada (nome=valor) |
Compress |
comprime cada mensagem com gzip; precisa da unit RALCompressZLib
|
MaxMessageSize |
maior mensagem de resposta aceita (4 MB; 0 = sem limite) |
LastStatus, LastStatusMessage, LastMetadata
|
o que a última chamada deste objeto trouxe (não serve a várias threads) |
Um status diferente de OK levanta ERALGrpcError.
-
Prazo: o cliente manda
grpc-timeout; no servidor,ACall.Expired/TimeLeftdizem quanto resta. Passado o prazo,SenddáFalsee a chamada termina comDEADLINE_EXCEEDED. -
Compressão: gzip por mensagem nos dois lados, com
RALCompressZLibnouses. -
Tamanho:
MaxMessageSizedo módulo (pedido) e do cliente (resposta); passou, o status éRESOURCE_EXHAUSTED. -
Navegador: o gRPC-Web vindo de outra origem precisa do
TRALCORSPluginliberando a origem. O módulo já mandaAccess-Control-Expose-Headers: grpc-status, grpc-message, para o JavaScript ler o status de uma resposta sem mensagem. - Foi testado contra o
@grpc/grpc-js(nativo) e comcurl(gRPC-Web).
| O que acontece | Causa | O que fazer |
|---|---|---|
| 415 | o módulo não aceita aquele tipo de conteúdo | confira AcceptProtocols e o Protocol do cliente |
gpNative não funciona |
o motor do servidor não manda trailers | use o NgHttp2, ou gpWeb
|
UNIMPLEMENTED |
serviço ou método não ligado ao módulo |
AddService, ou o nome do .proto mudou |
| o navegador recusa a chamada | a origem da página não está liberada | ligue o TRALCORSPlugin com a origem |
| gzip falha | falta RALCompressZLib no uses
|
acrescente a unit |
RESOURCE_EXHAUSTED |
mensagem maior que MaxMessageSize
|
aumente o limite dos dois lados |
-
Protocol Buffers: as mensagens e o
ralprotoc. - Motor NgHttp2: HTTP/2 com trailers, para o gRPC nativo.
- Resposta em fluxo, Plugins.
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 🚧
- 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 🚧
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