21
Introduction à FastAPI (Python) : Partie 3
Voici une série d'articles qui vous permettra de créer une API en Python avec FastAPI.
Je vais publier un nouvel article régulièrement et petit à petit vous apprendrez tout ce qu'il y a à savoir sur FastAPI
Pour ne rien manquer suivez-moi sur twitter : https://twitter.com/EricLeCodeur
Jusqu’à présent nous avons couvert le READ du CRUD, voyons maintenant le "Create".
Ici il ne s'agit plus de lire des données mais d'en créer une nouvelle.
Pour créer un nouveau produit nous devons envoyer de l'information au serveur, et pour ce faire nous aurons besoin d'utiliser l'action HTTP POST
POST www.example.com/products
L'action POST permet d'envoyer des données du navigateur vers le serveur.
Nous allons faire un exemple et ajouter le produit "MacBook" à notre liste de produit existant.
Voici le résultat visé :
products = [
{"id": 1, "name": "iPad", "price": 599},
{"id": 2, "name": "iPhone", "price": 999},
{"id": 3, "name": "iWatch", "price": 699},
{"id": 4, "name": "MacBook", "price": 1299},
]
Pour faire un POST avec FastAPI voici le code que vous devez utiliser
@app.post("/products")
def create_product(product: dict, response: Response):
product["id"] = len(products) + 1
products.append(product)
response.status_code = 201
return product
Reprenons ce code ligne par ligne:
@app.post("/products")
Ce code permet de spécifier à FastAPI que cette requête sera une action POST "/products"
def create_product(product: dict, response: Response):
Ce code permet de définir la fonction qui sera lancée lorsque le serveur va recevoir la requête "POST /products"
La fonction contient deux paramètres, un pour le produit et l'autre pour une référence à l'objet réponse.
À noter que lorsque l'on fait une action POST les données à envoyer devront être inclus dans le body de la requête et devront l'être en format texte JSON.
Dans cet exemple on voit toute la puissance et facilité de FastAPI. FastAPI sait qu'il s'agit d'une requête POST, Il va donc automatiquement prendre le JSON qui se trouve dans le body de la requête, le convertir en dictionnaire Python et placer le résultat dans le premier paramètre (product).
Nous pouvons donc ensuite utiliser ce paramètre "product" pour ajouter le produit à notre liste de produit.
product["id"] = len(products) + 1
products.append(product)
Une fois que le produit a été ajouté avec succès, il faut retourner le code d'état approprié.
response.status_code = 201
Ce code permet de retourner le code d'état 201 (Created). Qui indique que le produit est bel et bien créé avec succès.
Enfin, par convention le nouveau produit est toujours retourné avec la réponse.
return product
Les navigateurs web ne permettent pas de lancer une requête POST. Donc il ne sera pas possible de tester ce nouvel API à partir du navigateur.
Nous avons un premier API, nous devons maintenant le tester.
Les navigateurs web ne permettent pas de lancer une requête POST. Donc il ne sera pas possible de tester ce nouvel API à partir du navigateur.
Il existe plusieurs autres façons de le faire. Nous pourrions utiliser un logiciel comme Postman et tester nos requêtes à partir de Postman.
Un des avantages de FastAPI c'est qui produit automatiquement la documentation de notre API. Cette documentation permet aux usagers de comprendre comment utiliser notre API, quels sont les chemins URL disponible et également de lancer des requêtes.
Nous allons donc pouvoir utiliser la documentation afin de tester notre API
Comme mentionné, dans le cas de notre API la documentation est créée automatiquement. Pour la consulter, lancer le serveur
$ uvicorn first-api:app --reload
Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
et visiter /docs :
http://127.0.0.1:8000/docs
La documentation va s'afficher à l'écran !
Pour tester un chemin URL c'est très simple, il suffit de cliquer sur le nom du chemin et FastAPI dévoilera une interface permettant de tester ce chemin.
Par exemple si vous cliquez sur POST/products vous verrez apparaître
Vous pouvez ensuite cliquer sur "Try it out", saisir les données à ajouter dans la section "Request body" (voir exemple ici bas)
Les données sont en format texte JSON
{"name": "MacBook", "price": 1299}
Enfin appuyer sur "Execute", la doc envoyer la requête POST à votre serveur FastAPI
Le code d'état de la réponse ainsi que la réponse en tant que tel seront également affichés dans la page.
Cette documentation automatique est encore une autre belle démonstration de la puissance et facilité de FastAPI.
Si vous désirez, vous pouvez cliquer sur tous les chemins un après l'autre afin de les tester.
Reprenons le dernier exemple que nous avons créé
@app.post("/products")
def create_product(product: dict, response: Response):
product["id"] = len(products) + 1
products.append(product)
response.status_code = 201
return product
La fonction @app.post() fonctionne mais comporte plusieurs lacunes. En fait, il n'y a aucune validation et aucun message d'erreur n'est retourné si cette validation ne passe pas.
Par exemple, pour créer un nouveau produit nous avons besoin du "name" et "price". Que se passe-t-il si seulement le "name" est envoyé mais pas le "price" ?
Ou bien que se passe-t-il si le "price" n'est pas un format numérique.
Je pourrais vous donner encore plusieurs exemples mais je crois que vous comprenez le concept.
Pour faire ces validations et retourner les messages d'erreurs associées, il faudrait ajouter pas mal de code à notre fonction. Et il faudrait répéter ce code pour chaque action et chaque ressource. Le tout viendrait compliquer de beaucoup notre application.
Heureusement que FastAPI porte bien son nom soit "Fast" API. Il existe donc une façon très simple d'implanter un système de validation automatique. Ce système ce sont les schémas !
Les schémas sont des modèles de données qui servent à FastAPI pour valider nos fonctions.
Par exemple nous pourrions définir un schéma comme celui-ci:
from pydantic import BaseModel
class Product(BaseModel):
name: str
price: float
Ce modèle de donnée est très simple à comprendre. Nous avons une entité "Product" qui contient les attributs "name" et "price". Nous pouvons même définir de quel type sont les attributs.
Une fois que nous avons défini notre modèle de donné, nous pouvons modifier notre fonction @app.post()
@app.post ("/products")
def create_product(new_product: Product, response: Response):
product = new_product.dict()
product["id"] = len(products) + 1
products.append(product)
response.status_code = 201
return product
Nous avons remplacé le paramètre de type "dict" par un paramètre de type "Product".
Une fois cette modification faite, si vous testez cette fonction, vous verrez que FastAPI applique maintenant la validation automatique et retournera une erreur si ce que vous envoyez ne respecte pas le modèle "Product'
L'action PUT permet de modifier une ressource existante. Comme l'action POST, il faut envoyer les données à modifier avec la requête.
Voici un exemple d'une fonction PUT
@app.put("/products/{id}")
def edit_product(id: int, edited_product: Product, response: Response):
for product in products:
if product["id"] == id:
product['name'] = edited_product.name
product['price'] = edited_product.price
response.status_code = 200
return product
else:
response.status_code = 404
return "Product Not found"
Ici il n’y a rien de vraiment nouveau. C'est exactement les mêmes concepts que nous avons découverts un peu plus tôt.
L'action DELETE permet de supprimer une ressource. Voici le code qui permet d'implanter cette action
@app.delete("/products/{id}")
def destroy_product(id: int, response: Response):
for product in products:
if product["id"] == id:
products.remove(product)
response.status_code = 204
return "Product Deleted"
else:
response.status_code = 404
return "Product Not found"
Le code que vous venez de créer pour implémenter le CRUD est bien beau mais il manque tout même une notion importante et c'est de relier la ressource avec une base de données. La prochaine section va justement vous expliquer comment faire étape par étape.
C'est tout pour aujourd'hui, suivez-moi sur twitter : https://twitter.com/EricLeCodeur afin d'être avisé de la parution du prochain article.
21