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:
protectedwrite 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:
this.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 retorno | Tipo da requisição | Descrição |
---|---|---|
1 | GET / POST | Sucesso! |
-1 | GET / POST | Erro genérico. Aqui pode ser quase qualquer coisa, incluindo falha na criação do objeto herdado de internetresult (que fizemos no passo anterior). |
-2 | GET / POST | URL inválida |
-4 | GET / POST | Não foi possível se conectar a internet |
-5 | POST | Requisição feita utilizando protocolo não suportado. (O PB não da suporte para requisições post, usando https.) |
-6 | POST | Requisiçã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.
int li_get_ret
string ls_url
uo_inet_result luo_get_result
inet l_inet
ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/ping"
l_inet = create inet
li_get_ret = i_inet.getURL(ls_url, luo_get_result)
if li_get_ret = 1 then
MessageBox("Success!", luo_get_result.is_result, Information!)
else
MessageBox("Error!", "Deu ruim!", StopSign!)
end if
No código acima:
- primeiro declaramos e definimos as variáveis.
- na sequencia, utilizo o objeto inet (l_inet) para fazer a requisição GET).
- 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:
- Temos que definir um header para enviar com a requisição;
- Precisamos converter o conteúdo que será enviado para blob;
int li_post_ret
string ls_url
string ls_data
string ls_header
long ll_port
blob lblb_data
uo_inet_result luo_get_result
inet l_inet
l_inet = create inet
ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/echo"
ls_data = "The quick brown fox jumps over the lazy dog."
ls_headers = "Content-Length: " + string(len(ls_data))
ll_port = 80
lblb_data = blob(ls_data, EncodingUTF8!)
Nó código acima:
- Coloquei o conteúdo que desejo enviar via POST na variável ls_data
- 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;
- Na variável ll_port, configurei a porta que vai ser utilizada.
- Por último, converti a variável ls_data de string para blob.
Agora que isso foi resolvido, basta fazer a requisição em si:
li_post_ret = l_inet.postURL(ls_url, lblb_data, ls_header, ll_port, luo_post_result)
if li_post_ret = 1 then
MessageBox("Success!", luo_get_result.is_result, Information!)
else
MessageBox("Error!", "Deu ruim!", StopSign!)
end 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:
- 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);
- 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;
- Atenção: Não é possível fazer requisições POST usando HTTPS. GET é tranquilo;
- 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
//Declaring variables
string ls_method, ls_querystring, ls_url
string ls_result
uo_requester luo_requester
//Initializing
ls_method = "echoargs"
ls_querystring = "?foo=42&bar=code"
luo_requester = create uo_requester
//Setting the base url for all requests.
luo_requester.of_set_base_url("https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/")
//Getting the full URL
ls_url = luo_requester.of_get_full_url(ls_method + ls_querystring)
//The actual GET request.
ls_result = luo_requester.of_get(ls_url)
//Testing result.
if isNull(ls_result) then
//Something went wrong.
else
//ls_result contains the returned value of the request.
end if
//Destroying object.
destroy luo_requester
Request GET com Querystring #2
//Declaring variables
string ls_url
string ls_result
uo_requester luo_requester
//Initializing
luo_requester = create uo_requester
//Defining the full URL
ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/echoargs?foo=42&bar=code"
//The actual GET request.
ls_result = luo_requester.of_get(ls_url)
//Testing result.
if isNull(ls_result) then
//Something went wrong.
else
//ls_result contains the returned value of the request.
end if
//Destroying object.
destroy luo_requester
Request POST
//Declaring variables
string ls_headers
string ls_url
string ls_data
string ls_result
blob lblb_data
long ll_data_size
uo_requester luo_requester
//Initializing
luo_requester = create uo_requester
//Defining the full URL
ls_url = "https://raccoon-ninja-dummy-api.herokuapp.com/api/v1/echo"
//Preparing data that will be sent
ls_data = "I'll send this to the webservice!"
if luo_requester.of_encode_args(ls_data, lblb_data, ll_data_size) = -1 then
//Error encoding data.
return -1
end if
//Getting headers.
ls_headers = luo_requester.of_get_headers(ll_data_size)
//The actual GET request.
ls_result = luo_requester.of_post(ls_url, lblb_data, ls_headers)
//Testing result.
if isNull(ls_result) then
//Something went wrong.
else
//ls_result contains the returned value of the request.
end if
//Destroying object.
destroy 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: