# FastAPI à partir de zéro : installation, app = FastAPI(), une première route et le lancement du serveur<no value>

## Qu'allons-nous apprendre ?

Cette leçon est une **mise en place complète, à partir de zéro**, d'un vrai serveur :

1. **Un environnement virtuel** (venv) : là où les bibliothèques sont installées.
2. **Installer FastAPI** avec `pip`.
3. **`main.py`** : l'import, la création de `app`, et une première **route**.
4. **Le lancer** avec `uvicorn`.
5. **Tester** : le navigateur, curl, et la page de documentation automatique `/docs`.

## Pourquoi en avons-nous besoin ?

Dans le thème des réseaux, nous avons vu ce qu'implique un serveur « fait à la main » : `bind`, `listen`, `accept`, et le décodage du texte. C'est beaucoup de travail, et il est facile de planter sur une mauvaise entrée. **FastAPI** fait tout cela pour nous : il reçoit la requête, décode le HTTP, trouve la bonne fonction, convertit la réponse en JSON, et vérifie les types. Nous n'écrivons **que la logique**.

FastAPI est l'une des bibliothèques les plus répandues pour un backend en Python, surtout pour les API et dans les mondes de la Data et de l'IA.

## Explication à partir des bases

### Qu'est-ce que FastAPI ?

**FastAPI** est un **framework** pour construire des API web en Python. Un framework = une bibliothèque qui impose une **structure** : « vous écrivez des fonctions, et je les appelle quand une requête correspondante arrive ».

**Uvicorn** est **le serveur HTTP** lui-même : le programme qui écoute sur un port (le thème des réseaux : `listen`), reçoit les connexions, et transmet chaque requête à FastAPI. FastAPI = **quoi** répondre. Uvicorn = **l'accueil** à l'entrée.

```text
Browser ──HTTP──► Uvicorn (listens on port 8000) ──► FastAPI (finds the right function) ──► your function
        ◄──JSON── Uvicorn ◄── FastAPI (converts dict to JSON) ◄──────────────────────── return {...}
```

### Une bibliothèque externe et pip

Jusqu'à présent, nous n'avons utilisé que des modules **fournis avec Python** (`os`, `json`, `logging`). FastAPI est une **bibliothèque externe** (un paquet tiers, Third-party Package), il faut donc l'installer.

**pip** est le gestionnaire de paquets de Python : il télécharge des bibliothèques depuis **PyPI** (le dépôt public de bibliothèques Python) et les installe.

### Un environnement virtuel (venv) — et pourquoi il est nécessaire

