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

Home > Servidor > Objetos no corpo 🚧

Receber e devolver objetos (JSON, formulário, CSV, YAML)

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: em vez de ler params um a um, a rota recebe o corpo já convertido num objeto seu, validado, e responde com um objeto no formato que o cliente pediu (Accept).

Você vai precisar: o pacote RALModuleObjectsPackage.

A classe

Qualquer classe com propriedades published. Descenda de TRALObject (um TPersistent com construtor virtual) para o RAL chamar o seu Create e criar o que a classe possui:

type
  TItem = class(TCollectionItem)
  published
    property Produto: string ...;
    property Qtd: Integer ...;
  end;

  TPedido = class(TRALObject)
  public
    constructor Create; override;     // cria FItens e FEndereco
    destructor Destroy; override;
  published
    property Id: Int64 ...;
    property Cliente: string ...;
    property Criado: TDateTime ...;   // ISO 8601
    property Cores: TCores ...;       // conjunto -> ["azul","verde"]
    property Endereco: TEndereco read FEndereco;   // objeto aninhado
    property Itens: TCollection read FItens;       // array
    property Obs: TStrings read FObs;              // array de textos
  end;

initialization
  RALRegisterObjectClass(TPedido);   // para achar a classe pelo nome

Também viram JSON: TStream (base64), TDataSet (array de registros) e listas TObjectList registradas com RALRegisterListClass(TMinhaLista, TItem). Com RTTI estendida (Delphi 2010+), TObjectList<T>, records e arrays também (TRALObjectRTTI.ToText<T> / FromText<T>).

A rota

Server.CreateObjectRoute('pedidos', 'TPedido', Salvar).Allow([amPOST]);

procedure TForm1.Salvar(ARequest: TRALRequest; AResponse: TRALResponse; ABody: TObject);
var
  vPedido: TPedido;
begin
  vPedido := TPedido(ABody);           // lido, validado; o RAL libera depois
  ...
  RALAnswerObject(ARequest, AResponse, HTTP_Created, vPedido);
end;

No Object Inspector: BodyClass e o evento OnReplyObject da rota. Corpo ilegível (JSON quebrado) é 400; tipo que nenhum formatador lê é 415; regra quebrada é 422 (validação), sempre em application/problem+json.

Sem rota de objeto, as mesmas peças avulsas: RALReadBody(ARequest, Obj), RALReadParams(ARequest, Obj) (query, path, cabeçalho e campos pelo nome da propriedade) e RALAnswerObject.

Formatos (negociação)

tipo lê escreve
application/json (e *+json) sim sim (padrão)
application/x-www-form-urlencoded, multipart/form-data sim urlencoded
text/csv uma coleção coleção, lista, dataset
application/yaml não sim

Ao responder vale o Accept com q= (q=0 recusa um tipo); ninguém serve, 406. Um formatador seu herda de TRALObjectFormatter e entra com RALRegisterFormatter. RALPreferredLanguage(ARequest.GetHeader('Accept-Language'), ['pt-BR', 'en']) escolhe o idioma.

Nomes e opções

RALObjectSettings.JSON (ou o componente TRALObjectSettings): Naming (onAsIs, onCamel → valorTotal, onSnake → valor_total, onKebab, onLower), EnumAs, DateFormat (ISO local, ISO UTC, Unix), SkipNil, SkipDefault, IgnoreUnknown, MaxDepth (corta ciclos), NullAs, ValidationStatus (422) e UnreadableStatus (400). RALRegisterPropertyName(TClasse, 'Tipo', 'type') fixa um nome; com atributos (Delphi 2010+) [JSONName('type')] e [JSONIgnore] fazem o mesmo.

Cliente tipado

Api := TRALObjectClient.Create(Cliente);         // Cliente: um TRALClient
if Api.Post('/pedidos', Pedido, Resposta) = 201 then ...
Api.Get('/pedidos/7', Pedido);                    // lê a resposta 2xx no objeto

LastText guarda o corpo da última resposta (o problem+json de um erro). Para descrever a API como interface, veja controllers.

Importar OpenAPI

ralopenapi petstore.json PetStore.pas

Gera uma unidade com uma classe TRALObject por components/schemas (com allOf como herança, arrays de referência como listas registradas, os nomes da API registrados) e um cliente com um método por operação. Lê JSON (OpenAPI 3.0 e 3.1); oneOf/anyOf viram texto. Em código: RALOpenAPIToPascal(Texto, RALOpenAPIOptions('MinhaUnit')).

Swagger

Uma rota com BodyClass ou ResponseClass aparece no Swagger com o esquema da classe em components/schemas (as regras de validação viram required, maxLength, pattern...), e os 400/422. O módulo Swagger também serve swagger.yaml.

Erros comuns

sintoma causa
propriedades aninhadas nil, AV no handler a classe não descende de TRALObject (o Create dela não roda)
500 "BodyClass ... não está registrada" falta RALRegisterObjectClass (ou RegisterClass)
500 "RALModuleObjectsPackage não está ligado" a unit RALObjectBinding não está no projeto
lista vazia no JSON TObjectList sem RALRegisterListClass
datas uma hora fora DateFormat diferente dos dois lados; ISO com offset é o padrão

Veja também

Clone this wiki locally