PBToolboxAI v3 ← Site

restclient — n_pbt_restclient #

← Référence des composants · Sommaire du guide

Un client HTTPS pour PowerBuilder, la version 10 comprise : GET, POST, PUT, PATCH, DELETE, les en-têtes, un corps JSON, le téléchargement d'un fichier. Natif — le TLS, le proxy et la décompression du système, et aucun mur CORS, parce que la requête ne part pas d'une page.

▶ Le voir en vrai — Application de démonstration, tuile REST client : les réponses, le code qui les obtient et cette page, côte à côte (connexion Internet requise).


En bref #

Objet non visueln_pbt_restclient
Sert àAppeler une API REST depuis une application PowerBuilder : lire, créer, mettre à jour, télécharger
PrincipeUne requête est un appel qui rend le statut HTTP ; la réponse attend dans l'objet, lue par of_response_text ou of_json_value
DépendanceWinHTTP, dans la DLL de la bibliothèque — aucune page, aucun runtime supplémentaire

Démarrage rapide #

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

Chaque méthode HTTP rend le statut que le serveur a choisi — un 404 est une réponse, pas une erreur — ou un code négatif quand la requête n'a pas abouti : -5 URL invalide, -4 échec (pas de réseau, nom inconnu, délai dépassé, TLS ; is_last_error dit lequel), -6 refusé en mode démo.


Pourquoi natif, et pas la page #

Un fetch() lancé depuis une page de la bibliothèque est soumis à CORS : toute API qui n'envoie pas Access-Control-Allow-Origin lui est fermée, et les API d'entreprise ne l'envoient pas. La requête part donc de la DLL, par WinHTTP : le TLS du système et ses certificats, le proxy configuré, gzip. Ce que vous perdez : rien ; ce que vous gagnez : toutes les API.


Propriétés #

PropriétéTypeDéfautRôle
is_base_urlstring""Mis devant une URL relative : is_base_url = "https://api.example.com" puis of_get("/orders/4152"). Une URL absolue est prise telle quelle
il_timeout_mslong30000Durée maximale d'une requête, connexion et réponse comprises. Au-delà : -4 et « timed out »
is_last_errorstring""Pourquoi la dernière requête a rendu un code négatif. Vide après une requête arrivée au serveur — un 404 n'est pas une erreur
il_statuslong0Le statut HTTP de la dernière requête, ou son code négatif ; la valeur que la requête a rendue

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


Méthodes #

MéthodeRôle
of_set_header (string as_name, string as_value)Un en-tête envoyé avec chaque requête désormais ; un nom déjà posé est remplacé. Content-Type est ajouté seul quand un corps part sans lui (JSON, UTF-8)
of_remove_header (string as_name)Oublie un en-tête, par nom (la casse est indifférente)
of_clear_headers ( )Oublie tous les en-têtes, l'authentification comprise
of_set_bearer (string as_token)Authorization: Bearer sur chaque requête ; un jeton vide le retire
of_set_basic (string as_user, string as_password)Authentification Basic ; la DLL encode elle-même le base64 — PowerBuilder 10 n'en a pas
of_get (string as_url) → longGET. Rend le statut HTTP, ou -5 URL invalide, -4 échec, -6 refusé en démo
of_post (string as_url, string as_body) → longPOST avec un corps (JSON par défaut, construit avec n_pbt_json). Rend le statut HTTP, ou -5 / -4 / -6
of_put (string as_url, string as_body) → longPUT avec un corps. Rend le statut HTTP, ou -5 / -4 / -6
of_patch (string as_url, string as_body) → longPATCH avec un corps. Rend le statut HTTP, ou -5 / -4 / -6
of_delete (string as_url) → longDELETE. Rend le statut HTTP, ou -5 / -4 / -6
of_request (string as_method, string as_url, string as_body) → longN'importe quelle méthode (METHOD_*, ou la vôtre), n'importe quel corps envoyé en UTF-8 : ce que les cinq raccourcis appellent. Rend le statut HTTP, ou -5 / -4 / -6
of_download (string as_url, string as_path) → longGET directement dans un fichier, octets intacts, quelle que soit la taille. Rend le statut HTTP, ou -5 URL ou chemin vide, -4 échec, -6 refusé en démo
of_response_text ( ) → stringLe corps de la dernière réponse, en texte (UTF-8 décodé)
of_response_headers ( ) → stringTous les en-têtes de la dernière réponse, un par ligne
of_response_header (string as_name) → stringUn en-tête de la dernière réponse, par nom ; vide s'il n'a pas été envoyé
of_json_value (string as_key) → stringUne valeur du corps JSON par sa clé, la première occurrence à n'importe quelle profondeur. Pour plus d'une valeur, lisez of_response_text et n_pbt_utils.of_json_get_*
of_reset ( )Retour aux valeurs par défaut : plus d'en-tête, plus d'URL de base, le délai par défaut, la dernière réponse oubliée

Exemples #

Lire une liste et la parcourir #

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

Télécharger un document #

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

Une API qui répond en erreur #

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

