FastAPI : le nouveau framework web pour vos API avec Python

Il y a depuis longtemps deux frameworks web bien implantés dans le monde Python : Django et Flask. Il y a des pros et des cons à chacun de ces frameworks, Django étant souvent présenté comme plus complet mais plus difficile à prendre en main, Flask comme étant plus simple pour déployer rapidement une API.

Depuis quelques mois, on entend de plus en plus parler d'un nouveau framework: FastAPI. Par exemple, JetBrains conduit tous les ans une enquête auprès de développeur.se.s Python et FastAPI a fait une entrée remarquée en 2020 :

FastAPI was introduced to the options for the first time with this iteration of the survey, and it appears to be the third most popular web framework for Python.

Ce framework se veut moderne, rapide, prêt au déploiement. Voyons voir ça !

Installation

L'installation se fait bien évidemment avec pip :

pip install fastapi[all]

Petit truc exotique quand même : des crochets dans le nom du paquet. Histoire de mettre un peu de paillettes dans la vie des développeurs.

Notez qu'uvicorn sera installé en même temps. Il nous servira de serveur pour nos exemples.

hello, world

Dans un dossier myapi, on crée un fichier main.py :

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "hello, world"}

Ce code est très simple à comprendre. On crée une instance de FastAPI nommée app, puis on ajoute une route vers la racine avec une opération GET, grâce une élégante syntaxe à base d'annotations.

On lance un serveur pour exposer notre API :

$> cd myapi
$> uvicorn main:app --reload
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [1972] using watchgod
INFO:     Started server process [16100]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

On utilise ici uvicorn comme serveur. On lui demande d'utiliser le module Python main (il faut donc exécuter la commande depuis le dossier où se trouve notre fichier main.py) et y chercher l'instance app de FastAPI.

On ouvre l'adresse indiquée dans un navigateur :

L'option --reload demande à uvicorn de recharger le site au fur et à mesure que le fichier main.py est modifié, sans avoir besoin de redémarrer l'application.

Pour tester cette fonctionnalité, on ajoute une nouvelle route /about dans à notre API :

@app.get('/about')
async def about():
    return {"about": "This is my first api with FastAPI"}

Les logs de uvicorn montrent que les changements sont bien détectés et chargés :

WARNING:  WatchGodReload detected file change in '['C:\\myapi\\main.py']'. Reloading...
INFO:     Started server process [3708]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

Cette nouvelle route est accessible par notre navigateur :

Route avec paramètres

Il est bien sûr possible d'ajouter des paramètres à une route.

Pour l'exemple, on crée une variable users avec la liste des utilisateurs. On ajoute une route de type GET pour récupérer cette liste, et une route de type POST pour ajouter un élément à cette liste :

users = ['pierre', 'natacha', 'benjamin']


@app.get('/users/list')
async def users_list():
    """Get the list of available users."""
    return json.dumps(users)


@app.post('/users/add/{name}')
async def users_add(name: str):
    """Add a new user.

    :param name: the name of the new user
    """
    users.append(name)
    return {'added': name}

On utilise curl pour tester nos nouvelles routes :

$ curl --request GET http://127.0.0.1:8000/users/list
"[\"pierre\", \"natacha\", \"benjamin\"]"
$ curl --request POST http://127.0.0.1:8000/users/add/florian
{"added":"florian"}
$ curl --request POST http://127.0.0.1:8000/users/add/denis
{"added":"denis"}
$ curl --request POST http://127.0.0.1:8000/users/add/bertrand
{"added":"bertrand"}
$ curl --request GET http://127.0.0.1:8000/users/list
"[\"pierre\", \"natacha\", \"benjamin\", \"florian\", \"denis\", \"bertrand\"]"

Documentation de l'API

FastAPI se charge de générer la documentation de l'API. Cette documentation est accessible grâce à des routes ajoutées automatiquement à l'API.

Pour cela, il génère un schéma OpenAPI, en récupérant les docstrings des fonctions annotées. Ce schéma est disponible avec la route /openapi.json :

Ensuite, il utilise Swagger UI et Redoc pour le rendu. Ces 2 versions de la documentation sont accessibles avec les routes /docs et /redoc respectivement.

On a ainsi la liste des routes, avec leurs types, leurs paramètres, leurs documentations. On peut tester notre API directement depuis ces pages. Et comme tout est en auto-reload, on peut faire nos modifications au fur et à mesure et uvicorn remettra à jour /docs et /redoc pour qu'on puisse retester immédiatement.

Conclusion

Mes premières impressions sur FastAPI sont très positives. La syntaxe est proche de celle de Flask, peut-être encore plus simple et élégante. La génération automatique et out-of-the-box de la documentation est vraiment cool ! Je ne me suis pas intéressé à l'aspect performances du framework, pour me concentrer sur son utilisation. Je vous laisse consulter la section "Benchmarks" du site officiel pour cela.

17