Compare commits

...

2 Commits

Author SHA1 Message Date
github-actions[bot]
40ce6603b3 🎨 Auto format 2026-01-16 12:11:55 +00:00
github-actions[bot]
a9ca408f6a 🌐 Update translations for fr (update-outdated) 2026-01-16 12:11:23 +00:00
24 changed files with 2372 additions and 1359 deletions

View File

@@ -1,6 +1,6 @@
# Réponses supplémentaires dans OpenAPI
# Réponses supplémentaires dans OpenAPI { #additional-responses-in-openapi }
/// warning | Attention
/// warning | Alertes
Ceci concerne un sujet plutôt avancé.
@@ -8,29 +8,29 @@ Si vous débutez avec **FastAPI**, vous n'en aurez peut-être pas besoin.
///
Vous pouvez déclarer des réponses supplémentaires, avec des codes HTTP, des types de médias, des descriptions, etc.
Vous pouvez déclarer des réponses supplémentaires, avec des codes de statut supplémentaires, des types de médias, des descriptions, etc.
Ces réponses supplémentaires seront incluses dans le schéma OpenAPI, elles apparaîtront donc également dans la documentation de l'API.
Mais pour ces réponses supplémentaires, vous devez vous assurer de renvoyer directement une `Response` comme `JSONResponse`, avec votre code HTTP et votre contenu.
Mais pour ces réponses supplémentaires, vous devez vous assurer de renvoyer directement une `Response` comme `JSONResponse`, avec votre code de statut et votre contenu.
## Réponse supplémentaire avec `model`
## Réponse supplémentaire avec `model` { #additional-response-with-model }
Vous pouvez ajouter à votre décorateur de *paramètre de chemin* un paramètre `responses`.
Vous pouvez passer à vos *décorateurs de chemin d'accès* un paramètre `responses`.
Il prend comme valeur un `dict` dont les clés sont des codes HTTP pour chaque réponse, comme `200`, et la valeur de ces clés sont d'autres `dict` avec des informations pour chacun d'eux.
Il reçoit un `dict` : les clés sont des codes de statut pour chaque réponse (comme `200`), et les valeurs sont d'autres `dict` avec les informations pour chacune d'elles.
Chacun de ces `dict` de réponse peut avoir une clé `model`, contenant un modèle Pydantic, tout comme `response_model`.
**FastAPI** prendra ce modèle, générera son schéma JSON et l'inclura au bon endroit dans OpenAPI.
**FastAPI** prendra ce modèle, générera son JSON Schema et l'inclura au bon endroit dans OpenAPI.
Par exemple, pour déclarer une autre réponse avec un code HTTP `404` et un modèle Pydantic `Message`, vous pouvez écrire :
Par exemple, pour déclarer une autre réponse avec un code de statut `404` et un modèle Pydantic `Message`, vous pouvez écrire :
{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *}
{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
/// note | Remarque
Gardez à l'esprit que vous devez renvoyer directement `JSONResponse`.
Gardez à l'esprit que vous devez renvoyer directement le `JSONResponse`.
///
@@ -38,18 +38,18 @@ Gardez à l'esprit que vous devez renvoyer directement `JSONResponse`.
La clé `model` ne fait pas partie d'OpenAPI.
**FastAPI** prendra le modèle Pydantic à partir de là, générera le `JSON Schema` et le placera au bon endroit.
**FastAPI** prendra le modèle Pydantic à partir de là, générera le JSON Schema et le placera au bon endroit.
Le bon endroit est :
* Dans la clé `content`, qui a pour valeur un autre objet JSON (`dict`) qui contient :
* Une clé avec le type de support, par ex. `application/json`, qui contient comme valeur un autre objet JSON, qui contient :
* Une clé `schema`, qui a pour valeur le schéma JSON du modèle, voici le bon endroit.
* **FastAPI** ajoute ici une référence aux schémas JSON globaux à un autre endroit de votre OpenAPI au lieu de l'inclure directement. De cette façon, d'autres applications et clients peuvent utiliser ces schémas JSON directement, fournir de meilleurs outils de génération de code, etc.
* Dans la clé `content`, qui a pour valeur un autre objet JSON (`dict`) qui contient :
* Une clé avec le type de média, par ex. `application/json`, qui contient comme valeur un autre objet JSON, qui contient :
* Une clé `schema`, qui a pour valeur le JSON Schema du modèle, voici le bon endroit.
* **FastAPI** ajoute ici une référence aux JSON Schemas globaux à un autre endroit de votre OpenAPI au lieu de l'inclure directement. De cette façon, d'autres applications et clients peuvent utiliser ces JSON Schemas directement, fournir de meilleurs outils de génération de code, etc.
///
Les réponses générées au format OpenAPI pour cette *opération de chemin* seront :
Les réponses générées dans OpenAPI pour cette *opération de chemin d'accès* seront :
```JSON hl_lines="3-12"
{
@@ -88,7 +88,7 @@ Les réponses générées au format OpenAPI pour cette *opération de chemin* se
}
```
Les schémas sont référencés à un autre endroit du modèle OpenAPI :
Les schémas sont référencés à un autre endroit dans le schéma OpenAPI :
```JSON hl_lines="4-16"
{
@@ -169,13 +169,13 @@ Les schémas sont référencés à un autre endroit du modèle OpenAPI :
}
```
## Types de médias supplémentaires pour la réponse principale
## Types de médias supplémentaires pour la réponse principale { #additional-media-types-for-the-main-response }
Vous pouvez utiliser ce même paramètre `responses` pour ajouter différents types de médias pour la même réponse principale.
Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *opération de chemin* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *opération de chemin d'accès* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *}
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
/// note | Remarque
@@ -191,29 +191,29 @@ Mais si vous avez spécifié une classe de réponse personnalisée avec `None` c
///
## Combinaison d'informations
## Combinaison d'informations { #combining-information }
Vous pouvez également combiner des informations de réponse provenant de plusieurs endroits, y compris les paramètres `response_model`, `status_code` et `responses`.
Vous pouvez déclarer un `response_model`, en utilisant le code HTTP par défaut `200` (ou un code personnalisé si vous en avez besoin), puis déclarer des informations supplémentaires pour cette même réponse dans `responses`, directement dans le schéma OpenAPI.
Vous pouvez déclarer un `response_model`, en utilisant le code de statut par défaut `200` (ou un code personnalisé si vous en avez besoin), puis déclarer des informations supplémentaires pour cette même réponse dans `responses`, directement dans le schéma OpenAPI.
**FastAPI** conservera les informations supplémentaires des `responses` et les combinera avec le schéma JSON de votre modèle.
**FastAPI** conservera les informations supplémentaires des `responses` et les combinera avec le JSON Schema de votre modèle.
Par exemple, vous pouvez déclarer une réponse avec un code HTTP `404` qui utilise un modèle Pydantic et a une `description` personnalisée.
Par exemple, vous pouvez déclarer une réponse avec un code de statut `404` qui utilise un modèle Pydantic et a une `description` personnalisée.
Et une réponse avec un code HTTP `200` qui utilise votre `response_model`, mais inclut un `example` personnalisé :
Et une réponse avec un code de statut `200` qui utilise votre `response_model`, mais inclut un `example` personnalisé :
{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *}
{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
Tout sera combiné et inclus dans votre OpenAPI, et affiché dans la documentation de l'API :
Tout sera combiné et inclus dans votre OpenAPI, et affiché dans la documentation de l'API :
<img src="/img/tutorial/additional-responses/image01.png">
## Combinez les réponses prédéfinies et les réponses personnalisées
## Combiner des réponses prédéfinies et des réponses personnalisées { #combine-predefined-responses-and-custom-ones }
Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *paramètre de chemin*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *opération de chemin*.
Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreuses *opérations de chemin d'accès*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *opération de chemin d'accès*.
Dans ces cas, vous pouvez utiliser la technique Python "d'affection par décomposition" (appelé _unpacking_ en anglais) d'un `dict` avec `**dict_to_unpack` :
Dans ces cas, vous pouvez utiliser la technique Python de « unpacking » d'un `dict` avec `**dict_to_unpack` :
```Python
old_dict = {
@@ -223,7 +223,7 @@ old_dict = {
new_dict = {**old_dict, "new key": "new value"}
```
Ici, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la nouvelle paire clé-valeur :
Ici, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la nouvelle paire clé-valeur :
```Python
{
@@ -233,15 +233,15 @@ Ici, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la n
}
```
Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *paramètres de chemin* et les combiner avec des réponses personnalisées supplémentaires.
Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *opérations de chemin d'accès* et les combiner avec des réponses personnalisées supplémentaires.
Par exemple:
Par exemple :
{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *}
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
## Plus d'informations sur les réponses OpenAPI
## Plus d'informations sur les réponses OpenAPI { #more-information-about-openapi-responses }
Pour voir exactement ce que vous pouvez inclure dans les réponses, vous pouvez consulter ces sections dans la spécification OpenAPI :
Pour voir exactement ce que vous pouvez inclure dans les réponses, vous pouvez consulter ces sections dans la spécification OpenAPI :
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">Objet Responses de OpenAPI </a>, il inclut le `Response Object`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">Objet Response de OpenAPI </a>, vous pouvez inclure n'importe quoi directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et schémas JSON) et `links`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">Objet Responses d'OpenAPI</a>, il inclut le `Response Object`.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">Objet Response d'OpenAPI</a>, vous pouvez inclure n'importe quoi à partir de celui-ci directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et JSON Schemas), et `links`.

View File

@@ -1,28 +1,28 @@
# Codes HTTP supplémentaires
# Codes de statut 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*.
Il utilisera le code de statut par défaut ou celui que vous définissez dans votre *chemin d'accès*.
## Codes HTTP supplémentaires
## Codes de statut supplémentaires { #additional-status-codes_1 }
Si vous souhaitez renvoyer des codes HTTP supplémentaires en plus du code principal, vous pouvez le faire en renvoyant directement une `Response`, comme une `JSONResponse`, et en définissant directement le code HTTP supplémentaire.
Si vous souhaitez renvoyer des codes de statut supplémentaires en plus du code principal, vous pouvez le faire en renvoyant directement une `Response`, comme une `JSONResponse`, et en définissant directement le code de statut supplémentaire.
Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 "OK" en cas de succès.
Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour des éléments et renvoie des codes de statut HTTP 200 « OK » en cas de succès.
Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 "Créé".
Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code de statut HTTP de 201 « Created ».
Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous souhaitez :
Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous voulez :
{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *}
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
/// warning | Attention
/// warning | Alertes
Lorsque vous renvoyez une `Response` directement, comme dans l'exemple ci-dessus, elle sera renvoyée directement.
Elle ne sera pas sérialisée avec un modèle.
Elle ne sera pas sérialisée avec un modèle, etc.
Assurez-vous qu'il contient les données souhaitées et que les valeurs soient dans un format JSON valides (si vous utilisez une `JSONResponse`).
Vous devez vous assurer qu'elle contient les données que vous voulez qu'elle contienne, et que les valeurs sont du JSON valide (si vous utilisez `JSONResponse`).
///
@@ -30,12 +30,12 @@ Assurez-vous qu'il contient les données souhaitées et que les valeurs soient d
Vous pouvez également utiliser `from starlette.responses import JSONResponse`.
Pour plus de commodités, **FastAPI** fournit les objets `starlette.responses` sous forme d'un alias accessible par `fastapi.responses`. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en est de même avec l'objet `statut`.
**FastAPI** fournit les mêmes `starlette.responses` que `fastapi.responses` uniquement par commodité pour vous, le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette. De même pour `status`.
///
## Documents OpenAPI et API
## Documents OpenAPI et API { #openapi-and-api-docs }
Si vous renvoyez directement des codes HTTP et des réponses supplémentaires, ils ne seront pas inclus dans le schéma OpenAPI (la documentation de l'API), car FastAPI n'a aucun moyen de savoir à l'avance ce que vous allez renvoyer.
Si vous renvoyez directement des codes de statut et des réponses supplémentaires, ils ne seront pas inclus dans le schéma OpenAPI (les documents de l'API), car FastAPI n'a aucun moyen de savoir à l'avance ce que vous allez renvoyer.
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires](additional-responses.md){.internal-link target=_blank}.

View File

@@ -1,27 +1,21 @@
# Guide de l'utilisateur avancé
# Guide de l'utilisateur avancé { #advanced-user-guide }
## Caractéristiques supplémentaires
## Caractéristiques supplémentaires { #additional-features }
Le [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank} devrait suffire à vous faire découvrir toutes les fonctionnalités principales de **FastAPI**.
Dans les sections suivantes, vous verrez des options, configurations et fonctionnalités supplémentaires.
/// note | Remarque
/// tip | Astuce
Les sections de ce chapitre ne sont **pas nécessairement "avancées"**.
Les sections suivantes ne sont **pas nécessairement « avancées »**.
Et il est possible que pour votre cas d'utilisation, la solution se trouve dans l'un d'entre eux.
Et il est possible que, pour votre cas d'utilisation, la solution se trouve dans l'une d'entre elles.
///
## Lisez d'abord le didacticiel
## Lisez d'abord le didacticiel { #read-the-tutorial-first }
Vous pouvez utiliser la plupart des fonctionnalités de **FastAPI** grâce aux connaissances du [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank}.
Vous pouvez toujours utiliser la plupart des fonctionnalités de **FastAPI** avec les connaissances du [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank}.
Et les sections suivantes supposent que vous l'avez lu et que vous en connaissez les idées principales.
## Cours TestDriven.io
Si vous souhaitez suivre un cours pour débutants avancés pour compléter cette section de la documentation, vous pouvez consulter : <a href="https://testdrive.io/courses/tdd-fastapi/" class="external- link" target="_blank">Développement piloté par les tests avec FastAPI et Docker</a> par **TestDriven.io**.
10 % de tous les bénéfices de ce cours sont reversés au développement de **FastAPI**. 🎉 😄
Et les sections suivantes supposent que vous l'avez déjà lu, et supposent que vous connaissez ces idées principales.

View File

@@ -1,26 +1,26 @@
# Configuration avancée des paramètres de chemin
# Configuration avancée des chemins d'accès { #path-operation-advanced-configuration }
## ID d'opération OpenAPI
## operationId OpenAPI { #openapi-operationid }
/// warning | Attention
/// warning | Alertes
Si vous n'êtes pas un "expert" en OpenAPI, vous n'en avez probablement pas besoin.
Si vous nêtes pas un « expert » en OpenAPI, vous nen avez probablement pas besoin.
///
Dans OpenAPI, les chemins sont des ressources, tels que /users/ ou /items/, exposées par votre API, et les opérations sont les méthodes HTTP utilisées pour manipuler ces chemins, telles que GET, POST ou DELETE. Les operationId sont des chaînes uniques facultatives utilisées pour identifier une opération d'un chemin. Vous pouvez définir l'OpenAPI `operationId` à utiliser dans votre *opération de chemin* avec le paramètre `operation_id`.
Vous pouvez définir lOpenAPI `operationId` à utiliser dans votre *chemin d'accès* avec le paramètre `operation_id`.
Vous devez vous assurer qu'il est unique pour chaque opération.
Vous devez vous assurer quil est unique pour chaque opération.
{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
### Utilisation du nom *path operation function* comme operationId
### 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 chaque `operation_id` de l'*opération de chemin* en utilisant leur `APIRoute.name`.
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer chaque `operation_id` des *chemins d'accès* en utilisant leur `APIRoute.name`.
Vous devriez le faire après avoir ajouté toutes vos *paramètres de chemin*.
Vous devez le faire après avoir ajouté tous vos *chemins d'accès*.
{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2,12:21,24] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
/// tip | Astuce
@@ -28,79 +28,81 @@ Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `ope
///
/// warning | Attention
/// warning | Alertes
Pour faire cela, vous devez vous assurer que chacun de vos *chemin* ait un nom unique.
Si vous faites cela, vous devez vous assurer que chacune de vos *fonctions de chemin d'accès* a un nom unique.
Même s'ils se trouvent dans des modules différents (fichiers Python).
Même si elles sont dans des modules différents (fichiers Python).
///
## Exclusion d'OpenAPI
## Exclusion d'OpenAPI { #exclude-from-openapi }
Pour exclure un *chemin* du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et assignez-lui la valeur `False` :
Pour exclure un *chemin d'accès* du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et définissez-le à `False` :
{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
## Description avancée de docstring
## Description avancée depuis la docstring { #advanced-description-from-docstring }
Vous pouvez limiter le texte utilisé de la docstring d'une *fonction de chemin* qui sera affiché sur OpenAPI.
Vous pouvez limiter les lignes utilisées depuis la docstring dune *fonction de chemin d'accès* pour OpenAPI.
L'ajout d'un `\f` (un caractère d'échappement "form feed") va permettre à **FastAPI** de tronquer la sortie utilisée pour OpenAPI à ce stade.
Ajouter un `\f` (un caractère « form feed » échappé) amène **FastAPI** à tronquer la sortie utilisée pour OpenAPI à cet endroit.
Il n'apparaîtra pas dans la documentation, mais d'autres outils (tel que Sphinx) pourront utiliser le reste.
Il napparaîtra pas dans la documentation, mais dautres outils (tels que Sphinx) pourront utiliser le reste.
{* ../../docs_src/path_operation_advanced_configuration/tutorial004.py hl[19:29] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
## Réponses supplémentaires
## Réponses supplémentaires { #additional-responses }
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour une *opération de chemin*.
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour un *chemin d'accès*.
Cela définit les métadonnées sur la réponse principale d'une *opération de chemin*.
Cela définit les métadonnées concernant la réponse principale dun *chemin d'accès*.
Vous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc.
Il y a un chapitre entier ici dans la documentation à ce sujet, vous pouvez le lire sur [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
Il y a un chapitre entier dans la documentation à ce sujet, vous pouvez le lire dans [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
## OpenAPI supplémentaire
## OpenAPI Extra { #openapi-extra }
Lorsque vous déclarez un *chemin* dans votre application, **FastAPI** génère automatiquement les métadonnées concernant ce *chemin* à inclure dans le schéma OpenAPI.
Lorsque vous déclarez un *chemin d'accès* dans votre application, **FastAPI** génère automatiquement les métadonnées pertinentes concernant ce *chemin d'accès* à inclure dans le schéma OpenAPI.
/// note | Détails techniques
La spécification OpenAPI appelle ces métadonnées des <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Objets d'opération</a>.
Dans la spécification OpenAPI, cela sappelle l<a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Operation Object</a>.
///
Il contient toutes les informations sur le *chemin* et est utilisé pour générer automatiquement la documentation.
Il contient toutes les informations sur le *chemin d'accès* et est utilisé pour générer la documentation automatique.
Il inclut les `tags`, `parameters`, `requestBody`, `responses`, etc.
Ce schéma OpenAPI spécifique aux *operations* est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l'étendre.
Ce schéma OpenAPI spécifique au *chemin d'accès* est normalement généré automatiquement par **FastAPI**, mais vous pouvez aussi létendre.
/// tip | Astuce
Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d'utiliser les [réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
Cest un point dextension de bas niveau.
Si vous avez uniquement besoin de déclarer des réponses supplémentaires, une manière plus pratique de le faire est avec [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
///
Vous pouvez étendre le schéma OpenAPI pour une *opération de chemin* en utilisant le paramètre `openapi_extra`.
Vous pouvez étendre le schéma OpenAPI pour un *chemin d'accès* en utilisant le paramètre `openapi_extra`.
### Extensions OpenAPI
### Extensions OpenAPI { #openapi-extensions }
Cet `openapi_extra` peut être utile, par exemple, pour déclarer [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :
Cet `openapi_extra` peut être utile, par exemple, pour déclarer des [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :
{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
Si vous ouvrez la documentation automatique de l'API, votre extension apparaîtra au bas du *chemin* spécifique.
Si vous ouvrez les documents automatiques de lAPI, votre extension apparaîtra au bas du *chemin d'accès* spécifique.
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
Et dans le fichier openapi généré (`/openapi.json`), vous verrez également votre extension dans le cadre du *chemin* spécifique :
Et si vous regardez lOpenAPI résultant (dans `/openapi.json` de votre API), vous verrez aussi votre extension comme faisant partie du *chemin d'accès* spécifique :
```JSON hl_lines="22"
{
"openapi": "3.0.2",
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
@@ -127,44 +129,44 @@ Et dans le fichier openapi généré (`/openapi.json`), vous verrez également v
}
```
### Personnalisation du Schéma OpenAPI pour un chemin
### Schéma OpenAPI personnalisé pour un *chemin d'accès* { #custom-openapi-path-operation-schema }
Le dictionnaire contenu dans la variable `openapi_extra` sera fusionné avec le schéma OpenAPI généré automatiquement pour l'*opération de chemin*.
Le dictionnaire dans `openapi_extra` sera fusionné en profondeur avec le schéma OpenAPI généré automatiquement pour le *chemin d'accès*.
Ainsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement.
Ainsi, vous pourriez ajouter des données supplémentaires au schéma généré automatiquement.
Par exemple, vous pouvez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de validation proposée par Pydantic, mais vous pouvez toujours définir la requête dans le schéma OpenAPI.
Par exemple, vous pourriez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de FastAPI avec Pydantic, mais vous pourriez tout de même vouloir définir la requête dans le schéma OpenAPI.
Vous pouvez le faire avec `openapi_extra` :
Vous pourriez faire cela avec `openapi_extra` :
{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[20:37,39:40] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
Dans cet exemple, nous n'avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n'est même pas <abbr title="converti d'un format simple, comme des octets, en objets Python">parsé</abbr> en tant que JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargé de l'analyser d'une manière ou d'une autre.
Dans cet exemple, nous navons déclaré aucun modèle Pydantic. En fait, le corps de la requête nest même pas <abbr title="converted from some plain format, like bytes, into Python objects - converti depuis un format simple, comme des octets, en objets Python">parsed</abbr> en tant que JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargée de lanalyser dune manière ou dune autre.
Néanmoins, nous pouvons déclarer le schéma attendu pour le corps de la requête.
### Type de contenu OpenAPI personnalisé
### Type de contenu OpenAPI personnalisé { #custom-openapi-content-type }
En utilisant cette même astuce, vous pouvez utiliser un modèle Pydantic pour définir le schéma JSON qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le *chemin* concerné.
En utilisant cette même astuce, vous pourriez utiliser un modèle Pydantic pour définir le JSON Schema qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le *chemin d'accès*.
Et vous pouvez le faire même si le type de données dans la requête n'est pas au format JSON.
Et vous pourriez faire cela même si le type de données dans la requête nest pas du JSON.
Dans cet exemple, nous n'utilisons pas les fonctionnalités de FastAPI pour extraire le schéma JSON des modèles Pydantic ni la validation automatique pour JSON. En fait, nous déclarons le type de contenu de la requête en tant que YAML, et non JSON :
Par exemple, dans cette application, nous nutilisons pas la fonctionnalité intégrée de FastAPI pour extraire le JSON Schema depuis les modèles Pydantic ni la validation automatique pour le JSON. En fait, nous déclarons le type de contenu de la requête comme étant du YAML, pas du JSON :
{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[17:22,24] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
Néanmoins, bien que nous n'utilisions pas la fonctionnalité par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le schéma JSON pour les données que nous souhaitons recevoir en YAML.
Néanmoins, bien que nous nutilisions pas la fonctionnalité intégrée par défaut, nous utilisons tout de même un modèle Pydantic pour générer manuellement le JSON Schema pour les données que nous voulons recevoir en YAML.
Ensuite, nous utilisons directement la requête et extrayons son contenu en tant qu'octets. Cela signifie que FastAPI n'essaiera même pas d'analyser le payload de la requête en tant que JSON.
Ensuite, nous utilisons la requête directement et extrayons le corps en tant que `bytes`. Cela signifie que FastAPI nessaiera même pas danalyser le payload de la requête comme du JSON.
Et nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
Et ensuite, dans notre code, nous analysons directement ce contenu YAML, et puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[26:33] *}
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
/// tip | Astuce
Ici, nous réutilisons le même modèle Pydantic.
Mais nous aurions pu tout aussi bien pu le valider d'une autre manière.
Mais, de la même manière, nous aurions pu le valider dune autre façon.
///

View File

@@ -1,20 +1,20 @@
# Renvoyer directement une réponse
# Renvoyer directement une réponse { #return-a-response-directly }
Lorsque vous créez une *opération de chemins* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.
Lorsque vous créez un *chemin d'accès* **FastAPI**, vous pouvez normalement en retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.
Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [Encodeur compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}.
Ensuite, en arrière-plan, il mettra ces données JSON-compatible (par exemple un `dict`) à l'intérieur d'un `JSONResponse` qui sera utilisé pour envoyer la réponse au client.
Ensuite, en arrière-plan, il mettrait ces données compatibles JSON (par exemple un `dict`) à l'intérieur d'une `JSONResponse` qui serait utilisée pour envoyer la réponse au client.
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *opérations de chemin*.
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *chemins d'accès*.
Cela peut être utile, par exemple, pour retourner des en-têtes personnalisés ou des cookies.
## Renvoyer une `Response`
## Renvoyer une `Response` { #return-a-response }
En fait, vous pouvez retourner n'importe quelle `Response` ou n'importe quelle sous-classe de celle-ci.
/// note | Remarque
/// tip | Astuce
`JSONResponse` est elle-même une sous-classe de `Response`.
@@ -22,29 +22,29 @@ En fait, vous pouvez retourner n'importe quelle `Response` ou n'importe quelle s
Et quand vous retournez une `Response`, **FastAPI** la transmet directement.
Elle ne fera aucune conversion de données avec les modèles Pydantic, elle ne convertira pas le contenu en un type quelconque.
Elle ne fera aucune conversion de données avec les modèles Pydantic, elle ne convertira pas le contenu en un type quelconque, etc.
Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données.
Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données, etc.
## Utiliser le `jsonable_encoder` dans une `Response`
## Utiliser le `jsonable_encoder` dans une `Response` { #using-the-jsonable-encoder-in-a-response }
Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt à être utilisé (sérialisable).
Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt.
Par exemple, vous ne pouvez pas mettre un modèle Pydantic dans une `JSONResponse` sans d'abord le convertir en un `dict` avec tous les types de données (comme `datetime`, `UUID`, etc.) convertis en types compatibles avec JSON.
Par exemple, vous ne pouvez pas mettre un modèle Pydantic dans une `JSONResponse` sans d'abord le convertir en un `dict` avec tous les types de données (comme `datetime`, `UUID`, etc) convertis en types compatibles avec JSON.
Pour ces cas, vous pouvez spécifier un appel à `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
Pour ces cas, vous pouvez utiliser le `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
/// note | Détails techniques
Vous pouvez aussi utiliser `from starlette.responses import JSONResponse`.
**FastAPI** fournit le même objet `starlette.responses` que `fastapi.responses` juste par commodité pour le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
**FastAPI** fournit le même objet `starlette.responses` que `fastapi.responses` juste par commodité pour vous, le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
///
## Renvoyer une `Response` personnalisée
## Renvoyer une `Response` personnalisée { #returning-a-custom-response }
L'exemple ci-dessus montre toutes les parties dont vous avez besoin, mais il n'est pas encore très utile, car vous auriez pu retourner l'`item` directement, et **FastAPI** l'aurait mis dans une `JSONResponse` pour vous, en le convertissant en `dict`, etc. Tout cela par défaut.
@@ -54,12 +54,12 @@ Disons que vous voulez retourner une réponse <a href="https://en.wikipedia.org/
Vous pouvez mettre votre contenu XML dans une chaîne de caractères, la placer dans une `Response`, et la retourner :
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
## Notes
## Notes { #notes }
Lorsque vous renvoyez une `Response` directement, ses données ne sont pas validées, converties (sérialisées), ni documentées automatiquement.
Mais vous pouvez toujours les documenter comme décrit dans [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
Mais vous pouvez toujours les documenter comme décrit dans [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
Vous pouvez voir dans les sections suivantes comment utiliser/déclarer ces `Response`s personnalisées tout en conservant la conversion automatique des données, la documentation, etc.

View File

@@ -1,34 +1,34 @@
# Test de performance
# Benchmarks { #benchmarks }
Les tests de performance de TechEmpower montrent que les applications **FastAPI** tournant sous Uvicorn comme <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">étant l'un des frameworks Python les plus rapides disponibles</a>, seulement inférieur à Starlette et Uvicorn (tous deux utilisés au cœur de FastAPI). (*)
Les benchmarks indépendants de TechEmpower montrent que les applications **FastAPI** exécutées avec Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">lun des frameworks Python les plus rapides disponibles</a>, juste en dessous de Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI).
Mais en prêtant attention aux tests de performance et aux comparaisons, il faut tenir compte de ce qu'il suit.
Mais lorsque vous consultez des benchmarks et des comparaisons, vous devez garder ce qui suit à lesprit.
## Tests de performance et rapidité
## Benchmarks et vitesse { #benchmarks-and-speed }
Lorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents.
Lorsque vous consultez les benchmarks, il est courant de voir plusieurs outils de types différents comparés comme sils étaient équivalents.
En particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils).
En particulier, de voir Uvicorn, Starlette et FastAPI comparés ensemble (parmi de nombreux autres outils).
Plus le problème résolu par un outil est simple, mieux seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils.
Plus le problème résolu par loutil est simple, meilleures seront les performances quil obtiendra. Et la plupart des benchmarks ne testent pas les fonctionnalités supplémentaires fournies par loutil.
La hiérarchie est la suivante :
* **Uvicorn** : un serveur ASGI
* **Starlette** : (utilise Uvicorn) un micro-framework web
* **FastAPI**: (utilise Starlette) un micro-framework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc.
* **Starlette** : (utilise Uvicorn) un microframework web
* **FastAPI** : (utilise Starlette) un microframework dAPI avec plusieurs fonctionnalités supplémentaires pour construire des API, avec la validation des données, etc.
* **Uvicorn** :
* A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis-à-part le serveur en lui-même.
* On n'écrit pas une application avec uniquement Uvicorn. Cela signifie que le code devrait inclure plus ou moins, au minimum, tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale apportera les mêmes complications que si on avait utilisé un framework et que l'on avait minimisé la quantité de code et de bugs.
* Si on compare Uvicorn, il faut le comparer à d'autre applications de serveurs comme Daphne, Hypercorn, uWSGI, etc.
* Aura les meilleures performances, car il na pas beaucoup de code supplémentaire en dehors du serveur lui-même.
* Vous nécririez pas une application directement en Uvicorn. Cela signifierait que votre code devrait inclure plus ou moins, au minimum, tout le code fourni par Starlette (ou **FastAPI**). Et si vous faisiez cela, votre application finale aurait la même surcharge que si vous aviez utilisé un framework, tout en minimisant le code de votre application et les bugs.
* Si vous comparez Uvicorn, comparez-le à Daphne, Hypercorn, uWSGI, etc. Des serveurs dapplications.
* **Starlette** :
* A les seconde meilleures performances après Uvicorn. Starlette utilise en réalité Uvicorn. De ce fait, il ne peut quêtre plus "lent" qu'Uvicorn car il requiert l'exécution de plus de code.
* Cependant il nous apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc.
* Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou micorframework) comme Sanic, Flask, Django, etc.
* Aura les performances suivantes, après Uvicorn. En fait, Starlette utilise Uvicorn pour sexécuter. Donc, il ne peut probablement que devenir « plus lent » quUvicorn, en devant exécuter plus de code.
* Mais il vous fournit les outils pour construire des applications web simples, avec du routage basé sur des chemins, etc.
* Si vous comparez Starlette, comparez-le à Sanic, Flask, Django, etc. Des frameworks web (ou microframeworks).
* **FastAPI** :
* Comme Starlette, FastAPI utilise Uvicorn et ne peut donc pas être plus rapide que ce dernier.
* FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités qui sont nécessaires presque systématiquement lors de la création d'une API, comme la validation des données, la sérialisation. En utilisant FastAPI, on obtient une documentation automatiquement (qui ne requiert aucune manipulation pour être mise en place).
* Si on n'utilisait pas FastAPI mais directement Starlette (ou un outil équivalent comme Sanic, Flask, Responder, etc) il faudrait implémenter la validation des données et la sérialisation par nous-même. Le résultat serait donc le même dans les deux cas mais du travail supplémentaire serait à réaliser avec Starlette, surtout en considérant que la validation des données et la sérialisation représentent la plus grande quantité de code à écrire dans une application.
* De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient les mêmes performances (si ce n'est de meilleurs performances) que l'on aurait pu avoir sans ce framework (en ayant à implémenter de nombreuses fonctionnalités importantes par nous-mêmes).
* Si on compare FastAPI, il faut le comparer à d'autres frameworks web (ou ensemble d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc.
* De la même manière que Starlette utilise Uvicorn et ne peut pas être plus rapide que lui, **FastAPI** utilise Starlette, donc il ne peut pas être plus rapide que lui.
* FastAPI fournit plus de fonctionnalités par-dessus Starlette. Des fonctionnalités dont vous avez presque toujours besoin lorsque vous construisez des API, comme la validation des données et la sérialisation. Et en lutilisant, vous obtenez de la documentation automatique gratuitement (la documentation automatique najoute même pas de surcharge à lexécution des applications, elle est générée au démarrage).
* Si vous nutilisiez pas FastAPI et utilisiez Starlette directement (ou un autre outil, comme Sanic, Flask, Responder, etc.), vous devriez implémenter vous-même toute la validation des données et la sérialisation. Ainsi, votre application finale aurait toujours la même surcharge que si elle avait été construite en utilisant FastAPI. Et dans de nombreux cas, cette validation des données et cette sérialisation représentent la plus grande quantité de code écrite dans les applications.
* Ainsi, en utilisant FastAPI, vous économisez du temps de développement, des bugs, des lignes de code, et vous obtiendriez probablement les mêmes performances (ou de meilleures) que si vous ne lutilisiez pas (puisque vous devriez tout implémenter dans votre code).
* Si vous comparez FastAPI, comparez-le à un framework dapplication web (ou à un ensemble doutils) qui fournit la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc. Des frameworks avec validation automatique intégrée des données, sérialisation et documentation.

View File

@@ -1,74 +1,151 @@
# Déployer avec Docker
# FastAPI dans des conteneurs - Docker { #fastapi-in-containers-docker }
Dans cette section, vous verrez des instructions et des liens vers des guides pour savoir comment :
Lors du déploiement dapplications FastAPI, une approche courante consiste à construire une **image de conteneur Linux**. Cela se fait généralement avec <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Vous pouvez ensuite déployer cette image de conteneur de lune de plusieurs manières possibles.
* Faire de votre application **FastAPI** une image/conteneur Docker avec une performance maximale. En environ **5 min**.
* (Optionnellement) comprendre ce que vous, en tant que développeur, devez savoir sur HTTPS.
* Configurer un cluster en mode Docker Swarm avec HTTPS automatique, même sur un simple serveur à 5 dollars US/mois. En environ **20 min**.
* Générer et déployer une application **FastAPI** complète, en utilisant votre cluster Docker Swarm, avec HTTPS, etc. En environ **10 min**.
Vous pouvez utiliser <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a> pour le déploiement. Il présente plusieurs avantages comme la sécurité, la réplicabilité, la simplicité de développement, etc.
Si vous utilisez Docker, vous pouvez utiliser l'image Docker officielle :
## <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>
Cette image est dotée d'un mécanisme d'"auto-tuning", de sorte qu'il vous suffit d'ajouter votre code pour obtenir automatiquement des performances très élevées. Et sans faire de sacrifices.
Mais vous pouvez toujours changer et mettre à jour toutes les configurations avec des variables d'environnement ou des fichiers de configuration.
Lutilisation de conteneurs Linux présente plusieurs avantages, notamment la **sécurité**, la **réplicabilité**, la **simplicité**, et dautres.
/// tip | Astuce
Pour voir toutes les configurations et options, rendez-vous sur la page de l'image Docker : <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>.
Vous êtes pressé(e) et vous connaissez déjà tout ça ? Allez directement au [`Dockerfile` ci-dessous 👇](#build-a-docker-image-for-fastapi).
///
## Créer un `Dockerfile`
* Allez dans le répertoire de votre projet.
* Créez un `Dockerfile` avec :
<details>
<summary>Aperçu du Dockerfile 👀</summary>
```Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
FROM python:3.9
COPY ./app /app
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
# If running behind a proxy like Nginx or Traefik add --proxy-headers
# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
```
### Applications plus larges
</details>
Si vous avez suivi la section sur la création d' [Applications avec plusieurs fichiers](../tutorial/bigger-applications.md){.internal-link target=_blank}, votre `Dockerfile` pourrait ressembler à ceci :
## Quest-ce quun conteneur { #what-is-a-container }
```Dockerfile
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
Les conteneurs (principalement les conteneurs Linux) sont une manière très **légère** dempaqueter des applications, y compris toutes leurs dépendances et les fichiers nécessaires, tout en les gardant isolées des autres conteneurs (dautres applications ou composants) sur le même système.
COPY ./app /app/app
Les conteneurs Linux sexécutent en utilisant le même kernel Linux que lhôte (machine, machine virtuelle, serveur cloud, etc.). Cela signifie simplement quils sont très légers (comparés à des machines virtuelles complètes émulant un système dexploitation entier).
Ainsi, les conteneurs consomment **peu de ressources**, une quantité comparable à lexécution directe des processus (une machine virtuelle consommerait bien plus).
Les conteneurs ont aussi leurs propres processus en cours dexécution **isolés** (généralement un seul processus), leur système de fichiers et leur réseau, ce qui simplifie le déploiement, la sécurité, le développement, etc.
## Quest-ce quune image de conteneur { #what-is-a-container-image }
Un **conteneur** sexécute à partir dune **image de conteneur**.
Une image de conteneur est une version **statique** de tous les fichiers, des variables denvironnement, et de la commande/du programme par défaut qui doivent être présents dans un conteneur. **Statique** signifie ici que l**image** de conteneur ne sexécute pas, elle nest pas lancée, ce sont uniquement les fichiers empaquetés et les métadonnées.
Contrairement à une «image de conteneur» qui correspond au contenu statique stocké, un «conteneur» désigne généralement linstance en cours dexécution, la chose qui est **exécutée**.
Quand le **conteneur** est démarré et sexécute (démarré depuis une **image de conteneur**), il peut créer ou modifier des fichiers, des variables denvironnement, etc. Ces changements nexisteront que dans ce conteneur, et ne persisteront pas dans limage de conteneur sous-jacente (ils ne seront pas enregistrés sur disque).
Une image de conteneur est comparable au fichier et au contenu dun **programme**, par exemple `python` et un fichier `main.py`.
Et le **conteneur** lui-même (par opposition à l**image de conteneur**) est linstance réellement exécutée de limage, comparable à un **processus**. En fait, un conteneur ne sexécute que lorsquil a un **processus en cours dexécution** (et normalement cest un seul processus). Le conteneur sarrête lorsquil ny a plus de processus en cours dexécution à lintérieur.
## Images de conteneur { #container-images }
Docker a été lun des principaux outils pour créer et gérer les **images de conteneur** et les **conteneurs**.
Et il existe un <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> public avec des **images de conteneur officielles** préfabriquées pour de nombreux outils, environnements, bases de données, et applications.
Par exemple, il existe une <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">image Python</a> officielle.
Et il existe beaucoup dautres images pour différentes choses comme des bases de données, par exemple pour :
* <a href="https://hub.docker.com/_/postgres" class="external-link" target="_blank">PostgreSQL</a>
* <a href="https://hub.docker.com/_/mysql" class="external-link" target="_blank">MySQL</a>
* <a href="https://hub.docker.com/_/mongo" class="external-link" target="_blank">MongoDB</a>
* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>, etc.
En utilisant une image de conteneur préfabriquée, il est très facile de **combiner** et dutiliser différents outils. Par exemple, pour tester une nouvelle base de données. Dans la plupart des cas, vous pouvez utiliser les **images officielles** et simplement les configurer via des variables denvironnement.
De cette façon, dans de nombreux cas, vous pouvez apprendre les conteneurs et Docker et réutiliser ces connaissances avec beaucoup doutils et de composants différents.
Ainsi, vous exécuteriez **plusieurs conteneurs** avec différentes choses, comme une base de données, une application Python, un serveur web avec une application frontend React, et vous les connecteriez entre eux via leur réseau interne.
Tous les systèmes de gestion de conteneurs (comme Docker ou Kubernetes) intègrent ces fonctionnalités réseau.
## Conteneurs et processus { #containers-and-processes }
Une **image de conteneur** inclut normalement dans ses métadonnées le programme ou la commande par défaut à exécuter lorsque le **conteneur** est démarré, ainsi que les paramètres à passer à ce programme. Très similaire à ce que ce serait en ligne de commande.
Quand un **conteneur** est démarré, il exécutera cette commande/ce programme (bien que vous puissiez loutrepasser et lui faire exécuter une commande/un programme différent).
Un conteneur sexécute tant que le **processus principal** (commande ou programme) sexécute.
Un conteneur a normalement un **seul processus**, mais il est aussi possible de démarrer des sous-processus depuis le processus principal, et ainsi vous aurez **plusieurs processus** dans le même conteneur.
Mais il nest pas possible davoir un conteneur en cours dexécution sans **au moins un processus en cours dexécution**. Si le processus principal sarrête, le conteneur sarrête.
## Construire une image Docker pour FastAPI { #build-a-docker-image-for-fastapi }
Ok, construisons quelque chose maintenant ! 🚀
Je vais vous montrer comment construire une **image Docker** pour FastAPI **à partir de zéro**, sur la base de l**image Python officielle**.
Cest ce que vous voudrez faire dans **la plupart des cas**, par exemple :
* Utiliser **Kubernetes** ou des outils similaires
* Exécuter sur un **Raspberry Pi**
* Utiliser un service cloud qui exécute une image de conteneur pour vous, etc.
### Exigences de packages { #package-requirements }
Vous aurez normalement les **exigences de packages** de votre application dans un fichier.
Cela dépendra principalement de loutil que vous utilisez pour **installer** ces exigences.
La manière la plus courante de le faire est davoir un fichier `requirements.txt` avec les noms de packages et leurs versions, un par ligne.
Vous utiliseriez bien sûr les mêmes idées que celles présentées dans [À propos des versions de FastAPI](versions.md){.internal-link target=_blank} pour définir les plages de versions.
Par exemple, votre `requirements.txt` pourrait ressembler à :
```
fastapi[standard]>=0.113.0,<0.114.0
pydantic>=2.7.0,<3.0.0
```
### Raspberry Pi et autres architectures
Et vous installeriez normalement ces dépendances de packages avec `pip`, par exemple :
Si vous utilisez Docker sur un Raspberry Pi (qui a un processeur ARM) ou toute autre architecture, vous pouvez créer un `Dockerfile` à partir de zéro, basé sur une image de base Python (qui est multi-architecture) et utiliser Uvicorn seul.
<div class="termy">
Dans ce cas, votre `Dockerfile` pourrait ressembler à ceci :
```Dockerfile
FROM python:3.7
RUN pip install fastapi uvicorn
EXPOSE 80
COPY ./app /app
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
```console
$ pip install -r requirements.txt
---> 100%
Successfully installed fastapi pydantic
```
## Créer le code **FastAPI**.
</div>
* Créer un répertoire `app` et y entrer.
* Créez un fichier `main.py` avec :
/// info
Il existe dautres formats et outils pour définir et installer des dépendances de packages.
///
### Créer le code **FastAPI** { #create-the-fastapi-code }
* Créez un répertoire `app` et entrez dedans.
* Créez un fichier vide `__init__.py`.
* Créez un fichier `main.py` avec :
```Python
from typing import Optional
from typing import Union
from fastapi import FastAPI
@@ -81,20 +158,166 @@ def read_root():
@app.get("/items/{item_id}")
def read_item(item_id: int, q: Optional[str] = None):
def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
* Vous devriez maintenant avoir une structure de répertoire telle que :
### Dockerfile { #dockerfile }
Maintenant, dans le même répertoire de projet, créez un fichier `Dockerfile` avec :
```{ .dockerfile .annotate }
# (1)!
FROM python:3.9
# (2)!
WORKDIR /code
# (3)!
COPY ./requirements.txt /code/requirements.txt
# (4)!
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# (5)!
COPY ./app /code/app
# (6)!
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
```
1. Partir de limage de base Python officielle.
2. Définir le répertoire de travail courant sur `/code`.
Cest là que nous mettrons le fichier `requirements.txt` et le répertoire `app`.
3. Copier le fichier contenant les exigences dans le répertoire `/code`.
Copier **uniquement** le fichier contenant les exigences dabord, pas le reste du code.
Comme ce fichier **ne change pas souvent**, Docker le détectera et utilisera le **cache** pour cette étape, permettant dutiliser le cache pour létape suivante aussi.
4. Installer les dépendances de packages du fichier dexigences.
Loption `--no-cache-dir` indique à `pip` de ne pas enregistrer localement les packages téléchargés, car cela ne sert que si `pip` devait être relancé pour installer les mêmes packages, mais ce nest pas le cas lorsquon travaille avec des conteneurs.
/// note | Remarque
`--no-cache-dir` est uniquement lié à `pip`, il na rien à voir avec Docker ou les conteneurs.
///
Loption `--upgrade` indique à `pip` de mettre à niveau les packages sils sont déjà installés.
Comme létape précédente de copie du fichier pourrait être détectée par le **cache Docker**, cette étape va aussi **utiliser le cache Docker** lorsquil est disponible.
Utiliser le cache à cette étape va vous **faire gagner** beaucoup de **temps** lorsque vous reconstruisez limage encore et encore pendant le développement, au lieu de **télécharger et installer** toutes les dépendances **à chaque fois**.
5. Copier le répertoire `./app` dans le répertoire `/code`.
Comme cela contient tout le code, qui est ce qui **change le plus fréquemment**, le **cache** Docker ne sera pas facilement utilisé pour cette étape ou pour les **étapes suivantes**.
Il est donc important de placer cela **près de la fin** du `Dockerfile`, pour optimiser les temps de build de limage de conteneur.
6. Définir la **commande** pour utiliser `fastapi run`, qui utilise Uvicorn en dessous.
`CMD` prend une liste de chaînes de caractères, chacune de ces chaînes correspond à ce que vous taperiez en ligne de commande, séparé par des espaces.
Cette commande sera exécutée depuis le **répertoire de travail courant**, le même répertoire `/code` que vous avez défini plus haut avec `WORKDIR /code`.
/// tip | Astuce
Passez en revue ce que fait chaque ligne en cliquant sur chaque bulle numérotée dans le code. 👆
///
/// warning | Alertes
Vous devez vous assurer dutiliser **toujours** la **forme exec** de linstruction `CMD`, comme expliqué ci-dessous.
///
#### Utiliser `CMD` - forme exec { #use-cmd-exec-form }
Linstruction Docker <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> peut sécrire sous deux formes :
✅ Forme **exec** :
```Dockerfile
# ✅ Do this
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
```
⛔️ Forme **shell** :
```Dockerfile
# ⛔️ Don't do this
CMD fastapi run app/main.py --port 80
```
Vous devez vous assurer de toujours utiliser la forme **exec** pour garantir que FastAPI puisse sarrêter proprement et que les [événements de lifespan](../advanced/events.md){.internal-link target=_blank} soient déclenchés.
Vous pouvez en lire plus à ce sujet dans la <a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">documentation Docker sur les formes shell et exec</a>.
Cela peut être assez visible lors de lutilisation de `docker compose`. Consultez cette section de la FAQ Docker Compose pour plus de détails techniques : <a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Why do my services take 10 seconds to recreate or stop?</a>.
#### Structure de répertoires { #directory-structure }
Vous devriez maintenant avoir une structure de répertoires comme :
```
.
├── app
│   ├── __init__.py
│ └── main.py
── Dockerfile
── Dockerfile
└── requirements.txt
```
## Construire l'image Docker
#### Derrière un proxy de terminaison TLS { #behind-a-tls-termination-proxy }
Si vous exécutez votre conteneur derrière un proxy de terminaison TLS (load balancer) comme Nginx ou Traefik, ajoutez loption `--proxy-headers` ; cela indiquera à Uvicorn (via la CLI FastAPI) de faire confiance aux en-têtes envoyés par ce proxy lui indiquant que lapplication sexécute derrière HTTPS, etc.
```Dockerfile
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
```
#### Cache Docker { #docker-cache }
Il y a une astuce importante dans ce `Dockerfile` : nous copions dabord **le fichier des dépendances seul**, pas le reste du code. Je vais vous expliquer pourquoi.
```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```
Docker et dautres outils **construisent** ces images de conteneur **de manière incrémentale**, en ajoutant **une couche par-dessus lautre**, en commençant par le haut du `Dockerfile` et en ajoutant tous les fichiers créés par chacune des instructions du `Dockerfile`.
Docker et des outils similaires utilisent aussi un **cache interne** lors de la construction de limage : si un fichier na pas changé depuis la dernière construction de limage de conteneur, alors il va **réutiliser la même couche** créée la dernière fois, au lieu de copier le fichier à nouveau et de créer une nouvelle couche à partir de zéro.
Le simple fait déviter la copie de fichiers naméliore pas forcément beaucoup les choses, mais comme le cache a été utilisé pour cette étape, il peut **être utilisé pour létape suivante**. Par exemple, il pourrait être utilisé pour linstruction qui installe les dépendances avec :
```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
Le fichier des exigences de packages **ne changera pas fréquemment**. Donc, en ne copiant que ce fichier, Docker pourra **utiliser le cache** pour cette étape.
Et ensuite, Docker pourra **utiliser le cache pour létape suivante** qui télécharge et installe ces dépendances. Et cest là que nous **gagnons beaucoup de temps**. ✨ ... et évitons lennui dattendre. 😪😆
Le téléchargement et linstallation des dépendances de packages **peuvent prendre des minutes**, mais utiliser le **cache** **prendrait au maximum quelques secondes**.
Et comme vous reconstruiriez limage de conteneur encore et encore pendant le développement pour vérifier que vos modifications de code fonctionnent, cela vous ferait gagner beaucoup de temps cumulé.
Ensuite, près de la fin du `Dockerfile`, nous copions tout le code. Comme cest ce qui **change le plus fréquemment**, nous le mettons près de la fin, car presque toujours, tout ce qui vient après cette étape ne pourra pas utiliser le cache.
```Dockerfile
COPY ./app /code/app
```
### Construire limage Docker { #build-the-docker-image }
Maintenant que tous les fichiers sont en place, construisons limage de conteneur.
* Allez dans le répertoire du projet (dans lequel se trouve votre `Dockerfile`, contenant votre répertoire `app`).
* Construisez votre image FastAPI :
@@ -109,9 +332,17 @@ $ docker build -t myimage .
</div>
## Démarrer le conteneur Docker
/// tip | Astuce
* Exécutez un conteneur basé sur votre image :
Remarquez le `.` à la fin, il est équivalent à `./` : il indique à Docker le répertoire à utiliser pour construire limage de conteneur.
Dans ce cas, cest le même répertoire courant (`.`).
///
### Démarrer le conteneur Docker { #start-the-docker-container }
* Exécutez un conteneur basé sur votre image :
<div class="termy">
@@ -121,65 +352,269 @@ $ docker run -d --name mycontainer -p 80:80 myimage
</div>
Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre
serveur actuel (et le nombre de cœurs du CPU).
## Vérifier { #check-it }
## Vérifier
Vous devriez pouvoir le vérifier via lURL de votre conteneur Docker, par exemple : <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou équivalent, en utilisant votre hôte Docker).
Vous devriez pouvoir accéder à votre application via l'URL de votre conteneur Docker, par exemple : <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou équivalent, en utilisant votre hôte Docker).
Vous verrez quelque chose comme :
Vous verrez quelque chose comme :
```JSON
{"item_id": 5, "q": "somequery"}
```
## Documentation interactive de l'API
## Documentation interactive de lAPI { #interactive-api-docs }
Vous pouvez maintenant visiter <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> ou <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (ou équivalent, en utilisant votre hôte Docker).
Vous pouvez maintenant aller sur <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> ou <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (ou équivalent, en utilisant votre hôte Docker).
Vous verrez la documentation interactive automatique de l'API (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
Vous verrez la documentation interactive automatique de lAPI (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
## Documentation de l'API alternative
## Documentation de lAPI alternative { #alternative-api-docs }
Et vous pouvez également aller sur <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> ou <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (ou équivalent, en utilisant votre hôte Docker).
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Traefik
## Construire une image Docker avec un FastAPI dans un seul fichier { #build-a-docker-image-with-a-single-file-fastapi }
<a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a> est un reverse proxy/load balancer
haute performance. Il peut faire office de "Proxy de terminaison TLS" (entre autres fonctionnalités).
Si votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./app`, votre structure de fichiers pourrait ressembler à ceci :
Il est intégré à Let's Encrypt. Ainsi, il peut gérer toutes les parties HTTPS, y compris l'acquisition et le renouvellement des certificats.
```
.
├── Dockerfile
├── main.py
└── requirements.txt
```
Il est également intégré à Docker. Ainsi, vous pouvez déclarer vos domaines dans les configurations de chaque application et faire en sorte qu'elles lisent ces configurations, génèrent les certificats HTTPS et servent via HTTPS à votre application automatiquement, sans nécessiter aucune modification de leurs configurations.
Ensuite, vous nauriez quà modifier les chemins correspondants pour copier le fichier dans le `Dockerfile` :
```{ .dockerfile .annotate hl_lines="10 13" }
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
# (1)!
COPY ./main.py /code/
# (2)!
CMD ["fastapi", "run", "main.py", "--port", "80"]
```
1. Copier le fichier `main.py` directement dans le répertoire `/code` (sans aucun répertoire `./app`).
2. Utiliser `fastapi run` pour servir votre application dans le fichier unique `main.py`.
Quand vous passez le fichier à `fastapi run`, il détectera automatiquement quil sagit dun fichier unique et non dune partie dun package, et saura comment limporter et servir votre application FastAPI. 😎
## Concepts de déploiement { #deployment-concepts }
Parlons à nouveau de certains des mêmes [concepts de déploiement](concepts.md){.internal-link target=_blank} en termes de conteneurs.
Les conteneurs sont principalement un outil pour simplifier le processus de **construction et de déploiement** dune application, mais ils nimposent pas une approche particulière pour gérer ces **concepts de déploiement**, et il existe plusieurs stratégies possibles.
La **bonne nouvelle**, cest quavec chaque stratégie différente il existe un moyen de couvrir tous les concepts de déploiement. 🎉
Passons en revue ces **concepts de déploiement** en termes de conteneurs :
* HTTPS
* Exécution au démarrage
* Redémarrages
* Réplication (le nombre de processus en cours dexécution)
* Mémoire
* Étapes préalables avant de démarrer
## HTTPS { #https }
Si nous nous concentrons uniquement sur l**image de conteneur** dune application FastAPI (et plus tard sur le **conteneur** en cours dexécution), HTTPS serait normalement géré **en externe** par un autre outil.
Cela pourrait être un autre conteneur, par exemple avec <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, gérant **HTTPS** et lacquisition **automatique** de **certificats**.
/// tip | Astuce
Traefik dispose dintégrations avec Docker, Kubernetes et dautres, il est donc très simple à mettre en place et à configurer pour HTTPS avec vos conteneurs.
///
Alternativement, HTTPS pourrait être géré par un fournisseur cloud comme lun de ses services (tout en exécutant lapplication dans un conteneur).
## Exécution au démarrage et redémarrages { #running-on-startup-and-restarts }
Il y a normalement un autre outil chargé de **démarrer et exécuter** votre conteneur.
Cela pourrait être **Docker** directement, **Docker Compose**, **Kubernetes**, un **service cloud**, etc.
Dans la plupart (ou tous) les cas, il existe une option simple pour activer lexécution du conteneur au démarrage et activer les redémarrages en cas déchec. Par exemple, dans Docker, cest loption en ligne de commande `--restart`.
Sans utiliser de conteneurs, faire exécuter des applications au démarrage et avec redémarrages peut être contraignant et difficile. Mais en **travaillant avec des conteneurs**, dans la plupart des cas cette fonctionnalité est incluse par défaut. ✨
## Réplication - Nombre de processus { #replication-number-of-processes }
Si vous avez un <abbr title="Un groupe de machines configurées pour être connectées et travailler ensemble dune certaine façon.">cluster</abbr> de machines avec **Kubernetes**, Docker Swarm Mode, Nomad, ou un autre système complexe similaire pour gérer des conteneurs distribués sur plusieurs machines, alors vous voudrez probablement **gérer la réplication** au **niveau du cluster** au lieu dutiliser un **gestionnaire de processus** (comme Uvicorn avec des workers) dans chaque conteneur.
Un de ces systèmes de gestion de conteneurs distribués comme Kubernetes dispose normalement dun moyen intégré de gérer la **réplication des conteneurs** tout en prenant en charge l**équilibrage de charge** pour les requêtes entrantes. Le tout au **niveau du cluster**.
Dans ces cas, vous voudrez probablement construire une **image Docker à partir de zéro** comme [expliqué ci-dessus](#dockerfile), installer vos dépendances, et exécuter **un seul processus Uvicorn** au lieu dutiliser plusieurs workers Uvicorn.
### Load Balancer { #load-balancer }
Lors de lutilisation de conteneurs, vous aurez normalement un composant **à lécoute sur le port principal**. Cela pourrait éventuellement être un autre conteneur qui est aussi un **proxy de terminaison TLS** pour gérer **HTTPS** ou un outil similaire.
Comme ce composant prendrait la **charge** des requêtes et la distribuerait entre les workers dune manière (espérons-le) **équilibrée**, on lappelle aussi communément un **Load Balancer**.
/// tip | Astuce
Le même composant de **proxy de terminaison TLS** utilisé pour HTTPS serait probablement aussi un **Load Balancer**.
///
Et en travaillant avec des conteneurs, le même système que vous utilisez pour les démarrer et les gérer aura déjà des outils internes pour transmettre la **communication réseau** (par exemple les requêtes HTTP) depuis ce **load balancer** (qui pourrait aussi être un **proxy de terminaison TLS**) vers le(s) conteneur(s) avec votre application.
### Un load balancer - Plusieurs conteneurs workers { #one-load-balancer-multiple-worker-containers }
En travaillant avec **Kubernetes** ou des systèmes distribués de gestion de conteneurs similaires, utiliser leurs mécanismes réseau internes permettrait au **load balancer** unique qui écoute sur le **port** principal de transmettre la communication (les requêtes) à potentiellement **plusieurs conteneurs** exécutant votre application.
Chacun de ces conteneurs exécutant votre application aurait normalement **un seul processus** (par exemple un processus Uvicorn exécutant votre application FastAPI). Ce seraient tous des **conteneurs identiques**, exécutant la même chose, mais chacun avec son propre processus, sa mémoire, etc. Ainsi, vous profiteriez de la **parallélisation** sur **différents cœurs** du CPU, ou même sur **différentes machines**.
Et le système de conteneurs distribués avec le **load balancer** **distribuerait les requêtes** à chacun des conteneurs avec votre application **à tour de rôle**. Ainsi, chaque requête pourrait être traitée par lun des multiples **conteneurs répliqués** exécutant votre application.
Et normalement ce **load balancer** serait capable de gérer des requêtes allant vers *dautres* applications dans votre cluster (par exemple vers un domaine différent, ou sous un préfixe de chemin dURL différent), et transmettrait cette communication aux bons conteneurs pour *cette autre* application sexécutant dans votre cluster.
### Un processus par conteneur { #one-process-per-container }
Dans ce type de scénario, vous voudrez probablement avoir **un seul processus (Uvicorn) par conteneur**, puisque vous gérez déjà la réplication au niveau du cluster.
Donc, dans ce cas, vous **ne** voudrez **pas** avoir plusieurs workers dans le conteneur, par exemple avec loption en ligne de commande `--workers`. Vous voudrez avoir un **seul processus Uvicorn** par conteneur (mais probablement plusieurs conteneurs).
Avoir un autre gestionnaire de processus à lintérieur du conteneur (comme ce serait le cas avec plusieurs workers) ne ferait quajouter une **complexité inutile** que vous gérez très probablement déjà avec votre système de cluster.
### Conteneurs avec plusieurs processus et cas particuliers { #containers-with-multiple-processes-and-special-cases }
Bien sûr, il existe des **cas particuliers** où vous pourriez vouloir avoir **un conteneur** avec plusieurs **processus workers Uvicorn** à lintérieur.
Dans ces cas, vous pouvez utiliser loption en ligne de commande `--workers` pour définir le nombre de workers que vous souhaitez exécuter :
```{ .dockerfile .annotate }
FROM python:3.9
WORKDIR /code
COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
# (1)!
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
```
1. Ici, nous utilisons loption en ligne de commande `--workers` pour définir le nombre de workers à 4.
Voici quelques exemples où cela pourrait avoir du sens :
#### Une application simple { #a-simple-app }
Vous pourriez vouloir un gestionnaire de processus dans le conteneur si votre application est **suffisamment simple** pour pouvoir sexécuter sur un **seul serveur**, pas un cluster.
#### Docker Compose { #docker-compose }
Vous pourriez déployer sur un **seul serveur** (pas un cluster) avec **Docker Compose**, et vous nauriez donc pas un moyen simple de gérer la réplication des conteneurs (avec Docker Compose) tout en préservant le réseau partagé et l**équilibrage de charge**.
Vous pourriez alors vouloir avoir **un seul conteneur** avec un **gestionnaire de processus** démarrant **plusieurs processus worker** à lintérieur.
---
Avec ces informations et ces outils, passez à la section suivante pour tout combiner.
Le point principal est que **rien** de tout cela nest une **règle gravée dans le marbre** que vous devez suivre aveuglément. Vous pouvez utiliser ces idées pour **évaluer votre propre cas dusage** et décider quelle est la meilleure approche pour votre système, en examinant comment gérer les concepts de :
## Cluster en mode Docker Swarm avec Traefik et HTTPS
* Sécurité - HTTPS
* Exécution au démarrage
* Redémarrages
* Réplication (le nombre de processus en cours dexécution)
* Mémoire
* Étapes préalables avant de démarrer
Vous pouvez avoir un cluster en mode Docker Swarm configuré en quelques minutes (environ 20 min) avec un processus Traefik principal gérant HTTPS (y compris l'acquisition et le renouvellement des certificats).
## Mémoire { #memory }
En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir
d'un serveur à 5 USD/mois) et ensuite vous pouvez vous développer autant que vous le souhaitez en ajoutant d'autres serveurs.
Si vous exécutez **un seul processus par conteneur**, vous aurez une quantité de mémoire plus ou moins bien définie, stable, et limitée consommée par chacun de ces conteneurs (plus dun si vous les répliquez).
Pour configurer un cluster en mode Docker Swarm avec Traefik et la gestion de HTTPS, suivez ce guide :
Et ensuite, vous pouvez définir ces mêmes limites et exigences de mémoire dans vos configurations pour votre système de gestion de conteneurs (par exemple dans **Kubernetes**). Ainsi, il pourra **répliquer les conteneurs** sur les **machines disponibles** en tenant compte de la quantité de mémoire nécessaire et de la quantité disponible sur les machines du cluster.
### <a href="https://medium.com/@tiangolo/docker-swarm-mode-and-traefik-for-a-https-cluster-20328dba6232" class="external-link" target="_blank">Docker Swarm Mode et Traefik pour un cluster HTTPS</a>
Si votre application est **simple**, ce ne sera probablement **pas un problème**, et vous pourriez ne pas avoir besoin de spécifier des limites strictes de mémoire. Mais si vous **utilisez beaucoup de mémoire** (par exemple avec des modèles de **machine learning**), vous devriez vérifier la quantité de mémoire consommée et ajuster le **nombre de conteneurs** qui sexécutent sur **chaque machine** (et peut-être ajouter plus de machines à votre cluster).
### Déployer une application FastAPI
Si vous exécutez **plusieurs processus par conteneur**, vous devez vous assurer que le nombre de processus démarrés ne **consomme pas plus de mémoire** que ce qui est disponible.
La façon la plus simple de tout mettre en place, serait d'utiliser les [**Générateurs de projet FastAPI**](../project-generation.md){.internal-link target=_blank}.
## Étapes préalables avant de démarrer et conteneurs { #previous-steps-before-starting-and-containers }
Le génerateur de projet adéquat est conçu pour être intégré à ce cluster Docker Swarm avec Traefik et HTTPS décrit ci-dessus.
Si vous utilisez des conteneurs (par exemple Docker, Kubernetes), alors il existe deux approches principales que vous pouvez utiliser.
Vous pouvez générer un projet en 2 min environ.
### Plusieurs conteneurs { #multiple-containers }
Le projet généré a des instructions pour le déployer et le faire prend 2 min de plus.
Si vous avez **plusieurs conteneurs**, probablement chacun exécutant un **seul processus** (par exemple, dans un cluster **Kubernetes**), vous voudrez probablement avoir un **conteneur séparé** pour effectuer le travail des **étapes préalables** dans un conteneur unique, exécutant un seul processus, **avant** dexécuter les conteneurs workers répliqués.
/// info
Si vous utilisez Kubernetes, ce serait probablement un <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>.
///
Si, dans votre cas dusage, il ny a pas de problème à exécuter ces étapes préalables **plusieurs fois en parallèle** (par exemple si vous nexécutez pas des migrations de base de données, mais vérifiez simplement si la base de données est prête), alors vous pourriez aussi les placer dans chaque conteneur juste avant de démarrer le processus principal.
### Conteneur unique { #single-container }
Si vous avez une configuration simple, avec un **conteneur unique** qui démarre ensuite plusieurs **processus worker** (ou aussi juste un processus), alors vous pourriez exécuter ces étapes préalables dans le même conteneur, juste avant de démarrer le processus avec lapplication.
### Image Docker de base { #base-docker-image }
Il existait une image Docker FastAPI officielle : <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Mais elle est maintenant dépréciée. ⛔️
Vous ne devriez probablement **pas** utiliser cette image Docker de base (ni une autre similaire).
Si vous utilisez **Kubernetes** (ou dautres) et que vous définissez déjà la **réplication** au niveau du cluster, avec plusieurs **conteneurs**. Dans ces cas, il vaut mieux **construire une image à partir de zéro** comme décrit ci-dessus : [Construire une image Docker pour FastAPI](#build-a-docker-image-for-fastapi).
Et si vous devez avoir plusieurs workers, vous pouvez simplement utiliser loption en ligne de commande `--workers`.
/// note | Détails techniques
Limage Docker a été créée à une époque où Uvicorn ne prenait pas en charge la gestion et le redémarrage des workers morts, il était donc nécessaire dutiliser Gunicorn avec Uvicorn, ce qui ajoutait pas mal de complexité, simplement pour que Gunicorn gère et redémarre les processus workers Uvicorn.
Mais maintenant quUvicorn (et la commande `fastapi`) prennent en charge lutilisation de `--workers`, il ny a aucune raison dutiliser une image Docker de base au lieu de construire la vôtre (cest à peu près la même quantité de code 😅).
///
## Déployer limage de conteneur { #deploy-the-container-image }
Après avoir une image de conteneur (Docker), il existe plusieurs façons de la déployer.
Par exemple :
* Avec **Docker Compose** sur un seul serveur
* Avec un cluster **Kubernetes**
* Avec un cluster en mode Docker Swarm
* Avec un autre outil comme Nomad
* Avec un service cloud qui prend votre image de conteneur et la déploie
## Image Docker avec `uv` { #docker-image-with-uv }
Si vous utilisez <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> pour installer et gérer votre projet, vous pouvez suivre leur <a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">guide Docker uv</a>.
## Récapitulatif { #recap }
En utilisant des systèmes de conteneurs (par ex. avec **Docker** et **Kubernetes**), il devient assez simple de gérer tous les **concepts de déploiement** :
* HTTPS
* Exécution au démarrage
* Redémarrages
* Réplication (le nombre de processus en cours dexécution)
* Mémoire
* Étapes préalables avant de démarrer
Dans la plupart des cas, vous ne voudrez probablement pas utiliser une image de base, et vous voudrez plutôt **construire une image de conteneur à partir de zéro** basée sur limage Docker Python officielle.
En prenant soin de l**ordre** des instructions dans le `Dockerfile` et du **cache Docker**, vous pouvez **minimiser les temps de build**, afin de maximiser votre productivité (et déviter lennui). 😎

View File

@@ -1,56 +1,231 @@
# À propos de HTTPS
# À propos de HTTPS { #about-https }
Il est facile de penser que HTTPS peut simplement être "activé" ou non.
Il est facile de supposer que HTTPS est quelque chose qui est simplement « activé » ou non.
Mais c'est beaucoup plus complexe que cela.
Mais c'est bien plus complexe que cela.
/// tip
/// tip | Astuce
Si vous êtes pressé ou si cela ne vous intéresse pas, passez aux sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques.
Si vous êtes pressé ou si cela ne vous intéresse pas, continuez avec les sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques.
///
Pour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez <a href="https://howhttps.works/"
class="external-link" target="_blank">https://howhttps.works/</a>.
Pour **apprendre les bases de HTTPS**, du point de vue d'un utilisateur, consultez <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
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 à garder à l'esprit en pensant à HTTPS :
* Pour le HTTPS, le serveur a besoin de "certificats" générés par une tierce partie.
* Ces certificats sont en fait acquis auprès de la tierce partie, et non "générés".
* Les certificats ont une durée de vie.
* Ils expirent.
* Puis ils doivent être renouvelés et acquis à nouveau auprès de la tierce partie.
* Le cryptage de la connexion se fait au niveau du protocole TCP.
* C'est une couche en dessous de HTTP.
* Donc, le certificat et le traitement du cryptage sont faits avant HTTP.
* TCP ne connaît pas les "domaines", seulement les adresses IP.
* L'information sur le domaine spécifique demandé se trouve dans les données HTTP.
* Les certificats HTTPS "certifient" un certain domaine, mais le protocole et le cryptage se font au niveau TCP, avant de savoir quel domaine est traité.
* Par défaut, cela signifie que vous ne pouvez avoir qu'un seul certificat HTTPS par adresse IP.
* Quelle que soit la taille de votre serveur ou la taille de chacune des applications qu'il contient.
* Il existe cependant une solution à ce problème.
* Il existe une extension du protocole TLS (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée <a
href="https://fr.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr
title="Server Name Indication (indication du nom du serveur)">SNI (indication du nom du serveur)</abbr></a>.
* Cette extension SNI permet à un seul serveur (avec une seule adresse IP) d'avoir plusieurs certificats HTTPS et de servir plusieurs domaines/applications HTTPS.
* Pour que cela fonctionne, un seul composant (programme) fonctionnant sur le serveur, écoutant sur l'adresse IP publique, doit avoir tous les certificats HTTPS du serveur.
* Après avoir obtenu une connexion sécurisée, le protocole de communication est toujours HTTP.
* Le contenu est crypté, même s'il est envoyé avec le protocole HTTP.
* Pour HTTPS, **le serveur** doit **avoir des « certificats »** générés par une **tierce partie**.
* Ces certificats sont en fait **acquis** auprès de la tierce partie, et non « générés ».
* Les certificats ont une **durée de vie**.
* Ils **expirent**.
* Et ensuite ils doivent être **renouvelés**, **acquis à nouveau** auprès de la tierce partie.
* Le chiffrement de la connexion se fait au **niveau TCP**.
* C'est une couche **en dessous de HTTP**.
* Donc, la gestion du **certificat et du chiffrement** est faite **avant HTTP**.
* **TCP ne connaît pas les « domaines »**. Seulement les adresses IP.
* L'information sur le **domaine spécifique** demandé se trouve dans les **données HTTP**.
* Les **certificats HTTPS** « certifient » un **certain domaine**, mais le protocole et le chiffrement se font au niveau TCP, **avant de savoir** quel domaine est traité.
* **Par défaut**, cela signifierait que vous ne pouvez avoir qu'**un seul certificat HTTPS par adresse IP**.
* Peu importe la taille de votre serveur ou à quel point chaque application que vous avez dessus peut être petite.
* Il existe cependant une **solution** à ce problème.
* Il existe une **extension** du protocole **TLS** (celui qui gère le chiffrement au niveau TCP, avant HTTP) appelée **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication - Indication du nom du serveur">SNI</abbr></a>**.
* Cette extension SNI permet à un seul serveur (avec une **seule adresse IP**) d'avoir **plusieurs certificats HTTPS** et de servir **plusieurs domaines/applications HTTPS**.
* Pour que cela fonctionne, un **seul** composant (programme) fonctionnant sur le serveur, écoutant sur l'**adresse IP publique**, doit avoir **tous les certificats HTTPS** du serveur.
* **Après** avoir obtenu une connexion sécurisée, le protocole de communication est **toujours HTTP**.
* Le contenu est **chiffré**, même s'il est envoyé avec le **protocole HTTP**.
Il est courant d'avoir un seul programme/serveur HTTP fonctionnant sur le serveur (la machine, l'hôte, etc.) et
gérant toutes les parties HTTPS : envoyer les requêtes HTTP décryptées à l'application HTTP réelle fonctionnant sur
le même serveur (dans ce cas, l'application **FastAPI**), prendre la réponse HTTP de l'application, la crypter en utilisant le certificat approprié et la renvoyer au client en utilisant HTTPS. Ce serveur est souvent appelé un <a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">Proxy de terminaison TLS</a>.
Il est courant d'avoir **un seul programme/serveur HTTP** fonctionnant sur le serveur (la machine, l'hôte, etc.) et **gérant toutes les parties HTTPS** : recevoir les **requêtes HTTPS chiffrées**, envoyer les **requêtes HTTP déchiffrées** à l'application HTTP réelle fonctionnant sur le même serveur (l'application **FastAPI**, dans ce cas), prendre la **réponse HTTP** de l'application, la **chiffrer** en utilisant le **certificat HTTPS** approprié et la renvoyer au client en utilisant **HTTPS**. Ce serveur est souvent appelé un **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">Proxy de terminaison TLS</a>**.
## Let's Encrypt
Certaines des options que vous pouvez utiliser comme Proxy de terminaison TLS sont :
Avant Let's Encrypt, ces certificats HTTPS étaient vendus par des tiers de confiance.
* Traefik (qui peut aussi gérer les renouvellements de certificats)
* Caddy (qui peut aussi gérer les renouvellements de certificats)
* Nginx
* HAProxy
## Let's Encrypt { #lets-encrypt }
Avant Let's Encrypt, ces **certificats HTTPS** étaient vendus par des tiers de confiance.
Le processus d'acquisition d'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasses et les certificats étaient assez chers.
Mais ensuite, <a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a> a été créé.
Mais ensuite **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>** a été créé.
Il s'agit d'un projet de la Fondation Linux. Il fournit des certificats HTTPS gratuitement. De manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la sécurité est en fait meilleure en raison de leur durée de vie réduite.
Il s'agit d'un projet de la Linux Foundation. Il fournit des **certificats HTTPS gratuitement**, de manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard, et ont une durée de vie courte (environ 3 mois), de sorte que la **sécurité est en fait meilleure** en raison de leur durée de vie réduite.
Les domaines sont vérifiés de manière sécurisée et les certificats sont générés automatiquement. Cela permet également d'automatiser le renouvellement de ces certificats.
L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un HTTPS sécurisé, gratuitement et pour toujours.
L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un **HTTPS sécurisé, gratuitement, pour toujours**.
## HTTPS pour les développeurs { #https-for-developers }
Voici un exemple de ce à quoi une API HTTPS pourrait ressembler, étape par étape, en faisant attention principalement aux idées importantes pour les développeurs.
### Nom de domaine { #domain-name }
Cela commencerait probablement par le fait que vous **acquérez** un **nom de domaine**. Ensuite, vous le configureriez dans un serveur DNS (éventuellement votre même fournisseur cloud).
Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une adresse IP publique <abbr title="That doesn't change - Qui ne change pas">fixed</abbr>.
Dans le(s) serveur(s) DNS vous configureriez un enregistrement (un « `A record` ») pour faire pointer **votre domaine** vers l'**adresse IP publique de votre serveur**.
Vous feriez probablement cela une seule fois, la première fois, lorsque vous mettez tout en place.
/// tip | Astuce
Cette partie « nom de domaine » se situe bien avant HTTPS, mais comme tout dépend du domaine et de l'adresse IP, cela vaut la peine de le mentionner ici.
///
### DNS { #dns }
Maintenant, concentrons-nous sur toutes les parties réellement liées à HTTPS.
D'abord, le navigateur vérifierait auprès des **serveurs DNS** quelle est l'**IP du domaine**, dans ce cas, `someapp.example.com`.
Les serveurs DNS diraient au navigateur d'utiliser une **adresse IP** spécifique. Ce serait l'adresse IP publique utilisée par votre serveur, que vous avez configurée dans les serveurs DNS.
<img src="/img/deployment/https/https01.drawio.svg">
### Début du handshake TLS { #tls-handshake-start }
Le navigateur communiquerait ensuite avec cette adresse IP sur le **port 443** (le port HTTPS).
La première partie de la communication consiste simplement à établir la connexion entre le client et le serveur et à décider des clés cryptographiques qu'ils utiliseront, etc.
<img src="/img/deployment/https/https02.drawio.svg">
Cette interaction entre le client et le serveur pour établir la connexion TLS s'appelle le **handshake TLS**.
### TLS avec l'extension SNI { #tls-with-sni-extension }
**Un seul process** sur le serveur peut écouter sur un **port** spécifique sur une **adresse IP** spécifique. Il peut y avoir d'autres process écoutant sur d'autres ports sur la même adresse IP, mais un seul pour chaque combinaison d'adresse IP et de port.
TLS (HTTPS) utilise par défaut le port spécifique `443`. Donc c'est ce port dont nous avons besoin.
Comme un seul process peut écouter sur ce port, le process qui le ferait serait le **Proxy de terminaison TLS**.
Le Proxy de terminaison TLS aurait accès à un ou plusieurs **certificats TLS** (certificats HTTPS).
En utilisant l'**extension SNI** mentionnée ci-dessus, le Proxy de terminaison TLS vérifierait lequel des certificats TLS (HTTPS) disponibles il doit utiliser pour cette connexion, en utilisant celui qui correspond au domaine attendu par le client.
Dans ce cas, il utiliserait le certificat pour `someapp.example.com`.
<img src="/img/deployment/https/https03.drawio.svg">
Le client **fait déjà confiance** à l'entité qui a généré ce certificat TLS (dans ce cas Let's Encrypt, mais nous verrons cela plus tard), il peut donc **vérifier** que le certificat est valide.
Ensuite, en utilisant le certificat, le client et le Proxy de terminaison TLS **décident comment chiffrer** le reste de la **communication TCP**. Cela complète la partie **Handshake TLS**.
Après cela, le client et le serveur ont une **connexion TCP chiffrée**, c'est ce que fournit TLS. Et ensuite ils peuvent utiliser cette connexion pour démarrer la véritable **communication HTTP**.
Et c'est ce qu'est **HTTPS**, c'est simplement du **HTTP** à l'intérieur d'une **connexion TLS sécurisée** au lieu d'une connexion TCP pure (non chiffrée).
/// tip | Astuce
Notez que le chiffrement de la communication se produit au **niveau TCP**, pas au niveau HTTP.
///
### Requête HTTPS { #https-request }
Maintenant que le client et le serveur (spécifiquement le navigateur et le Proxy de terminaison TLS) ont une **connexion TCP chiffrée**, ils peuvent démarrer la **communication HTTP**.
Ainsi, le client envoie une **requête HTTPS**. Il s'agit simplement d'une requête HTTP via une connexion TLS chiffrée.
<img src="/img/deployment/https/https04.drawio.svg">
### Déchiffrer la requête { #decrypt-the-request }
Le Proxy de terminaison TLS utiliserait le chiffrement convenu pour **déchiffrer la requête**, et transmettrait la **requête HTTP en clair (déchiffrée)** au process exécutant l'application (par exemple un process avec Uvicorn exécutant l'application FastAPI).
<img src="/img/deployment/https/https05.drawio.svg">
### Réponse HTTP { #http-response }
L'application traiterait la requête et enverrait une **réponse HTTP en clair (non chiffrée)** au Proxy de terminaison TLS.
<img src="/img/deployment/https/https06.drawio.svg">
### Réponse HTTPS { #https-response }
Le Proxy de terminaison TLS **chiffrerait ensuite la réponse** en utilisant la cryptographie convenue auparavant (qui a commencé avec le certificat pour `someapp.example.com`), et la renverrait au navigateur.
Ensuite, le navigateur vérifierait que la réponse est valide et chiffrée avec la bonne clé cryptographique, etc. Il **déchiffrerait ensuite la réponse** et la traiterait.
<img src="/img/deployment/https/https07.drawio.svg">
Le client (navigateur) saura que la réponse provient du bon serveur parce qu'il utilise la cryptographie qu'ils ont convenue en utilisant le **certificat HTTPS** auparavant.
### Applications multiples { #multiple-applications }
Sur le même serveur (ou les mêmes serveurs), il pourrait y avoir **plusieurs applications**, par exemple d'autres programmes d'API ou une base de données.
Un seul process peut gérer la combinaison spécifique d'IP et de port (le Proxy de terminaison TLS dans notre exemple) mais les autres applications/process peuvent également s'exécuter sur le(s) serveur(s), tant qu'ils n'essaient pas d'utiliser la même **combinaison d'IP publique et de port**.
<img src="/img/deployment/https/https08.drawio.svg">
De cette façon, le Proxy de terminaison TLS pourrait gérer HTTPS et les certificats pour **plusieurs domaines**, pour plusieurs applications, puis transmettre les requêtes à la bonne application dans chaque cas.
### Renouvellement des certificats { #certificate-renewal }
À un moment donné dans le futur, chaque certificat **expirerait** (environ 3 mois après son acquisition).
Et ensuite, il y aurait un autre programme (dans certains cas c'est un autre programme, dans certains cas cela pourrait être le même Proxy de terminaison TLS) qui parlerait à Let's Encrypt, et renouvellerait le(s) certificat(s).
<img src="/img/deployment/https/https.drawio.svg">
Les **certificats TLS** sont **associés à un nom de domaine**, pas à une adresse IP.
Ainsi, pour renouveler les certificats, le programme de renouvellement doit **prouver** à l'autorité (Let's Encrypt) qu'il **« possède » et contrôle effectivement ce domaine**.
Pour ce faire, et pour répondre à différents besoins applicatifs, il existe plusieurs façons de procéder. Voici quelques méthodes populaires :
* **Modifier certains enregistrements DNS**.
* Pour cela, le programme de renouvellement doit prendre en charge les API du fournisseur DNS, donc, selon le fournisseur DNS que vous utilisez, cela peut ou non être une option.
* **S'exécuter comme un serveur** (au moins pendant le processus d'acquisition du certificat) sur l'adresse IP publique associée au domaine.
* Comme nous l'avons dit ci-dessus, un seul process peut écouter sur une IP et un port spécifiques.
* C'est l'une des raisons pour lesquelles il est très utile que le même Proxy de terminaison TLS s'occupe aussi du processus de renouvellement des certificats.
* Sinon, vous devrez peut-être arrêter momentanément le Proxy de terminaison TLS, démarrer le programme de renouvellement pour acquérir les certificats, puis les configurer avec le Proxy de terminaison TLS, et ensuite redémarrer le Proxy de terminaison TLS. Ce n'est pas idéal, car votre/vos app(s) ne seront pas disponibles pendant le temps où le Proxy de terminaison TLS est arrêté.
Tout ce processus de renouvellement, tout en continuant de servir l'app, est l'une des principales raisons pour lesquelles vous voulez avoir un **système séparé pour gérer HTTPS** avec un Proxy de terminaison TLS au lieu de simplement utiliser les certificats TLS directement avec le serveur d'application (par ex. Uvicorn).
## En-têtes de proxy transférés { #proxy-forwarded-headers }
Lorsque vous utilisez un proxy pour gérer HTTPS, votre **serveur d'application** (par exemple Uvicorn via la FastAPI CLI) ne sait rien du processus HTTPS, il communique en HTTP en clair avec le **Proxy de terminaison TLS**.
Ce **proxy** définirait normalement certains en-têtes HTTP à la volée avant de transmettre la requête au **serveur d'application**, pour indiquer au serveur d'application que la requête est **transférée** par le proxy.
/// note | Détails techniques
Les en-têtes du proxy sont :
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
///
Néanmoins, comme le **serveur d'application** ne sait pas qu'il est derrière un **proxy** de confiance, par défaut, il ne ferait pas confiance à ces en-têtes.
Mais vous pouvez configurer le **serveur d'application** pour faire confiance aux en-têtes *forwarded* envoyés par le **proxy**. Si vous utilisez la FastAPI CLI, vous pouvez utiliser l'*option CLI* `--forwarded-allow-ips` pour lui indiquer depuis quelles IP il doit faire confiance à ces en-têtes *forwarded*.
Par exemple, si le **serveur d'application** ne reçoit la communication que du **proxy** de confiance, vous pouvez le définir sur `--forwarded-allow-ips="*"` pour lui faire confiance pour toutes les IP entrantes, car il ne recevra des requêtes que depuis l'adresse IP utilisée par le **proxy**.
De cette façon, l'application serait capable de connaître sa propre URL publique, si elle utilise HTTPS, le domaine, etc.
Ce serait utile par exemple pour gérer correctement les redirections.
/// tip | Astuce
Vous pouvez en apprendre davantage à ce sujet dans la documentation pour [Derrière un proxy - Activer les en-têtes Proxy Forwarded](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank}
///
## Récapitulatif { #recap }
Avoir **HTTPS** est très important, et assez **critique** dans la plupart des cas. La plupart des efforts que vous, en tant que développeur, devez fournir autour de HTTPS consistent simplement à **comprendre ces concepts** et comment ils fonctionnent.
Mais une fois que vous connaissez les informations de base sur **HTTPS pour les développeurs** vous pouvez facilement combiner et configurer différents outils pour vous aider à tout gérer de manière simple.
Dans certains des prochains chapitres, je vais vous montrer plusieurs exemples concrets de configuration de **HTTPS** pour des applications **FastAPI**. 🔒

View File

@@ -1,28 +1,23 @@
# Déploiement
# Déploiement { #deployment }
Le déploiement d'une application **FastAPI** est relativement simple.
## Que signifie le déploiement
## Que signifie le déploiement { #what-does-deployment-mean }
**Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les
utilisateurs**.
**Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les utilisateurs**.
Pour une **API Web**, cela implique normalement de la placer sur une **machine distante**, avec un **programme serveur**
qui offre de bonnes performances, une bonne stabilité, _etc._, afin que vos **utilisateurs** puissent **accéder** à
l'application efficacement et sans interruption ni problème.
Pour une **API Web**, cela implique normalement de la placer sur une **machine distante**, avec un **programme serveur** qui offre de bonnes performances, une bonne stabilité, etc, afin que vos **utilisateurs** puissent **accéder** à l'application efficacement et sans interruption ni problème.
Ceci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser
et de le réparer, d'arrêter et de redémarrer le serveur de développement, _etc._
Ceci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser et de le réparer, d'arrêter et de redémarrer le serveur de développement, etc.
## Stratégies de déploiement
## Stratégies de déploiement { #deployment-strategies }
Il existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous
utilisez.
Il existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous utilisez.
Vous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service
cloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles.
Vous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service cloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles.
Je vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement
d'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web).
Par exemple, nous, l'équipe derrière FastAPI, avons créé <a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a>, afin de rendre le déploiement d'apps FastAPI sur le cloud aussi rationalisé que possible, avec la même expérience développeur que celle du travail avec FastAPI.
Je vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement d'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web).
Vous verrez plus de détails à avoir en tête et certaines des techniques pour le faire dans les sections suivantes. ✨

View File

@@ -1,85 +1,78 @@
# À propos des versions de FastAPI
# À propos des versions de FastAPI { #about-fastapi-versions }
**FastAPI** est déjà utilisé en production dans de nombreuses applications et systèmes. Et la couverture de test est maintenue à 100 %. Mais son développement est toujours aussi rapide.
**FastAPI** est déjà utilisé en production dans de nombreuses applications et systèmes. Et la couverture de test est maintenue à 100 %. Mais son développement avance toujours rapidement.
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code est
amélioré continuellement.
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement, et le code continue de saméliorer en continu.
C'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version peut potentiellement
recevoir des changements non rétrocompatibles. Cela suit les conventions de <a href="https://semver.org/" class="external-link"
target="_blank">versionnage sémantique</a>.
Cest pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version peut potentiellement introduire des changements incompatibles. Cela suit les conventions du <a href="https://semver.org/" class="external-link" target="_blank">Semantic Versioning</a>.
Vous pouvez créer des applications de production avec **FastAPI** dès maintenant (et vous le faites probablement depuis un certain temps), vous devez juste vous assurer que vous utilisez une version qui fonctionne correctement avec le reste de votre code.
Vous pouvez créer des applications de production avec **FastAPI** dès maintenant (et vous le faites probablement depuis un certain temps), vous devez simplement vous assurer que vous utilisez une version qui fonctionne correctement avec le reste de votre code.
## Épinglez votre version de `fastapi`
## Épinglez votre version de `fastapi` { #pin-your-fastapi-version }
Tout d'abord il faut "épingler" la version de **FastAPI** que vous utilisez à la dernière version dont vous savez
qu'elle fonctionne correctement pour votre application.
La première chose que vous devez faire est d« épingler » la version de **FastAPI** que vous utilisez à la version spécifique la plus récente dont vous savez quelle fonctionne correctement pour votre application.
Par exemple, disons que vous utilisez la version `0.45.0` dans votre application.
Par exemple, disons que vous utilisez la version `0.112.0` dans votre app.
Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec :
Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec :
```txt
fastapi==0.45.0
fastapi[standard]==0.112.0
```
ce qui signifierait que vous utiliseriez exactement la version `0.45.0`.
cela signifierait que vous utiliseriez exactement la version `0.112.0`.
Ou vous pourriez aussi l'épingler avec :
Ou vous pourriez aussi lépingler avec :
```txt
fastapi[standard]>=0.112.0,<0.113.0
```
cela signifierait que vous utiliseriez les versions `0.112.0` ou supérieures, mais inférieures à `0.113.0`, par exemple, une version `0.112.2` serait toujours acceptée.
Si vous utilisez un autre outil pour gérer vos installations, comme `uv`, Poetry, Pipenv, ou autres, ils ont tous un moyen que vous pouvez utiliser pour définir des versions spécifiques pour vos paquets.
## Versions disponibles { #available-versions }
Vous pouvez consulter les versions disponibles (p. ex. pour vérifier quelle est la dernière version actuelle) dans les [Notes de version](../release-notes.md){.internal-link target=_blank}.
## À propos des versions { #about-versions }
En suivant les conventions du Semantic Versioning, toute version inférieure à `1.0.0` peut potentiellement ajouter des changements incompatibles.
FastAPI suit également la convention selon laquelle tout changement de version « PATCH » concerne des corrections de bogues et des changements compatibles.
/// tip | Astuce
Le « PATCH » est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.
///
Ainsi, vous devriez pouvoir épingler une version comme suit :
```txt
fastapi>=0.45.0,<0.46.0
```
cela signifierait que vous utiliseriez les versions `0.45.0` ou supérieures, mais inférieures à `0.46.0`, par exemple, une version `0.45.2` serait toujours acceptée.
Si vous utilisez un autre outil pour gérer vos installations, comme Poetry, Pipenv, ou autres, ils ont tous un moyen que vous pouvez utiliser pour définir des versions spécifiques pour vos paquets.
## Versions disponibles
Vous pouvez consulter les versions disponibles (par exemple, pour vérifier quelle est la dernière version en date) dans les [Notes de version](../release-notes.md){.internal-link target=_blank}.
## À propos des versions
Suivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter
des changements non rétrocompatibles.
FastAPI suit également la convention que tout changement de version "PATCH" est pour des corrections de bogues et
des changements rétrocompatibles.
Les changements incompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions « MINOR ».
/// tip | Astuce
Le "PATCH" est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.
Le « MINOR » est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
///
Donc, vous devriez être capable d'épingler une version comme suit :
## Mettre à niveau les versions de FastAPI { #upgrading-the-fastapi-versions }
```txt
fastapi>=0.45.0,<0.46.0
```
Vous devez ajouter des tests pour votre app.
Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions "MINOR".
Avec **FastAPI**, cest très facile (grâce à Starlette), consultez la documentation : [Testing](../tutorial/testing.md){.internal-link target=_blank}
/// tip | Astuce
Après avoir des tests, vous pouvez alors mettre à niveau la version de **FastAPI** vers une version plus récente, et vous assurer que tout votre code fonctionne correctement en exécutant vos tests.
Le "MINOR" est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
Si tout fonctionne, ou après avoir effectué les changements nécessaires, et que tous vos tests passent, vous pouvez alors épingler votre `fastapi` à cette nouvelle version récente.
///
## Mise à jour des versions FastAPI
Vous devriez tester votre application.
Avec **FastAPI** c'est très facile (merci à Starlette), consultez la documentation : [Testing](../tutorial/testing.md){.internal-link target=_blank}
Après avoir effectué des tests, vous pouvez mettre à jour la version **FastAPI** vers une version plus récente, et vous assurer que tout votre code fonctionne correctement en exécutant vos tests.
Si tout fonctionne, ou après avoir fait les changements nécessaires, et que tous vos tests passent, vous pouvez
épingler votre version de `fastapi` à cette nouvelle version récente.
## À propos de Starlette
## À propos de Starlette { #about-starlette }
Vous ne devriez pas épingler la version de `starlette`.
@@ -87,15 +80,14 @@ Différentes versions de **FastAPI** utiliseront une version spécifique plus r
Ainsi, vous pouvez simplement laisser **FastAPI** utiliser la bonne version de Starlette.
## À propos de Pydantic
## À propos de Pydantic { #about-pydantic }
Pydantic inclut des tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus
de `1.0.0`) sont toujours compatibles avec **FastAPI**.
Pydantic inclut les tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus de `1.0.0`) sont toujours compatibles avec FastAPI.
Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous et inférieure à `2.0.0`.
Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous.
Par exemple :
Par exemple :
```txt
pydantic>=1.2.0,<2.0.0
pydantic>=2.7.0,<3.0.0
```

View File

@@ -1,11 +1,11 @@
# FastAPI
# FastAPI { #fastapi }
<style>
.md-content .md-typeset h1 { display: none; }
</style>
<p align="center">
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
<a href="https://fastapi.tiangolo.com/fr"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
</p>
<p align="center">
<em>Framework FastAPI, haute performance, facile à apprendre, rapide à coder, prêt pour la production</em>
@@ -27,7 +27,7 @@
---
**Documentation** : <a href="https://fastapi.tiangolo.com" target="_blank">https://fastapi.tiangolo.com</a>
**Documentation** : <a href="https://fastapi.tiangolo.com/fr" target="_blank">https://fastapi.tiangolo.com</a>
**Code Source** : <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
@@ -41,120 +41,124 @@ Les principales fonctionnalités sont :
* **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 IDE. <abbr title="également connu sous le nom d'auto-complétion, autocomplétion, IntelliSense">Complétion</abbr> complète. Moins de temps passé à déboguer.
* **Facile** : Conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire la documentation.
* **Facile** : Conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire les documents.
* **Concis** : Diminue la duplication de code. De nombreuses fonctionnalités liées à la déclaration de chaque paramètre. Moins de bugs.
* **Robuste** : Obtenez un code prêt pour la production. Avec une documentation interactive automatique.
* **Basé sur des normes** : Basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (précédemment connu sous le nom de Swagger) et <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
<small>* estimation basée sur des tests d'une équipe de développement interne, construisant des applications de production.</small>
## Sponsors
## Sponsors { #sponsors }
<!-- sponsors -->
{% if sponsors %}
### Sponsor Keystone { #keystone-sponsor }
{% for sponsor in sponsors.keystone -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor -%}
### Sponsors Gold et Silver { #gold-and-silver-sponsors }
{% for sponsor in sponsors.gold -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor -%}
{%- for sponsor in sponsors.silver -%}
<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
{% endfor %}
{% endif %}
<!-- /sponsors -->
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
<a href="https://fastapi.tiangolo.com/fr/fastapi-people/#sponsors" class="external-link" target="_blank">Autres sponsors</a>
## Opinions
## Opinions { #opinions }
"_[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux seront intégrés dans le coeur de **Windows** et dans certains produits **Office**._"
"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
---
"_Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_"
"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin et Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
---
"_**Netflix** a le plaisir d'annoncer la sortie en open-source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_"
"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
---
"_Je suis très enthousiaste à propos de **FastAPI**. C'est un bonheur !_"
"_Im over the moon excited about **FastAPI**. Its so fun!_"
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong>Auteur du podcast <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a></strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> podcast host</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
"_Honnêtement, ce que vous avez construit a l'air super solide et élégant. A bien des égards, c'est comme ça que je voulais que **Hug** soit - c'est vraiment inspirant de voir quelqu'un construire ça._"
"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong> Créateur de <a href="https://github.com/hugapi/hug" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creator</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
"_Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et à apprendre [...]_"
"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
"_Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_"
"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>Fondateurs de <a href="https://explosion.ai" target="_blank">Explosion AI</a> - Créateurs de <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> founders - <a href="https://spacy.io" target="_blank">spaCy</a> creators</strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
---
"_Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **bien conçu**, **simple à utiliser** et **très évolutif**. Il est devenu un **composant clé** dans notre stratégie de développement API first et il est à l'origine de nombreux automatismes et services tels que notre ingénieur virtuel TAC._"
"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our 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/" target="_blank"><small>(ref)</small></a></div>
---
## **Typer**, le FastAPI des <abbr title="Command Line Interface">CLI</abbr>
## Mini-documentaire FastAPI { #fastapi-mini-documentary }
Il existe un <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini-documentaire FastAPI</a> sorti à la fin de 2025, vous pouvez le regarder en ligne :
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
## **Typer**, le FastAPI des <abbr title="Command Line Interface">CLI</abbr> { #typer-the-fastapi-of-clis }
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
Si vous souhaitez construire une application <abbr title="Command Line Interface">CLI</abbr> utilisable dans un terminal au lieu d'une API web, regardez <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
Si vous construisez une application <abbr title="Command Line Interface">CLI</abbr> utilisable dans un terminal au lieu d'une API web, regardez <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des <abbr title="Command Line Interface">CLI</abbr>**. ⌨️ 🚀
## Prérequis
## Prérequis { #requirements }
FastAPI repose sur les épaules de géants :
* <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> pour les parties web.
* <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> pour les parties données.
## Installation
## Installation { #installation }
Créez et activez un <a href="https://fastapi.tiangolo.com/fr/virtual-environments/" class="external-link" target="_blank">environnement virtuel</a> puis installez FastAPI :
<div class="termy">
```console
$ pip install fastapi
$ pip install "fastapi[standard]"
---> 100%
```
</div>
Vous aurez également besoin d'un serveur ASGI pour la production tel que <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a> ou <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>.
**Remarque** : vous devez mettre `"fastapi[standard]"` entre guillemets pour vous assurer que cela fonctionne dans tous les terminaux.
<div class="termy">
## Exemple { #example }
```console
$ pip install "uvicorn[standard]"
### Créez-le { #create-it }
---> 100%
```
</div>
## Exemple
### Créez
* Créez un fichier `main.py` avec :
Créez un fichier `main.py` avec :
```Python
from typing import Union
@@ -175,7 +179,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
```
<details markdown="1">
<summary>Ou utilisez <code>async def</code> ...</summary>
<summary>Ou utilisez <code>async def</code>...</summary>
Si votre code utilise `async` / `await`, utilisez `async def` :
@@ -197,24 +201,37 @@ async def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
**Note**
**Remarque** :
Si vous n'êtes pas familier avec cette notion, consultez la section _"Vous êtes pressés ?"_ à propos de <a href="https://fastapi.tiangolo.com/fr/async/#vous-etes-presses" target="_blank">`async` et `await` dans la documentation</a>.
Si vous ne savez pas, consultez la section _« In a hurry? »_ à propos de <a href="https://fastapi.tiangolo.com/fr/async/#in-a-hurry" target="_blank">`async` et `await` dans les documents</a>.
</details>
### Lancez
### Lancez-le { #run-it }
Lancez le serveur avec :
<div class="termy">
```console
$ uvicorn main:app --reload
$ fastapi dev main.py
╭────────── FastAPI CLI - Development mode ───────────╮
│ │
│ Serving at: http://127.0.0.1:8000 │
│ │
│ API docs: http://127.0.0.1:8000/docs │
│ │
│ Running in development mode, for production use: │
│ │
│ fastapi run │
│ │
╰─────────────────────────────────────────────────────╯
INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [28720]
INFO: Started server process [28722]
INFO: Started reloader process [2248755] using WatchFiles
INFO: Started server process [2248757]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
@@ -222,21 +239,21 @@ INFO: Application startup complete.
</div>
<details markdown="1">
<summary>À propos de la commande <code>uvicorn main:app --reload</code> ...</summary>
<summary>À propos de la commande <code>fastapi dev main.py</code>...</summary>
La commande `uvicorn main:app` fait référence à :
La commande `fastapi dev` lit votre fichier `main.py`, détecte l'app **FastAPI** qu'il contient et démarre un serveur en utilisant <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>.
* `main` : le fichier `main.py` (le "module" Python).
* `app` : l'objet créé à l'intérieur de `main.py` avec la ligne `app = FastAPI()`.
* `--reload` : fait redémarrer le serveur après des changements de code. À n'utiliser que pour le développement.
Par défaut, `fastapi dev` démarre avec l'auto-reload activé pour le développement local.
Vous pouvez en savoir plus dans <a href="https://fastapi.tiangolo.com/fr/fastapi-cli/" target="_blank">la documentation de FastAPI CLI</a>.
</details>
### Vérifiez
### Vérifiez-le { #check-it }
Ouvrez votre navigateur à l'adresse <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
Vous obtenez alors cette réponse <abbr title="JavaScript Object Notation">JSON</abbr> :
Vous verrez la réponse JSON comme suit :
```JSON
{"item_id": 5, "q": "somequery"}
@@ -246,10 +263,10 @@ Vous venez de créer une API qui :
* Reçoit les requêtes HTTP pour les _chemins_ `/` et `/items/{item_id}`.
* Les deux _chemins_ acceptent des <em>opérations</em> `GET` (également connu sous le nom de _méthodes_ HTTP).
* Le _chemin_ `/items/{item_id}` a un _<abbr title="en anglais : path parameter">paramètre</abbr>_ `item_id` qui doit être un `int`.
* Le _chemin_ `/items/{item_id}` a un _<abbr title="en anglais : query param">paramètre de requête</abbr>_ optionnel `q` de type `str`.
* Le _chemin_ `/items/{item_id}` a un paramètre de chemin `item_id` qui doit être un `int`.
* Le _chemin_ `/items/{item_id}` a un paramètre de requête optionnel `q` de type `str`.
### Documentation API interactive
### Documentation API interactive { #interactive-api-docs }
Maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
@@ -257,17 +274,17 @@ Vous verrez la documentation interactive automatique de l'API (fournie par <a hr
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Documentation API alternative
### Documentation API alternative { #alternative-api-docs }
Et maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Vous verrez la documentation interactive automatique de l'API (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Exemple plus poussé
## Mettre à niveau l'exemple { #example-upgrade }
Maintenant, modifiez le fichier `main.py` pour recevoir <abbr title="en anglais : body">le corps</abbr> d'une requête `PUT`.
Maintenant, modifiez le fichier `main.py` pour recevoir un corps à partir d'une requête `PUT`.
Déclarez ce corps en utilisant les types Python standards, grâce à Pydantic.
@@ -301,35 +318,35 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
Le serveur se recharge normalement automatiquement (car vous avez pensé à `--reload` dans la commande `uvicorn` ci-dessus).
Le serveur `fastapi dev` devrait se recharger automatiquement.
### Plus loin avec la documentation API interactive
### Mettre à niveau la documentation API interactive { #interactive-api-docs-upgrade }
Maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps de la requête :
* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps :
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* Cliquez sur le bouton "Try it out", il vous permet de renseigner les paramètres et d'interagir directement avec l'API :
* Cliquez sur le bouton « Try it out », il vous permet de renseigner les paramètres et d'interagir directement avec l'API :
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
* Cliquez ensuite sur le bouton "Execute", l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran :
* Cliquez ensuite sur le bouton « Execute », l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran :
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Plus loin avec la documentation API alternative
### Mettre à niveau la documentation API alternative { #alternative-api-docs-upgrade }
Et maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
* La documentation alternative reflétera également le nouveau paramètre de requête et le nouveau corps :
* La documentation alternative reflétera également le nouveau paramètre de requête et le corps :
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### En résumé
### En résumé { #recap }
En résumé, vous déclarez **une fois** les types de paramètres, <abbr title="en anglais : body">le corps</abbr> de la requête, etc. en tant que paramètres de fonction.
En résumé, vous déclarez **une fois** les types de paramètres, le corps, etc. en tant que paramètres de fonction.
Vous faites cela avec les types Python standard modernes.
@@ -351,48 +368,48 @@ item: Item
... et avec cette déclaration unique, vous obtenez :
* Une assistance dans votre IDE, notamment :
* Une assistance dans votre éditeur, notamment :
* la complétion.
* la vérification des types.
* La validation des données :
* des erreurs automatiques et claires lorsque les données ne sont pas valides.
* une validation même pour les objets <abbr title="JavaScript Object Notation">JSON</abbr> profondément imbriqués.
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Une conversion</abbr> des données d'entrée : venant du réseau et allant vers les données et types de Python, permettant de lire :
* le <abbr title="JavaScript Object Notation">JSON</abbr>.
* <abbr title="en anglais : path parameters">les paramètres du chemin</abbr>.
* <abbr title="en anglais : query parameters">les paramètres de la requête</abbr>.
* les cookies.
* <abbr title="en anglais : headers">les en-têtes</abbr>.
* <abbr title="en anglais : forms">les formulaires</abbr>.
* <abbr title="en anglais : files">les fichiers</abbr>.
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">La conversion</abbr> des données de sortie : conversion des données et types Python en données réseau (au format <abbr title="JavaScript Object Notation">JSON</abbr>), permettant de convertir :
* les types Python (`str`, `int`, `float`, `bool`, `list`, etc).
* une validation même pour les objets JSON profondément imbriqués.
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> des données d'entrée : venant du réseau et allant vers les données et types de Python. Lecture de :
* JSON.
* Les paramètres de chemin.
* Les paramètres de requête.
* Les cookies.
* Les en-têtes.
* Les formulaires.
* Les fichiers.
* <abbr title="also known as: serialization, parsing, marshalling">Conversion</abbr> des données de sortie : conversion des données et types Python en données réseau (au format JSON) :
* Convertir les types Python (`str`, `int`, `float`, `bool`, `list`, etc).
* les objets `datetime`.
* les objets `UUID`.
* les modèles de base de données.
* ... et beaucoup plus.
* La documentation API interactive automatique, avec 2 interfaces utilisateur au choix :
* La documentation API interactive automatique, incluant 2 interfaces utilisateur alternatives :
* Swagger UI.
* ReDoc.
---
Pour revenir à l'exemple de code précédent, **FastAPI** permet de :
Pour revenir à l'exemple de code précédent, **FastAPI** va :
* Valider que `item_id` existe dans le chemin des requêtes `GET` et `PUT`.
* Valider que `item_id` est de type `int` pour les requêtes `GET` et `PUT`.
* Si ce n'est pas le cas, le client voit une erreur utile et claire.
* Vérifier qu'il existe un paramètre de requête facultatif nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.
* Puisque le paramètre `q` est déclaré avec `= None`, il est facultatif.
* Sans le `None`, il serait nécessaire (comme l'est <abbr title="en anglais : body">le corps</abbr> de la requête dans le cas du `PUT`).
* Pour les requêtes `PUT` vers `/items/{item_id}`, de lire <abbr title="en anglais : body">le corps</abbr> en <abbr title="JavaScript Object Notation">JSON</abbr> :
* Si ce n'est pas le cas, le client verra une erreur utile et claire.
* Vérifier qu'il existe un paramètre de requête optionnel nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.
* Puisque le paramètre `q` est déclaré avec `= None`, il est optionnel.
* Sans le `None`, il serait nécessaire (comme l'est le corps dans le cas du `PUT`).
* Pour les requêtes `PUT` vers `/items/{item_id}`, lire le corps en JSON :
* Vérifier qu'il a un attribut obligatoire `name` qui devrait être un `str`.
* Vérifier qu'il a un attribut obligatoire `prix` qui doit être un `float`.
* Vérifier qu'il a un attribut obligatoire `price` qui doit être un `float`.
* Vérifier qu'il a un attribut facultatif `is_offer`, qui devrait être un `bool`, s'il est présent.
* Tout cela fonctionnerait également pour les objets <abbr title="JavaScript Object Notation">JSON</abbr> profondément imbriqués.
* Convertir de et vers <abbr title="JavaScript Object Notation">JSON</abbr> automatiquement.
* Tout cela fonctionnerait également pour les objets JSON profondément imbriqués.
* Convertir automatiquement depuis et vers JSON.
* Documenter tout avec OpenAPI, qui peut être utilisé par :
* Les systèmes de documentation interactifs.
* Les systèmes de documentation interactive.
* Les systèmes de génération automatique de code client, pour de nombreuses langues.
* Fournir directement 2 interfaces web de documentation interactive.
@@ -420,53 +437,129 @@ Essayez de changer la ligne contenant :
... et voyez comment votre éditeur complétera automatiquement les attributs et connaîtra leurs types :
![compatibilité IDE](https://fastapi.tiangolo.com/img/vscode-completion.png)
![compatibilité éditeur](https://fastapi.tiangolo.com/img/vscode-completion.png)
Pour un exemple plus complet comprenant plus de fonctionnalités, voir le <a href="https://fastapi.tiangolo.com/fr/tutorial/">Tutoriel - Guide utilisateur</a>.
**Spoiler alert** : le tutoriel - guide utilisateur inclut :
* Déclaration de **paramètres** provenant d'autres endroits différents comme : **<abbr title="en anglais : headers">en-têtes</abbr>.**, **cookies**, **champs de formulaire** et **fichiers**.
* L'utilisation de **contraintes de validation** comme `maximum_length` ou `regex`.
* Un **<abbr title="aussi connu sous le nom de composants, ressources, fournisseurs, services, injectables">système d'injection de dépendance </abbr>** très puissant et facile à utiliser .
* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec les **<abbr title="en anglais : JWT tokens">jetons <abbr title="JSON Web Tokens">JWT</abbr></abbr>** et l'authentification **HTTP Basic**.
* Des techniques plus avancées (mais tout aussi faciles) pour déclarer les **modèles <abbr title="JavaScript Object Notation">JSON</abbr> profondément imbriqués** (grâce à Pydantic).
* Déclaration de **paramètres** provenant d'autres endroits différents comme : **en-têtes**, **cookies**, **champs de formulaire** et **fichiers**.
* Comment définir des **contraintes de validation** comme `maximum_length` ou `regex`.
* Un **système <abbr title="also known as components, resources, providers, services, injectables">Dependency Injection</abbr>** très puissant et facile à utiliser.
* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec des **JWT tokens** et l'authentification **HTTP Basic**.
* Des techniques plus avancées (mais tout aussi faciles) pour déclarer des **modèles JSON profondément imbriqués** (grâce à Pydantic).
* Intégration de **GraphQL** avec <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> et d'autres bibliothèques.
* D'obtenir de nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
* De nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
* **WebSockets**
* de tester le code très facilement avec `requests` et `pytest`
* **<abbr title="Cross-Origin Resource Sharing">CORS</abbr>**
* des tests extrêmement simples basés sur HTTPX et `pytest`
* **CORS**
* **Cookie Sessions**
* ... et plus encore.
## Performance
### Déployer votre app (optionnel) { #deploy-your-app-optional }
Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank"> parmi les frameworks existants en Python les plus rapides </a>, juste derrière Starlette et Uvicorn (utilisés en interne par FastAPI). (*)
Vous pouvez éventuellement déployer votre app FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, 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 commande.
Avant de déployer, assurez-vous que vous êtes connecté :
<div class="termy">
```console
$ fastapi login
You are logged in to FastAPI Cloud 🚀
```
</div>
Puis déployez votre app :
<div class="termy">
```console
$ fastapi deploy
Deploying to FastAPI Cloud...
✅ Deployment successful!
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
```
</div>
C'est tout ! Vous pouvez maintenant accéder à votre app à cette URL. ✨
#### À propos de FastAPI Cloud { #about-fastapi-cloud }
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est construit par le même auteur et la même équipe derrière **FastAPI**.
Il rationalise le processus de **construction**, de **déploiement** et d'**accès** à une API avec un minimum d'effort.
Il apporte la même **expérience développeur** de construction d'apps avec FastAPI au **déploiement** dans le cloud. 🎉
FastAPI Cloud est le sponsor principal et le fournisseur de financement des projets open source *FastAPI and friends*. ✨
#### Déployer sur d'autres fournisseurs cloud { #deploy-to-other-cloud-providers }
FastAPI est open source et basé sur des normes. Vous pouvez déployer des apps FastAPI sur n'importe quel fournisseur cloud de votre choix.
Suivez les guides de votre fournisseur cloud pour y déployer des apps FastAPI. 🤓
## Performance { #performance }
Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">parmi les frameworks Python disponibles les plus rapides</a>, juste derrière Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI). (*)
Pour en savoir plus, consultez la section <a href="https://fastapi.tiangolo.com/fr/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
## Dépendances facultatives
## Dépendances { #dependencies }
Utilisées par Pydantic:
FastAPI dépend de Pydantic et de Starlette.
### Dépendances `standard` { #standard-dependencies }
Quand vous installez FastAPI avec `pip install "fastapi[standard]"`, il est fourni avec le groupe `standard` de dépendances optionnelles :
Utilisées par Pydantic :
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - pour la validation des adresses email.
Utilisées par Starlette :
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</code></a> - Obligatoire si vous souhaitez utiliser `TestClient`.
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obligatoire si vous souhaitez utiliser `TestClient`.
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Obligatoire si vous souhaitez utiliser la configuration de template par défaut.
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obligatoire si vous souhaitez supporter le <abbr title="convertit la chaine de caractère d'une requête HTTP en donnée Python">"décodage"</abbr> de formulaire avec `request.form()`.
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - Obligatoire pour la prise en charge de `SessionMiddleware`.
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - Obligatoire pour le support `SchemaGenerator` de Starlette (vous n'en avez probablement pas besoin avec FastAPI).
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obligatoire si vous souhaitez supporter le <abbr title="conversion de la chaîne qui provient d'une requête HTTP en données Python">« parsing »</abbr> de formulaire, avec `request.form()`.
Utilisées par FastAPI / Starlette :
Utilisées par FastAPI :
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - pour le serveur qui charge et sert votre application. Cela inclut `uvicorn[standard]`, qui inclut certaines dépendances (par exemple `uvloop`) nécessaires pour un service à haute performance.
* `fastapi-cli[standard]` - pour fournir la commande `fastapi`.
* Cela inclut `fastapi-cloud-cli`, qui vous permet de déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
### Sans les dépendances `standard` { #without-standard-dependencies }
Si vous ne voulez pas inclure les dépendances optionnelles `standard`, vous pouvez installer avec `pip install fastapi` au lieu de `pip install "fastapi[standard]"`.
### Sans `fastapi-cloud-cli` { #without-fastapi-cloud-cli }
Si vous voulez installer FastAPI avec les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
### Dépendances optionnelles supplémentaires { #additional-optional-dependencies }
Il y a quelques dépendances supplémentaires que vous pourriez vouloir installer.
Dépendances optionnelles Pydantic supplémentaires :
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - pour la gestion des paramètres.
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - pour les types supplémentaires à utiliser avec Pydantic.
Dépendances optionnelles FastAPI supplémentaires :
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - Pour le serveur qui charge et sert votre application.
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Obligatoire si vous voulez utiliser `ORJSONResponse`.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Obligatoire si vous souhaitez utiliser `UJSONResponse`.
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Obligatoire si vous voulez utiliser `UJSONResponse`.
Vous pouvez tout installer avec `pip install fastapi[all]`.
## Licence
## Licence { #license }
Ce projet est soumis aux termes de la licence MIT.

View File

@@ -1,5 +1,5 @@
# Apprendre
# Apprendre { #learn }
Voici les sections introductives et les tutoriels pour apprendre **FastAPI**.
Vous pouvez considérer ceci comme un **manuel**, un **cours**, la **méthode officielle** et recommandée pour appréhender FastAPI. 😎
Vous pouvez considérer ceci comme un **livre**, un **cours**, la **méthode officielle** et recommandée pour apprendre FastAPI. 😎

View File

@@ -1,84 +1,28 @@
# Génération de projets - Modèle
# Modèle Full Stack FastAPI { #full-stack-fastapi-template }
Vous pouvez utiliser un générateur de projet pour commencer, qui réalisera pour vous la mise en place de bases côté architecture globale, sécurité, base de données et premières routes d'API.
Les modèles, bien quils soient généralement fournis 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. 🏁
Un générateur de projet fera toujours une mise en place très subjective que vous devriez modifier et adapter suivant vos besoins, mais cela reste un bon point de départ pour vos projets.
Vous pouvez utiliser ce modèle pour commencer, car il inclut déjà une grande partie de la configuration initiale, de la sécurité, de la base de données et certains endpoints dAPI déjà faits pour vous.
## Full Stack FastAPI PostgreSQL
Dépôt GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Modèle Full Stack FastAPI</a>
GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-postgresql</a>
## Modèle Full Stack FastAPI - Stack technologique et fonctionnalités { #full-stack-fastapi-template-technology-stack-and-features }
### Full Stack FastAPI PostgreSQL - Fonctionnalités
* Intégration **Docker** complète (basée sur Docker).
* Déploiement Docker en mode <a href="https://docs.docker.com/engine/swarm/" class="external-link" target="_blank">Swarm</a>
* Intégration **Docker Compose** et optimisation pour développement local.
* Serveur web Python **prêt au déploiement** utilisant Uvicorn et Gunicorn.
* Backend Python <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">**FastAPI**</a> :
* **Rapide** : Très hautes performances, comparables à **NodeJS** ou **Go** (grâce à Starlette et Pydantic).
* **Intuitif** : Excellent support des éditeurs. <abbr title="aussi appelée auto-complétion, autocomplétion, IntelliSense...">Complétion</abbr> partout. Moins de temps passé à déboguer.
* **Facile** : Fait pour être facile à utiliser et apprendre. Moins de temps passé à lire de la documentation.
* **Concis** : Minimise la duplication de code. Plusieurs fonctionnalités à chaque déclaration de paramètre.
* **Robuste** : Obtenez du code prêt pour être utilisé en production. Avec de la documentation automatique interactive.
* **Basé sur des normes** : Basé sur (et totalement compatible avec) les normes ouvertes pour les APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> et <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
* <a href="https://fastapi.tiangolo.com/features/" class="external-link" target="_blank">**Et bien d'autres fonctionnalités**</a> comme la validation automatique, la sérialisation, l'authentification avec OAuth2 JWT tokens, etc.
* Hashage de **mots de passe sécurisé** par défaut.
* Authentification par **jetons JWT**.
* Modèles **SQLAlchemy** (indépendants des extensions Flask, afin qu'ils puissent être utilisés directement avec des *workers* Celery).
* Modèle de démarrages basiques pour les utilisateurs (à modifier et supprimer au besoin).
* Migrations **Alembic**.
* **CORS** (partage des ressources entre origines multiples, ou *Cross Origin Resource Sharing*).
* *Worker* **Celery** pouvant importer et utiliser les modèles et le code du reste du backend.
* Tests du backend REST basés sur **Pytest**, intégrés dans Docker, pour que vous puissiez tester toutes les interactions de l'API indépendamment de la base de données. Étant exécutés dans Docker, les tests peuvent utiliser un nouvel entrepôt de données créé de zéro à chaque fois (vous pouvez donc utiliser ElasticSearch, MongoDB, CouchDB, etc. et juste tester que l'API fonctionne).
* Intégration Python facile avec **Jupyter Kernels** pour le développement à distance ou intra-Docker avec des extensions comme Atom Hydrogen ou Visual Studio Code Jupyter.
* Frontend **Vue** :
* Généré avec Vue CLI.
* Gestion de l'**Authentification JWT**.
* Page de connexion.
* Après la connexion, page de tableau de bord principal.
* Tableau de bord principal avec création et modification d'utilisateurs.
* Modification de ses propres caractéristiques utilisateur.
* **Vuex**.
* **Vue-router**.
* **Vuetify** pour de magnifiques composants *material design*.
* **TypeScript**.
* Serveur Docker basé sur **Nginx** (configuré pour être facilement manipulé avec Vue-router).
* Utilisation de *Docker multi-stage building*, pour ne pas avoir besoin de sauvegarder ou *commit* du code compilé.
* Tests frontend exécutés à la compilation (pouvant être désactivés).
* Fait aussi modulable que possible, pour pouvoir fonctionner comme tel, tout en pouvant être utilisé qu'en partie grâce à Vue CLI.
* **PGAdmin** pour les bases de données PostgreSQL, facilement modifiable pour utiliser PHPMYAdmin ou MySQL.
* **Flower** pour la surveillance de tâches Celery.
* Équilibrage de charge entre le frontend et le backend avec **Traefik**, afin de pouvoir avoir les deux sur le même domaine, séparés par chemins, mais servis par différents conteneurs.
* Intégration Traefik, comprenant la génération automatique de certificat **HTTPS** Let's Encrypt.
* GitLab **CI** (intégration continue), comprenant des tests pour le frontend et le backend.
## Full Stack FastAPI Couchbase
GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-couchbase" class="external-link" target="_blank">https://github.com/tiangolo/full-stack-fastapi-couchbase</a>
⚠️ **ATTENTION** ⚠️
Si vous démarrez un nouveau projet de zéro, allez voir les alternatives au début de cette page.
Par exemple, le générateur de projet <a href="https://github.com/tiangolo/full-stack-fastapi-postgresql" class="external-link" target="_blank">Full Stack FastAPI PostgreSQL</a> peut être une meilleure alternative, étant activement maintenu et utilisé et comprenant toutes les nouvelles fonctionnalités et améliorations.
Vous êtes toujours libre d'utiliser le générateur basé sur Couchbase si vous le voulez, cela devrait probablement fonctionner correctement, et si vous avez déjà un projet généré en utilisant ce dernier, cela devrait fonctionner aussi (et vous l'avez déjà probablement mis à jour suivant vos besoins).
Vous pouvez en apprendre plus dans la documentation du dépôt GithHub.
## Full Stack FastAPI MongoDB
...viendra surement plus tard, suivant le temps que j'ai. 😅 🎉
## Modèles d'apprentissage automatique avec spaCy et FastAPI
GitHub : <a href="https://github.com/microsoft/cookiecutter-spacy-fastapi" class="external-link" target="_blank">https://github.com/microsoft/cookiecutter-spacy-fastapi</a>
## Modèles d'apprentissage automatique avec spaCy et FastAPI - Fonctionnalités
* Intégration d'un modèle NER **spaCy**.
* Formatage de requête pour **Azure Cognitive Search**.
* Serveur Python web **prêt à utiliser en production** utilisant Uvicorn et Gunicorn.
* Déploiement CI/CD Kubernetes pour **Azure DevOps** (AKS).
* **Multilangues**. Choisissez facilement l'une des langues intégrées à spaCy durant la mise en place du projet.
* **Facilement généralisable** à d'autres bibliothèques similaires (Pytorch, Tensorflow), et non juste spaCy.
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/fr) pour lAPI backend Python.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) pour les interactions avec la base de données SQL en Python (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), utilisé par FastAPI, pour la validation des données et la gestion des paramètres.
- 💾 [PostgreSQL](https://www.postgresql.org) comme base de données SQL.
- 🚀 [React](https://react.dev) pour le frontend.
- 💃 Utilisation de TypeScript, des hooks, de Vite et dautres éléments dune stack frontend moderne.
- 🎨 [Tailwind CSS](https://tailwindcss.com) et [shadcn/ui](https://ui.shadcn.com) pour les composants du frontend.
- 🤖 Un client frontend généré automatiquement.
- 🧪 [Playwright](https://playwright.dev) pour les tests End-to-End.
- 🦇 Prise en charge du mode sombre.
- 🐋 [Docker Compose](https://www.docker.com) pour le développement et la production.
- 🔒 Hashage sécurisé des mots de passe par défaut.
- 🔑 Authentification JWT (JSON Web Token).
- 📫 Récupération du mot de passe par e-mail.
- ✅ Tests avec [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) comme reverse proxy / load balancer.
- 🚢 Instructions de déploiement utilisant Docker Compose, y compris comment configurer un proxy Traefik frontend pour gérer des certificats HTTPS automatiques.
- 🏭 CI (intégration continue) et CD (déploiement continu) basées sur GitHub Actions.

View File

@@ -1,70 +1,68 @@
# Introduction aux Types Python
# Introduction aux Types Python { #python-types-intro }
Python supporte des annotations de type (ou *type hints*) optionnelles.
Python supporte des «type hints» optionnels (aussi appelés «type annotations»).
Ces annotations de type constituent une syntaxe spéciale qui permet de déclarer le <abbr title="par exemple : str, int, float, bool">type</abbr> d'une variable.
Ces **«type hints»** ou annotations sont une syntaxe spéciale qui permet de déclarer le <abbr title="par exemple : str, int, float, bool">type</abbr> d'une variable.
En déclarant les types de vos variables, cela permet aux différents outils comme les éditeurs de texte d'offrir un meilleur support.
En déclarant des types pour vos variables, les éditeurs et les outils peuvent vous offrir un meilleur support.
Ce chapitre n'est qu'un **tutoriel rapide / rappel** sur les annotations de type Python.
Seulement le minimum nécessaire pour les utiliser avec **FastAPI** sera couvert... ce qui est en réalité très peu.
Ceci n'est qu'un **tutoriel rapide / rappel** sur les «type hints» de Python. Il couvre seulement le minimum nécessaire pour les utiliser avec **FastAPI**... ce qui est en réalité très peu.
**FastAPI** est totalement basé sur ces annotations de type, qui lui donnent de nombreux avantages.
**FastAPI** est entièrement basé sur ces «type hints», ils lui donnent de nombreux avantages et bénéfices.
Mais même si vous n'utilisez pas ou n'utiliserez jamais **FastAPI**, vous pourriez bénéficier d'apprendre quelques choses sur ces dernières.
Mais même si vous n'utilisez jamais **FastAPI**, vous auriez intérêt à en apprendre un peu à leur sujet.
/// note
/// note | Remarque
Si vous êtes un expert Python, et que vous savez déjà **tout** sur les annotations de type, passez au chapitre suivant.
Si vous êtes un expert Python, et que vous savez déjà tout sur les «type hints», passez au chapitre suivant.
///
## Motivations
## Motivation { #motivation }
Prenons un exemple simple :
Commençons par un exemple simple :
{*../../docs_src/python_types/tutorial001.py*}
{* ../../docs_src/python_types/tutorial001_py39.py *}
Exécuter ce programe affiche :
L'exécution de ce programme affiche :
```
John Doe
```
La fonction :
La fonction fait ce qui suit :
* Prend un `first_name` et un `last_name`.
* Convertit la première lettre de chaque paramètre en majuscules grâce à `title()`.
* Concatène les résultats avec un espace entre les deux.
* Convertit la première lettre de chacun en majuscule avec `title()`.
* Les <abbr title="Puts them together, as one. With the contents of one after the other.">concatène</abbr> avec un espace au milieu.
{*../../docs_src/python_types/tutorial001.py hl[2] *}
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
### Limitations
### Le modifier { #edit-it }
C'est un programme très simple.
Mais maintenant imaginez que vous l'écriviez de zéro.
Mais imaginez maintenant que vous l'écriviez de zéro.
À un certain point vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts.
À un certain point, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts...
Mais vous aviez besoin de "cette méthode qui convertit la première lettre en majuscule".
Mais ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ».
Était-ce `upper` ? `uppercase` ? `first_uppercase` ? `capitalize` ?
Était-ce `upper` ? Était-ce `uppercase` ? `first_uppercase` ? `capitalize` ?
Vous essayez donc d'utiliser le vieil ami du programmeur, l'auto-complétion de l'éditeur.
Ensuite, vous essayez avec le vieil ami du programmeur, l'autocomplétion de l'éditeur.
Vous écrivez le premier paramètre, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'auto-complétion.
Vous tapez le premier paramètre de la fonction, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Space` pour déclencher la complétion.
Mais malheureusement, rien d'utile n'en résulte :
Mais, malheureusement, vous n'obtenez rien d'utile :
<img src="/img/python-types/image01.png">
### Ajouter des types
### Ajouter des types { #add-types }
Modifions une seule ligne de la version précédente.
Nous allons changer seulement cet extrait, les paramètres de la fonction, de :
Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
```Python
first_name, last_name
@@ -78,11 +76,11 @@ Nous allons changer seulement cet extrait, les paramètres de la fonction, de :
C'est tout.
Ce sont des annotations de types :
Ce sont les «type hints» :
{*../../docs_src/python_types/tutorial002.py hl[1] *}
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
À ne pas confondre avec la déclaration de valeurs par défaut comme ici :
Ce n'est pas la même chose que de déclarer des valeurs par défaut, comme ce serait le cas avec :
```Python
first_name="john", last_name="doe"
@@ -90,210 +88,377 @@ Ce sont des annotations de types :
C'est une chose différente.
On utilise un deux-points (`:`), et pas un égal (`=`).
Nous utilisons des deux-points (`:`), pas des signes égal (`=`).
Et ajouter des annotations de types ne ce normalement pas de différence avec le comportement qui aurait eu lieu si elles n'étaient pas là.
Et ajouter des «type hints» ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans eux.
Maintenant, imaginez que vous êtes en train de créer cette fonction, mais avec des annotations de type cette fois.
Mais maintenant, imaginez que vous êtes à nouveau en plein milieu de la création de cette fonction, mais avec des «type hints».
Au même moment que durant l'exemple précédent, vous essayez de déclencher l'auto-complétion et vous voyez :
Au même endroit, vous essayez de déclencher l'autocomplétion avec `Ctrl+Space` et vous voyez :
<img src="/img/python-types/image02.png">
Vous pouvez donc dérouler les options jusqu'à trouver la méthode à laquelle vous pensiez.
Avec ça, vous pouvez faire défiler, voir les options, jusqu'à trouver celle qui «vous dit quelque chose» :
<img src="/img/python-types/image03.png">
## Plus de motivations
## Plus de motivation { #more-motivation }
Cette fonction possède déjà des annotations de type :
Regardez cette fonction, elle a déjà des «type hints» :
{*../../docs_src/python_types/tutorial003.py hl[1] *}
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
Comme l'éditeur connaît le type des variables, vous n'avez pas seulement l'auto-complétion, mais aussi de la détection d'erreurs :
Parce que l'éditeur connaît les types des variables, vous n'avez pas seulement la complétion, vous avez aussi des vérifications d'erreurs :
<img src="/img/python-types/image04.png">
Maintenant que vous avez connaissance du problème, convertissez `age` en <abbr title="string">chaîne de caractères</abbr> grâce à `str(age)` :
Maintenant vous savez que vous devez le corriger, convertir `age` en chaîne de caractères avec `str(age)` :
{*../../docs_src/python_types/tutorial004.py hl[2] *}
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
## Déclarer des types
## Déclarer des types { #declaring-types }
Vous venez de voir là où les types sont généralement déclarés : dans les paramètres de fonctions.
Vous venez de voir l'endroit principal pour déclarer des « type hints». En tant que paramètres de fonction.
C'est aussi ici que vous les utiliseriez avec **FastAPI**.
C'est aussi l'endroit principal où vous les utiliseriez avec **FastAPI**.
### Types simples
### Types simples { #simple-types }
Vous pouvez déclarer tous les types de Python, pas seulement `str`.
Vous pouvez déclarer tous les types standards de Python, pas seulement `str`.
Comme par exemple :
Vous pouvez utiliser, par exemple :
* `int`
* `float`
* `bool`
* `bytes`
{*../../docs_src/python_types/tutorial005.py hl[1] *}
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
### Types génériques avec des paramètres de types
### Types génériques avec des paramètres de type { #generic-types-with-type-parameters }
Il existe certaines structures de données qui contiennent d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent elles aussi avoir leurs propres types.
Il existe des structures de données qui peuvent contenir d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent aussi avoir leur propre type.
Pour déclarer ces types et les types internes, on utilise le module standard de Python `typing`.
Ces types qui ont des types internes sont appelés des types «génériques» (**generic**). Et il est possible de les déclarer, même avec leurs types internes.
Il existe spécialement pour supporter ces annotations de types.
Pour déclarer ces types et les types internes, vous pouvez utiliser le module standard Python `typing`. Il existe spécifiquement pour supporter ces «type hints».
#### `List`
#### Versions plus récentes de Python { #newer-versions-of-python }
Par exemple, définissons une variable comme `list` de `str`.
La syntaxe utilisant `typing` est **compatible** avec toutes les versions, de Python 3.6 aux plus récentes, y compris Python 3.9, Python 3.10, etc.
Importez `List` (avec un `L` majuscule) depuis `typing`.
Au fur et à mesure que Python évolue, les **versions plus récentes** offrent un support amélioré pour ces annotations de type et, dans de nombreux cas, vous n'aurez même pas besoin d'importer et d'utiliser le module `typing` pour déclarer les annotations de type.
{*../../docs_src/python_types/tutorial006.py hl[1] *}
Si vous pouvez choisir une version plus récente de Python pour votre projet, vous pourrez profiter de cette simplicité supplémentaire.
Déclarez la variable, en utilisant la syntaxe des deux-points (`:`).
Dans toute la documentation, il y a des exemples compatibles avec chaque version de Python (quand il y a une différence).
Et comme type, mettez `List`.
Par exemple « **Python 3.6+** » signifie que c'est compatible avec Python 3.6 ou supérieur (y compris 3.7, 3.8, 3.9, 3.10, etc). Et « **Python 3.9+** » signifie que c'est compatible avec Python 3.9 ou supérieur (y compris 3.10, etc).
Les listes étant un type contenant des types internes, mettez ces derniers entre crochets (`[`, `]`) :
Si vous pouvez utiliser les **dernières versions de Python**, utilisez les exemples pour la version la plus récente, ceux-ci auront la **meilleure et la plus simple syntaxe**, par exemple, « **Python 3.10+** ».
{*../../docs_src/python_types/tutorial006.py hl[4] *}
#### List { #list }
/// tip | Astuce
Par exemple, définissons une variable comme une `list` de `str`.
Ces types internes entre crochets sont appelés des "paramètres de type".
Déclarez la variable, avec la même syntaxe de deux-points (`:`).
Ici, `str` est un paramètre de type passé à `List`.
Comme type, mettez `list`.
Comme la liste est un type qui contient des types internes, vous les mettez entre crochets :
{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *}
/// info
Ces types internes entre crochets sont appelés des «paramètres de type».
Dans ce cas, `str` est le paramètre de type passé à `list`.
///
Ce qui signifie : "la variable `items` est une `list`, et chacun de ses éléments a pour type `str`.
Cela signifie : « la variable `items` est une `list`, et chacun des éléments de cette liste est un `str` ».
En faisant cela, votre éditeur pourra vous aider, même pendant que vous traitez des éléments de la liste.
En faisant cela, votre éditeur peut fournir du support même pendant le traitement des éléments de la liste :
<img src="/img/python-types/image05.png">
Sans types, c'est presque impossible à réaliser.
Vous remarquerez que la variable `item` n'est qu'un des éléments de la list `items`.
Remarquez que la variable `item` est un des éléments de la liste `items`.
Et pourtant, l'éditeur sait qu'elle est de type `str` et pourra donc vous aider à l'utiliser.
Et pourtant, l'éditeur sait que c'est un `str`, et fournit du support pour ça.
#### `Tuple` et `Set`
#### Tuple et Set { #tuple-and-set }
C'est le même fonctionnement pour déclarer un `tuple` ou un `set` :
Vous feriez la même chose pour déclarer des `tuple` et des `set` :
{*../../docs_src/python_types/tutorial007.py hl[1,4] *}
{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
Dans cet exemple :
Cela signifie :
* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un deuxième `int`, et un `str`.
* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un autre `int`, et un `str`.
* La variable `items_s` est un `set`, et chacun de ses éléments est de type `bytes`.
#### `Dict`
#### Dict { #dict }
Pour définir un `dict`, il faut lui passer 2 paramètres, séparés par une virgule (`,`).
Pour définir un `dict`, vous passez 2 paramètres de type, séparés par des virgules.
Le premier paramètre de type est pour les clés et le second pour les valeurs du dictionnaire (`dict`).
Le premier paramètre de type est pour les clés du `dict`.
{*../../docs_src/python_types/tutorial008.py hl[1,4] *}
Le second paramètre de type est pour les valeurs du `dict` :
Dans cet exemple :
{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
* La variable `prices` est de type `dict` :
* Les clés de ce dictionnaire sont de type `str`.
* Les valeurs de ce dictionnaire sont de type `float`.
Cela signifie :
#### `Optional`
* La variable `prices` est un `dict` :
* Les clés de ce `dict` sont de type `str` (disons, le nom de chaque élément).
* Les valeurs de ce `dict` sont de type `float` (disons, le prix de chaque élément).
Vous pouvez aussi utiliser `Optional` pour déclarer qu'une variable a un type, comme `str` mais qu'il est "optionnel" signifiant qu'il pourrait aussi être `None`.
#### Union { #union }
{*../../docs_src/python_types/tutorial009.py hl[1,4] *}
Vous pouvez déclarer qu'une variable peut être de **plusieurs types**, par exemple, un `int` ou un `str`.
Utiliser `Optional[str]` plutôt que `str` permettra à l'éditeur de vous aider à détecter les erreurs où vous supposeriez qu'une valeur est toujours de type `str`, alors qu'elle pourrait aussi être `None`.
En Python 3.6 et supérieur (y compris Python 3.10) vous pouvez utiliser le type `Union` de `typing` et mettre entre crochets les types possibles à accepter.
#### Types génériques
En Python 3.10, il existe aussi une **nouvelle syntaxe** où vous pouvez mettre les types possibles séparés par une <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>barre verticale (`|`)</abbr>.
Les types qui peuvent contenir des paramètres de types entre crochets, comme :
//// tab | Python 3.10+
* `List`
* `Tuple`
* `Set`
* `Dict`
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial008b_py39.py!}
```
////
Dans les deux cas, cela signifie que `item` pourrait être un `int` ou un `str`.
#### Possiblement `None` { #possibly-none }
Vous pouvez déclarer qu'une valeur pourrait avoir un type, comme `str`, mais qu'elle pourrait aussi être `None`.
En Python 3.6 et supérieur (y compris Python 3.10) vous pouvez le déclarer en important et en utilisant `Optional` depuis le module `typing`.
```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009_py39.py!}
```
Utiliser `Optional[str]` au lieu de seulement `str` permettra à l'éditeur de vous aider à détecter des erreurs où vous pourriez supposer qu'une valeur est toujours un `str`, alors qu'elle pourrait aussi être `None`.
`Optional[Something]` est en fait un raccourci pour `Union[Something, None]`, ils sont équivalents.
Cela signifie aussi qu'en Python 3.10, vous pouvez utiliser `Something | None` :
//// tab | Python 3.10+
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial009_py310.py!}
```
////
//// tab | Python 3.9+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009_py39.py!}
```
////
//// tab | Alternative Python 3.9+
```Python hl_lines="1 4"
{!> ../../docs_src/python_types/tutorial009b_py39.py!}
```
////
#### Utiliser `Union` ou `Optional` { #using-union-or-optional }
Si vous utilisez une version de Python inférieure à 3.10, voici une astuce de mon point de vue très **subjectif** :
* 🚨 Évitez d'utiliser `Optional[SomeType]`
* À la place ✨ **utilisez `Union[SomeType, None]`** ✨.
Les deux sont équivalents et, en dessous, c'est la même chose, mais je recommande `Union` plutôt que `Optional` parce que le mot «optional» semblerait impliquer que la valeur est optionnelle, et cela signifie en réalité «elle peut être `None` », même si elle n'est pas optionnelle et est toujours requise.
Je pense que `Union[SomeType, None]` est plus explicite sur ce que cela signifie.
Ce n'est qu'une question de mots et de noms. Mais ces mots peuvent affecter la façon dont vous et vos coéquipiers pensez au code.
Par exemple, prenons cette fonction :
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
Le paramètre `name` est défini comme `Optional[str]`, mais il n'est **pas optionnel**, vous ne pouvez pas appeler la fonction sans le paramètre :
```Python
say_hi() # Oh, no, this throws an error! 😱
```
Le paramètre `name` est **toujours requis** (pas *optionnel*) parce qu'il n'a pas de valeur par défaut. Pourtant, `name` accepte `None` comme valeur :
```Python
say_hi(name=None) # This works, None is valid 🎉
```
La bonne nouvelle est qu'une fois que vous serez sur Python 3.10, vous n'aurez plus à vous en soucier, car vous pourrez simplement utiliser `|` pour définir des unions de types :
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
Et ensuite vous n'aurez plus à vous soucier de noms comme `Optional` et `Union`. 😎
#### Types génériques { #generic-types }
Ces types qui prennent des paramètres de type entre crochets sont appelés des **Generic types** ou **Generics**, par exemple :
//// tab | Python 3.10+
Vous pouvez utiliser les mêmes types intégrés comme generics (avec des crochets et des types à l'intérieur) :
* `list`
* `tuple`
* `set`
* `dict`
Et comme avec les versions précédentes de Python, depuis le module `typing` :
* `Union`
* `Optional`
* ...et d'autres.
sont appelés des **types génériques** ou **Generics**.
En Python 3.10, comme alternative à l'utilisation des generics `Union` et `Optional`, vous pouvez utiliser la <abbr title='also called "bitwise or operator", but that meaning is not relevant here'>barre verticale (`|`)</abbr> pour déclarer des unions de types, c'est bien mieux et plus simple.
### Classes en tant que types
////
//// tab | Python 3.9+
Vous pouvez utiliser les mêmes types intégrés comme generics (avec des crochets et des types à l'intérieur) :
* `list`
* `tuple`
* `set`
* `dict`
Et des generics depuis le module `typing` :
* `Union`
* `Optional`
* ...et d'autres.
////
### Classes en tant que types { #classes-as-types }
Vous pouvez aussi déclarer une classe comme type d'une variable.
Disons que vous avez une classe `Person`, avec une variable `name` :
{*../../docs_src/python_types/tutorial010.py hl[1:3] *}
Disons que vous avez une classe `Person`, avec un nom :
{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *}
Vous pouvez ensuite déclarer une variable de type `Person` :
{*../../docs_src/python_types/tutorial010.py hl[6] *}
{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *}
Et vous aurez accès, encore une fois, au support complet offert par l'éditeur :
Et alors, encore une fois, vous obtenez tout le support de l'éditeur :
<img src="/img/python-types/image06.png">
## Les modèles Pydantic
Remarquez que cela signifie que « `one_person` est une **instance** de la classe `Person` ».
Cela ne signifie pas que « `one_person` est la **classe** appelée `Person` ».
## Les modèles Pydantic { #pydantic-models }
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> est une bibliothèque Python pour effectuer de la validation de données.
Vous déclarez la forme de la donnée avec des classes et des attributs.
Vous déclarez la « forme » de la donnée comme des classes avec des attributs.
Chaque attribut possède un type.
Et chaque attribut a un type.
Puis vous créez une instance de cette classe avec certaines valeurs et **Pydantic** validera les valeurs, les convertira dans le type adéquat (si c'est nécessaire et possible) et vous donnera un objet avec toute la donnée.
Ensuite vous créez une instance de cette classe avec certaines valeurs et elle validera les valeurs, les convertira dans le type approprié (si c'est le cas) et vous donnera un objet avec toutes les données.
Ainsi, votre éditeur vous offrira un support adapté pour l'objet résultant.
Et vous obtenez tout le support de l'éditeur avec cet objet résultant.
Extrait de la documentation officielle de **Pydantic** :
Un exemple des documents officiels de Pydantic :
{*../../docs_src/python_types/tutorial011.py*}
{* ../../docs_src/python_types/tutorial011_py310.py *}
/// info
Pour en savoir plus à propos de <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic, allez jeter un coup d'oeil à sa documentation</a>.
Pour en savoir plus sur <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic, consultez sa documentation</a>.
///
**FastAPI** est basé entièrement sur **Pydantic**.
**FastAPI** est entièrement basé sur Pydantic.
Vous verrez bien plus d'exemples de son utilisation dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
Vous verrez beaucoup plus tout cela en pratique dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
## Les annotations de type dans **FastAPI**
/// tip | Astuce
**FastAPI** utilise ces annotations pour faire différentes choses.
Pydantic a un comportement spécial lorsque vous utilisez `Optional` ou `Union[Something, None]` sans valeur par défaut, vous pouvez en lire plus à ce sujet dans la documentation Pydantic sur les <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">Required Optional fields</a>.
Avec **FastAPI**, vous déclarez des paramètres grâce aux annotations de types et vous obtenez :
///
* **du support de l'éditeur**
* **de la vérification de types**
## Type Hints avec des annotations de métadonnées { #type-hints-with-metadata-annotations }
...et **FastAPI** utilise ces mêmes déclarations pour :
Python a aussi une fonctionnalité qui permet de mettre des **<abbr title="Data about the data, in this case, information about the type, e.g. a description.">métadonnées</abbr> supplémentaires** dans ces «type hints» en utilisant `Annotated`.
* **Définir les prérequis** : depuis les paramètres de chemins des requêtes, les entêtes, les corps, les dépendances, etc.
* **Convertir des données** : depuis la requête vers les types requis.
* **Valider des données** : venant de chaque requête :
* Générant automatiquement des **erreurs** renvoyées au client quand la donnée est invalide.
Depuis Python 3.9, `Annotated` fait partie de la bibliothèque standard, vous pouvez donc l'importer depuis `typing`.
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
Python lui-même ne fait rien avec ce `Annotated`. Et pour les éditeurs et d'autres outils, le type est toujours `str`.
Mais vous pouvez utiliser cet espace dans `Annotated` pour fournir à **FastAPI** des métadonnées supplémentaires sur la manière dont vous voulez que votre application se comporte.
La chose importante à retenir est que **le premier *paramètre de type*** que vous passez à `Annotated` est le **vrai type**. Le reste n'est que des métadonnées pour d'autres outils.
Pour le moment, vous devez juste savoir que `Annotated` existe, et que c'est du Python standard. 😎
Plus tard, vous verrez à quel point cela peut être **puissant**.
/// tip | Astuce
Le fait que ce soit du **Python standard** signifie que vous aurez toujours la **meilleure expérience développeur possible** dans votre éditeur, avec les outils que vous utilisez pour analyser et refactoriser votre code, etc. ✨
Et aussi que votre code sera très compatible avec de nombreux autres outils et bibliothèques Python. 🚀
///
## Les annotations de type dans **FastAPI** { #type-hints-in-fastapi }
**FastAPI** tire parti de ces «type hints» pour faire plusieurs choses.
Avec **FastAPI** vous déclarez des paramètres avec des «type hints» et vous obtenez :
* **Support de l'éditeur**.
* **Vérifications de types**.
... et **FastAPI** utilise les mêmes déclarations pour :
* **Définir des exigences** : à partir des paramètres de chemin de la requête, des paramètres de requête, des en-têtes, des corps, des dépendances, etc.
* **Convertir les données** : de la requête vers le type requis.
* **Valider les données** : provenant de chaque requête :
* Générant des **erreurs automatiques** renvoyées au client lorsque les données sont invalides.
* **Documenter** l'API avec OpenAPI :
* ce qui ensuite utilisé par les interfaces utilisateur automatiques de documentation interactive.
* ce qui est ensuite utilisé par les interfaces utilisateur automatiques de documentation interactive.
Tout cela peut paraître bien abstrait, mais ne vous inquiétez pas, vous verrez tout ça en pratique dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
Tout cela peut sembler abstrait. Ne vous inquiétez pas. Vous verrez tout cela en action dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
Ce qu'il faut retenir c'est qu'en utilisant les types standard de Python, à un seul endroit (plutôt que d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous.
L'important est qu'en utilisant les types standards de Python, à un seul endroit (au lieu d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous.
/// info
Si vous avez déjà lu le tutoriel et êtes revenus ici pour voir plus sur les types, une bonne ressource est la <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">"cheat sheet" de `mypy`</a>.
Si vous avez déjà parcouru tout le tutoriel et que vous êtes revenu pour en voir plus sur les types, une bonne ressource est <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">la « cheat sheet » de `mypy`</a>.
///

View File

@@ -1,84 +1,86 @@
# Tâches d'arrière-plan
# Tâches d'arrière-plan { #background-tasks }
Vous pouvez définir des tâches d'arrière-plan qui seront exécutées après avoir retourné une réponse.
Vous pouvez définir des tâches d'arrière-plan à exécuter *après* avoir renvoyé une réponse.
Ceci est utile pour les opérations qui doivent avoir lieu après une requête, mais le client n'a pas réellement besoin d'attendre que l'opération soit terminée pour recevoir une réponse.
Ceci est utile pour les opérations qui doivent avoir lieu après une requête, mais pour lesquelles le client n'a pas réellement besoin d'attendre que l'opération se termine avant de recevoir la réponse.
Cela comprend, par exemple :
* Les notifications par email envoyées après l'exécution d'une action :
* Étant donné que se connecter à un serveur et envoyer un email a tendance à être «lent» (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan.
* Traiter des données :
* Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse «Accepted» (HTTP 202) puis faire le traitement en arrière-plan.
* Comme se connecter à un serveur email et envoyer un email a tendance à être « lent » (plusieurs secondes), vous pouvez renvoyer la réponse immédiatement et envoyer la notification par email en arrière-plan.
* Le traitement de données :
* Par exemple, disons que vous recevez un fichier qui doit passer par un traitement lent, vous pouvez renvoyer une réponse « Accepted » (HTTP 202) et traiter le fichier en arrière-plan.
## Utiliser `BackgroundTasks` { #using-backgroundtasks }
## Utiliser `BackgroundTasks`
Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin d'accès* avec une déclaration de type `BackgroundTasks` :
Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin* avec `BackgroundTasks` comme type déclaré.
{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
**FastAPI** créera l'objet de type `BackgroundTasks` pour vous et le passera comme paramètre.
## Créer une fonction de tâche
## Créer une fonction de tâche { #create-a-task-function }
Une fonction à exécuter comme tâche d'arrière-plan est juste une fonction standard qui peut recevoir des paramètres.
Créez une fonction à exécuter comme tâche d'arrière-plan.
Elle peut être une fonction asynchrone (`async def`) ou une fonction normale (`def`), **FastAPI** saura la gérer correctement.
C'est simplement une fonction standard qui peut recevoir des paramètres.
Dans cet exemple, la fonction de tâche écrira dans un fichier (afin de simuler un envoi d'email).
Elle peut être une fonction `async def` ou une fonction `def` normale, **FastAPI** saura la gérer correctement.
L'opération d'écriture n'utilisant ni `async` ni `await`, on définit la fonction avec un `def` normal.
Dans ce cas, la fonction de tâche écrira dans un fichier (en simulant l'envoi d'un email).
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
Et comme l'opération d'écriture n'utilise pas `async` et `await`, nous définissons la fonction avec un `def` normal :
## Ajouter une tâche d'arrière-plan
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
Dans votre *fonction de chemin*, passez votre fonction de tâche à l'objet de type `BackgroundTasks` (`background_tasks` ici) grâce à la méthode `.add_task()` :
## Ajouter la tâche d'arrière-plan { #add-the-background-task }
À l'intérieur de votre *fonction de chemin d'accès*, passez votre fonction de tâche à l'objet de type *background tasks* avec la méthode `.add_task()` :
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
`.add_task()` reçoit comme arguments :
* Une fonction de tâche à exécuter en arrière-plan (`write_notification`).
* Les arguments positionnels à passer à la fonction de tâche dans l'ordre (`email`).
* Les arguments nommés à passer à la fonction de tâche (`message="some notification"`).
* N'importe quelle séquence d'arguments qui doit être passée à la fonction de tâche dans l'ordre (`email`).
* N'importe quels arguments nommés qui doivent être passés à la fonction de tâche (`message="some notification"`).
## Injection de dépendances
## Injection de dépendances { #dependency-injection }
Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances. Vous pouvez déclarer un paramètre de type `BackgroundTasks` à différents niveaux : dans une *fonction de chemin*, dans une dépendance, dans une sous-dépendance...
Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances, vous pouvez déclarer un paramètre de type `BackgroundTasks` à plusieurs niveaux : dans une *fonction de chemin d'accès*, dans une dépendance (dependable), dans une sous-dépendance, etc.
**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que tous les paramètres de type `BackgroundTasks` soient fusionnés et que les tâches soient exécutées en arrière-plan :
**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, de sorte que toutes les tâches d'arrière-plan sont fusionnées et exécutées ensuite en arrière-plan :
{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
Dans cet exemple, les messages seront écrits dans le fichier `log.txt` après que la réponse soit envoyée.
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
S'il y avait une `query` (paramètre nommé `q`) dans la requête, alors elle sera écrite dans `log.txt` via une tâche d'arrière-plan.
Et ensuite une autre tâche d'arrière-plan (générée dans les paramètres de la *la fonction de chemin*) écrira un message dans `log.txt` comprenant le paramètre de chemin `email`.
Dans cet exemple, les messages seront écrits dans le fichier `log.txt` *après* que la réponse est envoyée.
## Détails techniques
S'il y avait une query dans la requête, elle sera écrite dans le log via une tâche d'arrière-plan.
Et ensuite une autre tâche d'arrière-plan générée au niveau de la *fonction de chemin d'accès* écrira un message en utilisant le paramètre de chemin `email`.
## Détails techniques { #technical-details }
La classe `BackgroundTasks` provient directement de <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`starlette.background`</a>.
Elle est importée/incluse directement dans **FastAPI** pour que vous puissiez l'importer depuis `fastapi` et éviter d'importer accidentellement `BackgroundTask` (sans `s` à la fin) depuis `starlette.background`.
Elle est importée/incluse directement dans FastAPI afin que vous puissiez l'importer depuis `fastapi` et éviter d'importer accidentellement l'alternative `BackgroundTask` (sans le `s` à la fin) depuis `starlette.background`.
En utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin* et de laisser **FastAPI** gérer le reste pour vous, comme en utilisant l'objet `Request` directement.
En utilisant uniquement `BackgroundTasks` (et non `BackgroundTask`), il est alors possible de l'utiliser comme paramètre de *fonction de chemin d'accès* et de laisser **FastAPI** gérer le reste pour vous, comme lorsque vous utilisez directement l'objet `Request`.
Il est tout de même possible d'utiliser `BackgroundTask` seul dans **FastAPI**, mais dans ce cas il faut créer l'objet dans le code et renvoyer une `Response` Starlette l'incluant.
Il est toujours possible d'utiliser `BackgroundTask` seul dans FastAPI, mais vous devez créer l'objet dans votre code et renvoyer une `Response` Starlette l'incluant.
Plus de détails sont disponibles dans <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">la documentation officielle de Starlette sur les tâches d'arrière-plan</a> (via leurs classes `BackgroundTasks`et `BackgroundTask`).
Vous pouvez voir plus de détails dans <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">la documentation officielle de Starlette sur les Background Tasks</a>.
## Avertissement
## Mise en garde { #caveat }
Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
Si vous devez effectuer des calculs lourds en arrière-plan et que vous n'avez pas nécessairement besoin qu'ils soient exécutés par le même process (par exemple, vous n'avez pas besoin de partager la mémoire, les variables, etc.), vous pouvez tirer bénéfice d'utiliser d'autres outils plus importants comme <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et potentiellement, sur plusieurs serveurs.
Ils ont tendance à nécessiter des configurations plus complexes, un gestionnaire de file de messages/tâches, comme RabbitMQ ou Redis, mais ils vous permettent d'exécuter des tâches d'arrière-plan dans plusieurs process, et surtout, sur plusieurs serveurs.
Mais si vous avez besoin d'accéder aux variables et objets de la même application **FastAPI**, ou si vous avez besoin d'effectuer de petites tâches d'arrière-plan (comme envoyer des notifications par email), vous pouvez simplement vous contenter d'utiliser `BackgroundTasks`.
Mais si vous devez accéder à des variables et objets de la même app **FastAPI**, ou si vous devez effectuer de petites tâches d'arrière-plan (comme envoyer une notification par email), vous pouvez simplement utiliser `BackgroundTasks`.
## Résumé
## Résumé { #recap }
Importez et utilisez `BackgroundTasks` grâce aux paramètres de *fonction de chemin* et les dépendances pour ajouter des tâches d'arrière-plan.
Importez et utilisez `BackgroundTasks` avec des paramètres dans les *fonctions de chemin d'accès* et les dépendances pour ajouter des tâches d'arrière-plan.

View File

@@ -1,24 +1,24 @@
# Body - Paramètres multiples
# Body - Paramètres multiples { #body-multiple-parameters }
Maintenant que nous avons vu comment manipuler `Path` et `Query`, voyons comment faire pour le corps d'une requête, communément désigné par le terme anglais "body".
Maintenant que nous avons vu comment utiliser `Path` et `Query`, voyons des usages plus avancés des déclarations du corps de la requête.
## Mélanger les paramètres `Path`, `Query` et body
## Mélanger les paramètres `Path`, `Query` et body { #mix-path-query-and-body-parameters }
Tout d'abord, sachez que vous pouvez mélanger les déclarations des paramètres `Path`, `Query` et body, **FastAPI** saura quoi faire.
Tout d'abord, bien entendu, vous pouvez mélanger librement les déclarations de paramètres `Path`, `Query` et du corps de la requête, et **FastAPI** saura quoi faire.
Vous pouvez également déclarer des paramètres body comme étant optionnels, en leur assignant une valeur par défaut à `None` :
Et vous pouvez également déclarer des paramètres body comme étant optionnels, en définissant la valeur par défaut à `None` :
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
/// note
/// note | Remarque
Notez que, dans ce cas, le paramètre `item` provenant du `Body` est optionnel (sa valeur par défaut est `None`).
Notez que, dans ce cas, le `item` qui serait pris depuis le corps est optionnel, car il a une valeur par défaut à `None`.
///
## Paramètres multiples du body
## Paramètres multiples du body { #multiple-body-parameters }
Dans l'exemple précédent, les opérations de routage attendaient un body JSON avec les attributs d'un `Item`, par exemple :
Dans l'exemple précédent, les *chemins d'accès* s'attendraient à un corps JSON avec les attributs d'un `Item`, comme :
```JSON
{
@@ -29,13 +29,14 @@ Dans l'exemple précédent, les opérations de routage attendaient un body JSON
}
```
Mais vous pouvez également déclarer plusieurs paramètres provenant de body, par exemple `item` et `user` simultanément :
Mais vous pouvez aussi déclarer plusieurs paramètres body, par ex. `item` et `user` :
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
Dans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre dans le body (chacun correspondant à un modèle Pydantic).
Il utilisera alors les noms des paramètres comme clés, et s'attendra à recevoir quelque chose de semblable à :
Dans ce cas, **FastAPI** remarquera qu'il y a plus d'un paramètre body dans la fonction (il y a deux paramètres qui sont des modèles Pydantic).
Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le corps, et s'attendra à un corps comme :
```JSON
{
@@ -52,29 +53,30 @@ Il utilisera alors les noms des paramètres comme clés, et s'attendra à recevo
}
```
/// note
/// note | Remarque
"Notez que, bien que nous ayons déclaré le paramètre `item` de la même manière que précédemment, il est maintenant associé à la clé `item` dans le corps de la requête."`.
Notez que, même si le `item` a été déclaré de la même manière qu'avant, il est maintenant attendu dans le corps avec une clé `item`.
///
**FastAPI** effectue la conversion de la requête de façon transparente, de sorte que les objets `item` et `user` se trouvent correctement définis.
**FastAPI** fera la conversion automatique à partir de la requête, de sorte que le paramètre `item` reçoive son contenu spécifique, et de même pour `user`.
Il effectue également la validation des données (même imbriquées les unes dans les autres), et permet de les documenter correctement (schéma OpenAPI et documentation auto-générée).
Il effectuera la validation des données composées, et les documentera ainsi pour le schéma OpenAPI et les documents automatiques.
## Valeurs scalaires dans le body
## Valeurs scalaires dans le body { #singular-values-in-body }
De la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres query et path, **FastAPI** fournit un équivalent `Body`.
De la même manière qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres de requête et de chemin, **FastAPI** fournit un équivalent `Body`.
Par exemple, en étendant le modèle précédent, vous pouvez vouloir ajouter un paramètre `importance` dans le même body, en plus des paramètres `item` et `user`.
Par exemple, en étendant le modèle précédent, vous pourriez décider que vous voulez une autre clé `importance` dans le même corps, en plus de `item` et `user`.
Si vous le déclarez tel quel, comme c'est une valeur [scalaire](https://docs.github.com/fr/graphql/reference/scalars), **FastAPI** supposera qu'il s'agit d'un paramètre de requête (`Query`).
Si vous le déclarez tel quel, comme c'est une valeur scalaire, **FastAPI** supposera qu'il s'agit d'un paramètre de requête.
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une variable de body en utilisant `Body` :
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une autre clé dans le corps en utilisant `Body` :
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
Dans ce cas, **FastAPI** s'attendra à un body semblable à :
Dans ce cas, **FastAPI** s'attendra à un corps comme :
```JSON
{
@@ -92,19 +94,19 @@ Dans ce cas, **FastAPI** s'attendra à un body semblable à :
}
```
Encore une fois, cela convertira les types de données, les validera, permettra de générer la documentation, etc...
Là encore, il convertira les types de données, validera, documentera, etc.
## Paramètres multiples body et query
## Plusieurs paramètres body et query { #multiple-body-params-and-query }
Bien entendu, vous pouvez déclarer autant de paramètres que vous le souhaitez, en plus des paramètres body déjà déclarés.
Bien entendu, vous pouvez aussi déclarer des paramètres de requête supplémentaires dès que vous en avez besoin, en plus de n'importe quels paramètres body.
Par défaut, les valeurs [scalaires](https://docs.github.com/fr/graphql/reference/scalars) sont interprétées comme des paramètres query, donc inutile d'ajouter explicitement `Query`. Vous pouvez juste écrire :
Comme, par défaut, les valeurs scalaires sont interprétées comme des paramètres de requête, vous n'avez pas besoin d'ajouter explicitement un `Query`, vous pouvez simplement faire :
```Python
q: Union[str, None] = None
```
Ou bien, en Python 3.10 et supérieur :
Ou en Python 3.10 et supérieur :
```Python
q: str | None = None
@@ -112,31 +114,33 @@ q: str | None = None
Par exemple :
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[27] *}
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
/// info
`Body` possède les mêmes paramètres de validation additionnels et de gestion des métadonnées que `Query` et `Path`, ainsi que d'autres que nous verrons plus tard.
/// info | info
`Body` possède aussi 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.
///
## Inclure un paramètre imbriqué dans le body
## Inclure un seul paramètre body { #embed-a-single-body-parameter }
Disons que vous avez seulement un paramètre `item` dans le body, correspondant à un modèle Pydantic `Item`.
Disons que vous n'avez qu'un seul paramètre body `item` issu d'un modèle Pydantic `Item`.
Par défaut, **FastAPI** attendra sa déclaration directement dans le body.
Par défaut, **FastAPI** s'attendra alors à son corps directement.
Cependant, si vous souhaitez qu'il interprête correctement un JSON avec une clé `item` associée au contenu du modèle, comme cela serait le cas si vous déclariez des paramètres body additionnels, vous pouvez utiliser le paramètre spécial `embed` de `Body` :
Mais si vous voulez qu'il s'attende à un JSON avec une clé `item` et, à l'intérieur, le contenu du modèle, comme il le fait lorsque vous déclarez des paramètres body supplémentaires, vous pouvez utiliser le paramètre spécial `embed` de `Body` :
```Python
item: Item = Body(embed=True)
```
Voici un exemple complet :
comme dans :
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
Dans ce cas **FastAPI** attendra un body semblable à :
Dans ce cas **FastAPI** s'attendra à un corps comme :
```JSON hl_lines="2"
{
@@ -160,12 +164,12 @@ au lieu de :
}
```
## Pour résumer
## Récapitulatif { #recap }
Vous pouvez ajouter plusieurs paramètres body dans votre fonction de routage, même si une requête ne peut avoir qu'un seul body.
Vous pouvez ajouter plusieurs paramètres body à votre *fonction de chemin d'accès*, même si une requête ne peut avoir qu'un seul corps.
Cependant, **FastAPI** se chargera de faire opérer sa magie, afin de toujours fournir à votre fonction des données correctes, les validera et documentera le schéma associé.
Mais **FastAPI** le gérera, vous donnera les données correctes dans votre fonction, et validera et documentera le schéma correct dans le *chemin d'accès*.
Vous pouvez également déclarer des valeurs [scalaires](https://docs.github.com/fr/graphql/reference/scalars) à recevoir dans le body.
Vous pouvez aussi déclarer des valeurs scalaires à recevoir dans le corps.
Et vous pouvez indiquer à **FastAPI** d'inclure le body dans une autre variable, même lorsqu'un seul paramètre est déclaré.
Et vous pouvez indiquer à **FastAPI** d'inclure le corps dans une clé même lorsqu'il n'y a qu'un seul paramètre déclaré.

View File

@@ -1,40 +1,41 @@
# Corps de la requête
# 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 des données depuis un client (disons, un navigateur) vers votre API, vous les 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.
Le corps d'une **requête** est des données envoyées 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**.
Votre API a presque toujours besoin d'envoyer un corps de **réponse**. Mais les clients n'ont pas nécessairement besoin d'envoyer des **corps de requête** en permanence, parfois ils demandent seulement un chemin, peut-être avec des paramètres de requête, mais n'envoient pas de corps.
Pour déclarer un corps de **requête**, on utilise les modèles de <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> en profitant de tous leurs avantages et fonctionnalités.
/// info
Pour envoyer de la donnée, vous devriez utiliser : `POST` (le plus populaire), `PUT`, `DELETE` ou `PATCH`.
Pour envoyer des données, vous devriez utiliser l'une des méthodes suivantes : `POST` (la plus courante), `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 avec une requête `GET` a un comportement non défini dans les spécifications ; néanmoins, cela est supporté par FastAPI, uniquement 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.
Comme cela est déconseillé, la documentation interactive avec Swagger UI n'affichera pas la documentation du corps lors de l'utilisation de `GET`, et les proxys intermédiaires risquent de ne pas le supporter.
///
## Importez le `BaseModel` de Pydantic
## Importer le `BaseModel` de Pydantic { #import-pydantics-basemodel }
Commencez par importer la classe `BaseModel` du module `pydantic` :
Commencez par importer `BaseModel` depuis `pydantic` :
{* ../../docs_src/body/tutorial001.py hl[4] *}
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
## Créez votre modèle de données
## Créer votre modèle de données { #create-your-data-model }
Déclarez ensuite votre modèle de données en tant que classe qui hérite de `BaseModel`.
Utilisez les types Python standard pour tous les attributs :
{* ../../docs_src/body/tutorial001.py hl[7:11] *}
{* ../../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, cet attribut doit être renseigné dans le corps de la requête. Pour rendre ce champ optionnel simplement, utilisez `None` comme valeur par défaut.
Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) tel que :
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 requis. Sinon, il est requis. Utilisez `None` pour le rendre simplement optionnel.
Par exemple, le modèle ci-dessus déclare un « `object` » JSON (ou `dict` Python) tel que :
```JSON
{
@@ -45,7 +46,7 @@ Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) te
}
```
...`description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), cet "objet" JSON serait aussi valide :
... comme `description` et `tax` sont optionnels (avec une valeur par défaut de `None`), cet « `object` » JSON serait aussi valide :
```JSON
{
@@ -54,109 +55,112 @@ Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) te
}
```
## Déclarez-le comme paramètre
## Le déclarer comme paramètre { #declare-it-as-a-parameter }
Pour l'ajouter à votre *opération de chemin*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête :
Pour l'ajouter à votre *chemin d'accès*, déclarez-le de la même manière que vous avez déclaré les paramètres de chemin et de requête :
{* ../../docs_src/body/tutorial001.py hl[18] *}
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
...et déclarez que son type est le modèle que vous avez créé : `Item`.
... et déclarez son type comme étant le modèle que vous avez créé, `Item`.
## Résultats
## Résultats { #results }
En utilisant uniquement les déclarations de type Python, **FastAPI** réussit à :
Avec simplement cette déclaration de type Python, **FastAPI** va :
* Lire le contenu de la requête en tant que JSON.
* Lire le corps de la requête en tant que JSON.
* Convertir les types correspondants (si nécessaire).
* Valider la donnée.
* Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où était la donnée incorrecte.
* 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 (auto-complétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs.
* Générer des définitions <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> pour votre modèle, qui peuvent être utilisées où vous en avez besoin dans votre projet ensuite.
* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront donc utilisés par les documentations automatiquement générées.
* Valider les données.
* Si les données sont invalides, il renverra une erreur propre et claire, indiquant exactement où et quelles étaient les données incorrectes.
* Vous donner les données reçues dans le paramètre `item`.
* Comme vous l'avez 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 et leurs types.
* Générer des définitions <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> pour votre modèle ; vous pouvez aussi les utiliser ailleurs si cela a du sens pour votre projet.
* Ces schémas feront partie du schéma OpenAPI généré et seront utilisés par la documentation automatique <abbr title="User Interfaces - Interfaces utilisateur">UIs</abbr>.
## Documentation automatique
## Documentation automatique { #automatic-docs }
Les schémas JSON de vos modèles seront intégrés au schéma OpenAPI global de votre application, et seront donc affichés dans la documentation interactive de l'API :
Les JSON Schemas de vos modèles feront partie du schéma OpenAPI généré de votre application, et seront affichés dans la documentation interactive de l'API :
<img src="/img/tutorial/body/image01.png">
Et seront aussi utilisés dans chaque *opération de chemin* de la documentation utilisant ces modèles :
Et seront aussi utilisés dans la documentation de l'API au sein de chaque *chemin d'accès* qui en a besoin :
<img src="/img/tutorial/body/image02.png">
## Support de l'éditeur
## Support de l'éditeur { #editor-support }
Dans votre éditeur, vous aurez des annotations de types et de l'auto-complétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez utilisé un classique `dict` plutôt qu'un modèle Pydantic) :
Dans votre éditeur, à l'intérieur de votre fonction, vous obtiendrez des annotations de type et de la complétion partout (cela n'arriverait pas si vous receviez un `dict` au lieu d'un modèle Pydantic) :
<img src="/img/tutorial/body/image03.png">
Et vous obtenez aussi de la vérification d'erreur pour les opérations incorrectes de types :
Vous obtenez aussi des vérifications d'erreur pour les opérations incorrectes de types :
<img src="/img/tutorial/body/image04.png">
Ce n'est pas un hasard, ce framework entier a été bâti avec ce design comme objectif.
Ce n'est pas un hasard, ce framework entier a été bâti autour de ce design.
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.
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.
Des changements sur Pydantic ont même été faits pour supporter cela.
Des changements ont même été faits sur Pydantic lui-même pour supporter cela.
Les captures d'écrans précédentes ont été prises sur <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
Les captures d'écrans précédentes ont été prises avec <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
Mais vous auriez le même support de l'éditeur avec <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> et la majorité des autres éditeurs de code Python.
Mais vous auriez le même support de l'éditeur avec <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> et la plupart des autres éditeurs Python :
<img src="/img/tutorial/body/image05.png">
/// tip | Astuce
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le Plugin <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
Ce qui améliore le support pour les modèles Pydantic avec :
Il améliore le support de l'éditeur pour les modèles Pydantic, avec :
* de l'auto-complétion
* des vérifications de type
* du "refactoring" (ou remaniement de code)
* de la recherche
* de l'inspection
* autocomplétion
* vérifications de type
* refactoring
* recherche
* inspections
///
## Utilisez le modèle
## Utiliser le modèle { #use-the-model }
Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement :
À l'intérieur de la fonction, vous pouvez accéder directement à tous les attributs de l'objet du modèle :
{* ../../docs_src/body/tutorial002.py hl[21] *}
{* ../../docs_src/body/tutorial002_py310.py *}
## Corps de la requête + paramètres de chemin
## 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 *opération de chemin*.
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** reconnaîtra 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 fonction déclarés comme modèles Pydantic doivent être **récupérés depuis le corps de la requête**.
{* ../../docs_src/body/tutorial003.py hl[17:18] *}
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
## Corps de la requête + paramètres de chemin et de requête
Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête** dans la même *opération de chemin*.
## Corps de la requête + paramètres de chemin et de requête { #request-body-path-query-parameters }
**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit.
Vous pouvez aussi déclarer des paramètres de **corps**, de **chemin** et de **requête**, tous en même temps.
{* ../../docs_src/body/tutorial004.py hl[18] *}
**FastAPI** reconnaîtra chacun d'entre eux et récupérera les données au bon endroit.
Les paramètres de la fonction seront reconnus comme tel :
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
Les paramètres de la fonction seront reconnus comme suit :
* Si le paramètre est aussi déclaré dans le **chemin**, il sera utilisé comme paramètre de chemin.
* Si le paramètre est d'un **type singulier** (comme `int`, `float`, `str`, `bool`, etc.), il sera interprété comme un paramètre de **requête**.
* Si le paramètre est déclaré comme ayant pour type un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête.
* Si le paramètre est déclaré comme étant du type d'un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête.
/// note
/// 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`.
Le type `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI**, mais sera utile à votre éditeur pour améliorer le support offert par ce dernier et détecter plus facilement des erreurs de type.
Le `str | None` (Python 3.10+) ou `Union` dans `Union[str, None]` (Python 3.9+) n'est pas utilisé par FastAPI pour déterminer que la valeur n'est pas requise ; il saura qu'elle n'est pas requise parce qu'elle a une valeur par défaut `= None`.
Mais ajouter les annotations de type permettra à votre éditeur de vous offrir un meilleur support et de détecter des erreurs.
///
## Sans Pydantic
## Sans Pydantic { #without-pydantic }
Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Corps**. Pour cela, allez voir la partie de la documentation sur [Corps de la requête - Paramètres multiples](body-multiple-params.md){.internal-link target=_blank}.
Si vous ne voulez pas utiliser de modèles Pydantic, vous pouvez aussi utiliser des paramètres **Body**. Consultez les documents pour [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.

View File

@@ -1,14 +1,14 @@
# <abbr title="En anglais: Debugging">Débogage</abbr>
# Débogage { #debugging }
Vous pouvez connecter le <abbr title="En anglais: debugger">débogueur</abbr> dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
Vous pouvez connecter le débogueur dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
## Faites appel à `uvicorn`
## Faites appel à `uvicorn` { #call-uvicorn }
Dans votre application FastAPI, importez et exécutez directement `uvicorn` :
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
### À propos de `__name__ == "__main__"`
### À propos de `__name__ == "__main__"` { #about-name-main }
Le but principal de `__name__ == "__main__"` est d'avoir du code qui est exécuté lorsque votre fichier est appelé avec :
@@ -26,7 +26,7 @@ mais qui n'est pas appelé lorsqu'un autre fichier l'importe, comme dans :
from myapp import app
```
#### Pour davantage de détails
#### Pour davantage de détails { #more-details }
Imaginons que votre fichier s'appelle `myapp.py`.
@@ -54,12 +54,12 @@ va s'exécuter.
Cela ne se produira pas si vous importez ce module (fichier).
Par exemple, si vous avez un autre fichier `importer.py` qui contient :
Ainsi, si vous avez un autre fichier `importer.py` qui contient :
```Python
from myapp import app
# Code supplémentaire
# Some more code
```
dans ce cas, la variable automatique `__name__` à l'intérieur de `myapp.py` n'aura pas la valeur `"__main__"`.
@@ -78,18 +78,18 @@ Pour plus d'informations, consultez <a href="https://docs.python.org/3/library/_
///
## Exécutez votre code avec votre <abbr title="En anglais: debugger">débogueur</abbr>
## Exécutez votre code avec votre débogueur { #run-your-code-with-your-debugger }
Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le <abbr title="En anglais: debugger">débogueur</abbr>.
Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le débogueur.
---
Par exemple, dans Visual Studio Code, vous pouvez :
- Cliquer sur l'onglet "Debug" de la barre d'activités de Visual Studio Code.
- "Add configuration...".
- Sélectionnez "Python".
- Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option "`Python: Current File (Integrated Terminal)`".
* Aller dans le panneau « Debug ».
* « Add configuration... ».
* Sélectionner « Python »
* Lancer le débogueur 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.
@@ -101,10 +101,10 @@ Voici à quoi cela pourrait ressembler :
Si vous utilisez Pycharm, vous pouvez :
- Ouvrir 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`).
* Ouvrir le menu « Run ».
* Sélectionner l'option « Debug... ».
* Un menu contextuel s'affiche alors.
* Sélectionner 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.

View File

@@ -1,107 +1,122 @@
# Démarrage
# Premiers pas { #first-steps }
Le fichier **FastAPI** le plus simple possible pourrait ressembler à cela :
Le fichier **FastAPI** le plus simple possible pourrait ressembler à ceci :
{* ../../docs_src/first_steps/tutorial001.py *}
{* ../../docs_src/first_steps/tutorial001_py39.py *}
Copiez ce code dans un fichier nommé `main.py`.
Copiez cela dans un fichier `main.py`.
Démarrez le serveur :
Lancez le serveur de développement :
<div class="termy">
```console
$ uvicorn main:app --reload
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
Searching for package file structure from directories
with <font color="#3465A4">__init__.py</font> files
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
the following code:
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
<b>fastapi run</b>
Logs:
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
<b>[</b><font color="#4E9A06">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
to quit<b>)</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
```
</div>
/// note
La commande `uvicorn main:app` fait référence à :
* `main` : le fichier `main.py` (le module Python).
* `app` : l'objet créé dans `main.py` via la ligne `app = FastAPI()`.
* `--reload` : l'option disant à uvicorn de redémarrer le serveur à chaque changement du code. À ne pas utiliser en production !
///
Vous devriez voir dans la console, une ligne semblable à la suivante :
Dans la sortie, il y a une ligne qui ressemble à :
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
Cette ligne montre l'URL par laquelle l'app est actuellement accessible, sur votre machine locale.
Cette ligne affiche lURL à laquelle votre app est servie, sur votre machine locale.
### Allez voir le résultat
### Vérifiez { #check-it }
Ouvrez votre navigateur à l'adresse <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
Ouvrez votre navigateur à ladresse <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
Vous obtiendrez cette réponse JSON :
Vous verrez la réponse JSON :
```JSON
{"message": "Hello World"}
```
### Documentation interactive de l'API
### Documentation interactive de lAPI { #interactive-api-docs }
Rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Rendez-vous maintenant sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Vous verrez la documentation interactive de l'API générée automatiquement (via <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
Vous verrez la documentation interactive de lAPI générée automatiquement (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Documentation alternative
### Documentation alternative de lAPI { #alternative-api-docs }
Ensuite, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Et maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
Vous y verrez la documentation alternative (via <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
Vous verrez la documentation alternative générée automatiquement (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
### OpenAPI
### OpenAPI { #openapi }
**FastAPI** génère un "schéma" contenant toute votre API dans le standard de définition d'API **OpenAPI**.
**FastAPI** génère un « schéma » contenant toute votre API en utilisant le standard **OpenAPI** pour définir les API.
#### "Schéma"
#### « Schéma » { #schema }
Un "schéma" est une définition ou une description de quelque chose. Pas le code qui l'implémente, uniquement une description abstraite.
Un « schéma » est une définition ou une description de quelque chose. Pas le code qui limplémente, mais simplement une description abstraite.
#### "Schéma" d'API
#### « Schéma » dAPI { #api-schema }
Ici, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> est une spécification qui dicte comment définir le schéma de votre API.
Dans ce cas, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> est une spécification qui dicte comment définir un schéma de votre API.
Le schéma inclut les chemins de votre API, les paramètres potentiels de chaque chemin, etc.
Cette définition de schéma inclut les chemins de votre API, les paramètres possibles quils acceptent, etc.
#### "Schéma" de données
#### « Schéma » de données { #data-schema }
Le terme "schéma" peut aussi faire référence à la forme de la donnée, comme un contenu JSON.
Le terme « schéma » peut aussi faire référence à la structure de certaines données, comme un contenu JSON.
Dans ce cas, cela signifierait les attributs JSON, ainsi que les types de ces attributs, etc.
Dans ce cas, cela signifierait les attributs JSON, et les types de données quils ont, etc.
#### OpenAPI et JSON Schema
#### OpenAPI et JSON Schema { #openapi-and-json-schema }
**OpenAPI** définit un schéma d'API pour votre API. Il inclut des définitions (ou "schémas") de la donnée envoyée et reçue par votre API en utilisant **JSON Schema**, le standard des schémas de données JSON.
OpenAPI définit un schéma dAPI pour votre API. Et ce schéma inclut des définitions (ou des « schémas ») des données envoyées et reçues par votre API en utilisant **JSON Schema**, le standard des schémas de données JSON.
#### Allez voir `openapi.json`
#### Vérifiez le `openapi.json` { #check-the-openapi-json }
Si vous êtes curieux d'à quoi ressemble le schéma brut **OpenAPI**, **FastAPI** génère automatiquement un (schéma) JSON avec les descriptions de toute votre API.
Si vous êtes curieux de voir à quoi ressemble le schéma OpenAPI brut, FastAPI génère automatiquement un (schéma) JSON avec les descriptions de toute votre API.
Vous pouvez le voir directement à cette adresse : <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
Le schéma devrait ressembler à ceci :
Vous pouvez le voir directement à ladresse : <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
Il affichera un JSON commençant par quelque chose comme :
```JSON
{
"openapi": "3.0.2",
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
@@ -120,79 +135,87 @@ Le schéma devrait ressembler à ceci :
...
```
#### À quoi sert OpenAPI
#### À quoi sert OpenAPI { #what-is-openapi-for }
Le schéma **OpenAPI** est ce qui alimente les deux systèmes de documentation interactive.
Le schéma OpenAPI est ce qui alimente les deux systèmes de documentation interactive inclus.
Et il existe des dizaines d'alternatives, toutes basées sur **OpenAPI**. Vous pourriez facilement ajouter n'importe laquelle de ces alternatives à votre application **FastAPI**.
Et il existe des dizaines dalternatives, toutes basées sur OpenAPI. Vous pourriez facilement ajouter nimporte laquelle de ces alternatives à votre application construite avec **FastAPI**.
Vous pourriez aussi l'utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Comme par exemple, des applications frontend, mobiles ou IOT.
Vous pourriez aussi lutiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Par exemple, des applications frontend, mobiles ou IoT.
## Récapitulatif, étape par étape
### Déployer votre app (optionnel) { #deploy-your-app-optional }
### Étape 1 : import `FastAPI`
Vous pouvez, de manière optionnelle, déployer votre app FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> ; allez vous inscrire sur la liste dattente si ce nest pas déjà fait. 🚀
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste dattente 😉), vous pouvez déployer votre application avec une seule commande.
`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires au lancement de votre API.
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>
Ensuite, déployez votre app :
<div class="termy">
```console
$ fastapi deploy
Deploying to FastAPI Cloud...
✅ Deployment successful!
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
```
</div>
Cest tout ! Vous pouvez maintenant accéder à votre app à cette URL. ✨
## Récapitulatif, étape par étape { #recap-step-by-step }
### Étape 1 : importer `FastAPI` { #step-1-import-fastapi }
{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
`FastAPI` est une classe Python qui fournit toutes les fonctionnalités pour votre API.
/// note | Détails techniques
`FastAPI` est une classe héritant directement de `Starlette`.
`FastAPI` est une classe qui hérite directement de `Starlette`.
Vous pouvez donc aussi utiliser toutes les fonctionnalités de <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> depuis `FastAPI`.
Vous pouvez aussi utiliser toutes les fonctionnalités de <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> avec `FastAPI`.
///
### Étape 2 : créer une "instance" `FastAPI`
### Étape 2 : créer une « instance » `FastAPI` { #step-2-create-a-fastapi-instance }
{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
Ici la variable `app` sera une "instance" de la classe `FastAPI`.
Ici, la variable `app` sera une « instance » de la classe `FastAPI`.
Ce sera le point principal d'interaction pour créer toute votre API.
Ce sera le point principal dinteraction pour créer toute votre API.
Cette `app` est la même que celle à laquelle fait référence `uvicorn` dans la commande :
### Étape 3 : créer un *chemin d'accès* { #step-3-create-a-path-operation }
<div class="termy">
#### Chemin { #path }
```console
$ uvicorn main:app --reload
« Path » fait référence ici à la dernière partie de lURL à partir du premier `/`.
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Si vous créez votre app avec :
{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
Et la mettez dans un fichier `main.py`, alors vous appelleriez `uvicorn` avec :
<div class="termy">
```console
$ uvicorn main:my_awesome_api --reload
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
### Étape 3: créer une *opération de chemin*
#### Chemin
Chemin, ou "path" fait référence ici à la dernière partie de l'URL démarrant au premier `/`.
Donc, dans un URL tel que :
Donc, dans une URL comme :
```
https://example.com/items/foo
```
...le "path" serait :
... le « path » serait :
```
/items/foo
@@ -200,66 +223,67 @@ https://example.com/items/foo
/// info
Un chemin, ou "path" est aussi souvent appelé route ou "endpoint".
Un « path » est aussi communément appelé un « endpoint » ou une « route ».
///
#### Opération
Lors de la construction dune API, le « path » est la principale façon de séparer les « préoccupations » et les « ressources ».
"Opération" fait référence à une des "méthodes" HTTP.
#### Opération { #operation }
Une de :
« Opération » fait référence ici à lune des « méthodes » HTTP.
Lune de :
* `POST`
* `GET`
* `PUT`
* `DELETE`
...ou une des plus exotiques :
... et les plus exotiques :
* `OPTIONS`
* `HEAD`
* `PATCH`
* `TRACE`
Dans le protocol HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plus) de ces "méthodes".
Dans le protocole HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plusieurs) de ces « méthodes ».
---
En construisant des APIs, vous utilisez généralement ces méthodes HTTP spécifiques pour effectuer une action précise.
Lors de la construction dAPI, vous utilisez normalement ces méthodes HTTP spécifiques pour effectuer une action précise.
Généralement vous utilisez :
Normalement vous utilisez :
* `POST` : pour créer de la donnée.
* `GET` : pour lire de la donnée.
* `PUT` : pour mettre à jour de la donnée.
* `DELETE` : pour supprimer de la donnée.
* `POST` : pour créer des données.
* `GET` : pour lire des données.
* `PUT` : pour mettre à jour des données.
* `DELETE` : pour supprimer des données.
Donc, dans **OpenAPI**, chaque méthode HTTP est appelée une "opération".
Donc, dans OpenAPI, chacune des méthodes HTTP est appelée une « opération ».
Nous allons donc aussi appeler ces dernières des "**opérations**".
Nous allons aussi les appeler des « **opérations** ».
#### Définir un *décorateur de chemin d'accès* { #define-a-path-operation-decorator }
#### Définir un *décorateur d'opération de chemin*
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
Le `@app.get("/")` dit à **FastAPI** que la fonction en dessous est chargée de gérer les requêtes qui vont sur :
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 <abbr title="une méthode GET HTTP">opération <code>get</code></abbr>
* en utilisant une <abbr title="an HTTP GET method">opération <code>get</code></abbr>
/// info | `@décorateur` Info
/// info | `@decorator` Info
Cette syntaxe `@something` en Python est appelée un "décorateur".
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 ce terme vient de là 🤷🏻‍♂).
Vous le mettez au-dessus dune fonction. Comme un joli chapeau décoratif (jimagine que cest de là que le terme vient).
Un "décorateur" prend la fonction en dessous et en fait quelque chose.
Un « décorateur » prend la fonction en dessous et fait quelque chose avec elle.
Dans notre cas, ce décorateur dit à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec l'**opération** `get`.
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 d'opération de chemin**".
Cest le « **décorateur de chemin d'accès** ».
///
@@ -269,7 +293,7 @@ Vous pouvez aussi utiliser les autres opérations :
* `@app.put()`
* `@app.delete()`
Tout comme celles les plus exotiques :
Et les plus exotiques :
* `@app.options()`
* `@app.head()`
@@ -278,58 +302,79 @@ Tout comme celles les plus exotiques :
/// tip | Astuce
Vous êtes libres d'utiliser chaque opération (méthode HTTP) comme vous le désirez.
Vous êtes libre dutiliser chaque opération (méthode HTTP) comme vous le souhaitez.
**FastAPI** n'impose pas de sens spécifique à chacune d'elle.
**FastAPI** nimpose aucun sens spécifique.
Les informations qui sont présentées ici forment une directive générale, pas des obligations.
Les informations présentées ici servent de guide, pas dexigence.
Par exemple, quand l'on utilise **GraphQL**, toutes les actions sont effectuées en utilisant uniquement des opérations `POST`.
Par exemple, quand vous utilisez GraphQL, vous effectuez normalement toutes les actions en utilisant uniquement des opérations `POST`.
///
### Étape 4 : définir la **fonction de chemin**.
### Étape 4 : définir la **fonction de chemin d'accès** { #step-4-define-the-path-operation-function }
Voici notre "**fonction de chemin**" (ou fonction d'opération de chemin) :
Voici notre « **fonction de chemin d'accès** » :
* **chemin** : `/`.
* **opération** : `get`.
* **fonction** : la fonction sous le "décorateur" (sous `@app.get("/")`).
* **chemin** : est `/`.
* **opération** : est `get`.
* **fonction** : est la fonction sous le « décorateur » (sous `@app.get("/")`).
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
C'est une fonction Python.
Cest une fonction Python.
Elle sera appelée par **FastAPI** quand une requête sur l'URL `/` sera reçue via une opération `GET`.
Elle sera appelée par **FastAPI** chaque fois quil recevra une requête vers lURL « `/` » en utilisant une opération `GET`.
Ici, c'est une fonction asynchrone (définie avec `async def`).
Dans ce cas, cest une fonction `async`.
---
Vous pourriez aussi la définir comme une fonction classique plutôt qu'avec `async def` :
Vous pourriez aussi la définir comme une fonction normale au lieu de `async def` :
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
/// note
/// note | Remarque
Si vous ne connaissez pas la différence, allez voir la section [Concurrence : *"Vous êtes pressés ?"*](../async.md#vous-etes-presses){.internal-link target=_blank}.
Si vous ne connaissez pas la différence, consultez [Async : *« Pressé ? »*](../async.md#in-a-hurry){.internal-link target=_blank}.
///
### Étape 5 : retourner le contenu
### Étape 5 : retourner le contenu { #step-5-return-the-content }
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
Vous pouvez retourner un dictionnaire (`dict`), une liste (`list`), des valeurs seules comme des chaines de caractères (`str`) et des entiers (`int`), etc.
Vous pouvez retourner un `dict`, `list`, des valeurs seules comme `str`, `int`, etc.
Vous pouvez aussi retourner des models **Pydantic** (qui seront détaillés plus tard).
Vous pouvez aussi retourner des modèles Pydantic (vous en verrez plus à ce sujet plus tard).
Il y a de nombreux autres objets et modèles qui seront automatiquement convertis en JSON. Essayez d'utiliser vos favoris, il est fort probable qu'ils soient déjà supportés.
Il y a de nombreux autres objets et modèles qui seront automatiquement convertis en JSON (y compris les ORM, etc). Essayez dutiliser vos favoris, il est très probable quils soient déjà pris en charge.
## Récapitulatif
### Étape 6 : le déployer { #step-6-deploy-it }
Déployez votre app sur **<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** avec une seule commande : `fastapi deploy`. 🎉
#### À propos de FastAPI Cloud { #about-fastapi-cloud }
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est construit par le même auteur et la même équipe derrière **FastAPI**.
Il simplifie le processus de **construction**, de **déploiement** et d**accès** à une API avec un effort minimal.
Il apporte la même **developer experience** de construction dapps avec FastAPI au **déploiement** dans le cloud. 🎉
FastAPI Cloud est le sponsor principal et le fournisseur de financement pour les projets open source *FastAPI and friends*. ✨
#### Déployer sur dautres fournisseurs cloud { #deploy-to-other-cloud-providers }
FastAPI est open source et basé sur des standards. Vous pouvez déployer des apps FastAPI sur nimporte quel fournisseur cloud de votre choix.
Suivez les guides de votre fournisseur cloud pour y déployer des apps FastAPI. 🤓
## Récapitulatif { #recap }
* Importez `FastAPI`.
* Créez une instance d'`app`.
* Ajoutez une **décorateur d'opération de chemin** (tel que `@app.get("/")`).
* Ajoutez une **fonction de chemin** (telle que `def root(): ...` comme ci-dessus).
* Lancez le serveur de développement (avec `uvicorn main:app --reload`).
* Créez une instance `app`.
* Écrivez un **décorateur de chemin d'accès** en utilisant des décorateurs comme `@app.get("/")`.
* Définissez une **fonction de chemin d'accès** ; par exemple, `def root(): ...`.
* Lancez le serveur de développement avec la commande `fastapi dev`.
* Déployez votre app de manière optionnelle avec `fastapi deploy`.

View File

@@ -1,83 +1,95 @@
# Tutoriel - Guide utilisateur - Introduction
# 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ésoudre vos besoins spécifiques en matière d'API.
Il est également conçu pour fonctionner comme une référence future.
Il est également conçu pour fonctionner comme une référence future afin que vous puissiez revenir et voir exactement ce dont vous avez besoin.
Vous pouvez donc revenir et voir exactement ce dont vous avez besoin.
## Exécuter le code
## Exécuter le code { #run-the-code }
Tous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés).
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et commencez `uvicorn` avec :
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et démarrez `fastapi dev` avec :
<div class="termy">
```console
$ uvicorn main:app --reload
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
<span style="color: green;">INFO</span>: Started reloader process [28720]
<span style="color: green;">INFO</span>: Started server process [28722]
<span style="color: green;">INFO</span>: Waiting for application startup.
<span style="color: green;">INFO</span>: Application startup complete.
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting development server 🚀
Searching for package file structure from directories
with <font color="#3465A4">__init__.py</font> files
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
the following code:
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000/docs</u></font>
<span style="background-color:#007166"><font color="#D3D7CF"> tip </font></span> Running in development mode, for production use:
<b>fastapi run</b>
Logs:
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Will watch for changes in these directories:
<b>[</b><font color="#4E9A06">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C
to quit<b>)</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started reloader process <b>[</b><font color="#34E2E2"><b>383138</b></font><b>]</b> using WatchFiles
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>383153</b></font><b>]</b>
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
```
</div>
Il est **FORTEMENT encouragé** que vous écriviez ou copiez le code, l'éditiez et l'exécutiez localement.
Il est **FORTEMENT encouragé** que vous écriviez ou copiiez le code, l'éditiez et l'exécutiez localement.
L'utiliser dans votre éditeur est ce qui vous montre vraiment les avantages de FastAPI, en voyant le peu de code que vous avez à écrire, toutes les vérifications de type, l'autocomplétion, etc.
---
## Installer FastAPI
## Installer FastAPI { #install-fastapi }
La première étape consiste à installer FastAPI.
Pour le tutoriel, vous voudrez peut-être l'installer avec toutes les dépendances et fonctionnalités optionnelles :
Vous devez vous assurer de créer un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis **d'installer FastAPI** :
<div class="termy">
```console
$ pip install fastapi[all]
$ pip install "fastapi[standard]"
---> 100%
```
</div>
... qui comprend également `uvicorn`, que vous pouvez utiliser comme serveur pour exécuter votre code.
/// note | Remarque
/// note
Lorsque vous installez avec `pip install "fastapi[standard]"`, cela inclut certaines dépendances standard optionnelles par défaut, notamment `fastapi-cloud-cli`, qui vous permet de déployer sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
Vous pouvez également l'installer pièce par pièce.
Si vous ne voulez pas avoir ces dépendances optionnelles, vous pouvez installer `pip install fastapi` à la place.
C'est ce que vous feriez probablement une fois que vous voudrez déployer votre application en production :
```
pip install fastapi
```
Installez également `uvicorn` pour qu'il fonctionne comme serveur :
```
pip install uvicorn
```
Et la même chose pour chacune des dépendances facultatives que vous voulez utiliser.
Si vous voulez installer les dépendances standard mais sans le `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
///
## Guide utilisateur avancé
## Guide utilisateur avancé { #advanced-user-guide }
Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**.
Il existe également un **Guide utilisateur avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide utilisateur**.
Le **Guide d'utilisation avancé**, qui s'appuie sur cette base, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
Le **Guide utilisateur avancé** s'appuie sur celui-ci, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
Mais vous devez d'abord lire le **Tutoriel - Guide d'utilisation** (ce que vous êtes en train de lire en ce moment).
Mais vous devez d'abord lire le **Tutoriel - Guide utilisateur** (ce que vous êtes en train de lire en ce moment).
Il est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide d'utilisation**, puis l'étendre de différentes manières, en fonction de vos besoins, en utilisant certaines des idées supplémentaires du **Guide d'utilisation avancé**.
Il est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide utilisateur**, puis l'étendre de différentes manières, en fonction de vos besoins, en utilisant certaines des idées supplémentaires du **Guide utilisateur avancé**.

View File

@@ -1,8 +1,8 @@
# Paramètres de chemin et validations numériques
# Paramètres de chemin et validations numériques { #path-parameters-and-numeric-validations }
De la même façon que vous pouvez déclarer plus de validations et de métadonnées pour les paramètres de requête avec `Query`, vous pouvez déclarer le même type de validations et de métadonnées pour les paramètres de chemin avec `Path`.
## Importer Path
## Importer `Path` { #import-path }
Tout d'abord, importez `Path` de `fastapi`, et importez `Annotated` :
@@ -12,29 +12,29 @@ Tout d'abord, importez `Path` de `fastapi`, et importez `Annotated` :
FastAPI a ajouté le support pour `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d'utiliser `Annotated`.
Si vous avez une version plus ancienne, vous obtiendriez des erreurs en essayant d'utiliser `Annotated`.
Assurez-vous de [Mettre à jour la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 à minima avant d'utiliser `Annotated`.
Assurez-vous de [Mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 à minima avant d'utiliser `Annotated`.
///
## Déclarer des métadonnées
## Déclarer des métadonnées { #declare-metadata }
Vous pouvez déclarer les mêmes paramètres que pour `Query`.
Vous pouvez déclarer tous les mêmes paramètres que pour `Query`.
Par exemple, pour déclarer une valeur de métadonnée `title` pour le paramètre de chemin `item_id`, vous pouvez écrire :
{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
/// note
/// note | Remarque
Un paramètre de chemin est toujours requis car il doit faire partie du chemin. Même si vous l'avez déclaré avec `None` ou défini une valeur par défaut, cela ne changerait rien, il serait toujours requis.
///
## Ordonnez les paramètres comme vous le souhaitez
## Ordonner les paramètres selon vos besoins { #order-the-parameters-as-you-need }
/// tip
/// tip | Astuce
Ce n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`.
@@ -46,23 +46,23 @@ Et vous n'avez pas besoin de déclarer autre chose pour ce paramètre, donc vous
Mais vous avez toujours besoin d'utiliser `Path` pour le paramètre de chemin `item_id`. Et vous ne voulez pas utiliser `Annotated` pour une raison quelconque.
Python se plaindra si vous mettez une valeur avec une "défaut" avant une valeur qui n'a pas de "défaut".
Python se plaindra si vous mettez une valeur avec une valeur « par défaut » avant une valeur qui n'a pas de valeur « par défaut ».
Mais vous pouvez les réorganiser, et avoir la valeur sans défaut (le paramètre de requête `q`) en premier.
Mais vous pouvez les réorganiser, et avoir la valeur sans valeur par défaut (le paramètre de requête `q`) en premier.
Cela n'a pas d'importance pour **FastAPI**. Il détectera les paramètres par leurs noms, types et déclarations par défaut (`Query`, `Path`, etc), il ne se soucie pas de l'ordre.
Ainsi, vous pouvez déclarer votre fonction comme suit :
{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *}
Mais gardez à l'esprit que si vous utilisez `Annotated`, vous n'aurez pas ce problème, cela n'aura pas d'importance car vous n'utilisez pas les valeurs par défaut des paramètres de fonction pour `Query()` ou `Path()`.
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py hl[10] *}
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
## Ordonnez les paramètres comme vous le souhaitez (astuces)
## Ordonner les paramètres selon vos besoins, astuces { #order-the-parameters-as-you-need-tricks }
/// tip
/// tip | Astuce
Ce n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`.
@@ -77,38 +77,29 @@ Si vous voulez :
* les avoir dans un ordre différent
* ne pas utiliser `Annotated`
...Python a une petite syntaxe spéciale pour cela.
... Python a une petite syntaxe spéciale pour cela.
Passez `*`, comme premier paramètre de la fonction.
Python ne fera rien avec ce `*`, mais il saura que tous les paramètres suivants doivent être appelés comme arguments "mots-clés" (paires clé-valeur), également connus sous le nom de <abbr title="De : K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Même s'ils n'ont pas de valeur par défaut.
Python ne fera rien avec ce `*`, mais il saura que tous les paramètres suivants doivent être appelés comme arguments par mot-clé (paires clé-valeur), également connus sous le nom de <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Même s'ils n'ont pas de valeur par défaut.
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
# Avec `Annotated`
### Mieux avec `Annotated` { #better-with-annotated }
Gardez à l'esprit que si vous utilisez `Annotated`, comme vous n'utilisez pas les valeurs par défaut des paramètres de fonction, vous n'aurez pas ce problème, et vous n'aurez probablement pas besoin d'utiliser `*`.
{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
## Validations numériques : supérieur ou égal
## Validations numériques : supérieur ou égal { #number-validations-greater-than-or-equal }
Avec `Query` et `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des contraintes numériques.
Ici, avec `ge=1`, `item_id` devra être un nombre entier "`g`reater than or `e`qual" à `1`.
Ici, avec `ge=1`, `item_id` devra être un nombre entier « `g`reater than or `e`qual » à `1`.
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
## Validations numériques : supérieur ou égal et inférieur ou égal
La même chose s'applique pour :
* `gt` : `g`reater `t`han
* `le` : `l`ess than or `e`qual
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
## Validations numériques : supérieur et inférieur ou égal
## Validations numériques : supérieur et inférieur ou égal { #number-validations-greater-than-and-less-than-or-equal }
La même chose s'applique pour :
@@ -117,7 +108,7 @@ La même chose s'applique pour :
{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
## Validations numériques : flottants, supérieur et inférieur
## Validations numériques : flottants, supérieur et inférieur { #number-validations-floats-greater-than-and-less-than }
Les validations numériques fonctionnent également pour les valeurs `float`.
@@ -129,9 +120,9 @@ Et la même chose pour <abbr title="less than"><code>lt</code></abbr>.
{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
## Pour résumer
## Pour résumer { #recap }
Avec `Query`, `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des métadonnées et des validations de chaînes de la même manière qu'avec les [Paramètres de requête et validations de chaînes](query-params-str-validations.md){.internal-link target=_blank}.
Avec `Query`, `Path` (et d'autres que vous n'avez pas encore vus) vous pouvez déclarer des métadonnées et des validations de chaînes de la même manière qu'avec les [Paramètres de requête et validations de chaînes](query-params-str-validations.md){.internal-link target=_blank}.
Et vous pouvez également déclarer des validations numériques :
@@ -144,7 +135,7 @@ Et vous pouvez également déclarer des validations numériques :
`Query`, `Path`, et d'autres classes que vous verrez plus tard sont des sous-classes d'une classe commune `Param`.
Tous partagent les mêmes paramètres pour des validations supplémentaires et des métadonnées que vous avez vu précédemment.
Tous partagent les mêmes paramètres pour des validations supplémentaires et des métadonnées que vous avez vus.
///

View File

@@ -1,205 +1,196 @@
# Paramètres de chemin
# Paramètres de chemin { #path-parameters }
Vous pouvez déclarer des "paramètres" ou "variables" de chemin avec la même syntaxe que celle utilisée par le
<a href="https://docs.python.org/fr/3/library/string.html#format-string-syntax" class="external-link" target="_blank">formatage de chaîne Python</a> :
Vous pouvez déclarer des « paramètres » ou « variables » de chemin avec la même syntaxe que celle utilisée par les chaînes de format Python :
{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
La valeur du paramètre de chemin `item_id` sera transmise à votre fonction comme argument `item_id`.
La valeur du paramètre `item_id` sera transmise à la fonction dans l'argument `item_id`.
Donc, si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>,
vous verrez comme réponse :
Donc, si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous verrez comme réponse :
```JSON
{"item_id":"foo"}
```
## Paramètres de chemin typés
## Paramètres de chemin typés { #path-parameters-with-types }
Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python :
Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type standard de Python :
{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
{* ../../docs_src/path_params/tutorial002.py hl[7] *}
Dans ce cas, `item_id` est déclaré comme `int`.
Ici, `item_id` est déclaré comme `int`.
/// check | Vérifications
/// check | vérifier
Ceci vous permettra d'obtenir des fonctionnalités de l'éditeur dans votre fonction, telles
que des vérifications d'erreur, de l'auto-complétion, etc.
Cela vous donnera le support de l'éditeur dans votre fonction, avec des vérifications d'erreurs, l'autocomplétion, etc.
///
## <abbr title="aussi appelé sérialisation, ou parfois parsing ou marshalling en anglais">Conversion</abbr> de données
## <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Conversion</abbr> de données { #data-conversion }
Si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, vous aurez comme réponse :
Si vous exécutez cet exemple et ouvrez votre navigateur sur <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, vous verrez comme réponse :
```JSON
{"item_id":3}
```
/// check | vérifier
/// check | Vérifications
Comme vous l'avez remarqué, la valeur reçue par la fonction (et renvoyée ensuite) est `3`,
en tant qu'entier (`int`) Python, pas la chaîne de caractères (`string`) `"3"`.
Remarquez que la valeur reçue par votre fonction (et renvoyée) est `3`, comme un `int` Python, pas une chaîne « 3 ».
Grâce aux déclarations de types, **FastAPI** fournit du
<abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">"parsing"</abbr> automatique.
Ainsi, avec cette déclaration de type, **FastAPI** vous fournit le <abbr title="conversion de la chaîne provenant d'une requête HTTP en données Python">« parsing »</abbr> automatique de la requête.
///
## Validation de données
## Validation de données { #data-validation }
Si vous allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous aurez une belle erreur HTTP :
Mais si vous allez dans le navigateur sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous verrez une belle erreur HTTP :
```JSON
{
"detail": [
{
"loc": [
"path",
"item_id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
"detail": [
{
"type": "int_parsing",
"loc": [
"path",
"item_id"
],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo"
}
]
}
```
car le paramètre de chemin `item_id` possède comme valeur `"foo"`, qui ne peut pas être convertie en entier (`int`).
car le paramètre de chemin `item_id` avait la valeur « foo », qui n'est pas un `int`.
La même erreur se produira si vous passez un nombre flottant (`float`) et non un entier, comme ici
<a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>.
La même erreur apparaîtrait si vous fournissiez un `float` au lieu d'un `int`, comme ici : <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
/// check | Vérifications
/// check | vérifier
Ainsi, avec la même déclaration de type Python, **FastAPI** vous fournit une validation de données.
Donc, avec ces mêmes déclarations de type Python, **FastAPI** vous fournit de la validation de données.
Remarquez que l'erreur indique aussi clairement le point exact où la validation n'est pas passée.
Notez que l'erreur mentionne le point exact où la validation n'a pas réussi.
Ce qui est incroyablement utile au moment de développer et débugger du code qui interagit avec votre API.
C'est incroyablement utile lors du développement et du débogage de code qui interagit avec votre API.
///
## Documentation
## Documentation { #documentation }
Et quand vous vous rendez sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, vous verrez la
documentation générée automatiquement et interactive :
Et lorsque vous ouvrez votre navigateur sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, vous verrez une documentation d'API automatique et interactive comme :
<img src="/img/tutorial/path-params/image01.png">
/// info
/// check | Vérifications
À nouveau, en utilisant uniquement les déclarations de type Python, **FastAPI** vous fournit automatiquement une documentation interactive (via Swagger UI).
Encore une fois, uniquement avec cette même déclaration de type Python, **FastAPI** vous fournit une documentation automatique et interactive (intégrant Swagger UI).
On voit bien dans la documentation que `item_id` est déclaré comme entier.
Remarquez que le paramètre de chemin est déclaré comme un entier.
///
## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative.
## Avantages basés sur les standards, documentation alternative { #standards-based-benefits-alternative-documentation }
Le schéma généré suivant la norme <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a>,
il existe de nombreux outils compatibles.
Et comme le schéma généré provient du standard <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a>, il existe de nombreux outils compatibles.
Grâce à cela, **FastAPI** lui-même fournit une documentation alternative (utilisant ReDoc), qui peut être lue
sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> :
Grâce à cela, **FastAPI** lui-même fournit une documentation d'API alternative (utilisant ReDoc), à laquelle vous pouvez accéder sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> :
<img src="/img/tutorial/path-params/image02.png">
De la même façon, il existe bien d'autres outils compatibles, y compris des outils de génération de code
pour de nombreux langages.
De la même façon, il existe de nombreux outils compatibles. Y compris des outils de génération de code pour de nombreux langages.
## Pydantic
## Pydantic { #pydantic }
Toute la validation de données est effectué en arrière-plan avec <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>,
dont vous bénéficierez de tous les avantages. Vous savez donc que vous êtes entre de bonnes mains.
Toute la validation de données est effectuée en arrière-plan par <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, vous bénéficiez donc de tous ses avantages. Et vous savez que vous êtes entre de bonnes mains.
## L'ordre importe
Vous pouvez utiliser les mêmes déclarations de type avec `str`, `float`, `bool` et de nombreux autres types de données complexes.
Quand vous créez des *fonctions de chemins*, vous pouvez vous retrouver dans une situation où vous avez un chemin fixe.
Plusieurs d'entre eux sont abordés dans les prochains chapitres du tutoriel.
Tel que `/users/me`, disons pour récupérer les données sur l'utilisateur actuel.
## L'ordre importe { #order-matters }
Et vous avez un second chemin : `/users/{user_id}` pour récupérer de la donnée sur un utilisateur spécifique grâce à son identifiant d'utilisateur
Lors de la création de *chemins d'accès*, vous pouvez vous retrouver dans des situations où vous avez un chemin fixe.
Les *fonctions de chemin* étant évaluées dans l'ordre, il faut s'assurer que la fonction correspondant à `/users/me` est déclarée avant celle de `/users/{user_id}` :
Comme `/users/me`, disons que c'est pour obtenir des données sur l'utilisateur actuel.
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
Et vous pouvez aussi avoir un chemin `/users/{user_id}` pour obtenir des données sur un utilisateur spécifique via un identifiant utilisateur.
Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, la fonction "croyant" qu'elle a reçu un paramètre `user_id` avec pour valeur `"me"`.
Comme les *chemins d'accès* sont évalués dans l'ordre, vous devez vous assurer que le chemin pour `/users/me` est déclaré avant celui pour `/users/{user_id}` :
## Valeurs prédéfinies
{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
Si vous avez une *fonction de chemin* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles des paramètres soient prédéfinies, vous pouvez utiliser les <abbr title="Enumeration">`Enum`</abbr> de Python.
Sinon, le chemin pour `/users/{user_id}` correspondrait aussi à `/users/me`, en « pensant » qu'il reçoit un paramètre `user_id` avec la valeur « me ».
### Création d'un `Enum`
De la même manière, vous ne pouvez pas redéfinir un chemin d'accès :
Importez `Enum` et créez une sous-classe qui hérite de `str` et `Enum`.
{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
En héritant de `str` la documentation sera capable de savoir que les valeurs doivent être de type `string` et pourra donc afficher cette `Enum` correctement.
Le premier sera toujours utilisé puisque le chemin correspond en premier.
Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs autorisées pour cette énumération.
## Valeurs prédéfinies { #predefined-values }
{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
Si vous avez un *chemin d'accès* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs valides possibles du *paramètre de chemin* soient prédéfinies, vous pouvez utiliser un <abbr title="Enumeration">`Enum`</abbr> Python standard.
/// info
### Créer une classe `Enum` { #create-an-enum-class }
<a href="https://docs.python.org/3/library/enum.html" class="external-link" target="_blank">Les énumérations (ou enums) sont disponibles en Python</a> depuis la version 3.4.
Importez `Enum` et créez une sous-classe qui hérite de `str` et de `Enum`.
///
En héritant de `str`, les documents de l'API pourront savoir que les valeurs doivent être de type `string` et pourront les afficher correctement.
Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs valides disponibles :
{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
/// tip | Astuce
Pour ceux qui se demandent, "AlexNet", "ResNet", et "LeNet" sont juste des noms de <abbr title="Techniquement, des architectures de modèles">modèles</abbr> de Machine Learning.
Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont simplement des noms de <abbr title="Technically, Deep Learning model architectures">modèles</abbr> de Machine Learning.
///
### Déclarer un paramètre de chemin
### Déclarer un *paramètre de chemin* { #declare-a-path-parameter }
Créez ensuite un *paramètre de chemin* avec une annotation de type désignant l'énumération créée précédemment (`ModelName`) :
Créez ensuite un *paramètre de chemin* avec une annotation de type utilisant la classe enum que vous avez créée (`ModelName`) :
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
### Documentation
### Vérifier la documentation { #check-the-docs }
Les valeurs disponibles pour le *paramètre de chemin* sont bien prédéfinies, la documentation les affiche correctement :
Comme les valeurs disponibles pour le *paramètre de chemin* sont prédéfinies, la documentation interactive peut bien les afficher :
<img src="/img/tutorial/path-params/image03.png">
### Manipuler les *énumérations* Python
### Travailler avec les *énumérations* Python { #working-with-python-enumerations }
La valeur du *paramètre de chemin* sera un des "membres" de l'énumération.
La valeur du *paramètre de chemin* sera un *membre d'énumération*.
#### Comparer les *membres d'énumération*
#### Comparer des *membres d'énumération* { #compare-enumeration-members }
Vous pouvez comparer ce paramètre avec les membres de votre énumération `ModelName` :
Vous pouvez la comparer avec le *membre d'énumération* de votre enum créée `ModelName` :
{* ../../docs_src/path_params/tutorial005.py hl[17] *}
{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
#### Récupérer la *valeur de l'énumération*
#### Obtenir la *valeur de l'énumération* { #get-the-enumeration-value }
Vous pouvez obtenir la valeur réel d'un membre (une chaîne de caractères ici), avec `model_name.value`, ou en général, `votre_membre_d'enum.value` :
Vous pouvez obtenir la valeur réelle (un `str` dans ce cas) en utilisant `model_name.value`, ou de manière générale, `your_enum_member.value` :
{* ../../docs_src/path_params/tutorial005.py hl[20] *}
{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
/// tip | Astuce
Vous pouvez aussi accéder la valeur `"lenet"` avec `ModelName.lenet.value`.
Vous pouvez aussi accéder à la valeur « lenet » avec `ModelName.lenet.value`.
///
#### Retourner des *membres d'énumération*
#### Retourner des *membres d'énumération* { #return-enumeration-members }
Vous pouvez retourner des *membres d'énumération* dans vos *fonctions de chemin*, même imbriquée dans un JSON (e.g. un `dict`).
Vous pouvez retourner des *membres d'enum* depuis votre *chemin d'accès*, même imbriqués dans un corps JSON (par ex. un `dict`).
Ils seront convertis vers leurs valeurs correspondantes (chaînes de caractères ici) avant d'être transmis au client :
Ils seront convertis en leurs valeurs correspondantes (des chaînes dans ce cas) avant de les renvoyer au client :
{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
Le client recevra une réponse JSON comme celle-ci :
Dans votre client, vous obtiendrez une réponse JSON comme :
```JSON
{
@@ -208,53 +199,53 @@ Le client recevra une réponse JSON comme celle-ci :
}
```
## Paramètres de chemin contenant des chemins
## Paramètres de chemin contenant des chemins { #path-parameters-containing-paths }
Disons que vous avez une *fonction de chemin* liée au chemin `/files/{file_path}`.
Disons que vous avez un *chemin d'accès* avec le chemin `/files/{file_path}`.
Mais que `file_path` lui-même doit contenir un *chemin*, comme `home/johndoe/myfile.txt` par exemple.
Mais vous avez besoin que `file_path` lui-même contienne un *chemin*, comme `home/johndoe/myfile.txt`.
Donc, l'URL pour ce fichier pourrait être : `/files/home/johndoe/myfile.txt`.
Donc, l'URL pour ce fichier serait quelque chose comme : `/files/home/johndoe/myfile.txt`.
### Support d'OpenAPI
### Support d'OpenAPI { #openapi-support }
OpenAPI ne supporte pas de manière de déclarer un paramètre de chemin contenant un *chemin*, cela pouvant causer des scénarios difficiles à tester et définir.
OpenAPI ne supporte pas une manière de déclarer qu'un *paramètre de chemin* contient un *chemin* à l'intérieur, car cela pourrait conduire à des scénarios difficiles à tester et à définir.
Néanmoins, cela reste faisable dans **FastAPI**, via les outils internes de Starlette.
Néanmoins, vous pouvez quand même le faire dans **FastAPI**, en utilisant un des outils internes de Starlette.
Et la documentation fonctionne quand même, bien qu'aucune section ne soit ajoutée pour dire que la paramètre devrait contenir un *chemin*.
Et les documents fonctionneraient quand même, bien qu'ils n'ajoutent aucune documentation indiquant que le paramètre devrait contenir un chemin.
### Convertisseur de *chemin*
### Convertisseur de chemin { #path-convertor }
En utilisant une option de Starlette directement, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :
En utilisant une option directement depuis Starlette, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :
```
/files/{file_path:path}
```
Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique à Starlette que le paramètre devrait correspondre à un *chemin*.
Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique que le paramètre doit correspondre à n'importe quel *chemin*.
Vous pouvez donc l'utilisez comme tel :
Ainsi, vous pouvez l'utiliser avec :
{* ../../docs_src/path_params/tutorial004.py hl[6] *}
{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
/// tip | Astuce
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash au début (`/`).
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash initial (`/`).
Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double slash (`//`) entre `files` et `home`.
///
## Récapitulatif
## Récapitulatif { #recap }
Avec **FastAPI**, en utilisant les déclarations de type rapides, intuitives et standards de Python, vous bénéficiez de :
Avec **FastAPI**, en utilisant des déclarations de type Python courtes, intuitives et standard, vous obtenez :
* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc.
* <abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">"Parsing"</abbr> de données.
* Validation de données.
* Annotations d'API et documentation automatique.
* Support de l'éditeur : vérifications d'erreurs, autocomplétion, etc.
* « parsing » de données <abbr title="conversion de la chaîne provenant d'une requête HTTP en données Python">parsing</abbr>
* Validation de données
* Annotation de l'API et documentation automatique
Et vous n'avez besoin de le déclarer qu'une fois.
Et vous n'avez à les déclarer qu'une seule fois.
C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres *frameworks* (outre les performances pures).
C'est probablement le principal avantage visible de **FastAPI** comparé aux frameworks alternatifs (en dehors de la performance brute).

View File

@@ -1,166 +1,273 @@
# Paramètres de requête et validations de chaînes de caractères
# Paramètres de requête et validations de chaînes de caractères { #query-parameters-and-string-validations }
**FastAPI** vous permet de déclarer des informations et des validateurs additionnels pour vos paramètres de requêtes.
**FastAPI** vous permet de déclarer des informations supplémentaires et de la validation pour vos paramètres.
Commençons avec cette application pour exemple :
Prenons cette application comme exemple :
{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
Le paramètre de requête `q` a pour type `Union[str, None]` (ou `str | None` en Python 3.10), signifiant qu'il est de type `str` mais pourrait aussi être égal à `None`, et bien sûr, la valeur par défaut est `None`, donc **FastAPI** saura qu'il n'est pas requis.
Le paramètre de requête `q` est de type `str | None`, ce qui signifie quil est de type `str` mais pourrait aussi être `None`, et en effet, la valeur par défaut est `None`, donc FastAPI saura quil nest pas requis.
/// note
/// 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` nest pas requise grâce à la valeur par défaut `= None`.
Le `Union` dans `Union[str, None]` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
Avoir `str | None` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
///
## Validation additionnelle
## Validation additionnelle { #additional-validation }
Nous allons imposer que bien que `q` soit un paramètre optionnel, dès qu'il est fourni, **sa longueur n'excède pas 50 caractères**.
Nous allons imposer que bien que `q` soit optionnel, dès quil est fourni, **sa longueur nexcède pas 50 caractères**.
## Importer `Query`
### Importer `Query` et `Annotated` { #import-query-and-annotated }
Pour cela, importez d'abord `Query` depuis `fastapi` :
Pour y parvenir, importez dabord :
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *}
* `Query` depuis `fastapi`
* `Annotated` depuis `typing`
## Utiliser `Query` comme valeur par défaut
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
Construisez ensuite la valeur par défaut de votre paramètre avec `Query`, en choisissant 50 comme `max_length` :
/// info
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *}
FastAPI a ajouté le support de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
Comme nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous pouvons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, il sert le même objectif qui est de définir cette valeur par défaut.
Si vous avez une version plus ancienne, vous obtiendriez des erreurs en essayant dutiliser `Annotated`.
Donc :
Vous devez vous assurer de [mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} au moins vers la 0.95.1 avant dutiliser `Annotated`.
///
## Utiliser `Annotated` dans le type du paramètre `q` { #use-annotated-in-the-type-for-the-q-parameter }
Vous vous souvenez que je vous ai dit précédemment que `Annotated` peut être utilisé pour ajouter des métadonnées à vos paramètres dans l[Introduction aux types Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} ?
Cest maintenant le moment de lutiliser avec FastAPI. 🚀
Nous avions cette annotation de type :
//// tab | Python 3.10+
```Python
q: Union[str, None] = Query(default=None)
q: str | None = None
```
... rend le paramètre optionnel, et est donc équivalent à :
////
//// tab | Python 3.9+
```Python
q: Union[str, None] = None
```
Mais déclare explicitement `q` comme étant un paramètre de requête.
////
/// info
Ce que nous allons faire est denvelopper cela avec `Annotated`, pour que cela devienne :
Gardez à l'esprit que la partie la plus importante pour rendre un paramètre optionnel est :
//// tab | Python 3.10+
```Python
= None
q: Annotated[str | None] = None
```
ou :
////
//// tab | Python 3.9+
```Python
= Query(None)
q: Annotated[Union[str, None]] = None
```
et utilisera ce `None` pour détecter que ce paramètre de requête **n'est pas requis**.
////
Le `Union[str, None]` est uniquement là pour permettre à votre éditeur un meilleur support.
Ces deux versions veulent dire la même chose, `q` est un paramètre qui peut être un `str` ou `None`, et par défaut, il vaut `None`.
Passons maintenant aux choses amusantes. 🎉
## Ajouter `Query` à `Annotated` dans le paramètre `q` { #add-query-to-annotated-in-the-q-parameter }
Maintenant que nous avons ce `Annotated` où nous pouvons mettre plus dinformations (dans ce cas une validation additionnelle), ajoutez `Query` à lintérieur de `Annotated`, et définissez le paramètre `max_length` à `50` :
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
Remarquez que la valeur par défaut est toujours `None`, donc le paramètre est toujours optionnel.
Mais maintenant, avec `Query(max_length=50)` à lintérieur de `Annotated`, nous disons à FastAPI que nous voulons **de la validation additionnelle** pour cette valeur, nous voulons quelle ait au maximum 50 caractères. 😎
/// tip | Astuce
Ici, nous utilisons `Query()` parce que cest un **paramètre de requête**. Plus tard, nous verrons dautres éléments comme `Path()`, `Body()`, `Header()` et `Cookie()`, qui acceptent aussi les mêmes arguments que `Query()`.
///
Ensuite, nous pouvons passer d'autres paramètres à `Query`. Dans cet exemple, le paramètre `max_length` qui s'applique aux chaînes de caractères :
FastAPI va maintenant :
* **Valider** les données en sassurant que la longueur maximale est de 50 caractères
* Afficher une **erreur claire** pour le client quand les données ne sont pas valides
* **Documenter** le paramètre dans le schéma OpenAPI de la *path operation* (il apparaîtra donc dans l**UI de documentation automatique**)
## Alternative (ancienne) : `Query` comme valeur par défaut { #alternative-old-query-as-the-default-value }
Les versions précédentes de FastAPI (avant <abbr title="before 2023-03 - avant 2023-03">0.95.0</abbr>) vous demandaient dutiliser `Query` comme valeur par défaut de votre paramètre, au lieu de le mettre dans `Annotated`. Il y a de fortes chances que vous voyiez du code qui lutilise, donc je vais vous lexpliquer.
/// tip | Astuce
Pour du nouveau code et dès que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a plusieurs avantages (expliqués ci-dessous) et aucun inconvénient. 🍰
///
Voici comment vous utiliseriez `Query()` comme valeur par défaut du paramètre de votre fonction, en définissant le paramètre `max_length` à 50 :
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
Comme dans ce cas (sans utiliser `Annotated`) nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous devons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, il sert le même objectif de définir cette valeur par défaut (au moins pour FastAPI).
Donc :
```Python
q: Union[str, None] = Query(default=None, max_length=50)
q: str | None = Query(default=None)
```
Cela va valider les données, montrer une erreur claire si ces dernières ne sont pas valides, et documenter le paramètre dans le schéma `OpenAPI` de cette *path operation*.
... rend le paramètre optionnel, avec une valeur par défaut de `None`, identique à :
## Rajouter plus de validation
```Python
q: str | None = None
```
Vous pouvez aussi rajouter un second paramètre `min_length` :
Mais la version avec `Query` le déclare explicitement comme étant un paramètre de requête.
{* ../../docs_src/query_params_str_validations/tutorial003.py hl[9] *}
Ensuite, nous pouvons passer dautres paramètres à `Query`. Dans ce cas, le paramètre `max_length` qui sapplique aux chaînes de caractères :
## Ajouter des validations par expressions régulières
```Python
q: str | None = Query(default=None, max_length=50)
```
On peut définir une <abbr title="Une expression régulière, regex ou regexp est une suite de caractères qui définit un pattern de correspondance pour les chaînes de caractères.">expression régulière</abbr> à laquelle le paramètre doit correspondre :
Cela va valider les données, montrer une erreur claire quand les données ne sont pas valides, et documenter le paramètre dans le schéma OpenAPI de la *path operation*.
{* ../../docs_src/query_params_str_validations/tutorial004.py hl[10] *}
### `Query` comme valeur par défaut ou dans `Annotated` { #query-as-the-default-value-or-in-annotated }
Cette expression régulière vérifie que la valeur passée comme paramètre :
Gardez à lesprit que lorsque vous utilisez `Query` à lintérieur de `Annotated`, vous ne pouvez pas utiliser le paramètre `default` pour `Query`.
* `^` : commence avec les caractères qui suivent, avec aucun caractère avant ceux-là.
À la place, utilisez la valeur par défaut réelle du paramètre de la fonction. Sinon, ce serait incohérent.
Par exemple, ceci nest pas autorisé :
```Python
q: Annotated[str, Query(default="rick")] = "morty"
```
... parce quil nest pas clair si la valeur par défaut devrait être `"rick"` ou `"morty"`.
Donc, vous utiliseriez (de préférence) :
```Python
q: Annotated[str, Query()] = "rick"
```
... ou dans des bases de code plus anciennes, vous trouverez :
```Python
q: str = Query(default="rick")
```
### Avantages de `Annotated` { #advantages-of-annotated }
**Utiliser `Annotated` est recommandé** plutôt que la valeur par défaut dans les paramètres de fonction, cest **mieux** pour plusieurs raisons. 🤓
La valeur par défaut du **paramètre de la fonction** est la **vraie valeur par défaut**, cest plus intuitif avec Python en général. 😌
Vous pourriez **appeler** cette même fonction à **dautres endroits** sans FastAPI, et elle **fonctionnerait comme prévu**. Sil y a un paramètre **requis** (sans valeur par défaut), votre **éditeur** vous le signalera avec une erreur, **Python** se plaindra aussi si vous lexécutez sans passer le paramètre requis.
Quand vous nutilisez pas `Annotated` et que vous utilisez à la place le **style (ancien) avec valeur par défaut**, si vous appelez cette fonction sans FastAPI à **dautres endroits**, vous devez **vous souvenir** de passer les arguments à la fonction pour quelle fonctionne correctement, sinon les valeurs seront différentes de ce que vous attendez (par exemple `QueryInfo` ou quelque chose de similaire au lieu de `str`). Et votre éditeur ne se plaindra pas, et Python ne se plaindra pas en exécutant cette fonction, seulement quand les opérations à lintérieur échoueront.
Parce que `Annotated` peut avoir plus dune annotation de métadonnées, vous pourriez maintenant même utiliser la même fonction avec dautres outils, comme <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
## Ajouter plus de validation { #add-more-validations }
Vous pouvez aussi ajouter un paramètre `min_length` :
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
## Ajouter des expressions régulières { #add-regular-expressions }
Vous pouvez définir un `pattern` d<abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings. - Une expression régulière, regex ou regexp est une suite de caractères qui définit un motif de recherche pour les chaînes de caractères.">expression régulière</abbr> auquel le paramètre doit correspondre :
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
Ce motif dexpression régulière spécifique vérifie que la valeur de paramètre reçue :
* `^` : commence avec les caractères qui suivent, na pas de caractères avant.
* `fixedquery` : a pour valeur exacte `fixedquery`.
* `$` : se termine directement ensuite, n'a pas d'autres caractères après `fixedquery`.
* `$` : se termine , na pas dautres caractères après `fixedquery`.
Si vous vous sentez perdu avec le concept d'**expression régulière**, pas d'inquiétudes. Il s'agit d'une notion difficile pour beaucoup, et l'on peut déjà réussir à faire beaucoup sans jamais avoir à les manipuler.
Si vous vous sentez perdu avec toutes ces idées d**« regular expression »**, pas dinquiétudes. Cest un sujet difficile pour beaucoup de gens. Vous pouvez encore faire beaucoup de choses sans avoir besoin dexpressions régulières.
Mais si vous décidez d'apprendre à les utiliser, sachez qu'ensuite vous pouvez les utiliser directement dans **FastAPI**.
Maintenant, vous savez que chaque fois que vous en avez besoin, vous pouvez les utiliser dans **FastAPI**.
## Valeurs par défaut
## Valeurs par défaut { #default-values }
De la même façon que vous pouvez passer `None` comme premier argument pour l'utiliser comme valeur par défaut, vous pouvez passer d'autres valeurs.
Vous pouvez, bien sûr, utiliser des valeurs par défaut autres que `None`.
Disons que vous déclarez le paramètre `q` comme ayant une longueur minimale de `3`, et une valeur par défaut étant `"fixedquery"` :
Disons que vous voulez déclarer le paramètre de requête `q` avec un `min_length` de `3`, et avec une valeur par défaut de `"fixedquery"` :
{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *}
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
/// note | Rappel
/// note | Remarque
Avoir une valeur par défaut rend le paramètre optionnel.
Avoir une valeur par défaut de nimporte quel type, y compris `None`, rend le paramètre optionnel (non requis).
///
## Rendre ce paramètre requis
## Paramètres requis { #required-parameters }
Quand on ne déclare ni validation, ni métadonnée, on peut rendre le paramètre `q` requis en ne lui déclarant juste aucune valeur par défaut :
Quand nous navons pas besoin de déclarer plus de validations ou de métadonnées, nous pouvons rendre le paramètre de requête `q` requis simplement en ne déclarant pas de valeur par défaut, comme :
```Python
q: str
```
à la place de :
au lieu de :
```Python
q: Union[str, None] = None
q: str | None = None
```
Mais maintenant, on déclare `q` avec `Query`, comme ceci :
Mais nous le déclarons maintenant avec `Query`, par exemple comme ceci :
```Python
q: Union[str, None] = Query(default=None, min_length=3)
q: Annotated[str | None, Query(min_length=3)] = None
```
Donc pour déclarer une valeur comme requise tout en utilisant `Query`, il faut utiliser `...` comme premier argument :
Donc, lorsque vous devez déclarer une valeur comme requise tout en utilisant `Query`, vous pouvez simplement ne pas déclarer de valeur par défaut :
{* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
/// info
### Requis, peut être `None` { #required-can-be-none }
Si vous n'avez jamais vu ce `...` auparavant : c'est une des constantes natives de Python <a href="https://docs.python.org/fr/3/library/constants.html#Ellipsis" class="external-link" target="_blank">appelée "Ellipsis"</a>.
Vous pouvez déclarer quun paramètre peut accepter `None`, mais quil est quand même requis. Cela forcerait les clients à envoyer une valeur, même si la valeur est `None`.
///
Pour faire cela, vous pouvez déclarer que `None` est un type valide mais simplement ne pas déclarer de valeur par défaut :
Cela indiquera à **FastAPI** que la présence de ce paramètre est obligatoire.
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
## Liste de paramètres / valeurs multiples via Query
## Liste de paramètres de requête / valeurs multiples { #query-parameter-list-multiple-values }
Quand on définit un paramètre de requête explicitement avec `Query` on peut aussi déclarer qu'il reçoit une liste de valeur, ou des "valeurs multiples".
Quand vous définissez un paramètre de requête explicitement avec `Query`, vous pouvez aussi le déclarer pour quil reçoive une liste de valeurs, ou dit autrement, pour quil reçoive plusieurs valeurs.
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans une URL, on écrit :
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans lURL, vous pouvez écrire :
{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
Ce qui fait qu'avec une URL comme :
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 au sein de votre fonction de **path operation**, dans le paramètre de fonction `q`.
vous recevriez les valeurs des multiples *query parameters* `q` (`foo` et `bar`) dans une `list` Python au sein de votre *path operation function*, dans le *function parameter* `q`.
Donc la réponse de cette URL serait :
Donc la réponse à cette URL serait :
```JSON
{
@@ -173,19 +280,19 @@ Donc la réponse de cette URL serait :
/// tip | Astuce
Pour déclarer un paramètre de requête de type `list`, comme dans l'exemple ci-dessus, il faut explicitement utiliser `Query`, sinon cela sera interprété comme faisant partie du corps de la requête.
Pour déclarer un paramètre de requête avec un type `list`, comme dans lexemple ci-dessus, vous devez explicitement utiliser `Query`, sinon cela serait interprété comme un corps de la requête.
///
La documentation sera donc mise à jour automatiquement pour autoriser plusieurs valeurs :
Les documents interactifs de lAPI seront mis à jour en conséquence, pour autoriser plusieurs valeurs :
<img src="/img/tutorial/query-params-str-validations/image02.png">
### Combiner liste de paramètres et valeurs par défaut
### Liste de paramètres de requête / valeurs multiples avec des valeurs par défaut { #query-parameter-list-multiple-values-with-defaults }
Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie :
Vous pouvez aussi définir une `list` de valeurs par défaut si aucune nest fournie :
{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
Si vous allez à :
@@ -193,9 +300,7 @@ Si vous allez à :
http://localhost:8000/items/
```
la valeur par défaut de `q` sera : `["foo", "bar"]`
et la réponse sera :
la valeur par défaut de `q` sera : `["foo", "bar"]` et votre réponse sera :
```JSON
{
@@ -206,93 +311,163 @@ et la réponse sera :
}
```
#### Utiliser `list`
#### Utiliser seulement `list` { #using-just-list }
Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` :
Vous pouvez aussi utiliser `list` directement au lieu de `list[str]` :
{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *}
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
/// note
/// note | Remarque
Dans ce cas-là, **FastAPI** ne vérifiera pas le contenu de la liste.
Gardez à lesprit que dans ce cas, FastAPI ne vérifiera pas le contenu de la liste.
Par exemple, `List[int]` vérifiera (et documentera) que la liste est bien entièrement composée d'entiers. Alors qu'un simple `list` ne ferait pas cette vérification.
Par exemple, `list[int]` vérifierait (et documenterait) que le contenu de la liste est composé dentiers. Mais `list` seul ne le ferait pas.
///
## Déclarer des métadonnées supplémentaires
## Déclarer plus de métadonnées { #declare-more-metadata }
On peut aussi ajouter plus d'informations sur le paramètre.
Vous pouvez ajouter plus dinformations à propos du paramètre.
Ces informations seront incluses dans le schéma `OpenAPI` généré et utilisées par la documentation interactive ou les outils externes utilisés.
Ces informations seront incluses dans lOpenAPI généré et utilisées par les interfaces utilisateur de la documentation et les outils externes.
/// note
/// note | Remarque
Gardez en tête que les outils externes utilisés ne supportent pas forcément tous parfaitement OpenAPI.
Gardez à lesprit que différents outils peuvent avoir des niveaux de support dOpenAPI différents.
Il se peut donc que certains d'entre eux n'utilisent pas toutes les métadonnées que vous avez déclarées pour le moment, bien que dans la plupart des cas, les fonctionnalités manquantes ont prévu d'être implémentées.
Certains dentre eux pourraient ne pas montrer toutes les informations supplémentaires déclarées pour le moment, bien que dans la plupart des cas, la fonctionnalité manquante soit déjà prévue pour le développement.
///
Vous pouvez ajouter un `title` :
{* ../../docs_src/query_params_str_validations/tutorial007.py hl[10] *}
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
Et une `description` :
{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *}
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
## Alias de paramètres
## Alias de paramètres { #alias-parameters }
Imaginez que vous vouliez que votre paramètre se nomme `item-query`.
Imaginez que vous voulez que le paramètre soit `item-query`.
Comme dans la requête :
Comme dans :
```
http://127.0.0.1:8000/items/?item-query=foobaritems
```
Mais `item-query` n'est pas un nom de variable valide en Python.
Mais `item-query` nest pas un nom de variable Python valide.
Le nom le plus proche serait `item_query`.
Le plus proche serait `item_query`.
Mais vous avez vraiment envie que ce soit exactement `item-query`...
Mais vous en avez encore besoin pour quil soit exactement `item-query`...
Pour cela vous pouvez déclarer un `alias`, et cet alias est ce qui sera utilisé pour trouver la valeur du paramètre :
Alors vous pouvez déclarer un `alias`, et cet alias sera ce qui sera utilisé pour trouver la valeur du paramètre :
{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *}
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
## Déprécier des paramètres
## Déprécier des paramètres { #deprecating-parameters }
Disons que vous ne vouliez plus utiliser ce paramètre désormais.
Disons maintenant que vous naimez plus ce paramètre.
Il faut qu'il continue à exister pendant un certain temps car vos clients l'utilisent, mais vous voulez que la documentation mentionne clairement que ce paramètre est <abbr title="obsolète, recommandé de ne pas l'utiliser">déprécié</abbr>.
Vous devez le laisser pendant un moment parce quil y a des clients qui lutilisent, mais vous voulez que les documents le montrent clairement comme <abbr title="obsolete, recommended not to use it - obsolète, recommandé de ne pas lutiliser">deprecated</abbr>.
On utilise alors l'argument `deprecated=True` de `Query` :
Ensuite, passez le paramètre `deprecated=True` à `Query` :
{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *}
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
La documentation le présentera comme il suit :
Les documents lafficheront comme ceci :
<img src="/img/tutorial/query-params-str-validations/image01.png">
## Pour résumer
## Exclusion d'OpenAPI { #exclude-parameters-from-openapi }
Il est possible d'ajouter des validateurs et métadonnées pour vos paramètres.
Pour exclure un paramètre de requête du schéma OpenAPI généré (et donc, des systèmes de documentation automatique), définissez le paramètre `include_in_schema` de `Query` à `False` :
Validateurs et métadonnées génériques:
{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
## Validation personnalisée { #custom-validation }
Il peut y avoir des cas où vous devez faire de la **validation personnalisée** qui ne peut pas être faite avec les paramètres montrés ci-dessus.
Dans ces cas, vous pouvez utiliser une **fonction de validateur personnalisée** qui est appliquée après la validation normale (par ex. après avoir validé que la valeur est un `str`).
Vous pouvez y parvenir en utilisant <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`AfterValidator` de Pydantic</a> à lintérieur de `Annotated`.
/// tip | Astuce
Pydantic a aussi <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> et dautres. 🤓
///
Par exemple, ce validateur personnalisé vérifie que lID de litem commence par `isbn-` pour un numéro de livre <abbr title="ISBN means International Standard Book Number - ISBN signifie International Standard Book Number">ISBN</abbr> ou par `imdb-` pour un ID dURL de film <abbr title="IMDB (Internet Movie Database) is a website with information about movies - IMDB (Internet Movie Database) est un site web contenant des informations sur les films">IMDB</abbr> :
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
/// info
Ceci est disponible avec Pydantic version 2 ou supérieure. 😎
///
/// tip | Astuce
Si vous devez faire tout type de validation qui nécessite de communiquer avec un **composant externe**, comme une base de données ou une autre API, vous devriez plutôt utiliser les **dépendances FastAPI**, vous en apprendrez plus à leur sujet plus tard.
Ces validateurs personnalisés sont pour des choses qui peuvent être vérifiées avec **uniquement** les **mêmes données** fournies dans la requête.
///
### Comprendre ce code { #understand-that-code }
Le point important est simplement dutiliser **`AfterValidator` avec une fonction dans `Annotated`**. Nhésitez pas à sauter cette partie. 🤸
---
Mais si vous êtes curieux à propos de cet exemple de code spécifique et que vous êtes encore diverti, voici quelques détails supplémentaires.
#### Chaîne avec `value.startswith()` { #string-with-value-startswith }
Avez-vous remarqué ? une chaîne utilisant `value.startswith()` peut prendre un tuple, et cela vérifiera chaque valeur dans le tuple :
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
#### Un item aléatoire { #a-random-item }
Avec `data.items()` nous obtenons un <abbr title="Something we can iterate on with a for loop, like a list, set, etc. - Quelque chose sur lequel on peut itérer avec une boucle for, comme une liste, un set, etc.">iterable object</abbr> avec des tuples contenant la clé et la valeur pour chaque élément du dictionnaire.
Nous convertissons cet objet itérable en une vraie `list` avec `list(data.items())`.
Ensuite, avec `random.choice()` nous pouvons obtenir une **valeur aléatoire** de la liste, donc, nous obtenons un tuple avec `(id, name)`. Ce sera quelque chose comme `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
Ensuite, nous **assignons ces deux valeurs** du tuple aux variables `id` et `name`.
Ainsi, si lutilisateur na pas fourni dID ditem, il recevra quand même une suggestion aléatoire.
... nous faisons tout cela en **une seule ligne simple**. 🤯 Vous naimez pas Python ? 🐍
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
## Pour résumer { #recap }
Vous pouvez déclarer des validations additionnelles et des métadonnées pour vos paramètres.
Validations et métadonnées génériques :
* `alias`
* `title`
* `description`
* `deprecated`
Validateurs spécifiques aux chaînes de caractères :
Validations spécifiques pour les chaînes de caractères :
* `min_length`
* `max_length`
* `regex`
* `pattern`
Parmi ces exemples, vous avez pu voir comment déclarer des validateurs pour les chaînes de caractères.
Validations personnalisées utilisant `AfterValidator`.
Dans les prochains chapitres, vous verrez comment déclarer des validateurs pour d'autres types, comme les nombres.
Dans ces exemples, vous avez vu comment déclarer des validations pour des valeurs `str`.
Consultez les chapitres suivants pour apprendre à déclarer des validations pour dautres types, comme les nombres.

View File

@@ -1,10 +1,10 @@
# Paramètres de requête
# Paramètres de requête { #query-parameters }
Quand vous déclarez des paramètres dans votre fonction de chemin qui ne font pas partie des paramètres indiqués dans le chemin associé, ces paramètres sont automatiquement considérés comme des paramètres de "requête".
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.py hl[9] *}
{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`.
La requête est l'ensemble des paires clé-valeur qui suivent le `?` dans une URL, séparées par des caractères `&`.
Par exemple, dans l'URL :
@@ -12,80 +12,72 @@ Par exemple, dans l'URL :
http://127.0.0.1:8000/items/?skip=0&limit=10
```
...les paramètres de requête sont :
... les paramètres de requête sont :
* `skip` : avec une valeur de`0`
* `skip` : avec une valeur de `0`
* `limit` : avec une valeur de `10`
Faisant partie de l'URL, ces valeurs sont des chaînes de caractères (`str`).
Comme ils font partie de l'URL, ce sont « naturellement » des chaînes de caractères.
Mais quand on les déclare avec des types Python (dans l'exemple précédent, en tant qu'`int`), elles sont converties dans les types renseignés.
Mais lorsque vous les déclarez avec des types Python (dans l'exemple ci-dessus, en tant que `int`), ils sont convertis vers ce type et validés par rapport à celui-ci.
Toutes les fonctionnalités qui s'appliquent aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
Tous les mêmes processus qui s'appliquaient aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc.
* <abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">"Parsing"</abbr> de données.
* Validation de données.
* Annotations d'API et documentation automatique.
* Support de l'éditeur (évidemment)
* <abbr title="converting the string that comes from an HTTP request into Python data - conversion de la chaîne de caractères venant d'une requête HTTP en données Python">« parsing »</abbr> des données
* Validation des données
* Documentation automatique
## Valeurs par défaut
## Valeurs par défaut { #defaults }
Les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut.
Comme les paramètres de requête ne constituent pas une partie fixe d'un chemin, ils peuvent être optionnels et peuvent avoir des valeurs par défaut.
Dans l'exemple ci-dessus, ils ont des valeurs par défaut qui sont `skip=0` et `limit=10`.
Dans l'exemple ci-dessus, ils ont des valeurs par défaut `skip=0` et `limit=10`.
Donc, accéder à l'URL :
Ainsi, aller à l'URL :
```
http://127.0.0.1:8000/items/
```
serait équivalent à accéder à l'URL :
serait équivalent à aller à :
```
http://127.0.0.1:8000/items/?skip=0&limit=10
```
Mais si vous accédez à, par exemple :
Mais si vous allez à, par exemple :
```
http://127.0.0.1:8000/items/?skip=20
```
Les valeurs des paramètres de votre fonction seront :
Les valeurs des paramètres dans votre fonction seront :
* `skip=20` : car c'est la valeur déclarée dans l'URL.
* `limit=10` : car `limit` n'a pas été déclaré dans l'URL, et que la valeur par défaut était `10`.
* `skip=20` : parce que vous l'avez défini dans l'URL
* `limit=10` : parce que c'était la valeur par défaut
## Paramètres optionnels
## Paramètres optionnels { #optional-parameters }
De la même façon, vous pouvez définir des paramètres de requête comme optionnels, en leur donnant comme valeur par défaut `None` :
De la même façon, vous pouvez déclarer des paramètres de requête optionnels, en définissant leur valeur par défaut à `None` :
{* ../../docs_src/query_params/tutorial002.py hl[9] *}
{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut.
Dans ce cas, le paramètre de fonction `q` sera optionnel, et aura `None` comme valeur par défaut.
/// check | Remarque
/// check | Vérifications
On peut voir que **FastAPI** est capable de détecter que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` n'en est pas un, c'est donc un paramètre de requête.
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` n'en est pas un, donc c'est un paramètre de requête.
///
/// note
## Conversion du type des paramètres de requête { #query-parameter-type-conversion }
**FastAPI** saura que `q` est optionnel grâce au `=None`.
Vous pouvez aussi déclarer des types `bool`, et ils seront convertis :
Le `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI** (**FastAPI** n'en utilisera que la partie `str`), mais il servira tout de même à votre éditeur de texte pour détecter des erreurs dans votre code.
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
///
## Conversion des types des paramètres de requête
Vous pouvez aussi déclarer des paramètres de requête comme booléens (`bool`), **FastAPI** les convertira :
{* ../../docs_src/query_params/tutorial003.py hl[9] *}
Avec ce code, en allant sur :
Dans ce cas, si vous allez à :
```
http://127.0.0.1:8000/items/foo?short=1
@@ -115,60 +107,62 @@ ou
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 considérera le paramètre `short` comme ayant une valeur booléenne à `True`. Sinon la valeur sera à `False`.
ou toute autre variation de casse (majuscules, première lettre en majuscule, etc.), votre fonction verra le paramètre `short` avec une valeur `bool` de `True`. Sinon, `False`.
## Multiples paramètres de chemin et de requête
Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer.
## Paramètres de chemin et de requête multiples { #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 lesquels sont lesquels.
Et vous n'avez pas besoin de les déclarer dans un ordre spécifique.
Ils seront détectés par leurs noms :
Ils seront détectés par leur nom :
{* ../../docs_src/query_params/tutorial004.py hl[8,10] *}
{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
## Paramètres de requête requis
## Paramètres de requête requis { #required-query-parameters }
Quand vous déclarez une valeur par défaut pour un paramètre qui n'est pas un paramètre de chemin (actuellement, nous n'avons vu que les paramètres de requête), alors ce paramètre n'est pas requis.
Lorsque vous déclarez une valeur par défaut pour des paramètres qui ne sont pas des paramètres de chemin (pour l'instant, nous n'avons vu que des paramètres de requête), alors ils ne sont pas requis.
Si vous ne voulez pas leur donner de valeur par défaut mais juste les rendre optionnels, utilisez `None` comme valeur par défaut.
Si vous ne voulez pas ajouter une valeur spécifique mais juste le rendre optionnel, définissez la valeur par défaut sur `None`.
Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez juste ne pas y affecter de valeur par défaut :
Mais lorsque vous voulez rendre un paramètre de requête requis, vous pouvez simplement ne pas déclarer de valeur par défaut :
{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
Ici le paramètre `needy` est un paramètre requis (ou obligatoire) de type `str`.
Ici, le paramètre de requête `needy` est un paramètre de requête requis de type `str`.
Si vous ouvrez une URL comme :
Si vous ouvrez dans votre navigateur une URL comme :
```
http://127.0.0.1:8000/items/foo-item
```
...sans ajouter le paramètre requis `needy`, vous aurez une erreur :
... sans ajouter le paramètre requis `needy`, vous verrez une erreur comme :
```JSON
{
"detail": [
{
"loc": [
"query",
"needy"
],
"msg": "field required",
"type": "value_error.missing"
}
]
"detail": [
{
"type": "missing",
"loc": [
"query",
"needy"
],
"msg": "Field required",
"input": null
}
]
}
```
La présence de `needy` étant nécessaire, vous auriez besoin de l'insérer dans l'URL :
Comme `needy` est un paramètre requis, vous devez le définir dans l'URL :
```
http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
```
...ce qui fonctionnerait :
... cela fonctionnerait :
```JSON
{
@@ -177,18 +171,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
}
```
Et bien sur, vous pouvez définir certains paramètres comme requis, certains avec des valeurs par défaut et certains entièrement optionnels :
Et bien sûr, vous pouvez définir certains paramètres comme requis, certains avec une valeur par défaut et certains entièrement optionnels :
{* ../../docs_src/query_params/tutorial006.py hl[10] *}
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
Ici, on a donc 3 paramètres de requête :
Dans ce cas, il y a 3 paramètres de requête :
* `needy`, requis et de type `str`.
* `skip`, un `int` avec comme valeur par défaut `0`.
* `needy`, un `str` requis.
* `skip`, un `int` avec une valeur par défaut de `0`.
* `limit`, un `int` optionnel.
/// tip | Astuce
Vous pouvez utiliser les `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#valeurs-predefinies){.internal-link target=_blank}.
Vous pouvez aussi utiliser des `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#predefined-values){.internal-link target=_blank}.
///