Fazendo requests POST/GET. (PowerBuilder)

Fazendo requests POST/GET. (PowerBuilder)

Overview

Aprender a lidar com requisições GET e POST no PowerBuilder pode parecer uma aventura pelos cantos misteriosos da programação. No entanto, este post iluminará o caminho com exemplos claros e práticos, direto ao ponto, garantindo que você navegue por esse desafio com a confiança de um veterano. Juntos, desvendaremos os segredos de como fazer requisições, tratar respostas e até mesmo entender os códigos de retorno, tudo isso enquanto mantemos uma conversa leve e direta. Pronto para se tornar um mestre das requisições web no PowerBuilder? Vem comigo!

Ha algum tempo precisei utilizar o PowerBuilder para realizar requisições GET e POST. Como não foi algo tão trivial quanto deveria e como as informações estavam todas picadas, resolvi fazer este post para ajudar no entendimento.

Antes de começarmos, um aviso: Vou passar os exemplos de códigos aqui, mas criei um repositório com objetos que vão te auxiliar neste processo.

Passo 1: Tratando conteúdo das respostas

A primeira coisa que você tem que saber é que precisa criar um objeto seu, herdado de internetresult. Nele você precisa criar o código para a função internetdata. Ela é uma função de callback, que é chamada automaticamente pelo PB, assim que a sua request é concluída. Não existe um padrão para tratar este resultado e o código é bem simples: Basta converter uma variável blob para string.

Vamos chamar este objeto que decodifica o resultado de uo_inet_result. Para cria-lo, primeiro acesse o menu File, New, aba PB Object, Standard Class e selecione a opção internetresult.

Agora abra o painter deste objeto que você acabou de criar e clique na aba "Declare Instance Variables". Nela, inclua o seguinte código:

1protectedwrite string is_result

Desta forma, você cria uma variável que será acessível por outros objetos, mas que não pode ser modificada externamente. Isso é o suficiente para este exemplo.

Agora abra o fonte da função internetdata e insira o seguinte código:

1this.is_result = string(data, EncodingUTF8!)

Como disse anteriormente, o procedimento é simples. Basta converter o conteúdo do argumento "data" de blob para string. Para trabalhar de forma mais segura, coloco o enum EncodingUTF8!. Desta forma, garantimos (ou algo bem próximo a isso) que não vão aparecer caracteres estranhos.

Passo 2: Tratando código de retorno

Agora a parte mais difícil está feita. Antes de mostrar como fazer as requests get e post, uma pequena (mas importante) nota: Esta forma de realizar requisições não te da acesso ao status_code da requisição. Você deve tratar os códigos de retorno específicos dos objeto. Veja abaixo:

Código de retornoTipo da requisiçãoDescrição
1GET / POSTSucesso!
-1GET / POSTErro genérico. Aqui pode ser quase qualquer coisa, incluindo falha na criação do objeto herdado de internetresult (que fizemos no passo anterior).
-2GET / POSTURL inválida
-4GET / POSTNão foi possível se conectar a internet
-5POSTRequisição feita utilizando protocolo não suportado. (O PB não da suporte para requisições post, usando https.)
-6POSTRequisição falhou.

(Aposto que você não percebeu, mas não existe um código de retorno -3.)

Passo 3: Fazendo requisição GET

Abaixo está o exemplo de uma requisição GET simples. Ela utiliza o objeto que criamos no passo 1.

 1int li_get_ret
 2string ls_url
 3uo_inet_result luo_get_result
 4inet l_inet
 5
 6ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/ping"
 7l_inet = create inet
 8
 9li_get_ret = i_inet.getURL(ls_url, luo_get_result)
10if li_get_ret = 1 then
11  MessageBox("Success!", luo_get_result.is_result, Information!)
12else
13  MessageBox("Error!", "Deu ruim!", StopSign!)
14end if

No código acima:

  1. primeiro declaramos e definimos as variáveis.
  2. na sequencia, utilizo o objeto inet (l_inet) para fazer a requisição GET).
  3. depois verifico o código de retorno (li_get_ret), se tudo deu certo (= 1), mostro um MessageBox com o resultado. Se deu errado, mostro outra MessageBox com uma mensagem de erro.

Passo 4: Fazendo uma requisição POST

Este tipo de post é bem parecido, com poucas diferenças:

  1. Temos que definir um header para enviar com a requisição;
  2. Precisamos converter o conteúdo que será enviado para blob;
 1int li_post_ret
 2string ls_url
 3string ls_data
 4string ls_header
 5long ll_port
 6blob lblb_data
 7uo_inet_result luo_get_result
 8inet l_inet
 9
