PBToolboxAI v3 ← Site

restclient — n_pbt_restclient #

← Referência dos componentes · Índice do guia

Um cliente HTTPS para PowerBuilder, versão 10 incluída: GET, POST, PUT, PATCH, DELETE, cabeçalhos, um corpo JSON, a transferência de um ficheiro. Nativo — o TLS, o proxy e a descompressão do sistema, e nenhum muro CORS, porque o pedido não parte de uma página.

▶ Ver ao vivo — Aplicação de demonstração, mosaico REST client: as respostas, o código que as obtém e esta página, lado a lado (ligação à Internet necessária).


Em resumo #

Objeto não visualn_pbt_restclient
Serve paraChamar uma API REST a partir de uma aplicação PowerBuilder: ler, criar, atualizar, transferir
PrincípioUm pedido é uma chamada que devolve o estado HTTP; a resposta espera no objeto, lida por of_response_text ou of_json_value
DependênciaWinHTTP, na DLL da biblioteca — sem página, sem runtime adicional

Início rápido #

n_pbt_restclient lnv_rest
n_pbt_json lnv_j
long ll_status

lnv_rest = create n_pbt_restclient
lnv_rest.is_base_url = "https://api.example.com"
lnv_rest.of_set_bearer(ls_token)

// Read : the status comes back, the body waits in the object
ll_status = lnv_rest.of_get("/orders/4152")
if ll_status = 200 then ls_customer = lnv_rest.of_json_value("customer")

// Create : the body is built with n_pbt_json, never by hand
lnv_j.of_set_number("order", 4152)
lnv_j.of_set_string("status", "shipped")
ll_status = lnv_rest.of_post("/shipments", lnv_j.of_text())
if ll_status < 0 then MessageBox("API", lnv_rest.is_last_error)

destroy lnv_rest

Cada método HTTP devolve o estado que o servidor escolheu — um 404 é uma resposta, não um erro — ou um código negativo quando o pedido não passou: -5 URL inválido, -4 falha (sem rede, nome desconhecido, tempo esgotado, TLS; is_last_error diz qual), -6 recusado em modo demo.


Porquê nativo, e não a página #

Um fetch() lançado a partir de uma página da biblioteca está sujeito a CORS: toda a API que não envie Access-Control-Allow-Origin fica-lhe fechada, e as API de empresa não o enviam. O pedido parte por isso da DLL, por WinHTTP: o TLS do sistema com os seus certificados, o proxy configurado, gzip. O que perde: nada; o que ganha: todas as API.


Propriedades #

PropriedadeTipoPredefiniçãoFunção
is_base_urlstring""Posto à frente de um URL relativo: is_base_url = "https://api.example.com" e depois of_get("/orders/4152"). Um URL absoluto é usado tal como está
il_timeout_mslong30000Duração máxima de um pedido, ligação e resposta incluídas. Depois: -4 e «timed out»
is_last_errorstring""Porque o último pedido devolveu um código negativo. Vazio após um pedido que chegou ao servidor — um 404 não é um erro
il_statuslong0O estado HTTP do último pedido, ou o seu código negativo; o valor que o pedido devolveu

Constantes: METHOD_GET, METHOD_POST, METHOD_PUT, METHOD_PATCH, METHOD_DELETE para of_request.


Métodos #

