Cours Python · Module 6: Async et FastAPI
FastAPI - une API asynchrone moderne
Dans cette leçon10
Content de te revoir ! Ici Darwin avec FastAPI - le framework le plus moderne pour construire des API en Python !
Dans la leçon précédente, tu as appris async/await. Maintenant, on va mettre ces connaissances en pratique avec FastAPI - un framework 3 à 5 fois plus rapide que Flask, doté d'une validation automatique et qui génère la documentation tout seul !
Analogie safari : Flask, c'est un circuit de safari traditionnel - éprouvé et fiable. FastAPI, c'est un safari avec des drones - rapide, moderne, avec GPS et suivi automatique des animaux !
Qu'est-ce que FastAPI ?
FastAPI est un framework moderne et rapide pour construire des API, créé par Sebastián Ramírez en 2018.
Fonctionnalités clés : Rapide - comparable à Node.js/Go (grâce à Starlette) Async natif - support complet de async/await Type hints - utilise les annotations de types Validation automatique - Pydantic prêt à l'emploi Docs automatiques - Swagger UI + ReDoc automatiquement Python moderne - Python 3.7+ requis
Installer FastAPI
1pip install fastapi[all] # Tout (Uvicorn, Pydantic, etc.)
2
3# Ou au minimum :
4pip install fastapi uvicorn[standard]Uvicorn = serveur ASGI (comme Gunicorn pour WSGI)
Hello World avec FastAPI
1# main.py
2from fastapi import FastAPI
3
4app = FastAPI()
5
6@app.get("/")
7async def root():
8 return {"message": "Bonjour Safari !"}
9
10# Lance : uvicorn main:app --reloadLance :
1uvicorn main:app --reloadSortie :
1INFO: Uvicorn running on http://127.0.0.1:8000
2INFO: Application startup complete.Ouvre :
- http://localhost:8000/ → {"message": "Bonjour Safari !"}
- http://localhost:8000/docs → Documentation Swagger UI automatique !
- http://localhost:8000/redoc → Documentation ReDoc alternative
FastAPI vs Flask
| FastAPI | Flask |
|---|---|
| Async natif | Sync (async possible, mais difficile) |
| Type hints requis | Optionnels |
| Validation automatique (Pydantic) | Manuelle (Flask-WTF) |
| Docs automatiques (Swagger/ReDoc) | Aucune |
| 3 à 5 fois plus rapide | Plus lent |
| Python moderne (3.7+) | Anciennes versions OK |
| API-first | Applis web + API |
Quand FastAPI ? API REST, microservices, E/S async Quand Flask ? Applis web avec templates, projets plus petits
Les endpoints de base
1from fastapi import FastAPI
2
3app = FastAPI(title="Safari Database API", version="1.0.0")
4
5# GET - récupérer des données
6@app.get("/species")
7async def list_species():
8 return [
9 {"id": 1, "name": "Lion", "population": 120},
10 {"id": 2, "name": "Elephant", "population": 450}
11 ]
12
13# GET avec paramètre de chemin
14@app.get("/species/{species_id}")
15async def get_species(species_id: int):
16 return {"id": species_id, "name": "Lion", "population": 120}
17
18# POST - ajouter des données
19@app.post("/species")
20async def create_species(name: str, population: int):
21 return {"id": 3, "name": name, "population": population, "status": "created"}
22
23# PUT - mettre à jour
24@app.put("/species/{species_id}")
25async def update_species(species_id: int, name: str, population: int):
26 return {"id": species_id, "name": name, "population": population}
27
28# DELETE - supprimer
29@app.delete("/species/{species_id}")
30async def delete_species(species_id: int):
31 return {"id": species_id, "status": "deleted"}Teste :
1# GET
2curl http://localhost:8000/species
3
4# POST
5curl -X POST "http://localhost:8000/species?name=Cheetah&population=7100"Les query parameters - validation automatique
FastAPI analyse automatiquement les query params et valide les types !
1from fastapi import FastAPI
2
3app = FastAPI()
4
5@app.get("/species")
6async def list_species(
7 skip: int = 0,
8 limit: int = 10,
9 habitat: str | None = None,
10 endangered: bool = False
11):
12 # FastAPI automatiquement :
13 # - analyse ?skip=10&limit=5&habitat=savanna&endangered=true
14 # - convertit les types (str → int, str → bool)
15 # - valide (skip doit être un int !)
16
17 return {
18 "skip": skip,
19 "limit": limit,
20 "habitat": habitat,
21 "endangered": endangered,
22 "results": ["Lion", "Elephant"]
23 }Teste :
1/species → skip=0, limit=10, habitat=None, endangered=False
2/species?skip=20&limit=5 → skip=20, limit=5
3/species?habitat=savanna&endangered=1 → habitat="savanna", endangered=True
4/species?skip=abc → ERREUR : erreur de validation !FastAPI génère automatiquement les erreurs de validation :
1{
2 "detail": [
3 {
4 "loc": ["query", "skip"],
5 "msg": "value is not a valid integer",
6 "type": "type_error.integer"
7 }
8 ]
9}Les response models - des réponses structurées
1from fastapi import FastAPI
2from pydantic import BaseModel
3
4app = FastAPI()
5
6class Species(BaseModel):
7 id: int
8 name: str
9 scientific_name: str
10 population: int
11 endangered: bool = False
12
13@app.get("/species/{species_id}", response_model=Species)
14async def get_species(species_id: int):
15 return Species(
16 id=species_id,
17 name="Lion",
18 scientific_name="Panthera leo",
19 population=120,
20 endangered=True
21 )Avantages de response_model :
- Sérialisation automatique en JSON
- Validation de la sortie
- La documentation montre automatiquement la structure
- Sécurité des types
Une API Safari complète - exemple
1# main.py
2from fastapi import FastAPI, HTTPException
3from pydantic import BaseModel, Field
4from typing import List
5
6app = FastAPI(
7 title="Safari Database API",
8 description="API pour gérer les espèces sauvages d'Afrique",
9 version="1.0.0"
10)
11
12# Modèles
13class SpeciesBase(BaseModel):
14 name: str = Field(..., min_length=2, max_length=100)
15 scientific_name: str
16 population: int = Field(..., ge=0)
17 habitat: str
18
19class SpeciesCreate(SpeciesBase):
20 pass
21
22class Species(SpeciesBase):
23 id: int
24
25 class Config:
26 from_attributes = True
27
28# Base de données en mémoire
29species_db: dict[int, Species] = {
30 1: Species(id=1, name="Lion", scientific_name="Panthera leo", population=120, habitat="savanna"),
31 2: Species(id=2, name="Elephant", scientific_name="Loxodonta africana", population=450, habitat="savanna"),
32}
33next_id = 3
34
35# Endpoints
36@app.get("/")
37async def root():
38 return {"message": "Safari Database API", "version": "1.0.0"}
39
40@app.get("/species", response_model=List[Species])
41async def list_species(skip: int = 0, limit: int = 10, habitat: str | None = None):
42 """Liste toutes les espèces avec pagination"""
43 results = list(species_db.values())
44
45 if habitat:
46 results = [s for s in results if s.habitat == habitat]
47
48 return results[skip : skip + limit]
49
50@app.get("/species/{species_id}", response_model=Species)
51async def get_species(species_id: int):
52 """Récupère une espèce précise par son ID"""
53 if species_id not in species_db:
54 raise HTTPException(status_code=404, detail=f"Species {species_id} not found")
55
56 return species_db[species_id]
57
58@app.post("/species", response_model=Species, status_code=201)
59async def create_species(species: SpeciesCreate):
60 """Crée une nouvelle espèce"""
61 global next_id
62
63 new_species = Species(id=next_id, **species.dict())
64 species_db[next_id] = new_species
65 next_id += 1
66
67 return new_species
68
69@app.put("/species/{species_id}", response_model=Species)
70async def update_species(species_id: int, species: SpeciesCreate):
71 """Met à jour une espèce existante"""
72 if species_id not in species_db:
73 raise HTTPException(status_code=404, detail="Species not found")
74
75 updated = Species(id=species_id, **species.dict())
76 species_db[species_id] = updated
77
78 return updated
79
80@app.delete("/species/{species_id}")
81async def delete_species(species_id: int):
82 """Supprime une espèce"""
83 if species_id not in species_db:
84 raise HTTPException(status_code=404, detail="Species not found")
85
86 del species_db[species_id]
87 return {"status": "deleted", "id": species_id}Lance :
1uvicorn main:app --reloadTeste l'API :
1# Liste
2curl http://localhost:8000/species
3
4# Espèce précise
5curl http://localhost:8000/species/1
6
7# Ajouter
8curl -X POST http://localhost:8000/species \
9 -H "Content-Type: application/json" \
10 -d '{"name":"Cheetah","scientific_name":"Acinonyx jubatus","population":7100,"habitat":"savanna"}'
11
12# Mettre à jour
13curl -X PUT http://localhost:8000/species/1 \
14 -H "Content-Type: application/json" \
15 -d '{"name":"Lion","scientific_name":"Panthera leo","population":150,"habitat":"savanna"}'
16
17# Supprimer
18curl -X DELETE http://localhost:8000/species/3La documentation automatique
FastAPI génère automatiquement une documentation interactive !
Swagger UI : http://localhost:8000/docs
- Tests interactifs de l'API
- Bouton « Try it out » pour chaque endpoint
- Formulaires automatiques
ReDoc : http://localhost:8000/redoc
- Documentation lisible
- Idéale pour les développeurs
OpenAPI JSON : http://localhost:8000/openapi.json
- Schéma OpenAPI 3.0 brut
- Pour les outils externes
Récapitulatif
Dans cette leçon, tu as appris :
- Ce qu'est FastAPI et pourquoi l'utiliser
- Installer FastAPI + Uvicorn
- Hello World et les endpoints de base
- GET, POST, PUT, DELETE
- Les paramètres de chemin et les query parameters
- Les response models avec Pydantic
- HTTPException pour les erreurs
- La documentation automatique (Swagger/ReDoc)
- Une API Safari Database complète
Prochaine leçon : Darwin va te montrer Pydantic v2 - un puissant système de validation de données avec FastAPI !
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Comment décrirais-tu le mieux FastAPI ?
2. Comment installe-t-on FastAPI avec un serveur ASGI ?
Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Tri horizontal
Comment crée-t-on une instance d'application FastAPI ?
- Tri vertical
Ordonne une application FastAPI minimale :
- Clique dans l'ordre
Ordonne la commande pour démarrer le serveur uvicorn :
- Éditeur de code
Écris un endpoint async GET /species qui renvoie une liste de dictionnaires contenant des espèces.