10l_inet = create inet
11ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/echo"
12ls_data = "The quick brown fox jumps over the lazy dog."
13ls_headers = "Content-Length: " + string(len(ls_data))
14ll_port = 80
15lblb_data = blob(ls_data, EncodingUTF8!)

Nó código acima:

  1. Coloquei o conteúdo que desejo enviar via POST na variável ls_data
  2. Criei a variável ls_headers para armazenar a informação de header. Nela coloquei apenas o tamanho dos dados que estão sendo enviados;
  3. Na variável ll_port, configurei a porta que vai ser utilizada.
  4. Por último, converti a variável ls_data de string para blob.

Agora que isso foi resolvido, basta fazer a requisição em si:

1li_post_ret = l_inet.postURL(ls_url, lblb_data, ls_header, ll_port, luo_post_result)
2
3if li_post_ret = 1 then
4  MessageBox("Success!", luo_get_result.is_result, Information!)
5else
6  MessageBox("Error!", "Deu ruim!", StopSign!)
7end if

Acima, apenas utilizei a função PostURL do objeto l_inet e processei o retorno dele, da mesma forma que fiz com a requisição GET.

Atenção aos detalhes!

Então, o PowerBuilder possui alguns comportamentos que você deve sempre ter em mente:

  1. Nas requisições GET, para mudar a porta utilizada, você tem que colocar esta informação na URL. (exemplo: http://localhost:5000 ou http://localhost:8080);
  2. Já nas requisições POST, não adianta colocar a porta na URL, você deve utilizar o parâmetro fornecido no método. O PB vai ignorar a porta da URL;
  3. Atenção: Não é possível fazer requisições POST usando HTTPS. GET é tranquilo;
  4. Requisições post não podem ter querystring.

Exemplos no Github

Criei uma aplicação de demonstração. Nela inclui uma PBL com os objetos já prontos para serem utilizados (uo_requester e uo_inet_result).

Para utiliza-los, veja os exemplos:

Request GET com Querystring #1

 1//Declaring variables
 2string ls_method, ls_querystring, ls_url
 3string ls_result
 4uo_requester luo_requester
 5
 6//Initializing
 7ls_method = "echoargs"
 8ls_querystring = "?foo=42&bar=code"
 9luo_requester = create uo_requester
10
11//Setting the base url for all requests.
12luo_requester.of_set_base_url("https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/")
13
14//Getting the full URL 
15ls_url = luo_requester.of_get_full_url(ls_method + ls_querystring)
16
17//The actual GET request.
18ls_result = luo_requester.of_get(ls_url)
19
20//Testing result.
21if isNull(ls_result) then
22	//Something went wrong.
23	
24else
25	//ls_result contains the returned value of the request.
26	
27end if
28
29//Destroying object.
30destroy luo_requester

Request GET com Querystring #2

 1//Declaring variables
 2string ls_url
 3string ls_result
 4uo_requester luo_requester
 5
 6//Initializing
 7luo_requester = create uo_requester
 8
 9//Defining the full URL 
10ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/echoargs?foo=42&bar=code"
11
12//The actual GET request.
13ls_result = luo_requester.of_get(ls_url)
14
15//Testing result.
16if isNull(ls_result) then
17	//Something went wrong.
18	
19else
20	//ls_result contains the returned value of the request.
21	
22end if
23
24//Destroying object.
25destroy luo_requester

Request POST

 1//Declaring variables
 2string ls_headers
 3string ls_url
 4string ls_data
 5string ls_result
 6blob lblb_data
 7long ll_data_size
 8uo_requester luo_requester
 9
10//Initializing
11luo_requester = create uo_requester
12
13//Defining the full URL 
14ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/echo"
15
16//Preparing data that will be sent
17ls_data = "I'll send this to the webservice!"
18
19if luo_requester.of_encode_args(ls_data, lblb_data, ll_data_size) = -1 then
20	//Error encoding data.
21	return -1
22end if
23
24//Getting headers.
25ls_headers = luo_requester.of_get_headers(ll_data_size)
26
27//The actual GET request.
28ls_result = luo_requester.of_post(ls_url, lblb_data, ls_headers)
29
30//Testing result.
31if isNull(ls_result) then
32	//Something went wrong.
33	
34else
35	//ls_result contains the returned value of the request.
36	
37end if
38
39//Destroying object.
40destroy luo_requester

Como encapsular estes métodos

Para facilitar, criei um objeto chamado uo_dummy_requester, que encapsula as chamadas para uma api de teste que criei. Você pode utiliza-la como exemplo para encapsular as chamadas que você precisa utilizar.

Link para o fonte no GitHub: https://github.com/brenordv/powerbuilder_webservice_poc

Espero ter ajudado!

Referências:

  1. inet.GetURL
  2. inet.PostURL