MétodoFunção
of_set_header (string as_name, string as_value)Um cabeçalho enviado com cada pedido a partir de agora; um nome já definido é substituído. Content-Type é acrescentado sozinho quando um corpo parte sem ele (JSON, UTF-8)
of_remove_header (string as_name)Esquece um cabeçalho, por nome (sem distinção de maiúsculas)
of_clear_headers ( )Esquece todos os cabeçalhos, autenticação incluída
of_set_bearer (string as_token)Authorization: Bearer em cada pedido; um token vazio remove-o
of_set_basic (string as_user, string as_password)Autenticação Basic; a DLL codifica ela própria o base64 — o PowerBuilder 10 não o tem
of_get (string as_url) → longGET. Devolve o estado HTTP, ou -5 URL inválido, -4 falha, -6 recusado em demo
of_post (string as_url, string as_body) → longPOST com um corpo (JSON por defeito, construído com n_pbt_json). Devolve o estado HTTP, ou -5 / -4 / -6
of_put (string as_url, string as_body) → longPUT com um corpo. Devolve o estado HTTP, ou -5 / -4 / -6
of_patch (string as_url, string as_body) → longPATCH com um corpo. Devolve o estado HTTP, ou -5 / -4 / -6
of_delete (string as_url) → longDELETE. Devolve o estado HTTP, ou -5 / -4 / -6
of_request (string as_method, string as_url, string as_body) → longQualquer método (METHOD_*, ou o seu), qualquer corpo enviado em UTF-8: o que os cinco atalhos chamam. Devolve o estado HTTP, ou -5 / -4 / -6
of_download (string as_url, string as_path) → longGET diretamente para um ficheiro, bytes intactos, qualquer que seja o tamanho. Devolve o estado HTTP, ou -5 URL ou caminho vazio, -4 falha, -6 recusado em demo
of_response_text ( ) → stringO corpo da última resposta, em texto (UTF-8 descodificado)
of_response_headers ( ) → stringTodos os cabeçalhos da última resposta, um por linha
of_response_header (string as_name) → stringUm cabeçalho da última resposta, por nome; vazio se não foi enviado
of_json_value (string as_key) → stringUm valor do corpo JSON pela sua chave, a primeira ocorrência a qualquer profundidade. Para mais do que um valor, leia of_response_text e n_pbt_utils.of_json_get_*
of_reset ( )Regresso aos valores por defeito: sem cabeçalhos, sem URL de base, o tempo por defeito, a última resposta esquecida

Exemplos #

Ler uma lista e percorrê-la #

string ls_body
if lnv_rest.of_get("/orders?status=open") = 200 then
	ls_body = lnv_rest.of_response_text()
	// One value : of_json_value. The whole list : n_pbt_utils.of_json_get_payload and
	// of_json_get_str on each object, or your own parser on ls_body.
end if

Transferir um documento #

long ll_status
ll_status = lnv_rest.of_download("/orders/4152/invoice.pdf", "C:\temp\invoice-4152.pdf")
if ll_status = 200 then
	Run("C:\temp\invoice-4152.pdf")
elseif ll_status < 0 then
	MessageBox("Download", lnv_rest.is_last_error)
end if

Uma API que responde com erro #

choose case lnv_rest.of_post("/shipments", ls_body)
	case 200, 201
		// created
	case 401
		MessageBox("API", "Token expired : " + lnv_rest.of_json_value("message"))
	case is < 0
		MessageBox("Network", lnv_rest.is_last_error)
end choose

Assíncrono (sem congelar a interface) #

As chamadas síncronas acima bloqueiam o script (a interface fica viva mas a linha espera). A API assíncrona nem sequer bloqueia o script: o pedido corre num fio de trabalho e a resposta volta mais tarde como evento.

Preparação — nada a ligar: o componente entrega a resposta sozinho em ue_response. of_open / of_close abrem e fecham o cliente (facultativo: o primeiro pedido async abre-o), of_clear_cookies esquece os cookies guardados entre pedidos. Internamente o pump do componente chama of_process_events para distribuir as respostas — nunca o chama.

Enviar — of_request_async(method, url, body), ou os atalhos of_get_async, of_post_async, of_put_async, of_patch_async, of_delete_async, devolvem de imediato um id de pedido. of_download_async(url, path) descarrega para um ficheiro e of_upload(url, field, path) envia um ficheiro como multipart/form-data — ambos com progresso. of_cancel(id) para um pedido em curso. As tentativas (il_max_retries, il_retry_backoff_ms) repetem em 429/503/falha de rede.

Receber — ue_response(al_id, al_status) (ler o corpo com of_response_text(al_id) / of_status(al_id) DENTRO do tratador), ue_failed(al_id, as_error), ue_progress(al_id, al_done, al_total).

