Sync fastapi docs from 7cb06f36 on 2026-07-11
This commit is contained in:
@@ -148,7 +148,7 @@ Du texte
|
||||
|
||||
//// tab | Info
|
||||
|
||||
Les onglets et les blocs « Info »/« Note »/« Warning »/etc. doivent avoir la traduction de leur titre ajoutée après une barre verticale (« | »).
|
||||
Les onglets et les blocs « Info »/« Note »/« Warning »/etc. doivent avoir la traduction de leur titre ajoutée après une barre verticale (`|`).
|
||||
|
||||
Voir les sections `### Special blocks` et `### Tab blocks` dans l’invite générale dans `scripts/translate.py`.
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ Gardez à l'esprit que vous devez renvoyer directement `JSONResponse`.
|
||||
|
||||
///
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
La clé `model` ne fait pas partie d'OpenAPI.
|
||||
|
||||
@@ -183,7 +183,7 @@ Notez que vous devez retourner l'image en utilisant directement un `FileResponse
|
||||
|
||||
///
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
À moins que vous ne spécifiiez explicitement un type de média différent dans votre paramètre `responses`, FastAPI supposera que la réponse a le même type de média que la classe de réponse principale (par défaut `application/json`).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Codes HTTP supplémentaires { #additional-status-codes }
|
||||
|
||||
Par défaut, **FastAPI** renverra les réponses à l'aide d'une structure de données `JSONResponse`, en plaçant la réponse de votre *chemin d'accès* à l'intérieur de cette `JSONResponse`.
|
||||
Par défaut, **FastAPI** renverra les réponses en utilisant une `JSONResponse`, en plaçant le contenu que vous renvoyez depuis votre *chemin d'accès* à l'intérieur de cette `JSONResponse`.
|
||||
|
||||
Il utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *chemin d'accès*.
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Nous pouvons créer une instance de cette classe avec :
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}
|
||||
|
||||
Et de cette façon, nous pouvons « paramétrer » notre dépendance, qui contient maintenant « bar », en tant qu’attribut `checker.fixed_content`.
|
||||
Et de cette façon, nous pouvons « paramétrer » notre dépendance, qui contient maintenant `"bar"`, en tant qu’attribut `checker.fixed_content`.
|
||||
|
||||
## Utiliser l'instance comme dépendance { #use-the-instance-as-a-dependency }
|
||||
|
||||
@@ -78,7 +78,7 @@ Les dépendances avec `yield` ont évolué au fil du temps pour couvrir différe
|
||||
|
||||
### Dépendances avec `yield` et `scope` { #dependencies-with-yield-and-scope }
|
||||
|
||||
Dans la version 0.121.0, **FastAPI** a ajouté la prise en charge de `Depends(scope="function")` pour les dépendances avec `yield`.
|
||||
Dans la version 0.121.0, FastAPI a ajouté la prise en charge de `Depends(scope="function")` pour les dépendances avec `yield`.
|
||||
|
||||
Avec `Depends(scope="function")`, le code d’arrêt après `yield` s’exécute immédiatement après la fin de la *fonction de chemin d'accès*, avant que la réponse ne soit renvoyée au client.
|
||||
|
||||
@@ -98,7 +98,7 @@ Par exemple, si vous aviez une session de base de données dans une dépendance
|
||||
|
||||
Ce comportement a été annulé en 0.118.0, afin que le code d’arrêt après `yield` s’exécute après l’envoi de la réponse.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Comme vous le verrez ci‑dessous, c’est très similaire au comportement avant la version 0.106.0, mais avec plusieurs améliorations et corrections de bogues pour des cas limites.
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Pour renvoyer une réponse avec du HTML directement depuis **FastAPI**, utilisez
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Le paramètre `response_class` sera aussi utilisé pour définir le « media type » de la réponse.
|
||||
|
||||
@@ -65,7 +65,7 @@ Une `Response` renvoyée directement par votre *fonction de chemin d'accès* ne
|
||||
|
||||
///
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Bien sûr, l'en-tête `Content-Type` réel, le code d'état, etc., proviendront de l'objet `Response` que vous avez renvoyé.
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Mais FastAPI prend aussi en charge l'utilisation de [`dataclasses`](https://docs
|
||||
|
||||
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
|
||||
|
||||
Cela fonctionne grâce à **Pydantic**, qui offre une [prise en charge interne des `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).
|
||||
C'est toujours pris en charge grâce à **Pydantic**, qui offre une [prise en charge interne des `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).
|
||||
|
||||
Ainsi, même avec le code ci‑dessus qui n'emploie pas explicitement Pydantic, FastAPI utilise Pydantic pour convertir ces dataclasses standard en la variante de dataclasses de Pydantic.
|
||||
|
||||
@@ -18,9 +18,9 @@ Et bien sûr, cela prend en charge la même chose :
|
||||
|
||||
Cela fonctionne de la même manière qu'avec les modèles Pydantic. Et, en réalité, c'est mis en œuvre de la même façon en interne, en utilisant Pydantic.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Gardez à l'esprit que les dataclasses ne peuvent pas tout ce que peuvent faire les modèles Pydantic.
|
||||
Gardez à l'esprit que les dataclasses ne peuvent pas faire tout ce que peuvent faire les modèles Pydantic.
|
||||
|
||||
Vous pourriez donc avoir encore besoin d'utiliser des modèles Pydantic.
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ Ces fonctions peuvent être déclarées avec `async def` ou un `def` normal.
|
||||
|
||||
### Événement `startup` { #startup-event }
|
||||
|
||||
Pour ajouter une fonction qui doit être exécutée avant le démarrage de l'application, déclarez-la avec l'événement « startup » :
|
||||
Pour ajouter une fonction qui doit être exécutée avant le démarrage de l'application, déclarez-la avec l'événement `"startup"` :
|
||||
|
||||
{* ../../docs_src/events/tutorial001_py310.py hl[8] *}
|
||||
|
||||
@@ -114,13 +114,13 @@ Et votre application ne commencera pas à recevoir des requêtes avant que tous
|
||||
|
||||
### Événement `shutdown` { #shutdown-event }
|
||||
|
||||
Pour ajouter une fonction qui doit être exécutée lorsque l'application s'arrête, déclarez-la avec l'événement « shutdown » :
|
||||
Pour ajouter une fonction qui doit être exécutée lorsque l'application s'arrête, déclarez-la avec l'événement `"shutdown"` :
|
||||
|
||||
{* ../../docs_src/events/tutorial002_py310.py hl[6] *}
|
||||
|
||||
Ici, la fonction gestionnaire de l'événement `shutdown` écrira une ligne de texte « Application shutdown » dans un fichier `log.txt`.
|
||||
Ici, la fonction gestionnaire de l'événement `shutdown` écrira une ligne de texte `"Application shutdown"` dans un fichier `log.txt`.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Dans la fonction `open()`, le `mode="a"` signifie « append » (ajouter) ; la ligne sera donc ajoutée après ce qui se trouve déjà dans ce fichier, sans écraser le contenu précédent.
|
||||
|
||||
@@ -152,7 +152,7 @@ Juste un détail technique pour les nerds curieux. 🤓
|
||||
|
||||
Sous le capot, dans la spécification technique ASGI, cela fait partie du [protocole Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), et il y définit des événements appelés `startup` et `shutdown`.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Vous pouvez en lire plus sur les gestionnaires `lifespan` de Starlette dans la [documentation « Lifespan » de Starlette](https://www.starlette.dev/lifespan/).
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Générer des SDK { #generating-sdks }
|
||||
# Générer des SDKs { #generating-sdks }
|
||||
|
||||
Parce que **FastAPI** est basé sur la spécification **OpenAPI**, ses API peuvent être décrites dans un format standard compris par de nombreux outils.
|
||||
|
||||
@@ -20,21 +20,6 @@ FastAPI génère automatiquement des spécifications **OpenAPI 3.1**, donc tout
|
||||
|
||||
///
|
||||
|
||||
## Générateurs de SDK par les sponsors de FastAPI { #sdk-generators-from-fastapi-sponsors }
|
||||
|
||||
Cette section met en avant des solutions **soutenues par des fonds** et **par des entreprises** qui sponsorisent FastAPI. Ces produits offrent **des fonctionnalités supplémentaires** et **des intégrations** en plus de SDK de haute qualité générés.
|
||||
|
||||
En ✨ [**sponsorisant FastAPI**](../help-fastapi.md#sponsor-the-author) ✨, ces entreprises contribuent à garantir que le framework et son **écosystème** restent sains et **durables**.
|
||||
|
||||
Leur sponsoring démontre également un fort engagement envers la **communauté** FastAPI (vous), montrant qu’elles se soucient non seulement d’offrir un **excellent service**, mais aussi de soutenir un **framework robuste et florissant**, FastAPI. 🙇
|
||||
|
||||
Par exemple, vous pourriez essayer :
|
||||
|
||||
* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)
|
||||
* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)
|
||||
|
||||
Certaines de ces solutions peuvent aussi être open source ou proposer des niveaux gratuits, afin que vous puissiez les essayer sans engagement financier. D’autres générateurs de SDK commerciaux existent et peuvent être trouvés en ligne. 🤓
|
||||
|
||||
## Créer un SDK TypeScript { #create-a-typescript-sdk }
|
||||
|
||||
Commençons par une application FastAPI simple :
|
||||
@@ -57,7 +42,7 @@ Ces mêmes informations issues des modèles, incluses dans OpenAPI, peuvent êtr
|
||||
|
||||
### Hey API { #hey-api }
|
||||
|
||||
Une fois que vous avez une application FastAPI avec les modèles, vous pouvez utiliser Hey API pour générer un client TypeScript. Le moyen le plus rapide de le faire est via npx.
|
||||
Une fois que nous avons une application FastAPI avec les modèles, nous pouvons utiliser Hey API pour générer un client TypeScript. Le moyen le plus rapide de le faire est via npx.
|
||||
|
||||
```sh
|
||||
npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
|
||||
|
||||
@@ -4,7 +4,7 @@ Si votre application doit recevoir et envoyer des données JSON, mais que vous d
|
||||
|
||||
## Base64 vs fichiers { #base64-vs-files }
|
||||
|
||||
Envisagez d'abord d'utiliser [Fichiers de requête](../tutorial/request-files.md) pour téléverser des données binaires et [Réponse personnalisée - FileResponse](./custom-response.md#fileresponse--fileresponse-) pour envoyer des données binaires, plutôt que de les encoder dans du JSON.
|
||||
Envisagez d'abord d'utiliser [Fichiers de requête](../tutorial/request-files.md) pour téléverser des données binaires et [Réponse personnalisée - FileResponse](./custom-response.md#fileresponse) pour envoyer des données binaires, plutôt que de les encoder dans du JSON.
|
||||
|
||||
JSON ne peut contenir que des chaînes encodées en UTF-8, il ne peut donc pas contenir d'octets bruts.
|
||||
|
||||
@@ -14,7 +14,7 @@ N'utilisez base64 que si vous devez absolument inclure des données binaires dan
|
||||
|
||||
## Pydantic `bytes` { #pydantic-bytes }
|
||||
|
||||
Vous pouvez déclarer un modèle Pydantic avec des champs `bytes`, puis utiliser `val_json_bytes` dans la configuration du modèle pour lui indiquer d'utiliser base64 pour valider les données JSON en entrée ; dans le cadre de cette validation, il décodera la chaîne base64 en octets.
|
||||
Vous pouvez déclarer un modèle Pydantic avec des champs `bytes`, puis utiliser `val_json_bytes` dans la configuration du modèle pour lui indiquer d'utiliser base64 pour *valider* les données JSON en entrée ; dans le cadre de cette validation, il décodera la chaîne base64 en octets.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}
|
||||
|
||||
@@ -52,12 +52,12 @@ Vous recevrez une réponse comme :
|
||||
|
||||
## Pydantic `bytes` pour les données de sortie { #pydantic-bytes-for-output-data }
|
||||
|
||||
Vous pouvez également utiliser des champs `bytes` avec `ser_json_bytes` dans la configuration du modèle pour les données de sortie ; Pydantic sérialisera alors les octets en base64 lors de la génération de la réponse JSON.
|
||||
Vous pouvez également utiliser des champs `bytes` avec `ser_json_bytes` dans la configuration du modèle pour les données de sortie ; Pydantic *sérialisera* alors les octets en base64 lors de la génération de la réponse JSON.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}
|
||||
|
||||
## Pydantic `bytes` pour les données d'entrée et de sortie { #pydantic-bytes-for-input-and-output-data }
|
||||
|
||||
Et bien sûr, vous pouvez utiliser le même modèle configuré pour utiliser base64 afin de gérer à la fois l'entrée (valider) avec `val_json_bytes` et la sortie (sérialiser) avec `ser_json_bytes` lors de la réception et de l'envoi de données JSON.
|
||||
Et bien sûr, vous pouvez utiliser le même modèle configuré pour utiliser base64 afin de gérer à la fois l'entrée (*valider*) avec `val_json_bytes` et la sortie (*sérialiser*) avec `ser_json_bytes` lors de la réception et de l'envoi de données JSON.
|
||||
|
||||
{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Callbacks OpenAPI { #openapi-callbacks }
|
||||
|
||||
Vous pourriez créer une API avec un *chemin d'accès* qui déclenche une requête vers une *API externe* créée par quelqu'un d'autre (probablement la même personne développeuse qui utiliserait votre API).
|
||||
Vous pourriez créer une API avec un *chemin d'accès* qui déclenche une requête vers une *API externe* créée par quelqu'un d'autre (probablement la même personne développeuse qui *utiliserait* votre API).
|
||||
|
||||
Le processus qui se produit lorsque votre application API appelle l’*API externe* s’appelle un « callback ». Parce que le logiciel écrit par la personne développeuse externe envoie une requête à votre API puis votre API « rappelle », en envoyant une requête à une *API externe* (probablement créée par la même personne développeuse).
|
||||
Le processus qui se produit lorsque votre application API appelle l’*API externe* s’appelle un « callback ». Parce que le logiciel écrit par la personne développeuse externe envoie une requête à votre API puis votre API *rappelle*, en envoyant une requête à une *API externe* (probablement créée par la même personne développeuse).
|
||||
|
||||
Dans ce cas, vous pourriez vouloir documenter à quoi cette API externe devrait ressembler. Quel *chemin d'accès* elle devrait avoir, quel corps elle devrait attendre, quelle réponse elle devrait renvoyer, etc.
|
||||
Dans ce cas, vous pourriez vouloir documenter à quoi cette API externe *devrait* ressembler. Quel *chemin d'accès* elle devrait avoir, quel corps elle devrait attendre, quelle réponse elle devrait renvoyer, etc.
|
||||
|
||||
## Une application avec des callbacks { #an-app-with-callbacks }
|
||||
|
||||
@@ -47,7 +47,7 @@ Le code réel du callback dépendra fortement de votre application API.
|
||||
|
||||
Et il variera probablement beaucoup d’une application à l’autre.
|
||||
|
||||
Cela pourrait être seulement une ou deux lignes de code, comme :
|
||||
Cela pourrait être seulement une ou deux lignes de code, comme :
|
||||
|
||||
```Python
|
||||
callback_url = "https://example.com/api/v1/invoices/events/"
|
||||
@@ -96,35 +96,35 @@ Commencez par créer un nouveau `APIRouter` qui contiendra un ou plusieurs callb
|
||||
|
||||
Pour créer le *chemin d'accès* du callback, utilisez le même `APIRouter` que vous avez créé ci-dessus.
|
||||
|
||||
Il devrait ressembler exactement à un *chemin d'accès* FastAPI normal :
|
||||
Il devrait ressembler exactement à un *chemin d'accès* FastAPI normal :
|
||||
|
||||
* Il devrait probablement déclarer le corps qu’il doit recevoir, par exemple `body: InvoiceEvent`.
|
||||
* Et il pourrait aussi déclarer la réponse qu’il doit renvoyer, par exemple `response_model=InvoiceEventReceived`.
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
|
||||
|
||||
Il y a 2 principales différences par rapport à un *chemin d'accès* normal :
|
||||
Il y a 2 principales différences par rapport à un *chemin d'accès* normal :
|
||||
|
||||
* Il n’a pas besoin d’avoir de code réel, car votre application n’appellera jamais ce code. Il sert uniquement à documenter l’*API externe*. La fonction peut donc simplement contenir `pass`.
|
||||
* Le *chemin* peut contenir une [expression OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (voir plus bas) où il peut utiliser des variables avec des paramètres et des parties de la requête originale envoyée à *votre API*.
|
||||
* Le *chemin* peut contenir une [expression OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (voir plus bas) où il peut utiliser des variables avec des paramètres et des parties de la requête originale envoyée à *votre API*.
|
||||
|
||||
### L’expression du chemin de callback { #the-callback-path-expression }
|
||||
|
||||
Le *chemin* du callback peut contenir une [expression OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) qui peut inclure des parties de la requête originale envoyée à *votre API*.
|
||||
Le *chemin* du callback peut contenir une [expression OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) qui peut inclure des parties de la requête originale envoyée à *votre API*.
|
||||
|
||||
Dans ce cas, c’est la `str` :
|
||||
Dans ce cas, c’est la `str` :
|
||||
|
||||
```Python
|
||||
"{$callback_url}/invoices/{$request.body.id}"
|
||||
```
|
||||
|
||||
Ainsi, si l’utilisateur de votre API (la personne développeuse externe) envoie une requête à *votre API* vers :
|
||||
Ainsi, si l’utilisateur de votre API (la personne développeuse externe) envoie une requête à *votre API* vers :
|
||||
|
||||
```
|
||||
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
|
||||
```
|
||||
|
||||
avec un corps JSON :
|
||||
avec un corps JSON :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -134,13 +134,13 @@ avec un corps JSON :
|
||||
}
|
||||
```
|
||||
|
||||
alors *votre API* traitera la facture et, à un moment ultérieur, enverra une requête de callback à `callback_url` (l’*API externe*) :
|
||||
alors *votre API* traitera la facture et, à un moment ultérieur, enverra une requête de callback à `callback_url` (l’*API externe*) :
|
||||
|
||||
```
|
||||
https://www.external.org/events/invoices/2expen51ve
|
||||
```
|
||||
|
||||
avec un corps JSON contenant quelque chose comme :
|
||||
avec un corps JSON contenant quelque chose comme :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -149,7 +149,7 @@ avec un corps JSON contenant quelque chose comme :
|
||||
}
|
||||
```
|
||||
|
||||
et elle s’attendra à une réponse de cette *API externe* avec un corps JSON comme :
|
||||
et elle s’attendrait à une réponse de cette *API externe* avec un corps JSON comme :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -167,13 +167,13 @@ Remarquez que l’URL de callback utilisée contient l’URL reçue en paramètr
|
||||
|
||||
À ce stade, vous avez le(s) *chemin(s) d'accès de callback* nécessaire(s) (celui/ceux que la *personne développeuse externe* doit implémenter dans l’*API externe*) dans le routeur de callback que vous avez créé ci-dessus.
|
||||
|
||||
Utilisez maintenant le paramètre `callbacks` dans *le décorateur de chemin d'accès de votre API* pour passer l’attribut `.routes` (qui est en fait juste une `list` de routes/*chemins d'accès*) depuis ce routeur de callback :
|
||||
Utilisez maintenant le paramètre `callbacks` dans *le décorateur de chemin d'accès de votre API* pour passer l’attribut `.routes` depuis ce routeur de callback :
|
||||
|
||||
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Remarquez que vous ne passez pas le routeur lui-même (`invoices_callback_router`) à `callback=`, mais l’attribut `.routes`, comme dans `invoices_callback_router.routes`.
|
||||
Remarquez que vous ne passez pas le routeur lui-même (`invoices_callback_router`) à `callbacks=`, mais son attribut `.routes`, comme dans `invoices_callback_router.routes`. FastAPI utilisera ces routes pour générer la documentation OpenAPI du callback.
|
||||
|
||||
///
|
||||
|
||||
@@ -181,6 +181,6 @@ Remarquez que vous ne passez pas le routeur lui-même (`invoices_callback_router
|
||||
|
||||
Vous pouvez maintenant démarrer votre application et aller sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
Vous verrez votre documentation incluant une section « Callbacks » pour votre *chemin d'accès* qui montre à quoi l’*API externe* devrait ressembler :
|
||||
Vous verrez votre documentation incluant une section « Callbacks » pour votre *chemin d'accès* qui montre à quoi l’*API externe* devrait ressembler :
|
||||
|
||||
<img src="/img/tutorial/openapi-callbacks/image01.png">
|
||||
|
||||
@@ -16,13 +16,13 @@ Et vos utilisateurs définissent aussi, d'une manière ou d'une autre (par exemp
|
||||
|
||||
Toute la logique de gestion des URL des webhooks et le code qui envoie effectivement ces requêtes vous incombent. Vous l'implémentez comme vous le souhaitez dans votre propre code.
|
||||
|
||||
## Documenter des webhooks avec FastAPI et OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }
|
||||
## Documenter des webhooks avec **FastAPI** et OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }
|
||||
|
||||
Avec FastAPI, en utilisant OpenAPI, vous pouvez définir les noms de ces webhooks, les types d'opérations HTTP que votre application peut envoyer (par exemple `POST`, `PUT`, etc.) et les corps des requêtes que votre application enverra.
|
||||
Avec **FastAPI**, en utilisant OpenAPI, vous pouvez définir les noms de ces webhooks, les types d'opérations HTTP que votre application peut envoyer (par exemple `POST`, `PUT`, etc.) et les **corps** des requêtes que votre application enverra.
|
||||
|
||||
Cela peut grandement faciliter la tâche de vos utilisateurs pour implémenter leurs API afin de recevoir vos requêtes de webhook ; ils pourront même peut-être générer automatiquement une partie de leur propre code d'API.
|
||||
Cela peut grandement faciliter la tâche de vos utilisateurs pour **implémenter leurs API** afin de recevoir vos requêtes de **webhook** ; ils pourront même peut-être générer automatiquement une partie de leur propre code d'API.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Les webhooks sont disponibles dans OpenAPI 3.1.0 et versions ultérieures, pris en charge par FastAPI `0.99.0` et versions ultérieures.
|
||||
|
||||
@@ -30,13 +30,13 @@ Les webhooks sont disponibles dans OpenAPI 3.1.0 et versions ultérieures, pris
|
||||
|
||||
## Créer une application avec des webhooks { #an-app-with-webhooks }
|
||||
|
||||
Lorsque vous créez une application FastAPI, il existe un attribut `webhooks` que vous pouvez utiliser pour définir des webhooks, de la même manière que vous définiriez des chemins d'accès, par exemple avec `@app.webhooks.post()`.
|
||||
Lorsque vous créez une application **FastAPI**, il existe un attribut `webhooks` que vous pouvez utiliser pour définir des webhooks, de la même manière que vous définiriez des chemins d'accès, par exemple avec `@app.webhooks.post()`.
|
||||
|
||||
{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}
|
||||
|
||||
Les webhooks que vous définissez apparaîtront dans le schéma OpenAPI et dans l'interface de documentation automatique.
|
||||
Les webhooks que vous définissez apparaîtront dans le schéma **OpenAPI** et dans l'**interface de documentation** automatique.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
L'objet `app.webhooks` est en fait simplement un `APIRouter`, le même type que vous utiliseriez pour structurer votre application en plusieurs fichiers.
|
||||
|
||||
@@ -50,6 +50,6 @@ C'est parce qu'on s'attend à ce que vos utilisateurs définissent, par un autre
|
||||
|
||||
Vous pouvez maintenant démarrer votre application et aller sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
Vous verrez que votre documentation contient les chemins d'accès habituels et désormais aussi des webhooks :
|
||||
Vous verrez que votre documentation contient les *chemins d'accès* habituels et désormais aussi des **webhooks** :
|
||||
|
||||
<img src="/img/tutorial/openapi-webhooks/image01.png">
|
||||
|
||||
@@ -16,17 +16,11 @@ Vous devez vous assurer qu’il est unique pour chaque opération.
|
||||
|
||||
### Utiliser le nom de la fonction de chemin d’accès comme operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer l’`operation_id` de chaque chemin d’accès en utilisant leur `APIRoute.name`.
|
||||
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez passer une fonction personnalisée `generate_unique_id_function` à `FastAPI`.
|
||||
|
||||
Vous devez le faire après avoir ajouté tous vos chemins d’accès.
|
||||
Cette fonction reçoit chaque `APIRoute` et renvoie l’`operationId` à utiliser pour ce chemin d’accès.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant cela.
|
||||
|
||||
///
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2,5:6,9] *}
|
||||
|
||||
/// warning | Alertes
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Pour ces cas, vous pouvez utiliser un paramètre `Response`.
|
||||
|
||||
## Utiliser un paramètre `Response` { #use-a-response-parameter }
|
||||
|
||||
Vous pouvez déclarer un paramètre de type `Response` dans votre fonction de chemin d'accès (comme vous pouvez le faire pour les cookies et les en-têtes).
|
||||
Vous pouvez déclarer un paramètre de type `Response` dans votre *fonction de chemin d'accès* (comme vous pouvez le faire pour les cookies et les en-têtes).
|
||||
|
||||
Vous pouvez ensuite définir le `status_code` dans cet objet de réponse *temporaire*.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Cookies de réponse { #response-cookies }
|
||||
|
||||
|
||||
## Utiliser un paramètre `Response` { #use-a-response-parameter }
|
||||
|
||||
Vous pouvez déclarer un paramètre de type `Response` dans votre *fonction de chemin d'accès*.
|
||||
|
||||
@@ -18,7 +18,7 @@ Vous aurez normalement une bien meilleure performance en utilisant un [Modèle d
|
||||
|
||||
Vous pouvez renvoyer une `Response` ou n'importe laquelle de ses sous-classes.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
`JSONResponse` est elle-même une sous-classe de `Response`.
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
## Utiliser un paramètre `Response` { #use-a-response-parameter }
|
||||
|
||||
Vous pouvez déclarer un paramètre de type `Response` dans votre fonction de chemin d'accès (comme vous pouvez le faire pour les cookies).
|
||||
Vous pouvez déclarer un paramètre de type `Response` dans votre *fonction de chemin d'accès* (comme vous pouvez le faire pour les cookies).
|
||||
|
||||
Vous pouvez ensuite définir des en-têtes dans cet objet de réponse temporaire.
|
||||
Vous pouvez ensuite définir des en-têtes dans cet objet de réponse *temporaire*.
|
||||
|
||||
{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}
|
||||
|
||||
@@ -12,7 +12,7 @@ Ensuite, vous pouvez renvoyer n'importe quel objet dont vous avez besoin, comme
|
||||
|
||||
Et si vous avez déclaré un `response_model`, il sera toujours utilisé pour filtrer et convertir l'objet que vous avez renvoyé.
|
||||
|
||||
**FastAPI** utilisera cette réponse temporaire pour extraire les en-têtes (ainsi que les cookies et le code de statut), et les placera dans la réponse finale qui contient la valeur que vous avez renvoyée, filtrée par tout `response_model`.
|
||||
**FastAPI** utilisera cette réponse *temporaire* pour extraire les en-têtes (ainsi que les cookies et le code de statut), et les placera dans la réponse finale qui contient la valeur que vous avez renvoyée, filtrée par tout `response_model`.
|
||||
|
||||
Vous pouvez également déclarer le paramètre `Response` dans des dépendances, et y définir des en-têtes (et des cookies).
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
Vous pouvez utiliser des scopes OAuth2 directement avec **FastAPI**, ils sont intégrés pour fonctionner de manière transparente.
|
||||
|
||||
Cela vous permettrait d’avoir un système d’autorisations plus fin, conforme au standard OAuth2, intégré à votre application OpenAPI (et à la documentation de l’API).
|
||||
Cela vous permettrait d’avoir un système d’autorisations plus fin, conforme au standard OAuth2, intégré à votre application OpenAPI (et aux documents de l’API).
|
||||
|
||||
OAuth2 avec scopes est le mécanisme utilisé par de nombreux grands fournisseurs d’authentification, comme Facebook, Google, GitHub, Microsoft, X (Twitter), etc. Ils l’utilisent pour fournir des permissions spécifiques aux utilisateurs et aux applications.
|
||||
|
||||
Chaque fois que vous « log in with » Facebook, Google, GitHub, Microsoft, X (Twitter), cette application utilise OAuth2 avec scopes.
|
||||
Chaque fois que vous utilisez « se connecter avec » Facebook, Google, GitHub, Microsoft, X (Twitter), cette application utilise OAuth2 avec scopes.
|
||||
|
||||
Dans cette section, vous verrez comment gérer l’authentification et l’autorisation avec le même OAuth2 avec scopes dans votre application **FastAPI**.
|
||||
|
||||
@@ -16,7 +16,7 @@ C’est une section plus ou moins avancée. Si vous débutez, vous pouvez la pas
|
||||
|
||||
Vous n’avez pas nécessairement besoin des scopes OAuth2, et vous pouvez gérer l’authentification et l’autorisation comme vous le souhaitez.
|
||||
|
||||
Mais OAuth2 avec scopes peut s’intégrer élégamment à votre API (avec OpenAPI) et à votre documentation d’API.
|
||||
Mais OAuth2 avec scopes peut s’intégrer élégamment à votre API (avec OpenAPI) et à vos documents d’API.
|
||||
|
||||
Néanmoins, c’est toujours à vous de faire appliquer ces scopes, ou toute autre exigence de sécurité/autorisation, selon vos besoins, dans votre code.
|
||||
|
||||
@@ -34,7 +34,7 @@ Le contenu de chacune de ces chaînes peut avoir n’importe quel format, mais n
|
||||
|
||||
Ces scopes représentent des « permissions ».
|
||||
|
||||
Dans OpenAPI (par ex. la documentation de l’API), vous pouvez définir des « schémas de sécurité ».
|
||||
Dans OpenAPI (par ex. les documents de l’API), vous pouvez définir des « schémas de sécurité ».
|
||||
|
||||
Lorsqu’un de ces schémas de sécurité utilise OAuth2, vous pouvez aussi déclarer et utiliser des scopes.
|
||||
|
||||
@@ -46,7 +46,7 @@ Ils sont généralement utilisés pour déclarer des permissions de sécurité s
|
||||
* `instagram_basic` est utilisé par Facebook / Instagram.
|
||||
* `https://www.googleapis.com/auth/drive` est utilisé par Google.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Dans OAuth2, un « scope » est simplement une chaîne qui déclare une permission spécifique requise.
|
||||
|
||||
@@ -74,7 +74,7 @@ Le paramètre `scopes` reçoit un `dict` avec chaque scope en clé et la descrip
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
|
||||
|
||||
Comme nous déclarons maintenant ces scopes, ils apparaîtront dans la documentation de l’API lorsque vous vous authentifiez/autorisez.
|
||||
Comme nous déclarons maintenant ces scopes, ils apparaîtront dans les documents de l’API lorsque vous vous authentifiez/autorisez.
|
||||
|
||||
Et vous pourrez sélectionner à quels scopes vous souhaitez accorder l’accès : `me` et `items`.
|
||||
|
||||
@@ -126,7 +126,7 @@ Nous le faisons ici pour montrer comment **FastAPI** gère des scopes déclarés
|
||||
|
||||
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}
|
||||
|
||||
/// info | Détails techniques
|
||||
/// note | Détails techniques
|
||||
|
||||
`Security` est en réalité une sous-classe de `Depends`, et elle n’a qu’un paramètre supplémentaire que nous verrons plus tard.
|
||||
|
||||
@@ -235,11 +235,11 @@ Elles seront vérifiées indépendamment pour chaque *chemin d’accès*.
|
||||
|
||||
## Tester { #check-it }
|
||||
|
||||
Si vous ouvrez la documentation de l’API, vous pouvez vous authentifier et spécifier quels scopes vous voulez autoriser.
|
||||
Si vous ouvrez les documents de l’API, vous pouvez vous authentifier et spécifier quels scopes vous voulez autoriser.
|
||||
|
||||
<img src="/img/tutorial/security/image11.png">
|
||||
|
||||
Si vous ne sélectionnez aucun scope, vous serez « authenticated », mais lorsque vous essayerez d’accéder à `/users/me/` ou `/users/me/items/`, vous obtiendrez une erreur indiquant que vous n’avez pas suffisamment de permissions. Vous pourrez toujours accéder à `/status/`.
|
||||
Si vous ne sélectionnez aucun scope, vous serez « authentifié », mais lorsque vous essayerez d’accéder à `/users/me/` ou `/users/me/items/`, vous obtiendrez une erreur indiquant que vous n’avez pas suffisamment de permissions. Vous pourrez toujours accéder à `/status/`.
|
||||
|
||||
Et si vous sélectionnez le scope `me` mais pas le scope `items`, vous pourrez accéder à `/users/me/` mais pas à `/users/me/items/`.
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ Pour l'instant, vous pouvez supposer que `get_settings()` est une fonction norma
|
||||
|
||||
///
|
||||
|
||||
Nous pouvons ensuite l'exiger depuis la fonction de chemin d'accès comme dépendance et l'utiliser où nous en avons besoin.
|
||||
Nous pouvons ensuite l'exiger depuis la *fonction de chemin d'accès* comme dépendance et l'utiliser où nous en avons besoin.
|
||||
|
||||
{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
Si vous voulez diffuser des données pouvant être structurées en JSON, vous devez [Diffuser des JSON Lines](../tutorial/stream-json-lines.md).
|
||||
|
||||
Mais si vous voulez diffuser des données binaires pures ou des chaînes, voici comment procéder.
|
||||
Mais si vous voulez **diffuser des données binaires pures** ou des chaînes, voici comment procéder.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Ajouté dans FastAPI 0.134.0.
|
||||
|
||||
@@ -14,7 +14,7 @@ Ajouté dans FastAPI 0.134.0.
|
||||
|
||||
Vous pouvez l'utiliser si vous souhaitez diffuser des chaînes pures, par exemple directement depuis la sortie d'un service d'**IA LLM**.
|
||||
|
||||
Vous pouvez également l'utiliser pour diffuser de gros fichiers binaires, en envoyant chaque bloc de données au fur et à mesure de la lecture, sans tout charger en mémoire d'un coup.
|
||||
Vous pouvez également l'utiliser pour diffuser de **gros fichiers binaires**, en envoyant chaque bloc de données au fur et à mesure de la lecture, sans tout charger en mémoire d'un coup.
|
||||
|
||||
Vous pouvez aussi diffuser de la **vidéo** ou de l'**audio** de cette manière ; cela peut même être généré au fil du traitement et de l'envoi.
|
||||
|
||||
@@ -26,7 +26,7 @@ Si vous déclarez un `response_class=StreamingResponse` dans votre *fonction de
|
||||
|
||||
FastAPI transmettra chaque bloc de données à la `StreamingResponse` tel quel ; il n'essaiera pas de le convertir en JSON ni autre chose similaire.
|
||||
|
||||
### Fonctions de chemin d'accès non async { #non-async-path-operation-functions }
|
||||
### *Fonctions de chemin d'accès* non async { #non-async-path-operation-functions }
|
||||
|
||||
Vous pouvez également utiliser des fonctions `def` classiques (sans `async`), et utiliser `yield` de la même manière.
|
||||
|
||||
@@ -40,7 +40,7 @@ Comme FastAPI n'essaiera pas de convertir les données en JSON avec Pydantic ni
|
||||
|
||||
{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}
|
||||
|
||||
Cela signifie aussi qu'avec `StreamingResponse` vous avez la liberté — et la responsabilité — de produire et d'encoder les octets de données exactement comme vous avez besoin de les envoyer, indépendamment des annotations de type. 🤓
|
||||
Cela signifie aussi qu'avec `StreamingResponse` vous avez la **liberté** et la **responsabilité** de produire et d'encoder les octets de données exactement comme vous avez besoin de les envoyer, indépendamment des annotations de type. 🤓
|
||||
|
||||
### Diffuser des bytes { #stream-bytes }
|
||||
|
||||
@@ -90,7 +90,7 @@ Par exemple, ils n'ont pas de `await file.read()`, ni de `async for chunk in fil
|
||||
|
||||
Et dans de nombreux cas, leur lecture serait une opération bloquante (pouvant bloquer la boucle d'événements), car ils sont lus depuis le disque ou le réseau.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
L'exemple ci-dessus est en réalité une exception, car l'objet `io.BytesIO` est déjà en mémoire ; sa lecture ne bloquera donc rien.
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ Si vous devez prendre en charge des clients qui n’envoient pas d’en-tête `C
|
||||
|
||||
Avec ce paramètre, les requêtes sans en-tête `Content-Type` verront leur corps analysé comme JSON, ce qui correspond au comportement des anciennes versions de FastAPI.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Ce comportement et cette configuration ont été ajoutés dans FastAPI 0.132.0.
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ Ils fonctionnent de la même manière que pour les autres endpoints/*chemins d'a
|
||||
|
||||
{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Comme il s'agit d'un WebSocket, il n'est pas vraiment logique de lever une `HTTPException`, nous levons plutôt une `WebSocketException`.
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
# Inclure WSGI - Flask, Django, autres { #including-wsgi-flask-django-others }
|
||||
|
||||
|
||||
Vous pouvez monter des applications WSGI comme vous l'avez vu avec [Sous-applications - Montages](sub-applications.md), [Derrière un proxy](behind-a-proxy.md).
|
||||
|
||||
Pour cela, vous pouvez utiliser `WSGIMiddleware` et l'utiliser pour envelopper votre application WSGI, par exemple Flask, Django, etc.
|
||||
|
||||
## Utiliser `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Cela nécessite l'installation de `a2wsgi`, par exemple avec `pip install a2wsgi`.
|
||||
|
||||
|
||||
@@ -39,19 +39,19 @@ premières idées qui a inspiré « la recherche de » **FastAPI**.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Django REST Framework a été créé par Tom Christie. Le créateur de Starlette et Uvicorn, sur lesquels **FastAPI** est basé.
|
||||
Django REST Framework a été créé par Tom Christie. Le même créateur de Starlette et Uvicorn, sur lesquels **FastAPI** est basé.
|
||||
|
||||
///
|
||||
|
||||
/// tip | A inspiré **FastAPI** à
|
||||
|
||||
Avoir une interface de documentation automatique de l'API.
|
||||
Avoir une interface utilisateur web de documentation automatique de l'API.
|
||||
|
||||
///
|
||||
|
||||
### [Flask](https://flask.palletsprojects.com) { #flask }
|
||||
|
||||
Flask est un « micro‑framework », il ne comprend pas d'intégrations de bases de données ni beaucoup de choses qui sont fournies par défaut dans Django.
|
||||
Flask est un « microframework », il ne comprend pas d'intégrations de bases de données ni beaucoup de choses qui sont fournies par défaut dans Django.
|
||||
|
||||
Cette simplicité et cette flexibilité permettent d'utiliser des bases de données NoSQL comme principal système de stockage de données.
|
||||
|
||||
@@ -60,22 +60,22 @@ technique par moments.
|
||||
|
||||
Il est aussi couramment utilisé pour d'autres applications qui n'ont pas nécessairement besoin d'une base de données, de gestion des utilisateurs ou de l'une des nombreuses fonctionnalités préinstallées dans Django. Bien que beaucoup de ces fonctionnalités puissent être ajoutées avec des plug-ins.
|
||||
|
||||
Ce découplage des parties, et le fait d'être un « micro‑framework » qui puisse être étendu pour couvrir exactement ce
|
||||
Ce découplage des parties, et le fait d'être un « microframework » qui puisse être étendu pour couvrir exactement ce
|
||||
qui est nécessaire, était une caractéristique clé que je voulais conserver.
|
||||
|
||||
Compte tenu de la simplicité de Flask, il semblait bien adapté à la création d'API. La prochaine chose à trouver était un « Django REST Framework » pour Flask.
|
||||
|
||||
/// tip | A inspiré **FastAPI** à
|
||||
|
||||
Être un micro‑framework. Il est donc facile de combiner les outils et les pièces nécessaires.
|
||||
Être un micro-framework. Il est donc facile de combiner les outils et les pièces nécessaires.
|
||||
|
||||
Proposer un système de routage simple et facile à utiliser.
|
||||
Proposer un système de routing simple et facile à utiliser.
|
||||
|
||||
///
|
||||
|
||||
### [Requests](https://requests.readthedocs.io) { #requests }
|
||||
|
||||
**FastAPI** n'est pas réellement une alternative à **Requests**. Leur cadre est très différent.
|
||||
**FastAPI** n'est pas réellement une alternative à **Requests**. Leur portée est très différente.
|
||||
|
||||
Il serait en fait plus courant d'utiliser Requests _à l'intérieur_ d'une application FastAPI.
|
||||
|
||||
@@ -85,7 +85,7 @@ Mais quand même, FastAPI s'est inspiré de Requests.
|
||||
|
||||
Ils sont, plus ou moins, aux extrémités opposées, se complétant l'un l'autre.
|
||||
|
||||
Requests a un design très simple et intuitif, il est très facile à utiliser, avec des valeurs par défaut raisonnables, tout en étant très puissant et personnalisable.
|
||||
Requests a un design très simple et intuitif, il est très facile à utiliser, avec des valeurs par défaut raisonnables. Mais en même temps, il est très puissant et personnalisable.
|
||||
|
||||
C'est pourquoi, comme le dit le site officiel :
|
||||
|
||||
@@ -97,7 +97,7 @@ La façon dont vous l'utilisez est très simple. Par exemple, pour faire une req
|
||||
response = requests.get("http://example.com/some/url")
|
||||
```
|
||||
|
||||
L’opération de chemin d'accès correspondante dans **FastAPI** pourrait ressembler à ceci :
|
||||
Le *chemin d'accès* d'API correspondant dans **FastAPI** pourrait ressembler à ceci :
|
||||
|
||||
```Python hl_lines="1"
|
||||
@app.get("/some/url")
|
||||
@@ -117,7 +117,7 @@ Notez les similitudes entre `requests.get(...)` et `@app.get(...)`.
|
||||
|
||||
### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }
|
||||
|
||||
La principale fonctionnalité que j'ai emprunté à Django REST Framework était la documentation automatique des API.
|
||||
La principale fonctionnalité que j'ai empruntée à Django REST Framework était la documentation automatique des API.
|
||||
|
||||
Puis j'ai découvert qu'il existait une norme pour documenter les API, en utilisant JSON (ou YAML, une extension de JSON) appelée Swagger.
|
||||
|
||||
@@ -132,12 +132,12 @@ C'est pourquoi, lorsqu'on parle de la version 2.0, il est courant de dire « Swa
|
||||
|
||||
Adopter et utiliser une norme ouverte pour les spécifications des API, au lieu d'un schéma personnalisé.
|
||||
|
||||
Intégrer des outils d'interface utilisateur basés sur des normes :
|
||||
Et intégrer des outils d'interface utilisateur basés sur des normes :
|
||||
|
||||
* [Swagger UI](https://github.com/swagger-api/swagger-ui)
|
||||
* [ReDoc](https://github.com/Rebilly/ReDoc)
|
||||
|
||||
Ces deux-là ont été choisis parce qu'ils sont populaires et stables, mais en faisant une recherche rapide, vous pourriez trouver des dizaines d'alternatives supplémentaires pour OpenAPI (que vous pouvez utiliser avec **FastAPI**).
|
||||
Ces deux-là ont été choisis parce qu'ils sont populaires et stables, mais en faisant une recherche rapide, vous pourriez trouver des dizaines d'interfaces utilisateur alternatives pour OpenAPI (que vous pouvez utiliser avec **FastAPI**).
|
||||
|
||||
///
|
||||
|
||||
@@ -149,14 +149,13 @@ permanents qui les rendent inadaptés.
|
||||
|
||||
### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }
|
||||
|
||||
L'une des principales fonctionnalités nécessaires aux systèmes API est la « <dfn title="aussi appelé : marshalling, conversion">sérialisation</dfn> » des données, qui consiste à prendre les données du code (Python) et à
|
||||
L'une des principales fonctionnalités nécessaires aux systèmes API est la « <dfn title="aussi appelé marshalling, conversion">sérialisation</dfn> » des données, qui consiste à prendre les données du code (Python) et à
|
||||
les convertir en quelque chose qui peut être envoyé sur le réseau. Par exemple, convertir un objet contenant des
|
||||
données provenant d'une base de données en un objet JSON. Convertir des objets `datetime` en strings, etc.
|
||||
|
||||
La validation des données est une autre fonctionnalité importante dont ont besoin les API. Elle permet de s'assurer
|
||||
que les données sont valides, compte tenu de certains paramètres. Par exemple, qu'un champ est un `int`, et non un
|
||||
string.
|
||||
Ceci est particulièrement utile pour les données entrantes.
|
||||
string. Ceci est particulièrement utile pour les données entrantes.
|
||||
|
||||
Sans un système de validation des données, vous devriez effectuer toutes les vérifications à la main, dans le code.
|
||||
|
||||
@@ -182,7 +181,7 @@ C'est un outil formidable et je l'ai beaucoup utilisé aussi, avant d'avoir **Fa
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Webargs a été créé par les développeurs de Marshmallow.
|
||||
Webargs a été créé par les mêmes développeurs de Marshmallow.
|
||||
|
||||
///
|
||||
|
||||
@@ -206,13 +205,13 @@ Et il génère des schémas OpenAPI.
|
||||
|
||||
C'est ainsi que cela fonctionne dans Flask, Starlette, Responder, etc.
|
||||
|
||||
Mais alors, nous avons à nouveau le problème d'avoir une micro-syntaxe, dans une docstring Python (un gros morceau de YAML).
|
||||
Mais alors, nous avons à nouveau le problème d'avoir une micro-syntaxe, dans une string Python (un gros morceau de YAML).
|
||||
|
||||
L'éditeur ne peut guère aider en la matière. Et si nous modifions les paramètres ou les schémas Marshmallow et que nous oublions de modifier également cette docstring YAML, le schéma généré deviendrait obsolète.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
APISpec a été créé par les développeurs de Marshmallow.
|
||||
APISpec a été créé par les mêmes développeurs de Marshmallow.
|
||||
|
||||
///
|
||||
|
||||
@@ -241,11 +240,11 @@ j'ai (ainsi que plusieurs équipes externes) utilisées jusqu'à présent :
|
||||
* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)
|
||||
* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)
|
||||
|
||||
Ces mêmes générateurs full-stack ont servi de base aux [Générateurs de projets pour **FastAPI**](project-generation.md).
|
||||
Et ces mêmes générateurs full-stack ont servi de base aux [Générateurs de projets **FastAPI**](project-generation.md).
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Flask-apispec a été créé par les développeurs de Marshmallow.
|
||||
Flask-apispec a été créé par les mêmes développeurs de Marshmallow.
|
||||
|
||||
///
|
||||
|
||||
@@ -284,9 +283,9 @@ C'était l'un des premiers frameworks Python extrêmement rapides basés sur `as
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
Il utilisait [`uvloop`](https://github.com/MagicStack/uvloop) au lieu du système par défaut de Python `asyncio`. C'est ce qui l'a rendu si rapide.
|
||||
Il utilisait [`uvloop`](https://github.com/MagicStack/uvloop) au lieu de la boucle par défaut de Python `asyncio`. C'est ce qui l'a rendu si rapide.
|
||||
|
||||
Il a clairement inspiré Uvicorn et Starlette, qui sont actuellement plus rapides que Sanic dans les benchmarks.
|
||||
Il a clairement inspiré Uvicorn et Starlette, qui sont actuellement plus rapides que Sanic dans les benchmarks ouverts.
|
||||
|
||||
///
|
||||
|
||||
@@ -304,7 +303,7 @@ Falcon est un autre framework Python haute performance, il est conçu pour être
|
||||
|
||||
Il est conçu pour avoir des fonctions qui reçoivent deux paramètres, une « requête » et une « réponse ». Ensuite, vous
|
||||
« lisez » des parties de la requête et « écrivez » des parties dans la réponse. En raison de cette conception, il n'est
|
||||
pas possible de déclarer des paramètres de requête et des corps avec des indications de type Python standard comme paramètres de fonction.
|
||||
pas possible de déclarer des paramètres de requête et des corps avec des annotations de type Python standard comme paramètres de fonction.
|
||||
|
||||
Ainsi, la validation, la sérialisation et la documentation des données doivent être effectuées dans le code, et non pas automatiquement. Ou bien elles doivent être implémentées comme un framework au-dessus de Falcon, comme Hug. Cette même distinction se retrouve dans d'autres frameworks qui s'inspirent de la conception de Falcon, qui consiste à avoir un objet de requête et un objet de réponse comme paramètres.
|
||||
|
||||
@@ -326,7 +325,7 @@ J'ai découvert Molten lors des premières étapes de développement de **FastAP
|
||||
* Validation et documentation via ces types.
|
||||
* Système d'injection de dépendances.
|
||||
|
||||
Il n'utilise pas une librairie tiers de validation, sérialisation et de documentation tel que Pydantic, il utilise son propre système. Ainsi, ces définitions de types de données ne sont pas réutilisables aussi facilement.
|
||||
Il n'utilise pas une librairie tierce de validation, sérialisation et de documentation telle que Pydantic, il utilise son propre système. Ainsi, ces définitions de types de données ne sont pas réutilisables aussi facilement.
|
||||
|
||||
Il nécessite une configuration un peu plus verbeuse. Et comme il est basé sur WSGI (au lieu d'ASGI), il n'est pas
|
||||
conçu pour profiter des hautes performances fournies par des outils comme Uvicorn, Starlette et Sanic.
|
||||
@@ -363,7 +362,7 @@ Comme il est basé sur l'ancienne norme pour les frameworks web Python synchrone
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Hug a été créé par Timothy Crosley, le créateur de [`isort`](https://github.com/timothycrosley/isort), un excellent outil pour trier automatiquement les imports dans les fichiers Python.
|
||||
Hug a été créé par Timothy Crosley, le même créateur de [`isort`](https://github.com/timothycrosley/isort), un excellent outil pour trier automatiquement les imports dans les fichiers Python.
|
||||
|
||||
///
|
||||
|
||||
@@ -388,11 +387,11 @@ et les requêtes que j'ai vues (avant NestJS et Molten). Je l'ai trouvé plus ou
|
||||
|
||||
Il disposait de la validation automatique, sérialisation des données et d'une génération de schéma OpenAPI basée sur les mêmes annotations de type à plusieurs endroits.
|
||||
|
||||
La définition du schéma de corps de requête n'utilisait pas les mêmes annotations de type Python que Pydantic, il était un peu plus proche de Marshmallow, donc le support de l'éditeur n'était pas aussi bon, mais APIStar était quand même la meilleure option disponible.
|
||||
Les définitions de schéma de corps n'utilisaient pas les mêmes annotations de type Python que Pydantic, c'était un peu plus proche de Marshmallow, donc le support de l'éditeur n'était pas aussi bon, mais APIStar était quand même la meilleure option disponible.
|
||||
|
||||
Il avait les meilleures performances d'après les benchmarks de l'époque (seulement surpassé par Starlette).
|
||||
|
||||
Au départ, il ne disposait pas d'une interface web de documentation automatique de l'API, mais je savais que je pouvais lui ajouter une interface Swagger.
|
||||
Au départ, il ne disposait pas d'une interface utilisateur web de documentation automatique de l'API, mais je savais que je pouvais lui ajouter Swagger UI.
|
||||
|
||||
Il avait un système d'injection de dépendances. Il nécessitait un pré-enregistrement des composants, comme d'autres outils discutés ci-dessus. Mais c'était quand même une excellente fonctionnalité.
|
||||
|
||||
@@ -422,7 +421,7 @@ L'idée de déclarer plusieurs choses (validation des données, sérialisation e
|
||||
|
||||
Et après avoir longtemps cherché un framework similaire et testé de nombreuses alternatives, APIStar était la meilleure option disponible.
|
||||
|
||||
Puis APIStar a cessé d'exister en tant que serveur et Starlette a été créé, et a constitué une meilleure base pour un tel système. Ce fut l'inspiration finale pour construire **FastAPI**.
|
||||
Puis APIStar a cessé d'exister en tant que serveur et Starlette a été créé, et a constitué une nouvelle base meilleure pour un tel système. Ce fut l'inspiration finale pour construire **FastAPI**.
|
||||
|
||||
Je considère **FastAPI** comme un « successeur spirituel » d'APIStar, tout en améliorant et en augmentant les fonctionnalités, le système de typage et d'autres parties, sur la base des enseignements tirés de tous ces outils précédents.
|
||||
|
||||
@@ -441,7 +440,7 @@ basé sur les mêmes annotations de type Python, le support de l'éditeur est gr
|
||||
|
||||
/// tip | **FastAPI** l'utilise pour
|
||||
|
||||
Gérer toute la validation des données, leur sérialisation et la documentation automatique du modèle (basée sur le schéma JSON).
|
||||
Gérer toute la validation des données, leur sérialisation et la documentation automatique du modèle (basée sur JSON Schema).
|
||||
|
||||
**FastAPI** prend ensuite ces données JSON Schema et les place dans OpenAPI, en plus de toutes les autres choses qu'il fait.
|
||||
|
||||
@@ -455,20 +454,20 @@ Il est très simple et intuitif. Il est conçu pour être facilement extensible
|
||||
|
||||
Il offre :
|
||||
|
||||
- Des performances vraiment impressionnantes.
|
||||
- Le support des WebSockets.
|
||||
- Les tâches d'arrière-plan.
|
||||
- Les événements de démarrage et d'arrêt.
|
||||
- Un client de test basé sur HTTPX.
|
||||
- CORS, GZip, fichiers statiques, streaming des réponses.
|
||||
- Le support des sessions et des cookies.
|
||||
- Une couverture de test à 100 %.
|
||||
- 100 % de la base de code avec des annotations de type.
|
||||
- Peu de dépendances strictes.
|
||||
* Des performances vraiment impressionnantes.
|
||||
* Le support de WebSocket.
|
||||
* Les tâches d'arrière-plan in-process.
|
||||
* Les événements de démarrage et d'arrêt.
|
||||
* Un client de test basé sur HTTPX.
|
||||
* CORS, GZip, fichiers statiques, streaming des réponses.
|
||||
* Le support des sessions et des cookies.
|
||||
* Une couverture de test à 100 %.
|
||||
* 100 % de la base de code avec des annotations de type.
|
||||
* Peu de dépendances strictes.
|
||||
|
||||
Starlette est actuellement le framework Python le plus rapide testé. Seulement dépassé par Uvicorn, qui n'est pas un framework, mais un serveur.
|
||||
|
||||
Starlette fournit toutes les fonctionnalités de base d'un micro‑framework web.
|
||||
Starlette fournit toutes les fonctionnalités de base d'un microframework web.
|
||||
|
||||
Mais il ne fournit pas de validation automatique des données, de sérialisation ou de documentation.
|
||||
|
||||
@@ -496,7 +495,7 @@ Ainsi, tout ce que vous pouvez faire avec Starlette, vous pouvez le faire direct
|
||||
|
||||
Uvicorn est un serveur ASGI rapide comme l'éclair, basé sur uvloop et httptools.
|
||||
|
||||
Il ne s'agit pas d'un framework web, mais d'un serveur. Par exemple, il ne fournit pas d'outils pour le routing. C'est
|
||||
Il ne s'agit pas d'un framework web, mais d'un serveur. Par exemple, il ne fournit pas d'outils pour le routing par chemins. C'est
|
||||
quelque chose qu'un framework comme Starlette (ou **FastAPI**) fournirait par-dessus.
|
||||
|
||||
C'est le serveur recommandé pour Starlette et **FastAPI**.
|
||||
|
||||
+100
-100
@@ -44,19 +44,19 @@ Si votre application (d'une certaine manière) n'a pas à communiquer avec une a
|
||||
|
||||
---
|
||||
|
||||
Si vous ne savez pas, utilisez seulement `def`.
|
||||
Si vous ne savez pas, utilisez un `def` normal.
|
||||
|
||||
---
|
||||
|
||||
Note : vous pouvez mélanger `def` et `async def` dans vos *fonctions de chemin d'accès* autant que nécessaire, et définir chacune avec l’option la plus adaptée pour vous. FastAPI fera ce qu'il faut avec elles.
|
||||
**Remarque** : vous pouvez mélanger `def` et `async def` dans vos *fonctions de chemin d'accès* autant que nécessaire, et définir chacune avec l’option la plus adaptée pour vous. FastAPI fera ce qu'il faut avec elles.
|
||||
|
||||
Au final, peu importe le cas parmi ceux ci-dessus, FastAPI fonctionnera de manière asynchrone et sera extrêmement rapide.
|
||||
|
||||
Mais si vous suivez bien les instructions ci-dessus, il pourra effectuer quelques optimisations et ainsi améliorer les performances.
|
||||
Mais si vous suivez bien les étapes ci-dessus, il pourra effectuer quelques optimisations de performance.
|
||||
|
||||
## Détails techniques { #technical-details }
|
||||
|
||||
Les versions modernes de Python supportent le **code asynchrone** grâce aux **« coroutines »** avec les syntaxes **`async` et `await`**.
|
||||
Les versions modernes de Python supportent le **« code asynchrone »** en utilisant quelque chose appelé **« coroutines »**, avec la syntaxe **`async` et `await`**.
|
||||
|
||||
Analysons les différentes parties de cette phrase dans les sections suivantes :
|
||||
|
||||
@@ -70,7 +70,7 @@ Faire du code asynchrone signifie que le langage 💬 est capable de dire à l'o
|
||||
|
||||
Donc, pendant ce temps, l'ordinateur pourra effectuer d'autres tâches, pendant que « slow-file » 📝 se termine.
|
||||
|
||||
Ensuite l'ordinateur / le programme 🤖 reviendra à chaque fois qu'il en a la chance que ce soit parce qu'il attend à nouveau, ou car il 🤖 a fini tout le travail qu'il avait à faire. Il 🤖 regardera donc si les tâches qu'il attend ont terminé d'être effectuées.
|
||||
Ensuite l'ordinateur / le programme 🤖 reviendra à chaque fois qu'il en a la chance, parce qu'il attend à nouveau, ou quand il 🤖 a fini tout le travail qu'il avait à faire à ce moment-là. Et il 🤖 regardera si des tâches qu'il attendait ont déjà terminé, en faisant ce qu'il devait faire.
|
||||
|
||||
Ensuite, il 🤖 prendra la première tâche à finir (disons, notre « slow-file » 📝) et continuera à faire avec cette dernière ce qu'il était censé.
|
||||
|
||||
@@ -80,18 +80,18 @@ Ce « attendre quelque chose d'autre » fait généralement référence à des o
|
||||
* de la donnée envoyée depuis votre programme soit reçue par le client à travers le réseau
|
||||
* le contenu d'un fichier sur le disque soit lu par le système et passé à votre programme
|
||||
* le contenu que votre programme a passé au système soit écrit sur le disque
|
||||
* une opération effectuée à distance par une API se termine
|
||||
* une opération effectuée à distance par une API
|
||||
* une opération en base de données se termine
|
||||
* une requête à une base de données renvoie un résultat
|
||||
* etc.
|
||||
|
||||
Le temps d'exécution étant consommé majoritairement par l'attente d'opérations <abbr title="Input and Output - Entrées et sorties">I/O</abbr>, on appelle ceci des opérations « I/O bound ».
|
||||
|
||||
Ce concept se nomme « asynchrone » car l'ordinateur / le programme n'a pas besoin d'être « synchronisé » avec la tâche, attendant le moment exact où cette dernière se terminera en ne faisant rien, pour être capable de récupérer le résultat de la tâche et l'utiliser dans la suite des opérations.
|
||||
Ce concept se nomme « asynchrone » car l'ordinateur / le programme n'a pas besoin d'être « synchronisé » avec la tâche lente, attendant le moment exact où cette dernière se terminera en ne faisant rien, pour être capable de récupérer le résultat de la tâche et l'utiliser dans la suite des opérations.
|
||||
|
||||
À la place, en étant « asynchrone », une fois terminée, une tâche peut légèrement attendre (quelques microsecondes) que l'ordinateur / le programme finisse ce qu'il était en train de faire, et revienne récupérer le résultat.
|
||||
À la place, en étant un système « asynchrone », une fois terminée, la tâche peut attendre un peu dans la file (quelques microsecondes) que l'ordinateur / le programme finisse ce qu'il était en train de faire, puis revienne récupérer les résultats et continue à travailler avec eux.
|
||||
|
||||
Pour parler de tâches « synchrones » (en opposition à « asynchrones »), on utilise souvent le terme « séquentiel », car l'ordinateur / le programme va effectuer toutes les étapes d'une tâche séquentiellement avant de passer à une autre tâche, même si ces étapes impliquent de l'attente.
|
||||
Pour parler de tâches « synchrones » (en opposition à « asynchrones »), on utilise souvent aussi le terme « séquentiel », car l'ordinateur / le programme va effectuer toutes les étapes d'une tâche séquentiellement avant de passer à une autre tâche, même si ces étapes impliquent de l'attente.
|
||||
|
||||
### Concurrence et Burgers { #concurrency-and-burgers }
|
||||
|
||||
@@ -99,49 +99,49 @@ L'idée de code **asynchrone** décrite ci-dessus est parfois aussi appelée **
|
||||
|
||||
La **concurrence** et le **parallélisme** sont tous deux liés à l'idée de « différentes choses arrivant plus ou moins au même moment ».
|
||||
|
||||
Mais les détails entre la **concurrence** et le **parallélisme** diffèrent sur de nombreux points.
|
||||
Mais les détails entre la *concurrence* et le *parallélisme* sont assez différents.
|
||||
|
||||
Pour expliquer la différence, voici une histoire de burgers :
|
||||
Pour expliquer la différence, imaginez l'histoire suivante à propos de burgers :
|
||||
|
||||
### Burgers concurrents { #concurrent-burgers }
|
||||
|
||||
Vous amenez votre crush 😍 dans votre fast food 🍔 favori, et faites la queue pendant que le serveur 💁 prend les commandes des personnes devant vous.
|
||||
Vous allez avec votre crush chercher de la nourriture dans un fast food, vous faites la queue pendant que le caissier prend les commandes des personnes devant vous. 😍
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-01.png" class="illustration">
|
||||
|
||||
Puis vient votre tour, vous commandez alors 2 magnifiques burgers 🍔 pour votre crush 😍 et vous.
|
||||
Puis vient votre tour, vous commandez alors 2 burgers très sophistiqués pour votre crush et vous. 🍔🍔
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-02.png" class="illustration">
|
||||
|
||||
Le serveur 💁 dit quelque chose à son collègue dans la cuisine 👨🍳 pour qu'il sache qu'il doit préparer vos burgers 🍔 (bien qu'il soit déjà en train de préparer ceux des clients précédents).
|
||||
Le caissier dit quelque chose au cuisinier dans la cuisine pour qu'il sache qu'il doit préparer vos burgers (bien qu'il soit déjà en train de préparer ceux des clients précédents).
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-03.png" class="illustration">
|
||||
|
||||
Vous payez 💸.
|
||||
Vous payez. 💸
|
||||
|
||||
Le serveur 💁 vous donne le numéro assigné à votre commande.
|
||||
Le caissier vous donne le numéro de votre tour.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-04.png" class="illustration">
|
||||
|
||||
Pendant que vous attendez, vous allez choisir une table avec votre crush 😍, vous discutez avec votre crush 😍 pendant un long moment (les burgers étant « magnifiques » ils sont très longs à préparer ✨🍔✨).
|
||||
Pendant que vous attendez, vous allez choisir une table avec votre crush, vous vous asseyez et discutez avec votre crush pendant un long moment (vos burgers étant très sophistiqués, ils prennent du temps à préparer).
|
||||
|
||||
Pendant que vous êtes assis à table, en attendant que les burgers 🍔 soient prêts, vous pouvez passer ce temps à admirer à quel point votre crush 😍 est géniale, mignonne et intelligente ✨😍✨.
|
||||
Pendant que vous êtes assis à table avec votre crush, en attendant les burgers, vous pouvez passer ce temps à admirer à quel point votre crush est géniale, mignonne et intelligente ✨😍✨.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-05.png" class="illustration">
|
||||
|
||||
Pendant que vous discutez avec votre crush 😍, de temps en temps vous jetez un coup d’œil au nombre affiché au-dessus du comptoir pour savoir si c'est à votre tour d'être servis.
|
||||
Pendant que vous attendez et discutez avec votre crush, de temps en temps, vous jetez un coup d’œil au nombre affiché au-dessus du comptoir pour savoir si c'est déjà votre tour.
|
||||
|
||||
Jusqu'au moment où c'est (enfin) votre tour. Vous allez au comptoir, récupérez vos burgers 🍔 et revenez à votre table.
|
||||
Puis, à un moment, c'est enfin votre tour. Vous allez au comptoir, récupérez vos burgers et revenez à votre table.
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-06.png" class="illustration">
|
||||
|
||||
Vous et votre crush 😍 mangez les burgers 🍔 et passez un bon moment ✨.
|
||||
Vous et votre crush mangez les burgers et passez un bon moment. ✨
|
||||
|
||||
<img src="/img/async/concurrent-burgers/concurrent-burgers-07.png" class="illustration">
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Illustrations proposées par [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨
|
||||
Belles illustrations par [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨
|
||||
|
||||
///
|
||||
|
||||
@@ -149,103 +149,103 @@ Illustrations proposées par [Ketrina Thompson](https://www.instagram.com/ketrin
|
||||
|
||||
Imaginez que vous êtes l'ordinateur / le programme 🤖 dans cette histoire.
|
||||
|
||||
Pendant que vous faites la queue, vous être simplement inactif 😴, attendant votre tour, ne faisant rien de « productif ». Mais la queue est rapide car le serveur 💁 prend seulement les commandes (et ne les prépare pas), donc tout va bien.
|
||||
Pendant que vous faites la queue, vous êtes simplement inactif 😴, attendant votre tour, ne faisant rien de très « productif ». Mais la queue est rapide car le caissier prend seulement les commandes (et ne les prépare pas), donc tout va bien.
|
||||
|
||||
Ensuite, quand c'est votre tour, vous faites des actions « productives » 🤓, vous étudiez le menu, décidez ce que vous voulez, demandez à votre crush 😍 son choix, payez 💸, vérifiez que vous utilisez la bonne carte de crédit, vérifiez que le montant débité sur la carte est correct, vérifiez que la commande contient les bons produits, etc.
|
||||
Ensuite, quand c'est votre tour, vous faites du vrai travail « productif », vous étudiez le menu, décidez ce que vous voulez, demandez à votre crush son choix, payez, vérifiez que vous donnez le bon billet ou la bonne carte, vérifiez que le montant débité est correct, vérifiez que la commande contient les bons produits, etc.
|
||||
|
||||
Mais ensuite, même si vous n'avez pas encore vos burgers 🍔, votre travail avec le serveur 💁 est « en pause » ⏸, car vous devez attendre 🕙 que vos burgers soient prêts.
|
||||
Mais ensuite, même si vous n'avez toujours pas vos burgers, votre travail avec le caissier est « en pause » ⏸, car vous devez attendre 🕙 que vos burgers soient prêts.
|
||||
|
||||
Après vous être écarté du comptoir et vous être assis à votre table avec le numéro de votre commande, vous pouvez tourner 🔀 votre attention vers votre crush 😍, et « travailler » ⏯ 🤓 là-dessus. Vous êtes donc à nouveau en train de faire quelque chose de « productif » 🤓, vous flirtez avec votre crush 😍.
|
||||
Mais lorsque vous vous écartez du comptoir et vous asseyez à table avec un numéro pour votre tour, vous pouvez tourner 🔀 votre attention vers votre crush, et « travailler » ⏯ 🤓 là-dessus. Vous êtes donc à nouveau en train de faire quelque chose de très « productif », comme flirter avec votre crush 😍.
|
||||
|
||||
Puis le serveur 💁 dit « J'ai fini de préparer les burgers » 🍔 en mettant votre numéro sur l'affichage du comptoir, mais vous ne courez pas immédiatement au moment où votre numéro s'affiche. Vous savez que personne ne volera vos burgers 🍔 car vous avez votre numéro et les autres clients ont le leur.
|
||||
Puis le caissier 💁 dit « J'ai fini de faire les burgers » en mettant votre numéro sur l'affichage du comptoir, mais vous ne sautez pas comme un fou immédiatement quand le numéro affiché change pour devenir votre numéro. Vous savez que personne ne volera vos burgers car vous avez le numéro de votre tour, et les autres ont le leur.
|
||||
|
||||
Vous attendez donc que votre crush 😍 finisse son histoire, souriez gentiment et dites que vous allez chercher les burgers ⏸.
|
||||
Vous attendez donc que votre crush finisse son histoire (termine le travail actuel ⏯ / la tâche en cours de traitement 🤓), souriez gentiment et dites que vous allez chercher les burgers ⏸.
|
||||
|
||||
Pour finir vous allez au comptoir 🔀, vers la tâche initiale qui est désormais terminée ⏯, récupérez les burgers 🍔, remerciez le serveur et ramenez les burgers 🍔 à votre table. Ceci termine l'étape / la tâche d'interaction avec le comptoir ⏹. Ce qui ensuite, crée une nouvelle tâche de « manger les burgers » 🔀 ⏯, mais la précédente, « récupérer les burgers » est terminée ⏹.
|
||||
Puis vous allez au comptoir 🔀, vers la tâche initiale qui est désormais terminée ⏯, récupérez les burgers, remerciez et ramenez les burgers à votre table. Ceci termine l'étape / la tâche d'interaction avec le comptoir ⏹. Ce qui ensuite crée une nouvelle tâche, « manger les burgers » 🔀 ⏯, mais la précédente, « récupérer les burgers », est terminée ⏹.
|
||||
|
||||
### Burgers parallèles { #parallel-burgers }
|
||||
|
||||
Imaginons désormais que ce ne sont pas des « burgers concurrents » mais des « burgers parallèles ».
|
||||
Imaginons désormais que ce ne sont pas des « Burgers concurrents » mais des « Burgers parallèles ».
|
||||
|
||||
Vous allez avec votre crush 😍 dans un fast food 🍔 parallélisé.
|
||||
Vous allez avec votre crush chercher de la nourriture dans un fast food parallèle.
|
||||
|
||||
Vous attendez pendant que plusieurs (disons 8) serveurs qui sont aussi des cuisiniers 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳 prennent les commandes des personnes devant vous.
|
||||
Vous attendez pendant que plusieurs (disons 8) caissiers qui sont en même temps cuisiniers prennent les commandes des personnes devant vous.
|
||||
|
||||
Chaque personne devant vous attend 🕙 que son burger 🍔 soit prêt avant de quitter le comptoir car chacun des 8 serveurs va lui-même préparer le burger directement avant de prendre la commande suivante.
|
||||
Chaque personne devant vous attend que son burger soit prêt avant de quitter le comptoir car chacun des 8 caissiers va préparer le burger directement avant de prendre la commande suivante.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-01.png" class="illustration">
|
||||
|
||||
Puis c'est enfin votre tour, vous commandez 2 magnifiques burgers 🍔 pour vous et votre crush 😍.
|
||||
Puis c'est enfin votre tour, vous commandez 2 burgers très sophistiqués pour vous et votre crush.
|
||||
|
||||
Vous payez 💸.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-02.png" class="illustration">
|
||||
|
||||
Le serveur va dans la cuisine 👨🍳.
|
||||
Le caissier va dans la cuisine.
|
||||
|
||||
Vous attendez devant le comptoir afin que personne ne prenne vos burgers 🍔 avant vous, vu qu'il n'y a pas de numéro de commande.
|
||||
Vous attendez, debout devant le comptoir 🕙, afin que personne d'autre ne prenne vos burgers avant vous, vu qu'il n'y a pas de numéros pour les tours.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-03.png" class="illustration">
|
||||
|
||||
Vous et votre crush 😍 étant occupés à vérifier que personne ne passe devant vous prendre vos burgers au moment où ils arriveront 🕙, vous ne pouvez pas vous préoccuper de votre crush 😞.
|
||||
Vous et votre crush étant occupés à ne laisser personne passer devant vous et prendre vos burgers au moment où ils arriveront, vous ne pouvez pas prêter attention à votre crush. 😞
|
||||
|
||||
C'est du travail « synchrone », vous être « synchronisés » avec le serveur/cuisinier 👨🍳. Vous devez attendre 🕙 et être présent au moment exact où le serveur/cuisinier 👨🍳 finira les burgers 🍔 et vous les donnera, sinon quelqu'un risque de vous les prendre.
|
||||
C'est du travail « synchrone », vous être « synchronisés » avec le caissier/cuisinier 👨🍳. Vous devez attendre 🕙 et être présent au moment exact où le caissier/cuisinier 👨🍳 finira les burgers et vous les donnera, sinon quelqu'un d'autre risque de vous les prendre.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-04.png" class="illustration">
|
||||
|
||||
Puis le serveur/cuisinier 👨🍳 revient enfin avec vos burgers 🍔, après un long moment d'attente 🕙 devant le comptoir.
|
||||
Puis votre caissier/cuisinier 👨🍳 revient enfin avec vos burgers, après un long moment d'attente 🕙 devant le comptoir.
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-05.png" class="illustration">
|
||||
|
||||
Vous prenez vos burgers 🍔 et allez à une table avec votre crush 😍
|
||||
Vous prenez vos burgers et allez à une table avec votre crush.
|
||||
|
||||
Vous les mangez, et vous avez terminé 🍔 ⏹.
|
||||
Vous les mangez simplement, et vous avez terminé. ⏹
|
||||
|
||||
<img src="/img/async/parallel-burgers/parallel-burgers-06.png" class="illustration">
|
||||
|
||||
Durant tout ce processus, il n'y a presque pas eu de discussions ou de flirts car la plupart de votre temps à été passé à attendre 🕙 devant le comptoir 😞.
|
||||
Il n'y a pas eu beaucoup de discussions ou de flirts car la plupart du temps a été passé à attendre 🕙 devant le comptoir. 😞
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Illustrations proposées par [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨
|
||||
Belles illustrations par [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨
|
||||
|
||||
///
|
||||
|
||||
---
|
||||
|
||||
Dans ce scénario de burgers parallèles, vous êtes un ordinateur / programme 🤖 avec deux processeurs (vous et votre crush 😍) attendant 🕙 à deux et dédiant votre attention ⏯ à « attendre devant le comptoir » 🕙 pour une longue durée.
|
||||
Dans ce scénario de burgers parallèles, vous êtes un ordinateur / programme 🤖 avec deux processeurs (vous et votre crush), tous deux attendant 🕙 et dédiant leur attention ⏯ à « attendre devant le comptoir » 🕙 pour une longue durée.
|
||||
|
||||
Le fast-food a 8 processeurs (serveurs/cuisiniers) 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳. Alors que le fast-food de burgers concurrents en avait 2 (un serveur et un cuisinier).
|
||||
Le fast food a 8 processeurs (caissiers/cuisiniers). Alors que le fast food de burgers concurrents aurait pu n'en avoir que 2 (un caissier et un cuisinier).
|
||||
|
||||
Et pourtant l'expérience finale n'est pas meilleure 😞.
|
||||
Mais tout de même, l'expérience finale n'est pas la meilleure. 😞
|
||||
|
||||
---
|
||||
|
||||
C'est donc l'histoire équivalente parallèle pour les burgers 🍔.
|
||||
Ce serait donc l'histoire équivalente parallèle pour les burgers. 🍔
|
||||
|
||||
Pour un exemple plus courant dans la « vie réelle », imaginez une banque.
|
||||
Pour un exemple plus « vie réelle », imaginez une banque.
|
||||
|
||||
Jusqu'à récemment, la plupart des banques avaient plusieurs caisses (et banquiers) 👨💼👨💼👨💼👨💼 et une unique file d'attente 🕙🕙🕙🕙🕙🕙🕙🕙.
|
||||
Jusqu'à récemment, la plupart des banques avaient plusieurs caissiers 👨💼👨💼👨💼👨💼 et une grande file d'attente 🕙🕙🕙🕙🕙🕙🕙🕙.
|
||||
|
||||
Tous les banquiers faisaient l'intégralité du travail avec chaque client avant de passer au suivant 👨💼⏯.
|
||||
Tous les caissiers faisaient tout le travail avec chaque client avant de passer au suivant 👨💼⏯.
|
||||
|
||||
Et vous deviez attendre 🕙 dans la file pendant un long moment ou vous perdiez votre place.
|
||||
Et vous devez attendre 🕙 dans la file pendant un long moment ou vous perdez votre tour.
|
||||
|
||||
Vous n'auriez donc probablement pas envie d'amener votre crush 😍 avec vous à la banque 🏦.
|
||||
Vous n'auriez donc probablement pas envie d'amener votre crush 😍 avec vous pour faire des démarches à la banque 🏦.
|
||||
|
||||
### Conclusion sur les burgers { #burger-conclusion }
|
||||
|
||||
Dans ce scénario des « burgers du fast-food avec votre crush », comme il y a beaucoup d'attente 🕙, il est très logique d'avoir un système concurrent ⏸🔀⏯.
|
||||
Dans ce scénario des « burgers de fast food avec votre crush », comme il y a beaucoup d'attente 🕙, il est beaucoup plus logique d'avoir un système concurrent ⏸🔀⏯.
|
||||
|
||||
Et c'est le cas pour la plupart des applications web.
|
||||
C'est le cas pour la plupart des applications web.
|
||||
|
||||
Vous aurez de nombreux, nombreux utilisateurs, mais votre serveur attendra 🕙 que leur connexion peu performante envoie des requêtes.
|
||||
De très, très nombreux utilisateurs, mais votre serveur attend 🕙 que leur connexion pas très bonne envoie leurs requêtes.
|
||||
|
||||
Puis vous attendrez 🕙 de nouveau que leurs réponses reviennent.
|
||||
Puis attend 🕙 de nouveau que les réponses reviennent.
|
||||
|
||||
Cette « attente » 🕙 se mesure en microsecondes, mais tout de même, en cumulé cela fait beaucoup d'attente.
|
||||
Cette « attente » 🕙 se mesure en microsecondes, mais tout de même, en les cumulant toutes, cela fait beaucoup d'attente au final.
|
||||
|
||||
C'est pourquoi il est logique d'utiliser du code asynchrone ⏸🔀⏯ pour des APIs web.
|
||||
C'est pourquoi il est très logique d'utiliser du code asynchrone ⏸🔀⏯ pour des APIs web.
|
||||
|
||||
Ce type d'asynchronicité est ce qui a rendu NodeJS populaire (bien que NodeJS ne soit pas parallèle) et c'est la force de Go en tant que langage de programmation.
|
||||
|
||||
@@ -255,11 +255,11 @@ Et comme on peut avoir du parallélisme et de l'asynchronicité en même temps,
|
||||
|
||||
### Est-ce que la concurrence est mieux que le parallélisme ? { #is-concurrency-better-than-parallelism }
|
||||
|
||||
Nope ! C'est ça la morale de l'histoire.
|
||||
Nope ! Ce n'est pas la morale de l'histoire.
|
||||
|
||||
La concurrence est différente du parallélisme. C'est mieux sur des scénarios **spécifiques** qui impliquent beaucoup d'attente. À cause de ça, c'est généralement bien meilleur que le parallélisme pour le développement d'applications web. Mais pas pour tout.
|
||||
La concurrence est différente du parallélisme. Et c'est mieux dans des scénarios **spécifiques** qui impliquent beaucoup d'attente. À cause de ça, c'est généralement bien meilleur que le parallélisme pour le développement d'applications web. Mais pas pour tout.
|
||||
|
||||
Donc pour équilibrer tout ça, imaginez l'histoire suivante :
|
||||
Donc pour équilibrer tout ça, imaginez l'histoire courte suivante :
|
||||
|
||||
> Vous devez nettoyer une grande et sale maison.
|
||||
|
||||
@@ -269,42 +269,42 @@ Donc pour équilibrer tout ça, imaginez l'histoire suivante :
|
||||
|
||||
Il n'y a plus d'attente 🕙 nulle part, juste beaucoup de travail à effectuer, dans différentes pièces de la maison.
|
||||
|
||||
Vous pourriez diviser en différentes sections comme avec les burgers, d'abord le salon, puis la cuisine, etc. Mais vous n'attendez 🕙 rien, vous ne faites que nettoyer et nettoyer, la séparation en sections ne changerait rien au final.
|
||||
Vous pourriez avoir des tours comme dans l'exemple des burgers, d'abord le salon, puis la cuisine, mais comme vous n'attendez 🕙 rien, vous ne faites que nettoyer et nettoyer, les tours ne changeraient rien.
|
||||
|
||||
Cela prendrait autant de temps pour finir avec ou sans sections (concurrence) et vous auriez effectué la même quantité de travail.
|
||||
Cela prendrait autant de temps pour finir avec ou sans tours (concurrence) et vous auriez effectué la même quantité de travail.
|
||||
|
||||
Mais dans ce cas, si pouviez amener 8 ex-serveurs/cuisiniers/devenus-nettoyeurs 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳, et que chacun d'eux (plus vous) pouvait prendre une zone de la maison pour la nettoyer, vous pourriez faire tout le travail en parallèle, et finir plus tôt.
|
||||
Mais dans ce cas, si vous pouviez amener les 8 ex-caissiers/cuisiniers/désormais-nettoyeurs, et que chacun d'eux (plus vous) pouvait prendre une zone de la maison pour la nettoyer, vous pourriez faire tout le travail en **parallèle**, avec l'aide supplémentaire, et finir beaucoup plus tôt.
|
||||
|
||||
Dans ce scénario, chacun des nettoyeurs (vous y compris) serait un processeur, faisant sa partie du travail.
|
||||
|
||||
Et comme la plupart du temps d'exécution est pris par du « vrai » travail (et non de l'attente), et que le travail dans un ordinateur est fait par un <abbr title="Central Processing Unit - Unité centrale de traitement">CPU</abbr>, ce sont des problèmes dits « CPU bound ».
|
||||
Et comme la plupart du temps d'exécution est pris par du vrai travail (et non de l'attente), et que le travail dans un ordinateur est fait par un <abbr title="Central Processing Unit - Unité centrale de traitement">CPU</abbr>, ce sont des problèmes dits « CPU bound ».
|
||||
|
||||
---
|
||||
|
||||
Des exemples communs d'opérations « CPU bound » sont les procédés qui requièrent des traitements mathématiques complexes.
|
||||
Des exemples communs d'opérations CPU bound sont les choses qui requièrent des traitements mathématiques complexes.
|
||||
|
||||
Par exemple :
|
||||
|
||||
* Traitements d'**audio** et d'**images**.
|
||||
* La **vision par ordinateur** : une image est composée de millions de pixels, chaque pixel ayant 3 valeurs / couleurs, les traiter tous va nécessiter d'effectuer des traitements sur chaque pixel, et de préférence tous en même temps.
|
||||
* L'apprentissage automatique (ou **Machine Learning**) : cela nécessite de nombreuses multiplications de matrices et vecteurs. Imaginez une énorme feuille de calcul remplie de nombres que vous multiplierez entre eux tous au même moment.
|
||||
* L'apprentissage profond (ou **Deep Learning**) : est un sous-domaine du **Machine Learning**, donc les mêmes raisons s'appliquent. Avec la différence qu'il n'y a pas une unique feuille de calcul de nombres à multiplier, mais une énorme quantité d'entre elles, et dans de nombreux cas, on utilise un processeur spécial pour construire et / ou utiliser ces modèles.
|
||||
* Traitements d'**audio** ou d'**images**.
|
||||
* **Computer vision** : une image est composée de millions de pixels, chaque pixel ayant 3 valeurs / couleurs, les traiter nécessite normalement d'effectuer des calculs sur ces pixels, tous en même temps.
|
||||
* **Machine Learning** : cela nécessite normalement de nombreuses multiplications de « matrices » et de « vecteurs ». Imaginez une énorme feuille de calcul remplie de nombres et les multiplier tous ensemble au même moment.
|
||||
* **Deep Learning** : c'est un sous-domaine du Machine Learning, donc les mêmes raisons s'appliquent. C'est juste qu'il n'y a pas une unique feuille de calcul de nombres à multiplier, mais une énorme quantité d'entre elles, et dans de nombreux cas, on utilise un processeur spécial pour construire et / ou utiliser ces modèles.
|
||||
|
||||
### Concurrence + Parallélisme : Web + Machine Learning { #concurrency-parallelism-web-machine-learning }
|
||||
|
||||
Avec **FastAPI** vous pouvez bénéficier de la concurrence qui est très courante en développement web (c'est l'attrait principal de NodeJS).
|
||||
Avec **FastAPI** vous pouvez bénéficier de la concurrence qui est très courante en développement web (le même attrait principal de NodeJS).
|
||||
|
||||
Mais vous pouvez aussi profiter du parallélisme et du multiprocessing (plusieurs processus s'exécutant en parallèle) afin de gérer des charges **CPU bound** qui sont récurrentes dans les systèmes de *Machine Learning*.
|
||||
Mais vous pouvez aussi profiter du parallélisme et du multiprocessing (plusieurs processus s'exécutant en parallèle) afin de gérer des charges **CPU bound** comme celles des systèmes de Machine Learning.
|
||||
|
||||
Ça, ajouté au fait que Python soit le langage le plus populaire pour la **Data Science**, le **Machine Learning** et surtout le **Deep Learning**, font de **FastAPI** un très bon choix pour les APIs et applications de **Data Science** / **Machine Learning**.
|
||||
Ça, ajouté au simple fait que Python soit le langage principal pour la **Data Science**, le Machine Learning et surtout le Deep Learning, fait de FastAPI un très bon choix pour les APIs web et applications de Data Science / Machine Learning (entre autres).
|
||||
|
||||
Pour comprendre comment mettre en place ce parallélisme en production, allez lire la section [Déploiement](deployment/index.md).
|
||||
Pour comprendre comment mettre en place ce parallélisme en production, consultez la section sur le [Déploiement](deployment/index.md).
|
||||
|
||||
## `async` et `await` { #async-and-await }
|
||||
|
||||
Les versions modernes de Python ont une manière très intuitive de définir le code asynchrone, tout en gardant une apparence de code « séquentiel » classique en laissant Python faire l'attente pour vous au bon moment.
|
||||
Les versions modernes de Python ont une manière très intuitive de définir le code asynchrone. Cela le fait ressembler à du code « séquentiel » normal et effectue l'« attente » pour vous aux bons moments.
|
||||
|
||||
Pour une opération qui nécessite de l'attente avant de donner un résultat et qui supporte ces nouvelles fonctionnalités Python, vous pouvez l'utiliser comme tel :
|
||||
Pour une opération qui nécessite de l'attente avant de donner un résultat et qui supporte ces nouvelles fonctionnalités Python, vous pouvez l'écrire comme ceci :
|
||||
|
||||
```Python
|
||||
burgers = await get_burgers(2)
|
||||
@@ -312,7 +312,7 @@ burgers = await get_burgers(2)
|
||||
|
||||
Le mot-clé important ici est `await`. Il informe Python qu'il faut attendre ⏸ que `get_burgers(2)` finisse d'effectuer ses opérations 🕙 avant de stocker les résultats dans la variable `burgers`. Grâce à cela, Python saura qu'il peut aller effectuer d'autres opérations 🔀 ⏯ pendant ce temps (comme par exemple recevoir une autre requête).
|
||||
|
||||
Pour que `await` fonctionne, il doit être placé dans une fonction qui supporte l'asynchronicité. Pour que ça soit le cas, il faut déclarer cette dernière avec `async def` :
|
||||
Pour que `await` fonctionne, il doit être placé dans une fonction qui supporte cette asynchronicité. Pour que ça soit le cas, il faut déclarer cette dernière avec `async def` :
|
||||
|
||||
```Python hl_lines="1"
|
||||
async def get_burgers(number: int):
|
||||
@@ -320,7 +320,7 @@ async def get_burgers(number: int):
|
||||
return burgers
|
||||
```
|
||||
|
||||
... et non `def` :
|
||||
... au lieu de `def` :
|
||||
|
||||
```Python hl_lines="2"
|
||||
# Ceci n'est pas asynchrone
|
||||
@@ -331,16 +331,16 @@ def get_sequential_burgers(number: int):
|
||||
|
||||
Avec `async def`, Python sait que dans cette fonction il doit prendre en compte les expressions `await`, et qu'il peut mettre en pause ⏸ l'exécution de la fonction pour aller faire autre chose 🔀 avant de revenir.
|
||||
|
||||
Pour appeler une fonction définie avec `async def`, vous devez utiliser `await`. Donc ceci ne marche pas :
|
||||
Lorsque vous voulez appeler une fonction `async def`, vous devez l'« attendre ». Donc ceci ne marche pas :
|
||||
|
||||
```Python
|
||||
# Ceci ne fonctionne pas, car get_burgers a été défini avec async def
|
||||
# Ceci ne fonctionne pas, car get_burgers a été défini avec : async def
|
||||
burgers = get_burgers(2)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Donc, si vous utilisez une bibliothèque qui nécessite que ses fonctions soient appelées avec `await`, vous devez définir la *fonction de chemin d'accès* en utilisant `async def` comme dans :
|
||||
Donc, si vous utilisez une bibliothèque qui vous indique que vous pouvez l'appeler avec `await`, vous devez créer les *fonctions de chemin d'accès* qui l'utilisent avec `async def`, comme dans :
|
||||
|
||||
```Python hl_lines="2-3"
|
||||
@app.get('/burgers')
|
||||
@@ -351,13 +351,13 @@ async def read_burgers():
|
||||
|
||||
### Plus de détails techniques { #more-technical-details }
|
||||
|
||||
Vous avez donc compris que `await` peut seulement être utilisé dans des fonctions définies avec `async def`.
|
||||
Vous avez peut-être remarqué que `await` peut seulement être utilisé dans des fonctions définies avec `async def`.
|
||||
|
||||
Mais en même temps, les fonctions définies avec `async def` doivent être appelées avec `await` et donc dans des fonctions définies elles aussi avec `async def`.
|
||||
Mais en même temps, les fonctions définies avec `async def` doivent être « attendues ». Donc, les fonctions avec `async def` peuvent seulement être appelées à l'intérieur de fonctions définies elles aussi avec `async def`.
|
||||
|
||||
Vous avez donc remarqué ce paradoxe d'œuf et de la poule, comment appelle-t-on la première fonction `async` ?
|
||||
Donc, à propos de l'œuf et de la poule, comment appelle-t-on la première fonction `async` ?
|
||||
|
||||
Si vous utilisez **FastAPI**, pas besoin de vous en inquiéter, car cette « première » fonction sera votre *fonction de chemin d'accès* ; et **FastAPI** saura comment arriver au résultat attendu.
|
||||
Si vous utilisez **FastAPI**, pas besoin de vous en inquiéter, car cette « première » fonction sera votre *fonction de chemin d'accès*, et FastAPI saura comment faire ce qu'il faut.
|
||||
|
||||
Mais si vous souhaitez utiliser `async` / `await` sans FastAPI, vous pouvez également le faire.
|
||||
|
||||
@@ -367,7 +367,7 @@ Starlette (et **FastAPI**) s’appuie sur [AnyIO](https://anyio.readthedocs.io/e
|
||||
|
||||
En particulier, vous pouvez utiliser directement [AnyIO](https://anyio.readthedocs.io/en/stable/) pour vos cas d’usage de concurrence avancés qui nécessitent des schémas plus élaborés dans votre propre code.
|
||||
|
||||
Et même si vous n’utilisiez pas FastAPI, vous pourriez aussi écrire vos propres applications async avec [AnyIO](https://anyio.readthedocs.io/en/stable/) pour une grande compatibilité et pour bénéficier de ses avantages (par ex. la « structured concurrency »).
|
||||
Et même si vous n’utilisiez pas FastAPI, vous pourriez aussi écrire vos propres applications async avec [AnyIO](https://anyio.readthedocs.io/en/stable/) pour une grande compatibilité et pour bénéficier de ses avantages (par ex. la *structured concurrency*).
|
||||
|
||||
J’ai créé une autre bibliothèque au-dessus d’AnyIO, comme une fine surcouche, pour améliorer un peu les annotations de type et obtenir une meilleure **autocomplétion**, des **erreurs en ligne**, etc. Elle propose également une introduction et un tutoriel accessibles pour vous aider à **comprendre** et écrire **votre propre code async** : [Asyncer](https://asyncer.tiangolo.com/). Elle sera particulièrement utile si vous devez **combiner du code async avec du code classique** (bloquant/synchrone).
|
||||
|
||||
@@ -377,25 +377,25 @@ L'utilisation d'`async` et `await` est relativement nouvelle dans ce langage.
|
||||
|
||||
Mais cela rend la programmation asynchrone bien plus simple.
|
||||
|
||||
Cette même syntaxe (ou presque) a aussi été incluse récemment dans les versions modernes de JavaScript (dans les navigateurs et NodeJS).
|
||||
Cette même syntaxe (ou presque) a aussi été incluse récemment dans les versions modernes de JavaScript (dans le navigateur et NodeJS).
|
||||
|
||||
Mais avant ça, gérer du code asynchrone était bien plus complexe et difficile.
|
||||
|
||||
Dans les versions précédentes de Python, vous auriez utilisé des threads ou [Gevent](https://www.gevent.org/). Mais le code aurait été bien plus difficile à comprendre, débugger, et concevoir.
|
||||
Dans les versions précédentes de Python, vous auriez pu utiliser des threads ou [Gevent](https://www.gevent.org/). Mais le code est bien plus difficile à comprendre, débugger, et concevoir.
|
||||
|
||||
Dans les versions précédentes de JavaScript côté navigateur / NodeJS, vous auriez utilisé des « callbacks ». Menant potentiellement à ce que l'on appelle le « callback hell ».
|
||||
Dans les versions précédentes de NodeJS / JavaScript de navigateur, vous auriez utilisé des « callbacks ». Ce qui mène au « callback hell ».
|
||||
|
||||
## Coroutines { #coroutines }
|
||||
|
||||
« Coroutine » est juste un terme élaboré pour désigner ce qui est retourné par une fonction définie avec `async def`. Python sait que c'est comme une fonction classique qui va démarrer à un moment et terminer à un autre, mais qu'elle peut aussi être mise en pause ⏸, du moment qu'il y a un `await` dans son contenu.
|
||||
**Coroutine** est juste un terme élaboré pour désigner ce qui est retourné par une fonction définie avec `async def`. Python sait que c'est comme une fonction, qui peut démarrer et qui se terminera à un moment, mais qu'elle peut aussi être mise en pause ⏸ en interne, quand il y a un `await` à l'intérieur.
|
||||
|
||||
Mais toutes ces fonctionnalités d'utilisation de code asynchrone avec `async` et `await` sont souvent résumées comme l'utilisation des « coroutines ». On peut comparer cela à la principale fonctionnalité clé de Go, les « Goroutines ».
|
||||
|
||||
## Conclusion { #conclusion }
|
||||
|
||||
Reprenons la phrase du début de la page :
|
||||
Reprenons la même phrase ci-dessus :
|
||||
|
||||
> Les versions modernes de Python supportent le **code asynchrone** grâce aux **« coroutines »** avec les syntaxes **`async` et `await`**.
|
||||
> Les versions modernes de Python supportent le **« code asynchrone »** en utilisant quelque chose appelé **« coroutines »**, avec la syntaxe **`async` et `await`**.
|
||||
|
||||
Ceci devrait être plus compréhensible désormais. ✨
|
||||
|
||||
@@ -409,25 +409,25 @@ Vous pouvez probablement ignorer cela.
|
||||
|
||||
Ce sont des détails très poussés sur comment **FastAPI** fonctionne en arrière-plan.
|
||||
|
||||
Si vous avez de bonnes connaissances techniques (coroutines, threads, code bloquant, etc.) et êtes curieux de comment **FastAPI** gère `async def` versus le `def` classique, cette partie est faite pour vous.
|
||||
Si vous avez de bonnes connaissances techniques (coroutines, threads, code bloquant, etc.) et êtes curieux de comment FastAPI gère `async def` versus le `def` classique, cette partie est faite pour vous.
|
||||
|
||||
///
|
||||
|
||||
### Fonctions de chemin d'accès { #path-operation-functions }
|
||||
|
||||
Quand vous déclarez une *fonction de chemin d'accès* avec un `def` normal et non `async def`, elle est exécutée dans un groupe de threads (threadpool) externe qui est ensuite attendu, plutôt que d'être appelée directement (car cela bloquerait le serveur).
|
||||
Quand vous déclarez une *fonction de chemin d'accès* avec un `def` normal et non `async def`, elle est exécutée dans une threadpool externe qui est ensuite attendue, plutôt que d'être appelée directement (car cela bloquerait le serveur).
|
||||
|
||||
Si vous venez d'un autre framework asynchrone qui ne fonctionne pas comme de la façon décrite ci-dessus et que vous êtes habitué à définir des *fonctions de chemin d'accès* basiques et purement calculatoires avec un simple `def` pour un faible gain de performance (environ 100 nanosecondes), veuillez noter que dans **FastAPI**, l'effet serait plutôt contraire. Dans ces cas-là, il vaut mieux utiliser `async def` à moins que votre *fonction de chemin d'accès* utilise du code qui effectue des opérations <abbr title="Input/Output - Entrées/Sorties: lecture ou écriture sur le disque, communications réseau.">I/O</abbr> bloquantes.
|
||||
Si vous venez d'un autre framework async qui ne fonctionne pas de la façon décrite ci-dessus et que vous êtes habitué à définir des *fonctions de chemin d'accès* triviales faisant uniquement du calcul avec un simple `def` pour un faible gain de performance (environ 100 nanosecondes), veuillez noter que dans **FastAPI**, l'effet serait plutôt contraire. Dans ces cas-là, il vaut mieux utiliser `async def` à moins que vos *fonctions de chemin d'accès* utilisent du code qui effectue des opérations <abbr title="Input/Output - Entrées/Sorties: lecture ou écriture sur le disque, communications réseau.">I/O</abbr> bloquantes.
|
||||
|
||||
Au final, dans les deux situations, il est fort probable que **FastAPI** soit tout de même [plus rapide](index.md#performance) que (ou au moins de vitesse égale à) votre framework précédent.
|
||||
Au final, dans les deux situations, il est fort probable que **FastAPI** soit [tout de même plus rapide](index.md#performance) que (ou au moins comparable à) votre framework précédent.
|
||||
|
||||
### Dépendances { #dependencies }
|
||||
|
||||
La même chose s'applique aux [dépendances](tutorial/dependencies/index.md). Si une dépendance est définie avec `def` plutôt que `async def`, elle est exécutée dans la threadpool externe.
|
||||
La même chose s'applique aux [dépendances](tutorial/dependencies/index.md). Si une dépendance est une fonction standard `def` plutôt qu'`async def`, elle est exécutée dans la threadpool externe.
|
||||
|
||||
### Sous-dépendances { #sub-dependencies }
|
||||
|
||||
Vous pouvez avoir de multiples dépendances et [sous-dépendances](tutorial/dependencies/sub-dependencies.md) dépendant les unes des autres (en tant que paramètres de la définition de la *fonction de chemin d'accès*), certaines créées avec `async def` et d'autres avec `def`. Cela fonctionnerait aussi, et celles définies avec un simple `def` seraient exécutées sur un thread externe (venant de la threadpool) plutôt que d'être « attendues ».
|
||||
Vous pouvez avoir de multiples dépendances et [sous-dépendances](tutorial/dependencies/sub-dependencies.md) dépendant les unes des autres (en tant que paramètres des définitions des fonctions), certaines créées avec `async def` et d'autres avec un `def` normal. Cela fonctionnerait aussi, et celles définies avec un `def` normal seraient appelées sur un thread externe (venant de la threadpool) plutôt que d'être « attendues ».
|
||||
|
||||
### Autres fonctions utilitaires { #other-utility-functions }
|
||||
|
||||
@@ -435,10 +435,10 @@ Toute autre fonction utilitaire que vous appelez directement peut être créée
|
||||
|
||||
Contrairement aux fonctions que FastAPI appelle pour vous : les *fonctions de chemin d'accès* et dépendances.
|
||||
|
||||
Si votre fonction utilitaire est une fonction classique définie avec `def`, elle sera appelée directement (telle qu'écrite dans votre code), pas dans une threadpool ; si la fonction est définie avec `async def` alors vous devrez attendre (avec `await`) que cette fonction se termine avant de passer à la suite du code.
|
||||
Si votre fonction utilitaire est une fonction classique définie avec `def`, elle sera appelée directement (telle qu'écrite dans votre code), pas dans une threadpool ; si la fonction est définie avec `async def` alors vous devez `await` cette fonction lorsque vous l'appelez dans votre code.
|
||||
|
||||
---
|
||||
|
||||
Encore une fois, ce sont des détails très techniques qui peuvent être utiles si vous venez ici les chercher.
|
||||
|
||||
Sinon, les instructions de la section <a href="#in-a-hurry">Vous êtes pressés ?</a> ci-dessus sont largement suffisantes.
|
||||
Sinon, les instructions de la section ci-dessus sont largement suffisantes : <a href="#in-a-hurry">Vous êtes pressés ?</a>.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Déployer FastAPI sur des fournisseurs cloud { #deploy-fastapi-on-cloud-providers }
|
||||
|
||||
Vous pouvez utiliser pratiquement n'importe quel fournisseur cloud pour déployer votre application FastAPI.
|
||||
Vous pouvez utiliser pratiquement **n'importe quel fournisseur cloud** pour déployer votre application FastAPI.
|
||||
|
||||
Dans la plupart des cas, les principaux fournisseurs cloud proposent des guides pour déployer FastAPI avec leurs services.
|
||||
|
||||
@@ -16,7 +16,7 @@ FastAPI Cloud est le sponsor principal et le financeur des projets open source *
|
||||
|
||||
## Fournisseurs cloud - Sponsors { #cloud-providers-sponsors }
|
||||
|
||||
D'autres fournisseurs cloud ✨ [**parrainent FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ également. 🙇
|
||||
Certains autres fournisseurs cloud ✨ [**parrainent FastAPI**](https://github.com/sponsors/tiangolo) ✨ également. 🙇
|
||||
|
||||
Vous pouvez également envisager ces fournisseurs pour suivre leurs guides et essayer leurs services :
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Concepts de déploiement { #deployments-concepts }
|
||||
|
||||
|
||||
Lorsque vous déployez une application **FastAPI**, ou en fait n'importe quel type de web API, il existe plusieurs concepts qui vous importent probablement, et en les utilisant vous pouvez trouver la manière la **plus appropriée** de **déployer votre application**.
|
||||
|
||||
Parmi les concepts importants, on trouve :
|
||||
|
||||
@@ -132,7 +132,7 @@ Successfully installed fastapi pydantic
|
||||
|
||||
</div>
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Il existe d'autres formats et outils pour définir et installer des dépendances de paquets.
|
||||
|
||||
@@ -232,7 +232,7 @@ Passez en revue ce que fait chaque ligne en cliquant sur chaque bulle numéroté
|
||||
|
||||
/// warning | Alertes
|
||||
|
||||
Vous devez vous assurer d'utiliser **toujours** la **forme exec** de l'instruction `CMD`, comme expliqué ci-dessous.
|
||||
Vous devez **toujours** utiliser la **forme exec** de l'instruction `CMD`, comme expliqué ci-dessous.
|
||||
|
||||
///
|
||||
|
||||
@@ -254,7 +254,7 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
CMD fastapi run app/main.py --port 80
|
||||
```
|
||||
|
||||
Assurez-vous d'utiliser toujours la forme **exec** pour garantir que FastAPI peut s'arrêter proprement et que les [événements de cycle de vie](../advanced/events.md) sont déclenchés.
|
||||
Vous devez toujours utiliser la forme **exec** pour garantir que FastAPI peut s'arrêter proprement et que les [événements de cycle de vie](../advanced/events.md) sont déclenchés.
|
||||
|
||||
Vous pouvez en lire davantage dans la [documentation Docker sur les formes shell et exec](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).
|
||||
|
||||
@@ -556,7 +556,7 @@ Si vous utilisez des conteneurs (par ex. Docker, Kubernetes), alors il existe de
|
||||
|
||||
Si vous avez **plusieurs conteneurs**, probablement chacun exécutant un **seul processus** (par exemple, dans un cluster **Kubernetes**), alors vous voudrez probablement avoir un **conteneur séparé** effectuant le travail des **étapes préalables** dans un seul conteneur, exécutant un seul processus, **avant** d'exécuter les conteneurs worker répliqués.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Si vous utilisez Kubernetes, ce sera probablement un [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).
|
||||
|
||||
|
||||
@@ -1,26 +1,6 @@
|
||||
# FastAPI Cloud { #fastapi-cloud }
|
||||
|
||||
Vous pouvez déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com) avec une **seule commande**, allez vous inscrire sur la liste d’attente si ce n’est pas déjà fait. 🚀
|
||||
|
||||
## Se connecter { #login }
|
||||
|
||||
Vous devez vous assurer que vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉).
|
||||
|
||||
Connectez-vous ensuite :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Déployer { #deploy }
|
||||
|
||||
Déployez maintenant votre application, avec une **seule commande** :
|
||||
Vous pouvez déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com) avec une **seule commande**. 🚀
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -36,6 +16,8 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
La CLI détecte automatiquement votre application FastAPI et la déploie dans le cloud. Si vous n’êtes pas connecté, votre navigateur s’ouvrira pour terminer le processus d’authentification.
|
||||
|
||||
C’est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
|
||||
## À propos de FastAPI Cloud { #about-fastapi-cloud }
|
||||
@@ -62,4 +44,4 @@ Suivez les guides de votre fournisseur cloud pour déployer des applications Fas
|
||||
|
||||
## Déployer votre propre serveur { #deploy-your-own-server }
|
||||
|
||||
Je vous expliquerai également plus loin dans ce guide de **Déploiement** tous les détails, afin que vous compreniez ce qui se passe, ce qui doit être fait, et comment déployer des applications FastAPI par vous-même, y compris sur vos propres serveurs. 🤓
|
||||
Je vous expliquerai également plus loin dans ce guide de **Déploiement** tous les détails, afin que vous compreniez ce qui se passe, ce qui doit être fait, ou comment déployer des applications FastAPI par vous-même, y compris sur vos propres serveurs. 🤓
|
||||
|
||||
@@ -10,9 +10,9 @@ Si vous êtes pressé ou si cela ne vous intéresse pas, continuez avec les sect
|
||||
|
||||
///
|
||||
|
||||
Pour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez [https://howhttps.works/](https://howhttps.works/).
|
||||
Pour **apprendre les bases du HTTPS**, du point de vue d'un utilisateur, consultez [https://howhttps.works/](https://howhttps.works/).
|
||||
|
||||
Maintenant, du point de vue d'un développeur, voici plusieurs choses à avoir en tête en pensant au HTTPS :
|
||||
Maintenant, du **point de vue d'un développeur**, voici plusieurs choses à avoir en tête en pensant au HTTPS :
|
||||
|
||||
* Pour le HTTPS, **le serveur** doit **disposer de « certificats »** générés par une **tierce partie**.
|
||||
* Ces certificats sont en réalité **acquis** auprès de la tierce partie, et non « générés ».
|
||||
@@ -65,7 +65,7 @@ Voici un exemple de ce à quoi pourrait ressembler une API HTTPS, étape par ét
|
||||
|
||||
Tout commencerait probablement par le fait que vous **acquériez** un **nom de domaine**. Ensuite, vous le configureriez dans un serveur DNS (possiblement le même que votre fournisseur cloud).
|
||||
|
||||
Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une adresse IP publique <dfn title="Ne change pas dans le temps. Pas dynamique.">fixe</dfn>.
|
||||
Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une **adresse IP publique** <dfn title="Ne change pas dans le temps. Pas dynamique.">fixe</dfn>.
|
||||
|
||||
Dans le ou les serveurs DNS, vous configureriez un enregistrement (un « `A record` ») pour faire pointer **votre domaine** vers l'**adresse IP publique de votre serveur**.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
|
||||
|
||||
Cela fonctionnerait pour la plupart des cas. 😎
|
||||
|
||||
Vous pourriez utiliser cette commande par exemple pour démarrer votre application **FastAPI** dans un conteneur, sur un serveur, etc.
|
||||
Vous pourriez utiliser cette commande par exemple pour démarrer votre **FastAPI** app dans un conteneur, sur un serveur, etc.
|
||||
|
||||
## Serveurs ASGI { #asgi-servers }
|
||||
|
||||
@@ -48,7 +48,7 @@ Allons un peu plus en détail.
|
||||
|
||||
FastAPI utilise un standard pour construire des frameworks web Python et des serveurs appelé <abbr title="Asynchronous Server Gateway Interface - Interface passerelle serveur asynchrone">ASGI</abbr>. FastAPI est un framework web ASGI.
|
||||
|
||||
La principale chose dont vous avez besoin pour exécuter une application **FastAPI** (ou toute autre application ASGI) sur une machine serveur distante est un programme serveur ASGI comme **Uvicorn**, c'est celui utilisé par défaut par la commande `fastapi`.
|
||||
La principale chose dont vous avez besoin pour exécuter une application **FastAPI** (ou toute autre application ASGI) sur une machine serveur distante est un programme serveur ASGI comme **Uvicorn**, c'est celui fourni par défaut avec la commande `fastapi`.
|
||||
|
||||
Il existe plusieurs alternatives, notamment :
|
||||
|
||||
@@ -56,15 +56,14 @@ Il existe plusieurs alternatives, notamment :
|
||||
* [Hypercorn](https://hypercorn.readthedocs.io/) : un serveur ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.
|
||||
* [Daphne](https://github.com/django/daphne) : le serveur ASGI conçu pour Django Channels.
|
||||
* [Granian](https://github.com/emmett-framework/granian) : un serveur HTTP Rust pour les applications Python.
|
||||
* [NGINX Unit](https://unit.nginx.org/howto/fastapi/) : NGINX Unit est un environnement d'exécution d'applications web léger et polyvalent.
|
||||
|
||||
## Machine serveur et programme serveur { #server-machine-and-server-program }
|
||||
|
||||
Il y a un petit détail sur les noms à garder à l'esprit. 💡
|
||||
|
||||
Le mot « serveur » est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
|
||||
Le mot « **serveur** » est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
|
||||
|
||||
Gardez cela à l'esprit lorsque vous lisez « serveur » en général, cela pourrait faire référence à l'une de ces deux choses.
|
||||
Gardez simplement à l'esprit que lorsque vous lisez « serveur » en général, cela pourrait faire référence à l'une de ces deux choses.
|
||||
|
||||
Lorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant normalement Linux, sur laquelle vous exécutez des programmes.
|
||||
|
||||
@@ -118,7 +117,7 @@ $ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
La commande `uvicorn main:app` fait référence à :
|
||||
|
||||
* `main` : le fichier `main.py` (le « module » Python).
|
||||
* `main` : le fichier `main.py` (le « module » Python).
|
||||
* `app` : l'objet créé dans `main.py` avec la ligne `app = FastAPI()`.
|
||||
|
||||
C'est équivalent à :
|
||||
|
||||
@@ -17,7 +17,7 @@ Comme vous l'avez vu dans le chapitre précédent sur les [Concepts de déploiem
|
||||
|
||||
Ici, je vais vous montrer comment utiliser Uvicorn avec des processus workers en utilisant la commande `fastapi` ou directement la commande `uvicorn`.
|
||||
|
||||
/// info | Info
|
||||
/// note | Remarque
|
||||
|
||||
Si vous utilisez des conteneurs, par exemple avec Docker ou Kubernetes, je vous en dirai plus à ce sujet dans le prochain chapitre : [FastAPI dans des conteneurs - Docker](docker.md).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Prise en charge des éditeurs { #editor-support }
|
||||
|
||||
L’extension officielle [Extension FastAPI](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) améliore votre flux de développement FastAPI grâce à la découverte des chemins d'accès, à la navigation, ainsi qu’au déploiement sur FastAPI Cloud et à la diffusion en direct des journaux.
|
||||
L’extension officielle [Extension FastAPI](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) améliore votre flux de développement FastAPI grâce à la découverte des *chemins d'accès*, à la navigation, ainsi qu’au déploiement sur FastAPI Cloud et à la diffusion en direct des journaux.
|
||||
|
||||
Pour plus de détails sur l’extension, reportez-vous au README sur le [référentiel GitHub](https://github.com/fastapi/fastapi-vscode).
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ Si vous savez déjà ce que sont les « variables d'environnement » et comment
|
||||
|
||||
///
|
||||
|
||||
Une variable d'environnement (également appelée « env var ») est une variable qui vit en dehors du code Python, dans le système d'exploitation, et qui peut être lue par votre code Python (ou par d'autres programmes également).
|
||||
Une variable d'environnement (également appelée « **env var** ») est une variable qui vit **en dehors** du code Python, dans le **système d'exploitation**, et qui peut être lue par votre code Python (ou par d'autres programmes également).
|
||||
|
||||
Les variables d'environnement peuvent être utiles pour gérer des **paramètres** d'application, dans le cadre de l'**installation** de Python, etc.
|
||||
|
||||
## Créer et utiliser des variables d'environnement { #create-and-use-env-vars }
|
||||
|
||||
Vous pouvez créer et utiliser des variables d'environnement dans le **shell (terminal)**, sans avoir besoin de Python :
|
||||
Vous pouvez **créer** et utiliser des variables d'environnement dans le **shell (terminal)**, sans avoir besoin de Python :
|
||||
|
||||
//// tab | Linux, macOS, Windows Bash
|
||||
|
||||
@@ -54,7 +54,7 @@ Hello Wade Wilson
|
||||
|
||||
Vous pouvez également créer des variables d'environnement **en dehors** de Python, dans le terminal (ou par tout autre moyen), puis les **lire en Python**.
|
||||
|
||||
Par exemple, vous pouvez avoir un fichier `main.py` contenant :
|
||||
Par exemple, vous pouvez avoir un fichier `main.py` contenant :
|
||||
|
||||
```Python hl_lines="3"
|
||||
import os
|
||||
@@ -71,7 +71,7 @@ S'il n'est pas fourni, c'est `None` par défaut ; ici, nous fournissons `"World"
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez ensuite exécuter ce programme Python :
|
||||
Vous pouvez ensuite exécuter ce programme Python :
|
||||
|
||||
//// tab | Linux, macOS, Windows Bash
|
||||
|
||||
@@ -131,7 +131,7 @@ Comme les variables d'environnement peuvent être définies en dehors du code, m
|
||||
|
||||
Vous pouvez également créer une variable d'environnement uniquement pour l'**invocation d'un programme spécifique**, qui ne sera disponible que pour ce programme et uniquement pendant sa durée d'exécution.
|
||||
|
||||
Pour cela, créez-la juste avant le programme, sur la même ligne :
|
||||
Pour cela, créez-la juste avant le programme, sur la même ligne :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -159,7 +159,7 @@ Vous pouvez en lire davantage sur [The Twelve-Factor App : Config](https://12fac
|
||||
|
||||
## Gérer les types et la validation { #types-and-validation }
|
||||
|
||||
Ces variables d'environnement ne peuvent gérer que des **chaînes de texte**, car elles sont externes à Python et doivent être compatibles avec les autres programmes et le reste du système (et même avec différents systèmes d'exploitation, comme Linux, Windows, macOS).
|
||||
Ces variables d'environnement ne peuvent gérer que des **chaînes de texte**, car elles sont externes à Python et doivent être compatibles avec les autres programmes et le reste du système (et même avec différents systèmes d'exploitation, comme Linux, Windows et macOS).
|
||||
|
||||
Cela signifie que **toute valeur** lue en Python à partir d'une variable d'environnement **sera une `str`**, et que toute conversion vers un autre type ou toute validation doit être effectuée dans le code.
|
||||
|
||||
@@ -167,11 +167,11 @@ Vous en apprendrez davantage sur l'utilisation des variables d'environnement pou
|
||||
|
||||
## Variable d'environnement `PATH` { #path-environment-variable }
|
||||
|
||||
Il existe une **variable d'environnement spéciale** appelée **`PATH`** qui est utilisée par les systèmes d'exploitation (Linux, macOS, Windows) pour trouver les programmes à exécuter.
|
||||
Il existe une variable d'environnement **spéciale** appelée **`PATH`** qui est utilisée par les systèmes d'exploitation (Linux, macOS, Windows) pour trouver les programmes à exécuter.
|
||||
|
||||
La valeur de la variable `PATH` est une longue chaîne composée de répertoires séparés par deux-points `:` sous Linux et macOS, et par point-virgule `;` sous Windows.
|
||||
|
||||
Par exemple, la variable d'environnement `PATH` peut ressembler à ceci :
|
||||
Par exemple, la variable d'environnement `PATH` peut ressembler à ceci :
|
||||
|
||||
//// tab | Linux, macOS
|
||||
|
||||
@@ -179,7 +179,7 @@ Par exemple, la variable d'environnement `PATH` peut ressembler à ceci :
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
||||
```
|
||||
|
||||
Cela signifie que le système doit rechercher les programmes dans les répertoires :
|
||||
Cela signifie que le système doit rechercher les programmes dans les répertoires :
|
||||
|
||||
* `/usr/local/bin`
|
||||
* `/usr/bin`
|
||||
@@ -195,7 +195,7 @@ Cela signifie que le système doit rechercher les programmes dans les répertoir
|
||||
C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
|
||||
```
|
||||
|
||||
Cela signifie que le système doit rechercher les programmes dans les répertoires :
|
||||
Cela signifie que le système doit rechercher les programmes dans les répertoires :
|
||||
|
||||
* `C:\Program Files\Python312\Scripts`
|
||||
* `C:\Program Files\Python312`
|
||||
@@ -219,7 +219,7 @@ Supposons que vous installiez Python et qu'il se retrouve dans un répertoire `/
|
||||
|
||||
Si vous acceptez de mettre à jour la variable d'environnement `PATH`, l'installateur ajoutera `/opt/custompython/bin` à la variable d'environnement `PATH`.
|
||||
|
||||
Cela pourrait ressembler à ceci :
|
||||
Cela pourrait ressembler à ceci :
|
||||
|
||||
```plaintext
|
||||
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
|
||||
@@ -243,7 +243,7 @@ Ainsi, lorsque vous tapez `python` dans le terminal, le système trouvera le pro
|
||||
|
||||
////
|
||||
|
||||
Ainsi, si vous tapez :
|
||||
Ainsi, si vous tapez :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -257,7 +257,7 @@ $ python
|
||||
|
||||
Le système va **trouver** le programme `python` dans `/opt/custompython/bin` et l'exécuter.
|
||||
|
||||
Cela reviendrait à peu près à taper :
|
||||
Cela reviendrait à peu près à taper :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -273,7 +273,7 @@ $ /opt/custompython/bin/python
|
||||
|
||||
Le système va **trouver** le programme `python` dans `C:\opt\custompython\bin\python` et l'exécuter.
|
||||
|
||||
Cela reviendrait à peu près à taper :
|
||||
Cela reviendrait à peu près à taper :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Documentation d'API interactive et interfaces web d'exploration. Comme le framew
|
||||
|
||||
* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), avec exploration interactive, appelez et testez votre API directement depuis le navigateur.
|
||||
|
||||

|
||||

|
||||
|
||||
* Documentation d'API alternative avec [**ReDoc**](https://github.com/Rebilly/ReDoc).
|
||||
|
||||
@@ -85,11 +85,11 @@ Voici comment votre éditeur peut vous aider :
|
||||
|
||||
* dans [Visual Studio Code](https://code.visualstudio.com/) :
|
||||
|
||||

|
||||

|
||||
|
||||
* dans [PyCharm](https://www.jetbrains.com/pycharm/) :
|
||||
|
||||

|
||||

|
||||
|
||||
Vous obtiendrez de l'autocomplétion dans du code que vous auriez pu considérer impossible auparavant. Par exemple, la clé `price` à l'intérieur d'un corps JSON (qui aurait pu être imbriqué) provenant d'une requête.
|
||||
|
||||
@@ -105,7 +105,7 @@ Mais par défaut, tout **« just works »**.
|
||||
|
||||
* Validation pour la plupart (ou tous ?) des **types de données** Python, y compris :
|
||||
* objets JSON (`dict`).
|
||||
* tableaux JSON (`list`) définissant les types d'éléments.
|
||||
* tableau JSON (`list`) définissant les types d'éléments.
|
||||
* champs String (`str`), définition des longueurs minimale et maximale.
|
||||
* nombres (`int`, `float`) avec valeurs minimale et maximale, etc.
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Aider { #help }
|
||||
|
||||
|
||||
Souhaitez-vous aider FastAPI ou obtenir de l'aide à propos de FastAPI ?
|
||||
|
||||
Il existe des moyens très simples d'aider et d'obtenir de l'aide.
|
||||
|
||||
@@ -50,11 +50,11 @@ Par exemple, pour désactiver `deepLinking`, vous pourriez passer ces paramètre
|
||||
|
||||
## Autres paramètres de Swagger UI { #other-swagger-ui-parameters }
|
||||
|
||||
Pour voir toutes les autres configurations possibles que vous pouvez utiliser, lisez les [documents officiels pour les paramètres de Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).
|
||||
Pour voir toutes les autres configurations possibles que vous pouvez utiliser, lisez les documents officiels [pour les paramètres de Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).
|
||||
|
||||
## Paramètres JavaScript uniquement { #javascript-only-settings }
|
||||
|
||||
Swagger UI permet également d'autres configurations qui sont des objets réservés à JavaScript (par exemple, des fonctions JavaScript).
|
||||
Swagger UI permet également d'autres configurations qui sont des objets **réservés à JavaScript** (par exemple, des fonctions JavaScript).
|
||||
|
||||
FastAPI inclut aussi ces paramètres `presets` réservés à JavaScript :
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ Le `dict` `scope` et la fonction `receive` font tous deux partie de la spécific
|
||||
|
||||
Et ces deux éléments, `scope` et `receive`, sont ce dont on a besoin pour créer une nouvelle instance de `Request`.
|
||||
|
||||
Pour en savoir plus sur `Request`, consultez [la documentation de Starlette sur les requêtes](https://www.starlette.dev/requests/).
|
||||
Pour en savoir plus sur `Request`, consultez [les documents de Starlette sur les requêtes](https://www.starlette.dev/requests/).
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -25,9 +25,17 @@ Et cette fonction `get_openapi()` reçoit comme paramètres :
|
||||
* `openapi_version` : La version de la spécification OpenAPI utilisée. Par défaut, la plus récente : `3.1.0`.
|
||||
* `summary` : Un court résumé de l'API.
|
||||
* `description` : La description de votre API ; elle peut inclure du markdown et sera affichée dans la documentation.
|
||||
* `routes` : Une liste de routes ; chacune correspond à un *chemin d'accès* enregistré. Elles sont extraites de `app.routes`.
|
||||
* `routes` : Les routes de l'application, extraites de `app.routes`. FastAPI les utilise pour collecter les *chemins d'accès* enregistrés, y compris ceux provenant des routeurs inclus.
|
||||
|
||||
/// info
|
||||
/// tip | Détails techniques
|
||||
|
||||
`app.routes` est un arbre de routes de plus bas niveau. Il peut inclure des routes candidates que FastAPI utilise en interne pour les routeurs inclus, et pas uniquement des objets `APIRoute` finaux.
|
||||
|
||||
Vous pouvez néanmoins passer `app.routes` à `get_openapi()`. FastAPI parcourra cet arbre de routes pour collecter les chemins d'accès effectifs.
|
||||
|
||||
///
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Le paramètre `summary` est disponible à partir d'OpenAPI 3.1.0, pris en charge par FastAPI 0.99.0 et versions ultérieures.
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ Assurez-vous d'évaluer si les **bénéfices** pour votre cas d'utilisation comp
|
||||
Voici quelques bibliothèques **GraphQL** qui prennent en charge **ASGI**. Vous pouvez les utiliser avec **FastAPI** :
|
||||
|
||||
* [Strawberry](https://strawberry.rocks/) 🍓
|
||||
* Avec [la documentation pour FastAPI](https://strawberry.rocks/docs/integrations/fastapi)
|
||||
* Avec [les documents pour FastAPI](https://strawberry.rocks/docs/integrations/fastapi)
|
||||
* [Ariadne](https://ariadnegraphql.org/)
|
||||
* Avec [la documentation pour FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)
|
||||
* Avec [les documents pour FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)
|
||||
* [Tartiflette](https://tartiflette.io/)
|
||||
* Avec [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) pour fournir l'intégration ASGI
|
||||
* [Graphene](https://graphene-python.org/)
|
||||
@@ -39,7 +39,7 @@ Voici un petit aperçu de la manière dont vous pouvez intégrer Strawberry avec
|
||||
|
||||
Vous pouvez en apprendre davantage sur Strawberry dans la [documentation de Strawberry](https://strawberry.rocks/).
|
||||
|
||||
Et également la documentation sur [Strawberry avec FastAPI](https://strawberry.rocks/docs/integrations/fastapi).
|
||||
Et également les documents sur [Strawberry avec FastAPI](https://strawberry.rocks/docs/integrations/fastapi).
|
||||
|
||||
## Ancien `GraphQLApp` de Starlette { #older-graphqlapp-from-starlette }
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ FastAPI version 0.119.0 a introduit une prise en charge partielle de Pydantic v1
|
||||
|
||||
FastAPI 0.126.0 a supprimé la prise en charge de Pydantic v1, tout en continuant à prendre en charge `pydantic.v1` pendant un certain temps.
|
||||
|
||||
FastAPI 0.128.0 a également supprimé la prise en charge de `pydantic.v1`, donc les dernières versions de FastAPI nécessitent Pydantic v2.
|
||||
|
||||
/// warning | Alertes
|
||||
|
||||
L'équipe Pydantic a arrêté la prise en charge de Pydantic v1 pour les dernières versions de Python, à partir de **Python 3.14**.
|
||||
@@ -54,6 +56,16 @@ Cela signifie que vous pouvez installer la dernière version de Pydantic v2 et i
|
||||
|
||||
### Prise en charge de FastAPI pour Pydantic v1 dans v2 { #fastapi-support-for-pydantic-v1-in-v2 }
|
||||
|
||||
/// warning | Alertes
|
||||
|
||||
Cette prise en charge FastAPI des modèles `pydantic.v1` a été ajoutée dans **FastAPI 0.119.0** et supprimée dans **FastAPI 0.128.0**. Elle était destinée à être une aide temporaire pour la migration vers Pydantic v2.
|
||||
|
||||
Dans les versions actuelles de FastAPI, l'utilisation d'un modèle `pydantic.v1` dans votre application lèvera une erreur.
|
||||
|
||||
Le reste de cette section décrit la prise en charge temporaire disponible uniquement dans ces anciennes versions.
|
||||
|
||||
///
|
||||
|
||||
Depuis FastAPI 0.119.0, il existe également une prise en charge partielle de Pydantic v1 depuis l'intérieur de Pydantic v2, pour faciliter la migration vers v2.
|
||||
|
||||
Vous pouvez donc mettre à niveau Pydantic vers la dernière version 2 et modifier les imports pour utiliser le sous-module `pydantic.v1`, et dans de nombreux cas cela fonctionnera tel quel.
|
||||
@@ -122,6 +134,12 @@ Si vous devez utiliser certains des outils spécifiques à FastAPI pour les para
|
||||
|
||||
### Migrer par étapes { #migrate-in-steps }
|
||||
|
||||
/// warning | Alertes
|
||||
|
||||
La migration progressive utilisant à la fois des modèles Pydantic v1 et v2 dans la même application décrite ci-dessous ne fonctionne que dans **FastAPI 0.119.0 à 0.127.x**. Elle a été supprimée dans **FastAPI 0.128.0**, les dernières versions nécessitent des modèles **Pydantic v2**.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Essayez d'abord avec `bump-pydantic` ; si vos tests passent et que cela fonctionne, vous avez tout terminé en une seule commande. ✨
|
||||
|
||||
@@ -34,7 +34,7 @@ Mais si vous utilisez le même modèle en sortie, comme ici :
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
|
||||
|
||||
... alors, comme `description` a une valeur par défaut, si vous ne retournez rien pour ce champ, il aura tout de même cette **valeur par défaut**.
|
||||
... alors, comme `description` a une valeur par défaut, si vous **ne retournez rien** pour ce champ, il aura tout de même cette **valeur par défaut**.
|
||||
|
||||
### Modèle pour les données de réponse en sortie { #model-for-output-response-data }
|
||||
|
||||
@@ -52,8 +52,8 @@ La manière de décrire cela dans OpenAPI est de marquer ce champ comme **requis
|
||||
|
||||
Pour cette raison, le schéma JSON d'un modèle peut être différent selon qu'il est utilisé pour **l'entrée ou la sortie** :
|
||||
|
||||
- pour **l'entrée**, `description` ne sera **pas requis**
|
||||
- pour **la sortie**, il sera **requis** (et éventuellement `None`, ou en termes JSON, `null`)
|
||||
* pour **l'entrée**, `description` ne sera **pas requis**
|
||||
* pour **la sortie**, il sera **requis** (et éventuellement `None`, ou en termes JSON, `null`)
|
||||
|
||||
### Modèle de sortie dans les documents { #model-for-output-in-docs }
|
||||
|
||||
@@ -79,13 +79,13 @@ Avec cette fonctionnalité de **Pydantic v2**, la documentation de votre API est
|
||||
|
||||
## Ne pas séparer les schémas { #do-not-separate-schemas }
|
||||
|
||||
Il existe des cas où vous pourriez vouloir avoir le **même schéma pour l'entrée et la sortie**.
|
||||
Maintenant, il existe des cas où vous pourriez vouloir avoir le **même schéma pour l'entrée et la sortie**.
|
||||
|
||||
Le cas d'usage principal est probablement que vous avez déjà du code client/SDKs générés automatiquement et que vous ne souhaitez pas encore mettre à jour tout ce code client/ces SDKs générés automatiquement ; vous le ferez sans doute à un moment donné, mais peut‑être pas tout de suite.
|
||||
|
||||
Dans ce cas, vous pouvez désactiver cette fonctionnalité dans **FastAPI**, avec le paramètre `separate_input_output_schemas=False`.
|
||||
|
||||
/// info | info
|
||||
/// note | Remarque
|
||||
|
||||
La prise en charge de `separate_input_output_schemas` a été ajoutée dans FastAPI `0.102.0`. 🤓
|
||||
|
||||
@@ -95,7 +95,7 @@ La prise en charge de `separate_input_output_schemas` a été ajoutée dans Fast
|
||||
|
||||
### Utiliser le même schéma pour les modèles d'entrée et de sortie dans les documents { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
Désormais, il n'y aura qu'un seul schéma pour l'entrée et la sortie du modèle, uniquement `Item`, et `description` ne sera pas requis :
|
||||
Désormais, il n'y aura qu'un seul schéma pour l'entrée et la sortie du modèle, uniquement `Item`, et `description` sera **non requis** :
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
|
||||
@@ -45,7 +45,7 @@ Les principales fonctionnalités sont :
|
||||
* **Rapide** : très hautes performances, au niveau de **NodeJS** et **Go** (grâce à Starlette et Pydantic). [L'un des frameworks Python les plus rapides](#performance).
|
||||
* **Rapide à coder** : augmente la vitesse de développement des fonctionnalités d'environ 200 % à 300 %. *
|
||||
* **Moins de bugs** : réduit d'environ 40 % les erreurs induites par le développeur. *
|
||||
* **Intuitif** : excellente compatibilité avec les éditeurs. <dfn title="également connu sous le nom de : auto-complétion, autocomplétion, IntelliSense">Autocomplétion</dfn> partout. Moins de temps passé à déboguer.
|
||||
* **Intuitif** : excellente compatibilité avec les éditeurs. <dfn title="également connu sous le nom de : autocomplétion, autocomplétion, IntelliSense">Autocomplétion</dfn> partout. Moins de temps passé à déboguer.
|
||||
* **Facile** : conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire les documents.
|
||||
* **Concis** : diminue la duplication de code. Plusieurs fonctionnalités à partir de chaque déclaration de paramètre. Moins de bugs.
|
||||
* **Robuste** : obtenez un code prêt pour la production. Avec une documentation interactive automatique.
|
||||
@@ -143,7 +143,7 @@ Les principales fonctionnalités sont :
|
||||
|
||||
---
|
||||
|
||||
« _Si quelqu’un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **magnifiquement conçu**, **simple à utiliser** et **hautement scalable** — il est devenu un **composant clé** de notre stratégie de développement API-first._ »
|
||||
« _Si quelqu’un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **magnifiquement conçu**, **simple à utiliser** et **hautement scalable**, il est devenu un **composant clé** de notre stratégie de développement API-first et alimente de nombreuses automatisations et services tels que notre Virtual TAC Engineer._ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/"><small>(ref)</small></a></div>
|
||||
|
||||
@@ -192,7 +192,7 @@ $ pip install "fastapi[standard]"
|
||||
|
||||
</div>
|
||||
|
||||
**Remarque** : Vous devez vous assurer de mettre « fastapi[standard] » entre guillemets pour garantir que cela fonctionne dans tous les terminaux.
|
||||
**Remarque** : Vous devez vous assurer de mettre `"fastapi[standard]"` entre guillemets pour garantir que cela fonctionne dans tous les terminaux.
|
||||
|
||||
## Exemple { #example }
|
||||
|
||||
@@ -239,7 +239,7 @@ async def read_item(item_id: int, q: str | None = None):
|
||||
|
||||
**Remarque** :
|
||||
|
||||
Si vous ne savez pas, consultez la section « Vous êtes pressés ? » à propos de [`async` et `await` dans la documentation](https://fastapi.tiangolo.com/fr/async/#in-a-hurry).
|
||||
Si vous ne savez pas, consultez la section « Vous êtes pressés ? » à propos de [`async` et `await` dans les documents](https://fastapi.tiangolo.com/fr/async/#in-a-hurry).
|
||||
|
||||
</details>
|
||||
|
||||
@@ -492,9 +492,7 @@ Pour un exemple plus complet comprenant plus de fonctionnalités, voir le <a hre
|
||||
|
||||
### Déployer votre application (optionnel) { #deploy-your-app-optional }
|
||||
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com), allez vous inscrire sur la liste d'attente si ce n'est pas déjà fait. 🚀
|
||||
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d'attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com) avec une seule commande. 🚀
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -510,6 +508,8 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
La CLI détectera automatiquement votre application FastAPI et la déploiera dans le cloud. Si vous n'êtes pas connecté, votre navigateur s'ouvrira pour terminer le processus d'authentification.
|
||||
|
||||
C'est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
|
||||
#### À propos de FastAPI Cloud { #about-fastapi-cloud }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Modèle Full Stack FastAPI { #full-stack-fastapi-template }
|
||||
|
||||
|
||||
Les modèles, bien qu'ils soient généralement livrés avec une configuration spécifique, sont conçus pour être flexibles et personnalisables. Cela vous permet de les modifier et de les adapter aux exigences de votre projet, ce qui en fait un excellent point de départ. 🏁
|
||||
|
||||
Vous pouvez utiliser ce modèle pour démarrer, car il inclut une grande partie de la configuration initiale, la sécurité, la base de données et quelques endpoints d'API déjà prêts pour vous.
|
||||
|
||||
@@ -44,7 +44,7 @@ C'est un programme très simple.
|
||||
|
||||
Mais maintenant imaginez que vous l'écriviez de zéro.
|
||||
|
||||
À un certain moment, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts ...
|
||||
À un moment donné, vous commencez à définir la fonction, et vous avez les paramètres prêts ...
|
||||
|
||||
Mais ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ».
|
||||
|
||||
@@ -279,13 +279,13 @@ Ensuite, vous créez une instance de cette classe avec certaines valeurs et elle
|
||||
|
||||
Et vous obtenez tout le support de l'éditeur avec cet objet résultant.
|
||||
|
||||
Un exemple tiré de la documentation officielle de Pydantic :
|
||||
Un exemple tiré des documents officiels de Pydantic :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011_py310.py *}
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Pour en savoir plus à propos de [Pydantic, consultez sa documentation](https://docs.pydantic.dev/).
|
||||
Pour en savoir plus à propos de [Pydantic, consultez ses documents](https://docs.pydantic.dev/).
|
||||
|
||||
///
|
||||
|
||||
@@ -305,7 +305,7 @@ Python lui-même ne fait rien avec ce `Annotated`. Et pour les éditeurs et autr
|
||||
|
||||
Mais vous pouvez utiliser cet espace dans `Annotated` pour fournir à **FastAPI** des métadonnées supplémentaires sur la façon dont vous voulez que votre application se comporte.
|
||||
|
||||
L'important à retenir est que **le premier « paramètre de type »** que vous passez à `Annotated` est le **type réel**. Le reste n'est que des métadonnées pour d'autres outils.
|
||||
L'important à retenir est que **le premier *paramètre de type*** que vous passez à `Annotated` est le **type réel**. Le reste n'est que des métadonnées pour d'autres outils.
|
||||
|
||||
Pour l'instant, vous avez juste besoin de savoir que `Annotated` existe, et que c'est du Python standard. 😎
|
||||
|
||||
|
||||
@@ -17,16 +17,16 @@ Supposons que vous ayez une structure de fichiers comme ceci :
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
│ ├── __init__.py
|
||||
│ ├── main.py
|
||||
│ ├── dependencies.py
|
||||
│ └── routers
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── items.py
|
||||
│ │ └── users.py
|
||||
│ └── internal
|
||||
│ ├── __init__.py
|
||||
│ └── admin.py
|
||||
```
|
||||
|
||||
/// tip | Astuce
|
||||
@@ -283,7 +283,7 @@ Mais nous pouvons toujours ajouter _davantage_ de `tags` qui seront appliqués
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ce dernier *chemin d'accès* aura la combinaison de tags : `["items", "custom"]`.
|
||||
Ce dernier chemin d'accès aura la combinaison de tags : `["items", "custom"]`.
|
||||
|
||||
Et il aura également les deux réponses dans la documentation, une pour `404` et une pour `403`.
|
||||
|
||||
@@ -396,9 +396,9 @@ Cela inclura toutes les routes de ce routeur comme faisant partie de l'applicati
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
En interne, cela créera en fait un *chemin d'accès* pour chaque *chemin d'accès* qui a été déclaré dans le `APIRouter`.
|
||||
FastAPI conserve le `APIRouter` original et ses `APIRoute` actifs lorsque le routeur est inclus dans l'application principale.
|
||||
|
||||
Donc, en coulisses, cela fonctionnera comme si tout faisait partie d'une seule et même application.
|
||||
Cela signifie que des sous-classes personnalisées de `APIRouter` et `APIRoute` peuvent toujours intervenir après l'inclusion du routeur.
|
||||
|
||||
///
|
||||
|
||||
@@ -406,7 +406,7 @@ Donc, en coulisses, cela fonctionnera comme si tout faisait partie d'une seule e
|
||||
|
||||
Vous n'avez pas à vous soucier de la performance lors de l'inclusion de routeurs.
|
||||
|
||||
Cela prendra des microsecondes et ne se produira qu'au démarrage.
|
||||
C'est conçu pour être léger et pour éviter d'ajouter une surcharge à chaque requête.
|
||||
|
||||
Donc cela n'affectera pas la performance. ⚡
|
||||
|
||||
@@ -453,7 +453,7 @@ et cela fonctionnera correctement, avec tous les autres *chemins d'accès* ajout
|
||||
|
||||
/// note | Détails très techniques
|
||||
|
||||
Note : c'est un détail très technique que vous pouvez probablement **simplement ignorer**.
|
||||
**Remarque** : c'est un détail très technique que vous pouvez probablement **simplement ignorer**.
|
||||
|
||||
---
|
||||
|
||||
@@ -461,7 +461,7 @@ Les `APIRouter` ne sont pas « montés », ils ne sont pas isolés du reste de l
|
||||
|
||||
C'est parce que nous voulons inclure leurs *chemins d'accès* dans le schéma OpenAPI et les interfaces utilisateur.
|
||||
|
||||
Comme nous ne pouvons pas simplement les isoler et les « monter » indépendamment du reste, les *chemins d'accès* sont « clonés » (recréés), pas inclus directement.
|
||||
FastAPI conserve les routeurs et chemins d'accès originaux actifs, et combine les préfixes de routeur, dépendances, tags, réponses et autres métadonnées lors du traitement des requêtes et de la génération d'OpenAPI.
|
||||
|
||||
///
|
||||
|
||||
@@ -482,7 +482,7 @@ from app.main import app
|
||||
|
||||
De cette façon, la commande `fastapi` saura où trouver votre app.
|
||||
|
||||
/// note | Remarque
|
||||
/// Note | Remarque
|
||||
|
||||
Vous pourriez aussi passer le chemin à la commande, comme :
|
||||
|
||||
@@ -490,13 +490,13 @@ Vous pourriez aussi passer le chemin à la commande, comme :
|
||||
$ fastapi dev app/main.py
|
||||
```
|
||||
|
||||
Mais vous devriez vous rappeler de passer le bon chemin à chaque fois que vous appelez la commande `fastapi`.
|
||||
Mais vous devez vous rappeler de passer le bon chemin à chaque fois que vous appelez la commande `fastapi`.
|
||||
|
||||
En outre, d'autres outils pourraient ne pas être en mesure de la trouver, par exemple l'[Extension VS Code](../editor-support.md) ou [FastAPI Cloud](https://fastapicloud.com), il est donc recommandé d'utiliser l'`entrypoint` dans `pyproject.toml`.
|
||||
|
||||
///
|
||||
|
||||
## Consulter la documentation API automatique { #check-the-automatic-api-docs }
|
||||
## Consulter les documents d'API automatiques { #check-the-automatic-api-docs }
|
||||
|
||||
Maintenant, exécutez votre application :
|
||||
|
||||
@@ -512,7 +512,7 @@ $ fastapi dev
|
||||
|
||||
Et ouvrez les documents à [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
Vous verrez la documentation API automatique, incluant les chemins de tous les sous-modules, utilisant les bons chemins (et préfixes) et les bons tags :
|
||||
Vous verrez les documents d'API automatiques, incluant les chemins de tous les sous-modules, utilisant les bons chemins (et préfixes) et les bons tags :
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
@@ -532,4 +532,16 @@ De la même manière que vous pouvez inclure un `APIRouter` dans une application
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
Vous devez vous assurer de le faire avant d'inclure `router` dans l'application `FastAPI`, afin que les *chemins d'accès* de `other_router` soient également inclus.
|
||||
Vous pouvez le faire avant ou après avoir inclus `router` dans l'application `FastAPI`. FastAPI inclura quand même les *chemins d'accès* de `other_router` dans le routage et dans OpenAPI.
|
||||
|
||||
Il en va de même pour les *chemins d'accès* ajoutés plus tard aux routeurs. Ils seront visibles via l'inclusion antérieure également.
|
||||
|
||||
/// warning | Détails techniques
|
||||
|
||||
Évitez de modifier directement `router.routes` après avoir inclus un routeur. FastAPI considère l'inclusion d'un routeur comme « en direct », de sorte que le routeur original et ses routes restent utilisés pour le routage et la génération d'OpenAPI.
|
||||
|
||||
Utilisez les API documentées comme les décorateurs de *chemin d'accès* et `.include_router()` pour ajouter des routes et des routeurs.
|
||||
|
||||
Considérez `router.routes` comme un arbre de routes de plus bas niveau pouvant contenir des définitions de routes et des routeurs inclus, et évitez de vous y fier comme à une liste plate de *chemins d'accès* finaux.
|
||||
|
||||
///
|
||||
|
||||
@@ -108,7 +108,7 @@ Par exemple :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
`Body` possède également les mêmes paramètres supplémentaires de validation et de métadonnées que `Query`, `Path` et d'autres que vous verrez plus tard.
|
||||
|
||||
@@ -123,7 +123,7 @@ Par défaut, **FastAPI** attendra alors son contenu directement.
|
||||
Mais si vous voulez qu'il attende un JSON avec une clé `item` contenant le contenu du modèle, comme lorsqu'on déclare des paramètres supplémentaires du corps de la requête, vous pouvez utiliser le paramètre spécial `embed` de `Body` :
|
||||
|
||||
```Python
|
||||
item: Item = Body(embed=True)
|
||||
item: Annotated[Item, Body(embed=True)]
|
||||
```
|
||||
|
||||
comme dans :
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Corps - Modèles imbriqués { #body-nested-models }
|
||||
|
||||
Avec FastAPI, vous pouvez définir, valider, documenter et utiliser des modèles imbriqués à n'importe quelle profondeur (grâce à Pydantic).
|
||||
Avec **FastAPI**, vous pouvez définir, valider, documenter et utiliser des modèles imbriqués à n'importe quelle profondeur (grâce à Pydantic).
|
||||
|
||||
## Déclarer des champs de liste { #list-fields }
|
||||
|
||||
@@ -69,7 +69,7 @@ Nous pouvons ensuite l'utiliser comme type d'un attribut :
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
Cela signifie que FastAPI attendrait un corps similaire à :
|
||||
Cela signifie que **FastAPI** attendrait un corps similaire à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -85,7 +85,7 @@ Cela signifie que FastAPI attendrait un corps similaire à :
|
||||
}
|
||||
```
|
||||
|
||||
Là encore, avec cette simple déclaration, avec FastAPI vous obtenez :
|
||||
Là encore, avec cette simple déclaration, avec **FastAPI** vous obtenez :
|
||||
|
||||
- Prise en charge par l'éditeur (autocomplétion, etc.), même pour les modèles imbriqués
|
||||
- Conversion des données
|
||||
@@ -135,7 +135,7 @@ Cela attendra (convertira, validera, documentera, etc.) un corps JSON comme :
|
||||
]
|
||||
}
|
||||
```
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Remarquez que la clé `images` contient maintenant une liste d'objets image.
|
||||
|
||||
@@ -147,7 +147,7 @@ Vous pouvez définir des modèles imbriqués à une profondeur arbitraire :
|
||||
|
||||
{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Remarquez que `Offer` a une liste d’`Item`, qui à leur tour ont une liste optionnelle d’`Image`.
|
||||
|
||||
@@ -209,7 +209,7 @@ Et le `dict` que vous recevez dans `weights` aura en réalité des clés `int` e
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Avec FastAPI, vous bénéficiez de la flexibilité maximale fournie par les modèles Pydantic, tout en gardant votre code simple, concis et élégant.
|
||||
Avec **FastAPI**, vous bénéficiez de la flexibilité maximale fournie par les modèles Pydantic, tout en gardant votre code simple, concis et élégant.
|
||||
|
||||
Mais avec tous les avantages :
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Corps de la requête { #request-body }
|
||||
|
||||
Quand vous avez besoin d'envoyer de la donnée depuis un client (comme un navigateur) vers votre API, vous l'envoyez en tant que **corps de requête**.
|
||||
Quand vous avez besoin d'envoyer de la donnée depuis un client (comme un navigateur) vers votre API, vous l'envoyez en tant que **corps de la requête**.
|
||||
|
||||
Le corps d'une **requête** est de la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée envoyée par votre API au client.
|
||||
|
||||
Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un **corps de requête** : parfois il demande seulement un chemin, peut-être avec quelques paramètres de requête, mais n'envoie pas de corps.
|
||||
Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un **corps de la requête** : parfois il demande seulement un chemin, peut-être avec quelques paramètres de requête, mais n'envoie pas de corps.
|
||||
|
||||
Pour déclarer un corps de **requête**, on utilise les modèles de [Pydantic](https://docs.pydantic.dev/) en profitant de tous leurs avantages et fonctionnalités.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour envoyer de la donnée, vous devez utiliser : `POST` (le plus populaire), `PUT`, `DELETE` ou `PATCH`.
|
||||
Pour envoyer de la donnée, vous devez utiliser l'une de ces méthodes : `POST` (le plus populaire), `PUT`, `DELETE` ou `PATCH`.
|
||||
|
||||
Envoyer un corps dans une requête `GET` a un comportement non défini dans les spécifications, cela est néanmoins supporté par **FastAPI**, seulement pour des cas d'utilisation très complexes/extrêmes.
|
||||
Envoyer un corps dans une requête `GET` a un comportement non défini dans les spécifications, cela est néanmoins supporté par FastAPI, seulement pour des cas d'utilisation très complexes/extrêmes.
|
||||
|
||||
Ceci étant découragé, la documentation interactive générée par Swagger UI ne montrera pas de documentation pour le corps d'une requête `GET`, et les proxys intermédiaires risquent de ne pas le supporter.
|
||||
|
||||
@@ -32,6 +32,7 @@ Utilisez les types Python standard pour tous les attributs :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
|
||||
Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, il est requis. Utilisez `None` pour le rendre simplement optionnel.
|
||||
|
||||
Par exemple, le modèle ci-dessus déclare un JSON « `object` » (ou `dict` Python) tel que :
|
||||
@@ -73,7 +74,7 @@ En utilisant uniquement les déclarations de type Python, **FastAPI** réussit
|
||||
* Passer la donnée reçue dans le paramètre `item`.
|
||||
* Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (autocomplétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs.
|
||||
* Générer des définitions [JSON Schema](https://json-schema.org) pour votre modèle ; vous pouvez également les utiliser partout ailleurs si cela a du sens pour votre projet.
|
||||
* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront utilisés par les documentations automatiques <abbr title="User Interfaces - Interfaces utilisateur">UIs</abbr>.
|
||||
* Ces schémas feront partie du schéma OpenAPI généré, et seront utilisés par les <abbr title="User Interfaces - Interfaces utilisateur">UIs</abbr> de la documentation automatique.
|
||||
|
||||
## Documentation automatique { #automatic-docs }
|
||||
|
||||
@@ -97,11 +98,11 @@ Et vous obtenez aussi des vérifications d'erreurs pour les opérations de types
|
||||
|
||||
Ce n'est pas un hasard, ce framework entier a été bâti avec ce design comme objectif.
|
||||
|
||||
Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour vous assurer que cela fonctionnerait avec tous les éditeurs.
|
||||
Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour s'assurer que cela fonctionnerait avec tous les éditeurs.
|
||||
|
||||
Des changements sur Pydantic ont même été faits pour supporter cela.
|
||||
|
||||
Les captures d'écran précédentes ont été prises sur [Visual Studio Code](https://code.visualstudio.com).
|
||||
Les captures d'écran précédentes ont été prises avec [Visual Studio Code](https://code.visualstudio.com).
|
||||
|
||||
Mais vous auriez le même support de l'éditeur avec [PyCharm](https://www.jetbrains.com/pycharm/) et la majorité des autres éditeurs de code Python :
|
||||
|
||||
@@ -129,15 +130,16 @@ Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modè
|
||||
|
||||
## Corps de la requête + paramètres de chemin { #request-body-path-parameters }
|
||||
|
||||
Vous pouvez déclarer des paramètres de chemin et un corps de requête pour la même *chemin d'accès*.
|
||||
Vous pouvez déclarer des paramètres de chemin et le corps de la requête en même temps.
|
||||
|
||||
**FastAPI** est capable de reconnaître que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de fonctions déclarés comme modèles Pydantic devraient être **récupérés depuis le corps de la requête**.
|
||||
**FastAPI** est capable de reconnaître que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de la fonction déclarés comme modèles Pydantic devraient être **récupérés depuis le corps de la requête**.
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
|
||||
## Corps de la requête + paramètres de chemin et de requête { #request-body-path-query-parameters }
|
||||
|
||||
Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête** dans la même *chemin d'accès*.
|
||||
Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête**, tous en même temps.
|
||||
|
||||
**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit.
|
||||
|
||||
@@ -151,9 +153,9 @@ Les paramètres de la fonction seront reconnus comme tel :
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
|
||||
FastAPI saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
|
||||
|
||||
L'annotation de type `str | None` n'est pas utilisée par **FastAPI** pour déterminer que la valeur n'est pas requise, il le saura parce qu'elle a une valeur par défaut `= None`.
|
||||
L'annotation de type `str | None` n'est pas utilisée par FastAPI pour déterminer que la valeur n'est pas requise, il le saura parce qu'elle a une valeur par défaut `= None`.
|
||||
|
||||
Mais ajouter ces annotations de type permettra à votre éditeur de vous offrir un meilleur support et de détecter des erreurs.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Vous pouvez voir les cookies définis dans l'interface de la documentation à `/
|
||||
<img src="/img/tutorial/cookie-param-models/image01.png">
|
||||
</div>
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Gardez à l'esprit que, comme les **navigateurs gèrent les cookies** de manière particulière et en arrière-plan, ils **n'autorisent pas** facilement **JavaScript** à y accéder.
|
||||
|
||||
|
||||
@@ -24,13 +24,13 @@ Mais rappelez-vous que lorsque vous importez `Query`, `Path`, `Cookie` et d'autr
|
||||
|
||||
///
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour déclarer des cookies, vous devez utiliser `Cookie`, sinon les paramètres seraient interprétés comme des paramètres de requête.
|
||||
|
||||
///
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Gardez à l'esprit que, comme **les navigateurs gèrent les cookies** de manière particulière et en coulisses, ils **n'autorisent pas** facilement **JavaScript** à y accéder.
|
||||
|
||||
|
||||
@@ -72,9 +72,9 @@ Ainsi, la ligne :
|
||||
|
||||
ne sera pas exécutée.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour plus d'informations, consultez [la documentation officielle de Python](https://docs.python.org/3/library/__main__.html).
|
||||
Pour plus d'informations, consultez [les documents officiels de Python](https://docs.python.org/3/library/__main__.html).
|
||||
|
||||
///
|
||||
|
||||
@@ -86,10 +86,10 @@ Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous
|
||||
|
||||
Par exemple, dans Visual Studio Code, vous pouvez :
|
||||
|
||||
- Allez dans le panneau « Debug ».
|
||||
- « Add configuration ... ».
|
||||
- Sélectionnez « Python ».
|
||||
- Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option « Python: Current File (Integrated Terminal) ».
|
||||
* Allez dans le panneau « Debug ».
|
||||
* « Add configuration... ».
|
||||
* Sélectionnez « Python ».
|
||||
* Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option « `Python: Current File (Integrated Terminal)` ».
|
||||
|
||||
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
|
||||
|
||||
@@ -99,12 +99,12 @@ Voici à quoi cela pourrait ressembler :
|
||||
|
||||
---
|
||||
|
||||
Si vous utilisez Pycharm, vous pouvez :
|
||||
Si vous utilisez PyCharm, vous pouvez :
|
||||
|
||||
- Ouvrez le menu « Run ».
|
||||
- Sélectionnez l'option « Debug ... ».
|
||||
- Un menu contextuel s'affiche alors.
|
||||
- Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).
|
||||
* Ouvrez le menu « Run ».
|
||||
* Sélectionnez l'option « Debug... ».
|
||||
* Un menu contextuel s'affiche alors.
|
||||
* Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).
|
||||
|
||||
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Cela peut également éviter toute confusion pour les nouveaux développeurs qui
|
||||
|
||||
///
|
||||
|
||||
/// info | Info
|
||||
/// note | Remarque
|
||||
|
||||
Dans cet exemple, nous utilisons des en-têtes personnalisés fictifs `X-Key` et `X-Token`.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Utiliser des dépendances avec `yield` { #dependencies-with-yield }
|
||||
|
||||
FastAPI prend en charge des dépendances qui effectuent des <dfn title='parfois aussi appelées « exit code », « cleanup code », « teardown code », « closing code », « context manager exit code », etc.'>étapes supplémentaires après l'exécution</dfn>.
|
||||
FastAPI prend en charge des dépendances qui effectuent des <dfn title='parfois également appelées « code de sortie », « code de nettoyage », « code de démontage », « code de fermeture », « code de sortie de gestionnaire de contexte », etc.'>étapes supplémentaires après l'exécution</dfn>.
|
||||
|
||||
Pour cela, utilisez `yield` au lieu de `return`, et écrivez les étapes supplémentaires (code) après.
|
||||
|
||||
@@ -170,7 +170,7 @@ participant tasks as Background tasks
|
||||
end
|
||||
```
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Une **seule réponse** sera envoyée au client. Il peut s'agir d'une des réponses d'erreur ou de la réponse provenant du *chemin d'accès*.
|
||||
|
||||
@@ -194,16 +194,16 @@ Mais si vous savez que vous n'aurez pas besoin d'utiliser la dépendance après
|
||||
|
||||
`Depends()` reçoit un paramètre `scope` qui peut être :
|
||||
|
||||
* « function » : démarrer la dépendance avant la *fonction de chemin d'accès* qui gère la requête, terminer la dépendance après la fin de la *fonction de chemin d'accès*, mais **avant** que la réponse ne soit renvoyée au client. Ainsi, la fonction de dépendance sera exécutée **autour** de la *fonction de chemin d'accès*.
|
||||
* « request » : démarrer la dépendance avant la *fonction de chemin d'accès* qui gère la requête (similaire à l'utilisation de « function »), mais terminer **après** que la réponse a été renvoyée au client. Ainsi, la fonction de dépendance sera exécutée **autour** du cycle **requête** et réponse.
|
||||
* `"function"` : démarrer la dépendance avant la *fonction de chemin d'accès* qui gère la requête, terminer la dépendance après la fin de la *fonction de chemin d'accès*, mais **avant** que la réponse ne soit renvoyée au client. Ainsi, la fonction de dépendance sera exécutée **autour** de la *fonction de chemin d'accès*.
|
||||
* `"request"` : démarrer la dépendance avant la *fonction de chemin d'accès* qui gère la requête (similaire à l'utilisation de `"function"`), mais terminer **après** que la réponse a été renvoyée au client. Ainsi, la fonction de dépendance sera exécutée **autour** du cycle **requête** et réponse.
|
||||
|
||||
S'il n'est pas spécifié et que la dépendance utilise `yield`, le `scope` sera par défaut « request ».
|
||||
S'il n'est pas spécifié et que la dépendance utilise `yield`, le `scope` sera par défaut `"request"`.
|
||||
|
||||
### Définir `scope` pour les sous-dépendances { #scope-for-sub-dependencies }
|
||||
|
||||
Lorsque vous déclarez une dépendance avec un `scope="request"` (par défaut), toute sous-dépendance doit également avoir un `scope` de « request ».
|
||||
Lorsque vous déclarez une dépendance avec un `scope="request"` (par défaut), toute sous-dépendance doit également avoir un `scope` de `"request"`.
|
||||
|
||||
Mais une dépendance avec un `scope` de « function » peut avoir des dépendances avec un `scope` de « function » et un `scope` de « request ».
|
||||
Mais une dépendance avec un `scope` de `"function"` peut avoir des dépendances avec un `scope` de `"function"` et un `scope` de `"request"`.
|
||||
|
||||
Cela vient du fait que toute dépendance doit pouvoir exécuter son code de sortie avant ses sous-dépendances, car elle pourrait encore avoir besoin de les utiliser pendant son code de sortie.
|
||||
|
||||
@@ -234,6 +234,7 @@ participant operation as Path Operation
|
||||
Les dépendances avec `yield` ont évolué au fil du temps pour couvrir différents cas d'utilisation et corriger certains problèmes.
|
||||
|
||||
Si vous souhaitez voir ce qui a changé dans différentes versions de FastAPI, vous pouvez en savoir plus dans le guide avancé, dans [Dépendances avancées - Dépendances avec `yield`, `HTTPException`, `except` et Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).
|
||||
|
||||
## Gestionnaires de contexte { #context-managers }
|
||||
|
||||
### Que sont les « Context Managers » { #what-are-context-managers }
|
||||
|
||||
@@ -6,7 +6,7 @@ Il est conçu pour être très simple à utiliser, et pour faciliter l’intégr
|
||||
|
||||
## Qu’est-ce que « l’injection de dépendances » { #what-is-dependency-injection }
|
||||
|
||||
L’**« injection de dépendances »** signifie, en programmation, qu’il existe un moyen pour votre code (dans ce cas, vos fonctions de chemins d’accès) de déclarer ce dont il a besoin pour fonctionner et utiliser : « dépendances ».
|
||||
L’**« injection de dépendances »** signifie, en programmation, qu’il existe un moyen pour votre code (dans ce cas, vos fonctions de chemin d’accès) de déclarer ce dont il a besoin pour fonctionner et utiliser : « dépendances ».
|
||||
|
||||
Ensuite, ce système (dans ce cas **FastAPI**) se charge de faire tout le nécessaire pour fournir à votre code ces dépendances requises (« injecter » les dépendances).
|
||||
|
||||
@@ -37,7 +37,7 @@ C’est tout.
|
||||
|
||||
**2 lignes**.
|
||||
|
||||
Et elle a la même forme et structure que toutes vos fonctions de chemins d’accès.
|
||||
Et elle a la même forme et structure que toutes vos fonctions de chemin d’accès.
|
||||
|
||||
Vous pouvez la considérer comme une fonction de chemin d’accès sans le « décorateur » (sans le `@app.get("/some-path")`).
|
||||
|
||||
@@ -51,7 +51,7 @@ Dans ce cas, cette dépendance attend :
|
||||
|
||||
Puis elle retourne simplement un `dict` contenant ces valeurs.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
FastAPI a ajouté la prise en charge de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
|
||||
|
||||
@@ -79,7 +79,7 @@ Ce paramètre doit être quelque chose comme une fonction.
|
||||
|
||||
Vous ne l’appelez pas directement (n’ajoutez pas de parenthèses à la fin), vous le passez simplement en paramètre à `Depends()`.
|
||||
|
||||
Et cette fonction prend des paramètres de la même manière que les fonctions de chemins d’accès.
|
||||
Et cette fonction prend des paramètres de la même manière que les fonctions de chemin d’accès.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
@@ -106,7 +106,7 @@ common_parameters --> read_users
|
||||
|
||||
De cette façon vous écrivez le code partagé une seule fois et **FastAPI** se charge de l’appeler pour vos chemins d’accès.
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
Notez que vous n’avez pas à créer une classe spéciale et à la passer quelque part à **FastAPI** pour l’« enregistrer » ou quoi que ce soit de similaire.
|
||||
|
||||
@@ -142,11 +142,11 @@ Cela sera particulièrement utile lorsque vous l’utiliserez dans une **grande
|
||||
|
||||
## Utiliser `async` ou non { #to-async-or-not-to-async }
|
||||
|
||||
Comme les dépendances seront aussi appelées par **FastAPI** (tout comme vos fonctions de chemins d’accès), les mêmes règles s’appliquent lors de la définition de vos fonctions.
|
||||
Comme les dépendances seront aussi appelées par **FastAPI** (tout comme vos fonctions de chemin d’accès), les mêmes règles s’appliquent lors de la définition de vos fonctions.
|
||||
|
||||
Vous pouvez utiliser `async def` ou un `def` normal.
|
||||
|
||||
Et vous pouvez déclarer des dépendances avec `async def` à l’intérieur de fonctions de chemins d’accès `def` normales, ou des dépendances `def` à l’intérieur de fonctions de chemins d’accès `async def`, etc.
|
||||
Et vous pouvez déclarer des dépendances avec `async def` à l’intérieur de fonctions de chemin d’accès `def` normales, ou des dépendances `def` à l’intérieur de fonctions de chemin d’accès `async def`, etc.
|
||||
|
||||
Peu importe. **FastAPI** saura quoi faire.
|
||||
|
||||
@@ -166,7 +166,7 @@ Ainsi, la documentation interactive contiendra aussi toutes les informations iss
|
||||
|
||||
## Utilisation simple { #simple-usage }
|
||||
|
||||
Si vous y regardez de près, les fonctions de chemins d’accès sont déclarées pour être utilisées chaque fois qu’un « chemin » et une « opération » correspondent, puis **FastAPI** se charge d’appeler la fonction avec les bons paramètres, en extrayant les données de la requête.
|
||||
Si vous y regardez de près, les fonctions de chemin d’accès sont déclarées pour être utilisées chaque fois qu’un « chemin » et une « opération » correspondent, puis **FastAPI** se charge d’appeler la fonction avec les bons paramètres, en extrayant les données de la requête.
|
||||
|
||||
En réalité, tous (ou la plupart) des frameworks web fonctionnent de cette manière.
|
||||
|
||||
@@ -184,7 +184,7 @@ D’autres termes courants pour cette même idée « d’injection de dépendanc
|
||||
|
||||
## Plug-ins **FastAPI** { #fastapi-plug-ins }
|
||||
|
||||
Les intégrations et « plug-ins » peuvent être construits en utilisant le système d’**injection de dépendances**. Mais en réalité, il n’y a **pas besoin de créer des « plug-ins »**, car en utilisant des dépendances il est possible de déclarer un nombre infini d’intégrations et d’interactions qui deviennent disponibles pour vos fonctions de chemins d’accès.
|
||||
Les intégrations et « plug-ins » peuvent être construits en utilisant le système d’**injection de dépendances**. Mais en réalité, il n’y a **pas besoin de créer des « plug-ins »**, car en utilisant des dépendances il est possible de déclarer un nombre infini d’intégrations et d’interactions qui deviennent disponibles pour vos fonctions de chemin d’accès.
|
||||
|
||||
Et les dépendances peuvent être créées de manière très simple et intuitive, ce qui vous permet d’importer juste les packages Python dont vous avez besoin, et de les intégrer à vos fonctions d’API en quelques lignes de code, *littéralement*.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Sous-dépendances { #sub-dependencies }
|
||||
|
||||
Vous pouvez créer des dépendances qui ont des sous-dépendances.
|
||||
Vous pouvez créer des dépendances qui ont des **sous-dépendances**.
|
||||
|
||||
Elles peuvent être aussi profondes que nécessaire.
|
||||
Elles peuvent être aussi **profondes** que nécessaire.
|
||||
|
||||
**FastAPI** se chargera de les résoudre.
|
||||
|
||||
@@ -35,7 +35,7 @@ Nous pouvons ensuite utiliser la dépendance avec :
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Notez que nous ne déclarons qu'une seule dépendance dans la *fonction de chemin d'accès*, `query_or_cookie_extractor`.
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ Voici quelques types de données supplémentaires que vous pouvez utiliser :
|
||||
* `datetime.timedelta` :
|
||||
* Un `datetime.timedelta` Python.
|
||||
* Dans les requêtes et les réponses, il sera représenté sous forme de `float` de secondes totales.
|
||||
* Pydantic permet aussi de le représenter sous la forme d'un « encodage de différence de temps ISO 8601 », [voir la documentation pour plus d'informations](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
|
||||
* Pydantic permet aussi de le représenter sous la forme d'un « encodage de différence de temps ISO 8601 », [voir les documents pour plus d'informations](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).
|
||||
* `frozenset` :
|
||||
* Dans les requêtes et les réponses, traité de la même manière qu'un `set` :
|
||||
* Dans les requêtes, une liste sera lue, les doublons éliminés, puis convertie en `set`.
|
||||
|
||||
@@ -4,9 +4,9 @@ En poursuivant l'exemple précédent, il est courant d'avoir plusieurs modèles
|
||||
|
||||
C'est particulièrement vrai pour les modèles d'utilisateur, car :
|
||||
|
||||
* Le modèle d'entrée doit pouvoir contenir un mot de passe.
|
||||
* Le modèle de sortie ne doit pas avoir de mot de passe.
|
||||
* Le modèle de base de données devra probablement avoir un mot de passe haché.
|
||||
* Le **modèle d'entrée** doit pouvoir contenir un mot de passe.
|
||||
* Le **modèle de sortie** ne doit pas avoir de mot de passe.
|
||||
* Le **modèle de base de données** aurait probablement besoin d'avoir un mot de passe haché.
|
||||
|
||||
/// danger | Danger
|
||||
|
||||
@@ -30,13 +30,13 @@ Voici une idée générale de l'apparence des modèles avec leurs champs de mot
|
||||
|
||||
Les modèles Pydantic ont une méthode `.model_dump()` qui renvoie un `dict` avec les données du modèle.
|
||||
|
||||
Ainsi, si nous créons un objet Pydantic `user_in` comme :
|
||||
Ainsi, si nous créons un objet Pydantic `user_in` comme :
|
||||
|
||||
```Python
|
||||
user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
|
||||
```
|
||||
|
||||
et que nous appelons ensuite :
|
||||
et que nous appelons ensuite :
|
||||
|
||||
```Python
|
||||
user_dict = user_in.model_dump()
|
||||
@@ -44,13 +44,13 @@ user_dict = user_in.model_dump()
|
||||
|
||||
nous avons maintenant un `dict` avec les données dans la variable `user_dict` (c'est un `dict` au lieu d'un objet modèle Pydantic).
|
||||
|
||||
Et si nous appelons :
|
||||
Et si nous appelons :
|
||||
|
||||
```Python
|
||||
print(user_dict)
|
||||
```
|
||||
|
||||
nous obtiendrions un `dict` Python contenant :
|
||||
nous obtiendrions un `dict` Python contenant :
|
||||
|
||||
```Python
|
||||
{
|
||||
@@ -63,15 +63,15 @@ nous obtiendrions un `dict` Python contenant :
|
||||
|
||||
#### Déballer un `dict` { #unpacking-a-dict }
|
||||
|
||||
Si nous prenons un `dict` comme `user_dict` et que nous le passons à une fonction (ou une classe) avec `**user_dict`, Python va « déballer » ce `dict`. Il passera les clés et valeurs de `user_dict` directement comme arguments nommés.
|
||||
Si nous prenons un `dict` comme `user_dict` et que nous le passons à une fonction (ou une classe) avec `**user_dict`, Python va « déballer » ce `dict`. Il passera les clés et valeurs de `user_dict` directement comme arguments clé-valeur.
|
||||
|
||||
Ainsi, en reprenant `user_dict` ci-dessus, écrire :
|
||||
Ainsi, en reprenant `user_dict` ci-dessus, écrire :
|
||||
|
||||
```Python
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
aurait pour résultat quelque chose d'équivalent à :
|
||||
aurait pour résultat quelque chose d'équivalent à :
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -82,7 +82,7 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
Ou plus exactement, en utilisant `user_dict` directement, quels que soient ses contenus futurs :
|
||||
Ou plus exactement, en utilisant `user_dict` directement, quels que soient ses contenus futurs :
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -95,14 +95,14 @@ UserInDB(
|
||||
|
||||
#### Créer un modèle Pydantic à partir du contenu d'un autre { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
Comme dans l'exemple ci-dessus nous avons obtenu `user_dict` depuis `user_in.model_dump()`, ce code :
|
||||
Comme dans l'exemple ci-dessus nous avons obtenu `user_dict` depuis `user_in.model_dump()`, ce code :
|
||||
|
||||
```Python
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
serait équivalent à :
|
||||
serait équivalent à :
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.model_dump())
|
||||
@@ -114,13 +114,13 @@ Ainsi, nous obtenons un modèle Pydantic à partir des données d'un autre modè
|
||||
|
||||
#### Déballer un `dict` et ajouter des mots-clés supplémentaires { #unpacking-a-dict-and-extra-keywords }
|
||||
|
||||
Et en ajoutant ensuite l'argument nommé supplémentaire `hashed_password=hashed_password`, comme ici :
|
||||
Et en ajoutant ensuite l'argument nommé supplémentaire `hashed_password=hashed_password`, comme ici :
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
... revient à :
|
||||
... revient à :
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -152,7 +152,7 @@ Nous pouvons déclarer un modèle `UserBase` qui sert de base à nos autres mod
|
||||
|
||||
Toutes les conversions de données, validations, documentation, etc., fonctionneront comme d'habitude.
|
||||
|
||||
De cette façon, nous pouvons ne déclarer que les différences entre les modèles (avec `password` en clair, avec `hashed_password` et sans mot de passe) :
|
||||
De cette façon, nous pouvons ne déclarer que les différences entre les modèles (avec `password` en clair, avec `hashed_password` et sans mot de passe) :
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
|
||||
|
||||
@@ -162,7 +162,7 @@ Vous pouvez déclarer qu'une réponse est l'`Union` de deux types ou plus, ce qu
|
||||
|
||||
Cela sera défini dans OpenAPI avec `anyOf`.
|
||||
|
||||
Pour ce faire, utilisez l'annotation de type Python standard [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union) :
|
||||
Pour ce faire, utilisez l'annotation de type Python standard [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union) :
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
@@ -176,21 +176,21 @@ Lors de la définition d'une [`Union`](https://docs.pydantic.dev/latest/concepts
|
||||
|
||||
Dans cet exemple, nous passons `Union[PlaneItem, CarItem]` comme valeur de l'argument `response_model`.
|
||||
|
||||
Comme nous le passons comme valeur d'un argument au lieu de l'utiliser dans une annotation de type, nous devons utiliser `Union` même en Python 3.10.
|
||||
Comme nous le passons comme **valeur à un argument** au lieu de l'utiliser dans une **annotation de type**, nous devons utiliser `Union` même en Python 3.10.
|
||||
|
||||
S'il s'agissait d'une annotation de type, nous pourrions utiliser la barre verticale, comme :
|
||||
S'il s'agissait d'une annotation de type, nous pourrions utiliser la barre verticale, comme :
|
||||
|
||||
```Python
|
||||
some_variable: PlaneItem | CarItem
|
||||
```
|
||||
|
||||
Mais si nous écrivons cela dans l'affectation `response_model=PlaneItem | CarItem`, nous obtiendrons une erreur, car Python essaierait d'effectuer une « opération invalide » entre `PlaneItem` et `CarItem` au lieu de l'interpréter comme une annotation de type.
|
||||
Mais si nous écrivons cela dans l'affectation `response_model=PlaneItem | CarItem`, nous obtiendrons une erreur, car Python essaierait d'effectuer une **opération invalide** entre `PlaneItem` et `CarItem` au lieu de l'interpréter comme une annotation de type.
|
||||
|
||||
## Liste de modèles { #list-of-models }
|
||||
|
||||
De la même manière, vous pouvez déclarer des réponses contenant des listes d'objets.
|
||||
|
||||
Pour cela, utilisez le `list` Python standard :
|
||||
Pour cela, utilisez le `list` Python standard :
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}
|
||||
|
||||
@@ -200,7 +200,7 @@ Vous pouvez également déclarer une réponse en utilisant un simple `dict` arbi
|
||||
|
||||
C'est utile si vous ne connaissez pas à l'avance les noms de champs/attributs valides (qui seraient nécessaires pour un modèle Pydantic).
|
||||
|
||||
Dans ce cas, vous pouvez utiliser `dict` :
|
||||
Dans ce cas, vous pouvez utiliser `dict` :
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}
|
||||
|
||||
@@ -208,4 +208,4 @@ Dans ce cas, vous pouvez utiliser `dict` :
|
||||
|
||||
Utilisez plusieurs modèles Pydantic et héritez librement selon chaque cas.
|
||||
|
||||
Vous n'avez pas besoin d'avoir un seul modèle de données par entité si cette entité doit pouvoir avoir différents « états ». Comme pour l'« entité » utilisateur, avec un état incluant `password`, `password_hash` et sans mot de passe.
|
||||
Vous n'avez pas besoin d'avoir un seul modèle de données par entité si cette entité doit pouvoir avoir différents « états ». L'« entité » **utilisateur** est un exemple, avec des états qui incluent `password`, `password_hash`, ou aucun mot de passe.
|
||||
|
||||
@@ -145,20 +145,20 @@ Vous pourriez également l’utiliser pour générer du code automatiquement, po
|
||||
|
||||
### Configurer le `entrypoint` de l’application dans `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }
|
||||
|
||||
Vous pouvez configurer l’emplacement de votre application dans un fichier `pyproject.toml` comme :
|
||||
Vous pouvez configurer l’emplacement de votre application dans un fichier `pyproject.toml` comme :
|
||||
|
||||
```toml
|
||||
[tool.fastapi]
|
||||
entrypoint = "main:app"
|
||||
```
|
||||
|
||||
Ce `entrypoint` indiquera à la commande `fastapi` qu’elle doit importer l’application comme :
|
||||
Ce `entrypoint` indiquera à la commande `fastapi` qu’elle doit importer l’application comme :
|
||||
|
||||
```python
|
||||
from main import app
|
||||
```
|
||||
|
||||
Si votre code est structuré comme :
|
||||
Si votre code est structuré comme :
|
||||
|
||||
```
|
||||
.
|
||||
@@ -167,50 +167,40 @@ Si votre code est structuré comme :
|
||||
│ ├── __init__.py
|
||||
```
|
||||
|
||||
Alors vous définiriez le `entrypoint` comme :
|
||||
Alors vous définiriez le `entrypoint` comme :
|
||||
|
||||
```toml
|
||||
[tool.fastapi]
|
||||
entrypoint = "backend.main:app"
|
||||
```
|
||||
|
||||
ce qui équivaudrait à :
|
||||
ce qui équivaudrait à :
|
||||
|
||||
```python
|
||||
from backend.main import app
|
||||
```
|
||||
|
||||
### `fastapi dev` avec un chemin { #fastapi-dev-with-path }
|
||||
### `fastapi dev` avec un chemin ou avec l’option CLI `--entrypoint` { #fastapi-dev-with-path-or-with-entrypoint-cli-option }
|
||||
|
||||
Vous pouvez également passer le chemin du fichier à la commande `fastapi dev`, et elle devinera l’objet d’application FastAPI à utiliser :
|
||||
Vous pouvez également passer le chemin du fichier à la commande `fastapi dev`, et elle devinera l’objet d’application FastAPI à utiliser :
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
```
|
||||
|
||||
Mais vous devrez vous souvenir de passer le chemin correct à chaque exécution de la commande `fastapi`.
|
||||
Ou bien, vous pouvez aussi passer l’option `--entrypoint` à la commande `fastapi dev` :
|
||||
|
||||
```console
|
||||
$ fastapi dev --entrypoint main:app
|
||||
```
|
||||
|
||||
Mais vous devez vous souvenir de passer le chemin\entrypoint correct à chaque exécution de la commande `fastapi`.
|
||||
|
||||
De plus, d’autres outils pourraient ne pas être capables de le trouver, par exemple l’[Extension VS Code](../editor-support.md) ou [FastAPI Cloud](https://fastapicloud.com), il est donc recommandé d’utiliser le `entrypoint` dans `pyproject.toml`.
|
||||
|
||||
### Déployer votre application (optionnel) { #deploy-your-app-optional }
|
||||
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com), allez rejoindre la liste d’attente si ce n’est pas déjà fait. 🚀
|
||||
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
|
||||
Avant de déployer, vous devez vous assurer que vous êtes connecté :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi login
|
||||
|
||||
You are logged in to FastAPI Cloud 🚀
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Puis déployez votre application :
|
||||
Vous pouvez éventuellement déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com) avec une seule commande. 🚀
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -226,6 +216,8 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
Le CLI détectera automatiquement votre application FastAPI et la déploiera dans le cloud. Si vous n’êtes pas connecté, votre navigateur s’ouvrira pour terminer le processus d’authentification.
|
||||
|
||||
C’est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
|
||||
## Récapitulatif, étape par étape { #recap-step-by-step }
|
||||
@@ -252,7 +244,7 @@ Ici, la variable `app` sera une « instance » de la classe `FastAPI`.
|
||||
|
||||
Ce sera le point principal d’interaction pour créer toute votre API.
|
||||
|
||||
### Étape 3 : créer un « chemin d’accès » { #step-3-create-a-path-operation }
|
||||
### Étape 3 : créer un *chemin d’accès* { #step-3-create-a-path-operation }
|
||||
|
||||
#### Chemin { #path }
|
||||
|
||||
@@ -270,7 +262,7 @@ https://example.com/items/foo
|
||||
/items/foo
|
||||
```
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Un « chemin » est aussi couramment appelé « endpoint » ou « route ».
|
||||
|
||||
@@ -313,26 +305,26 @@ Donc, dans OpenAPI, chacune des méthodes HTTP est appelée une « opération »
|
||||
|
||||
Nous allons donc aussi les appeler « opérations ».
|
||||
|
||||
#### Définir un « décorateur de chemin d’accès » { #define-a-path-operation-decorator }
|
||||
#### Définir un *décorateur de chemin d’accès* { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}
|
||||
|
||||
Le `@app.get("/")` indique à **FastAPI** que la fonction juste en dessous est chargée de gérer les requêtes qui vont vers :
|
||||
Le `@app.get("/")` indique à **FastAPI** que la fonction juste en dessous est chargée de gérer les requêtes qui vont vers :
|
||||
|
||||
* le chemin `/`
|
||||
* en utilisant une <dfn title="une méthode HTTP GET"><code>get</code> opération</dfn>
|
||||
|
||||
/// info | `@decorator` Info
|
||||
/// note | Informations sur `@decorator`
|
||||
|
||||
Cette syntaxe `@something` en Python est appelée un « décorateur ».
|
||||
|
||||
Vous la mettez au-dessus d’une fonction. Comme un joli chapeau décoratif (j’imagine que c’est de là que vient le terme 🤷🏻♂).
|
||||
Vous la mettez au-dessus d’une fonction. Comme un joli chapeau décoratif (j’imagine que c’est de là que vient le terme).
|
||||
|
||||
Un « décorateur » prend la fonction en dessous et fait quelque chose avec.
|
||||
|
||||
Dans notre cas, ce décorateur indique à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec une **opération** `get`.
|
||||
|
||||
C’est le « décorateur de chemin d’accès ».
|
||||
C’est le **« décorateur de chemin d’accès »**.
|
||||
|
||||
///
|
||||
|
||||
@@ -363,7 +355,7 @@ Par exemple, lorsque vous utilisez GraphQL, vous effectuez normalement toutes le
|
||||
|
||||
### Étape 4 : définir la **fonction de chemin d’accès** { #step-4-define-the-path-operation-function }
|
||||
|
||||
Voici notre « fonction de chemin d’accès » :
|
||||
Voici notre **« fonction de chemin d’accès »** :
|
||||
|
||||
* **chemin** : `/`.
|
||||
* **opération** : `get`.
|
||||
@@ -373,7 +365,7 @@ Voici notre « fonction de chemin d’accès » :
|
||||
|
||||
C’est une fonction Python.
|
||||
|
||||
Elle sera appelée par **FastAPI** chaque fois qu’il recevra une requête vers l’URL « / » en utilisant une opération `GET`.
|
||||
Elle sera appelée par **FastAPI** chaque fois qu’il recevra une requête vers l’URL « `/` » en utilisant une opération `GET`.
|
||||
|
||||
Dans ce cas, c’est une fonction `async`.
|
||||
|
||||
@@ -385,7 +377,7 @@ Vous pouvez aussi la définir comme une fonction normale au lieu de `async def`
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Si vous ne connaissez pas la différence, consultez [Asynchrone : « Pressé ? »](../async.md#in-a-hurry).
|
||||
Si vous ne connaissez pas la différence, consultez [Asynchrone : *« Pressé ? »*](../async.md#in-a-hurry).
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
# Frontend { #frontend }
|
||||
|
||||
Vous pouvez servir des applications frontend statiques avec `app.frontend()` (ou `router.frontend()`).
|
||||
|
||||
C'est utile pour les outils frontend qui génèrent des fichiers statiques, comme React avec Vite, TanStack Router, Astro, Vue, Svelte, Angular, Solid, et d'autres.
|
||||
|
||||
Avec ces outils, vous avez normalement une étape qui build le frontend, avec une commande comme :
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Cela générerait un répertoire comme `./dist/` avec vos fichiers frontend.
|
||||
|
||||
Vous pouvez utiliser `app.frontend()` pour servir ce répertoire en suivant les conventions nécessaires à ces frameworks frontend.
|
||||
|
||||
**FastAPI** vérifie d'abord les *chemins d'accès*. Les fichiers frontend ne sont vérifiés que si aucune route normale ne correspond, donc votre API ne sera pas affectée.
|
||||
|
||||
## Servir un frontend { #serve-a-frontend }
|
||||
|
||||
Après avoir build votre frontend, par exemple avec `npm run build`, placez les fichiers générés dans un répertoire, par exemple `dist`.
|
||||
|
||||
La structure de votre projet pourrait ressembler à ceci :
|
||||
|
||||
```text
|
||||
.
|
||||
├── pyproject.toml
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ └── main.py
|
||||
└── dist
|
||||
├── index.html
|
||||
└── assets
|
||||
└── app.js
|
||||
```
|
||||
|
||||
Servez-le ensuite avec `app.frontend()` :
|
||||
|
||||
{* ../../docs_src/frontend/tutorial001_py310.py hl[5] *}
|
||||
|
||||
Avec cela, une requête vers `/assets/app.js` peut servir `dist/assets/app.js`.
|
||||
|
||||
Si vous avez également un *chemin d'accès* **FastAPI**, le *chemin d'accès* est prioritaire.
|
||||
|
||||
## Routage côté client { #client-side-routing }
|
||||
|
||||
De nombreuses applications frontend, y compris les **applications monopages** (SPAs), utilisent le routage côté client. Un chemin comme `/dashboard/settings` peut ne pas être un vrai fichier, mais le framework se chargerait de le gérer.
|
||||
|
||||
Ainsi, si vous accédez directement à cette URL (au lieu de naviguer via l'application), le backend doit servir l'application frontend depuis `index.html`, afin que le framework frontend puisse ensuite gérer le routage côté client.
|
||||
|
||||
Pour cela, utilisez `fallback="index.html"` :
|
||||
|
||||
{* ../../docs_src/frontend/tutorial002_py310.py hl[5] *}
|
||||
|
||||
**FastAPI** utilise ce fallback uniquement pour les requêtes `GET` et `HEAD` qui ressemblent à une navigation de navigateur. Les fichiers manquants comme JavaScript, CSS et les images renvoient toujours `404`.
|
||||
|
||||
Les requêtes avec d'autres méthodes, comme `POST` ou `PUT`, vers des chemins qui ne correspondent qu'au fallback frontend renvoient également `404`. Les *chemins d'accès* **FastAPI** réguliers ont toujours une priorité plus élevée que les routes frontend.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Par défaut, `fallback` a une valeur de `fallback="auto"`. Dans la plupart des cas, vous n'avez pas besoin de spécifier `fallback`. Lisez ci-dessous pour plus de détails.
|
||||
|
||||
///
|
||||
|
||||
C'est ce que vous souhaitez avec de nombreuses applications frontend qui utilisent le routage côté client, par exemple React avec TanStack Router, Vue, Angular, SvelteKit ou Solid.
|
||||
|
||||
## Page 404 personnalisée { #custom-404-page }
|
||||
|
||||
Vous pouvez également servir une page statique `404.html` pour les chemins frontend manquants :
|
||||
|
||||
{* ../../docs_src/frontend/tutorial003_py310.py hl[5] *}
|
||||
|
||||
Cette réponse conserve un code de statut `404`.
|
||||
|
||||
Dans ce cas, **FastAPI** ne servira pas `index.html` pour les chemins frontend manquants. Il renverra le fichier `404.html` à la place.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Par défaut, `fallback` a une valeur de `fallback="auto"`. Avec cela, si un fichier `404.html` est trouvé, il sera utilisé automatiquement comme fallback.
|
||||
|
||||
Vous pouvez donc normalement omettre l'argument `fallback`.
|
||||
|
||||
///
|
||||
|
||||
C'est utile avec les outils frontend qui génèrent des fichiers HTML statiques pour chaque page, comme Astro.
|
||||
|
||||
## Fallback automatique { #fallback-auto }
|
||||
|
||||
Par défaut, `app.frontend()` utilise `fallback="auto"`.
|
||||
|
||||
S'il y a un fichier `404.html` dans le répertoire frontend, les chemins frontend manquants servent ce fichier avec le code de statut `404`.
|
||||
|
||||
Sinon, s'il y a un fichier `index.html`, les chemins de navigation de navigateur manquants servent `index.html`, ce qui est attendu par de nombreuses applications frontend avec routage côté client.
|
||||
|
||||
Ainsi, dans la plupart des cas, vous pouvez utiliser `app.frontend("/", directory="dist")` sans spécifier l'argument `fallback`.
|
||||
|
||||
{* ../../docs_src/frontend/tutorial001_py310.py hl[5] *}
|
||||
|
||||
## Désactiver le fallback { #disable-fallback }
|
||||
|
||||
Si vous ne souhaitez pas servir de fichier fallback pour les chemins frontend manquants, utilisez `fallback=None` :
|
||||
|
||||
{* ../../docs_src/frontend/tutorial005_py310.py hl[5] *}
|
||||
|
||||
Les chemins frontend manquants renvoient alors le `404` normal.
|
||||
|
||||
## Vérifier le répertoire { #check-directory }
|
||||
|
||||
Par défaut, `app.frontend()` vérifie que le répertoire existe lorsque l'application est créée.
|
||||
|
||||
Cela permet de détecter tôt les erreurs de configuration. Par exemple, si le répertoire de sortie du build frontend est manquant, **FastAPI** lèvera une erreur au démarrage.
|
||||
|
||||
Si vos fichiers frontend sont créés plus tard, par exemple par une étape de build séparée après la création de l'objet app, définissez `check_dir=False` :
|
||||
|
||||
{* ../../docs_src/frontend/tutorial006_py310.py hl[5] *}
|
||||
|
||||
Avec `check_dir=False`, **FastAPI** ne vérifiera pas le répertoire lorsque l'application est créée. Si le répertoire configuré est toujours manquant lorsqu'une requête est traitée, **FastAPI** lèvera alors une erreur.
|
||||
|
||||
## L'utiliser avec `APIRouter` { #use-it-with-apirouter }
|
||||
|
||||
Vous pouvez également ajouter des fichiers frontend à un `APIRouter` et l'inclure avec un préfixe :
|
||||
|
||||
{* ../../docs_src/frontend/tutorial004_py310.py hl[6,7] *}
|
||||
|
||||
Dans cet exemple, les chemins frontend sont servis sous `/app`.
|
||||
|
||||
Tous les *chemins d'accès* réguliers dans l'application seront toujours prioritaires, y compris dans d'autres routers.
|
||||
|
||||
## Sortie de build statique uniquement { #static-build-output-only }
|
||||
|
||||
`app.frontend()` sert des fichiers déjà générés par votre build frontend.
|
||||
|
||||
Il n'exécute pas de rendu côté serveur. Il est destiné aux frameworks frontend qui génèrent des fichiers statiques, pas aux frameworks qui nécessitent un rendu dynamique sur le serveur pour chaque requête.
|
||||
@@ -43,7 +43,7 @@ Dans cet exemple, lorsque le client demande un élément par un ID qui n'existe
|
||||
|
||||
### Réponse résultante { #the-resulting-response }
|
||||
|
||||
Si le client demande `http://example.com/items/foo` (un `item_id` « foo »), il recevra un code d'état HTTP 200 et une réponse JSON :
|
||||
Si le client demande `http://example.com/items/foo` (un `item_id` `"foo"`), il recevra un code d'état HTTP 200 et une réponse JSON :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -51,7 +51,7 @@ Si le client demande `http://example.com/items/foo` (un `item_id` « foo »), il
|
||||
}
|
||||
```
|
||||
|
||||
Mais si le client demande `http://example.com/items/bar` (un `item_id` inexistant « bar »), il recevra un code d'état HTTP 404 (l'erreur « not found ») et une réponse JSON :
|
||||
Mais si le client demande `http://example.com/items/bar` (un `item_id` inexistant `"bar"`), il recevra un code d'état HTTP 404 (l'erreur « not found ») et une réponse JSON :
|
||||
|
||||
```JSON
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Tutoriel - Guide utilisateur { #tutorial-user-guide }
|
||||
|
||||
|
||||
Ce tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape.
|
||||
|
||||
Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour répondre à vos besoins spécifiques d'API.
|
||||
|
||||
@@ -11,7 +11,7 @@ Vous pouvez définir les champs suivants qui sont utilisés dans la spécificati
|
||||
| `title` | `str` | Le titre de l’API. |
|
||||
| `summary` | `str` | Un court résumé de l’API. <small>Disponible depuis OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
|
||||
| `description` | `str` | Une brève description de l’API. Elle peut utiliser Markdown. |
|
||||
| `version` | `string` | La version de l’API. C’est la version de votre propre application, pas d’OpenAPI. Par exemple `2.5.0`. |
|
||||
| `version` | `str` | La version de l’API. C’est la version de votre propre application, pas d’OpenAPI. Par exemple `2.5.0`. |
|
||||
| `terms_of_service` | `str` | Une URL vers les Conditions d’utilisation de l’API. Le cas échéant, il doit s’agir d’une URL. |
|
||||
| `contact` | `dict` | Les informations de contact pour l’API exposée. Cela peut contenir plusieurs champs. <details><summary>champs de <code>contact</code></summary><table><thead><tr><th>Paramètre</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Le nom identifiant de la personne/organisation de contact.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>L’URL pointant vers les informations de contact. DOIT être au format d’une URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>L’adresse e-mail de la personne/organisation de contact. DOIT être au format d’une adresse e-mail.</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | Les informations de licence pour l’API exposée. Cela peut contenir plusieurs champs. <details><summary>champs de <code>license_info</code></summary><table><thead><tr><th>Paramètre</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>OBLIGATOIRE</strong> (si un <code>license_info</code> est défini). Le nom de la licence utilisée pour l’API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Une expression de licence [SPDX](https://spdx.org/licenses/) pour l’API. Le champ <code>identifier</code> est mutuellement exclusif du champ <code>url</code>. <small>Disponible depuis OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>Une URL vers la licence utilisée pour l’API. DOIT être au format d’une URL.</td></tr></tbody></table></details> |
|
||||
@@ -74,7 +74,7 @@ Utilisez le paramètre `tags` avec vos *chemins d'accès* (et `APIRouter`s) pour
|
||||
|
||||
{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
En savoir plus sur les tags dans [Configuration de chemins d'accès](path-operation-configuration.md#tags).
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Configurer les chemins d'accès { #path-operation-configuration }
|
||||
|
||||
|
||||
Vous pouvez passer plusieurs paramètres à votre *décorateur de chemin d'accès* pour le configurer.
|
||||
|
||||
/// warning | Alertes
|
||||
@@ -72,13 +73,13 @@ Vous pouvez spécifier la description de la réponse avec le paramètre `respons
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Notez que `response_description` se réfère spécifiquement à la réponse, tandis que `description` se réfère au *chemin d'accès* en général.
|
||||
|
||||
///
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
OpenAPI spécifie que chaque *chemin d'accès* requiert une description de réponse.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Tout d'abord, importez `Path` de `fastapi`, et importez `Annotated` :
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
FastAPI a ajouté le support pour `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
|
||||
|
||||
@@ -131,7 +131,7 @@ Et vous pouvez également déclarer des validations numériques :
|
||||
* `lt` : `l`ess `t`han
|
||||
* `le` : `l`ess than or `e`qual
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
`Query`, `Path`, et d'autres classes que vous verrez plus tard sont des sous-classes d'une classe commune `Param`.
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en uti
|
||||
|
||||
Ici, `item_id` est déclaré comme `int`.
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
Cela vous apporte la prise en charge par l'éditeur dans votre fonction, avec vérifications d'erreurs, autocomplétion, etc.
|
||||
|
||||
@@ -34,7 +34,7 @@ Si vous exécutez cet exemple et ouvrez votre navigateur sur [http://127.0.0.1:8
|
||||
{"item_id":3}
|
||||
```
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
Remarquez que la valeur reçue par votre fonction (et renvoyée) est `3`, en tant qu'entier (`int`) Python, pas la chaîne de caractères « 3 ».
|
||||
|
||||
@@ -66,7 +66,7 @@ car le paramètre de chemin `item_id` a pour valeur « foo », qui n'est pas un
|
||||
|
||||
La même erreur apparaîtrait si vous fournissiez un `float` au lieu d'un `int`, comme ici : [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
Ainsi, avec la même déclaration de type Python, **FastAPI** vous fournit la validation de données.
|
||||
|
||||
@@ -82,7 +82,7 @@ Et lorsque vous ouvrez votre navigateur sur [http://127.0.0.1:8000/docs](http://
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
À nouveau, simplement avec cette même déclaration de type Python, **FastAPI** vous fournit une documentation interactive automatique (intégrant Swagger UI).
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ Pour ce faire, importez d’abord :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
FastAPI a ajouté la prise en charge de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
|
||||
|
||||
@@ -81,7 +81,7 @@ FastAPI va maintenant :
|
||||
|
||||
- **Valider** les données en s’assurant que la longueur maximale est de 50 caractères
|
||||
- Afficher une **erreur claire** au client quand les données ne sont pas valides
|
||||
- **Documenter** le paramètre dans la *chemin d'accès* du schéma OpenAPI (il apparaîtra donc dans l’**interface de documentation automatique**)
|
||||
- **Documenter** le paramètre dans le *chemin d'accès* du schéma OpenAPI (il apparaîtra donc dans l’**interface de documentation automatique**)
|
||||
|
||||
## Alternative (ancienne) : `Query` comme valeur par défaut { #alternative-old-query-as-the-default-value }
|
||||
|
||||
@@ -89,7 +89,7 @@ Les versions précédentes de FastAPI (avant <dfn title="avant 2023-03">0.95.0</
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pour du nouveau code et dès que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a de multiples avantages (expliqués ci-dessous) et aucun inconvénient. 🍰
|
||||
Pour du nouveau code et chaque fois que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a de multiples avantages (expliqués ci-dessous) et aucun inconvénient. 🍰
|
||||
|
||||
///
|
||||
|
||||
@@ -119,7 +119,7 @@ Ensuite, nous pouvons passer plus de paramètres à `Query`. Dans ce cas, le par
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
Cela validera les données, affichera une erreur claire lorsque les données ne sont pas valides et documentera le paramètre dans la *chemin d'accès* du schéma OpenAPI.
|
||||
Cela validera les données, affichera une erreur claire lorsque les données ne sont pas valides et documentera le paramètre dans le *chemin d'accès* du schéma OpenAPI.
|
||||
|
||||
### `Query` comme valeur par défaut ou dans `Annotated` { #query-as-the-default-value-or-in-annotated }
|
||||
|
||||
@@ -241,7 +241,7 @@ Ensuite, avec une URL comme :
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python à l’intérieur de votre fonction de *chemin d'accès*, dans le *paramètre de fonction* `q`.
|
||||
vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python à l’intérieur de votre *fonction de chemin d'accès*, dans le *paramètre de fonction* `q`.
|
||||
|
||||
Donc, la réponse pour cette URL serait :
|
||||
|
||||
@@ -381,7 +381,7 @@ Par exemple, ce validateur personnalisé vérifie que l’ID d’item commence p
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
C’est disponible avec Pydantic version 2 ou supérieure. 😎
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Paramètres de requête { #query-parameters }
|
||||
|
||||
Quand vous déclarez d'autres paramètres de fonction qui ne font pas partie des paramètres de chemin, ils sont automatiquement interprétés comme des paramètres de « query ».
|
||||
Quand vous déclarez d'autres paramètres de fonction qui ne font pas partie des paramètres de chemin, ils sont automatiquement interprétés comme des paramètres de requête.
|
||||
|
||||
{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}
|
||||
|
||||
@@ -65,7 +65,7 @@ De la même façon, vous pouvez déclarer des paramètres de requête optionnels
|
||||
|
||||
Dans ce cas, le paramètre de fonction `q` sera optionnel et vaudra `None` par défaut.
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
Notez également que **FastAPI** est suffisamment intelligent pour remarquer que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` ne l'est pas, c'est donc un paramètre de requête.
|
||||
|
||||
@@ -109,6 +109,7 @@ http://127.0.0.1:8000/items/foo?short=yes
|
||||
|
||||
ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction verra le paramètre `short` avec une valeur `bool` à `True`. Sinon la valeur sera à `False`.
|
||||
|
||||
|
||||
## Multiples paramètres de chemin et de requête { #multiple-path-and-query-parameters }
|
||||
|
||||
Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête en même temps, **FastAPI** sait lequel est lequel.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# Envoyer des fichiers { #request-files }
|
||||
|
||||
|
||||
Vous pouvez définir des fichiers à téléverser par le client en utilisant `File`.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour recevoir des fichiers téléversés, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
@@ -28,7 +29,7 @@ Créez des paramètres de fichier de la même manière que pour `Body` ou `Form`
|
||||
|
||||
{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
`File` est une classe qui hérite directement de `Form`.
|
||||
|
||||
@@ -44,7 +45,7 @@ Pour déclarer des fichiers dans le corps de la requête, vous devez utiliser `F
|
||||
|
||||
Les fichiers seront téléversés en « données de formulaire ».
|
||||
|
||||
Si vous déclarez le type de votre paramètre de *fonction de chemin d'accès* comme `bytes`, **FastAPI** lira le fichier pour vous et vous recevrez le contenu sous forme de `bytes`.
|
||||
Si vous déclarez le type de votre *fonction de chemin d'accès* comme `bytes`, **FastAPI** lira le fichier pour vous et vous recevrez le contenu sous forme de `bytes`.
|
||||
|
||||
Gardez à l'esprit que cela signifie que tout le contenu sera stocké en mémoire. Cela fonctionnera bien pour de petits fichiers.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Vous pouvez utiliser des **modèles Pydantic** pour déclarer des **champs de formulaire** dans FastAPI.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour utiliser les formulaires, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Vous pouvez définir des fichiers et des champs de formulaire en même temps à l'aide de `File` et `Form`.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour recevoir des fichiers téléversés et/ou des données de formulaire, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
Lorsque vous devez recevoir des champs de formulaire au lieu de JSON, vous pouvez utiliser `Form`.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour utiliser les formulaires, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).
|
||||
|
||||
Assurez-vous de créer un [environnement virtuel](../virtual-environments.md), de l'activer, puis installez-le, par exemple :
|
||||
Vous devez créer un [environnement virtuel](../virtual-environments.md), l'activer, puis installer le paquet, par exemple :
|
||||
|
||||
```console
|
||||
$ pip install python-multipart
|
||||
@@ -32,7 +32,7 @@ La <dfn title="spécification">spécification</dfn> exige que les champs soient
|
||||
|
||||
Avec `Form`, vous pouvez déclarer les mêmes configurations que pour `Body` (ainsi que `Query`, `Path`, `Cookie`), y compris la validation, des exemples, un alias (p. ex. `user-name` au lieu de `username`), etc.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
`Form` est une classe qui hérite directement de `Body`.
|
||||
|
||||
@@ -56,7 +56,7 @@ Les données issues des formulaires sont normalement encodées avec le « type d
|
||||
|
||||
Mais lorsque le formulaire inclut des fichiers, il est encodé en `multipart/form-data`. Vous lirez la gestion des fichiers dans le chapitre suivant.
|
||||
|
||||
Si vous voulez en savoir plus sur ces encodages et les champs de formulaire, consultez la [<abbr title="Mozilla Developer Network - Réseau des développeurs Mozilla">MDN</abbr> web docs pour `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
Si vous voulez en savoir plus sur ces encodages et les champs de formulaire, consultez les [documents web de la <abbr title="Mozilla Developer Network - Réseau des développeurs Mozilla">MDN</abbr> pour `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ Ici, nous déclarons un modèle `UserIn`, il contiendra un mot de passe en clair
|
||||
|
||||
{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
|
||||
|
||||
/// info | Info
|
||||
/// note | Remarque
|
||||
|
||||
Pour utiliser `EmailStr`, installez d'abord [`email-validator`](https://github.com/JoshData/python-email-validator).
|
||||
|
||||
@@ -251,7 +251,7 @@ Ainsi, si vous envoyez une requête à ce *chemin d'accès* pour l'article avec
|
||||
}
|
||||
```
|
||||
|
||||
/// info | Info
|
||||
/// note | Remarque
|
||||
|
||||
Vous pouvez également utiliser :
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# Code d'état de la réponse { #response-status-code }
|
||||
|
||||
|
||||
De la même manière que vous pouvez spécifier un modèle de réponse, vous pouvez également déclarer le code d'état HTTP utilisé pour la réponse avec le paramètre `status_code` dans n'importe lequel des chemins d'accès :
|
||||
|
||||
* `@app.get()`
|
||||
@@ -18,7 +19,7 @@ Remarquez que `status_code` est un paramètre de la méthode « decorator » (`g
|
||||
|
||||
Le paramètre `status_code` reçoit un nombre correspondant au code d'état HTTP.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
`status_code` peut aussi recevoir un `IntEnum`, comme le [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) de Python.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Déclarer des exemples de données de requête { #declare-request-example-data }
|
||||
|
||||
Vous pouvez déclarer des exemples des données que votre application peut recevoir.
|
||||
Vous pouvez déclarer des exemples de données que votre application peut recevoir.
|
||||
|
||||
Voici plusieurs façons de le faire.
|
||||
|
||||
@@ -10,9 +10,9 @@ Vous pouvez déclarer `examples` pour un modèle Pydantic qui seront ajoutés au
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
|
||||
|
||||
Ces informations supplémentaires seront ajoutées telles quelles au **JSON Schema** de sortie pour ce modèle, et elles seront utilisées dans la documentation de l'API.
|
||||
Ces informations supplémentaires seront ajoutées telles quelles au **JSON Schema** de sortie pour ce modèle, et elles seront utilisées dans les documents de l'API.
|
||||
|
||||
Vous pouvez utiliser l'attribut `model_config` qui accepte un `dict` comme décrit dans [Documentation de Pydantic : Configuration](https://docs.pydantic.dev/latest/api/config/).
|
||||
Vous pouvez utiliser l'attribut `model_config` qui accepte un `dict` comme décrit dans [documents de Pydantic : Configuration](https://docs.pydantic.dev/latest/api/config/).
|
||||
|
||||
Vous pouvez définir `"json_schema_extra"` avec un `dict` contenant toutes les données supplémentaires que vous souhaitez voir apparaître dans le JSON Schema généré, y compris `examples`.
|
||||
|
||||
@@ -24,11 +24,11 @@ Par exemple, vous pourriez l'utiliser pour ajouter des métadonnées pour une in
|
||||
|
||||
///
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
OpenAPI 3.1.0 (utilisé depuis FastAPI 0.99.0) a ajouté la prise en charge de `examples`, qui fait partie du standard **JSON Schema**.
|
||||
|
||||
Avant cela, seule la clé `example` avec un exemple unique était prise en charge. Elle l'est toujours par OpenAPI 3.1.0, mais elle est dépréciée et ne fait pas partie du standard JSON Schema. Vous êtes donc encouragé à migrer de `example` vers `examples`. 🤓
|
||||
Avant cela, seul le mot-clé `example` avec un exemple unique était pris en charge. Il l'est toujours par OpenAPI 3.1.0, mais il est déprécié et ne fait pas partie du standard JSON Schema. Vous êtes donc encouragé à migrer de `example` vers `examples`. 🤓
|
||||
|
||||
Vous pouvez en lire davantage à la fin de cette page.
|
||||
|
||||
@@ -155,7 +155,7 @@ OpenAPI a également ajouté les champs `example` et `examples` à d'autres part
|
||||
* `File()`
|
||||
* `Form()`
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Ce paramètre `examples` ancien et spécifique à OpenAPI est désormais `openapi_examples` depuis FastAPI `0.103.0`.
|
||||
|
||||
@@ -171,9 +171,9 @@ Et désormais, ce nouveau champ `examples` a priorité sur l'ancien champ unique
|
||||
|
||||
Ce nouveau champ `examples` dans JSON Schema est **juste une `list`** d'exemples, et non pas un dict avec des métadonnées supplémentaires comme dans les autres endroits d'OpenAPI (décrits ci-dessus).
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Même après la sortie d'OpenAPI 3.1.0 avec cette nouvelle intégration plus simple avec JSON Schema, pendant un temps, Swagger UI, l'outil qui fournit la documentation automatique, ne prenait pas en charge OpenAPI 3.1.0 (il le fait depuis la version 5.0.0 🎉).
|
||||
Même après la sortie d'OpenAPI 3.1.0 avec cette nouvelle intégration plus simple avec JSON Schema, pendant un temps, Swagger UI, l'outil qui fournit les documents automatiques, ne prenait pas en charge OpenAPI 3.1.0 (il le fait depuis la version 5.0.0 🎉).
|
||||
|
||||
À cause de cela, les versions de FastAPI antérieures à 0.99.0 utilisaient encore des versions d'OpenAPI inférieures à 3.1.0.
|
||||
|
||||
@@ -183,7 +183,7 @@ Même après la sortie d'OpenAPI 3.1.0 avec cette nouvelle intégration plus sim
|
||||
|
||||
Lorsque vous ajoutez `examples` dans un modèle Pydantic, en utilisant `schema_extra` ou `Field(examples=["something"])`, cet exemple est ajouté au **JSON Schema** de ce modèle Pydantic.
|
||||
|
||||
Et ce **JSON Schema** du modèle Pydantic est inclus dans l'**OpenAPI** de votre API, puis il est utilisé dans l'interface de la documentation.
|
||||
Et ce **JSON Schema** du modèle Pydantic est inclus dans l'**OpenAPI** de votre API, puis il est utilisé dans l'interface des documents.
|
||||
|
||||
Dans les versions de FastAPI antérieures à 0.99.0 (0.99.0 et supérieures utilisent le nouveau OpenAPI 3.1.0), lorsque vous utilisiez `example` ou `examples` avec l'une des autres utilitaires (`Query()`, `Body()`, etc.), ces exemples n'étaient pas ajoutés au JSON Schema qui décrit ces données (pas même à la version de JSON Schema propre à OpenAPI), ils étaient ajoutés directement à la déclaration du *chemin d'accès* dans OpenAPI (en dehors des parties d'OpenAPI qui utilisent JSON Schema).
|
||||
|
||||
@@ -191,7 +191,7 @@ Mais maintenant que FastAPI 0.99.0 et supérieures utilisent OpenAPI 3.1.0, qui
|
||||
|
||||
### Swagger UI et `examples` spécifiques à OpenAPI { #swagger-ui-and-openapi-specific-examples }
|
||||
|
||||
Comme Swagger UI ne prenait pas en charge plusieurs exemples JSON Schema (au 2023-08-26), les utilisateurs n'avaient pas de moyen d'afficher plusieurs exemples dans les documents.
|
||||
Maintenant, comme Swagger UI ne prenait pas en charge plusieurs exemples JSON Schema (au 2023-08-26), les utilisateurs n'avaient pas de moyen d'afficher plusieurs exemples dans les documents.
|
||||
|
||||
Pour résoudre cela, FastAPI `0.103.0` a **ajouté la prise en charge** de la déclaration du même ancien champ `examples` **spécifique à OpenAPI** avec le nouveau paramètre `openapi_examples`. 🤓
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Copiez l'exemple dans un fichier `main.py` :
|
||||
|
||||
## Exécuter { #run-it }
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Le package [`python-multipart`](https://github.com/Kludex/python-multipart) est installé automatiquement avec **FastAPI** lorsque vous exécutez la commande `pip install "fastapi[standard]"`.
|
||||
|
||||
@@ -54,13 +54,13 @@ $ fastapi dev
|
||||
|
||||
## Vérifier { #check-it }
|
||||
|
||||
Allez à la documentation interactive à l'adresse : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
Allez aux documents interactifs à l'adresse : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
Vous verrez quelque chose comme ceci :
|
||||
|
||||
<img src="/img/tutorial/security/image01.png">
|
||||
|
||||
/// check | Bouton « Authorize » !
|
||||
/// tip | Bouton « Authorize » !
|
||||
|
||||
Vous avez déjà un tout nouveau bouton « Authorize ».
|
||||
|
||||
@@ -98,19 +98,19 @@ Mais dans ce cas, la même application **FastAPI** gérera l'API et l'authentifi
|
||||
|
||||
Voyons cela selon ce point de vue simplifié :
|
||||
|
||||
- L'utilisateur saisit le `username` et le `password` dans le frontend, puis appuie sur Entrée.
|
||||
- Le frontend (exécuté dans le navigateur de l'utilisateur) envoie ce `username` et ce `password` vers une URL spécifique de notre API (déclarée avec `tokenUrl="token"`).
|
||||
- L'API vérifie ce `username` et ce `password`, et répond avec un « token » (nous n'avons encore rien implémenté de tout cela).
|
||||
- Un « token » n'est qu'une chaîne contenant des informations que nous pouvons utiliser plus tard pour vérifier cet utilisateur.
|
||||
- Normalement, un token est configuré pour expirer après un certain temps.
|
||||
- Ainsi, l'utilisateur devra se reconnecter à un moment donné.
|
||||
- Et si le token est volé, le risque est moindre. Ce n'est pas une clé permanente qui fonctionnerait indéfiniment (dans la plupart des cas).
|
||||
- Le frontend stocke ce token temporairement quelque part.
|
||||
- L'utilisateur clique dans le frontend pour aller vers une autre section de l'application web frontend.
|
||||
- Le frontend doit récupérer d'autres données depuis l'API.
|
||||
- Mais cela nécessite une authentification pour cet endpoint spécifique.
|
||||
- Donc, pour s'authentifier auprès de notre API, il envoie un en-tête `Authorization` avec une valeur `Bearer ` suivie du token.
|
||||
- Si le token contient `foobar`, le contenu de l'en-tête `Authorization` serait : `Bearer foobar`.
|
||||
* L'utilisateur saisit le `username` et le `password` dans le frontend, puis appuie sur Entrée.
|
||||
* Le frontend (exécuté dans le navigateur de l'utilisateur) envoie ce `username` et ce `password` vers une URL spécifique de notre API (déclarée avec `tokenUrl="token"`).
|
||||
* L'API vérifie ce `username` et ce `password`, et répond avec un « token » (nous n'avons encore rien implémenté de tout cela).
|
||||
* Un « token » n'est qu'une chaîne contenant des informations que nous pouvons utiliser plus tard pour vérifier cet utilisateur.
|
||||
* Normalement, un token est configuré pour expirer après un certain temps.
|
||||
* Ainsi, l'utilisateur devra se reconnecter à un moment donné.
|
||||
* Et si le token est volé, le risque est moindre. Ce n'est pas une clé permanente qui fonctionnerait indéfiniment (dans la plupart des cas).
|
||||
* Le frontend stocke ce token temporairement quelque part.
|
||||
* L'utilisateur clique dans le frontend pour aller vers une autre section de l'application web frontend.
|
||||
* Le frontend doit récupérer d'autres données depuis l'API.
|
||||
* Mais cela nécessite une authentification pour cet endpoint spécifique.
|
||||
* Donc, pour s'authentifier auprès de notre API, il envoie un en-tête `Authorization` avec une valeur `Bearer ` suivie du token.
|
||||
* Si le token contient `foobar`, le contenu de l'en-tête `Authorization` serait : `Bearer foobar`.
|
||||
|
||||
## Le `OAuth2PasswordBearer` de **FastAPI** { #fastapis-oauth2passwordbearer }
|
||||
|
||||
@@ -118,7 +118,7 @@ Voyons cela selon ce point de vue simplifié :
|
||||
|
||||
Dans cet exemple, nous allons utiliser **OAuth2**, avec le flux **Password**, en utilisant un token **Bearer**. Nous le faisons avec la classe `OAuth2PasswordBearer`.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Un token « bearer » n'est pas la seule option.
|
||||
|
||||
@@ -148,7 +148,7 @@ Ce paramètre ne crée pas cet endpoint / *chemin d'accès*, mais déclare que l
|
||||
|
||||
Nous créerons bientôt aussi le véritable chemin d'accès.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Si vous êtes un « Pythonista » très strict, vous pourriez ne pas apprécier le style du nom de paramètre `tokenUrl` au lieu de `token_url`.
|
||||
|
||||
@@ -172,15 +172,15 @@ Vous pouvez maintenant passer ce `oauth2_scheme` en dépendance avec `Depends`.
|
||||
|
||||
{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}
|
||||
|
||||
Cette dépendance fournira une `str` qui est affectée au paramètre `token` de la fonction de *chemin d'accès*.
|
||||
Cette dépendance fournira une `str` qui est affectée au paramètre `token` de la *fonction de chemin d'accès*.
|
||||
|
||||
**FastAPI** saura qu'il peut utiliser cette dépendance pour définir un « schéma de sécurité » dans le schéma OpenAPI (et la documentation API automatique).
|
||||
**FastAPI** saura qu'il peut utiliser cette dépendance pour définir un « schéma de sécurité » dans le schéma OpenAPI (et les documents automatiques de l'API).
|
||||
|
||||
/// info | Détails techniques
|
||||
/// note | Détails techniques
|
||||
|
||||
**FastAPI** saura qu'il peut utiliser la classe `OAuth2PasswordBearer` (déclarée dans une dépendance) pour définir le schéma de sécurité dans OpenAPI parce qu'elle hérite de `fastapi.security.oauth2.OAuth2`, qui hérite à son tour de `fastapi.security.base.SecurityBase`.
|
||||
|
||||
Tous les utilitaires de sécurité qui s'intègrent à OpenAPI (et à la documentation API automatique) héritent de `SecurityBase`, c'est ainsi que **FastAPI** sait comment les intégrer dans OpenAPI.
|
||||
Tous les utilitaires de sécurité qui s'intègrent à OpenAPI (et aux documents automatiques de l'API) héritent de `SecurityBase`, c'est ainsi que **FastAPI** sait comment les intégrer dans OpenAPI.
|
||||
|
||||
///
|
||||
|
||||
@@ -192,7 +192,7 @@ S'il ne voit pas d'en-tête `Authorization`, ou si la valeur n'a pas de token `B
|
||||
|
||||
Vous n'avez même pas à vérifier si le token existe pour renvoyer une erreur. Vous pouvez être sûr que si votre fonction est exécutée, elle aura une `str` dans ce token.
|
||||
|
||||
Vous pouvez déjà l'essayer dans la documentation interactive :
|
||||
Vous pouvez déjà l'essayer dans les documents interactifs :
|
||||
|
||||
<img src="/img/tutorial/security/image03.png">
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ Commençons par créer un modèle d'utilisateur Pydantic.
|
||||
|
||||
De la même manière que nous utilisons Pydantic pour déclarer des corps de requête, nous pouvons l'utiliser ailleurs :
|
||||
|
||||
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
|
||||
{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:16] *}
|
||||
|
||||
## Créer une dépendance `get_current_user` { #create-a-get-current-user-dependency }
|
||||
|
||||
@@ -52,7 +52,7 @@ Ici, **FastAPI** ne s'y trompera pas car vous utilisez `Depends`.
|
||||
|
||||
///
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
La manière dont ce système de dépendances est conçu nous permet d'avoir différentes dépendances (différents « dependables ») qui retournent toutes un modèle `User`.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ $ pip install pyjwt
|
||||
|
||||
</div>
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Si vous prévoyez d'utiliser des algorithmes de signature numérique comme RSA ou ECDSA, vous devez installer la dépendance de bibliothèque de cryptographie `pyjwt[crypto]`.
|
||||
|
||||
@@ -58,7 +58,7 @@ Chaque fois que vous fournissez exactement le même contenu (exactement le même
|
||||
|
||||
Mais vous ne pouvez pas convertir le charabia en sens inverse vers le mot de passe.
|
||||
|
||||
### Pourquoi utiliser le hachage de mot passe { #why-use-password-hashing }
|
||||
### Pourquoi utiliser le hachage de mot de passe { #why-use-password-hashing }
|
||||
|
||||
Si votre base de données est volée, le voleur n'aura pas les mots de passe en clair de vos utilisateurs, seulement les hachages.
|
||||
|
||||
@@ -120,7 +120,7 @@ Et une autre pour authentifier et renvoyer un utilisateur.
|
||||
|
||||
Lorsque `authenticate_user` est appelée avec un nom d'utilisateur qui n'existe pas dans la base de données, nous exécutons tout de même `verify_password` contre un hachage factice.
|
||||
|
||||
Cela garantit que le point de terminaison met approximativement le même temps à répondre que le nom d'utilisateur soit valide ou non, empêchant des **attaques temporelles** qui pourraient être utilisées pour énumérer les noms d'utilisateur existants.
|
||||
Cela garantit que l'endpoint met approximativement le même temps à répondre que le nom d'utilisateur soit valide ou non, empêchant des **attaques temporelles** qui pourraient être utilisées pour énumérer les noms d'utilisateur existants.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
@@ -152,7 +152,7 @@ Créez une variable `ALGORITHM` avec l'algorithme utilisé pour signer le jeton
|
||||
|
||||
Créez une variable pour l'expiration du jeton.
|
||||
|
||||
Définissez un modèle Pydantic qui sera utilisé dans le point de terminaison du jeton pour la réponse.
|
||||
Définissez un modèle Pydantic qui sera utilisé dans l'endpoint du jeton pour la réponse.
|
||||
|
||||
Créez une fonction utilitaire pour générer un nouveau jeton d'accès.
|
||||
|
||||
@@ -200,7 +200,7 @@ L'important à garder à l'esprit est que la clé `sub` doit contenir un identif
|
||||
|
||||
## Vérifier { #check-it }
|
||||
|
||||
Lancez le serveur et allez à la documentation : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
Lancez le serveur et accédez aux documents : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
Vous verrez l'interface utilisateur suivante :
|
||||
|
||||
@@ -213,15 +213,15 @@ En utilisant les identifiants :
|
||||
Nom d'utilisateur : `johndoe`
|
||||
Mot de passe : `secret`
|
||||
|
||||
/// check | Vérifications
|
||||
/// tip | Astuce
|
||||
|
||||
Remarquez qu'à aucun endroit du code le mot de passe en clair « secret » n'apparaît, nous n'avons que la version hachée.
|
||||
Remarquez qu'à aucun endroit du code le mot de passe en clair « `secret` » n'apparaît, nous n'avons que la version hachée.
|
||||
|
||||
///
|
||||
|
||||
<img src="/img/tutorial/security/image08.png">
|
||||
|
||||
Appelez le point de terminaison `/users/me/`, vous obtiendrez la réponse suivante :
|
||||
Appelez l'endpoint `/users/me/`, vous obtiendrez la réponse suivante :
|
||||
|
||||
```JSON
|
||||
{
|
||||
|
||||
@@ -14,13 +14,13 @@ Mais ne vous inquiétez pas, vous pouvez l'afficher comme vous le souhaitez à v
|
||||
|
||||
Et vos modèles de base de données peuvent utiliser les noms que vous voulez.
|
||||
|
||||
Mais pour le chemin d'accès de connexion, nous devons utiliser ces noms pour être compatibles avec la spécification (et pouvoir, par exemple, utiliser le système de documentation API intégré).
|
||||
Mais pour le *chemin d'accès* de connexion, nous devons utiliser ces noms pour être compatibles avec la spécification (et pouvoir, par exemple, utiliser le système de documentation API intégré).
|
||||
|
||||
La spécification précise également que `username` et `password` doivent être envoyés en données de formulaire (donc pas de JSON ici).
|
||||
|
||||
### `scope` { #scope }
|
||||
|
||||
La spécification indique aussi que le client peut envoyer un autre champ de formulaire « scope ».
|
||||
La spécification indique aussi que le client peut envoyer un autre champ de formulaire « `scope` ».
|
||||
|
||||
Le nom du champ de formulaire est `scope` (au singulier), mais il s'agit en fait d'une longue chaîne contenant des « scopes » séparés par des espaces.
|
||||
|
||||
@@ -32,7 +32,7 @@ Ils sont normalement utilisés pour déclarer des permissions de sécurité spé
|
||||
* `instagram_basic` est utilisé par Facebook / Instagram.
|
||||
* `https://www.googleapis.com/auth/drive` est utilisé par Google.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
En OAuth2, un « scope » est simplement une chaîne qui déclare une permission spécifique requise.
|
||||
|
||||
@@ -50,7 +50,7 @@ Utilisons maintenant les utilités fournies par **FastAPI** pour gérer cela.
|
||||
|
||||
### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }
|
||||
|
||||
Tout d'abord, importez `OAuth2PasswordRequestForm`, et utilisez-la en tant que dépendance avec `Depends` dans le chemin d'accès pour `/token` :
|
||||
Tout d'abord, importez `OAuth2PasswordRequestForm`, et utilisez-la en tant que dépendance avec `Depends` dans le *chemin d'accès* pour `/token` :
|
||||
|
||||
{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
|
||||
|
||||
@@ -63,7 +63,7 @@ Tout d'abord, importez `OAuth2PasswordRequestForm`, et utilisez-la en tant que d
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
La spécification OAuth2 exige en réalité un champ `grant_type` avec la valeur fixe `password`, mais `OAuth2PasswordRequestForm` ne l'impose pas.
|
||||
La spécification OAuth2 *exige* en réalité un champ `grant_type` avec la valeur fixe `password`, mais `OAuth2PasswordRequestForm` ne l'impose pas.
|
||||
|
||||
Si vous avez besoin de l'imposer, utilisez `OAuth2PasswordRequestFormStrict` au lieu de `OAuth2PasswordRequestForm`.
|
||||
|
||||
@@ -72,7 +72,7 @@ Si vous avez besoin de l'imposer, utilisez `OAuth2PasswordRequestFormStrict` au
|
||||
* Un `client_id` optionnel (nous n'en avons pas besoin pour notre exemple).
|
||||
* Un `client_secret` optionnel (nous n'en avons pas besoin pour notre exemple).
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
La classe `OAuth2PasswordRequestForm` n'est pas une classe spéciale pour **FastAPI** comme l'est `OAuth2PasswordBearer`.
|
||||
|
||||
@@ -132,7 +132,7 @@ Ainsi, il ne pourra pas essayer d'utiliser ces mêmes mots de passe dans un autr
|
||||
|
||||
`UserInDB(**user_dict)` signifie :
|
||||
|
||||
Passez les clés et valeurs de `user_dict` directement comme arguments clé‑valeur, équivalent à :
|
||||
*Passez les clés et valeurs de `user_dict` directement comme arguments clé‑valeur, équivalent à :*
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -144,9 +144,9 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour une explication plus complète de `**user_dict`, consultez [la documentation pour **Modèles supplémentaires**](../extra-models.md#about-user-in-dict).
|
||||
Pour une explication plus complète de `**user_dict`, consultez [la documentation pour **Modèles supplémentaires**](../extra-models.md#about-user-in-model-dump).
|
||||
|
||||
///
|
||||
|
||||
@@ -154,7 +154,7 @@ Pour une explication plus complète de `**user_dict`, consultez [la documentatio
|
||||
|
||||
La réponse de l'endpoint `token` doit être un objet JSON.
|
||||
|
||||
Il doit contenir un `token_type`. Dans notre cas, comme nous utilisons des jetons « Bearer », le type de jeton doit être « bearer ».
|
||||
Il doit contenir un `token_type`. Dans notre cas, comme nous utilisons des jetons « Bearer », le type de jeton doit être « `bearer` ».
|
||||
|
||||
Et il doit contenir un `access_token`, avec une chaîne contenant notre jeton d'accès.
|
||||
|
||||
@@ -186,7 +186,7 @@ Pour le reste, **FastAPI** s'en charge pour vous.
|
||||
|
||||
Nous allons maintenant mettre à jour nos dépendances.
|
||||
|
||||
Nous voulons obtenir `current_user` uniquement si cet utilisateur est actif.
|
||||
Nous voulons obtenir `current_user` *uniquement* si cet utilisateur est actif.
|
||||
|
||||
Nous créons donc une dépendance supplémentaire `get_current_active_user` qui utilise à son tour `get_current_user` comme dépendance.
|
||||
|
||||
@@ -196,7 +196,7 @@ Ainsi, dans notre endpoint, nous n'obtiendrons un utilisateur que si l'utilisate
|
||||
|
||||
{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
L'en‑tête supplémentaire `WWW-Authenticate` avec la valeur `Bearer` que nous renvoyons ici fait également partie de la spécification.
|
||||
|
||||
@@ -216,7 +216,7 @@ C'est l'avantage des standards ...
|
||||
|
||||
## Voir en action { #see-it-in-action }
|
||||
|
||||
Ouvrez la documentation interactive : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
Ouvrez les documents interactifs : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
|
||||
|
||||
### S'authentifier { #authenticate }
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Vous pouvez diffuser des données vers le client en utilisant les **Server-Sent
|
||||
|
||||
C'est similaire à [Diffuser des JSON Lines](stream-json-lines.md), mais cela utilise le format `text/event-stream`, pris en charge nativement par les navigateurs via l’API [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
|
||||
|
||||
/// info | Info
|
||||
/// note | Remarque
|
||||
|
||||
Ajouté dans FastAPI 0.135.0.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Il existe un générateur de projet officiel avec **FastAPI** et **PostgreSQL**,
|
||||
|
||||
///
|
||||
|
||||
Il s'agit d'un tutoriel très simple et court ; si vous souhaitez apprendre sur les bases de données en général, sur SQL, ou des fonctionnalités plus avancées, allez voir la [documentation SQLModel](https://sqlmodel.tiangolo.com/).
|
||||
Il s'agit d'un tutoriel très simple et court ; si vous souhaitez apprendre sur les bases de données en général, sur SQL, ou des fonctionnalités plus avancées, allez voir les [documents de SQLModel](https://sqlmodel.tiangolo.com/).
|
||||
|
||||
## Installer `SQLModel` { #install-sqlmodel }
|
||||
|
||||
@@ -57,15 +57,15 @@ Importez `SQLModel` et créez un modèle de base de données :
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
|
||||
|
||||
La classe `Hero` est très similaire à un modèle Pydantic (en fait, en dessous, c'est réellement un modèle Pydantic).
|
||||
La classe `Hero` est très similaire à un modèle Pydantic (en fait, en dessous, c'est réellement *un modèle Pydantic*).
|
||||
|
||||
Il y a quelques différences :
|
||||
|
||||
* `table=True` indique à SQLModel qu'il s'agit d'un *modèle de table*, il doit représenter une **table** dans la base SQL, ce n'est pas seulement un *modèle de données* (comme le serait n'importe quelle autre classe Pydantic classique).
|
||||
|
||||
* `Field(primary_key=True)` indique à SQLModel que `id` est la **clé primaire** dans la base SQL (vous pouvez en savoir plus sur les clés primaires SQL dans la documentation SQLModel).
|
||||
* `Field(primary_key=True)` indique à SQLModel que `id` est la **clé primaire** dans la base SQL (vous pouvez en savoir plus sur les clés primaires SQL dans les documents de SQLModel).
|
||||
|
||||
Remarque : nous utilisons `int | None` pour le champ clé primaire afin qu'en Python nous puissions *créer un objet sans `id`* (`id=None`), en supposant que la base *le génère à l'enregistrement*. SQLModel comprend que la base fournira l'`id` et *définit la colonne comme un `INTEGER` non nul* dans le schéma de base. Voir la [documentation SQLModel sur les clés primaires](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) pour plus de détails.
|
||||
**Remarque :** nous utilisons `int | None` pour le champ clé primaire afin qu'en Python nous puissions *créer un objet sans `id`* (`id=None`), en supposant que la base *le génère à l'enregistrement*. SQLModel comprend que la base fournira l'`id` et *définit la colonne comme un `INTEGER` non nul* dans le schéma de base. Voir les [documents de SQLModel sur les clés primaires](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) pour plus de détails.
|
||||
|
||||
* `Field(index=True)` indique à SQLModel qu'il doit créer un **index SQL** pour cette colonne, ce qui permettra des recherches plus rapides dans la base lors de la lecture de données filtrées par cette colonne.
|
||||
|
||||
@@ -121,7 +121,7 @@ Comme chaque modèle SQLModel est aussi un modèle Pydantic, vous pouvez l'utili
|
||||
|
||||
Par exemple, si vous déclarez un paramètre de type `Hero`, il sera lu depuis le **corps JSON**.
|
||||
|
||||
De la même manière, vous pouvez le déclarer comme **type de retour** de la fonction, et alors la forme des données apparaîtra dans l'UI automatique de documentation de l'API.
|
||||
De la même manière, vous pouvez le déclarer comme **type de retour** de la fonction, et alors la forme des données apparaîtra dans l'UI automatique des documents de l'API.
|
||||
|
||||
{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
|
||||
|
||||
@@ -173,7 +173,7 @@ Si vous vérifiez l'application précédente, dans l'UI vous pouvez voir que, ju
|
||||
|
||||
Nous ne devrions pas laisser cela se produire, ils pourraient écraser un `id` que nous avons déjà attribué dans la base. Décider de l'`id` doit être fait par le **backend** ou la **base**, **pas par le client**.
|
||||
|
||||
De plus, nous créons un `secret_name` pour le héros, mais jusqu'ici, nous le renvoyons partout, ce n'est pas très « secret » ... 😅
|
||||
De plus, nous créons un `secret_name` pour le héros, mais jusqu'ici, nous le renvoyons partout, ce n'est pas très **secret** ... 😅
|
||||
|
||||
Nous allons corriger ces choses en ajoutant quelques **modèles supplémentaires**. C'est là que SQLModel brille. ✨
|
||||
|
||||
@@ -354,4 +354,4 @@ Si vous allez sur l'UI `/docs` de l'API, vous verrez qu'elle est maintenant à j
|
||||
|
||||
Vous pouvez utiliser [**SQLModel**](https://sqlmodel.tiangolo.com/) pour interagir avec une base SQL et simplifier le code avec des *modèles de données* et des *modèles de table*.
|
||||
|
||||
Vous pouvez en apprendre beaucoup plus dans la documentation **SQLModel**, il y a un mini [tutoriel plus long sur l'utilisation de SQLModel avec **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀
|
||||
Vous pouvez en apprendre beaucoup plus dans les documents de **SQLModel**, il y a un mini [tutoriel plus long sur l'utilisation de SQLModel avec **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
Vous pouvez servir des fichiers statiques automatiquement à partir d'un répertoire en utilisant `StaticFiles`.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous devez héberger un frontend, utilisez plutôt `app.frontend()`, lisez-en davantage dans [Frontend](frontend.md).
|
||||
|
||||
`app.frontend()` utilise `StaticFiles` en interne, avec plusieurs avantages supplémentaires pour les frontends, comme la gestion du routing côté client.
|
||||
|
||||
///
|
||||
|
||||
## Utiliser `StaticFiles` { #use-staticfiles }
|
||||
|
||||
- Importer `StaticFiles`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Diffuser des JSON Lines { #stream-json-lines }
|
||||
|
||||
Vous pouvez avoir une séquence de données que vous souhaitez envoyer en « flux » ; vous pouvez le faire avec « JSON Lines ».
|
||||
Vous pouvez avoir une séquence de données que vous souhaitez envoyer en « flux », vous pouvez le faire avec « JSON Lines ».
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Ajouté dans FastAPI 0.134.0.
|
||||
|
||||
@@ -48,7 +48,7 @@ Une réponse aurait un type de contenu `application/jsonl` (au lieu de `applicat
|
||||
|
||||
C'est très similaire à un tableau JSON (équivalent d'une liste Python), mais au lieu d'être entouré de `[]` et d'avoir des `,` entre les éléments, il y a un objet JSON par ligne, ils sont séparés par un caractère de saut de ligne.
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Le point important est que votre application pourra produire chaque ligne à son tour, tandis que le client consomme les lignes précédentes.
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ Avec cela, vous pouvez utiliser [pytest](https://docs.pytest.org/) directement a
|
||||
|
||||
## Utiliser `TestClient` { #using-testclient }
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Pour utiliser `TestClient`, installez d’abord [`httpx`](https://www.python-httpx.org).
|
||||
|
||||
Vous devez créer un [environnement virtuel](../virtual-environments.md), l’activer, puis y installer le paquet, par exemple :
|
||||
Vous devez vous assurer de créer un [environnement virtuel](../virtual-environments.md), de l’activer, puis d’y installer le paquet, par exemple :
|
||||
|
||||
```console
|
||||
$ pip install httpx
|
||||
@@ -144,7 +144,7 @@ Par exemple :
|
||||
|
||||
Pour plus d’informations sur la manière de transmettre des données au backend (en utilisant `httpx` ou le `TestClient`), consultez la [documentation HTTPX](https://www.python-httpx.org).
|
||||
|
||||
/// info
|
||||
/// note | Remarque
|
||||
|
||||
Notez que le `TestClient` reçoit des données qui peuvent être converties en JSON, pas des modèles Pydantic.
|
||||
|
||||
@@ -156,7 +156,7 @@ Si vous avez un modèle Pydantic dans votre test et que vous souhaitez envoyer s
|
||||
|
||||
Après cela, vous avez simplement besoin d’installer `pytest`.
|
||||
|
||||
Vous devez créer un [environnement virtuel](../virtual-environments.md), l’activer, puis y installer le paquet, par exemple :
|
||||
Vous devez vous assurer de créer un [environnement virtuel](../virtual-environments.md), de l’activer, puis d’y installer le paquet, par exemple :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Environnements virtuels { #virtual-environments }
|
||||
|
||||
Lorsque vous travaillez sur des projets Python, vous devriez probablement utiliser un environnement virtuel (ou un mécanisme similaire) pour isoler les packages que vous installez pour chaque projet.
|
||||
Lorsque vous travaillez sur des projets Python, vous devriez probablement utiliser un **environnement virtuel** (ou un mécanisme similaire) pour isoler les packages que vous installez pour chaque projet.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
@@ -10,19 +10,19 @@ Si vous connaissez déjà les environnements virtuels, comment les créer et les
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Un environnement virtuel est différent d’une variable d’environnement.
|
||||
Un **environnement virtuel** est différent d’une **variable d’environnement**.
|
||||
|
||||
Une variable d’environnement est une variable du système qui peut être utilisée par des programmes.
|
||||
Une **variable d’environnement** est une variable du système qui peut être utilisée par des programmes.
|
||||
|
||||
Un environnement virtuel est un répertoire contenant certains fichiers.
|
||||
Un **environnement virtuel** est un répertoire contenant certains fichiers.
|
||||
|
||||
///
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Cette page vous apprendra à utiliser les environnements virtuels et à comprendre leur fonctionnement.
|
||||
Cette page vous apprendra à utiliser les **environnements virtuels** et à comprendre leur fonctionnement.
|
||||
|
||||
Si vous êtes prêt à adopter un outil qui gère tout pour vous (y compris l’installation de Python), essayez [uv](https://github.com/astral-sh/uv).
|
||||
Si vous êtes prêt à adopter un **outil qui gère tout** pour vous (y compris l’installation de Python), essayez [uv](https://github.com/astral-sh/uv).
|
||||
|
||||
///
|
||||
|
||||
@@ -53,11 +53,11 @@ $ cd awesome-project
|
||||
|
||||
## Créer un environnement virtuel { #create-a-virtual-environment }
|
||||
|
||||
Lorsque vous commencez à travailler sur un projet Python pour la première fois, créez un environnement virtuel <strong><dfn title="il existe d'autres options, il s'agit d'une simple recommandation">dans votre projet</dfn></strong>.
|
||||
Lorsque vous commencez à travailler sur un projet Python **pour la première fois**, créez un environnement virtuel **<dfn title="il existe d'autres options, il s'agit d'une simple recommandation">dans votre projet</dfn>**.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous n’avez besoin de faire cela qu’une seule fois par projet, pas à chaque fois que vous travaillez.
|
||||
Vous n’avez besoin de faire cela qu’**une seule fois par projet**, pas à chaque fois que vous travaillez.
|
||||
|
||||
///
|
||||
|
||||
@@ -120,7 +120,7 @@ Activez le nouvel environnement virtuel afin que toute commande Python que vous
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Faites cela à chaque fois que vous démarrez une nouvelle session de terminal pour travailler sur le projet.
|
||||
Faites cela **chaque fois** que vous démarrez une **nouvelle session de terminal** pour travailler sur le projet.
|
||||
|
||||
///
|
||||
|
||||
@@ -164,9 +164,9 @@ $ source .venv/Scripts/activate
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Chaque fois que vous installez un nouveau package dans cet environnement, activez de nouveau l’environnement.
|
||||
Chaque fois que vous installez un **nouveau package** dans cet environnement, **activez** de nouveau l’environnement.
|
||||
|
||||
Vous vous assurez ainsi que si vous utilisez un programme de terminal (<abbr title="command line interface - interface en ligne de commande">CLI</abbr>) installé par ce package, vous utilisez celui de votre environnement virtuel et non un autre qui pourrait être installé globalement, probablement avec une version différente de celle dont vous avez besoin.
|
||||
Vous vous assurez ainsi que si vous utilisez un **programme de terminal (<abbr title="command line interface - interface en ligne de commande">CLI</abbr>)** installé par ce package, vous utilisez celui de votre environnement virtuel et non un autre qui pourrait être installé globalement, probablement avec une version différente de celle dont vous avez besoin.
|
||||
|
||||
///
|
||||
|
||||
@@ -176,7 +176,7 @@ Vérifiez que l’environnement virtuel est actif (la commande précédente a fo
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
C’est facultatif, mais c’est une bonne manière de vérifier que tout fonctionne comme prévu et que vous utilisez l’environnement virtuel voulu.
|
||||
C’est **facultatif**, mais c’est une bonne manière de **vérifier** que tout fonctionne comme prévu et que vous utilisez l’environnement virtuel voulu.
|
||||
|
||||
///
|
||||
|
||||
@@ -220,13 +220,13 @@ Si vous utilisez [`uv`](https://github.com/astral-sh/uv), vous l’utiliserez po
|
||||
|
||||
///
|
||||
|
||||
Si vous utilisez `pip` pour installer des packages (il est fourni par défaut avec Python), vous devez le mettre à niveau vers la dernière version.
|
||||
Si vous utilisez `pip` pour installer des packages (il est fourni par défaut avec Python), vous devez le **mettre à niveau** vers la dernière version.
|
||||
|
||||
Beaucoup d’erreurs exotiques lors de l’installation d’un package se résolvent simplement en mettant d’abord `pip` à niveau.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous feriez normalement cela une seule fois, juste après avoir créé l’environnement virtuel.
|
||||
Vous feriez normalement cela **une seule fois**, juste après avoir créé l’environnement virtuel.
|
||||
|
||||
///
|
||||
|
||||
@@ -264,7 +264,7 @@ Cette commande installera pip s’il n’est pas déjà installé et garantit au
|
||||
|
||||
## Ajouter `.gitignore` { #add-gitignore }
|
||||
|
||||
Si vous utilisez Git (vous devriez), ajoutez un fichier `.gitignore` pour exclure tout ce qui se trouve dans votre `.venv` de Git.
|
||||
Si vous utilisez **Git** (vous devriez), ajoutez un fichier `.gitignore` pour exclure tout ce qui se trouve dans votre `.venv` de Git.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
@@ -274,7 +274,7 @@ Si vous avez utilisé [`uv`](https://github.com/astral-sh/uv) pour créer l’en
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Faites cela une seule fois, juste après avoir créé l’environnement virtuel.
|
||||
Faites cela **une seule fois**, juste après avoir créé l’environnement virtuel.
|
||||
|
||||
///
|
||||
|
||||
@@ -308,19 +308,19 @@ Après avoir activé l’environnement, vous pouvez y installer des packages.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Faites cela une seule fois lorsque vous installez ou mettez à niveau les packages nécessaires à votre projet.
|
||||
Faites cela **une seule fois** lorsque vous installez ou mettez à niveau les packages nécessaires à votre projet.
|
||||
|
||||
Si vous devez mettre à niveau une version ou ajouter un nouveau package, vous le referez.
|
||||
Si vous devez mettre à niveau une version ou ajouter un nouveau package, vous le **referez**.
|
||||
|
||||
///
|
||||
|
||||
### Installer des packages directement { #install-packages-directly }
|
||||
|
||||
Si vous êtes pressé et ne souhaitez pas utiliser un fichier pour déclarer les dépendances de votre projet, vous pouvez les installer directement.
|
||||
Si vous êtes pressé et ne souhaitez pas utiliser un fichier pour déclarer les dépendances de packages de votre projet, vous pouvez les installer directement.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
C’est une très bonne idée de placer les packages et leurs versions nécessaires à votre programme dans un fichier (par exemple `requirements.txt` ou `pyproject.toml`).
|
||||
C’est une (très) bonne idée de placer les packages et leurs versions nécessaires à votre programme dans un fichier (par exemple `requirements.txt` ou `pyproject.toml`).
|
||||
|
||||
///
|
||||
|
||||
@@ -421,13 +421,13 @@ Par exemple :
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous devez normalement faire cela une seule fois, lorsque vous créez l’environnement virtuel.
|
||||
Vous devez normalement faire cela seulement **une fois**, lorsque vous créez l’environnement virtuel.
|
||||
|
||||
///
|
||||
|
||||
## Désactiver l’environnement virtuel { #deactivate-the-virtual-environment }
|
||||
|
||||
Une fois que vous avez fini de travailler sur votre projet, vous pouvez désactiver l’environnement virtuel.
|
||||
Une fois que vous avez fini de travailler sur votre projet, vous pouvez **désactiver** l’environnement virtuel.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -457,17 +457,17 @@ Continuez la lecture. 👇🤓
|
||||
|
||||
Pour travailler avec FastAPI, vous devez installer [Python](https://www.python.org/).
|
||||
|
||||
Ensuite, vous devrez installer FastAPI et tout autre package que vous souhaitez utiliser.
|
||||
Ensuite, vous devez **installer** FastAPI et tout autre **package** que vous souhaitez utiliser.
|
||||
|
||||
Pour installer des packages, vous utiliseriez normalement la commande `pip` fournie avec Python (ou des alternatives similaires).
|
||||
|
||||
Néanmoins, si vous utilisez simplement `pip` directement, les packages seraient installés dans votre environnement Python global (l’installation globale de Python).
|
||||
Néanmoins, si vous utilisez simplement `pip` directement, les packages seraient installés dans votre **environnement Python global** (l’installation globale de Python).
|
||||
|
||||
### Le problème { #the-problem }
|
||||
|
||||
Alors, quel est le problème d’installer des packages dans l’environnement Python global ?
|
||||
|
||||
À un moment donné, vous finirez probablement par écrire de nombreux programmes différents qui dépendent de packages différents. Et certains de ces projets sur lesquels vous travaillez dépendront de versions différentes du même package. 😱
|
||||
À un moment donné, vous finirez probablement par écrire de nombreux programmes différents qui dépendent de **packages différents**. Et certains de ces projets sur lesquels vous travaillez dépendront de **versions différentes** du même package. 😱
|
||||
|
||||
Par exemple, vous pourriez créer un projet appelé `philosophers-stone`, ce programme dépend d’un autre package appelé **`harry`, en version `1`**. Vous devez donc installer `harry`.
|
||||
|
||||
@@ -483,7 +483,7 @@ flowchart LR
|
||||
azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
|
||||
```
|
||||
|
||||
Mais maintenant, le problème est que, si vous installez les packages globalement (dans l’environnement global) au lieu de dans un environnement virtuel local, vous devrez choisir quelle version de `harry` installer.
|
||||
Mais maintenant, le problème est que, si vous installez les packages globalement (dans l’environnement global) au lieu de dans un **environnement virtuel** local, vous devrez choisir quelle version de `harry` installer.
|
||||
|
||||
Si vous voulez exécuter `philosophers-stone`, vous devrez d’abord installer `harry` en version `1`, par exemple avec :
|
||||
|
||||
@@ -519,7 +519,7 @@ $ pip install "harry==3"
|
||||
|
||||
Et vous vous retrouverez alors avec `harry` version `3` installé dans votre environnement Python global.
|
||||
|
||||
Et si vous essayez d’exécuter à nouveau `philosophers-stone`, il y a une chance que cela ne fonctionne pas car il a besoin de `harry` version `1`.
|
||||
Et si vous essayez d’exécuter à nouveau `philosophers-stone`, il y a une chance que cela **ne fonctionne pas** car il a besoin de `harry` version `1`.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -538,13 +538,13 @@ flowchart LR
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Il est très courant que les packages Python fassent de leur mieux pour éviter les changements cassants dans les nouvelles versions, mais il vaut mieux jouer la sécurité et installer de nouvelles versions intentionnellement et lorsque vous pouvez exécuter les tests pour vérifier que tout fonctionne correctement.
|
||||
Il est très courant que les packages Python fassent de leur mieux pour **éviter les changements cassants** dans les **nouvelles versions**, mais il vaut mieux jouer la sécurité et installer de nouvelles versions intentionnellement et lorsque vous pouvez exécuter les tests pour vérifier que tout fonctionne correctement.
|
||||
|
||||
///
|
||||
|
||||
Maintenant, imaginez cela avec beaucoup d’autres packages dont tous vos projets dépendent. C’est très difficile à gérer. Et vous finiriez probablement par exécuter certains projets avec des versions incompatibles des packages, sans savoir pourquoi quelque chose ne fonctionne pas.
|
||||
Maintenant, imaginez cela avec **beaucoup** d’autres **packages** dont tous vos **projets dépendent**. C’est très difficile à gérer. Et vous finiriez probablement par exécuter certains projets avec des **versions incompatibles** des packages, sans savoir pourquoi quelque chose ne fonctionne pas.
|
||||
|
||||
De plus, selon votre système d’exploitation (par exemple Linux, Windows, macOS), il se peut qu’il soit livré avec Python déjà installé. Et dans ce cas, il avait probablement des packages préinstallés avec des versions spécifiques nécessaires à votre système. Si vous installez des packages dans l’environnement Python global, vous pourriez finir par casser certains des programmes fournis avec votre système d’exploitation.
|
||||
De plus, selon votre système d’exploitation (par exemple Linux, Windows, macOS), il se peut qu’il soit livré avec Python déjà installé. Et dans ce cas, il avait probablement des packages préinstallés avec des versions spécifiques **nécessaires à votre système**. Si vous installez des packages dans l’environnement Python global, vous pourriez finir par **casser** certains des programmes fournis avec votre système d’exploitation.
|
||||
|
||||
## Où les packages sont-ils installés { #where-are-packages-installed }
|
||||
|
||||
@@ -566,17 +566,17 @@ $ pip install "fastapi[standard]"
|
||||
|
||||
Cela téléchargera un fichier compressé avec le code de FastAPI, normalement depuis [PyPI](https://pypi.org/project/fastapi/).
|
||||
|
||||
Il téléchargera également des fichiers pour d’autres packages dont FastAPI dépend.
|
||||
Il **téléchargera** également des fichiers pour d’autres packages dont FastAPI dépend.
|
||||
|
||||
Ensuite, il extraira tous ces fichiers et les placera dans un répertoire de votre ordinateur.
|
||||
Ensuite, il **extraira** tous ces fichiers et les placera dans un répertoire de votre ordinateur.
|
||||
|
||||
Par défaut, il placera ces fichiers téléchargés et extraits dans le répertoire fourni avec votre installation de Python, c’est l’environnement global.
|
||||
Par défaut, il placera ces fichiers téléchargés et extraits dans le répertoire fourni avec votre installation de Python, c’est l’**environnement global**.
|
||||
|
||||
## Qu’est-ce qu’un environnement virtuel { #what-are-virtual-environments }
|
||||
|
||||
La solution aux problèmes posés par le fait d’avoir tous les packages dans l’environnement global est d’utiliser un environnement virtuel pour chaque projet sur lequel vous travaillez.
|
||||
La solution aux problèmes posés par le fait d’avoir tous les packages dans l’environnement global est d’utiliser un **environnement virtuel pour chaque projet** sur lequel vous travaillez.
|
||||
|
||||
Un environnement virtuel est un répertoire, très similaire à celui global, où vous pouvez installer les packages pour un projet.
|
||||
Un environnement virtuel est un **répertoire**, très similaire à celui global, où vous pouvez installer les packages pour un projet.
|
||||
|
||||
De cette manière, chaque projet aura son propre environnement virtuel (répertoire `.venv`) avec ses propres packages.
|
||||
|
||||
@@ -730,7 +730,7 @@ et utilisera celui-ci.
|
||||
|
||||
////
|
||||
|
||||
Un détail important est qu’il placera le chemin de l’environnement virtuel au début de la variable `PATH`. Le système le trouvera avant de trouver tout autre Python disponible. Ainsi, lorsque vous exécutez `python`, il utilisera le Python de l’environnement virtuel au lieu de tout autre `python` (par exemple, un `python` d’un environnement global).
|
||||
Un détail important est qu’il placera le chemin de l’environnement virtuel au **début** de la variable `PATH`. Le système le trouvera **avant** de trouver tout autre Python disponible. Ainsi, lorsque vous exécutez `python`, il utilisera le Python **de l’environnement virtuel** au lieu de tout autre `python` (par exemple, un `python` d’un environnement global).
|
||||
|
||||
Activer un environnement virtuel change aussi deux ou trois autres choses, mais c’est l’un des points les plus importants.
|
||||
|
||||
@@ -766,11 +766,11 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python
|
||||
|
||||
////
|
||||
|
||||
Cela signifie que le programme `python` qui sera utilisé est celui dans l’environnement virtuel.
|
||||
Cela signifie que le programme `python` qui sera utilisé est celui **dans l’environnement virtuel**.
|
||||
|
||||
Vous utilisez `which` sous Linux et macOS et `Get-Command` sous Windows PowerShell.
|
||||
|
||||
La façon dont cette commande fonctionne est qu’elle va vérifier la variable d’environnement `PATH`, en parcourant chaque chemin dans l’ordre, à la recherche du programme nommé `python`. Une fois trouvé, elle vous affichera le chemin vers ce programme.
|
||||
La façon dont cette commande fonctionne est qu’elle va vérifier la variable d’environnement `PATH`, en parcourant **chaque chemin dans l’ordre**, à la recherche du programme nommé `python`. Une fois trouvé, elle vous **affichera le chemin** vers ce programme.
|
||||
|
||||
La partie la plus importante est que lorsque vous appelez `python`, c’est exactement « `python` » qui sera exécuté.
|
||||
|
||||
@@ -778,9 +778,9 @@ Ainsi, vous pouvez confirmer si vous êtes dans le bon environnement virtuel.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Il est facile d’activer un environnement virtuel, d’obtenir un Python, puis d’aller vers un autre projet.
|
||||
Il est facile d’activer un environnement virtuel, d’obtenir un Python, puis d’**aller vers un autre projet**.
|
||||
|
||||
Et le second projet ne fonctionnerait pas parce que vous utilisez le Python incorrect, provenant d’un environnement virtuel d’un autre projet.
|
||||
Et le second projet **ne fonctionnerait pas** parce que vous utilisez le **Python incorrect**, provenant d’un environnement virtuel d’un autre projet.
|
||||
|
||||
Il est utile de pouvoir vérifier quel `python` est utilisé. 🤓
|
||||
|
||||
@@ -788,9 +788,9 @@ Il est utile de pouvoir vérifier quel `python` est utilisé. 🤓
|
||||
|
||||
## Pourquoi désactiver un environnement virtuel { #why-deactivate-a-virtual-environment }
|
||||
|
||||
Par exemple, vous pourriez travailler sur un projet `philosophers-stone`, activer cet environnement virtuel, installer des packages et travailler avec cet environnement.
|
||||
Par exemple, vous pourriez travailler sur un projet `philosophers-stone`, **activer cet environnement virtuel**, installer des packages et travailler avec cet environnement.
|
||||
|
||||
Puis vous souhaitez travailler sur un autre projet `prisoner-of-azkaban`.
|
||||
Puis vous souhaitez travailler sur **un autre projet** `prisoner-of-azkaban`.
|
||||
|
||||
Vous allez vers ce projet :
|
||||
|
||||
@@ -842,23 +842,23 @@ I solemnly swear 🐺
|
||||
|
||||
## Alternatives { #alternatives }
|
||||
|
||||
Ceci est un guide simple pour vous lancer et vous montrer comment tout fonctionne en dessous.
|
||||
Ceci est un guide simple pour vous lancer et vous montrer comment tout fonctionne **en dessous**.
|
||||
|
||||
Il existe de nombreuses alternatives pour gérer les environnements virtuels, les dépendances de packages (requirements), les projets.
|
||||
Il existe de nombreuses **alternatives** pour gérer les environnements virtuels, les dépendances de packages (requirements), les projets.
|
||||
|
||||
Lorsque vous êtes prêt et souhaitez utiliser un outil pour gérer l’ensemble du projet, les dépendances, les environnements virtuels, etc., je vous suggère d’essayer [uv](https://github.com/astral-sh/uv).
|
||||
Lorsque vous êtes prêt et souhaitez utiliser un outil pour **gérer l’ensemble du projet**, les dépendances de packages, les environnements virtuels, etc., je vous suggère d’essayer [uv](https://github.com/astral-sh/uv).
|
||||
|
||||
`uv` peut faire beaucoup de choses, il peut :
|
||||
|
||||
* Installer Python pour vous, y compris différentes versions
|
||||
* Gérer l’environnement virtuel pour vos projets
|
||||
* Installer des packages
|
||||
* Gérer les dépendances de packages et leurs versions pour votre projet
|
||||
* Vous assurer d’avoir un ensemble exact de packages et de versions à installer, y compris leurs dépendances, afin que vous puissiez être certain d’exécuter votre projet en production exactement comme sur votre ordinateur pendant le développement, cela s’appelle le locking
|
||||
* **Installer Python** pour vous, y compris différentes versions
|
||||
* Gérer l’**environnement virtuel** pour vos projets
|
||||
* Installer des **packages**
|
||||
* Gérer les **dépendances et versions** de packages pour votre projet
|
||||
* Vous assurer d’avoir un ensemble **exact** de packages et de versions à installer, y compris leurs dépendances, afin que vous puissiez être certain d’exécuter votre projet en production exactement comme sur votre ordinateur pendant le développement, cela s’appelle le **locking**
|
||||
* Et bien d’autres choses
|
||||
|
||||
## Conclusion { #conclusion }
|
||||
|
||||
Si vous avez lu et compris tout cela, vous en savez maintenant bien plus sur les environnements virtuels que beaucoup de développeurs. 🤓
|
||||
Si vous avez lu et compris tout cela, vous en savez maintenant **bien plus** sur les environnements virtuels que beaucoup de développeurs. 🤓
|
||||
|
||||
Connaître ces détails vous sera très probablement utile à l’avenir lorsque vous déboguerez quelque chose qui semble complexe, mais vous saurez comment tout fonctionne en dessous. 😎
|
||||
Connaître ces détails vous sera très probablement utile à l’avenir lorsque vous déboguerez quelque chose qui semble complexe, mais vous saurez **comment tout fonctionne en dessous**. 😎
|
||||
|
||||
Reference in New Issue
Block a user