Repository navigation
jsonrpc
Home > JSON-RPC 🚧
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: básico
Em uma frase: o JSON-RPC 2.0 deixa o cliente chamar procedimentos do servidor pelo
nome, com parâmetros em JSON, e o RAL traz o servidor (TRALJSONRPCModule), o cliente
(TRALJSONRPCClient) e o despachante que serve qualquer outro transporte.
Você vai precisar: o pacote RALModuleJSONRPCPackage (paleta RAL - Modules; o
cliente fica na paleta RAL - Client) e um motor.
- A operação é uma ação (
soma,enviarEmail), não um recurso com URL e verbo. - Você quer mandar vários pedidos num só, em lote (um único POST).
- Você quer notificações: chamadas sem resposta (o servidor responde 204).
- O protocolo que você vai falar é baseado em JSON-RPC, como o MCP.
Para recursos e verbos HTTP, continue com as rotas.
Solte um TRALJSONRPCModule no formulário e ligue-o ao servidor (Server). No Object
Inspector, Methods é a lista de métodos: cada item tem Name (diferencia maiúsculas),
Description, Params (os parâmetros declarados) e OnExecute.
| propriedade | |
|---|---|
Path |
rota que recebe as chamadas, sob o Domain; /rpc por padrão. Só aceita POST (GET responde 405) |
Methods |
os métodos respondidos |
OnUnknownMethod |
atende os métodos que não estão em Methods; marque AHandled := True, ou o chamador recebe Method not found
|
ErrorDetails |
True: a mensagem de uma exceção qualquer do método vai no data do erro (desligado por padrão, para não vazar detalhes) |
MaxBatch |
o máximo de chamadas num lote; acima disso é Invalid Request. 0 = sem limite |
Cada parâmetro declarado tem Name, ParamType (jptAny, jptString, jptNumber,
jptInteger, jptBoolean, jptObject, jptArray) e Required (verdadeiro por padrão).
Com parâmetros declarados, o RAL confere o pedido (quantidade, obrigatórios, tipos)
antes do OnExecute e responde Invalid params se não servir. Sem declarar, tudo chega
ao evento. Declarados, os parâmetros também podem vir por posição ([2, 3]) ou por
nome ({"a": 2, "b": 3}).
Por código:
uses RALJSONRPC, RALJSONRPCModule;
Modulo := TRALJSONRPCModule.Create(Self);
Modulo.Server := Servidor;
Metodo := Modulo.Methods.AddMethod('soma', {$IFDEF FPC}@{$ENDIF}Soma, 'soma dois inteiros');
Metodo.Params.AddParam('a', jptInteger);
Metodo.Params.AddParam('b', jptInteger);
Modulo.Methods.AddMethod('agora', {$IFDEF FPC}@{$ENDIF}Agora);
procedure TForm1.Soma(Sender: TObject; ARequest: TRALJSONRPCRequest;
AResult: TRALJSONRPCResult);
begin
// por nome ou por posição, o mesmo Param
AResult.SetInteger(ARequest.Param('a').AsInt64 + ARequest.Param('b').AsInt64);
end;No método, ARequest.Param('nome') devolve o parâmetro (levanta Invalid params se
faltar), FindParam devolve nil se faltar, ParamAt(i) e ParamCount leem por posição
(úteis sem declaração) e IsNotification diz se ninguém espera resposta. O
TRALRequest HTTP chega em ARequest.Context (cabeçalhos, usuário autenticado).
A resposta se dá em AResult: SetInteger, SetFloat, SetBoolean, SetString,
SetNull, SetJSON('{"a":1}') (texto JSON) ou SetValue(TRALJSON) (passa a ser dono).
Não responder é responder null.
Erros: levante ERALJSONRPCError.CreateRPC(codigo, mensagem, dadosJSON); o dadosJSON
é opcional e é texto JSON. Os códigos de -32768 a -32000 são reservados; use os seus fora
dessa faixa.
raise ERALJSONRPCError.CreateRPC(-1, 'Saldo insuficiente', '{"saldo": 10}');Qualquer outra exceção do método vira Internal error (-32603).
Solte um TRALJSONRPCClient e ligue Client a um TRALClient já configurado (motor,
BaseURL, autenticação); Path é a rota do módulo do servidor (/rpc).
uses RALJson, RALJSONRPC, RALJSONRPCClient;
Params := TRALJSON.ParseJSON('{"a": 2, "b": 3}');
try
Resultado := RPC.Call('soma', Params); // o resultado é seu: libere
try
WriteLn(Resultado.AsInt64); // 5
finally
Resultado.Free;
end;
finally
Params.Free;
end;
WriteLn(RPC.CallText('soma', '[2, 3]')); // parâmetros e resultado em texto: 5
RPC.Notify('registrar', Params); // sem respostaSe o servidor responde um erro, Call e CallText levantam ERALJSONRPCError, com
Code, Message e Data. Falha de rede ou de HTTP levanta a exceção do cliente.
Lote (um só POST, as respostas voltam pela posição devolvida por Call):
Lote := RPC.NewBatch;
try
P1 := Lote.Call('soma', ParamsSoma);
Lote.Notify('registrar');
P2 := Lote.Call('falha');
Lote.Send;
if Lote.ErrorCode(P1) = 0 then
WriteLn(Lote.Value(P1).AsInt64); // do lote: não libere
WriteLn(Lote.ErrorCode(P2), ' ', Lote.ErrorMessage(P2));
finally
Lote.Free;
end;Value(i) levanta ERALJSONRPCError se aquela chamada falhou; teste ErrorCode(i) = 0
antes. O valor pertence ao lote.
RALJSONRPCRegisterObject declara um método para cada método público do objeto
(prefixo.Nome, ou só Nome sem prefixo). Os tipos dos parâmetros vêm da RTTI e os
inválidos viram Invalid params.
uses RALJSONRPCObjects;
RALJSONRPCRegisterObject(Modulo.Dispatcher, Calculadora, 'calc'); // calc.Somar ...
// ...
RALJSONRPCUnregisterObject(Modulo.Dispatcher, Calculadora); // antes de liberarDesregistre antes de liberar o objeto. No Lazarus/FPC não existe; declare os métodos
por AddMethod.
| código | constante | quando |
|---|---|---|
| -32700 | cRALJSONRPCParseError |
o texto não é JSON válido |
| -32600 | cRALJSONRPCInvalidRequest |
não é um pedido válido (ou lote acima de MaxBatch) |
| -32601 | cRALJSONRPCMethodNotFound |
o método não existe |
| -32602 | cRALJSONRPCInvalidParams |
parâmetros ausentes, de tipo errado ou em quantidade errada |
| -32603 | cRALJSONRPCInternalError |
o método levantou uma exceção que não é ERALJSONRPCError
|
O módulo é uma casca HTTP sobre o TRALJSONRPCDispatcher (Modulo.Dispatcher, ou crie o
seu com TRALJSONRPCDispatcher.Create(nil)). Ele recebe e devolve texto, sem saber de
onde veio: WebSocket, stdio, fila.
Resposta := Despachante.Execute(Texto); // '' quando só havia notificaçõesExecute(texto, contexto) leva um TObject opcional, que chega aos métodos em
ARequest.Context; ExecuteJSON faz o mesmo com o JSON já lido. Os métodos de um lote
rodam em ordem, na thread de quem chamou.
| sintoma | causa |
|---|---|
Method not found para um método que existe |
o nome diferencia maiúsculas; ou o Path do cliente não é o do módulo |
405 ao abrir o /rpc no navegador |
o módulo só aceita POST |
Invalid params com os números certos |
o tipo declarado não bate (jptInteger não aceita 2.5) |
Internal error sem detalhe |
ligue ErrorDetails para ver a mensagem, só em desenvolvimento |
Value levanta ERALJSONRPCError
|
aquela chamada do lote falhou; teste ErrorCode
|
- Rotas e criar um módulo
- Cliente
- Plugins, para autenticar as chamadas
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) 🚧
- 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 🚧
Cliente
Motores
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