Client HTTP
Source: tutorial/05_http_client See in Playground
Récupère un article depuis une API publique de test (jsonplaceholder.typicode.com ), re-sérialise son corps JSON, et l’écrit dans un fichier.
Exécution
cd tutorial/05_http_client
melodium run Compo.toml --post_id 1L’URL de la requête est construite à partir de post_id avec |format. L’exemple journalise la fin de la requête, et distingue séparément un échec technique (DNS, connexion, dépassement de délai) d’un corps qui échoue à l’analyse, avant d’écrire le corps JSON analysé puis re-sérialisé dans post.txt.
Optionnel : ajoutez --api-report et un jeton d’API (MELODIUM_API_TOKEN) pour voir la trace complète de cette exécution sur Cadence.CI .
Fonctionnement
Cet exemple n’utilise aucun modèle : get n’a besoin d’aucun modèle de client pour une requête ponctuelle. Un modèle HttpClient à connexion réutilisable est employé à la place dans d’autres exemples, dès qu’une connexion doit rester ouverte entre plusieurs requêtes.
Flux de données
Déclenchement de la requête
get(url=...) se déclenche sur startup.trigger et diffuse le corps de la réponse via data, indépendamment de status/completed/failed/error, qui se déclenchent chacun une seule fois. L’URL est construite avec |format, appelée directement comme une valeur, sans port ni connexion :
fetch: get(url=|format("https://jsonplaceholder.typicode.com/posts/{id}", |map([|entry("id", post_id)])))
startup.trigger -> fetch.trigger
logOk: logInfoMessage(label="http", message="request completed")
fetch.completed -> logOk.triggerÉchec technique et échec applicatif
fetch.failed/fetch.error se déclenchent quand la requête elle-même n’a pas pu aboutir : problème de DNS, de connexion, ou de délai dépassé. Une réponse qui arrive avec succès mais dont le contenu n’est pas du JSON valide relève d’un tout autre mode d’échec, traité plus loin lorsque l’Option de toJson revient à none. Les deux ne doivent pas être confondus :
netFailed: logErrorMessage(label="http", message="request failed technically")
netError: logError(label="http")
fetch.failed -> netFailed.trigger
fetch.error -> netError.messageDécodage et re-sérialisation du corps
Le corps brut, en octets, est transformé en Stream<string> avec decode, analysé avec toJson, extrait avec unwrapOr, puis re-sérialisé. Cet aller-retour est un bon moyen de confirmer qu’une réponse est bien du JSON valide sans en changer le sens :
decode: decode()
fetch.data -> decode.data
parsed: toJson()
body: unwrapOr<Json>(default=|null())
asText: toString<Json>()
write: writeTextLocal(path=output)
logDone: logInfoMessage(label="http", message="response written to file")
decode.text -> parsed.text,json -> body.option,value -> asText.value,into -> write.text
write.finished -> logDone.triggerDépendances
[dependencies]
std = "0.10.3" # flux de base, journalisation, structures de données
http = "0.10.3" # client et serveur HTTP
json = "0.10.3" # analyse et sérialisation JSON
encoding = "0.10.3" # encodage/décodage UTF-8
fs = "0.10.3" # lecture/écriture de fichiers locaux