# Path Params, Query Parameters et Body<no value>

## Qu'allons-nous apprendre ?

Un client doit dire au serveur **ce qu'il** veut exactement. Il a trois façons de le faire :

| Façon | Où | Exemple |
|---|---|---|
| **Path Parameter** | Une partie du chemin lui-même | `/students/7` |
| **Query Parameters** | Après `?` dans l'URL | `/students?city=Haifa&limit=10` |
| **Body** | Dans le corps de la requête (JSON) | `{"name": "Dana", "age": 24}` |

## Pourquoi en avons-nous besoin ?

Dans la leçon suivante, nous écrirons le premier serveur, et dans FastAPI chacun des trois se définit d'une façon différente. Si vous ne comprenez pas la différence, vous mettez l'information au mauvais endroit : un identifiant dans le body, ou un mot de passe dans l'URL. Et toute vraie API que vous utiliserez (GitHub, météo, paiements) utilise les trois.

## Explication à partir des bases

### Path Parameter — « lequel ? »

Une partie **variable** dans le chemin, qui identifie **une ressource précise** :

```text
GET /students/7
              └─ path parameter: which student
GET /users/octocat/repos
           └─ path parameter: which user
```

**Quand :** quand on identifie **un seul élément** (généralement par son id). Sans le paramètre, le chemin n'est pas complet.

### Query Parameters — « comment ? combien ? filtré par quoi ? »

Des paires `key=value` après `?`, séparées par `&` :

```text
GET /students?city=Haifa&min_age=20&limit=10
             └──────────── query string ────────┘
                key=value & key=value & key=value
```

**Quand :** le **filtrage**, le **tri**, la **pagination** (Pagination), et les **options**. Généralement **facultatifs** : `GET /students` fonctionne aussi sans eux, et renvoie simplement tout.

### Body — « voici les données »

Les données elles-mêmes, dans le corps de la requête, presque toujours en **JSON** :

```text
POST /students
Content-Type: application/json

{"name": "Dana", "age": 24, "email": "dana@mail.com"}
```

**Quand :** quand on **envoie des données** pour créer ou mettre à jour (POST, PUT). On peut envoyer des structures complexes (listes, objets imbriqués) et de grandes quantités. **GET et DELETE n'ont pas de body.**

### Comment décider ?

| Question | Façon |
|---|---|
| Identifie **quel** élément ? | **Path** — `/students/7` |
| Filtre, trie, limite la quantité, une option d'affichage ? | **Query** — `?city=Haifa&sort=age` |
| **Les données** d'une ressource que l'on crée ou met à jour ? | **Body** — JSON |
| Une information sensible (un mot de passe, un jeton) ? | **Jamais dans l'URL** (elle est enregistrée dans les journaux et dans l'historique du navigateur). Le body ou les en-têtes |

{{< box "analogy" "Analogie : commander une pizza par téléphone" >}}
« J'appelle **la succursale de Haïfa** » (**Path** : quel endroit exactement). « Dites-moi les offres, **végan uniquement**, **les moins chères d'abord** » (**Query** : filtrage et tri de ce que je demande). « Je veux commander : **une pizza familiale, olives, champignons, au 10 rue Herzl** » (**Body** : tous les détails de ce qui est créé).
{{< /box >}}

### L'encodage d'URL (URL Encoding)