Asynchrone (sans gel de l'interface) #

Les appels synchrones ci-dessus bloquent le script (l'interface reste vivante mais la ligne attend). L'API asynchrone ne bloque même plus le script : la requête part sur un fil de travail et sa réponse revient plus tard en événement.

Mise en place — rien à câbler : le composant livre la réponse tout seul dans ue_response. of_open / of_close ouvrent et ferment le client (facultatif : le premier appel async l'ouvre), of_clear_cookies oublie les cookies gardés d'une requête à l'autre. En interne, un pump du composant appelle of_process_events pour drainer les réponses — vous ne l'appelez jamais.

Envoyer — of_request_async(method, url, body), ou les raccourcis of_get_async, of_post_async, of_put_async, of_patch_async, of_delete_async, rendent aussitôt un id de requête. of_download_async(url, path) télécharge vers un fichier et of_upload(url, field, path) téléverse un fichier en multipart/form-data — les deux avec progression. of_cancel(id) arrête une requête en vol. Les tentatives (il_max_retries, il_retry_backoff_ms) rejouent sur 429/503/panne réseau.

Recevoir — ue_response(al_id, al_status) (lire le corps avec of_response_text(al_id) / of_status(al_id) DANS le gestionnaire), ue_failed(al_id, as_error), ue_progress(al_id, al_done, al_total).

MéthodeRôle
of_open ( ) → longOuvre le client asynchrone, un canal d'événements natif (pas de WebView, pas de CORS). Facultatif : le premier appel async l'ouvre. Rend l'identifiant du client (> 0), ou un code négatif
of_close ( )Ferme le client asynchrone : ses cookies (la session) partent avec lui. Le prochain appel async le rouvre. Fait pour vous par of_reset et à la destruction
of_process_events ( )Draine les réponses asynchrones et lève ue_response / ue_failed / ue_progress. Publique UNIQUEMENT parce que le pump interne du composant l'appelle sur la boucle PowerBuilder, toutes les quelques millisecondes tant qu'une requête est en vol — vous ne l'appelez jamais, et vous ne câblez ni récepteur ni timer. L'appeler vous-même est sans danger : elle ne vide que ce qui attend déjà
of_clear_cookies ( )Oublie les cookies gardés d'une requête à l'autre (une déconnexion). Le réglage ib_keep_cookies ne change pas
of_get_async (string as_url) → longGET asynchrone. Rend aussitôt un id de requête ; la réponse arrive dans ue_response(id, status). Rend -5 sur une URL invalide, -2 si le client ne peut pas s'ouvrir
of_post_async (string as_url, string as_body) → longPOST asynchrone avec un corps (JSON par défaut, construit avec n_pbt_json). Rend aussitôt un id de requête ; la réponse arrive dans ue_response. Rend -5 / -2 comme of_get_async
of_put_async (string as_url, string as_body) → longPUT asynchrone avec un corps. Rend aussitôt un id de requête ; la réponse arrive dans ue_response. Rend -5 / -2 comme of_get_async
of_patch_async (string as_url, string as_body) → longPATCH asynchrone avec un corps. Rend aussitôt un id de requête ; la réponse arrive dans ue_response. Rend -5 / -2 comme of_get_async
of_delete_async (string as_url) → longDELETE asynchrone. Rend aussitôt un id de requête ; la réponse arrive dans ue_response. Rend -5 / -2 comme of_get_async
of_request_async (string as_method, string as_url, string as_body) → longEnvoi asynchrone avec la méthode HTTP de votre choix (of_get_async et ses frères l'appellent). Rend aussitôt un id de requête ; la réponse arrive dans ue_response, l'échec dans ue_failed. Rend -2 si le client ne s'ouvre pas
of_download_async (string as_url, string as_path) → longGET asynchrone directement dans un FICHIER, ue_progress en chemin. Rend un id de requête, -5 sur un chemin vide, -2 si le client ne s'ouvre pas
of_upload (string as_url, string as_field, string as_path) → longEnvoie un FICHIER en multipart/form-data (champ de formulaire as_field), en asynchrone, avec ue_progress. Rend un id de requête, -5 sur un chemin vide, -2 si le client ne s'ouvre pas, -6 en mode démo
of_cancel (long al_id) → longDemande à une requête en vol de s'arrêter ; elle se termine par ue_failed(id, "cancelled"). Rend 0, ou -1 si l'id est inconnu
of_status (long al_id) → longLe statut HTTP d'une réponse asynchrone, par id de requête - à lire DANS ue_response. Rend le statut (200, 404...), 0 si la requête est inconnue ou déjà oubliée
ÉvénementRôle
ue_response (long al_id, long al_status)Une requête asynchrone a abouti : al_id est l'id rendu à l'envoi, al_status le statut HTTP. Lire le corps avec of_response_text(al_id) DANS le gestionnaire : la requête est oubliée à la sortie de l'événement
ue_failed (long al_id, string as_error)Une requête asynchrone a échoué : pas de réseau, délai dépassé, TLS, ou annulée par of_cancel (as_error vaut alors cancelled)
ue_progress (long al_id, long al_done, long al_total)Avancement d'un téléchargement (of_download_async) ou d'un envoi (of_upload) asynchrone : al_done octets sur 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

Bonnes pratiques #

← Référence des composants · Sommaire du guide