JPO : Webinar d'information sur nos formations → RDV mardi à 17h30.

Construire des API avec Python, Flask, Swagger, Connexion et SQLAlchemy (Deuxième partie)

Flask Python flutter API

Nous avons vu dans les quatre précédents articles un premier exemple de programmation d’une API Web sous Flask.

Comment connecter une API Web à une base de donnée SQLite.

Comment programmer et documenter une API Web avec Python, Flask, Swagger et Connexion.

et nous avons introduit les outils permettant de combiner ces éléments avec la gestion d’une base de données, à savoir SQLAlchemy et Marshmallow.

Dans ce cinquième et dernier article, nous allons mettre à jour notre API en utilisant les connaissances acquises précédemment.

Mise à jour de l’API

Les changements qu’on a effectué jusqu’ici par rapport à la première version de notre API (annuaire interactif) ne sont pas radicaux.

On modifie simplement les définitions d’URL pour prendre ne compte le fait que la clef primaires est person_id :

  • Action : Create, Verbe HTTP : POST, URL : /api/people, Description : définit une URL pour créer une personne.
  • Action : Read, Verbe HTTP : GET, URL : /api/people, Description : définit une URL pour lire une collection de personnes.
  • Action : Read, Verbe HTTP : GET, URL : /api/people/{person_id}, Description : Définit une URL pour lire une personne particulière identifiée par son person_id.
  • Action : Update, Verbe HTTP : PUT, URL : /api/people/ {person_id}, Description : Définit une URL pour mettre à jour l’information d’une personne identifiée par son person_id.
  • Action : Delete, Verbe HTTP : DELETE, URL : /api/people/ {person_id}, Description : Définit un URL pour supprimer une personne identifiée par son person_id.


Alors que la première définition de l’API faisait appel à lname pour identifier une personne, celle-ci fait appel à person_id.

Cela permet d’autoriser l’utilisateur à modifier le nom de famille lors de la mise à jour de l’information d’une personne.

Afin d’implémenter ces changements, il faut éditer le fichier swagger.yml configurant l’API.

Le fichier modifié est accessible sur Github :

https://github.com/salimlardjane1/api2/blob/main/swagger.yml 

Pour l’essentiel, on remplace partout lname par person_id et on rajoute person_id aux réponses POST et PUT.

 

Mise à jour des gestionnaires

Après avoir mis à jour le fichier swagger.yml de façon à prendre en compte l’identifiant person_id, il faut mettre à jour les fonctions correspondantes (appelées Gestionnaires, ang. Handlers) du fichier people.py pour prendre en compte ces changements.

De façon analogue à ce qu’on a fait pour swagger.yml, cela consiste essentiellement à remplacer lname par person_id.

Voici in extrait du nouveau module people.py montrant le gestionnaire (handler) associé à la requête GET /api/people :

Le module complet est disponible sur Github :

https://github.com/salimlardjane1/api2/blob/main/people.py

Les lignes 1 à 9 importent des modules Flask pour créer les réponses de l’API, ainsi que l’instance db du module config.py. De plus, elles importent les classes SQLAlchemy Person et Marshmallow PersonSchema qui permettent d’accéder à la base de données et de sérialiser les résultats.

La ligne 11 correspond au début de la définition du gestionnaire read_all( ) qui se charge de la requête GET / api/people et renvoie tous les enregistrements de la table person triés par ordre alphabétique du nom de famille.

Les lignes 17 à 19 demandent à SQLAlchemy de requêter la table person pour obtenir l’ensemble des enregistrements, de les trier par ordre croissant du nom de famille et de stocker la liste correspondante d’objets Python Person dans la variable people.

La ligne 21 crée une instance de la classe Marshmallow PersonSchema en lui passant le paramètre many = True. Ceci autorise l’instance à manipuler un itérable (ici une liste) à sérialiser.

La ligne 22 utilise l’instance person_schema en appelant sa méthode dump( ) avec comme argument la liste people. Le résultat est un objet possédant un attribut data contenant la liste people, qui peut être converti en JSON.

La conversion est effectuée par Connexion en réponse à la requête de l’API.