MétodoFunção
of_open ( ) → longAbre o cliente assíncrono, um canal de eventos nativo (sem WebView, sem CORS). Facultativo: o primeiro pedido async abre-o. Devolve o id do cliente (> 0), ou um código negativo
of_close ( )Fecha o cliente assíncrono: os seus cookies (a sessão) vão com ele. O próximo pedido async reabre-o. Feito por si por of_reset e na destruição
of_process_events ( )Distribui as respostas assíncronas e levanta ue_response / ue_failed / ue_progress. Pública APENAS porque o pump interno do componente a chama no ciclo PowerBuilder, de poucos em poucos milissegundos enquanto um pedido está em curso — nunca a chama, e não liga nem recetor nem temporizador. Chamá-la você mesmo é inofensivo: só esvazia o que já está à espera
of_clear_cookies ( )Esquece os cookies guardados entre pedidos (um logout). A definição ib_keep_cookies não muda
of_get_async (string as_url) → longGET assíncrono. Devolve de imediato um id de pedido; a resposta chega em ue_response(id, status). Devolve -5 num URL inválido, -2 se o cliente não conseguir abrir
of_post_async (string as_url, string as_body) → longPOST assíncrono com um corpo (JSON por defeito, construído com n_pbt_json). Devolve de imediato um id de pedido; a resposta chega em ue_response. Devolve -5 / -2 como of_get_async
of_put_async (string as_url, string as_body) → longPUT assíncrono com um corpo. Devolve de imediato um id de pedido; a resposta chega em ue_response. Devolve -5 / -2 como of_get_async
of_patch_async (string as_url, string as_body) → longPATCH assíncrono com um corpo. Devolve de imediato um id de pedido; a resposta chega em ue_response. Devolve -5 / -2 como of_get_async
of_delete_async (string as_url) → longDELETE assíncrono. Devolve de imediato um id de pedido; a resposta chega em ue_response. Devolve -5 / -2 como of_get_async
of_request_async (string as_method, string as_url, string as_body) → longPedido assíncrono com o método HTTP à sua escolha (of_get_async e os seus irmãos chamam-no). Devolve de imediato um id de pedido; a resposta chega em ue_response, uma falha em ue_failed. Devolve -2 se o cliente não abrir
of_download_async (string as_url, string as_path) → longGET assíncrono diretamente para um FICHEIRO, com ue_progress pelo caminho. Devolve um id de pedido, -5 com um caminho vazio, -2 se o cliente não abrir
of_upload (string as_url, string as_field, string as_path) → longEnvia um FICHEIRO como multipart/form-data (campo de formulário as_field), de forma assíncrona, com ue_progress. Devolve um id de pedido, -5 com um caminho vazio, -2 se o cliente não abrir, -6 em modo demo
of_cancel (long al_id) → longPede a um pedido em curso que pare; termina com ue_failed(id, "cancelled"). Devolve 0, ou -1 se o id for desconhecido
of_status (long al_id) → longO estado HTTP de uma resposta assíncrona, por id de pedido - a ler DENTRO de ue_response. Devolve o estado (200, 404...), 0 se o pedido for desconhecido ou já esquecido
EventoFunção
ue_response (long al_id, long al_status)Um pedido assíncrono terminou: al_id é o id devolvido no envio, al_status o estado HTTP. Leia o corpo com of_response_text(al_id) DENTRO do handler: o pedido é esquecido à saída do evento
ue_failed (long al_id, string as_error)Um pedido assíncrono falhou: sem rede, tempo esgotado, TLS, ou cancelado por of_cancel (as_error vale então cancelled)
ue_progress (long al_id, long al_done, long al_total)Progresso de uma transferência (of_download_async) ou envio (of_upload) assíncrono: al_done bytes de al_total
// Async : the UI never freezes, and there is nothing to wire.
ll_id = uo_rest.of_get_async("https://api.example.com/orders/4152")

// The answer arrives on its own in the ue_response event of uo_rest :
IF al_status >= 200 AND al_status < 300 THEN
	ls_body = uo_rest.of_response_text(al_id)
END IF

Boas práticas #

← Referência dos componentes · Índice do guia