Share Button

Estava trabalhando para simplificar o TRESTClient do DataSnap  e implementar alguns recursos que gostaria de ter e não encontrei no componente distribuido com o delphi ( Package para TRESTSocialClient ). Mapear as respostas Array para um TFDDataset primordial para facilitar o desenvolvimento (ex: TRESTSocialClientDataset). E quando não é possível mapear para um Dataset… código+código+bug+complexo…

Quando trabalho com um Servidor REST Datasnap escrito para delphi – a integração é simples utilizando o “Wizard” para criar um projeto REST Client disponível. Quando o servidor REST responde para múltiplas plataformas é imperativo que o servidor envie respostas “padronizadas” que sejam compatíveis com a plataforma que o cliente utiliza. O caminho mais rápido é responder JSON padrão evitando respostas específicas de uma plataforma ou outra.

Exemplo: um método não pode responder com um TDataset.Data como é o indicado pelo Delphi… isto obrigaria que o cliente seja igualmente um Delphi.. Então para manter padrão o método deve responder com um TJSONValue ou TJSONObject.

Tomando por base o Servidor Datasnap do post “FireDAC – Datasnap” onde publica o método  GetCliente/{cnpj} (http://localhost:8080/datasnap/rest/TServerMethods1/GetCliente/123456) que retorna:

{"result":[{"cliente":[{"RowId":1,"codigo":1,"nome":"Embarcadero SA","cidade":"Sao Paulo","estado":"SP","endereco":"Rua…xxxx…,10","debitos":100000.12},{"RowId":2,"codigo":2,"nome":"Embarcadero SA2","cidade":"Sao Paulo","estado":"SP","endereco":"Rua…xxxx…,10","debitos":100000.12}],"adicional":[{"codigo":1,"nome":"Exemplo 2"}]}]}

Nas andanças pelos BLOGs de MVPs encontrei um projeto “Introducing JsonToDelphiClass” que aponta para o repositório com o código do projeto.

O projeto JsonToDelphiClass permite que a representação JSON de retorno do servidor DataSnap seja colado no espaço para texto indicada e usar o botão de geração da Unit contendo a classe Delphi para a representação JSON.

As classes geradas pelo projeto possuem um método que fornecendo o código de retorno do servidor – popula o objeto delphi – facilitando a conversão da estrutura JSON para Classe.

class function FromJsonString(AJsonString: string): T... (criar a classe e popula)

.

Passando aquele retorno do Servidor, veja como ele construiu as classes para a representação JSON:

unit JsonRestServer;

//  *************************************************
//    Generated By: JsonToDelphiClass - 0.65
//    Project link: https://github.com/PKGeorgiev/Delphi-JsonToDelphiClass
//    Generated On: 2016-04-10 15:41:06
//  *************************************************
//    Created By  : Petar Georgiev - 2014
//    WebSite     : http://pgeorgiev.com
//  *************************************************

interface

uses Generics.Collections, Rest.Json;

type

TAdicionalClass = class
private
  FCodigo: Extended;
  FNome: String;
public
  property codigo: Extended read FCodigo write FCodigo;
  property nome: String read FNome write FNome;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TAdicionalClass;
end;

TClienteClass = class
private
  FRowId: Extended;
  FCidade: String;
  FCodigo: Extended;
  FDebitos: Extended;
  FEndereco: String;
  FEstado: String;
  FNome: String;
public
  property RowId: Extended read FRowId write FRowId;
  property cidade: String read FCidade write FCidade;
  property codigo: Extended read FCodigo write FCodigo;
  property debitos: Extended read FDebitos write FDebitos;
  property endereco: String read FEndereco write FEndereco;
  property estado: String read FEstado write FEstado;
  property nome: String read FNome write FNome;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TClienteClass;
end;

TResultClass = class
private
  FAdicional: TArray<TAdicionalClass>;
  FCliente: TArray<TClienteClass>;
public
  property adicional: TArray<TAdicionalClass> read FAdicional write FAdicional;
  property cliente: TArray<TClienteClass> read FCliente write FCliente;
  destructor Destroy; override;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TResultClass;
end;

TRootClass = class
private
  FResult: TArray<TResultClass>;
public
  property result: TArray<TResultClass> read FResult write FResult;
  destructor Destroy; override;
  function ToJsonString: string;
  class function FromJsonString(AJsonString: string): TRootClass;
end;

implementation

{TAdicionalClass}


function TAdicionalClass.ToJsonString: string;
begin
  result := TJson.ObjectToJsonString(self);
end;

class function TAdicionalClass.FromJsonString(AJsonString: string): TAdicionalClass;
begin
  result := TJson.JsonToObject<TAdicionalClass>(AJsonString)
end;

{TClienteClass}


function TClienteClass.ToJsonString: string;
begin
  result := TJson.ObjectToJsonString(self);
end;

class function TClienteClass.FromJsonString(AJsonString: string): TClienteClass;
begin
  result := TJson.JsonToObject<TClienteClass>(AJsonString)
end;

{TResultClass}

destructor TResultClass.Destroy;
var
  LclienteItem: TClienteClass;
  LadicionalItem: TAdicionalClass;
begin

 for LclienteItem in FCliente do
   LclienteItem.free;
 for LadicionalItem in FAdicional do
   LadicionalItem.free;

  inherited;
end;

function TResultClass.ToJsonString: string;
begin
  result := TJson.ObjectToJsonString(self);
end;

class function TResultClass.FromJsonString(AJsonString: string): TResultClass;
begin
  result := TJson.JsonToObject<TResultClass>(AJsonString)
end;

{TRootClass}

destructor TRootClass.Destroy;
var
  LresultItem: TResultClass;
begin

 for LresultItem in FResult do
   LresultItem.free;

  inherited;
end;

function TRootClass.ToJsonString: string;
begin
  result := TJson.ObjectToJsonString(self);
end;

class function TRootClass.FromJsonString(AJsonString: string): TRootClass;
begin
  result := TJson.JsonToObject<TRootClass>(AJsonString)
end;

end.

 

 

 

Share Button

O uso de Datasnap como cliente de acesso ao servidor JSON é resultante de uma combinação de componentes do delphi para completar a chamada. Se do lado do Servidor há um Datasnap então o lado cliente é facilitado ao coletar informações dos métodos exportados pelo servidor e geração do cliente automático. A implementação do servidor JSON pode apresentar uma variedade muito grande de formato de publicação (ou não) dos seus métodos, o que pode se tornar bastante trabalhoso a implementação do cliente.

Simplificando o trabalho:

TRESTSocialClient


Encapsula os componentes necessário para efetivar uma troca de informações entre do servidor para o cliente.

 public
    function Response: TRESTResponse;
    function Request: TRESTRequest;
    function Auth2: TOAuth2Authenticator;
    property AccessToken: string read GetAccessToken write SetAccessToken;
    procedure Clear; virtual;
    constructor create(ow: TComponent); override;
    destructor destroy; override;
    function Get(url: string; AResource: string = ''): string; virtual;
    function GetStream(AUrl: string; AResource: string; AStream: TStream)
      : integer; virtual;
    function SendStream(AUrl, AResource: string; AStream: TStream)
      : integer; virtual;
    function Post(url: string; AResource: string = ''): string; virtual;

 

 var rsp:string;
  with TRESTSocialClient.create(nil) do
  try
    rsp := Get('http://meuservidor/xxxx', '/GetCliente?codigo=1');  // chama o servidor                                                                 para pegar GetCliente.... finally
     free;
  end;

TRESTSocialClientDataset


Herança de TRESTSocialClient que associa a resposta do servidor um Dataset.

  with TRESTSocialClientDataset.create(nil) do
  try
    // pode indica um DATASET, para obter o retorno
    Dataset := MeuDataset;   // se nao for informado retorna um Dataset   TFDMemTable
    rootElement := 'result';  // espera um Array com as linhas da tabela;  
    rsp := Get('http://meuservidor/xxxx', '/GetCliente?codigo=1');  
                                                         // chama o servidor                                                                para pegar GetCliente....  
  finally
     free;
  end;

Exemplo:  REST.Social