Notons qu’on a dû passer par Marshmallow, car la liste people ne peut être convertie directement en JSON par Connexion, qui ne sait pas convertir le champ« timestamp » (objet datetime).

Voici un autre extrait du module people.py, qui contient le gestionnaire pour la requête de lecture des informations d’une personne particulière dans la table person : GET / api/people/{person_id}.

La fonction read_one(person_id) ci-après reçoit un person_id de l’URL de requête, indiquant que l’utilisateur cherche une personne en particulier :

 

Les lignes 9 à 11 utilisent le paramètre person_id dans une requête SQLAlchemy en utilisant la méthode filter de l’objet requête pour rechercher une personne ayant le person_id spécifié. Plutôt que d’utiliser la méthode de requête all( ), on utilise la méthode one_or_none( ) pour obtenir les informations d’une personne ou renvoyer None si aucune personne n’a été trouvée.

La ligne 13 détermine si une personne a été trouvée ou pas.

La ligne 15 illustre le fait que si person n’est pas None (i.e. si une personne a été trouvée) alors la sérialisation des données est un peu différente. On ne spécifie pas many = True lors de la création de l’instance PersonSchema. On laisse many = False (valeur par défaut) car il y a un seul objet à sérialiser.

La ligne 16 fait appel à la méthode dump de person_schema et l’attribut data de l’objet résultant est renvoyé.

La ligne 19 utilise la méthode Flask abort( ) pour renvoyer un message d’erreur si person vaut None (aucune personne n’a été trouvée).

Le module people.py doit également être modifié pour ce qui est de la création de nouvelles personnes dans la base de données :

On utilise la classe Marshmallow PersonSchema pour désérialiser une structure JSON envoyée avec la requête HTTP afin d’obtenir un objet SQLAlchemy Person.

Les lignes 9 et 10 définissent les variables fname et lname à partir de la structure Person passée dans le corps de la requête HTTP POST.

Les lignes 12 à 15 utilisent la classe SQLAlchemy Person pour requêter la base sur l’existence d’une personne de nom et prénom de même valeur que lname et fname.

La ligne 18 vérifie si existing_person vaut None (la personne n’a pas été trouvée).

La ligne 21 crée une instance de PersonSchema nommée schema.

La ligne 22 utilise la variable schema pour charger les données contenues dans les variables paramètres de person et créer une nouvelle instance de la classe SQLAlchemy Person appelée new_person.

La ligne 25 ajoute l’instance new_person db.session.

La ligne 26 enregistre l’instance new_person dans la base de données, ce qui a pour effet de lui assigner un identifiant (compteur entier auto-incrémenté) et un « timestamp ».

La ligne 33 utilise la méthode Flask abort( ) pour renvoyer un message d’erreur si existing_person ne vaut pas None, c’est-à-dire si la personne existe déjà dans la base de données.

Mise à jour de l’UI Swagger

Les modifications précédentes ayant été effectuées, notre nouvelle API est fonctionnelle.

Ces modifications sont reflétées par l’interface Swagger associée à l’API.

Voici à quoi ressemble à présent cette dernière :

API rest swagger fichier

Le paramètre de chemin lname a été remplacé par person_id qui est la clef primaire de la base de données.

Les modifications apportées à l’UI sont les résultats combinés des modifications apportées au fichier swagger.yml et des modifications correspondantes du code.

C’est ici que s’achève cette série d’articles autour de la programmation d’API Web avec Python. 

Pour aller plus loin, on pourra consulter les articles, en anglais, de Doug Farrell :

https://realpython.com/flask-connexion-rest-api-part-3/ 

et

https://realpython.com/flask-connexion-rest-api-part-4/ 

Merci pour votre attention !

4. Bibliographie

Facebook
Twitter
LinkedIn

Tag de l'article :

Vous souhaitez être alerté des nouveaux contenus en data science et intelligence artificielle ?

Laissez-nous votre e-mail, pour que nous puissions vous envoyer vos nouveaux articles au moment de leur publication !

Newsletter icone

S'inscrire à la JPO :

Vous souhaitez recevoir notre newsletter data 💌 hebdomadaire ?