Skip to content
mobius1qwe edited this page Nov 10, 2026 · 1 revision

Home > JSON-RPC 🚧

JSON-RPC 2.0

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.

Quando usar (em vez de REST)

  • 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.

Servidor

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).

Cliente

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 resposta

Se 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.

Um objeto inteiro, por RTTI (Delphi 2010 em diante)

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 liberar

Desregistre antes de liberar o objeto. No Lazarus/FPC não existe; declare os métodos por AddMethod.

Códigos de erro padrão

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

Só o despachante, para outros transportes

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ções

Execute(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.

Erros comuns

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

Veja também

Começar

Servidor

MQTT 🚧

Cliente

Motores

Avançado

Ajuda

🚧 = em desenvolvimento, pode mudar

Clone this wiki locally