APIs REST avec FastAPI ou Flask
Introduction aux APIs REST avec Python
Bienvenue dans cette leçon consacrée aux APIs REST (Representational State Transfer) avec deux des frameworks Python les plus populaires : Flask et FastAPI. Dans le cadre de votre apprentissage du développement avancé avec Python, la maîtrise des APIs est essentielle pour créer des applications web modernes et connectées.
Une API (Application Programming Interface) est un ensemble de définitions et de protocoles utilisés pour construire et intégrer des logiciels d'application. En d'autres termes, c'est un contrat qui permet à deux systèmes logiciels de communiquer entre eux. Les APIs REST sont devenues le standard de facto pour la création de services web en raison de leur simplicité, de leur évolutivité et de leur compatibilité avec le web.
Au cours de cette leçon, nous allons :
- Comprendre les principes fondamentaux des APIs REST.
- Découvrir pourquoi Flask et FastAPI sont d'excellents choix pour les construire en Python.
- Mettre en pratique ces concepts avec des exemples de code concrets pour chaque framework.
Préparez-vous à transformer vos applications Python en services web puissants et interactifs !
1. Comprendre les APIs REST
Avant de plonger dans le code, il est crucial de maîtriser les concepts théoriques qui sous-tendent les APIs REST.
1.1 Qu'est-ce qu'une API ?
Une API est un mécanisme qui permet à un programme (le client) de demander des services ou des informations à un autre programme (le serveur). Imaginez une API comme le menu d'un restaurant : il vous indique les plats (services) que vous pouvez commander, comment les commander (format de la requête) et à quoi vous attendre en retour (format de la réponse).
Dans le contexte du web, une API est souvent un ensemble d'URLs (ressources) que vous pouvez interroger pour effectuer des opérations (lire, créer, modifier, supprimer des données).
1.2 Les Principes de REST
REST n'est pas un protocole, mais un style architectural pour les systèmes hypermédia distribués, défini par Roy Fielding. Les APIs conformes aux principes REST sont appelées RESTful. Voici les principes clés :
- Client-Server : La séparation des préoccupations entre l'interface utilisateur (client) et le stockage des données (serveur) améliore la portabilité de l'interface utilisateur et la scalabilité du serveur.
- Stateless (Sans État) : Chaque requête du client au serveur doit contenir toutes les informations nécessaires pour comprendre la requête. Le serveur ne doit stocker aucun contexte client entre les requêtes. Cela améliore la scalabilité et la fiabilité.
- Cacheable (Cachable) : Les réponses doivent être définies comme cachables ou non cachables. Cela permet aux clients de mettre en cache les réponses pour améliorer la performance.
- Layered System (Système en Couches) : Un client ne sait pas s'il est directement connecté au serveur final ou à un intermédiaire. Cela permet l'utilisation de proxys, de passerelles et de pare-feu pour améliorer la sécurité, la scalabilité ou la modularité.
- Uniform Interface (Interface Uniforme) : C'est le principe central qui distingue REST des autres styles architecturaux. Il impose quatre contraintes :
- Identification des ressources : Chaque ressource est identifiée par une URI (Uniform Resource Identifier).
- Manipulation des ressources via des représentations : Le client manipule une représentation de la ressource (par exemple, un document JSON) et non la ressource elle-même.
- Messages auto-descriptifs : Chaque message (requête ou réponse) contient suffisamment d'informations pour être compris sans aucun état contextuel. Les types de médias sont souvent utilisés.
- Hypermedia as the Engine of Application State (HATEOAS) : Le serveur doit fournir, dans sa réponse, des liens hypermédia (URLs) qui guident le client vers les actions possibles ou les ressources liées. C'est le principe le moins souvent pleinement implémenté, mais il est fondamental pour une véritable API REST.
1.3 Verbes HTTP (Méthodes)
Les APIs REST utilisent les méthodes HTTP standard pour indiquer le type d'opération que le client souhaite effectuer sur une ressource.
GET: Récupérer une ressource ou une collection de ressources. (Ex:GET /books)POST: Créer une nouvelle ressource. Les données de la nouvelle ressource sont envoyées dans le corps de la requête. (Ex:POST /booksavec les données du livre)PUT: Mettre à jour entièrement une ressource existante, ou la créer si elle n'existe pas. (Ex:PUT /books/{id}avec toutes les données mises à jour du livre)PATCH: Mettre à jour partiellement une ressource existante. (Ex:PATCH /books/{id}avec seulement les champs à modifier)DELETE: Supprimer une ressource. (Ex:DELETE /books/{id})
1.4 Ressources et URLs
Dans REST, tout est une ressource. Une ressource est une entité abstraite, comme un utilisateur, un produit, une commande. Chaque ressource est identifiée de manière unique par une URI (Uniform Resource Identifier), qui est souvent une URL.
GET /users: Récupérer tous les utilisateurs.GET /users/123: Récupérer l'utilisateur avec l'ID 123.POST /users: Créer un nouvel utilisateur.PUT /users/123: Mettre à jour l'utilisateur 123.
1.5 Codes de Statut HTTP
Chaque réponse HTTP inclut un code de statut qui indique le résultat de la requête. Ils sont regroupés par catégories :
- 1xx - Information : La requête est reçue, traitement continu.
- 2xx - Succès : La requête a été reçue, comprise et acceptée.
200 OK: Succès général.201 Created: La ressource a été créée avec succès (souvent suite à unPOST).204 No Content: Succès, mais aucune donnée à retourner (souvent suite à unDELETEouPUT).
- 3xx - Redirection : Le client doit prendre des mesures supplémentaires pour compléter la requête.
- 4xx - Erreur Client : La requête contient une erreur ou est mal formée.
400 Bad Request: La requête est invalide.401 Unauthorized: Authentification requise.403 Forbidden: Accès refusé.404 Not Found: La ressource demandée n'existe pas.405 Method Not Allowed: La méthode HTTP n'est pas supportée pour cette ressource.409 Conflict: Conflit (par exemple, tentative de créer une ressource qui existe déjà).
- 5xx - Erreur Serveur : Le serveur n'a pas pu satisfaire une requête apparemment valide.
500 Internal Server Error: Erreur générique du serveur.503 Service Unavailable: Le serveur est temporairement incapable de gérer la requête.
1.6 Formats de Données
Les données échangées via les APIs REST sont généralement formatées en JSON (JavaScript Object Notation). C'est un format léger, lisible par l'homme et facile à analyser par les machines. Bien que le XML (eXtensible Markup Language) ait été utilisé par le passé, JSON est aujourd'hui le format dominant.
Exemple JSON :
{
"id": "123",
"title": "Le Seigneur des Anneaux",
"author": "J.R.R. Tolkien",
"year": 1954
}
2. Choisir son framework Python : Flask ou FastAPI
Python offre plusieurs frameworks pour créer des APIs. Nous nous concentrons sur Flask et FastAPI, chacun ayant ses forces.
2.1 Flask : Le Micro-framework
Flask est un micro-framework web léger. Il fournit les outils essentiels pour construire des applications web sans imposer de décisions techniques spécifiques.
-
Avantages :
- Léger et minimaliste : Idéal pour les petits projets ou pour les développeurs qui préfèrent choisir eux-mêmes leurs bibliothèques pour des fonctionnalités spécifiques (ORM, validation, etc.).
- Flexible : Permet une grande liberté dans l'architecture de votre projet.
- Communauté mature : Nombreuses extensions disponibles et vaste communauté pour le support.
- Idéal pour démarrer : Sa simplicité le rend très accessible pour les débutants.
-
Inconvénients :
- "Batteries non incluses" : Pour des projets plus complexes, vous devrez intégrer manuellement des extensions pour la validation de données, la gestion de bases de données, l'authentification, etc.
- Synchrone par défaut : Moins performant que les frameworks asynchrones pour les E/S intensives, bien qu'il puisse être étendu avec des bibliothèques asynchrones.
2.2 FastAPI : La Révolution Asynchrone
FastAPI est un framework web moderne et rapide pour construire des APIs avec Python 3.7+ basé sur les type hints standard de Python. Il s'appuie sur Starlette pour le web et Pydantic pour la validation/sérialisation des données.
-
Avantages :
- Performances élevées : Basé sur ASGI (Asynchronous Server Gateway Interface), il est conçu pour l'asynchronisme et peut gérer un grand nombre de requêtes simultanées. Il est souvent comparé aux performances de Node.js et Go.
- Validation et sérialisation automatiques : Utilise Pydantic pour définir des schémas de données clairs et valider automatiquement les requêtes et les réponses.
- Documentation interactive automatique : Génère automatiquement une documentation API interactive (OpenAPI/Swagger UI et ReDoc) basée sur vos type hints. C'est un atout majeur pour les équipes.
- Développement rapide : Moins de code boilerplate grâce à l'automatisation.
- Typage fort : Tire parti des type hints de Python, améliorant l'autocomplétion, la détection d'erreurs et la maintenabilité du code.
-
Inconvénients :
- Plus récent : Bien que mature, sa communauté est plus jeune que celle de Flask/Django.
- Courbe d'apprentissage : Si vous n'êtes pas familier avec les concepts asynchrones (
async/await) ou les type hints avancés, il y aura une petite courbe d'apprentissage.
En résumé :
- Choisissez Flask pour les projets simples, si vous préférez la flexibilité maximale, ou si vous êtes déjà très à l'aise avec ses extensions pour des besoins spécifiques.
- Choisissez FastAPI pour les projets nécessitant des performances élevées, une validation de données robuste, une documentation automatique, ou si vous souhaitez tirer parti des fonctionnalités modernes de Python (asynchronisme, type hints).
Pour cette leçon, nous allons explorer les deux.
3. Implémentation avec Flask
Nous allons créer une API simple pour gérer une collection de livres.
3.1 Installation de Flask
Tout d'abord, assurez-vous d'avoir Python installé. Il est recommandé d'utiliser un environnement virtuel.
python -m venv venv
source venv/bin/activate # Sur Windows, utilisez `venv\Scripts\activate`
pip install Flask
3.2 Créer une API RESTful simple avec Flask
Créons un fichier app.py. Nous allons simuler une base de données avec une liste Python.
# app.py
from flask import Flask, request, jsonify, abort
app = Flask(__name__)
# Base de données simple en mémoire
books = [
{"id": "1", "title": "Le Seigneur des Anneaux", "author": "J.R.R. Tolkien", "year": 1954},
{"id": "2", "title": "Dune", "author": "Frank Herbert", "year": 1965}
]
# --- Endpoints RESTful ---
# GET /books : Récupérer tous les livres
@app.route('/books', methods=['GET'])
def get_books():
return jsonify(books)
# GET /books/<id> : Récupérer un livre par son ID
@app.route('/books/<string:book_id>', methods=['GET'])
def get_book(book_id):
book = next((book for book in books if book['id'] == book_id), None)
if book is None:
abort(404, description="Livre non trouvé")
return jsonify(book)
# POST /books : Créer un nouveau livre
@app.route('/books', methods=['POST'])
def create_book():
if not request.json or not 'title' in request.json or not 'author' in request.json:
abort(400, description="Les champs 'title' et 'author' sont requis.")
new_id = str(len(books) + 1)
new_book = {
'id': new_id,
'title': request.json['title'],
'author': request.json['author'],
'year': request.json.get('year') # Le champ 'year' est optionnel
}
books.append(new_book)
return jsonify(new_book), 201 # Statut 201 Created
# PUT /books/<id> : Mettre à jour un livre existant
@app.route('/books/<string:book_id>', methods=['PUT'])
def update_book(book_id):
book = next((book for book in books if book['id'] == book_id), None)
if book is None:
abort(404, description="Livre non trouvé")
if not request.json:
abort(400, description="Données de mise à jour requises")
book['title'] = request.json.get('title', book['title'])
book['author'] = request.json.get('author', book['author'])
book['year'] = request.json.get('year', book['year'])
return jsonify(book)
# DELETE /books/<id> : Supprimer un livre
@app.route('/books/<string:book_id>', methods=['DELETE'])
def delete_book(book_id):
global books # Permet de modifier la liste 'books' globale
initial_len = len(books)
books = [book for book in books if book['id'] != book_id]
if len(books) == initial_len: # Si la longueur n'a pas changé, le livre n'a pas été trouvé
abort(404, description="Livre non trouvé")
return '', 204 # Statut 204 No Content
# Pour gérer les erreurs 404 de manière plus propre
@app.errorhandler(404)
def not_found(error):
return jsonify({"error": error.description}), 404
@app.errorhandler(400)
def bad_request(error):
return jsonify({"error": error.description}), 400
if __name__ == '__main__':
app.run(debug=True) # debug=True pour le développement, ne pas utiliser en production
Explication du code Flask :
from flask import Flask, request, jsonify, abort: Importe les modules nécessaires.Flask: La classe principale de l'application.request: L'objet global qui contient les données de la requête entrante (corps, headers, paramètres d'URL, etc.).jsonify: Une fonction utilitaire pour retourner des réponses JSON. Elle sérialise les dictionnaires Python en chaînes JSON et définit l'en-têteContent-Typeàapplication/json.abort: Utilisé pour lever une erreur HTTP avec un code de statut spécifique.
app = Flask(__name__): Crée une instance de l'application Flask.books = [...]: Une liste de dictionnaires simulant notre "base de données".@app.route('/books', methods=['GET']): C'est un décorateur qui associe une fonction Python (get_booksdans ce cas) à une URL (/books) et à une ou plusieurs méthodes HTTP (GET).get_books(): Retourne la liste complète des livres sous forme JSON.get_book(book_id): Récupère un livre spécifique. Notez/<string:book_id>dans la route, cela capture une partie de l'URL comme variablebook_id.next((item for item in list if condition), None)est une manière pythonique de trouver le premier élément correspondant ouNone.create_book():request.json: Accède au corps de la requête JSON. Flask le parse automatiquement si l'en-têteContent-Typeestapplication/json.- Validation rudimentaire : Vérifie si le corps de la requête contient
titleetauthor. - Retourne le nouveau livre et un statut
201 Created.
update_book(): Similaire àcreate_book, il met à jour les champs fournis dans la requête JSON.delete_book(): Supprime un livre de la liste. Notez l'utilisation deglobal bookspour pouvoir réaffecter la liste.@app.errorhandler(404): Permet de personnaliser les messages d'erreur HTTP.if __name__ == '__main__': app.run(debug=True): Lance le serveur de développement Flask.debug=Trueest utile pour le développement car il fournit des messages d'erreur détaillés et redémarre le serveur automatiquement lors des modifications de code.
Comment tester l'API Flask :
Lancez le serveur :
python app.py
Le serveur devrait démarrer sur http://127.0.0.1:5000/.
Utilisez un outil comme Postman, Insomnia, curl, ou même votre navigateur :
- GET
http://127.0.0.1:5000/books: Récupère tous les livres. - GET
http://127.0.0.1:5000/books/1: Récupère le livre avec l'ID "1". - POST
http://127.0.0.1:5000/booksCorps (JSON) :{ "title": "Le Petit Prince", "author": "Antoine de Saint-Exupéry", "year": 1943 } - PUT
http://127.0.0.1:5000/books/3(si vous avez créé le livre 3) Corps (JSON) :{ "title": "Le Petit Prince (édition révisée)", "year": 2020 } - DELETE
http://127.0.0.1:5000/books/1
4. Implémentation avec FastAPI
Maintenant, voyons comment créer la même API avec FastAPI, en tirant parti de ses fonctionnalités modernes.
4.1 Installation de FastAPI
python -m venv venv
source venv/bin/activate # Sur Windows, utilisez `venv\Scripts\activate`
pip install fastapi uvicorn[standard]
pip install pydantic # Pydantic est une dépendance de FastAPI, mais il est bon de la connaître explicitement
fastapi: Le framework.uvicorn: Un serveur ASGI pour exécuter l'application FastAPI.
4.2 Créer une API RESTful simple avec FastAPI
Créons un fichier main.py.
# main.py
from typing import List, Optional
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
# Initialisation de l'application FastAPI
app = FastAPI(
title="API Livres",
description="Une API REST simple pour gérer une collection de livres."
)
# Modèle de données pour un livre (utilisant Pydantic)
class Book(BaseModel):
id: Optional[str] = None # ID sera généré par le serveur lors de la création
title: str
author: str
year: Optional[int] = None
# Base de données simple en mémoire
books_db = [
Book(id="1", title="Le Seigneur des Anneaux", author="J.R.R. Tolkien", year=1954),
Book(id="2", title="Dune", author="Frank Herbert", year=1965)
]
# --- Endpoints RESTful ---
# GET /books : Récupérer tous les livres
@app.get("/books", response_model=List[Book], summary="Obtenir tous les livres")
async def get_all_books():
"""
Récupère la liste complète de tous les livres disponibles.
"""
return books_db
# GET /books/{book_id} : Récupérer un livre par son ID
@app.get("/books/{book_id}", response_model=Book, summary="Obtenir un livre par ID")
async def get_book_by_id(book_id: str):
"""
Récupère un livre spécifique en utilisant son identifiant unique.
"""
for book in books_db:
if book.id == book_id:
return book
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Livre non trouvé")
# POST /books : Créer un nouveau livre
@app.post("/books", response_model=Book, status_code=status.HTTP_201_CREATED, summary="Ajouter un nouveau livre")
async def create_new_book(book: Book):
"""
Ajoute un nouveau livre à la collection. L'ID du livre sera généré automatiquement.
"""
new_id = str(len(books_db) + 1)
book.id = new_id # Assigne l'ID généré
books_db.append(book)
return book
# PUT /books/{book_id} : Mettre à jour un livre existant
@app.put("/books/{book_id}", response_model=Book, summary="Mettre à jour un livre existant")
async def update_existing_book(book_id: str, updated_book: Book):
"""
Met à jour toutes les informations d'un livre existant.
"""
for index, book in enumerate(books_db):
if book.id == book_id:
updated_book.id = book_id # S'assurer que l'ID ne change pas
books_db[index] = updated_book
return updated_book
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Livre non trouvé")
# DELETE /books/{book_id} : Supprimer un livre
@app.delete("/books/{book_id}", status_code=status.HTTP_204_NO_CONTENT, summary="Supprimer un livre")
async def delete_existing_book(book_id: str):
"""
Supprime un livre de la collection par son identifiant.
"""
global books_db
initial_len = len(books_db)
books_db = [book for book in books_db if book.id != book_id]
if len(books_db) == initial_len:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Livre non trouvé")
return # Pas de contenu pour 204 No Content
Explication du code FastAPI :
from typing import List, Optional: Importe les type hints pour améliorer la clarté du code et permettre à FastAPI de générer la documentation.from fastapi import FastAPI, HTTPException, status:FastAPI: La classe principale de l'application.HTTPException: Utilisé pour lever des erreurs HTTP avec des codes de statut et des détails spécifiques.status: Un module qui contient des constantes pour les codes de statut HTTP (status.HTTP_404_NOT_FOUND).
from pydantic import BaseModel: ImporteBaseModelde Pydantic, la base pour définir des modèles de données.app = FastAPI(...): Crée une instance de l'application FastAPI. Les argumentstitleetdescriptionsont utilisés pour la documentation automatique.class Book(BaseModel): ...: C'est la définition du schéma de données pour un livre. Pydantic utilise les type hints Python pour :- Valider les données entrantes (par exemple, s'assurer que
titleest une chaîne de caractères). - Sérialiser les données sortantes (convertir l'objet
Booken JSON). - Générer automatiquement la documentation de l'API.
Optional[str] = Nonesignifie queidest une chaîne optionnelle et sa valeur par défaut estNone.
- Valider les données entrantes (par exemple, s'assurer que
books_db = [...]: Notre base de données simulée, où chaque entrée est maintenant une instance de la classeBookde Pydantic.@app.get("/books", response_model=List[Book], summary="Obtenir tous les livres"):@app.get,@app.post, etc. : Décorateurs spécifiques à FastAPI pour les méthodes HTTP.response_model=List[Book]: Indique à FastAPI que la réponse de cet endpoint sera une liste d'objetsBook. Cela aide à la validation des réponses et à la génération de la documentation.summary: Un court résumé pour la documentation.
async def get_all_books():: Les fonctions de route sontasync(asynchrones). FastAPI est construit sur l'asynchronisme, ce qui permet de gérer efficacement un grand nombre de requêtes simultanées, en particulier pour les opérations I/O (comme les requêtes de base de données).get_book_by_id(book_id: str): FastAPI utilise les type hints dans les arguments de fonction pour :- Extraire les paramètres de l'URL (
book_id). - Convertir automatiquement le type (ici,
book_idest converti enstr). - Fournir cette information à la documentation.
raise HTTPException(...): La manière standard de gérer les erreurs et de renvoyer des codes de statut HTTP appropriés.
- Extraire les paramètres de l'URL (
create_new_book(book: Book):book: Book: FastAPI détecte que l'argumentbookest une instance de notre modèle PydanticBook. Il va automatiquement :- Lire le corps de la requête comme JSON.
- Valider les données par rapport au schéma
Book. - Convertir les données validées en une instance de l'objet
Book.
status_code=status.HTTP_201_CREATED: Définit le code de statut HTTP de la réponse.
update_existing_book(book_id: str, updated_book: Book): Similaire à la création, FastAPI valide les données entrantes pourupdated_bookselon le modèleBook.delete_existing_book(): Ici, le statut eststatus.HTTP_204_NO_CONTENT, et la fonction ne retourne rien, car une réponse 204 ne doit pas avoir de corps.
Comment tester l'API FastAPI :
Lancez le serveur Uvicorn :
uvicorn main:app --reload
main: Le nom du fichier Python (main.py).app: L'objetFastAPIà l'intérieur du fichier.--reload: Redémarre le serveur automatiquement lors des modifications de code.
Le serveur devrait démarrer sur http://127.0.0.1:8000/.
Ouvrez votre navigateur à :
http://127.0.0.1:8000/docs: Vous verrez la documentation interactive (Swagger UI) générée automatiquement. Vous pouvez y tester tous les endpoints !http://127.0.0.1:8000/redoc: Une autre interface de documentation alternative.
Utilisez un outil comme Postman, Insomnia, ou curl pour interagir :
- GET
http://127.0.0.1:8000/books - GET
http://127.0.0.1:8000/books/1 - POST
http://127.0.0.1:8000/booksCorps (JSON) :{ "title": "Harry Potter à l'école des sorciers", "author": "J.K. Rowling", "year": 1997 } - PUT
http://127.0.0.1:8000/books/3(si vous avez créé le livre 3) Corps (JSON) :{ "id": "3", "title": "Harry Potter et la Chambre des Secrets", "author": "J.K. Rowling", "year": 1998 } - DELETE
http://127.0.0.1:8000/books/1
L'expérience avec FastAPI est souvent plus fluide pour le développement d'APIs grâce à l'automatisation de la validation et de la documentation.
5. Concepts Avancés (Bref Aperçu)
Cette leçon a couvert les bases, mais la création d'APIs robustes implique d'autres considérations :
- Authentification et Autorisation : Comment s'assurer que seuls les utilisateurs autorisés peuvent accéder à certaines ressources. Les tokens JWT (JSON Web Tokens) sont très courants.
- Intégration de Bases de Données : Dans des applications réelles, vous utiliserez une base de données (SQL comme PostgreSQL/MySQL avec SQLAlchemy ou ORM comme Tortoise ORM/SQLModel pour FastAPI ; NoSQL comme MongoDB).
- Gestion des Erreurs : Mettre en place une gestion des erreurs centralisée et cohérente pour retourner des messages d'erreur utiles aux clients.
- Tests Unitaires et d'Intégration : Écrire des tests pour garantir le bon fonctionnement de votre API. Flask et FastAPI ont d'excellents outils de test.
- Déploiement : Comment mettre votre API en production (serveurs cloud, conteneurs Docker, etc.).
- Versioning d'API : Comment gérer les changements dans votre API sans casser les applications clientes existantes (ex:
/v1/books,/v2/books).
Conclusion
Nous avons exploré en profondeur le monde des APIs REST avec Python, en utilisant les frameworks Flask et FastAPI.
Vous avez appris :
- Les principes fondamentaux de REST : client-serveur, stateless, cachable, système en couches et interface uniforme.
- L'importance des verbes HTTP (
GET,POST,PUT,DELETE), des ressources, des URLs et des codes de statut HTTP. - Les atouts de Flask pour sa légèreté et sa flexibilité, idéal pour des projets sur mesure ou pour débuter.
- Les avantages de FastAPI pour ses performances, sa validation automatique des données via Pydantic et sa génération de documentation interactive, en faisant un excellent choix pour les APIs modernes et complexes.
La capacité à construire des APIs est une compétence fondamentale dans le développement logiciel moderne. Que vous choisissiez Flask pour sa simplicité ou FastAPI pour sa puissance et ses fonctionnalités avancées, vous êtes désormais équipé pour commencer à bâtir des services web robustes et performants en Python. Continuez à explorer, à coder et à expérimenter pour maîtriser pleinement cet art !