sábado, 30 de setembro de 2017

Parm & Json

Tem muita gente que não é chegada em queijo. Não podemos negar que é um super alimento, e devido aos diversos tipos existentes no mundo, podemos dizer que sempre existe um tipo que combina muito bem com qualquer coisa.

Neste artigo vamos explorar um pouco dos nossos dotes culinários (inexistente, no meu caso) e desenvolver uma nova receita com dois ingredientes: Parm para passagem e recebimento de parâmetros, e JSON um mecanismo de registro de informação e também para transferência de dados.

Nosso problema surge quando desejamos transmitir um JSON para um serviço REST, pois quando combinamos: SDT, PARM, REST teremos um pouco de dificuldade para se atingir o ponto ideal do prato.

Veremos que da combinação desses dois ingredientes simplesmente temos “o nascer de uma nova culinária internacional”, rs.

Parm

O primeiro ingrediente que iremos incluir na nossa receita é a regra parm, que já utilizamos pelo menos um milhão de vezes ao longo do tempo em que programamos o Genexus. Eu mesmo nunca parei para pensar como a coisa funcionava, a não ser que tínhamos que enviar o mesmo número e tipo de parâmetros entre os objetos para que ocorresse a correspondência entre eles.

Porém nesta altura do campeonato um novo cenário se consolidou, e com ele a necessidade de se pensar no parm de maneira totalmente diferente do que havíamos até então aprendido, e que havia sido deixado no canto, esquecido por aí, como aquela latinha de atum que está na despensa há mais ou menos três anos.

JSON

Já discutimos JSON aqui no Genexando em muitas ocasiões, não vamos tomar seu precioso tempo para aprofundar neste tema, pois nosso foco, aqui é apenas utilizá-lo para transferir algum tipo de informação estruturada entre sistemas.

{"nome":"Joao da Silva", "endereco":"Rua Um, 2", "cidade":"São Paulo"}

Para alcançar o JSON precisaremos em Genexus criar um SDT, e em seguida criar uma variável do mesmo tipo.


Uma vez carregado o conteúdo, poderemos formatar o conteúdo como JSON, mediante o ToJson().

&sdt.nome="Joao da Silva"
&sdt.endereco="Rua Um, 2"
&sdt.cidade="São Paulo"
&json = &sdt.tojson()

O resultado desta operação, como sabemos, é um texto formatado no padrão JSON, ou seja, saímos do conceito da variável SDT e passamos para texto simples.

A combinação que não funciona

Como na química e na culinária, temos certos elementos que não combinam, temos no Parm e no SDT uma difícil tarefa de encaixá-los.

Se tentarmos transmitir uma variável SDT como parâmetro em um objeto Web (WebPanel ou Transação) teremos um erro, informando que não é possível. E por outro lado, se fizermos a comunicação entre Procedures, este problema não aparecerá.

Esta restrição não é do Genexus, a própria Web na verdade não aceita que sejam passadas variáveis SDT, Vetores ou Coleções nas chamadas HTTP/S, quer seja por conta das dimensões limites do protocolo. Não é possível passagem por referência na Web, e a saída que todos propõem é a serialização da informação no formato JSON (ou XML), ou seja, transformar o conteúdo em texto.

Vamos ao Problema

Feitas as considerações iniciais, vamos à questão fundamental: Como transferir um JSON em chamadas REST, e recebendo-os como parâmetros, considerando, que teremos vários cenários distintos de linguagens e soluções que poderão ser utilizadas para consumir nosso serviço.

Primeiramente teremos que ter uma Procedure ou Data Provider configurado como REST, o que é muito simples fazer, pois teremos apenas que definir duas propriedades: Expose as Web Service = true, e REST Protocol = true.



Nosso objetivo é receber informações diretamente em uma variável SDT, o que vimos ser difícil de se implementar nas chamadas Web. Para isso será necessária uma regra Parm com nossa variável SDT. Neste caso &sdt é uma variável criada com um tipo SDT.


Vimos que esta operação é impossível de se realizar na Web, mas quando falamos REST estaremos submetendo informações para uma procedure, mas claro, de um sistema externo para nossa procedure.

Como fazer isso? Para se chamar uma procedure REST teremos que ter algum tipo de cliente, que pode ser, por exemplo, o Postman. Ao se programar uma chamada REST neste programa o que necessitamos é definir o Método (POST), a URL (http://localhost/teste/rest/wsrestexemplo), para a nossa procedure wsrestexemplo em construção (observe o /rest/ na URL). O Header indicando a passagem do tipo Content-Type: application/json e no Body a informação a ser postada no serviço.


No Body é que está o segredinho da nossa receita, pois deveremos combinar o nosso JSON original, com os dados que queremos transmitir:

{"nome":"douglas", "endereco":"Rua 1, 2", "cidade":"São Paulo"}

Com informações sobre a regra Parm do nosso serviço. Isso quer dizer que se programarmos uma regra Parm(in:&sdt) deveremos produzir outro JSON para representar a nossa variável de entrada &sdt. Estranho isso não?

{"sdt": ... }

A combinação das duas coisas nos leva a solução:

{"sdt": {"nome":"douglas", "endereco":"Rua 1, 2", "cidade":"São Paulo"} }

Ou seja, nosso cliente deverá reproduzir o nome da variável de entrada da Parm.

Recebendo parâmetros

E assim como enviamos, podemos receber também parâmetros, na própria regra Parm, como por exemplo uma variável texto &resposta.


O interessante é que o mesmo comportamento de Json de envio também aparece na mensagem de retorno, e se programarmos &resposta = 'retorno da mensagem '+&sdt.nome, teremos como retorno:

Ou seja, um JSON de retorno, que inicia com o nome da variável &retorno.


Em Genexus

Finalmente em Genexus, para se programar o cliente com o httpClient, deveremos adicionar no body o mesmo formato da chamada.

&service = 'wsrestexemplo'
&httpclient.Host = 'localhost/'
&httpclient.Port = 80
&httpclient.BaseUrl = '/teste/rest/'
&httpclient.AddHeader('content-type','application/json')
&body = '{"sdt":'+ &sdt.ToJson() +'}'
&httpclient.AddString(&body)
&httpclient.Execute('POST', &service)
if &httpclient.ErrCode<>200
   &retorno.FromJson(&httpclient.ToString())
endif


Voilá, nous avons notre chef-d'œuvre avec du parmesan

Ou em português claro, enfim, temos nossa obra prima com parmesão, ou melhor, com parm & json.

Bom, antes de fechar a conta, preciso confessar que essa receita, na verdade eu copiei de dois outros chefs famosos, o Bruno Camargo e o Gonzalo Gallotti, que já estavam curiosos com a culinária envolvendo parmesão. https://es.stackoverflow.com/questions/67187/webservice-rest-con-sdt-por-par%C3%A1metro