Dans une URL, les espaces et les caractères spéciaux ne sont pas autorisés « tels quels ». Un espace devient `%20` (ou `+`), un `&` dans une valeur devient `%26`, et les lettres non anglaises (comme l'hébreu ou les lettres accentuées) sont encodées en octets (`%D7%93...`). Le navigateur et les bibliothèques font l'encodage pour nous — mais il est important de comprendre pourquoi il existe.

## Décomposer une adresse

```text
/students/7/grades?semester=2&limit=5

path   ->  students / 7 / grades   (the grades of student 7)
query  ->  semester = 2            (a filter)
           limit    = 5            (how many)
```

- Le **Path** identifie **quelle** ressource : les notes de l'étudiant 7.
- La **Query** commence après `?`, et chaque paramètre est séparé par `&`. Elle dit **comment** : quel semestre, et combien de résultats.

## Les trois dans une seule requête

```text
PUT /students/7?notify=true
Content-Type: application/json

{"name": "Dana Cohen", "age": 25}
```

| Partie | Valeur | Pourquoi ici |
|---|---|---|
| Path | `7` | **Quel** étudiant — fait partie de l'identité de la ressource |
| Query | `notify=true` | **Une option** de la requête — ne fait pas partie des données |
| Body | `{"name": ..., "age": ...}` | **Les nouvelles données** elles-mêmes |
| Header | `Content-Type: application/json` | **Dans quel format** est le corps |

Dans la leçon suivante, nous verrons comment FastAPI reçoit les trois automatiquement — et place chacun dans un paramètre de notre fonction.

## Erreur courante

**Erreur 1 : un identifiant dans la query au lieu du chemin, ou l'inverse.**

```text
GET /students?id=7          ← works, but not the convention for ONE resource
GET /students/city/Haifa    ← "Haifa" is a filter, not a resource id
```

La convention : **un élément précis dans le chemin** (`/students/7`), **le filtrage dans la query** (`/students?city=Haifa`).

**Erreur 2 : une valeur avec des espaces et un `&` « telle quelle » dans l'adresse.**

```text
/search?q=rock & roll
```

Les espaces cassent l'adresse, et le `&` est interprété comme le début d'un nouveau paramètre. La valeur doit être **encodée** : `q=rock+%26+roll`.

**Erreur 3 : oublier que tout ce qui est dans l'URL est une chaîne.** `"7"` ≠ `7`. Une comparaison `if student_id == 7` quand `student_id` est arrivé de l'URL sous forme de `"7"` → `False`. (FastAPI fera la conversion pour nous, si nous définissons un type.)

**Erreur 4 : des informations sensibles dans l'URL.** `GET /login?user=dana&password=1234`. L'URL est enregistrée dans l'historique du navigateur, dans les journaux du serveur, et dans les liens que vous envoyez. Les mots de passe : **uniquement dans le body** (et toujours en HTTPS).

<!-- 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: Où va chaque donnée ?

Pour chaque requête — la donnée est-elle un Path Parameter, un Query Parameter ou un body ?

1. L'identifiant de l'étudiant que vous voulez obtenir.
2. Filtrer les étudiants par ville.
3. Le nom et l'âge d'un nouvel étudiant.
4. Combien de résultats renvoyer par page.
5. Les données mises à jour d'un étudiant existant.

{{< solution >}}
1. **Path** — identifie **quelle** ressource : `/students/7`.
2. **Query** — le filtrage : `/students?city=Haifa`.
3. **Body** — les données d'une nouvelle ressource, en JSON.
4. **Query** — une option : `?limit=10`.
5. **Body** (et l'identifiant dans le **Path**) : `PUT /students/7` avec un corps.

La règle : **Path** — quelle ressource. **Query** — filtrage, tri et pages. **Body** — les données elles-mêmes.
{{< /solution >}}

### Exercice 2: Décomposer une adresse

Décomposez l'adresse : quel est le chemin, quel est l'identifiant qu'il contient, et quels sont les Query Parameters ?

```text
https://api.kodkod.dev/students/7/grades?semester=2&limit=5
```

{{< solution >}}
| Partie | Valeur | Signification |
|---|---|---|
| Path | `/students/7/grades` | Les notes de l'étudiant 7 |
| Identifiant dans le Path | `7` | **Quel** étudiant |
| Query | `semester=2` | Un filtre — le semestre 2 |
| Query | `limit=5` | Combien de résultats — 5 |

La query commence après `?`, et chaque paramètre est séparé par `&`.
{{< /solution >}}

### Exercice 3: Construire une adresse

Écrivez les adresses des requêtes suivantes, vers le serveur `https://api.x.com` :

1. Tous les étudiants de Haïfa.
2. Les étudiants de Haïfa, les dix premiers.
3. L'étudiant 7.
4. Les notes de l'étudiant 7 au semestre 1.

{{< solution >}}
```text
1. https://api.x.com/students?city=Haifa
2. https://api.x.com/students?city=Haifa&limit=10
3. https://api.x.com/students/7
4. https://api.x.com/students/7/grades?semester=1
```

L'identifiant va **dans le chemin**, et les filtres **dans la query** — après `?`, et reliés par `&`.
{{< /solution >}}

### Exercice 4: Les trois dans une seule requête

```text
PUT /students/7?notify=true
Content-Type: application/json

{"name": "Dana Cohen", "age": 25}
```

Identifiez le Path Parameter, le Query Parameter et le body, et expliquez pourquoi chaque donnée est à sa place. Quel est le rôle de l'en-tête `Content-Type` ?

{{< solution >}}
- **Path :** `7` — **quel** étudiant est mis à jour. Cela fait partie de l'identité de la ressource.
- **Query :** `notify=true` — **une option** de la requête : comment l'effectuer. Cela ne fait pas partie des données de l'étudiant.
- **Body :** `{"name": "Dana Cohen", "age": 25}` — **les nouvelles données** elles-mêmes.
- **`Content-Type: application/json`** — dit au serveur **dans quel format** est le corps, pour qu'il sache comment le lire.
{{< /solution >}}

### Exercice 5: Qu'est-ce qui ne va pas dans l'adresse ?

Pour chaque adresse — quel est le problème, et comment faire correctement ?

```text
1. GET /students?id=7
2. GET /students/city/Haifa
3. GET /login?user=dana&password=1234
4. GET /search?q=rock & roll
```

{{< solution >}}
1. **L'identifiant d'un seul élément va dans le chemin** : `GET /students/7`. La query est destinée au filtrage.
2. **« Haifa » est un filtre, pas l'identifiant d'une ressource** : `GET /students?city=Haifa`.
3. **Un mot de passe dans l'adresse** est enregistré dans l'historique du navigateur, dans les journaux du serveur et dans les liens que vous envoyez. Les mots de passe — **uniquement dans le body**, et toujours en HTTPS.
4. **Des espaces et un `&` dans une valeur** cassent l'adresse : le `&` est interprété comme le début d'un nouveau paramètre. La valeur doit être **encodée** (URL Encoding) : `q=rock+%26+roll`. En pratique, le navigateur et les bibliothèques font l'encodage pour nous.
{{< /solution >}}

<!-- exercises:end -->

## Résumé

- **Path Parameter** (`/students/7`) — **quelle** ressource. Fait partie du chemin.
- **Query Parameters** (`?city=Haifa&limit=10`) — **filtrage, tri, pagination, options**. Généralement facultatifs.
- **Body** (JSON) — **les données** pour créer et mettre à jour (POST, PUT). GET et DELETE n'ont pas de body.
- Tout ce qui est dans l'URL est une **chaîne**. Une query doit être correctement encodée (espaces, `&` et lettres non anglaises).
- Ne mettez pas de mots de passe ni d'informations sensibles dans l'URL.
- Dans les leçons suivantes, FastAPI décodera les trois automatiquement, y compris la conversion des types.

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

## Documentation officielle

- [MDN — What is a URL?](https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Web_mechanics/What_is_a_URL)
- [MDN — HTTP messages: Body](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Messages#request_body)

<!-- docs:end -->