Si vous installez des bibliothèques « globalement » (pour tout l'ordinateur), un projet a besoin de FastAPI version 0.100, et un autre projet de la 0.142, et il y a un conflit. Un **environnement virtuel** (Virtual Environment, venv) = **un dossier privé pour le projet**, avec sa propre copie de Python et de ses bibliothèques. Chaque projet avec ses propres bibliothèques, sans conflits.

{{< box "analogy" "Analogie : une boîte à outils pour chaque projet" >}}
Un artisan qui travaille sur trois maisons ne garde pas tous ses outils en un seul tas chez lui. Chaque chantier a **sa propre boîte à outils**, avec exactement ce dont le chantier a besoin. venv = la boîte à outils du projet. Et l'« activer » (activate) = « je travaille maintenant avec **cette** boîte ».
{{< /box >}}

### Le décorateur — `@app.get("/")`

Une ligne qui commence par `@` au-dessus d'un `def` est un **décorateur** (nous avons vu `@property` dans le thème POO). Dans FastAPI, `@app.get("/")` dit : **« enregistre la fonction ci-dessous comme gestionnaire des requêtes `GET` vers le chemin `/` »**.

Vous vous souvenez de la calculatrice avec un dict de fonctions (`OPERATIONS = {"+": add, ...}`) ? FastAPI construit exactement une telle table : **(méthode, chemin) → fonction**. Chaque `@app.get(...)` ajoute une ligne à la table. Quand une requête arrive, FastAPI la cherche dans la table et appelle la fonction. (Ce sont les fonctions comme objets en action !)

**Route** = le lien entre un endpoint (méthode + chemin) et la fonction qui le gère.

## Syntaxe

### Étape 1 — un dossier et un environnement virtuel

```powershell
mkdir ~\dev\kodkod6\week-4\hello-api
cd ~\dev\kodkod6\week-4\hello-api
python -m venv .venv
```

### Étape 2 — activer l'environnement

**Windows (PowerShell) :**

```powershell
.venv\Scripts\Activate.ps1
```

**Mac / Linux :**

```bash
source .venv/bin/activate
```

L'invite change et commence par `(.venv)`. **À partir de maintenant, `python` et `pip` appartiennent au projet.**

### Étape 3 — l'installation

```powershell
pip install "fastapi[standard]"
```

`[standard]` installe FastAPI **avec** Uvicorn et quelques autres outils utiles. Une vérification :

```powershell
pip list
```

### Étape 4 — `main.py`

```python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def home():
    return {"message": "Hello from my first server!"}
```

### Étape 5 — le lancement

```powershell
uvicorn main:app --reload
```

### Étape 6 — les tests

- Le navigateur : `http://127.0.0.1:8000/`
- La documentation : `http://127.0.0.1:8000/docs`
- Arrêter : `Ctrl + C`

## Premier exemple de code

Après les étapes 1 à 5, le terminal affiche :

```text
INFO:     Will watch for changes in these directories: ['C:\\Users\\dana\\dev\\kodkod6\\week-4\\hello-api']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [43864] using StatReload
INFO:     Started server process [29224]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
```

Dans le navigateur, `http://127.0.0.1:8000/` :

```json
{"message":"Hello from my first server!"}
```

Et dans le terminal, une ligne sur la requête s'ajoute :

```text
INFO:     127.0.0.1:52311 - "GET / HTTP/1.1" 200 OK
```

## Analyse du code ligne par ligne

**`main.py` :**

| Ligne | Explication |
|---|---|
| `from fastapi import FastAPI` | Importe la **classe** nommée `FastAPI` depuis la bibliothèque (la leçon sur les modules : `from ... import`). |
| `app = FastAPI()` | Crée un **objet** à partir de la classe (le thème POO !). `app` est **l'application** : elle contient la table des routes, et Uvicorn communiquera avec elle. |
| `@app.get("/")` | Un décorateur : « enregistre `home` comme gestionnaire de `GET /` ». `get` est une **méthode** de l'objet `app`. |
| `def home():` | Une fonction ordinaire. Le nom est libre. FastAPI la reconnaît grâce au décorateur, pas grâce à son nom. |
| `return {"message": "..."}` | On renvoie un **dict**, et FastAPI le convertit automatiquement en **JSON** (la sérialisation, la leçon sur JSON) et renvoie le code 200. |

**La commande `uvicorn main:app --reload` :**

| Partie | Explication |
|---|---|
| `uvicorn` | Lance le serveur HTTP. |
| `main` | **Le module** : le fichier `main.py` (sans `.py`). |
| `:app` | **L'objet** dans le module : la variable `app`. « Exécute l'application appelée `app`, qui se trouve dans `main` ». |
| `--reload` | **Le mode développement** : quand vous enregistrez une modification du code, le serveur redémarre tout seul. **Uniquement pour le développement**, pas sur un vrai serveur. |

**Les lignes de la sortie :**

| Ligne | Signification (et le lien avec le thème des réseaux) |
|---|---|
| `Will watch for changes...` | Le mode `--reload` : surveille les fichiers du dossier. |
| `Uvicorn running on http://127.0.0.1:8000` | Le serveur **écoute** (`listen`) sur **localhost**, **port 8000**. |
| `Started reloader process [43864]` | Un processus « surveillant » qui détecte les modifications. Un **PID**. |
| `Started server process [29224]` | **Le processus** qui gère réellement les requêtes. Un autre PID. |
| `"GET / HTTP/1.1" 200 OK` | Un **journal** de chaque requête : la méthode, le chemin, la version et le code d'état. |

## Un autre exemple

**Plus de routes, et `/docs`.** Mettez à jour `main.py` (avec `--reload`, le serveur se met à jour tout seul dès que vous enregistrez) :

```python
from fastapi import FastAPI

app = FastAPI(title="Kodkod Hello API")

COURSE = {"name": "Kodkod 6", "weeks": 5, "topics": ["OS", "Python", "OOP", "Backend", "DB"]}

@app.get("/")
def home():
    return {"message": "Hello from my first server!"}

@app.get("/course")
def course_info():
    return COURSE

@app.get("/course/topics")
def course_topics():
    return COURSE["topics"]

@app.get("/health")
def health():
    return {"status": "ok"}
```

**Des tests avec curl** (dans **un autre** terminal, car le premier est occupé par le serveur) :

```powershell
curl.exe http://127.0.0.1:8000/course
curl.exe http://127.0.0.1:8000/course/topics
curl.exe -i http://127.0.0.1:8000/nothing
```

**Sortie :**

```text
{"name":"Kodkod 6","weeks":5,"topics":["OS","Python","OOP","Backend","DB"]}
["OS","Python","OOP","Backend","DB"]
HTTP/1.1 404 Not Found
date: Tue, 06 Oct 2026 14:30:00 GMT
server: uvicorn
content-length: 22
content-type: application/json

{"detail":"Not Found"}
```

**Analyse :**

- `FastAPI(title="Kodkod Hello API")` — un nom pour l'application, qui apparaîtra dans la page de documentation.
- **On peut renvoyer tout ce que JSON sait représenter** : un dict (`/course`), une **liste** (`/course/topics`), une chaîne ou un nombre.
- **Un chemin qui n'a pas été défini** (`/nothing`) : FastAPI renvoie lui-même un **404**, avec un JSON d'erreur. Nous n'avons pas écrit une seule ligne pour cela.
- `/health` — un endpoint courant sur les vrais serveurs : les systèmes de surveillance le vérifient toutes les quelques secondes, pour savoir que le serveur est vivant.

### `/docs` — la documentation automatique

Ouvrez `http://127.0.0.1:8000/docs`. FastAPI a **construit tout seul** une page de documentation interactive (appelée **Swagger UI**) :

- Une liste de **tous les endpoints**, avec la méthode et le chemin.
- Cliquer sur un endpoint → **Try it out** → **Execute** : envoie une vraie requête et affiche la réponse.
- La documentation se met à jour automatiquement à chaque nouvelle route.

Dans le thème de l'API des étudiants, nous l'utiliserons comme **principal outil de test** du serveur.

## Erreur courante

**Erreur 1 : installer sans activer le venv**, ou ouvrir un nouveau terminal et oublier de l'activer.

```text
uvicorn : The term 'uvicorn' is not recognized ...
```

Ou :

```text
ModuleNotFoundError: No module named 'fastapi'
```

**Une vérification :** l'invite commence-t-elle par `(.venv)` ? Sinon, `.venv\Scripts\Activate.ps1`. **Dans chaque nouveau terminal, activez-le à nouveau.** (Une alternative qui fonctionne toujours : `python -m uvicorn main:app --reload`.)

**Erreur 2 : sous Windows, l'activation est bloquée.**

```text
.venv\Scripts\Activate.ps1 cannot be loaded because running scripts is disabled on this system.
```

PowerShell bloque l'exécution de scripts par défaut. Ouvrez PowerShell et lancez **une seule fois** :

```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```

(Cela autorise les scripts locaux pour votre utilisateur uniquement. Souvenez-vous des permissions du thème sur le système d'exploitation !)

**Erreur 3 : `main:app` ne correspond pas au code.**

```text
ERROR:    Error loading ASGI app. Attribute "app" not found in module "main".
```

Le fichier ne s'appelle pas `main.py`, ou la variable ne s'appelle pas `app` (par exemple `application = FastAPI()`). Le format est toujours `<fichier>:<variable>`. Et on le lance **depuis le dossier où se trouve le fichier** (le Current Working Directory, souvenez-vous du thème sur le système d'exploitation !).

**Erreur 4 : un port déjà occupé.**

```text
ERROR:    [WinError 10048] error while attempting to bind on address ('127.0.0.1', 8000): only one usage of each socket address (protocol/network address/port) is normally permitted
```

Un autre serveur (ou une copie précédente du même serveur) écoute déjà sur le 8000 (souvenez-vous des ports du thème des réseaux !). Arrêtez-le avec `Ctrl + C` dans son terminal, ou lancez sur un autre port : `uvicorn main:app --reload --port 8001`.

**Erreur 5 : mettre `.venv` dans Git.** Le dossier est énorme et contient des milliers de fichiers, qui dépendent de votre ordinateur. Ajoutez à `.gitignore` :

```text
.venv/
__pycache__/
```

Et à la place, enregistrez une **liste** des bibliothèques : `pip freeze > requirements.txt`. Celui qui télécharge le projet lance `pip install -r requirements.txt`.

<!-- exercises:start — generated by scripts/intro6/sync_site_exercises.py; edit scripts/intro6/exercises/ -->
## Exercices

Les exercices n'utilisent que ce qui a été vu dans cette leçon et les précédentes. Essayez d'abord seul, et n'ouvrez la solution qu'ensuite.

### Exercice 1: Mettre en place un projet

Écrivez la suite de commandes qui met en place un projet `hello-api` : un dossier, un environnement virtuel, son activation (Windows), et l'installation de FastAPI. Quel est le rôle de l'environnement virtuel ?

{{< solution >}}
```powershell
mkdir hello-api
cd hello-api
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install "fastapi[standard]"
pip list
```

(Sur Mac : `source .venv/bin/activate`.)

**Un environnement virtuel (venv)** isole les paquets du projet : chaque projet avec ses propres versions, sans entrer en conflit avec d'autres projets ni avec le Python de l'ordinateur. Le dossier `.venv` n'entre pas dans Git.
{{< /solution >}}

### Exercice 2: Une première route

Écrivez un `main.py` avec une application FastAPI et une route pour `/` qui renvoie `{"message": "Hello from my first server!"}`. Comment le lancer, et vers quelle adresse naviguer ?

{{< solution >}}
```python
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def home():
    return {"message": "Hello from my first server!"}
```

Lancez-le :

```powershell
uvicorn main:app --reload
```

Et naviguez vers `http://127.0.0.1:8000`. `main:app` = le fichier `main.py`, la variable `app`. `--reload` redémarre le serveur après chaque enregistrement.
{{< /solution >}}

### Exercice 3: D'une requête à une fonction

Remettez dans l'ordre le parcours d'une requête, du navigateur jusqu'à notre fonction et retour :

- (a) FastAPI convertit le dict en JSON
- (b) Le navigateur envoie `GET /`
- (c) La fonction `home()` renvoie un dict
- (d) Uvicorn reçoit la requête sur le port 8000
- (e) FastAPI trouve la fonction qui correspond à `GET /`

{{< solution >}}
L'ordre : **(b), (d), (e), (c), (a)**

1. Le navigateur envoie `GET /`.
2. **Uvicorn** — le serveur lui-même — reçoit la requête sur le port 8000.
3. **FastAPI** trouve la route qui correspond à la méthode et au chemin.
4. Notre fonction renvoie un **dict** ordinaire.
5. FastAPI le convertit en **JSON** et renvoie une réponse avec 200.
{{< /solution >}}

### Exercice 4: Une API de citations

Écrivez une API de citations avec une liste de citations (des dictionnaires avec `text` et `author`), et deux routes :

- `GET /quotes` — toutes les citations ;
- `GET /quotes/count` — `{"count": <number>}`.

Donnez à l'application le titre `"Quotes API"`.

{{< solution >}}
```python
from fastapi import FastAPI

app = FastAPI(title="Quotes API")

QUOTES = [
    {"text": "Simple is better than complex.", "author": "The Zen of Python"},
    {"text": "Readability counts.", "author": "The Zen of Python"},
    {"text": "Talk is cheap. Show me the code.", "author": "Linus Torvalds"},
]


@app.get("/quotes")
def all_quotes():
    return QUOTES


@app.get("/quotes/count")
def count_quotes():
    return {"count": len(QUOTES)}
```

`GET /quotes/count` renvoie `{"count": 3}`. FastAPI convertit aussi une liste en JSON. Le titre apparaît dans la page de documentation à `/docs`.
{{< /solution >}}

### Exercice 5: Swagger UI

1. Qu'y a-t-il à l'adresse `http://127.0.0.1:8000/docs` ?
2. Comment l'utiliser pour tester une route ?

{{< solution >}}
1. **Swagger UI** — une page de documentation que FastAPI construit **automatiquement** à partir du code : toutes les routes, la méthode de chacune, les paramètres et les réponses.
2. Ouvrez une route, cliquez sur **Try it out**, remplissez les paramètres s'il y en a, et cliquez sur **Execute**. Vous voyez la requête envoyée, le code d'état et le corps de la réponse — sans écrire de client.
{{< /solution >}}

<!-- exercises:end -->

## Résumé

- **FastAPI** = un framework dans lequel on définit des routes. **Uvicorn** = le serveur HTTP qui écoute sur le port et transmet les requêtes à FastAPI.
- **venv** : `python -m venv .venv`, l'activer (`Activate.ps1` / `source .venv/bin/activate`), puis `pip install "fastapi[standard]"`. Dans chaque nouveau terminal, activez-le à nouveau.
- `app = FastAPI()` = l'objet application. **`@app.get("/path")`** enregistre une fonction comme gestionnaire de `GET /path`.
- Renvoyez un dict ou une liste, et FastAPI le convertit en JSON avec 200. Un chemin qui n'existe pas reçoit automatiquement un 404.
- Le lancement : **`uvicorn main:app --reload`** (`fichier:variable`), depuis le dossier du fichier. Arrêter : `Ctrl + C`.
- **`/docs`** = une documentation et des tests interactifs et automatiques.
- `.venv/` dans `.gitignore`. `requirements.txt` dans Git.

<!-- docs:start — generated by scripts/intro6/site_docs.py; edit the links there -->

## Documentation officielle

- [FastAPI — Virtual Environments](https://fastapi.tiangolo.com/virtual-environments/)
- [FastAPI — First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/)
- [FastAPI — Interactive API docs](https://fastapi.tiangolo.com/tutorial/first-steps/#interactive-api-docs)

<!-- docs:end -->
