IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Voroltinquo

[Actualité] [Windev] Exploiter le résultat d'une API.

Noter ce billet
par , 11/12/2023 à 12h42 (3628 Affichages)
Il y a quelque temps, on m'a posé cette question :
"Je dois exploiter le résultats JSON des API suivantes :
1 - https://offline.turfinfo.api.pmu.fr/...amme/24112023/
2 - https://offline.turfinfo.api.pmu.fr/...e/24112023/R1/
3 - https://offline.turfinfo.api.pmu.fr/...4112023/R1/C1/
4 - https://offline.turfinfo.api.pmu.fr/...1/participants
comment dois-je m'y prendre ?"
Dans une premier temps on oublie les variants pour traiter le résultat d'une API, surtout si l'on doit alimenter sa propre BDD. Si, pour une raison ou pour une autre, le format du résultat change, tout ton boulot sera à jeter. Par ailleurs, si le résultat est en binaire, il n'est pas exploitable directement. Enfin, en jetant un oeil sur le résultat du premier lien, on voit que nous avons un JSON de plus de 15000 ligne. Bon courage pour faire exploiter ça avec des boucles.
Il faut penser sérialisation/désérialisation.
1-La sérialisation, qu'est ce c'est ?
La sérialisation, la littérature parle aussi de marshalling, est une opération qui permet de transformer des données structurées qui se trouvent en mémoires (le résultat d'une requête sur un serveur par exemple) en un buffer qui sera transmis sur le réseau ou stocké. Les formats les plus couramment utilisés sont le JSON, le XML et le binaire, mais on n'est pas à l'abri d'un format maison qui devienne un standard.
A l'autre bout du réseau, l'utilisateur devra faire l'opération inverse, la désérialisation, pour obtenir en mémoires des données structurées facilement exploitables.
2- Préparation de la désérialisation
2.1-Exploiter le résultat
Le résultat obtenu correspond à des données structurées reprises, la plupart du temps, dans la doc de l'API. Il arrive toutefois, que ce ne soit pas le cas. Si l'on connaît le XML ou le JSON, on peut retrouver las structures "à la main", mais pour un gros volume de données, cela peut s'avérer fastidieux, voire impossible en cas. Il existe de nombreux outils en ligne qui permettent de nous mâcher le boulot. Dans la suite, je me baserai sur le lien 1 (https://offline.turfinfo.api.pmu.fr/...amme/24112023/) pour illustrer mes propos.
J'utilise l'outils PCSOFT WJSON qui permet d'obtenir les structures, mais aussi les classe utilisées.
2.2-Récupérer les classes ou les structures
En ce qui concerne les structures, un copier/coller fait l'affaire, en ce qui concerne les classes, c'est légèrement plus subtil.
En plaçant le curseur de la souris sur la colonne de droite (la colonne de résultats,) 2 boutons apparaissent :
-le bouton copier (à droite)
-le bouton importer les classes.
L'importation des classes permet de télécharger un .zip qui contient la déclaration des classes en .txt. Pour les incorporer dans le projet, il suffit, dans l'explorateur, de faire un clic droit sur Classe et de sélectionner "Importer des fichiers txt" (la sélection multiple est possible)
2.3-Classe ou structure ?
Désérialise accepte indifféremment les classes ou les structures, quand est-il préférable d'utilser tel ou tel type?
Si c'est du "one shot" et que les manipulation des données sont restreintes e.g. récupération ponctuelle de données il est préférable d'utiliser les structures.
Si ces données doivent êtres stockées et a fortiori, si l'on veut travailler en objet (e.g. alimentation de champs par data binding,) il faut utiliser les classes.
Le WL met à notre disposition 2 attributs d'extension qui vont nous simplifier la vie surtout si l'on ne veut pas utiliser les noms que nous impose le JSON.
2.4-Conventions
2.4.1-Conventions concernant les noms de membre
En ce qui concerne le préfixage, j'utilise les conventions de la charte standard du WL. Un membre est préfixé par m_y ou y est le préfixe du type du membre e.g. m_nMonMembre représente un entier. Toutefois pour les entier sur 8 j'utilise m_pk, pour les chaînes ANSI, m_sa et pour les chaînes UNICODE m_su.(Cela est facilement modifiable dans l'éditeur de charte)
2.4.2-Convention concernant le nom des colonnes
-PK_ : clé primaire
-FK_ : clé étrangère
-NDX_ : Index
-AK_ : clé alternative
-CC_ : clé composée.
2.5-Modification des classes obtenues
2.5.1 Adaptation de la déclaration aux conventions des noms de membre
Je me limiterai à la classe CProgramme.
En étudiant le code
Code windev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
CProgramme est une Classe
    cached est un booléen
    'date' est un numérique
    timezoneOffset est un numérique
    reunions est un tableau de Creunions
    datesProgrammesDisponibles est un tableau de chaînes
    prochainesCoursesAPartir est un tableau de chaînes // Tableau vide, type indéfini
FIN
On voit qu'il ne correspond pas aux conventions de nommage des membres qu'à cela ne tienne, on va transformer le code pour pouvoir récupérer les données tout en utilisant les conventions. il faut pour cela utiliser l'attribut d'extension Sérialise :
Code Windev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
CProgramme est une Classe
    m_bCached est un booléen <Sérialise="cached"> //Attention à la casse
    m_pkDate est entier sur 8 <Sérialise="date">    //Format TimeStamp Bon candidat pour une PK
    m_xTimeZoneOffset est un entier <Sérialise="timezoneOffset">
    m_tabReunions est un tableau <Sérialise="reunion"> de Creunions //Attention à la place de l'attribut
    m_tabDatesProgrammesDisponibles est un tableau <Sérialise="datesProgrammesDisponibles"> de chaîne //Chaînes au format JJMMAAAA
    m_tabProchainesCoursesAPartir est un tableau <Sérialise="prochainesCoursesAPartir">de chaînes // Tableau vide, type indéfini
FIN

2.5.2-De la classe vers la table
On a la structure qui va recevoir le JSON en mémoire. Une fois les données récupérées, on peut déjà les utiliser telle quelle en liant les champs de notre fenêtre aux membres d'une variable de type classe, globale au minimum à cette fenêtre.
Toutefois, si l'on veut conserver les données récupérées, il va falloir créer des tables capables de récupérer ces données.
Certains AGL (e.g. AMC Designor) font cela automatiquement. Cela n'est pas le cas de windev. Cela n'a jamais été la grande histoire d'amour entre windev et la POO. On va donc devoir tout se taper à la main.

La méthode est simple
*-Chaque classe correspond à une table.
*-On ne conserve que les données atomiques (i.e. non structurées)
*-On cherche un candidat à la PK. S'il n'y en a pas, on en crée un. Rien de neuf par rapport à une création "classique"
On obtient donc la table suivante :
Nom : 2023-12-03_16h15_23.png
Affichages : 719
Taille : 3,1 Ko

Remarque : Le 12/02/2051 aura-t-on besoin de savoir que le 01/12/2023 on pouvait avoir les programmes jusqu'au 07/12/2023 ? En français, La colonne DateProgrammesDisponnibles est elle vraiment utile ? C'est une chose à voir avec le pilote pour modifier les règles de gestion. Pour des raisons didactiques nous dirons que cette colonne n'est pas utile.

Une nouvelle question se pose à nous : Que fait-on des données structurées ?
Ces données vont se transformer en liaison entre 2 tables :
- *,1 pour les structures simples e.g. Réunions->Hippodromme
- *,n pour les tableau de structures e.g. Programme->Réunions
Là encore, si dans la table secondaire on a un candidat pour devenir FK (e.g. DateRéunion dans Réunions) on l'utilise, sinon on crée notre FK ex nihilo.
Nos tables sont modélisées nous pouvons passer à l'étape suivante.
Voici un extrait du MLD.
Nom : 2023-12-05_17h30_29.png
Affichages : 276
Taille : 11,1 Ko

2.5.3-Adaptation de la déclaration aux conventions des noms de colonnes
Tout comme nous avons l'attribut sérialise pour passer du résultat d'une API à l'instance d'une classe, il existe un attribut pour récupérer sans douleurs les données de l'instance d'une classe dans une table, cet attribut s'appelle mapping.
La déclaration de la classe devient alors :
Code windev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
CProgramme est une Classe <MAPPING=Programme>
<MAPPING>
    m_bCached est un booléen <Sérialise="cached",mapping=Cached>    //Attention à la casse
    m_pkDate est un entier sur 8 octets <Sérialise="date",mapping=PK_Date,clé unique>
    m_nTimeZoneOffset est un entier <Sérialise="timezoneOffset",mapping=TimeZoneOffset>
<FIN>
    //m_tabReunions et m_tabProchainesCoursesAPartir ne sont pas atomiques donc pas dans la table, mapping inutile
    m_tabReunions est un tableau <Sérialise="reunions"> de CReunions //Attention à la place de l'attribut
    m_tabProchainesCoursesAPartir est un tableau <Sérialise="prochainesCoursesAPartir">de CCourses
    //m_tabDatesProgrammesDisponibles n'est pas dans la table, mapping inutile
    m_tabDatesProgrammesDisponibles est un tableau <Sérialise="datesProgrammesDisponibles"> de chaînes
FIN

PRIVE ou pas ?
C'est toujours la grande question. Les puristes diront :"Ce sont des classes donc les membres sont au minimum PROTEGE". Ils ont raison, SI on va manipuler nos classes via la POO et si on va les partager.
Si les classes créées ne servent que de réceptacle, ce n'est pas vraiment utile.

Nos classes sont maintenant prêtes à recevoir le résultat de l'API.

3-Récupération des données
Le code est simple (enfin presque.)
3.1-Code principal
Code Windev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
 
clRésultats est CResult
 
//Récupérer les données
clRésultats:LireDepuisAPI("https://offline.turfinfo.api.pmu.fr/rest/client/7/programme/24112023/")
 
//Au besoin sauvegarde des données récupérées
clResultats:Sauver()
Avec :
Code Windev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
 
PROCEDURE RécupérerRésultats(saURL est chaîne)
oMaRequête    est un httpRequête
oMaRéponse    est un httpRéponse
 
oMaRequête.URL    = saURL
oMaRéponse        = HTTPEnvoie(oMaRequête)
 
Désérialise(objet,oMaRéponse..Contenu,psdJSON)

3.2-Sauvegarde des instances de classe
3.2.1-Principe
*-Récupération des données atomiques via MémoireVersFichier
*-Récupération éventuelle des valeurs des FK (si la PK associée a été crée ex nihilo)
*-Sauvegarde des instances contenues dans l'instance en cours (e.g. sauvegarde des réunions d'un programme) cf 3.2.1
3.2.2-Application à notre cas
Sauver (CProgramme)
Code Windev : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PROCÉDURE Sauver()
clUneRéunion est CReunions

//Sauvegarde des données atomiques
MémoireVersFichier(objet,Programme)
//Je n'utilise pas HEnregistre car la fonction ne déclenche pas les triggers
SI PAS HLitRecherchePremier(Programme,PK_Date,:m_pkDate) ALORS
    HAjoute(Programme)
SINON
    HModifie(Programme)
FIN

//Sauvegarde des structures
POUR TOUT clUneRéunion DE :m_tabReunions
    clUneRéunion:Sauver()
FIN

//etc

Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog Viadeo Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog Twitter Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog Google Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog Facebook Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog Digg Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog Delicious Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog MySpace Envoyer le billet « [Windev] Exploiter le résultat d'une API. » dans le blog Yahoo

Commentaires