mirror of
https://github.com/fastapi/fastapi.git
synced 2026-01-24 14:02:49 -05:00
Compare commits
19 Commits
translate-
...
use-extern
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfadf80f48 | ||
|
|
0e65c3167f | ||
|
|
ef76935b10 | ||
|
|
f55d2ee641 | ||
|
|
c8f4a1b0d4 | ||
|
|
e0abd210f6 | ||
|
|
2eb978b87a | ||
|
|
50a78bf840 | ||
|
|
2d459e4845 | ||
|
|
7faa7089d6 | ||
|
|
0ab68a762f | ||
|
|
7443bc7a46 | ||
|
|
6afb15c518 | ||
|
|
ad6b2901a6 | ||
|
|
463a3a24d7 | ||
|
|
db5441eba1 | ||
|
|
536a5bafe7 | ||
|
|
0c7f2b66d7 | ||
|
|
9fec72687f |
@@ -65,9 +65,6 @@ bronze:
|
||||
# - url: https://testdriven.io/courses/tdd-fastapi/
|
||||
# title: Learn to build high-quality web apps with best practices
|
||||
# img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg
|
||||
- url: https://lambdatest.com/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage
|
||||
title: LambdaTest, AI-Powered Cloud-based Test Orchestration Platform
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/lambdatest.png
|
||||
- url: https://requestly.com/fastapi
|
||||
title: All-in-one platform to Test, Mock and Intercept APIs. Built for speed, privacy and offline support.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/requestly.png
|
||||
- url: https://www.testmu.ai/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage
|
||||
title: TestMu AI. The Native AI-Agentic Cloud Platform to Supercharge Quality Engineering.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/testmu.png
|
||||
|
||||
@@ -6,13 +6,29 @@ For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI applicat
|
||||
|
||||
## Using `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
You need to import `WSGIMiddleware`.
|
||||
/// info
|
||||
|
||||
This requires installing `a2wsgi` for example with `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
You need to import `WSGIMiddleware` from `a2wsgi`.
|
||||
|
||||
Then wrap the WSGI (e.g. Flask) app with the middleware.
|
||||
|
||||
And then mount that under a path.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note
|
||||
|
||||
Previously, it was recommended to use `WSGIMiddleware` from `fastapi.middleware.wsgi`, but it is now deprecated.
|
||||
|
||||
It’s advised to use the `a2wsgi` package instead. The usage remains the same.
|
||||
|
||||
Just ensure that you have the `a2wsgi` package installed and import `WSGIMiddleware` correctly from `a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
## Check it { #check-it }
|
||||
|
||||
|
||||
BIN
docs/en/docs/img/sponsors/testmu.png
Normal file
BIN
docs/en/docs/img/sponsors/testmu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@@ -35,11 +35,3 @@ It can be imported from `fastapi`:
|
||||
```python
|
||||
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
||||
```
|
||||
|
||||
::: fastapi.middleware.wsgi.WSGIMiddleware
|
||||
|
||||
It can be imported from `fastapi`:
|
||||
|
||||
```python
|
||||
from fastapi.middleware.wsgi import WSGIMiddleware
|
||||
```
|
||||
|
||||
@@ -18,6 +18,11 @@ hide:
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for pt (update-outdated). PR [#14724](https://github.com/fastapi/fastapi/pull/14724) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update Korean LLM prompt. PR [#14740](https://github.com/fastapi/fastapi/pull/14740) by [@hard-coders](https://github.com/hard-coders).
|
||||
* 🌐 Improve LLM prompt for Turkish translations. PR [#14728](https://github.com/fastapi/fastapi/pull/14728) by [@Kadermiyanyedi](https://github.com/Kadermiyanyedi).
|
||||
* 🌐 Update portuguese llm-prompt.md. PR [#14702](https://github.com/fastapi/fastapi/pull/14702) by [@ceb10n](https://github.com/ceb10n).
|
||||
* 🌐 Update LLM prompt instructions file for French. PR [#14618](https://github.com/fastapi/fastapi/pull/14618) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for ko (add-missing). PR [#14699](https://github.com/fastapi/fastapi/pull/14699) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for ko (update-outdated). PR [#14589](https://github.com/fastapi/fastapi/pull/14589) by [@tiangolo](https://github.com/tiangolo).
|
||||
@@ -29,6 +34,8 @@ hide:
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔧 Update sponsors: remove Requestly. PR [#14735](https://github.com/fastapi/fastapi/pull/14735) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, LambdaTest changes to TestMu AI. PR [#14734](https://github.com/fastapi/fastapi/pull/14734) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Bump actions/cache from 4 to 5. PR [#14511](https://github.com/fastapi/fastapi/pull/14511) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump actions/upload-artifact from 5 to 6. PR [#14525](https://github.com/fastapi/fastapi/pull/14525) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump actions/download-artifact from 6 to 7. PR [#14526](https://github.com/fastapi/fastapi/pull/14526) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Réponses supplémentaires dans OpenAPI { #additional-responses-in-openapi }
|
||||
# Réponses supplémentaires dans OpenAPI
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
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 de statut supplémentaires, des types de médias, des descriptions, etc.
|
||||
Vous pouvez déclarer des réponses supplémentaires, avec des codes HTTP, 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 de statut et votre contenu.
|
||||
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.
|
||||
|
||||
## Réponse supplémentaire avec `model` { #additional-response-with-model }
|
||||
## Réponse supplémentaire avec `model`
|
||||
|
||||
Vous pouvez passer à vos *décorateurs de chemin d'accès* un paramètre `responses`.
|
||||
Vous pouvez ajouter à votre décorateur de *paramètre de chemin* un paramètre `responses`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 JSON Schema et l'inclura au bon endroit dans OpenAPI.
|
||||
**FastAPI** prendra ce modèle, générera son schéma JSON et l'inclura au bon endroit dans OpenAPI.
|
||||
|
||||
Par exemple, pour déclarer une autre réponse avec un code de statut `404` et un modèle Pydantic `Message`, vous pouvez écrire :
|
||||
Par exemple, pour déclarer une autre réponse avec un code HTTP `404` et un modèle Pydantic `Message`, vous pouvez écrire :
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
|
||||
{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *}
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Gardez à l'esprit que vous devez renvoyer directement le `JSONResponse`.
|
||||
Gardez à l'esprit que vous devez renvoyer directement `JSONResponse`.
|
||||
|
||||
///
|
||||
|
||||
@@ -38,18 +38,18 @@ Gardez à l'esprit que vous devez renvoyer directement le `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 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.
|
||||
* 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.
|
||||
|
||||
///
|
||||
|
||||
Les réponses générées dans OpenAPI pour cette *opération de chemin d'accès* seront :
|
||||
Les réponses générées au format OpenAPI pour cette *opération de chemin* seront :
|
||||
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
@@ -88,7 +88,7 @@ Les réponses générées dans OpenAPI pour cette *opération de chemin d'accès
|
||||
}
|
||||
```
|
||||
|
||||
Les schémas sont référencés à un autre endroit dans le schéma OpenAPI :
|
||||
Les schémas sont référencés à un autre endroit du modèle OpenAPI :
|
||||
|
||||
```JSON hl_lines="4-16"
|
||||
{
|
||||
@@ -169,13 +169,13 @@ Les schémas sont référencés à un autre endroit dans le schéma OpenAPI :
|
||||
}
|
||||
```
|
||||
|
||||
## Types de médias supplémentaires pour la réponse principale { #additional-media-types-for-the-main-response }
|
||||
## Types de médias supplémentaires pour la réponse principale
|
||||
|
||||
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 d'accès* 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* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
|
||||
{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *}
|
||||
|
||||
/// 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 { #combining-information }
|
||||
## Combinaison d'informations
|
||||
|
||||
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 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.
|
||||
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.
|
||||
|
||||
**FastAPI** conservera les informations supplémentaires des `responses` et les combinera avec le JSON Schema de votre modèle.
|
||||
**FastAPI** conservera les informations supplémentaires des `responses` et les combinera avec le schéma JSON de votre modèle.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Et une réponse avec un code de statut `200` qui utilise votre `response_model`, mais inclut un `example` personnalisé :
|
||||
Et une réponse avec un code HTTP `200` qui utilise votre `response_model`, mais inclut un `example` personnalisé :
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
|
||||
{* ../../docs_src/additional_responses/tutorial003.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">
|
||||
|
||||
## Combiner des réponses prédéfinies et des réponses personnalisées { #combine-predefined-responses-and-custom-ones }
|
||||
## Combinez les réponses prédéfinies et les réponses personnalisées
|
||||
|
||||
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*.
|
||||
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*.
|
||||
|
||||
Dans ces cas, vous pouvez utiliser la technique Python de « unpacking » d'un `dict` avec `**dict_to_unpack` :
|
||||
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` :
|
||||
|
||||
```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 *opérations de chemin d'accès* 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 *paramètres de chemin* et les combiner avec des réponses personnalisées supplémentaires.
|
||||
|
||||
Par exemple :
|
||||
Par exemple:
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
|
||||
{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *}
|
||||
|
||||
## Plus d'informations sur les réponses OpenAPI { #more-information-about-openapi-responses }
|
||||
## Plus d'informations sur les réponses OpenAPI
|
||||
|
||||
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.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`.
|
||||
* <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`.
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
# Codes de statut supplémentaires { #additional-status-codes }
|
||||
# Codes HTTP supplémentaires
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
Il utilisera le code de statut par défaut ou celui que vous définissez dans votre *chemin d'accès*.
|
||||
Il utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *chemin d'accès*.
|
||||
|
||||
## Codes de statut supplémentaires { #additional-status-codes_1 }
|
||||
## Codes HTTP supplémentaires
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 ».
|
||||
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éé".
|
||||
|
||||
Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous voulez :
|
||||
Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous souhaitez :
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *}
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
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, etc.
|
||||
Elle ne sera pas sérialisée avec un modèle.
|
||||
|
||||
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`).
|
||||
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`).
|
||||
|
||||
///
|
||||
|
||||
@@ -30,12 +30,12 @@ Vous devez vous assurer qu'elle contient les données que vous voulez qu'elle co
|
||||
|
||||
Vous pouvez également utiliser `from starlette.responses import JSONResponse`.
|
||||
|
||||
**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`.
|
||||
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`.
|
||||
|
||||
///
|
||||
|
||||
## Documents OpenAPI et API { #openapi-and-api-docs }
|
||||
## Documents OpenAPI et API
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires](additional-responses.md){.internal-link target=_blank}.
|
||||
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
# Guide de l'utilisateur avancé { #advanced-user-guide }
|
||||
# Guide de l'utilisateur avancé
|
||||
|
||||
## Caractéristiques supplémentaires { #additional-features }
|
||||
## Caractéristiques supplémentaires
|
||||
|
||||
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.
|
||||
|
||||
/// tip | Astuce
|
||||
/// note | Remarque
|
||||
|
||||
Les sections suivantes ne sont **pas nécessairement « avancées »**.
|
||||
Les sections de ce chapitre ne sont **pas nécessairement "avancées"**.
|
||||
|
||||
Et il est possible que, pour votre cas d'utilisation, la solution se trouve dans l'une d'entre elles.
|
||||
Et il est possible que pour votre cas d'utilisation, la solution se trouve dans l'un d'entre eux.
|
||||
|
||||
///
|
||||
|
||||
## Lisez d'abord le didacticiel { #read-the-tutorial-first }
|
||||
## Lisez d'abord le didacticiel
|
||||
|
||||
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}.
|
||||
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}.
|
||||
|
||||
Et les sections suivantes supposent que vous l'avez déjà lu, et supposent que vous connaissez ces idées principales.
|
||||
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**. 🎉 😄
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
# Configuration avancée des chemins d'accès { #path-operation-advanced-configuration }
|
||||
# Configuration avancée des paramètres de chemin
|
||||
|
||||
## operationId OpenAPI { #openapi-operationid }
|
||||
## ID d'opération OpenAPI
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
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 n'en avez probablement pas besoin.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez définir l’OpenAPI `operationId` à utiliser dans votre *chemin d'accès* avec le paramètre `operation_id`.
|
||||
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 devez vous assurer qu’il est unique pour chaque opération.
|
||||
Vous devez vous assurer qu'il est unique pour chaque opération.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *}
|
||||
|
||||
### Utiliser le nom de la *fonction de chemin d'accès* comme operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
### Utilisation du nom *path operation function* comme operationId
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
Vous devez le faire après avoir ajouté tous vos *chemins d'accès*.
|
||||
Vous devriez le faire après avoir ajouté toutes vos *paramètres de chemin*.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2,12:21,24] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
@@ -28,81 +28,79 @@ Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `ope
|
||||
|
||||
///
|
||||
|
||||
/// warning | Alertes
|
||||
/// warning | Attention
|
||||
|
||||
Si vous faites cela, vous devez vous assurer que chacune de vos *fonctions de chemin d'accès* a un nom unique.
|
||||
Pour faire cela, vous devez vous assurer que chacun de vos *chemin* ait un nom unique.
|
||||
|
||||
Même si elles sont dans des modules différents (fichiers Python).
|
||||
Même s'ils se trouvent dans des modules différents (fichiers Python).
|
||||
|
||||
///
|
||||
|
||||
## Exclusion d'OpenAPI { #exclude-from-openapi }
|
||||
## Exclusion d'OpenAPI
|
||||
|
||||
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` :
|
||||
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` :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *}
|
||||
|
||||
## Description avancée depuis la docstring { #advanced-description-from-docstring }
|
||||
## Description avancée de docstring
|
||||
|
||||
Vous pouvez limiter les lignes utilisées depuis la docstring d’une *fonction de chemin d'accès* pour OpenAPI.
|
||||
Vous pouvez limiter le texte utilisé de la docstring d'une *fonction de chemin* qui sera affiché sur OpenAPI.
|
||||
|
||||
Ajouter un `\f` (un caractère « form feed » échappé) amène **FastAPI** à tronquer la sortie utilisée pour OpenAPI à cet endroit.
|
||||
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.
|
||||
|
||||
Il n’apparaîtra pas dans la documentation, mais d’autres outils (tels que Sphinx) pourront utiliser le reste.
|
||||
Il n'apparaîtra pas dans la documentation, mais d'autres outils (tel que Sphinx) pourront utiliser le reste.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004.py hl[19:29] *}
|
||||
|
||||
## Réponses supplémentaires { #additional-responses }
|
||||
## Réponses supplémentaires
|
||||
|
||||
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour un *chemin d'accès*.
|
||||
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour une *opération de chemin*.
|
||||
|
||||
Cela définit les métadonnées concernant la réponse principale d’un *chemin d'accès*.
|
||||
Cela définit les métadonnées sur la réponse principale d'une *opération de chemin*.
|
||||
|
||||
Vous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc.
|
||||
|
||||
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}.
|
||||
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}.
|
||||
|
||||
## OpenAPI Extra { #openapi-extra }
|
||||
## OpenAPI supplémentaire
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
Dans la spécification OpenAPI, cela s’appelle 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>.
|
||||
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>.
|
||||
|
||||
///
|
||||
|
||||
Il contient toutes les informations sur le *chemin d'accès* et est utilisé pour générer la documentation automatique.
|
||||
Il contient toutes les informations sur le *chemin* et est utilisé pour générer automatiquement la documentation.
|
||||
|
||||
Il inclut les `tags`, `parameters`, `requestBody`, `responses`, etc.
|
||||
|
||||
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.
|
||||
Ce schéma OpenAPI spécifique aux *operations* est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l'étendre.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
C’est un point d’extension 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}.
|
||||
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}.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez étendre le schéma OpenAPI pour un *chemin d'accès* en utilisant le paramètre `openapi_extra`.
|
||||
Vous pouvez étendre le schéma OpenAPI pour une *opération de chemin* en utilisant le paramètre `openapi_extra`.
|
||||
|
||||
### Extensions OpenAPI { #openapi-extensions }
|
||||
### Extensions OpenAPI
|
||||
|
||||
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) :
|
||||
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) :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *}
|
||||
|
||||
Si vous ouvrez les documents automatiques de l’API, votre extension apparaîtra au bas du *chemin d'accès* spécifique.
|
||||
Si vous ouvrez la documentation automatique de l'API, votre extension apparaîtra au bas du *chemin* spécifique.
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
Et si vous regardez l’OpenAPI résultant (dans `/openapi.json` de votre API), vous verrez aussi votre extension comme faisant partie du *chemin d'accès* spécifique :
|
||||
Et dans le fichier openapi généré (`/openapi.json`), vous verrez également votre extension dans le cadre du *chemin* spécifique :
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"openapi": "3.0.2",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
@@ -129,44 +127,44 @@ Et si vous regardez l’OpenAPI résultant (dans `/openapi.json` de votre API),
|
||||
}
|
||||
```
|
||||
|
||||
### Schéma OpenAPI personnalisé pour un *chemin d'accès* { #custom-openapi-path-operation-schema }
|
||||
### Personnalisation du Schéma OpenAPI pour un 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*.
|
||||
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*.
|
||||
|
||||
Ainsi, vous pourriez ajouter des données supplémentaires au schéma généré automatiquement.
|
||||
Ainsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Vous pourriez faire cela avec `openapi_extra` :
|
||||
Vous pouvez le faire avec `openapi_extra` :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[20:37,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="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 l’analyser d’une manière ou d’une autre.
|
||||
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.
|
||||
|
||||
Néanmoins, nous pouvons déclarer le schéma attendu pour le corps de la requête.
|
||||
|
||||
### Type de contenu OpenAPI personnalisé { #custom-openapi-content-type }
|
||||
### Type de contenu OpenAPI personnalisé
|
||||
|
||||
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*.
|
||||
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é.
|
||||
|
||||
Et vous pourriez faire cela même si le type de données dans la requête n’est pas du JSON.
|
||||
Et vous pouvez le faire même si le type de données dans la requête n'est pas au format JSON.
|
||||
|
||||
Par exemple, dans cette application, nous n’utilisons 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 :
|
||||
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 :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[17:22,24] *}
|
||||
|
||||
Néanmoins, bien que nous n’utilisions 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.
|
||||
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.
|
||||
|
||||
Ensuite, nous utilisons la requête directement et extrayons le corps en tant que `bytes`. Cela signifie que FastAPI n’essaiera même pas d’analyser le payload de la requête comme du JSON.
|
||||
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.
|
||||
|
||||
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 :
|
||||
Et nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[26:33] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ici, nous réutilisons le même modèle Pydantic.
|
||||
|
||||
Mais, de la même manière, nous aurions pu le valider d’une autre façon.
|
||||
Mais nous aurions pu tout aussi bien pu le valider d'une autre manière.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# Renvoyer directement une réponse { #return-a-response-directly }
|
||||
# Renvoyer directement une réponse
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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}.
|
||||
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}.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *chemins d'accès*.
|
||||
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *opérations de chemin*.
|
||||
|
||||
Cela peut être utile, par exemple, pour retourner des en-têtes personnalisés ou des cookies.
|
||||
|
||||
## Renvoyer une `Response` { #return-a-response }
|
||||
## Renvoyer une `Response`
|
||||
|
||||
En fait, vous pouvez retourner n'importe quelle `Response` ou n'importe quelle sous-classe de celle-ci.
|
||||
|
||||
/// tip | Astuce
|
||||
/// note | Remarque
|
||||
|
||||
`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, etc.
|
||||
Elle ne fera aucune conversion de données avec les modèles Pydantic, elle ne convertira pas le contenu en un type quelconque.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Utiliser le `jsonable_encoder` dans une `Response` { #using-the-jsonable-encoder-in-a-response }
|
||||
## Utiliser le `jsonable_encoder` dans une `Response`
|
||||
|
||||
Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt.
|
||||
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).
|
||||
|
||||
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 utiliser le `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
|
||||
Pour ces cas, vous pouvez spécifier un appel à `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
|
||||
{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
|
||||
|
||||
/// 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 vous, 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 le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
|
||||
|
||||
///
|
||||
|
||||
## Renvoyer une `Response` personnalisée { #returning-a-custom-response }
|
||||
## Renvoyer une `Response` personnalisée
|
||||
|
||||
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_py39.py hl[1,18] *}
|
||||
{* ../../docs_src/response_directly/tutorial002.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 [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
Mais vous pouvez toujours les documenter comme décrit dans [Additional Responses in 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.
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
# Benchmarks { #benchmarks }
|
||||
# Test de performance
|
||||
|
||||
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">l’un des frameworks Python les plus rapides disponibles</a>, juste en dessous de Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI).
|
||||
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). (*)
|
||||
|
||||
Mais lorsque vous consultez des benchmarks et des comparaisons, vous devez garder ce qui suit à l’esprit.
|
||||
Mais en prêtant attention aux tests de performance et aux comparaisons, il faut tenir compte de ce qu'il suit.
|
||||
|
||||
## Benchmarks et vitesse { #benchmarks-and-speed }
|
||||
## Tests de performance et rapidité
|
||||
|
||||
Lorsque vous consultez les benchmarks, il est courant de voir plusieurs outils de types différents comparés comme s’ils étaient équivalents.
|
||||
Lorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents.
|
||||
|
||||
En particulier, de voir Uvicorn, Starlette et FastAPI comparés ensemble (parmi de nombreux autres outils).
|
||||
En particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils).
|
||||
|
||||
Plus le problème résolu par l’outil est simple, meilleures seront les performances qu’il obtiendra. Et la plupart des benchmarks ne testent pas les fonctionnalités supplémentaires fournies par l’outil.
|
||||
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.
|
||||
|
||||
La hiérarchie est la suivante :
|
||||
|
||||
* **Uvicorn** : un serveur ASGI
|
||||
* **Starlette** : (utilise Uvicorn) un microframework web
|
||||
* **FastAPI** : (utilise Starlette) un microframework d’API avec plusieurs fonctionnalités supplémentaires pour construire des API, avec la validation des données, etc.
|
||||
* **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.
|
||||
|
||||
* **Uvicorn** :
|
||||
* Aura les meilleures performances, car il n’a 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 d’applications.
|
||||
* 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.
|
||||
* **Starlette** :
|
||||
* Aura les performances suivantes, après Uvicorn. En fait, Starlette utilise Uvicorn pour s’exécuter. Donc, il ne peut probablement que devenir « plus lent » qu’Uvicorn, 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).
|
||||
* 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.
|
||||
* **FastAPI** :
|
||||
* 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 l’utilisant, vous obtenez de la documentation automatique gratuitement (la documentation automatique n’ajoute même pas de surcharge à l’exécution des applications, elle est générée au démarrage).
|
||||
* Si vous n’utilisiez 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 l’utilisiez pas (puisque vous devriez tout implémenter dans votre code).
|
||||
* Si vous comparez FastAPI, comparez-le à un framework d’application web (ou à un ensemble d’outils) 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.
|
||||
* 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.
|
||||
|
||||
@@ -1,151 +1,74 @@
|
||||
# FastAPI dans des conteneurs - Docker { #fastapi-in-containers-docker }
|
||||
# Déployer avec Docker
|
||||
|
||||
Lors du déploiement d’applications 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 l’une de plusieurs manières possibles.
|
||||
Dans cette section, vous verrez des instructions et des liens vers des guides pour savoir comment :
|
||||
|
||||
L’utilisation de conteneurs Linux présente plusieurs avantages, notamment la **sécurité**, la **réplicabilité**, la **simplicité**, et d’autres.
|
||||
* 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.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous êtes pressé(e) et vous connaissez déjà tout ça ? Allez directement au [`Dockerfile` ci-dessous 👇](#build-a-docker-image-for-fastapi).
|
||||
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>.
|
||||
|
||||
///
|
||||
|
||||
<details>
|
||||
<summary>Aperçu du Dockerfile 👀</summary>
|
||||
## Créer un `Dockerfile`
|
||||
|
||||
* Allez dans le répertoire de votre projet.
|
||||
* Créez un `Dockerfile` avec :
|
||||
|
||||
```Dockerfile
|
||||
FROM python:3.9
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
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"]
|
||||
COPY ./app /app
|
||||
```
|
||||
|
||||
</details>
|
||||
### Applications plus larges
|
||||
|
||||
## Qu’est-ce qu’un conteneur { #what-is-a-container }
|
||||
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 :
|
||||
|
||||
Les conteneurs (principalement les conteneurs Linux) sont une manière très **légère** d’empaqueter des applications, y compris toutes leurs dépendances et les fichiers nécessaires, tout en les gardant isolées des autres conteneurs (d’autres applications ou composants) sur le même système.
|
||||
```Dockerfile
|
||||
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
|
||||
|
||||
Les conteneurs Linux s’exécutent en utilisant le même kernel Linux que l’hôte (machine, machine virtuelle, serveur cloud, etc.). Cela signifie simplement qu’ils sont très légers (comparés à des machines virtuelles complètes émulant un système d’exploitation entier).
|
||||
|
||||
Ainsi, les conteneurs consomment **peu de ressources**, une quantité comparable à l’exécution directe des processus (une machine virtuelle consommerait bien plus).
|
||||
|
||||
Les conteneurs ont aussi leurs propres processus en cours d’exé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.
|
||||
|
||||
## Qu’est-ce qu’une image de conteneur { #what-is-a-container-image }
|
||||
|
||||
Un **conteneur** s’exécute à partir d’une **image de conteneur**.
|
||||
|
||||
Une image de conteneur est une version **statique** de tous les fichiers, des variables d’environnement, 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 s’exécute pas, elle n’est 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 l’instance en cours d’exécution, la chose qui est **exécutée**.
|
||||
|
||||
Quand le **conteneur** est démarré et s’exécute (démarré depuis une **image de conteneur**), il peut créer ou modifier des fichiers, des variables d’environnement, etc. Ces changements n’existeront que dans ce conteneur, et ne persisteront pas dans l’image de conteneur sous-jacente (ils ne seront pas enregistrés sur disque).
|
||||
|
||||
Une image de conteneur est comparable au fichier et au contenu d’un **programme**, par exemple `python` et un fichier `main.py`.
|
||||
|
||||
Et le **conteneur** lui-même (par opposition à l’**image de conteneur**) est l’instance réellement exécutée de l’image, comparable à un **processus**. En fait, un conteneur ne s’exécute que lorsqu’il a un **processus en cours d’exécution** (et normalement c’est un seul processus). Le conteneur s’arrête lorsqu’il n’y a plus de processus en cours d’exécution à l’intérieur.
|
||||
|
||||
## Images de conteneur { #container-images }
|
||||
|
||||
Docker a été l’un 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 d’autres 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 d’utiliser 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 d’environnement.
|
||||
|
||||
De cette façon, dans de nombreux cas, vous pouvez apprendre les conteneurs et Docker et réutiliser ces connaissances avec beaucoup d’outils 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 l’outrepasser et lui faire exécuter une commande/un programme différent).
|
||||
|
||||
Un conteneur s’exécute tant que le **processus principal** (commande ou programme) s’exé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 n’est pas possible d’avoir un conteneur en cours d’exécution sans **au moins un processus en cours d’exécution**. Si le processus principal s’arrête, le conteneur s’arrê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**.
|
||||
|
||||
C’est 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 l’outil que vous utilisez pour **installer** ces exigences.
|
||||
|
||||
La manière la plus courante de le faire est d’avoir 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
|
||||
COPY ./app /app/app
|
||||
```
|
||||
|
||||
Et vous installeriez normalement ces dépendances de packages avec `pip`, par exemple :
|
||||
### Raspberry Pi et autres architectures
|
||||
|
||||
<div class="termy">
|
||||
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.
|
||||
|
||||
```console
|
||||
$ pip install -r requirements.txt
|
||||
---> 100%
|
||||
Successfully installed fastapi pydantic
|
||||
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"]
|
||||
```
|
||||
|
||||
</div>
|
||||
## Créer le code **FastAPI**.
|
||||
|
||||
/// info
|
||||
|
||||
Il existe d’autres 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 :
|
||||
* Créer un répertoire `app` et y entrer.
|
||||
* Créez un fichier `main.py` avec :
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
@@ -158,166 +81,20 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
### 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 l’image de base Python officielle.
|
||||
|
||||
2. Définir le répertoire de travail courant sur `/code`.
|
||||
|
||||
C’est 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 d’abord, pas le reste du code.
|
||||
|
||||
Comme ce fichier **ne change pas souvent**, Docker le détectera et utilisera le **cache** pour cette étape, permettant d’utiliser le cache pour l’étape suivante aussi.
|
||||
|
||||
4. Installer les dépendances de packages du fichier d’exigences.
|
||||
|
||||
L’option `--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 n’est pas le cas lorsqu’on travaille avec des conteneurs.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
`--no-cache-dir` est uniquement lié à `pip`, il n’a rien à voir avec Docker ou les conteneurs.
|
||||
|
||||
///
|
||||
|
||||
L’option `--upgrade` indique à `pip` de mettre à niveau les packages s’ils 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** lorsqu’il est disponible.
|
||||
|
||||
Utiliser le cache à cette étape va vous **faire gagner** beaucoup de **temps** lorsque vous reconstruisez l’image 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 l’image 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 d’utiliser **toujours** la **forme exec** de l’instruction `CMD`, comme expliqué ci-dessous.
|
||||
|
||||
///
|
||||
|
||||
#### Utiliser `CMD` - forme exec { #use-cmd-exec-form }
|
||||
|
||||
L’instruction 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 s’arrê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 l’utilisation 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 :
|
||||
* Vous devriez maintenant avoir une structure de répertoire telle que :
|
||||
|
||||
```
|
||||
.
|
||||
├── app
|
||||
│ ├── __init__.py
|
||||
│ └── main.py
|
||||
├── Dockerfile
|
||||
└── requirements.txt
|
||||
└── Dockerfile
|
||||
```
|
||||
|
||||
#### 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 l’option `--proxy-headers` ; cela indiquera à Uvicorn (via la CLI FastAPI) de faire confiance aux en-têtes envoyés par ce proxy lui indiquant que l’application s’exé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 d’abord **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 d’autres outils **construisent** ces images de conteneur **de manière incrémentale**, en ajoutant **une couche par-dessus l’autre**, 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 l’image : si un fichier n’a pas changé depuis la dernière construction de l’image 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 n’amé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 l’instruction 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 c’est là que nous **gagnons beaucoup de temps**. ✨ ... et évitons l’ennui d’attendre. 😪😆
|
||||
|
||||
Le téléchargement et l’installation des dépendances de packages **peuvent prendre des minutes**, mais utiliser le **cache** **prendrait au maximum quelques secondes**.
|
||||
|
||||
Et comme vous reconstruiriez l’image 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 c’est 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 l’image Docker { #build-the-docker-image }
|
||||
|
||||
Maintenant que tous les fichiers sont en place, construisons l’image de conteneur.
|
||||
## Construire l'image Docker
|
||||
|
||||
* Allez dans le répertoire du projet (dans lequel se trouve votre `Dockerfile`, contenant votre répertoire `app`).
|
||||
* Construisez votre image FastAPI :
|
||||
@@ -332,17 +109,9 @@ $ docker build -t myimage .
|
||||
|
||||
</div>
|
||||
|
||||
/// tip | Astuce
|
||||
## Démarrer le conteneur Docker
|
||||
|
||||
Remarquez le `.` à la fin, il est équivalent à `./` : il indique à Docker le répertoire à utiliser pour construire l’image de conteneur.
|
||||
|
||||
Dans ce cas, c’est le même répertoire courant (`.`).
|
||||
|
||||
///
|
||||
|
||||
### Démarrer le conteneur Docker { #start-the-docker-container }
|
||||
|
||||
* Exécutez un conteneur basé sur votre image :
|
||||
* Exécutez un conteneur basé sur votre image :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -352,269 +121,65 @@ $ docker run -d --name mycontainer -p 80:80 myimage
|
||||
|
||||
</div>
|
||||
|
||||
## Vérifier { #check-it }
|
||||
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).
|
||||
|
||||
Vous devriez pouvoir le vérifier 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).
|
||||
## Vérifier
|
||||
|
||||
Vous verrez quelque chose comme :
|
||||
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 :
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## Documentation interactive de l’API { #interactive-api-docs }
|
||||
## Documentation interactive de l'API
|
||||
|
||||
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 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 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 l'API (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
|
||||

|
||||
|
||||
## Documentation de l’API alternative { #alternative-api-docs }
|
||||
## Documentation de l'API alternative
|
||||
|
||||
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>) :
|
||||
|
||||

|
||||
|
||||
## Construire une image Docker avec un FastAPI dans un seul fichier { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
## Traefik
|
||||
|
||||
Si votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./app`, votre structure de fichiers pourrait ressembler à ceci :
|
||||
<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).
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile
|
||||
├── main.py
|
||||
└── requirements.txt
|
||||
```
|
||||
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.
|
||||
|
||||
Ensuite, vous n’auriez 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 qu’il s’agit d’un fichier unique et non d’une partie d’un package, et saura comment l’importer 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** d’une application, mais ils n’imposent pas une approche particulière pour gérer ces **concepts de déploiement**, et il existe plusieurs stratégies possibles.
|
||||
|
||||
La **bonne nouvelle**, c’est qu’avec 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 d’exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables avant de démarrer
|
||||
|
||||
## HTTPS { #https }
|
||||
|
||||
Si nous nous concentrons uniquement sur l’**image de conteneur** d’une application FastAPI (et plus tard sur le **conteneur** en cours d’exé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 l’acquisition **automatique** de **certificats**.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Traefik dispose d’intégrations avec Docker, Kubernetes et d’autres, 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 l’un de ses services (tout en exécutant l’application 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 l’exécution du conteneur au démarrage et activer les redémarrages en cas d’échec. Par exemple, dans Docker, c’est l’option 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 d’une 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 d’utiliser 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 d’un 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 d’utiliser plusieurs workers Uvicorn.
|
||||
|
||||
### Load Balancer { #load-balancer }
|
||||
|
||||
Lors de l’utilisation 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 d’une manière (espérons-le) **équilibrée**, on l’appelle 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 l’un 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 *d’autres* applications dans votre cluster (par exemple vers un domaine différent, ou sous un préfixe de chemin d’URL différent), et transmettrait cette communication aux bons conteneurs pour *cette autre* application s’exé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 l’option en ligne de commande `--workers`. Vous voudrez avoir un **seul processus Uvicorn** par conteneur (mais probablement plusieurs conteneurs).
|
||||
|
||||
Avoir un autre gestionnaire de processus à l’intérieur du conteneur (comme ce serait le cas avec plusieurs workers) ne ferait qu’ajouter 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** à l’intérieur.
|
||||
|
||||
Dans ces cas, vous pouvez utiliser l’option 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 l’option 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 s’exé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 n’auriez 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** à l’intérieur.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
Le point principal est que **rien** de tout cela n’est 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 d’usage** et décider quelle est la meilleure approche pour votre système, en examinant comment gérer les concepts de :
|
||||
Avec ces informations et ces outils, passez à la section suivante pour tout combiner.
|
||||
|
||||
* Sécurité - HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours d’exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables avant de démarrer
|
||||
## Cluster en mode Docker Swarm avec Traefik et HTTPS
|
||||
|
||||
## Mémoire { #memory }
|
||||
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).
|
||||
|
||||
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 d’un si vous les répliquez).
|
||||
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.
|
||||
|
||||
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.
|
||||
Pour configurer un cluster en mode Docker Swarm avec Traefik et la gestion de HTTPS, suivez ce guide :
|
||||
|
||||
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 s’exécutent sur **chaque machine** (et peut-être ajouter plus de machines à votre 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 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.
|
||||
### Déployer une application FastAPI
|
||||
|
||||
## Étapes préalables avant de démarrer et conteneurs { #previous-steps-before-starting-and-containers }
|
||||
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}.
|
||||
|
||||
Si vous utilisez des conteneurs (par exemple Docker, Kubernetes), alors il existe deux approches principales que vous pouvez utiliser.
|
||||
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.
|
||||
|
||||
### Plusieurs conteneurs { #multiple-containers }
|
||||
Vous pouvez générer un projet en 2 min environ.
|
||||
|
||||
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** d’exé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 d’usage, il n’y a pas de problème à exécuter ces étapes préalables **plusieurs fois en parallèle** (par exemple si vous n’exé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 l’application.
|
||||
|
||||
### 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 d’autres) 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 l’option en ligne de commande `--workers`.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
L’image 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 d’utiliser 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 qu’Uvicorn (et la commande `fastapi`) prennent en charge l’utilisation de `--workers`, il n’y a aucune raison d’utiliser une image Docker de base au lieu de construire la vôtre (c’est à peu près la même quantité de code 😅).
|
||||
|
||||
///
|
||||
|
||||
## Déployer l’image 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 d’exé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 l’image 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 l’ennui). 😎
|
||||
Le projet généré a des instructions pour le déployer et le faire prend 2 min de plus.
|
||||
|
||||
@@ -1,231 +1,56 @@
|
||||
# À propos de HTTPS { #about-https }
|
||||
# À propos de HTTPS
|
||||
|
||||
Il est facile de supposer que HTTPS est quelque chose qui est simplement « activé » ou non.
|
||||
Il est facile de penser que HTTPS peut simplement être "activé" ou non.
|
||||
|
||||
Mais c'est bien plus complexe que cela.
|
||||
Mais c'est beaucoup plus complexe que cela.
|
||||
|
||||
/// tip | Astuce
|
||||
/// tip
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
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>.
|
||||
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>.
|
||||
|
||||
Maintenant, du point de vue d'un développeur, voici plusieurs choses à garder à l'esprit en pensant à HTTPS :
|
||||
Maintenant, du point de vue d'un développeur, voici plusieurs choses à avoir en tête en pensant au HTTPS :
|
||||
|
||||
* 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**.
|
||||
* 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.
|
||||
|
||||
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>**.
|
||||
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>.
|
||||
|
||||
Certaines des options que vous pouvez utiliser comme Proxy de terminaison TLS sont :
|
||||
## Let's Encrypt
|
||||
|
||||
* 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.
|
||||
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 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.
|
||||
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.
|
||||
|
||||
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, 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**. 🔒
|
||||
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.
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
# Déploiement { #deployment }
|
||||
# Déploiement
|
||||
|
||||
Le déploiement d'une application **FastAPI** est relativement simple.
|
||||
|
||||
## Que signifie le déploiement { #what-does-deployment-mean }
|
||||
## Que signifie le déploiement
|
||||
|
||||
**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 { #deployment-strategies }
|
||||
## Stratégies de déploiement
|
||||
|
||||
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.
|
||||
|
||||
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).
|
||||
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. ✨
|
||||
|
||||
@@ -1,78 +1,85 @@
|
||||
# À propos des versions de FastAPI { #about-fastapi-versions }
|
||||
# À propos des versions de FastAPI
|
||||
|
||||
**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.
|
||||
**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.
|
||||
|
||||
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement, et le code continue de s’améliorer en continu.
|
||||
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code est
|
||||
amélioré continuellement.
|
||||
|
||||
C’est 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>.
|
||||
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>.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Épinglez votre version de `fastapi` { #pin-your-fastapi-version }
|
||||
## Épinglez votre version de `fastapi`
|
||||
|
||||
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 qu’elle fonctionne correctement pour votre application.
|
||||
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.
|
||||
|
||||
Par exemple, disons que vous utilisez la version `0.112.0` dans votre app.
|
||||
Par exemple, disons que vous utilisez la version `0.45.0` dans votre application.
|
||||
|
||||
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[standard]==0.112.0
|
||||
fastapi==0.45.0
|
||||
```
|
||||
|
||||
cela signifierait que vous utiliseriez exactement la version `0.112.0`.
|
||||
ce qui signifierait que vous utiliseriez exactement la version `0.45.0`.
|
||||
|
||||
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 :
|
||||
Ou vous pourriez aussi l'épingler avec :
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Les changements incompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions « MINOR ».
|
||||
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.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le « MINOR » est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
|
||||
Le "PATCH" est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.
|
||||
|
||||
///
|
||||
|
||||
## Mettre à niveau les versions de FastAPI { #upgrading-the-fastapi-versions }
|
||||
Donc, vous devriez être capable d'épingler une version comme suit :
|
||||
|
||||
Vous devez ajouter des tests pour votre app.
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Avec **FastAPI**, c’est très facile (grâce à Starlette), consultez la documentation : [Testing](../tutorial/testing.md){.internal-link target=_blank}
|
||||
Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions "MINOR".
|
||||
|
||||
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.
|
||||
/// tip | Astuce
|
||||
|
||||
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.
|
||||
Le "MINOR" est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
|
||||
|
||||
## À propos de Starlette { #about-starlette }
|
||||
///
|
||||
|
||||
## 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
|
||||
|
||||
Vous ne devriez pas épingler la version de `starlette`.
|
||||
|
||||
@@ -80,14 +87,15 @@ 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 { #about-pydantic }
|
||||
## À propos de Pydantic
|
||||
|
||||
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.
|
||||
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**.
|
||||
|
||||
Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous.
|
||||
Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous et inférieure à `2.0.0`.
|
||||
|
||||
Par exemple :
|
||||
Par exemple :
|
||||
|
||||
```txt
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
pydantic>=1.2.0,<2.0.0
|
||||
```
|
||||
|
||||
@@ -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/fr"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
<a href="https://fastapi.tiangolo.com"><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/fr" target="_blank">https://fastapi.tiangolo.com</a>
|
||||
**Documentation** : <a href="https://fastapi.tiangolo.com" 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,124 +41,120 @@ 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 les documents.
|
||||
* **Facile** : Conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire la documentation.
|
||||
* **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 -->
|
||||
|
||||
### 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 }
|
||||
|
||||
{% if 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/fr/fastapi-people/#sponsors" class="external-link" target="_blank">Autres sponsors</a>
|
||||
<a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
|
||||
|
||||
## Opinions { #opinions }
|
||||
## Opinions
|
||||
|
||||
"_[...] 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._"
|
||||
"_[...] 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**._"
|
||||
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
|
||||
"_Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_"
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
|
||||
"_**Netflix** a le plaisir d'annoncer la sortie en open-source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **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>
|
||||
|
||||
---
|
||||
|
||||
"_I’m over the moon excited about **FastAPI**. It’s so fun!_"
|
||||
"_Je suis très enthousiaste à propos de **FastAPI**. C'est un bonheur !_"
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
"_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._"
|
||||
"_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._"
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
"_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 [...]_"
|
||||
"_Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et à apprendre [...]_"
|
||||
|
||||
"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
|
||||
"_Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_"
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
"_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._"
|
||||
"_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._"
|
||||
|
||||
<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>
|
||||
|
||||
---
|
||||
|
||||
## 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 }
|
||||
## **Typer**, le FastAPI des <abbr title="Command Line Interface">CLI</abbr>
|
||||
|
||||
<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 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>.
|
||||
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>.
|
||||
|
||||
**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 { #requirements }
|
||||
## Prérequis
|
||||
|
||||
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 }
|
||||
|
||||
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 :
|
||||
## Installation
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
$ pip install fastapi
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
**Remarque** : vous devez mettre `"fastapi[standard]"` entre guillemets pour vous assurer que cela fonctionne dans tous les terminaux.
|
||||
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>.
|
||||
|
||||
## Exemple { #example }
|
||||
<div class="termy">
|
||||
|
||||
### Créez-le { #create-it }
|
||||
```console
|
||||
$ pip install "uvicorn[standard]"
|
||||
|
||||
Créez un fichier `main.py` avec :
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Exemple
|
||||
|
||||
### Créez
|
||||
|
||||
* Créez un fichier `main.py` avec :
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
@@ -179,7 +175,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` :
|
||||
|
||||
@@ -201,37 +197,24 @@ async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
**Remarque** :
|
||||
**Note**
|
||||
|
||||
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>.
|
||||
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>.
|
||||
|
||||
</details>
|
||||
|
||||
### Lancez-le { #run-it }
|
||||
### Lancez
|
||||
|
||||
Lancez le serveur avec :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ fastapi dev main.py
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
╭────────── 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 [2248755] using WatchFiles
|
||||
INFO: Started server process [2248757]
|
||||
INFO: Started reloader process [28720]
|
||||
INFO: Started server process [28722]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
```
|
||||
@@ -239,21 +222,21 @@ INFO: Application startup complete.
|
||||
</div>
|
||||
|
||||
<details markdown="1">
|
||||
<summary>À propos de la commande <code>fastapi dev main.py</code>...</summary>
|
||||
<summary>À propos de la commande <code>uvicorn main:app --reload</code> ...</summary>
|
||||
|
||||
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>.
|
||||
La commande `uvicorn main:app` fait référence à :
|
||||
|
||||
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>.
|
||||
* `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.
|
||||
|
||||
</details>
|
||||
|
||||
### Vérifiez-le { #check-it }
|
||||
### Vérifiez
|
||||
|
||||
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 verrez la réponse JSON comme suit :
|
||||
Vous obtenez alors cette réponse <abbr title="JavaScript Object Notation">JSON</abbr> :
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
@@ -263,10 +246,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 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`.
|
||||
* 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`.
|
||||
|
||||
### Documentation API interactive { #interactive-api-docs }
|
||||
### Documentation API interactive
|
||||
|
||||
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>.
|
||||
|
||||
@@ -274,17 +257,17 @@ Vous verrez la documentation interactive automatique de l'API (fournie par <a hr
|
||||
|
||||

|
||||
|
||||
### Documentation API alternative { #alternative-api-docs }
|
||||
### Documentation API alternative
|
||||
|
||||
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 automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">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>) :
|
||||
|
||||

|
||||
|
||||
## Mettre à niveau l'exemple { #example-upgrade }
|
||||
## Exemple plus poussé
|
||||
|
||||
Maintenant, modifiez le fichier `main.py` pour recevoir un corps à partir d'une requête `PUT`.
|
||||
Maintenant, modifiez le fichier `main.py` pour recevoir <abbr title="en anglais : body">le corps</abbr> d'une requête `PUT`.
|
||||
|
||||
Déclarez ce corps en utilisant les types Python standards, grâce à Pydantic.
|
||||
|
||||
@@ -318,35 +301,35 @@ def update_item(item_id: int, item: Item):
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
```
|
||||
|
||||
Le serveur `fastapi dev` devrait se recharger automatiquement.
|
||||
Le serveur se recharge normalement automatiquement (car vous avez pensé à `--reload` dans la commande `uvicorn` ci-dessus).
|
||||
|
||||
### Mettre à niveau la documentation API interactive { #interactive-api-docs-upgrade }
|
||||
### Plus loin avec la documentation API interactive
|
||||
|
||||
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 :
|
||||
* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps de la requête :
|
||||
|
||||

|
||||
|
||||
* 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 :
|
||||
|
||||

|
||||
|
||||
* 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 :
|
||||
|
||||

|
||||
|
||||
### Mettre à niveau la documentation API alternative { #alternative-api-docs-upgrade }
|
||||
### Plus loin avec la documentation API alternative
|
||||
|
||||
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 corps :
|
||||
* La documentation alternative reflétera également le nouveau paramètre de requête et le nouveau corps :
|
||||
|
||||

|
||||
|
||||
### En résumé { #recap }
|
||||
### En résumé
|
||||
|
||||
En résumé, vous déclarez **une fois** les types de paramètres, le corps, etc. en tant que paramètres de fonction.
|
||||
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.
|
||||
|
||||
Vous faites cela avec les types Python standard modernes.
|
||||
|
||||
@@ -368,48 +351,48 @@ item: Item
|
||||
|
||||
... et avec cette déclaration unique, vous obtenez :
|
||||
|
||||
* Une assistance dans votre éditeur, notamment :
|
||||
* Une assistance dans votre IDE, 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 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).
|
||||
* 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).
|
||||
* les objets `datetime`.
|
||||
* les objets `UUID`.
|
||||
* les modèles de base de données.
|
||||
* ... et beaucoup plus.
|
||||
* La documentation API interactive automatique, incluant 2 interfaces utilisateur alternatives :
|
||||
* La documentation API interactive automatique, avec 2 interfaces utilisateur au choix :
|
||||
* Swagger UI.
|
||||
* ReDoc.
|
||||
|
||||
---
|
||||
|
||||
Pour revenir à l'exemple de code précédent, **FastAPI** va :
|
||||
Pour revenir à l'exemple de code précédent, **FastAPI** permet de :
|
||||
|
||||
* 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 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 :
|
||||
* 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> :
|
||||
* Vérifier qu'il a un attribut obligatoire `name` qui devrait être un `str`.
|
||||
* Vérifier qu'il a un attribut obligatoire `price` qui doit être un `float`.
|
||||
* Vérifier qu'il a un attribut obligatoire `prix` 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 JSON profondément imbriqués.
|
||||
* Convertir automatiquement depuis et vers JSON.
|
||||
* 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.
|
||||
* Documenter tout avec OpenAPI, qui peut être utilisé par :
|
||||
* Les systèmes de documentation interactive.
|
||||
* Les systèmes de documentation interactifs.
|
||||
* Les systèmes de génération automatique de code client, pour de nombreuses langues.
|
||||
* Fournir directement 2 interfaces web de documentation interactive.
|
||||
|
||||
@@ -437,129 +420,53 @@ Essayez de changer la ligne contenant :
|
||||
|
||||
... et voyez comment votre éditeur complétera automatiquement les attributs et connaîtra leurs types :
|
||||
|
||||

|
||||

|
||||
|
||||
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 : **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).
|
||||
* 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).
|
||||
* Intégration de **GraphQL** avec <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> et d'autres bibliothèques.
|
||||
* De nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
|
||||
* D'obtenir de nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
|
||||
* **WebSockets**
|
||||
* des tests extrêmement simples basés sur HTTPX et `pytest`
|
||||
* **CORS**
|
||||
* de tester le code très facilement avec `requests` et `pytest`
|
||||
* **<abbr title="Cross-Origin Resource Sharing">CORS</abbr>**
|
||||
* **Cookie Sessions**
|
||||
* ... et plus encore.
|
||||
|
||||
### Déployer votre app (optionnel) { #deploy-your-app-optional }
|
||||
## Performance
|
||||
|
||||
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). (*)
|
||||
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). (*)
|
||||
|
||||
Pour en savoir plus, consultez la section <a href="https://fastapi.tiangolo.com/fr/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
|
||||
|
||||
## Dépendances { #dependencies }
|
||||
## Dépendances facultatives
|
||||
|
||||
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 :
|
||||
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://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obligatoire si vous souhaitez utiliser `TestClient`.
|
||||
* <a href="https://requests.readthedocs.io" target="_blank"><code>requests</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="conversion de la chaîne qui provient d'une requête HTTP en données Python">« parsing »</abbr> de formulaire, avec `request.form()`.
|
||||
* <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).
|
||||
|
||||
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 :
|
||||
Utilisées par FastAPI / Starlette :
|
||||
|
||||
* <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 voulez utiliser `UJSONResponse`.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Obligatoire si vous souhaitez utiliser `UJSONResponse`.
|
||||
|
||||
## Licence { #license }
|
||||
Vous pouvez tout installer avec `pip install fastapi[all]`.
|
||||
|
||||
## Licence
|
||||
|
||||
Ce projet est soumis aux termes de la licence MIT.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Apprendre { #learn }
|
||||
# Apprendre
|
||||
|
||||
Voici les sections introductives et les tutoriels pour apprendre **FastAPI**.
|
||||
|
||||
Vous pouvez considérer ceci comme un **livre**, un **cours**, la **méthode officielle** et recommandée pour apprendre FastAPI. 😎
|
||||
Vous pouvez considérer ceci comme un **manuel**, un **cours**, la **méthode officielle** et recommandée pour appréhender FastAPI. 😎
|
||||
|
||||
@@ -1,28 +1,84 @@
|
||||
# Modèle Full Stack FastAPI { #full-stack-fastapi-template }
|
||||
# Génération de projets - Modèle
|
||||
|
||||
Les modèles, bien qu’ils 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. 🏁
|
||||
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.
|
||||
|
||||
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 d’API déjà faits pour vous.
|
||||
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.
|
||||
|
||||
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>
|
||||
## Full Stack FastAPI PostgreSQL
|
||||
|
||||
## Modèle Full Stack FastAPI - Stack technologique et fonctionnalités { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
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>
|
||||
|
||||
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/fr) pour l’API 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 d’autres éléments d’une 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.
|
||||
### 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.
|
||||
|
||||
@@ -1,68 +1,70 @@
|
||||
# Introduction aux Types Python { #python-types-intro }
|
||||
# Introduction aux Types Python
|
||||
|
||||
Python supporte des « type hints » optionnels (aussi appelés « type annotations »).
|
||||
Python supporte des annotations de type (ou *type hints*) optionnelles.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
En déclarant des types pour vos variables, les éditeurs et les outils peuvent vous offrir un meilleur support.
|
||||
En déclarant les types de vos variables, cela permet aux différents outils comme les éditeurs de texte d'offrir un meilleur support.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
**FastAPI** est entièrement basé sur ces « type hints », ils lui donnent de nombreux avantages et bénéfices.
|
||||
**FastAPI** est totalement basé sur ces annotations de type, qui lui donnent de nombreux avantages.
|
||||
|
||||
Mais même si vous n'utilisez jamais **FastAPI**, vous auriez intérêt à en apprendre un peu à leur sujet.
|
||||
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.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Si vous êtes un expert Python, et que vous savez déjà tout sur les « type hints », passez au chapitre suivant.
|
||||
Si vous êtes un expert Python, et que vous savez déjà **tout** sur les annotations de type, passez au chapitre suivant.
|
||||
|
||||
///
|
||||
|
||||
## Motivation { #motivation }
|
||||
## Motivations
|
||||
|
||||
Commençons par un exemple simple :
|
||||
Prenons un exemple simple :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py *}
|
||||
{*../../docs_src/python_types/tutorial001.py*}
|
||||
|
||||
L'exécution de ce programme affiche :
|
||||
Exécuter ce programe affiche :
|
||||
|
||||
```
|
||||
John Doe
|
||||
```
|
||||
|
||||
La fonction fait ce qui suit :
|
||||
La fonction :
|
||||
|
||||
* Prend un `first_name` et un `last_name`.
|
||||
* 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.
|
||||
* 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.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
|
||||
{*../../docs_src/python_types/tutorial001.py hl[2] *}
|
||||
|
||||
### Le modifier { #edit-it }
|
||||
### Limitations
|
||||
|
||||
C'est un programme très simple.
|
||||
|
||||
Mais imaginez maintenant que vous l'écriviez de zéro.
|
||||
Mais maintenant imaginez 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 ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ».
|
||||
Mais vous aviez besoin de "cette méthode qui convertit la première lettre en majuscule".
|
||||
|
||||
Était-ce `upper` ? Était-ce `uppercase` ? `first_uppercase` ? `capitalize` ?
|
||||
Était-ce `upper` ? `uppercase` ? `first_uppercase` ? `capitalize` ?
|
||||
|
||||
Ensuite, vous essayez avec le vieil ami du programmeur, l'autocomplétion de l'éditeur.
|
||||
Vous essayez donc d'utiliser le vieil ami du programmeur, l'auto-complétion de l'éditeur.
|
||||
|
||||
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.
|
||||
Vous écrivez le premier paramètre, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'auto-complétion.
|
||||
|
||||
Mais, malheureusement, vous n'obtenez rien d'utile :
|
||||
Mais malheureusement, rien d'utile n'en résulte :
|
||||
|
||||
<img src="/img/python-types/image01.png">
|
||||
|
||||
### Ajouter des types { #add-types }
|
||||
### Ajouter des types
|
||||
|
||||
Modifions une seule ligne de la version précédente.
|
||||
|
||||
Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
|
||||
Nous allons changer seulement cet extrait, les paramètres de la fonction, de :
|
||||
|
||||
|
||||
```Python
|
||||
first_name, last_name
|
||||
@@ -76,11 +78,11 @@ Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
|
||||
|
||||
C'est tout.
|
||||
|
||||
Ce sont les « type hints » :
|
||||
Ce sont des annotations de types :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial002.py hl[1] *}
|
||||
|
||||
Ce n'est pas la même chose que de déclarer des valeurs par défaut, comme ce serait le cas avec :
|
||||
À ne pas confondre avec la déclaration de valeurs par défaut comme ici :
|
||||
|
||||
```Python
|
||||
first_name="john", last_name="doe"
|
||||
@@ -88,377 +90,210 @@ Ce n'est pas la même chose que de déclarer des valeurs par défaut, comme ce s
|
||||
|
||||
C'est une chose différente.
|
||||
|
||||
Nous utilisons des deux-points (`:`), pas des signes égal (`=`).
|
||||
On utilise un deux-points (`:`), et pas un égal (`=`).
|
||||
|
||||
Et ajouter des « type hints » ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans eux.
|
||||
Et ajouter des annotations de types ne crée normalement pas de différence avec le comportement qui aurait eu lieu si elles n'étaient pas là.
|
||||
|
||||
Mais maintenant, imaginez que vous êtes à nouveau en plein milieu de la création de cette fonction, mais avec des « type hints ».
|
||||
Maintenant, imaginez que vous êtes en train de créer cette fonction, mais avec des annotations de type cette fois.
|
||||
|
||||
Au même endroit, vous essayez de déclencher l'autocomplétion avec `Ctrl+Space` et vous voyez :
|
||||
Au même moment que durant l'exemple précédent, vous essayez de déclencher l'auto-complétion et vous voyez :
|
||||
|
||||
<img src="/img/python-types/image02.png">
|
||||
|
||||
Avec ça, vous pouvez faire défiler, voir les options, jusqu'à trouver celle qui « vous dit quelque chose » :
|
||||
Vous pouvez donc dérouler les options jusqu'à trouver la méthode à laquelle vous pensiez.
|
||||
|
||||
<img src="/img/python-types/image03.png">
|
||||
|
||||
## Plus de motivation { #more-motivation }
|
||||
## Plus de motivations
|
||||
|
||||
Regardez cette fonction, elle a déjà des « type hints » :
|
||||
Cette fonction possède déjà des annotations de type :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial003.py hl[1] *}
|
||||
|
||||
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 :
|
||||
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 :
|
||||
|
||||
<img src="/img/python-types/image04.png">
|
||||
|
||||
Maintenant vous savez que vous devez le corriger, convertir `age` en chaîne de caractères avec `str(age)` :
|
||||
Maintenant que vous avez connaissance du problème, convertissez `age` en <abbr title="string">chaîne de caractères</abbr> grâce à `str(age)` :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
|
||||
{*../../docs_src/python_types/tutorial004.py hl[2] *}
|
||||
|
||||
## Déclarer des types { #declaring-types }
|
||||
## Déclarer des types
|
||||
|
||||
Vous venez de voir l'endroit principal pour déclarer des « type hints ». En tant que paramètres de fonction.
|
||||
Vous venez de voir là où les types sont généralement déclarés : dans les paramètres de fonctions.
|
||||
|
||||
C'est aussi l'endroit principal où vous les utiliseriez avec **FastAPI**.
|
||||
C'est aussi ici que vous les utiliseriez avec **FastAPI**.
|
||||
|
||||
### Types simples { #simple-types }
|
||||
### Types simples
|
||||
|
||||
Vous pouvez déclarer tous les types standards de Python, pas seulement `str`.
|
||||
Vous pouvez déclarer tous les types de Python, pas seulement `str`.
|
||||
|
||||
Vous pouvez utiliser, par exemple :
|
||||
Comme par exemple :
|
||||
|
||||
* `int`
|
||||
* `float`
|
||||
* `bool`
|
||||
* `bytes`
|
||||
|
||||
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial005.py hl[1] *}
|
||||
|
||||
### Types génériques avec des paramètres de type { #generic-types-with-type-parameters }
|
||||
### Types génériques avec des paramètres de 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.
|
||||
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.
|
||||
|
||||
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.
|
||||
Pour déclarer ces types et les types internes, on utilise le module standard de Python `typing`.
|
||||
|
||||
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 ».
|
||||
Il existe spécialement pour supporter ces annotations de types.
|
||||
|
||||
#### Versions plus récentes de Python { #newer-versions-of-python }
|
||||
#### `List`
|
||||
|
||||
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.
|
||||
Par exemple, définissons une variable comme `list` de `str`.
|
||||
|
||||
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.
|
||||
Importez `List` (avec un `L` majuscule) depuis `typing`.
|
||||
|
||||
Si vous pouvez choisir une version plus récente de Python pour votre projet, vous pourrez profiter de cette simplicité supplémentaire.
|
||||
{*../../docs_src/python_types/tutorial006.py hl[1] *}
|
||||
|
||||
Dans toute la documentation, il y a des exemples compatibles avec chaque version de Python (quand il y a une différence).
|
||||
Déclarez la variable, en utilisant la syntaxe des deux-points (`:`).
|
||||
|
||||
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).
|
||||
Et comme type, mettez `List`.
|
||||
|
||||
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+** ».
|
||||
Les listes étant un type contenant des types internes, mettez ces derniers entre crochets (`[`, `]`) :
|
||||
|
||||
#### List { #list }
|
||||
{*../../docs_src/python_types/tutorial006.py hl[4] *}
|
||||
|
||||
Par exemple, définissons une variable comme une `list` de `str`.
|
||||
/// tip | Astuce
|
||||
|
||||
Déclarez la variable, avec la même syntaxe de deux-points (`:`).
|
||||
Ces types internes entre crochets sont appelés des "paramètres de type".
|
||||
|
||||
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`.
|
||||
Ici, `str` est un paramètre de type passé à `List`.
|
||||
|
||||
///
|
||||
|
||||
Cela signifie : « la variable `items` est une `list`, et chacun des éléments de cette liste est un `str` ».
|
||||
Ce qui signifie : "la variable `items` est une `list`, et chacun de ses éléments a pour type `str`.
|
||||
|
||||
En faisant cela, votre éditeur peut fournir du support même pendant le traitement des éléments de la liste :
|
||||
En faisant cela, votre éditeur pourra vous aider, même pendant que vous traitez des éléments de la liste.
|
||||
|
||||
<img src="/img/python-types/image05.png">
|
||||
|
||||
Sans types, c'est presque impossible à réaliser.
|
||||
|
||||
Remarquez que la variable `item` est un des éléments de la liste `items`.
|
||||
Vous remarquerez que la variable `item` n'est qu'un des éléments de la list `items`.
|
||||
|
||||
Et pourtant, l'éditeur sait que c'est un `str`, et fournit du support pour ça.
|
||||
Et pourtant, l'éditeur sait qu'elle est de type `str` et pourra donc vous aider à l'utiliser.
|
||||
|
||||
#### Tuple et Set { #tuple-and-set }
|
||||
#### `Tuple` et `Set`
|
||||
|
||||
Vous feriez la même chose pour déclarer des `tuple` et des `set` :
|
||||
C'est le même fonctionnement pour déclarer un `tuple` ou un `set` :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *}
|
||||
{*../../docs_src/python_types/tutorial007.py hl[1,4] *}
|
||||
|
||||
Cela signifie :
|
||||
Dans cet exemple :
|
||||
|
||||
* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un autre `int`, et un `str`.
|
||||
* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un deuxième `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`, vous passez 2 paramètres de type, séparés par des virgules.
|
||||
Pour définir un `dict`, il faut lui passer 2 paramètres, séparés par une virgule (`,`).
|
||||
|
||||
Le premier paramètre de type est pour les clés du `dict`.
|
||||
Le premier paramètre de type est pour les clés et le second pour les valeurs du dictionnaire (`dict`).
|
||||
|
||||
Le second paramètre de type est pour les valeurs du `dict` :
|
||||
{*../../docs_src/python_types/tutorial008.py hl[1,4] *}
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
|
||||
Dans cet exemple :
|
||||
|
||||
Cela signifie :
|
||||
* 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`.
|
||||
|
||||
* 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).
|
||||
#### `Optional`
|
||||
|
||||
#### Union { #union }
|
||||
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`.
|
||||
|
||||
Vous pouvez déclarer qu'une variable peut être de **plusieurs types**, par exemple, un `int` ou un `str`.
|
||||
{*../../docs_src/python_types/tutorial009.py hl[1,4] *}
|
||||
|
||||
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.
|
||||
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.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>.
|
||||
#### Types génériques
|
||||
|
||||
//// tab | Python 3.10+
|
||||
Les types qui peuvent contenir des paramètres de types entre crochets, comme :
|
||||
|
||||
```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`
|
||||
* `List`
|
||||
* `Tuple`
|
||||
* `Set`
|
||||
* `Dict`
|
||||
* `Optional`
|
||||
* ...et d'autres.
|
||||
|
||||
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.
|
||||
sont appelés des **types génériques** ou **Generics**.
|
||||
|
||||
////
|
||||
|
||||
//// 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 }
|
||||
### Classes en tant que types
|
||||
|
||||
Vous pouvez aussi déclarer une classe comme type d'une variable.
|
||||
|
||||
Disons que vous avez une classe `Person`, avec un nom :
|
||||
Disons que vous avez une classe `Person`, avec une variable `name` :
|
||||
|
||||
{*../../docs_src/python_types/tutorial010.py hl[1:3] *}
|
||||
|
||||
{* ../../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_py39.py hl[6] *}
|
||||
{*../../docs_src/python_types/tutorial010.py hl[6] *}
|
||||
|
||||
Et alors, encore une fois, vous obtenez tout le support de l'éditeur :
|
||||
Et vous aurez accès, encore une fois, au support complet offert par l'éditeur :
|
||||
|
||||
<img src="/img/python-types/image06.png">
|
||||
|
||||
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 }
|
||||
## Les modèles Pydantic
|
||||
|
||||
<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 comme des classes avec des attributs.
|
||||
Vous déclarez la forme de la donnée avec des classes et des attributs.
|
||||
|
||||
Et chaque attribut a un type.
|
||||
Chaque attribut possède un type.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Et vous obtenez tout le support de l'éditeur avec cet objet résultant.
|
||||
Ainsi, votre éditeur vous offrira un support adapté pour l'objet résultant.
|
||||
|
||||
Un exemple des documents officiels de Pydantic :
|
||||
Extrait de la documentation officielle de **Pydantic** :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial011_py310.py *}
|
||||
{*../../docs_src/python_types/tutorial011.py*}
|
||||
|
||||
/// info
|
||||
|
||||
Pour en savoir plus sur <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic, consultez sa documentation</a>.
|
||||
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>.
|
||||
|
||||
///
|
||||
|
||||
**FastAPI** est entièrement basé sur Pydantic.
|
||||
**FastAPI** est basé entièrement sur **Pydantic**.
|
||||
|
||||
Vous verrez beaucoup plus tout cela en pratique dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
|
||||
Vous verrez bien plus d'exemples de son utilisation dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Astuce
|
||||
## Les annotations de type dans **FastAPI**
|
||||
|
||||
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>.
|
||||
**FastAPI** utilise ces annotations pour faire différentes choses.
|
||||
|
||||
///
|
||||
Avec **FastAPI**, vous déclarez des paramètres grâce aux annotations de types et vous obtenez :
|
||||
|
||||
## Type Hints avec des annotations de métadonnées { #type-hints-with-metadata-annotations }
|
||||
* **du support de l'éditeur**
|
||||
* **de la vérification de types**
|
||||
|
||||
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`.
|
||||
...et **FastAPI** utilise ces mêmes déclarations pour :
|
||||
|
||||
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.
|
||||
* **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.
|
||||
* **Documenter** l'API avec OpenAPI :
|
||||
* ce qui est ensuite utilisé par les interfaces utilisateur automatiques de documentation interactive.
|
||||
* ce qui ensuite utilisé par les interfaces utilisateur automatiques de documentation interactive.
|
||||
|
||||
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}.
|
||||
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}.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
/// info
|
||||
|
||||
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>.
|
||||
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>.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,86 +1,84 @@
|
||||
# Tâches d'arrière-plan { #background-tasks }
|
||||
# Tâches d'arrière-plan
|
||||
|
||||
Vous pouvez définir des tâches d'arrière-plan à exécuter *après* avoir renvoyé une réponse.
|
||||
Vous pouvez définir des tâches d'arrière-plan qui seront exécutées après avoir retourné 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.
|
||||
Ceci est utile pour les opérations qui doivent avoir lieu après une requête, mais où le client n'a pas réellement besoin d'attendre que l'opération soit terminée pour recevoir une réponse.
|
||||
|
||||
Cela comprend, par exemple :
|
||||
|
||||
* Les notifications par email envoyées après l'exécution d'une action :
|
||||
* 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.
|
||||
* É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.
|
||||
|
||||
## Utiliser `BackgroundTasks` { #using-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` :
|
||||
## Utiliser `BackgroundTasks`
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
|
||||
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] *}
|
||||
|
||||
**FastAPI** créera l'objet de type `BackgroundTasks` pour vous et le passera comme paramètre.
|
||||
|
||||
## Créer une fonction de tâche { #create-a-task-function }
|
||||
## Créer une fonction de tâche
|
||||
|
||||
Créez une fonction à exécuter comme tâche d'arrière-plan.
|
||||
Une fonction à exécuter comme tâche d'arrière-plan est juste une fonction standard qui peut recevoir des paramètres.
|
||||
|
||||
C'est simplement une fonction standard qui peut recevoir des paramètres.
|
||||
Elle peut être une fonction asynchrone (`async def`) ou une fonction normale (`def`), **FastAPI** saura la gérer correctement.
|
||||
|
||||
Elle peut être une fonction `async def` ou une fonction `def` normale, **FastAPI** saura la gérer correctement.
|
||||
Dans cet exemple, la fonction de tâche écrira dans un fichier (afin de simuler un envoi d'email).
|
||||
|
||||
Dans ce cas, la fonction de tâche écrira dans un fichier (en simulant l'envoi d'un email).
|
||||
L'opération d'écriture n'utilisant ni `async` ni `await`, on définit la fonction avec un `def` normal.
|
||||
|
||||
Et comme l'opération d'écriture n'utilise pas `async` et `await`, nous définissons la fonction avec un `def` normal :
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
|
||||
## Ajouter une tâche d'arrière-plan
|
||||
|
||||
## Ajouter la tâche d'arrière-plan { #add-the-background-task }
|
||||
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()` :
|
||||
|
||||
À 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_py39.py hl[14] *}
|
||||
{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
|
||||
|
||||
`.add_task()` reçoit comme arguments :
|
||||
|
||||
* Une fonction de tâche à exécuter en arrière-plan (`write_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"`).
|
||||
* 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"`).
|
||||
|
||||
## Injection de dépendances { #dependency-injection }
|
||||
## Injection de dépendances
|
||||
|
||||
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.
|
||||
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...
|
||||
|
||||
**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 :
|
||||
**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 :
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002_an_py310.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.
|
||||
|
||||
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.
|
||||
|
||||
Dans cet exemple, les messages seront écrits dans le fichier `log.txt` *après* que la réponse est envoyée.
|
||||
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`.
|
||||
|
||||
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 }
|
||||
## Détails techniques
|
||||
|
||||
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 afin que vous puissiez l'importer depuis `fastapi` et éviter d'importer accidentellement l'alternative `BackgroundTask` (sans le `s` à la fin) depuis `starlette.background`.
|
||||
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`.
|
||||
|
||||
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`.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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>.
|
||||
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`).
|
||||
|
||||
## Mise en garde { #caveat }
|
||||
## Avertissement
|
||||
|
||||
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>.
|
||||
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>.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
## Résumé { #recap }
|
||||
## Résumé
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
# Body - Paramètres multiples { #body-multiple-parameters }
|
||||
# Body - Paramètres multiples
|
||||
|
||||
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.
|
||||
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".
|
||||
|
||||
## Mélanger les paramètres `Path`, `Query` et body { #mix-path-query-and-body-parameters }
|
||||
## Mélanger les paramètres `Path`, `Query` et body
|
||||
|
||||
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.
|
||||
Tout d'abord, sachez que vous pouvez mélanger les déclarations des paramètres `Path`, `Query` et body, **FastAPI** saura quoi faire.
|
||||
|
||||
Et vous pouvez également déclarer des paramètres body comme étant optionnels, en définissant la valeur par défaut à `None` :
|
||||
Vous pouvez également déclarer des paramètres body comme étant optionnels, en leur assignant une valeur par défaut à `None` :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Notez que, dans ce cas, le `item` qui serait pris depuis le corps est optionnel, car il a une valeur par défaut à `None`.
|
||||
Notez que, dans ce cas, le paramètre `item` provenant du `Body` est optionnel (sa valeur par défaut est `None`).
|
||||
|
||||
///
|
||||
|
||||
## Paramètres multiples du body { #multiple-body-parameters }
|
||||
## Paramètres multiples du body
|
||||
|
||||
Dans l'exemple précédent, les *chemins d'accès* s'attendraient à un corps JSON avec les attributs d'un `Item`, comme :
|
||||
Dans l'exemple précédent, les opérations de routage attendaient un body JSON avec les attributs d'un `Item`, par exemple :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -29,14 +29,13 @@ Dans l'exemple précédent, les *chemins d'accès* s'attendraient à un corps JS
|
||||
}
|
||||
```
|
||||
|
||||
Mais vous pouvez aussi déclarer plusieurs paramètres body, par ex. `item` et `user` :
|
||||
Mais vous pouvez également déclarer plusieurs paramètres provenant de body, par exemple `item` et `user` simultanément :
|
||||
|
||||
{* ../../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).
|
||||
|
||||
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 :
|
||||
Il utilisera alors les noms des paramètres comme clés, et s'attendra à recevoir quelque chose de semblable à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -53,30 +52,29 @@ Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le
|
||||
}
|
||||
```
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
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`.
|
||||
"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."`.
|
||||
|
||||
///
|
||||
|
||||
**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`.
|
||||
**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.
|
||||
|
||||
Il effectuera la validation des données composées, et les documentera ainsi pour le schéma OpenAPI et les documents automatiques.
|
||||
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).
|
||||
|
||||
## Valeurs scalaires dans le body { #singular-values-in-body }
|
||||
## Valeurs scalaires dans le 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`.
|
||||
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`.
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
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.
|
||||
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`).
|
||||
|
||||
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une autre clé dans le corps en utilisant `Body` :
|
||||
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une variable de body en utilisant `Body` :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
|
||||
|
||||
|
||||
Dans ce cas, **FastAPI** s'attendra à un corps comme :
|
||||
Dans ce cas, **FastAPI** s'attendra à un body semblable à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -94,19 +92,19 @@ Dans ce cas, **FastAPI** s'attendra à un corps comme :
|
||||
}
|
||||
```
|
||||
|
||||
Là encore, il convertira les types de données, validera, documentera, etc.
|
||||
Encore une fois, cela convertira les types de données, les validera, permettra de générer la documentation, etc...
|
||||
|
||||
## Plusieurs paramètres body et query { #multiple-body-params-and-query }
|
||||
## Paramètres multiples body et query
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 :
|
||||
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 :
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Ou en Python 3.10 et supérieur :
|
||||
Ou bien, en Python 3.10 et supérieur :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
@@ -114,33 +112,31 @@ q: str | None = None
|
||||
|
||||
Par exemple :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[27] *}
|
||||
|
||||
/// info
|
||||
|
||||
/// 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.
|
||||
`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.
|
||||
|
||||
///
|
||||
|
||||
## Inclure un seul paramètre body { #embed-a-single-body-parameter }
|
||||
## Inclure un paramètre imbriqué dans le body
|
||||
|
||||
Disons que vous n'avez qu'un seul paramètre body `item` issu d'un modèle Pydantic `Item`.
|
||||
Disons que vous avez seulement un paramètre `item` dans le body, correspondant à un modèle Pydantic `Item`.
|
||||
|
||||
Par défaut, **FastAPI** s'attendra alors à son corps directement.
|
||||
Par défaut, **FastAPI** attendra sa déclaration directement dans le 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` :
|
||||
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` :
|
||||
|
||||
```Python
|
||||
item: Item = Body(embed=True)
|
||||
```
|
||||
|
||||
comme dans :
|
||||
Voici un exemple complet :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
|
||||
|
||||
|
||||
Dans ce cas **FastAPI** s'attendra à un corps comme :
|
||||
Dans ce cas **FastAPI** attendra un body semblable à :
|
||||
|
||||
```JSON hl_lines="2"
|
||||
{
|
||||
@@ -164,12 +160,12 @@ au lieu de :
|
||||
}
|
||||
```
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
## Pour résumer
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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*.
|
||||
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é.
|
||||
|
||||
Vous pouvez aussi déclarer des valeurs scalaires à recevoir dans le corps.
|
||||
Vous pouvez également déclarer des valeurs [scalaires](https://docs.github.com/fr/graphql/reference/scalars) à recevoir dans le body.
|
||||
|
||||
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é.
|
||||
Et vous pouvez indiquer à **FastAPI** d'inclure le body dans une autre variable, même lorsqu'un seul paramètre est déclaré.
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
# Corps de la requête { #request-body }
|
||||
# Corps de la 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**.
|
||||
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**.
|
||||
|
||||
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.
|
||||
Le corps d'une **requête** est de la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée envoyée par votre API au client.
|
||||
|
||||
Votre API 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.
|
||||
Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un corps de **requête**.
|
||||
|
||||
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 des données, vous devriez utiliser l'une des méthodes suivantes : `POST` (la plus courante), `PUT`, `DELETE` ou `PATCH`.
|
||||
Pour envoyer de la donnée, vous devriez utiliser : `POST` (le plus populaire), `PUT`, `DELETE` ou `PATCH`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Importer le `BaseModel` de Pydantic { #import-pydantics-basemodel }
|
||||
## Importez le `BaseModel` de Pydantic
|
||||
|
||||
Commencez par importer `BaseModel` depuis `pydantic` :
|
||||
Commencez par importer la classe `BaseModel` du module `pydantic` :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[4] *}
|
||||
|
||||
## Créer votre modèle de données { #create-your-data-model }
|
||||
## Créez votre modèle de données
|
||||
|
||||
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_py310.py hl[5:9] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[7:11] *}
|
||||
|
||||
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.
|
||||
|
||||
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 :
|
||||
Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) tel que :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -46,7 +45,7 @@ Par exemple, le modèle ci-dessus déclare un « `object` » JSON (ou `dict` Pyt
|
||||
}
|
||||
```
|
||||
|
||||
... comme `description` et `tax` sont optionnels (avec une valeur par défaut de `None`), cet « `object` » JSON serait aussi valide :
|
||||
...`description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), cet "objet" JSON serait aussi valide :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -55,112 +54,109 @@ Par exemple, le modèle ci-dessus déclare un « `object` » JSON (ou `dict` Pyt
|
||||
}
|
||||
```
|
||||
|
||||
## Le déclarer comme paramètre { #declare-it-as-a-parameter }
|
||||
## Déclarez-le comme paramètre
|
||||
|
||||
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 :
|
||||
Pour l'ajouter à votre *opération de chemin*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
|
||||
{* ../../docs_src/body/tutorial001.py hl[18] *}
|
||||
|
||||
... et déclarez son type comme étant le modèle que vous avez créé, `Item`.
|
||||
...et déclarez que son type est le modèle que vous avez créé : `Item`.
|
||||
|
||||
## Résultats { #results }
|
||||
## Résultats
|
||||
|
||||
Avec simplement cette déclaration de type Python, **FastAPI** va :
|
||||
En utilisant uniquement les déclarations de type Python, **FastAPI** réussit à :
|
||||
|
||||
* Lire le corps de la requête en tant que JSON.
|
||||
* Lire le contenu de la requête en tant que JSON.
|
||||
* Convertir les types correspondants (si nécessaire).
|
||||
* 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>.
|
||||
* 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.
|
||||
|
||||
## Documentation automatique { #automatic-docs }
|
||||
## Documentation automatique
|
||||
|
||||
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 :
|
||||
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 :
|
||||
|
||||
<img src="/img/tutorial/body/image01.png">
|
||||
|
||||
Et seront aussi utilisés dans la documentation de l'API au sein de chaque *chemin d'accès* qui en a besoin :
|
||||
Et seront aussi utilisés dans chaque *opération de chemin* de la documentation utilisant ces modèles :
|
||||
|
||||
<img src="/img/tutorial/body/image02.png">
|
||||
|
||||
## Support de l'éditeur { #editor-support }
|
||||
## Support de l'éditeur
|
||||
|
||||
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) :
|
||||
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) :
|
||||
|
||||
<img src="/img/tutorial/body/image03.png">
|
||||
|
||||
Vous obtenez aussi des vérifications d'erreur pour les opérations incorrectes de types :
|
||||
Et vous obtenez aussi de la vérification 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 autour de ce design.
|
||||
Ce n'est pas un hasard, ce framework entier a été bâti avec ce design comme objectif.
|
||||
|
||||
Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour vous assurer que cela fonctionnerait avec tous les éditeurs.
|
||||
Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour s'assurer que cela fonctionnerait avec tous les éditeurs.
|
||||
|
||||
Des changements ont même été faits sur Pydantic lui-même pour supporter cela.
|
||||
Des changements sur Pydantic ont même été faits pour supporter cela.
|
||||
|
||||
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>.
|
||||
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>.
|
||||
|
||||
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 :
|
||||
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.
|
||||
|
||||
<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 <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 Plugin <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
|
||||
|
||||
Il améliore le support de l'éditeur pour les modèles Pydantic, avec :
|
||||
Ce qui améliore le support pour les modèles Pydantic avec :
|
||||
|
||||
* autocomplétion
|
||||
* vérifications de type
|
||||
* refactoring
|
||||
* recherche
|
||||
* inspections
|
||||
* de l'auto-complétion
|
||||
* des vérifications de type
|
||||
* du "refactoring" (ou remaniement de code)
|
||||
* de la recherche
|
||||
* de l'inspection
|
||||
|
||||
///
|
||||
|
||||
## Utiliser le modèle { #use-the-model }
|
||||
## Utilisez le modèle
|
||||
|
||||
À l'intérieur de la fonction, vous pouvez accéder directement à tous les attributs de l'objet du modèle :
|
||||
Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement :
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
{* ../../docs_src/body/tutorial002.py hl[21] *}
|
||||
|
||||
## Corps de la requête + paramètres de chemin { #request-body-path-parameters }
|
||||
## Corps de la requête + paramètres de chemin
|
||||
|
||||
Vous pouvez déclarer des paramètres de chemin et le corps de la requête en même temps.
|
||||
Vous pouvez déclarer des paramètres de chemin et un corps de requête pour la même *opération de chemin*.
|
||||
|
||||
**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**.
|
||||
**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**.
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
{* ../../docs_src/body/tutorial003.py hl[17:18] *}
|
||||
|
||||
## Corps de la requête + paramètres de chemin et de requête
|
||||
|
||||
## Corps de la requête + paramètres de chemin et de requête { #request-body-path-query-parameters }
|
||||
Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête** dans la même *opération de chemin*.
|
||||
|
||||
Vous pouvez aussi déclarer des paramètres de **corps**, de **chemin** et de **requête**, tous en même temps.
|
||||
**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit.
|
||||
|
||||
**FastAPI** reconnaîtra chacun d'entre eux et récupérera les données au bon endroit.
|
||||
{* ../../docs_src/body/tutorial004.py hl[18] *}
|
||||
|
||||
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
|
||||
|
||||
Les paramètres de la fonction seront reconnus comme suit :
|
||||
Les paramètres de la fonction seront reconnus comme tel :
|
||||
|
||||
* 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 étant du type d'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 ayant pour type un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
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 `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.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Sans Pydantic { #without-pydantic }
|
||||
## Sans Pydantic
|
||||
|
||||
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}.
|
||||
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}.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Débogage { #debugging }
|
||||
# <abbr title="En anglais: Debugging">Débogage</abbr>
|
||||
|
||||
Vous pouvez connecter le débogueur dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
|
||||
Vous pouvez connecter le <abbr title="En anglais: debugger">débogueur</abbr> dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
|
||||
|
||||
## Faites appel à `uvicorn` { #call-uvicorn }
|
||||
## Faites appel à `uvicorn`
|
||||
|
||||
Dans votre application FastAPI, importez et exécutez directement `uvicorn` :
|
||||
|
||||
{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *}
|
||||
{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
|
||||
|
||||
### À propos de `__name__ == "__main__"` { #about-name-main }
|
||||
### À propos de `__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 { #more-details }
|
||||
#### Pour davantage de détails
|
||||
|
||||
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).
|
||||
|
||||
Ainsi, si vous avez un autre fichier `importer.py` qui contient :
|
||||
Par exemple, si vous avez un autre fichier `importer.py` qui contient :
|
||||
|
||||
```Python
|
||||
from myapp import app
|
||||
|
||||
# Some more code
|
||||
# Code supplémentaire
|
||||
```
|
||||
|
||||
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 débogueur { #run-your-code-with-your-debugger }
|
||||
## Exécutez votre code avec votre <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.
|
||||
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>.
|
||||
|
||||
---
|
||||
|
||||
Par exemple, dans Visual Studio Code, vous pouvez :
|
||||
|
||||
* Aller dans le panneau « Debug ».
|
||||
* « Add configuration... ».
|
||||
* Sélectionner « Python »
|
||||
* Lancer le débogueur avec l'option « `Python: Current File (Integrated Terminal)` ».
|
||||
- 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)`".
|
||||
|
||||
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électionner l'option « Debug... ».
|
||||
* Un menu contextuel s'affiche alors.
|
||||
* Sélectionner le fichier à déboguer (dans ce cas, `main.py`).
|
||||
- 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`).
|
||||
|
||||
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
|
||||
|
||||
|
||||
@@ -1,122 +1,107 @@
|
||||
# Premiers pas { #first-steps }
|
||||
# Démarrage
|
||||
|
||||
Le fichier **FastAPI** le plus simple possible pourrait ressembler à ceci :
|
||||
Le fichier **FastAPI** le plus simple possible pourrait ressembler à cela :
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py *}
|
||||
|
||||
Copiez cela dans un fichier `main.py`.
|
||||
Copiez ce code dans un fichier nommé `main.py`.
|
||||
|
||||
Lancez le serveur de développement :
|
||||
Démarrez le serveur :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<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">'/home/user/code/awesomeapp'</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.
|
||||
<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.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Dans la sortie, il y a une ligne qui ressemble à :
|
||||
/// 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 :
|
||||
|
||||
```hl_lines="4"
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
Cette ligne affiche l’URL à laquelle votre app est servie, sur votre machine locale.
|
||||
Cette ligne montre l'URL par laquelle l'app est actuellement accessible, sur votre machine locale.
|
||||
|
||||
### Vérifiez { #check-it }
|
||||
### Allez voir le résultat
|
||||
|
||||
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 à l'adresse <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
Vous verrez la réponse JSON :
|
||||
Vous obtiendrez cette réponse JSON :
|
||||
|
||||
```JSON
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
### Documentation interactive de l’API { #interactive-api-docs }
|
||||
### Documentation interactive de l'API
|
||||
|
||||
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>.
|
||||
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>.
|
||||
|
||||
Vous verrez la documentation interactive de l’API générée automatiquement (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</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>) :
|
||||
|
||||

|
||||
|
||||
### Documentation alternative de l’API { #alternative-api-docs }
|
||||
### Documentation alternative
|
||||
|
||||
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>.
|
||||
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>.
|
||||
|
||||
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>) :
|
||||
Vous y verrez la documentation alternative (via <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
|
||||

|
||||
|
||||
### OpenAPI { #openapi }
|
||||
### OpenAPI
|
||||
|
||||
**FastAPI** génère un « schéma » contenant toute votre API en utilisant le standard **OpenAPI** pour définir les API.
|
||||
**FastAPI** génère un "schéma" contenant toute votre API dans le standard de définition d'API **OpenAPI**.
|
||||
|
||||
#### « Schéma » { #schema }
|
||||
#### "Schéma"
|
||||
|
||||
Un « schéma » est une définition ou une description de quelque chose. Pas le code qui l’implémente, mais simplement une description abstraite.
|
||||
Un "schéma" est une définition ou une description de quelque chose. Pas le code qui l'implémente, uniquement une description abstraite.
|
||||
|
||||
#### « Schéma » d’API { #api-schema }
|
||||
#### "Schéma" d'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.
|
||||
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.
|
||||
|
||||
Cette définition de schéma inclut les chemins de votre API, les paramètres possibles qu’ils acceptent, etc.
|
||||
Le schéma inclut les chemins de votre API, les paramètres potentiels de chaque chemin, etc.
|
||||
|
||||
#### « Schéma » de données { #data-schema }
|
||||
#### "Schéma" de données
|
||||
|
||||
Le terme « schéma » peut aussi faire référence à la structure de certaines données, comme un contenu JSON.
|
||||
Le terme "schéma" peut aussi faire référence à la forme de la donnée, comme un contenu JSON.
|
||||
|
||||
Dans ce cas, cela signifierait les attributs JSON, et les types de données qu’ils ont, etc.
|
||||
Dans ce cas, cela signifierait les attributs JSON, ainsi que les types de ces attributs, etc.
|
||||
|
||||
#### OpenAPI et JSON Schema { #openapi-and-json-schema }
|
||||
#### OpenAPI et JSON Schema
|
||||
|
||||
OpenAPI définit un schéma d’API 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.
|
||||
**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.
|
||||
|
||||
#### Vérifiez le `openapi.json` { #check-the-openapi-json }
|
||||
#### Allez voir `openapi.json`
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Vous pouvez le voir directement à l’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>.
|
||||
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 :
|
||||
|
||||
Il affichera un JSON commençant par quelque chose comme :
|
||||
|
||||
```JSON
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"openapi": "3.0.2",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
@@ -135,87 +120,79 @@ Il affichera un JSON commençant par quelque chose comme :
|
||||
...
|
||||
```
|
||||
|
||||
#### À quoi sert OpenAPI { #what-is-openapi-for }
|
||||
#### À quoi sert OpenAPI
|
||||
|
||||
Le schéma OpenAPI est ce qui alimente les deux systèmes de documentation interactive inclus.
|
||||
Le schéma **OpenAPI** est ce qui alimente les deux systèmes de documentation interactive.
|
||||
|
||||
Et il existe des dizaines d’alternatives, toutes basées sur OpenAPI. Vous pourriez facilement ajouter n’importe laquelle de ces alternatives à votre application construite avec **FastAPI**.
|
||||
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**.
|
||||
|
||||
Vous pourriez aussi l’utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Par exemple, des applications frontend, mobiles ou IoT.
|
||||
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.
|
||||
|
||||
### Déployer votre app (optionnel) { #deploy-your-app-optional }
|
||||
## Récapitulatif, étape par étape
|
||||
|
||||
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 d’attente si ce n’est pas déjà fait. 🚀
|
||||
### Étape 1 : import `FastAPI`
|
||||
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
|
||||
|
||||
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>
|
||||
|
||||
C’est 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.
|
||||
`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires au lancement de votre API.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
`FastAPI` est une classe qui hérite directement de `Starlette`.
|
||||
`FastAPI` est une classe héritant directement de `Starlette`.
|
||||
|
||||
Vous pouvez aussi utiliser toutes les fonctionnalités de <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> avec `FastAPI`.
|
||||
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`.
|
||||
|
||||
///
|
||||
|
||||
### Étape 2 : créer une « instance » `FastAPI` { #step-2-create-a-fastapi-instance }
|
||||
### Étape 2 : créer une "instance" `FastAPI`
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.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 d'interaction pour créer toute votre API.
|
||||
|
||||
### Étape 3 : créer un *chemin d'accès* { #step-3-create-a-path-operation }
|
||||
Cette `app` est la même que celle à laquelle fait référence `uvicorn` dans la commande :
|
||||
|
||||
#### Chemin { #path }
|
||||
<div class="termy">
|
||||
|
||||
« Path » fait référence ici à la dernière partie de l’URL à partir du premier `/`.
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
Donc, dans une URL comme :
|
||||
<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 :
|
||||
|
||||
```
|
||||
https://example.com/items/foo
|
||||
```
|
||||
|
||||
... le « path » serait :
|
||||
...le "path" serait :
|
||||
|
||||
```
|
||||
/items/foo
|
||||
@@ -223,67 +200,66 @@ https://example.com/items/foo
|
||||
|
||||
/// info
|
||||
|
||||
Un « path » est aussi communément appelé un « endpoint » ou une « route ».
|
||||
Un chemin, ou "path" est aussi souvent appelé route ou "endpoint".
|
||||
|
||||
///
|
||||
|
||||
Lors de la construction d’une API, le « path » est la principale façon de séparer les « préoccupations » et les « ressources ».
|
||||
#### Opération
|
||||
|
||||
#### Opération { #operation }
|
||||
"Opération" fait référence à une des "méthodes" HTTP.
|
||||
|
||||
« Opération » fait référence ici à l’une des « méthodes » HTTP.
|
||||
|
||||
L’une de :
|
||||
Une de :
|
||||
|
||||
* `POST`
|
||||
* `GET`
|
||||
* `PUT`
|
||||
* `DELETE`
|
||||
|
||||
... et les plus exotiques :
|
||||
...ou une des plus exotiques :
|
||||
|
||||
* `OPTIONS`
|
||||
* `HEAD`
|
||||
* `PATCH`
|
||||
* `TRACE`
|
||||
|
||||
Dans le protocole HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plusieurs) de ces « méthodes ».
|
||||
Dans le protocol HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plus) de ces "méthodes".
|
||||
|
||||
---
|
||||
|
||||
Lors de la construction d’API, vous utilisez normalement ces méthodes HTTP spécifiques pour effectuer une action précise.
|
||||
En construisant des APIs, vous utilisez généralement ces méthodes HTTP spécifiques pour effectuer une action précise.
|
||||
|
||||
Normalement vous utilisez :
|
||||
Généralement vous utilisez :
|
||||
|
||||
* `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.
|
||||
* `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.
|
||||
|
||||
Donc, dans OpenAPI, chacune des méthodes HTTP est appelée une « opération ».
|
||||
Donc, dans **OpenAPI**, chaque méthode HTTP est appelée une "opération".
|
||||
|
||||
Nous allons aussi les appeler des « **opérations** ».
|
||||
Nous allons donc aussi appeler ces dernières des "**opérations**".
|
||||
|
||||
#### Définir un *décorateur de chemin d'accès* { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
|
||||
#### Définir un *décorateur d'opération de chemin*
|
||||
|
||||
Le `@app.get("/")` indique à **FastAPI** que la fonction juste en dessous est chargée de gérer les requêtes qui vont vers :
|
||||
{* ../../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 chemin `/`
|
||||
* en utilisant une <abbr title="an HTTP GET method">opération <code>get</code></abbr>
|
||||
* en utilisant une <abbr title="une méthode GET HTTP">opération <code>get</code></abbr>
|
||||
|
||||
/// info | `@decorator` Info
|
||||
/// info | `@décorateur` Info
|
||||
|
||||
Cette syntaxe `@something` en Python est appelée un « décorateur ».
|
||||
Cette syntaxe `@something` en Python est appelée un "décorateur".
|
||||
|
||||
Vous le mettez au-dessus d’une fonction. Comme un joli chapeau décoratif (j’imagine que c’est de là que le terme vient).
|
||||
Vous la mettez au dessus d'une fonction. Comme un joli chapeau décoratif (j'imagine que ce terme vient de là 🤷🏻♂).
|
||||
|
||||
Un « décorateur » prend la fonction en dessous et fait quelque chose avec elle.
|
||||
Un "décorateur" prend la fonction en dessous et en fait quelque chose.
|
||||
|
||||
Dans notre cas, ce décorateur indique à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec une **opération** `get`.
|
||||
Dans notre cas, ce décorateur dit à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec l'**opération** `get`.
|
||||
|
||||
C’est le « **décorateur de chemin d'accès** ».
|
||||
C'est le "**décorateur d'opération de chemin**".
|
||||
|
||||
///
|
||||
|
||||
@@ -293,7 +269,7 @@ Vous pouvez aussi utiliser les autres opérations :
|
||||
* `@app.put()`
|
||||
* `@app.delete()`
|
||||
|
||||
Et les plus exotiques :
|
||||
Tout comme celles les plus exotiques :
|
||||
|
||||
* `@app.options()`
|
||||
* `@app.head()`
|
||||
@@ -302,79 +278,58 @@ Et les plus exotiques :
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous êtes libre d’utiliser chaque opération (méthode HTTP) comme vous le souhaitez.
|
||||
Vous êtes libres d'utiliser chaque opération (méthode HTTP) comme vous le désirez.
|
||||
|
||||
**FastAPI** n’impose aucun sens spécifique.
|
||||
**FastAPI** n'impose pas de sens spécifique à chacune d'elle.
|
||||
|
||||
Les informations présentées ici servent de guide, pas d’exigence.
|
||||
Les informations qui sont présentées ici forment une directive générale, pas des obligations.
|
||||
|
||||
Par exemple, quand vous utilisez GraphQL, vous effectuez normalement toutes les actions en utilisant uniquement des opérations `POST`.
|
||||
Par exemple, quand l'on utilise **GraphQL**, toutes les actions sont effectuées en utilisant uniquement des opérations `POST`.
|
||||
|
||||
///
|
||||
|
||||
### Étape 4 : définir la **fonction de chemin d'accès** { #step-4-define-the-path-operation-function }
|
||||
### Étape 4 : définir la **fonction de chemin**.
|
||||
|
||||
Voici notre « **fonction de chemin d'accès** » :
|
||||
Voici notre "**fonction de chemin**" (ou fonction d'opération de chemin) :
|
||||
|
||||
* **chemin** : est `/`.
|
||||
* **opération** : est `get`.
|
||||
* **fonction** : est la fonction sous le « décorateur » (sous `@app.get("/")`).
|
||||
* **chemin** : `/`.
|
||||
* **opération** : `get`.
|
||||
* **fonction** : la fonction sous le "décorateur" (sous `@app.get("/")`).
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
|
||||
|
||||
C’est une fonction Python.
|
||||
C'est une fonction Python.
|
||||
|
||||
Elle sera appelée par **FastAPI** chaque fois qu’il recevra une requête vers l’URL « `/` » en utilisant une opération `GET`.
|
||||
Elle sera appelée par **FastAPI** quand une requête sur l'URL `/` sera reçue via une opération `GET`.
|
||||
|
||||
Dans ce cas, c’est une fonction `async`.
|
||||
Ici, c'est une fonction asynchrone (définie avec `async def`).
|
||||
|
||||
---
|
||||
|
||||
Vous pourriez aussi la définir comme une fonction normale au lieu de `async def` :
|
||||
Vous pourriez aussi la définir comme une fonction classique plutôt qu'avec `async def` :
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
|
||||
{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Si vous ne connaissez pas la différence, consultez [Async : *« Pressé ? »*](../async.md#in-a-hurry){.internal-link target=_blank}.
|
||||
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}.
|
||||
|
||||
///
|
||||
|
||||
### Étape 5 : retourner le contenu { #step-5-return-the-content }
|
||||
### Étape 5 : retourner le contenu
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
|
||||
{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
|
||||
|
||||
Vous pouvez retourner un `dict`, `list`, des valeurs seules comme `str`, `int`, etc.
|
||||
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 aussi retourner des modèles Pydantic (vous en verrez plus à ce sujet plus tard).
|
||||
Vous pouvez aussi retourner des models **Pydantic** (qui seront détaillés plus tard).
|
||||
|
||||
Il y a de nombreux autres objets et modèles qui seront automatiquement convertis en JSON (y compris les ORM, etc). Essayez d’utiliser vos favoris, il est très probable qu’ils soient déjà pris en charge.
|
||||
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.
|
||||
|
||||
### É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 d’apps 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 d’autres fournisseurs cloud { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI est open source et basé sur des standards. 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. 🤓
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
## Récapitulatif
|
||||
|
||||
* Importez `FastAPI`.
|
||||
* 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`.
|
||||
* 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`).
|
||||
|
||||
@@ -1,95 +1,83 @@
|
||||
# Tutoriel - Guide utilisateur { #tutorial-user-guide }
|
||||
# Tutoriel - Guide utilisateur - Introduction
|
||||
|
||||
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 afin que vous puissiez revenir et voir exactement ce dont vous avez besoin.
|
||||
Il est également conçu pour fonctionner comme une référence future.
|
||||
|
||||
## Exécuter le code { #run-the-code }
|
||||
Vous pouvez donc revenir et voir exactement ce dont vous avez besoin.
|
||||
|
||||
## Exécuter le 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 démarrez `fastapi dev` avec :
|
||||
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et commencez `uvicorn` avec :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid">main.py</u>
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<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">'/home/user/code/awesomeapp'</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.
|
||||
<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.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Il est **FORTEMENT encouragé** que vous écriviez ou copiiez le code, l'éditiez et l'exécutiez localement.
|
||||
Il est **FORTEMENT encouragé** que vous écriviez ou copiez 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 { #install-fastapi }
|
||||
## Installer FastAPI
|
||||
|
||||
La première étape consiste à installer FastAPI.
|
||||
|
||||
Vous devez vous assurer de créer un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis **d'installer FastAPI** :
|
||||
Pour le tutoriel, vous voudrez peut-être l'installer avec toutes les dépendances et fonctionnalités optionnelles :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install "fastapi[standard]"
|
||||
$ pip install fastapi[all]
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
/// note | Remarque
|
||||
... qui comprend également `uvicorn`, que vous pouvez utiliser comme serveur pour exécuter votre code.
|
||||
|
||||
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>.
|
||||
/// note
|
||||
|
||||
Si vous ne voulez pas avoir ces dépendances optionnelles, vous pouvez installer `pip install fastapi` à la place.
|
||||
Vous pouvez également l'installer pièce par pièce.
|
||||
|
||||
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]"`.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Guide utilisateur avancé { #advanced-user-guide }
|
||||
## Guide utilisateur avancé
|
||||
|
||||
Il existe également un **Guide utilisateur avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide utilisateur**.
|
||||
Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**.
|
||||
|
||||
Le **Guide utilisateur avancé** s'appuie sur celui-ci, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
|
||||
Le **Guide d'utilisation avancé**, qui s'appuie sur cette base, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
|
||||
|
||||
Mais vous devez d'abord lire le **Tutoriel - Guide utilisateur** (ce que vous êtes en train de lire en ce moment).
|
||||
Mais vous devez d'abord lire le **Tutoriel - Guide d'utilisation** (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 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é**.
|
||||
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é**.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Paramètres de chemin et validations numériques { #path-parameters-and-numeric-validations }
|
||||
# Paramètres de chemin et validations numériques
|
||||
|
||||
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` { #import-path }
|
||||
## Importer 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 obtiendriez des erreurs en essayant d'utiliser `Annotated`.
|
||||
Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant 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`.
|
||||
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`.
|
||||
|
||||
///
|
||||
|
||||
## Déclarer des métadonnées { #declare-metadata }
|
||||
## Déclarer des métadonnées
|
||||
|
||||
Vous pouvez déclarer tous les mêmes paramètres que pour `Query`.
|
||||
Vous pouvez déclarer 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 | Remarque
|
||||
/// note
|
||||
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Ordonner les paramètres selon vos besoins { #order-the-parameters-as-you-need }
|
||||
## Ordonnez les paramètres comme vous le souhaitez
|
||||
|
||||
/// tip | Astuce
|
||||
/// tip
|
||||
|
||||
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 valeur « par défaut » avant une valeur qui n'a pas de valeur « par défaut ».
|
||||
Python se plaindra si vous mettez une valeur avec une "défaut" avant une valeur qui n'a pas de "défaut".
|
||||
|
||||
Mais vous pouvez les réorganiser, et avoir la valeur sans valeur par défaut (le paramètre de requête `q`) en premier.
|
||||
Mais vous pouvez les réorganiser, et avoir la valeur sans 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_py39.py hl[7] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002.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 *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py hl[10] *}
|
||||
|
||||
## Ordonner les paramètres selon vos besoins, astuces { #order-the-parameters-as-you-need-tricks }
|
||||
## Ordonnez les paramètres comme vous le souhaitez (astuces)
|
||||
|
||||
/// tip | Astuce
|
||||
/// tip
|
||||
|
||||
Ce n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`.
|
||||
|
||||
@@ -77,29 +77,38 @@ 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 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.
|
||||
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.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *}
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
|
||||
|
||||
### Mieux avec `Annotated` { #better-with-annotated }
|
||||
# Avec `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 { #number-validations-greater-than-or-equal }
|
||||
## Validations numériques : supérieur ou égal
|
||||
|
||||
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 et inférieur ou égal { #number-validations-greater-than-and-less-than-or-equal }
|
||||
## 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
|
||||
|
||||
La même chose s'applique pour :
|
||||
|
||||
@@ -108,7 +117,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 { #number-validations-floats-greater-than-and-less-than }
|
||||
## Validations numériques : flottants, supérieur et inférieur
|
||||
|
||||
Les validations numériques fonctionnent également pour les valeurs `float`.
|
||||
|
||||
@@ -120,9 +129,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 { #recap }
|
||||
## Pour résumer
|
||||
|
||||
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}.
|
||||
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}.
|
||||
|
||||
Et vous pouvez également déclarer des validations numériques :
|
||||
|
||||
@@ -135,7 +144,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 vus.
|
||||
Tous partagent les mêmes paramètres pour des validations supplémentaires et des métadonnées que vous avez vu précédemment.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -1,196 +1,205 @@
|
||||
# Paramètres de chemin { #path-parameters }
|
||||
# Paramètres de chemin
|
||||
|
||||
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 :
|
||||
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> :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
|
||||
|
||||
La valeur du paramètre de chemin `item_id` sera transmise à votre fonction comme argument `item_id`.
|
||||
{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
|
||||
|
||||
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 :
|
||||
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 :
|
||||
|
||||
```JSON
|
||||
{"item_id":"foo"}
|
||||
```
|
||||
|
||||
## Paramètres de chemin typés { #path-parameters-with-types }
|
||||
## Paramètres de chemin typés
|
||||
|
||||
Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type standard de Python :
|
||||
Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *}
|
||||
|
||||
Dans ce cas, `item_id` est déclaré comme `int`.
|
||||
{* ../../docs_src/path_params/tutorial002.py hl[7] *}
|
||||
|
||||
/// check | Vérifications
|
||||
Ici, `item_id` est déclaré comme `int`.
|
||||
|
||||
Cela vous donnera le support de l'éditeur dans votre fonction, avec des vérifications d'erreurs, l'autocomplétion, etc.
|
||||
/// 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.
|
||||
|
||||
///
|
||||
|
||||
## <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Conversion</abbr> de données { #data-conversion }
|
||||
## <abbr title="aussi appelé sérialisation, ou parfois parsing ou marshalling en anglais">Conversion</abbr> de données
|
||||
|
||||
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 :
|
||||
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 :
|
||||
|
||||
```JSON
|
||||
{"item_id":3}
|
||||
```
|
||||
|
||||
/// check | Vérifications
|
||||
/// check | vérifier
|
||||
|
||||
Remarquez que la valeur reçue par votre fonction (et renvoyée) est `3`, comme un `int` Python, pas une chaîne « 3 ».
|
||||
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"`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Validation de données { #data-validation }
|
||||
## Validation de données
|
||||
|
||||
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 :
|
||||
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 :
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "int_parsing",
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "Input should be a valid integer, unable to parse string as an integer",
|
||||
"input": "foo"
|
||||
}
|
||||
]
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"path",
|
||||
"item_id"
|
||||
],
|
||||
"msg": "value is not a valid integer",
|
||||
"type": "type_error.integer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
car le paramètre de chemin `item_id` avait la valeur « foo », qui n'est pas un `int`.
|
||||
car le paramètre de chemin `item_id` possède comme valeur `"foo"`, qui ne peut pas être convertie en entier (`int`).
|
||||
|
||||
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>
|
||||
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>.
|
||||
|
||||
/// check | Vérifications
|
||||
|
||||
Ainsi, avec la même déclaration de type Python, **FastAPI** vous fournit une validation de données.
|
||||
/// check | vérifier
|
||||
|
||||
Remarquez que l'erreur indique aussi clairement le point exact où la validation n'est pas passée.
|
||||
Donc, avec ces mêmes déclarations de type Python, **FastAPI** vous fournit de la validation de données.
|
||||
|
||||
C'est incroyablement utile lors du développement et du débogage de code qui interagit avec votre API.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Documentation { #documentation }
|
||||
## Documentation
|
||||
|
||||
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 :
|
||||
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 :
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
/// check | Vérifications
|
||||
/// info
|
||||
|
||||
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).
|
||||
À nouveau, en utilisant uniquement les déclarations de type Python, **FastAPI** vous fournit automatiquement une documentation interactive (via Swagger UI).
|
||||
|
||||
Remarquez que le paramètre de chemin est déclaré comme un entier.
|
||||
On voit bien dans la documentation que `item_id` est déclaré comme entier.
|
||||
|
||||
///
|
||||
|
||||
## Avantages basés sur les standards, documentation alternative { #standards-based-benefits-alternative-documentation }
|
||||
## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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> :
|
||||
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> :
|
||||
|
||||
<img src="/img/tutorial/path-params/image02.png">
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Pydantic { #pydantic }
|
||||
## Pydantic
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Vous pouvez utiliser les mêmes déclarations de type avec `str`, `float`, `bool` et de nombreux autres types de données complexes.
|
||||
## L'ordre importe
|
||||
|
||||
Plusieurs d'entre eux sont abordés dans les prochains chapitres du tutoriel.
|
||||
Quand vous créez des *fonctions de chemins*, vous pouvez vous retrouver dans une situation où vous avez un chemin fixe.
|
||||
|
||||
## L'ordre importe { #order-matters }
|
||||
Tel que `/users/me`, disons pour récupérer les données sur l'utilisateur actuel.
|
||||
|
||||
Lors de la création de *chemins d'accès*, vous pouvez vous retrouver dans des situations où vous avez un chemin fixe.
|
||||
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
|
||||
|
||||
Comme `/users/me`, disons que c'est pour obtenir des données sur l'utilisateur actuel.
|
||||
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}` :
|
||||
|
||||
Et vous pouvez aussi avoir un chemin `/users/{user_id}` pour obtenir des données sur un utilisateur spécifique via un identifiant utilisateur.
|
||||
{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
|
||||
|
||||
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}` :
|
||||
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"`.
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
|
||||
## Valeurs prédéfinies
|
||||
|
||||
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 ».
|
||||
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.
|
||||
|
||||
De la même manière, vous ne pouvez pas redéfinir un chemin d'accès :
|
||||
### Création d'un `Enum`
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
|
||||
Importez `Enum` et créez une sous-classe qui hérite de `str` et `Enum`.
|
||||
|
||||
Le premier sera toujours utilisé puisque le chemin correspond en premier.
|
||||
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.
|
||||
|
||||
## Valeurs prédéfinies { #predefined-values }
|
||||
Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs autorisées pour cette énumération.
|
||||
|
||||
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.
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
|
||||
|
||||
### Créer une classe `Enum` { #create-an-enum-class }
|
||||
/// info
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
<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.
|
||||
|
||||
///
|
||||
|
||||
### Déclarer un *paramètre de chemin* { #declare-a-path-parameter }
|
||||
/// tip | Astuce
|
||||
|
||||
Créez ensuite un *paramètre de chemin* avec une annotation de type utilisant la classe enum que vous avez créée (`ModelName`) :
|
||||
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.
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
|
||||
///
|
||||
|
||||
### Vérifier la documentation { #check-the-docs }
|
||||
### Déclarer un paramètre de chemin
|
||||
|
||||
Comme les valeurs disponibles pour le *paramètre de chemin* sont prédéfinies, la documentation interactive peut bien les afficher :
|
||||
Créez ensuite un *paramètre de chemin* avec une annotation de type désignant l'énumération créée précédemment (`ModelName`) :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[16] *}
|
||||
|
||||
### Documentation
|
||||
|
||||
Les valeurs disponibles pour le *paramètre de chemin* sont bien prédéfinies, la documentation les affiche correctement :
|
||||
|
||||
<img src="/img/tutorial/path-params/image03.png">
|
||||
|
||||
### Travailler avec les *énumérations* Python { #working-with-python-enumerations }
|
||||
### Manipuler les *énumérations* Python
|
||||
|
||||
La valeur du *paramètre de chemin* sera un *membre d'énumération*.
|
||||
La valeur du *paramètre de chemin* sera un des "membres" de l'énumération.
|
||||
|
||||
#### Comparer des *membres d'énumération* { #compare-enumeration-members }
|
||||
#### Comparer les *membres d'énumération*
|
||||
|
||||
Vous pouvez la comparer avec le *membre d'énumération* de votre enum créée `ModelName` :
|
||||
Vous pouvez comparer ce paramètre avec les membres de votre énumération `ModelName` :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[17] *}
|
||||
|
||||
#### Obtenir la *valeur de l'énumération* { #get-the-enumeration-value }
|
||||
#### Récupérer la *valeur de l'énumération*
|
||||
|
||||
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` :
|
||||
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` :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
|
||||
{* ../../docs_src/path_params/tutorial005.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* { #return-enumeration-members }
|
||||
#### Retourner des *membres d'énumération*
|
||||
|
||||
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`).
|
||||
Vous pouvez retourner des *membres d'énumération* dans vos *fonctions de chemin*, même imbriquée dans un JSON (e.g. un `dict`).
|
||||
|
||||
Ils seront convertis en leurs valeurs correspondantes (des chaînes dans ce cas) avant de les renvoyer au client :
|
||||
Ils seront convertis vers leurs valeurs correspondantes (chaînes de caractères ici) avant d'être transmis au client :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
|
||||
{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
|
||||
|
||||
Dans votre client, vous obtiendrez une réponse JSON comme :
|
||||
Le client recevra une réponse JSON comme celle-ci :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -199,53 +208,53 @@ Dans votre client, vous obtiendrez une réponse JSON comme :
|
||||
}
|
||||
```
|
||||
|
||||
## Paramètres de chemin contenant des chemins { #path-parameters-containing-paths }
|
||||
## Paramètres de chemin contenant des chemins
|
||||
|
||||
Disons que vous avez un *chemin d'accès* avec le chemin `/files/{file_path}`.
|
||||
Disons que vous avez une *fonction de chemin* liée au chemin `/files/{file_path}`.
|
||||
|
||||
Mais vous avez besoin que `file_path` lui-même contienne un *chemin*, comme `home/johndoe/myfile.txt`.
|
||||
Mais que `file_path` lui-même doit contenir un *chemin*, comme `home/johndoe/myfile.txt` par exemple.
|
||||
|
||||
Donc, l'URL pour ce fichier serait quelque chose comme : `/files/home/johndoe/myfile.txt`.
|
||||
Donc, l'URL pour ce fichier pourrait être : `/files/home/johndoe/myfile.txt`.
|
||||
|
||||
### Support d'OpenAPI { #openapi-support }
|
||||
### Support d'OpenAPI
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Néanmoins, vous pouvez quand même le faire dans **FastAPI**, en utilisant un des outils internes de Starlette.
|
||||
Néanmoins, cela reste faisable dans **FastAPI**, via les outils internes de Starlette.
|
||||
|
||||
Et les documents fonctionneraient quand même, bien qu'ils n'ajoutent aucune documentation indiquant que le paramètre devrait contenir un chemin.
|
||||
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*.
|
||||
|
||||
### Convertisseur de chemin { #path-convertor }
|
||||
### Convertisseur de *chemin*
|
||||
|
||||
En utilisant une option directement depuis Starlette, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :
|
||||
En utilisant une option de Starlette directement, 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 que le paramètre doit correspondre à n'importe quel *chemin*.
|
||||
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*.
|
||||
|
||||
Ainsi, vous pouvez l'utiliser avec :
|
||||
Vous pouvez donc l'utilisez comme tel :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
|
||||
{* ../../docs_src/path_params/tutorial004.py hl[6] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash initial (`/`).
|
||||
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash au début (`/`).
|
||||
|
||||
Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double slash (`//`) entre `files` et `home`.
|
||||
|
||||
///
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
## Récapitulatif
|
||||
|
||||
Avec **FastAPI**, en utilisant des déclarations de type Python courtes, intuitives et standard, vous obtenez :
|
||||
Avec **FastAPI**, en utilisant les déclarations de type rapides, intuitives et standards de Python, vous bénéficiez de :
|
||||
|
||||
* 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
|
||||
* 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.
|
||||
|
||||
Et vous n'avez à les déclarer qu'une seule fois.
|
||||
Et vous n'avez besoin de le déclarer qu'une fois.
|
||||
|
||||
C'est probablement le principal avantage visible de **FastAPI** comparé aux frameworks alternatifs (en dehors de la performance brute).
|
||||
C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres *frameworks* (outre les performances pures).
|
||||
|
||||
@@ -1,273 +1,166 @@
|
||||
# Paramètres de requête et validations de chaînes de caractères { #query-parameters-and-string-validations }
|
||||
# Paramètres de requête et validations de chaînes de caractères
|
||||
|
||||
**FastAPI** vous permet de déclarer des informations supplémentaires et de la validation pour vos paramètres.
|
||||
**FastAPI** vous permet de déclarer des informations et des validateurs additionnels pour vos paramètres de requêtes.
|
||||
|
||||
Prenons cette application comme exemple :
|
||||
Commençons avec cette application pour exemple :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *}
|
||||
|
||||
Le paramètre de requête `q` est de type `str | None`, ce qui signifie qu’il est de type `str` mais pourrait aussi être `None`, et en effet, la valeur par défaut est `None`, donc FastAPI saura qu’il n’est pas requis.
|
||||
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.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
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`.
|
||||
|
||||
Avoir `str | None` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
|
||||
Le `Union` dans `Union[str, None]` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
|
||||
|
||||
///
|
||||
|
||||
## Validation additionnelle { #additional-validation }
|
||||
## Validation additionnelle
|
||||
|
||||
Nous allons imposer que bien que `q` soit optionnel, dès qu’il est fourni, **sa longueur n’excède pas 50 caractères**.
|
||||
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**.
|
||||
|
||||
### Importer `Query` et `Annotated` { #import-query-and-annotated }
|
||||
## Importer `Query`
|
||||
|
||||
Pour y parvenir, importez d’abord :
|
||||
Pour cela, importez d'abord `Query` depuis `fastapi` :
|
||||
|
||||
* `Query` depuis `fastapi`
|
||||
* `Annotated` depuis `typing`
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *}
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||||
## Utiliser `Query` comme valeur par défaut
|
||||
|
||||
/// info
|
||||
Construisez ensuite la valeur par défaut de votre paramètre avec `Query`, en choisissant 50 comme `max_length` :
|
||||
|
||||
FastAPI a ajouté le support de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *}
|
||||
|
||||
Si vous avez une version plus ancienne, vous obtiendriez des erreurs en essayant d’utiliser `Annotated`.
|
||||
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.
|
||||
|
||||
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 d’utiliser `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} ?
|
||||
|
||||
C’est maintenant le moment de l’utiliser avec FastAPI. 🚀
|
||||
|
||||
Nous avions cette annotation de type :
|
||||
|
||||
//// tab | Python 3.10+
|
||||
Donc :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = Query(default=None)
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
... rend le paramètre optionnel, et est donc équivalent à :
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
////
|
||||
Mais déclare explicitement `q` comme étant un paramètre de requête.
|
||||
|
||||
Ce que nous allons faire est d’envelopper cela avec `Annotated`, pour que cela devienne :
|
||||
/// info
|
||||
|
||||
//// tab | Python 3.10+
|
||||
Gardez à l'esprit que la partie la plus importante pour rendre un paramètre optionnel est :
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None] = None
|
||||
= None
|
||||
```
|
||||
|
||||
////
|
||||
|
||||
//// tab | Python 3.9+
|
||||
ou :
|
||||
|
||||
```Python
|
||||
q: Annotated[Union[str, None]] = None
|
||||
= Query(None)
|
||||
```
|
||||
|
||||
////
|
||||
et utilisera ce `None` pour détecter que ce paramètre de requête **n'est pas requis**.
|
||||
|
||||
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 d’informations (dans ce cas une validation additionnelle), ajoutez `Query` à l’inté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)` à l’intérieur de `Annotated`, nous disons à FastAPI que nous voulons **de la validation additionnelle** pour cette valeur, nous voulons qu’elle ait au maximum 50 caractères. 😎
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ici, nous utilisons `Query()` parce que c’est un **paramètre de requête**. Plus tard, nous verrons d’autres éléments comme `Path()`, `Body()`, `Header()` et `Cookie()`, qui acceptent aussi les mêmes arguments que `Query()`.
|
||||
Le `Union[str, None]` est uniquement là pour permettre à votre éditeur un meilleur support.
|
||||
|
||||
///
|
||||
|
||||
FastAPI va maintenant :
|
||||
|
||||
* **Valider** les données en s’assurant 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 d’utiliser `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 l’utilise, donc je vais vous l’expliquer.
|
||||
|
||||
/// 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 :
|
||||
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 :
|
||||
|
||||
```Python
|
||||
q: str | None = Query(default=None)
|
||||
q: Union[str, None] = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
... rend le paramètre optionnel, avec une valeur par défaut de `None`, identique à :
|
||||
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*.
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
## Rajouter plus de validation
|
||||
|
||||
Mais la version avec `Query` le déclare explicitement comme étant un paramètre de requête.
|
||||
Vous pouvez aussi rajouter un second paramètre `min_length` :
|
||||
|
||||
Ensuite, nous pouvons passer d’autres paramètres à `Query`. Dans ce cas, le paramètre `max_length` qui s’applique aux chaînes de caractères :
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003.py hl[9] *}
|
||||
|
||||
```Python
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
## Ajouter des validations par expressions régulières
|
||||
|
||||
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*.
|
||||
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 :
|
||||
|
||||
### `Query` comme valeur par défaut ou dans `Annotated` { #query-as-the-default-value-or-in-annotated }
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004.py hl[10] *}
|
||||
|
||||
Gardez à l’esprit que lorsque vous utilisez `Query` à l’intérieur de `Annotated`, vous ne pouvez pas utiliser le paramètre `default` pour `Query`.
|
||||
Cette expression régulière vérifie que la valeur passée comme paramètre :
|
||||
|
||||
À la place, utilisez la valeur par défaut réelle du paramètre de la fonction. Sinon, ce serait incohérent.
|
||||
|
||||
Par exemple, ceci n’est pas autorisé :
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query(default="rick")] = "morty"
|
||||
```
|
||||
|
||||
... parce qu’il n’est 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, c’est **mieux** pour plusieurs raisons. 🤓
|
||||
|
||||
La valeur par défaut du **paramètre de la fonction** est la **vraie valeur par défaut**, c’est plus intuitif avec Python en général. 😌
|
||||
|
||||
Vous pourriez **appeler** cette même fonction à **d’autres endroits** sans FastAPI, et elle **fonctionnerait comme prévu**. S’il 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 l’exécutez sans passer le paramètre requis.
|
||||
|
||||
Quand vous n’utilisez pas `Annotated` et que vous utilisez à la place le **style (ancien) avec valeur par défaut**, si vous appelez cette fonction sans FastAPI à **d’autres endroits**, vous devez **vous souvenir** de passer les arguments à la fonction pour qu’elle 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 à l’intérieur échoueront.
|
||||
|
||||
Parce que `Annotated` peut avoir plus d’une annotation de métadonnées, vous pourriez maintenant même utiliser la même fonction avec d’autres 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 d’expression régulière spécifique vérifie que la valeur de paramètre reçue :
|
||||
|
||||
* `^` : commence avec les caractères qui suivent, n’a pas de caractères avant.
|
||||
* `^` : commence avec les caractères qui suivent, avec aucun caractère avant ceux-là.
|
||||
* `fixedquery` : a pour valeur exacte `fixedquery`.
|
||||
* `$` : se termine là, n’a pas d’autres caractères après `fixedquery`.
|
||||
* `$` : se termine directement ensuite, n'a pas d'autres caractères après `fixedquery`.
|
||||
|
||||
Si vous vous sentez perdu avec toutes ces idées d’**« regular expression »**, pas d’inquiétudes. C’est un sujet difficile pour beaucoup de gens. Vous pouvez encore faire beaucoup de choses sans avoir besoin d’expressions régulières.
|
||||
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.
|
||||
|
||||
Maintenant, vous savez que chaque fois que vous en avez besoin, vous pouvez les utiliser dans **FastAPI**.
|
||||
Mais si vous décidez d'apprendre à les utiliser, sachez qu'ensuite vous pouvez les utiliser directement dans **FastAPI**.
|
||||
|
||||
## Valeurs par défaut { #default-values }
|
||||
## Valeurs par défaut
|
||||
|
||||
Vous pouvez, bien sûr, utiliser des valeurs par défaut autres que `None`.
|
||||
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.
|
||||
|
||||
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"` :
|
||||
Disons que vous déclarez le paramètre `q` comme ayant une longueur minimale de `3`, et une valeur par défaut étant `"fixedquery"` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note | Rappel
|
||||
|
||||
Avoir une valeur par défaut de n’importe quel type, y compris `None`, rend le paramètre optionnel (non requis).
|
||||
Avoir une valeur par défaut rend le paramètre optionnel.
|
||||
|
||||
///
|
||||
|
||||
## Paramètres requis { #required-parameters }
|
||||
## Rendre ce paramètre requis
|
||||
|
||||
Quand nous n’avons 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 :
|
||||
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 :
|
||||
|
||||
```Python
|
||||
q: str
|
||||
```
|
||||
|
||||
au lieu de :
|
||||
à la place de :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Mais nous le déclarons maintenant avec `Query`, par exemple comme ceci :
|
||||
Mais maintenant, on déclare `q` avec `Query`, comme ceci :
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None, Query(min_length=3)] = None
|
||||
q: Union[str, None] = Query(default=None, min_length=3)
|
||||
```
|
||||
|
||||
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 :
|
||||
Donc pour déclarer une valeur comme requise tout en utilisant `Query`, il faut utiliser `...` comme premier argument :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
|
||||
|
||||
### Requis, peut être `None` { #required-can-be-none }
|
||||
/// info
|
||||
|
||||
Vous pouvez déclarer qu’un paramètre peut accepter `None`, mais qu’il est quand même requis. Cela forcerait les clients à envoyer une valeur, même si la valeur est `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>.
|
||||
|
||||
Pour faire cela, vous pouvez déclarer que `None` est un type valide mais simplement ne pas déclarer de valeur par défaut :
|
||||
///
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
|
||||
Cela indiquera à **FastAPI** que la présence de ce paramètre est obligatoire.
|
||||
|
||||
## Liste de paramètres de requête / valeurs multiples { #query-parameter-list-multiple-values }
|
||||
## Liste de paramètres / valeurs multiples via Query
|
||||
|
||||
Quand vous définissez un paramètre de requête explicitement avec `Query`, vous pouvez aussi le déclarer pour qu’il reçoive une liste de valeurs, ou dit autrement, pour qu’il reçoive plusieurs valeurs.
|
||||
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".
|
||||
|
||||
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans l’URL, vous pouvez écrire :
|
||||
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans une URL, on écrit :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *}
|
||||
|
||||
Ensuite, avec une URL comme :
|
||||
Ce qui fait qu'avec une URL comme :
|
||||
|
||||
```
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
Donc la réponse à cette URL serait :
|
||||
Donc la réponse de cette URL serait :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -280,19 +173,19 @@ Donc la réponse à cette URL serait :
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pour déclarer un paramètre de requête avec un type `list`, comme dans l’exemple ci-dessus, vous devez explicitement utiliser `Query`, sinon cela serait interprété comme un corps de la requête.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
Les documents interactifs de l’API seront mis à jour en conséquence, pour autoriser plusieurs valeurs :
|
||||
La documentation sera donc mise à jour automatiquement pour autoriser plusieurs valeurs :
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image02.png">
|
||||
|
||||
### Liste de paramètres de requête / valeurs multiples avec des valeurs par défaut { #query-parameter-list-multiple-values-with-defaults }
|
||||
### Combiner liste de paramètres et valeurs par défaut
|
||||
|
||||
Vous pouvez aussi définir une `list` de valeurs par défaut si aucune n’est fournie :
|
||||
Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *}
|
||||
|
||||
Si vous allez à :
|
||||
|
||||
@@ -300,7 +193,9 @@ Si vous allez à :
|
||||
http://localhost:8000/items/
|
||||
```
|
||||
|
||||
la valeur par défaut de `q` sera : `["foo", "bar"]` et votre réponse sera :
|
||||
la valeur par défaut de `q` sera : `["foo", "bar"]`
|
||||
|
||||
et la réponse sera :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -311,163 +206,93 @@ la valeur par défaut de `q` sera : `["foo", "bar"]` et votre réponse sera :
|
||||
}
|
||||
```
|
||||
|
||||
#### Utiliser seulement `list` { #using-just-list }
|
||||
#### Utiliser `list`
|
||||
|
||||
Vous pouvez aussi utiliser `list` directement au lieu de `list[str]` :
|
||||
Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Gardez à l’esprit que dans ce cas, FastAPI ne vérifiera pas le contenu de la liste.
|
||||
Dans ce cas-là, **FastAPI** ne vérifiera pas le contenu de la liste.
|
||||
|
||||
Par exemple, `list[int]` vérifierait (et documenterait) que le contenu de la liste est composé d’entiers. Mais `list` seul ne le ferait pas.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Déclarer plus de métadonnées { #declare-more-metadata }
|
||||
## Déclarer des métadonnées supplémentaires
|
||||
|
||||
Vous pouvez ajouter plus d’informations à propos du paramètre.
|
||||
On peut aussi ajouter plus d'informations sur le paramètre.
|
||||
|
||||
Ces informations seront incluses dans l’OpenAPI généré et utilisées par les interfaces utilisateur de la documentation et les outils externes.
|
||||
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.
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Gardez à l’esprit que différents outils peuvent avoir des niveaux de support d’OpenAPI différents.
|
||||
Gardez en tête que les outils externes utilisés ne supportent pas forcément tous parfaitement OpenAPI.
|
||||
|
||||
Certains d’entre 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.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez ajouter un `title` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial007.py hl[10] *}
|
||||
|
||||
Et une `description` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *}
|
||||
|
||||
## Alias de paramètres { #alias-parameters }
|
||||
## Alias de paramètres
|
||||
|
||||
Imaginez que vous voulez que le paramètre soit `item-query`.
|
||||
Imaginez que vous vouliez que votre paramètre se nomme `item-query`.
|
||||
|
||||
Comme dans :
|
||||
Comme dans la requête :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
```
|
||||
|
||||
Mais `item-query` n’est pas un nom de variable Python valide.
|
||||
Mais `item-query` n'est pas un nom de variable valide en Python.
|
||||
|
||||
Le plus proche serait `item_query`.
|
||||
Le nom le plus proche serait `item_query`.
|
||||
|
||||
Mais vous en avez encore besoin pour qu’il soit exactement `item-query`...
|
||||
Mais vous avez vraiment envie que ce soit exactement `item-query`...
|
||||
|
||||
Alors vous pouvez déclarer un `alias`, et cet alias sera ce qui sera utilisé pour trouver la valeur du paramètre :
|
||||
Pour cela vous pouvez déclarer un `alias`, et cet alias est ce qui sera utilisé pour trouver la valeur du paramètre :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *}
|
||||
|
||||
## Déprécier des paramètres { #deprecating-parameters }
|
||||
## Déprécier des paramètres
|
||||
|
||||
Disons maintenant que vous n’aimez plus ce paramètre.
|
||||
Disons que vous ne vouliez plus utiliser ce paramètre désormais.
|
||||
|
||||
Vous devez le laisser là pendant un moment parce qu’il y a des clients qui l’utilisent, mais vous voulez que les documents le montrent clairement comme <abbr title="obsolete, recommended not to use it - obsolète, recommandé de ne pas l’utiliser">deprecated</abbr>.
|
||||
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>.
|
||||
|
||||
Ensuite, passez le paramètre `deprecated=True` à `Query` :
|
||||
On utilise alors l'argument `deprecated=True` de `Query` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *}
|
||||
|
||||
Les documents l’afficheront comme ceci :
|
||||
La documentation le présentera comme il suit :
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image01.png">
|
||||
|
||||
## Exclusion d'OpenAPI { #exclude-parameters-from-openapi }
|
||||
## Pour résumer
|
||||
|
||||
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` :
|
||||
Il est possible d'ajouter des validateurs et métadonnées pour vos paramètres.
|
||||
|
||||
{* ../../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> à l’inté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 d’autres. 🤓
|
||||
|
||||
///
|
||||
|
||||
Par exemple, ce validateur personnalisé vérifie que l’ID de l’item 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 d’URL 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 d’utiliser **`AfterValidator` avec une fonction dans `Annotated`**. N’hé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 l’utilisateur n’a pas fourni d’ID d’item, il recevra quand même une suggestion aléatoire.
|
||||
|
||||
... nous faisons tout cela en **une seule ligne simple**. 🤯 Vous n’aimez 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 :
|
||||
Validateurs et métadonnées génériques:
|
||||
|
||||
* `alias`
|
||||
* `title`
|
||||
* `description`
|
||||
* `deprecated`
|
||||
|
||||
Validations spécifiques pour les chaînes de caractères :
|
||||
Validateurs spécifiques aux chaînes de caractères :
|
||||
|
||||
* `min_length`
|
||||
* `max_length`
|
||||
* `pattern`
|
||||
* `regex`
|
||||
|
||||
Validations personnalisées utilisant `AfterValidator`.
|
||||
Parmi ces exemples, vous avez pu voir comment déclarer des validateurs pour les chaînes de caractères.
|
||||
|
||||
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 d’autres types, comme les nombres.
|
||||
Dans les prochains chapitres, vous verrez comment déclarer des validateurs pour d'autres types, comme les nombres.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Paramètres de requête { #query-parameters }
|
||||
# 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 ».
|
||||
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".
|
||||
|
||||
{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
|
||||
{* ../../docs_src/query_params/tutorial001.py hl[9] *}
|
||||
|
||||
La requête est l'ensemble des paires clé-valeur qui suivent le `?` dans une URL, séparées par des caractères `&`.
|
||||
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 `&`.
|
||||
|
||||
Par exemple, dans l'URL :
|
||||
|
||||
@@ -12,72 +12,80 @@ 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`
|
||||
|
||||
Comme ils font partie de l'URL, ce sont « naturellement » des chaînes de caractères.
|
||||
Faisant partie de l'URL, ces valeurs sont des chaînes de caractères (`str`).
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
Tous les mêmes processus qui s'appliquaient aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
|
||||
Toutes les fonctionnalités qui s'appliquent aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
|
||||
|
||||
* 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
|
||||
* 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.
|
||||
|
||||
## Valeurs par défaut { #defaults }
|
||||
## 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.
|
||||
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.
|
||||
|
||||
Dans l'exemple ci-dessus, ils ont des valeurs par défaut `skip=0` et `limit=10`.
|
||||
Dans l'exemple ci-dessus, ils ont des valeurs par défaut qui sont `skip=0` et `limit=10`.
|
||||
|
||||
Ainsi, aller à l'URL :
|
||||
Donc, accéder à l'URL :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/
|
||||
```
|
||||
|
||||
serait équivalent à aller à :
|
||||
serait équivalent à accéder à l'URL :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
Mais si vous allez à, par exemple :
|
||||
Mais si vous accédez à, par exemple :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=20
|
||||
```
|
||||
|
||||
Les valeurs des paramètres dans votre fonction seront :
|
||||
Les valeurs des paramètres de votre fonction seront :
|
||||
|
||||
* `skip=20` : parce que vous l'avez défini dans l'URL
|
||||
* `limit=10` : parce que c'était la valeur par défaut
|
||||
* `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`.
|
||||
|
||||
## Paramètres optionnels { #optional-parameters }
|
||||
## Paramètres optionnels
|
||||
|
||||
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` :
|
||||
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` :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
|
||||
{* ../../docs_src/query_params/tutorial002.py hl[9] *}
|
||||
|
||||
Dans ce cas, le paramètre de fonction `q` sera optionnel, et aura `None` comme valeur par défaut.
|
||||
Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut.
|
||||
|
||||
/// check | Vérifications
|
||||
/// check | Remarque
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
## Conversion du type des paramètres de requête { #query-parameter-type-conversion }
|
||||
/// note
|
||||
|
||||
Vous pouvez aussi déclarer des types `bool`, et ils seront convertis :
|
||||
**FastAPI** saura que `q` est optionnel grâce au `=None`.
|
||||
|
||||
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
|
||||
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.
|
||||
|
||||
Dans ce cas, si vous allez à :
|
||||
///
|
||||
|
||||
## 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 :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=1
|
||||
@@ -107,62 +115,60 @@ ou
|
||||
http://127.0.0.1:8000/items/foo?short=yes
|
||||
```
|
||||
|
||||
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`.
|
||||
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`.
|
||||
|
||||
## Multiples paramètres de chemin et de requête
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
Et vous n'avez pas besoin de les déclarer dans un ordre spécifique.
|
||||
|
||||
Ils seront détectés par leur nom :
|
||||
Ils seront détectés par leurs noms :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
|
||||
{* ../../docs_src/query_params/tutorial004.py hl[8,10] *}
|
||||
|
||||
## Paramètres de requête requis { #required-query-parameters }
|
||||
## Paramètres de requête 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.
|
||||
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.
|
||||
|
||||
Si vous ne voulez pas ajouter une valeur spécifique mais juste le rendre optionnel, définissez la valeur par défaut sur `None`.
|
||||
Si vous ne voulez pas leur donner de valeur par défaut mais juste les rendre optionnels, utilisez `None` comme 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 :
|
||||
Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez juste ne pas y affecter de valeur par défaut :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
|
||||
{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
|
||||
|
||||
Ici, le paramètre de requête `needy` est un paramètre de requête requis de type `str`.
|
||||
Ici le paramètre `needy` est un paramètre requis (ou obligatoire) de type `str`.
|
||||
|
||||
Si vous ouvrez dans votre navigateur une URL comme :
|
||||
Si vous ouvrez une URL comme :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item
|
||||
```
|
||||
|
||||
... sans ajouter le paramètre requis `needy`, vous verrez une erreur comme :
|
||||
...sans ajouter le paramètre requis `needy`, vous aurez une erreur :
|
||||
|
||||
```JSON
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"type": "missing",
|
||||
"loc": [
|
||||
"query",
|
||||
"needy"
|
||||
],
|
||||
"msg": "Field required",
|
||||
"input": null
|
||||
}
|
||||
]
|
||||
"detail": [
|
||||
{
|
||||
"loc": [
|
||||
"query",
|
||||
"needy"
|
||||
],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Comme `needy` est un paramètre requis, vous devez le définir dans l'URL :
|
||||
La présence de `needy` étant nécessaire, vous auriez besoin de l'insérer dans l'URL :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
```
|
||||
|
||||
... cela fonctionnerait :
|
||||
...ce qui fonctionnerait :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -171,18 +177,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
}
|
||||
```
|
||||
|
||||
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 :
|
||||
Et bien sur, vous pouvez définir certains paramètres comme requis, certains avec des valeurs par défaut et certains entièrement optionnels :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
|
||||
{* ../../docs_src/query_params/tutorial006.py hl[10] *}
|
||||
|
||||
Dans ce cas, il y a 3 paramètres de requête :
|
||||
Ici, on a donc 3 paramètres de requête :
|
||||
|
||||
* `needy`, un `str` requis.
|
||||
* `skip`, un `int` avec une valeur par défaut de `0`.
|
||||
* `needy`, requis et de type `str`.
|
||||
* `skip`, un `int` avec comme valeur par défaut `0`.
|
||||
* `limit`, un `int` optionnel.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
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}.
|
||||
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}.
|
||||
|
||||
///
|
||||
|
||||
@@ -8,6 +8,7 @@ Language code: ko.
|
||||
|
||||
- Use polite, instructional Korean (e.g. 합니다/하세요 style).
|
||||
- Keep the tone consistent with the existing Korean FastAPI docs.
|
||||
- Do not translate “You” literally as “당신”. Use “여러분” where appropriate, or omit the subject if it sounds more natural in Korean.
|
||||
|
||||
### Headings
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Arquivo de teste de LLM { #llm-test-file }
|
||||
|
||||
Este documento testa se o <abbr title="Large Language Model – Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
|
||||
Este documento testa se o <abbr title="Large Language Model - Modelo de Linguagem de Grande Porte">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.
|
||||
|
||||
Os testes adicionados aqui serão vistos por todos os autores dos prompts específicos de idioma.
|
||||
Os testes adicionados aqui serão vistos por todos os designers dos prompts específicos de idioma.
|
||||
|
||||
Use da seguinte forma:
|
||||
|
||||
@@ -23,7 +23,7 @@ Este é um trecho de código: `foo`. E este é outro trecho de código: `bar`. E
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O conteúdo dos trechos de código deve ser deixado como está.
|
||||
|
||||
@@ -45,9 +45,9 @@ O LLM provavelmente vai traduzir isso errado. O interessante é apenas se ele ma
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O autor do prompt pode escolher se deseja converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
|
||||
O designer do prompt pode escolher se quer converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.
|
||||
|
||||
Veja, por exemplo, a seção `### Quotes` em `docs/de/llm-prompt.md`.
|
||||
|
||||
@@ -67,7 +67,7 @@ Pesado: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you ha
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
... No entanto, as aspas dentro de trechos de código devem permanecer como estão.
|
||||
|
||||
@@ -95,24 +95,24 @@ $ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid
|
||||
...e outro exemplo de código de console...
|
||||
|
||||
```console
|
||||
// Crie um diretório "Code"
|
||||
// Criar um diretório "Code"
|
||||
$ mkdir code
|
||||
// Entre nesse diretório
|
||||
// Mudar para esse diretório
|
||||
$ cd code
|
||||
```
|
||||
|
||||
...e um exemplo de código Python...
|
||||
|
||||
```Python
|
||||
wont_work() # Isto não vai funcionar 😱
|
||||
works(foo="bar") # Isto funciona 🎉
|
||||
wont_work() # This won't work 😱
|
||||
works(foo="bar") # This works 🎉
|
||||
```
|
||||
|
||||
...e é isso.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
O código em blocos de código não deve ser modificado, com exceção dos comentários.
|
||||
|
||||
@@ -154,7 +154,7 @@ Algum texto
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Abas e blocos `Info`/`Note`/`Warning`/etc. devem ter a tradução do seu título adicionada após uma barra vertical (`|`).
|
||||
|
||||
@@ -181,7 +181,7 @@ O texto do link deve ser traduzido, o endereço do link deve apontar para a trad
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Os links devem ser traduzidos, mas seus endereços devem permanecer inalterados. Uma exceção são links absolutos para páginas da documentação do FastAPI. Nesse caso, devem apontar para a tradução.
|
||||
|
||||
@@ -197,10 +197,10 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done – Fazer as Coisas">GTD</abbr>
|
||||
* <abbr title="menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token – Token Web XML">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface – Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
* <abbr title="Getting Things Done">GTD</abbr>
|
||||
* <abbr title="less than - menos que"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Interface de Gateway de Servidor Paralelo">PSGI</abbr>
|
||||
|
||||
### O abbr fornece uma explicação { #the-abbr-gives-an-explanation }
|
||||
|
||||
@@ -209,12 +209,12 @@ Aqui estão algumas coisas envolvidas em elementos HTML "abbr" (algumas são inv
|
||||
|
||||
### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network – Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output – Entrada/Saída: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
|
||||
* <abbr title="Mozilla Developer Network: documentação para desenvolvedores, escrita pelo pessoal do Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output: leitura ou escrita em disco, comunicações de rede.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Os atributos "title" dos elementos "abbr" são traduzidos seguindo algumas instruções específicas.
|
||||
|
||||
@@ -228,7 +228,7 @@ Veja a seção `### HTML abbr elements` no prompt geral em `scripts/translate.py
|
||||
|
||||
//// tab | Teste
|
||||
|
||||
### Desenvolver uma aplicação web - um tutorial { #develop-a-webapp-a-tutorial }
|
||||
### Desenvolver uma webapp - um tutorial { #develop-a-webapp-a-tutorial }
|
||||
|
||||
Olá.
|
||||
|
||||
@@ -242,7 +242,7 @@ Olá novamente.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
A única regra rígida para títulos é que o LLM deixe a parte do hash dentro de chaves inalterada, o que garante que os links não quebrem.
|
||||
|
||||
@@ -494,9 +494,9 @@ Para algumas instruções específicas do idioma, veja, por exemplo, a seção `
|
||||
|
||||
////
|
||||
|
||||
//// tab | Informações
|
||||
//// tab | Informação
|
||||
|
||||
Esta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o autor do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.
|
||||
Esta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o designer do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.
|
||||
|
||||
Veja, por exemplo, a seção `### List of English terms and their preferred German translations` em `docs/de/llm-prompt.md`.
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Se você não é um "especialista" no OpenAPI, você provavelmente não precisa
|
||||
|
||||
Você pode definir o `operationId` do OpenAPI que será utilizado na sua *operação de rota* com o parâmetro `operation_id`.
|
||||
|
||||
Você precisa ter certeza que ele é único para cada operação.
|
||||
Você deveria ter certeza que ele é único para cada operação.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
|
||||
@@ -18,13 +18,13 @@ Você precisa ter certeza que ele é único para cada operação.
|
||||
|
||||
Se você quiser utilizar o nome das funções da sua API como `operationId`s, você pode iterar sobre todos esses nomes e sobrescrever o `operation_id` em cada *operação de rota* utilizando o `APIRoute.name` dela.
|
||||
|
||||
Você deve fazer isso depois de adicionar todas as suas *operações de rota*.
|
||||
Você deveria fazer isso depois de adicionar todas as suas *operações de rota*.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você chamar `app.openapi()` manualmente, os `operationId`s devem ser atualizados antes dessa chamada.
|
||||
Se você chamar `app.openapi()` manualmente, você deveria atualizar os `operationId`s antes dessa chamada.
|
||||
|
||||
///
|
||||
|
||||
@@ -44,11 +44,11 @@ Para excluir uma *operação de rota* do esquema OpenAPI gerado (e por consequê
|
||||
|
||||
## Descrição avançada a partir de docstring { #advanced-description-from-docstring }
|
||||
|
||||
Você pode limitar as linhas utilizadas a partir de uma docstring de uma *função de operação de rota* para o OpenAPI.
|
||||
Você pode limitar as linhas utilizadas a partir da docstring de uma *função de operação de rota* para o OpenAPI.
|
||||
|
||||
Adicionar um `\f` (um caractere de escape para alimentação de formulário) faz com que o **FastAPI** restrinja a saída utilizada pelo OpenAPI até esse ponto.
|
||||
Adicionar um `\f` (um caractere de escape para "form feed") faz com que o **FastAPI** trunque a saída usada para o OpenAPI até esse ponto.
|
||||
|
||||
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto do texto.
|
||||
Ele não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
@@ -131,70 +131,38 @@ E se você olhar o esquema OpenAPI resultante (na rota `/openapi.json` da sua AP
|
||||
|
||||
### Esquema de *operação de rota* do OpenAPI personalizado { #custom-openapi-path-operation-schema }
|
||||
|
||||
O dicionário em `openapi_extra` vai ter todos os seus níveis mesclados dentro do esquema OpenAPI gerado automaticamente para a *operação de rota*.
|
||||
O dicionário em `openapi_extra` vai ser mesclado profundamente com o esquema OpenAPI gerado automaticamente para a *operação de rota*.
|
||||
|
||||
Então, você pode adicionar dados extras para o esquema gerado automaticamente.
|
||||
Então, você pode adicionar dados extras ao esquema gerado automaticamente.
|
||||
|
||||
Por exemplo, você poderia optar por ler e validar a requisição com seu próprio código, sem utilizar funcionalidades automatizadas do FastAPI com o Pydantic, mas você ainda pode quere definir a requisição no esquema OpenAPI.
|
||||
Por exemplo, você poderia decidir ler e validar a requisição com seu próprio código, sem usar as funcionalidades automáticas do FastAPI com o Pydantic, mas ainda assim querer definir a requisição no esquema OpenAPI.
|
||||
|
||||
Você pode fazer isso com `openapi_extra`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
|
||||
Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <abbr title="convertido de um formato plano, como bytes, para objetos Python">analisado</abbr> como JSON, ele é lido diretamente como `bytes` e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
|
||||
Nesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <abbr title="converted from some plain format, like bytes, into Python objects - convertido de algum formato simples, como bytes, em objetos Python">analisado</abbr> como JSON, ele é lido diretamente como `bytes`, e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma.
|
||||
|
||||
De toda forma, nós podemos declarar o esquema esperado para o corpo da requisição.
|
||||
|
||||
### Tipo de conteúdo do OpenAPI personalizado { #custom-openapi-content-type }
|
||||
|
||||
Utilizando esse mesmo truque, você pode utilizar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.
|
||||
Utilizando esse mesmo truque, você pode usar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.
|
||||
|
||||
E você pode fazer isso até mesmo quando os dados da requisição não seguem o formato JSON.
|
||||
E você pode fazer isso até mesmo quando o tipo de dados na requisição não é JSON.
|
||||
|
||||
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática do JSON. Na verdade, estamos declarando o tipo do conteúdo da requisição como YAML, em vez de JSON:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
Por exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática para JSON. Na verdade, estamos declarando o tipo de conteúdo da requisição como YAML, em vez de JSON:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber em YAML.
|
||||
|
||||
//// tab | Pydantic v1
|
||||
Então utilizamos a requisição diretamente e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o payload da requisição como JSON.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic, o método para obter o JSON Schema de um modelo é `Item.schema()`, na versão 2 do Pydantic, o método é `Item.model_json_schema()`.
|
||||
|
||||
///
|
||||
|
||||
Entretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber no formato YAML.
|
||||
|
||||
Então utilizamos a requisição diretamente, e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o corpo da requisição como JSON.
|
||||
|
||||
E então no nosso código, nós analisamos o conteúdo YAML diretamente, e estamos utilizando o mesmo modelo Pydantic para validar o conteúdo YAML:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
E então no nosso código, nós analisamos o conteúdo YAML diretamente e, em seguida, estamos usando novamente o mesmo modelo Pydantic para validar o conteúdo YAML:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic, o método para analisar e validar um objeto era `Item.parse_obj()`, na versão 2 do Pydantic, o método é chamado de `Item.model_validate()`.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Aqui reutilizamos o mesmo modelo do Pydantic.
|
||||
|
||||
@@ -46,12 +46,6 @@ $ pip install "fastapi[all]"
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 ele vinha incluído no pacote principal. Agora é distribuído como um pacote independente para que você possa optar por instalá-lo ou não, caso não precise dessa funcionalidade.
|
||||
|
||||
///
|
||||
|
||||
### Criar o objeto `Settings` { #create-the-settings-object }
|
||||
|
||||
Importe `BaseSettings` do Pydantic e crie uma subclasse, muito parecido com um modelo do Pydantic.
|
||||
@@ -60,24 +54,8 @@ Da mesma forma que com modelos do Pydantic, você declara atributos de classe co
|
||||
|
||||
Você pode usar as mesmas funcionalidades e ferramentas de validação que usa em modelos do Pydantic, como diferentes tipos de dados e validações adicionais com `Field()`.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 você importaria `BaseSettings` diretamente de `pydantic` em vez de `pydantic_settings`.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você quer algo rápido para copiar e colar, não use este exemplo, use o último abaixo.
|
||||
@@ -215,8 +193,6 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
E então atualizar seu `config.py` com:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
|
||||
|
||||
/// tip | Dica
|
||||
@@ -225,26 +201,6 @@ O atributo `model_config` é usado apenas para configuração do Pydantic. Você
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
A classe `Config` é usada apenas para configuração do Pydantic. Você pode ler mais em <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Na versão 1 do Pydantic a configuração era feita em uma classe interna `Config`, na versão 2 do Pydantic é feita em um atributo `model_config`. Esse atributo recebe um `dict`, e para ter autocompletar e erros inline você pode importar e usar `SettingsConfigDict` para definir esse `dict`.
|
||||
|
||||
///
|
||||
|
||||
Aqui definimos a configuração `env_file` dentro da sua classe `Settings` do Pydantic e definimos o valor como o nome do arquivo dotenv que queremos usar.
|
||||
|
||||
### Criando o `Settings` apenas uma vez com `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
Se você tem uma aplicação FastAPI antiga, pode estar usando o Pydantic versão 1.
|
||||
|
||||
O FastAPI tem suporte ao Pydantic v1 ou v2 desde a versão 0.100.0.
|
||||
O FastAPI versão 0.100.0 tinha suporte ao Pydantic v1 ou v2. Ele usaria aquele que você tivesse instalado.
|
||||
|
||||
Se você tiver o Pydantic v2 instalado, ele será utilizado. Se, em vez disso, tiver o Pydantic v1, será ele que será utilizado.
|
||||
O FastAPI versão 0.119.0 introduziu suporte parcial ao Pydantic v1 a partir de dentro do Pydantic v2 (como `pydantic.v1`), para facilitar a migração para o v2.
|
||||
|
||||
O Pydantic v1 está agora descontinuado e o suporte a ele será removido nas próximas versões do FastAPI, você deveria migrar para o Pydantic v2. Assim, você terá as funcionalidades, melhorias e correções mais recentes.
|
||||
O FastAPI 0.126.0 removeu o suporte ao Pydantic v1, enquanto ainda oferece suporte a `pydantic.v1` por mais algum tempo.
|
||||
|
||||
/// warning | Atenção
|
||||
|
||||
Além disso, a equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
|
||||
A equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.
|
||||
|
||||
Isso inclui `pydantic.v1`, que não é mais suportado no Python 3.14 e superiores.
|
||||
|
||||
Se quiser usar as funcionalidades mais recentes do Python, você precisará garantir que usa o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2 e as **novas funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
|
||||
Se você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2, e as **funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.
|
||||
|
||||
## Guia oficial { #official-guide }
|
||||
|
||||
@@ -44,7 +46,7 @@ Depois disso, você pode rodar os testes e verificar se tudo funciona. Se funcio
|
||||
|
||||
## Pydantic v1 no v2 { #pydantic-v1-in-v2 }
|
||||
|
||||
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`.
|
||||
O Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`. Mas isso não é mais suportado em versões acima do Python 3.13.
|
||||
|
||||
Isso significa que você pode instalar a versão mais recente do Pydantic v2 e importar e usar os componentes antigos do Pydantic v1 a partir desse submódulo, como se tivesse o Pydantic v1 antigo instalado.
|
||||
|
||||
@@ -66,7 +68,7 @@ Tenha em mente que, como a equipe do Pydantic não oferece mais suporte ao Pydan
|
||||
|
||||
### Pydantic v1 e v2 na mesma aplicação { #pydantic-v1-and-v2-on-the-same-app }
|
||||
|
||||
Não é suportado pelo Pydantic ter um modelo do Pydantic v2 com campos próprios definidos como modelos do Pydantic v1, ou vice-versa.
|
||||
Não é **suportado** pelo Pydantic ter um modelo do Pydantic v2 com campos próprios definidos como modelos do Pydantic v1, ou vice-versa.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -86,7 +88,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
...but, you can have separated models using Pydantic v1 and v2 in the same app.
|
||||
...mas, você pode ter modelos separados usando Pydantic v1 e v2 na mesma aplicação.
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
@@ -106,7 +108,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma operação de rota na sua aplicação FastAPI:
|
||||
Em alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma **operação de rota** na sua aplicação FastAPI:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
|
||||
|
||||
@@ -122,7 +124,7 @@ Se você precisar usar algumas das ferramentas específicas do FastAPI para par
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Primeiro tente com o `bump-pydantic`; se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
|
||||
Primeiro tente com o `bump-pydantic`, se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Esquemas OpenAPI Separados para Entrada e Saída ou Não { #separate-openapi-schemas-for-input-and-output-or-not }
|
||||
|
||||
Ao usar **Pydantic v2**, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
Desde que o **Pydantic v2** foi lançado, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎
|
||||
|
||||
Inclusive, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
|
||||
De fato, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.
|
||||
|
||||
Vamos ver como isso funciona e como alterar se for necessário.
|
||||
|
||||
@@ -95,10 +95,8 @@ O suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.
|
||||
|
||||
### Mesmo Esquema para Modelos de Entrada e Saída na Documentação { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e `description` **não será obrigatório**:
|
||||
E agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e ele terá `description` como **não obrigatório**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
|
||||
Esse é o mesmo comportamento do Pydantic v1. 🤓
|
||||
|
||||
@@ -40,8 +40,8 @@ Os recursos chave são:
|
||||
* **Rápido**: alta performance, equivalente a **NodeJS** e **Go** (graças ao Starlette e Pydantic). [Um dos frameworks mais rápidos disponíveis](#performance).
|
||||
* **Rápido para codar**: Aumenta a velocidade para desenvolver recursos entre 200% a 300%. *
|
||||
* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *
|
||||
* **Intuitivo**: Grande suporte a _IDEs_. <abbr title="também conhecido como autocompletar, preenchimento automático, IntelliSense">Preenchimento automático</abbr> em todos os lugares. Menos tempo debugando.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo documentação.
|
||||
* **Intuitivo**: Grande suporte a editores. <abbr title="também conhecido como auto-complete, autocompletion, IntelliSense">Completação</abbr> em todos os lugares. Menos tempo debugando.
|
||||
* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo docs.
|
||||
* **Enxuto**: Minimize duplicação de código. Múltiplas funcionalidades para cada declaração de parâmetro. Menos bugs.
|
||||
* **Robusto**: Tenha código pronto para produção. E com documentação interativa automática.
|
||||
* **Baseado em padrões**: Baseado em (e totalmente compatível com) os padrões abertos para APIs: <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (anteriormente conhecido como Swagger) e <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
@@ -73,7 +73,7 @@ Os recursos chave são:
|
||||
|
||||
## Opiniões { #opinions }
|
||||
|
||||
"*[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços _Machine Learning_ na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **Office**.*"
|
||||
"_[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços ML na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **Office**._"
|
||||
|
||||
<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>
|
||||
|
||||
@@ -91,39 +91,45 @@ Os recursos chave são:
|
||||
|
||||
---
|
||||
|
||||
"*Estou extremamente entusiasmado com o **FastAPI**. É tão divertido!*"
|
||||
"_Estou muito entusiasmado com o **FastAPI**. É tão divertido!_"
|
||||
|
||||
<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> podcaster</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> apresentador do podcast</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"*Honestamente, o que você construiu parece super sólido e rebuscado. De muitas formas, eu queria que o **Hug** fosse assim - é realmente inspirador ver alguém que construiu ele.*"
|
||||
"_Honestamente, o que você construiu parece super sólido e refinado. De muitas formas, é o que eu queria que o **Hug** fosse - é realmente inspirador ver alguém construir isso._"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong>criador do<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>
|
||||
|
||||
---
|
||||
|
||||
"*Se você está procurando aprender um **_framework_ moderno** para construir aplicações _REST_, dê uma olhada no **FastAPI** [...] É rápido, fácil de usar e fácil de aprender [...]*"
|
||||
"_Se você está procurando aprender um **framework moderno** para construir APIs REST, dê uma olhada no **FastAPI** [...] É rápido, fácil de usar e fácil de aprender [...]_"
|
||||
|
||||
"*Nós trocamos nossas **APIs** por **FastAPI** [...] Acredito que vocês gostarão dele [...]*"
|
||||
"_Nós trocamos nossas **APIs** por **FastAPI** [...] Acredito que você gostará dele [...]_"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>fundadores da <a href="https://explosion.ai" target="_blank">Explosion AI</a> - criadores da <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>
|
||||
|
||||
---
|
||||
|
||||
"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**. Ele se tornou um **componente chave** para a nossa estratégia API first de desenvolvimento e está impulsionando diversas automações e serviços, como o nosso Virtual TAC Engineer._"
|
||||
"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**, e se tornou um **componente chave** para a nossa estratégia de desenvolvimento API first, impulsionando diversas automações e serviços, como o nosso 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>
|
||||
|
||||
---
|
||||
|
||||
## Mini documentário do FastAPI { #fastapi-mini-documentary }
|
||||
|
||||
Há um <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documentário do FastAPI</a> lançado no fim de 2025, você pode assisti-lo online:
|
||||
|
||||
<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**, o FastAPI das interfaces de linhas de comando { #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>
|
||||
|
||||
Se você estiver construindo uma aplicação <abbr title="Command Line Interface – Interface de Linha de Comando">CLI</abbr> para ser utilizada em um terminal ao invés de uma aplicação web, dê uma olhada no <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
Se você estiver construindo uma aplicação <abbr title="Command Line Interface - Interface de Linha de Comando">CLI</abbr> para ser utilizada no terminal ao invés de uma API web, dê uma olhada no <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
|
||||
**Typer** é o irmão menor do FastAPI. E seu propósito é ser o **FastAPI das _CLIs_**. ⌨️ 🚀
|
||||
**Typer** é o irmão menor do FastAPI. E seu propósito é ser o **FastAPI das CLIs**. ⌨️ 🚀
|
||||
|
||||
## Requisitos { #requirements }
|
||||
|
||||
@@ -255,10 +261,10 @@ Você verá a resposta JSON como:
|
||||
|
||||
Você acabou de criar uma API que:
|
||||
|
||||
* Recebe requisições HTTP nas _rotas_ `/` e `/items/{item_id}`.
|
||||
* Ambas _rotas_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
|
||||
* A _rota_ `/items/{item_id}` tem um _parâmetro de rota_ `item_id` que deve ser um `int`.
|
||||
* A _rota_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
|
||||
* Recebe requisições HTTP nos _paths_ `/` e `/items/{item_id}`.
|
||||
* Ambos _paths_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).
|
||||
* O _path_ `/items/{item_id}` tem um _parâmetro de path_ `item_id` que deve ser um `int`.
|
||||
* O _path_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.
|
||||
|
||||
### Documentação Interativa da API { #interactive-api-docs }
|
||||
|
||||
@@ -278,7 +284,7 @@ Você verá a documentação automática alternativa (fornecida por <a href="htt
|
||||
|
||||
## Evoluindo o Exemplo { #example-upgrade }
|
||||
|
||||
Agora modifique o arquivo `main.py` para receber um corpo para uma requisição `PUT`.
|
||||
Agora modifique o arquivo `main.py` para receber um corpo de uma requisição `PUT`.
|
||||
|
||||
Declare o corpo utilizando tipos padrão Python, graças ao Pydantic.
|
||||
|
||||
@@ -334,7 +340,7 @@ Agora vá para <a href="http://127.0.0.1:8000/docs" class="external-link" target
|
||||
|
||||
E agora, vá para <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
* A documentação alternativa também irá refletir o novo parâmetro da _query_ e o corpo:
|
||||
* A documentação alternativa também irá refletir o novo parâmetro query e o corpo:
|
||||
|
||||

|
||||
|
||||
@@ -368,15 +374,15 @@ item: Item
|
||||
* Validação de dados:
|
||||
* Erros automáticos e claros quando o dado é inválido.
|
||||
* Validação até para objetos JSON profundamente aninhados.
|
||||
* <abbr title="também conhecido como: serialização, parsing, marshalling">Conversão</abbr> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
|
||||
* <abbr title="também conhecido como: serialization, parsing, marshalling">Conversão</abbr> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:
|
||||
* JSON.
|
||||
* Parâmetros de rota.
|
||||
* Parâmetros de _query_ .
|
||||
* _Cookies_.
|
||||
* Parâmetros de path.
|
||||
* Parâmetros query.
|
||||
* Cookies.
|
||||
* Cabeçalhos.
|
||||
* Formulários.
|
||||
* Arquivos.
|
||||
* <abbr title="também conhecido como: serialização, parsing, marshalling">Conversão</abbr> de dados de saída de tipos e dados Python para dados de rede (como JSON):
|
||||
* <abbr title="também conhecido como: serialization, parsing, marshalling">Conversão</abbr> de dados de saída: convertendo de tipos e dados Python para dados de rede (como JSON):
|
||||
* Converte tipos Python (`str`, `int`, `float`, `bool`, `list` etc).
|
||||
* Objetos `datetime`.
|
||||
* Objetos `UUID`.
|
||||
@@ -390,17 +396,17 @@ item: Item
|
||||
|
||||
Voltando ao código do exemplo anterior, **FastAPI** irá:
|
||||
|
||||
* Validar que existe um `item_id` na rota para requisições `GET` e `PUT`.
|
||||
* Validar que existe um `item_id` no path para requisições `GET` e `PUT`.
|
||||
* Validar que `item_id` é do tipo `int` para requisições `GET` e `PUT`.
|
||||
* Se não é validado, o cliente verá um útil, claro erro.
|
||||
* Verificar se existe um parâmetro de _query_ opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.
|
||||
* Se não for, o cliente verá um erro útil e claro.
|
||||
* Verificar se existe um parâmetro query opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.
|
||||
* Como o parâmetro `q` é declarado com `= None`, ele é opcional.
|
||||
* Sem o `None` ele poderia ser obrigatório (como o corpo no caso de `PUT`).
|
||||
* Sem o `None` ele seria obrigatório (como o corpo no caso de `PUT`).
|
||||
* Para requisições `PUT` para `/items/{item_id}`, lerá o corpo como JSON:
|
||||
* Verifica que tem um atributo obrigatório `name` que deve ser `str`.
|
||||
* Verifica que tem um atributo obrigatório `price` que deve ser `float`.
|
||||
* Verifica que tem an atributo opcional `is_offer`, que deve ser `bool`, se presente.
|
||||
* Tudo isso também funciona para objetos JSON profundamente aninhados.
|
||||
* Verifica que tem um atributo obrigatório `price` que tem que ser um `float`.
|
||||
* Verifica que tem um atributo opcional `is_offer`, que deve ser um `bool`, se presente.
|
||||
* Tudo isso também funcionaria para objetos JSON profundamente aninhados.
|
||||
* Converter de e para JSON automaticamente.
|
||||
* Documentar tudo com OpenAPI, que poderá ser usado por:
|
||||
* Sistemas de documentação interativos.
|
||||
@@ -409,7 +415,7 @@ Voltando ao código do exemplo anterior, **FastAPI** irá:
|
||||
|
||||
---
|
||||
|
||||
Nós apenas arranhamos a superfície, mas você já tem idéia de como tudo funciona.
|
||||
Nós apenas arranhamos a superfície, mas você já tem ideia de como tudo funciona.
|
||||
|
||||
Experimente mudar a seguinte linha:
|
||||
|
||||
@@ -437,22 +443,22 @@ Para um exemplo mais completo incluindo mais recursos, veja <a href="https://fas
|
||||
|
||||
**Alerta de Spoiler**: o tutorial - guia do usuário inclui:
|
||||
|
||||
* Declaração de **parâmetetros** de diferentes lugares como: **cabeçalhos**, **cookies**, **campos de formulários** e **arquivos**.
|
||||
* Como configurar **Limitações de Validação** como `maximum_length` ou `regex`.
|
||||
* Um poderoso e fácil de usar sistema de **<abbr title="também conhecido como componentes, recursos, fornecedores, serviços, injetáveis">Injeção de Dependência</abbr>**.
|
||||
* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação **JWT tokens** e **HTTP Basic**.
|
||||
* Declaração de **parâmetros** de diferentes lugares como: **cabeçalhos**, **cookies**, **campos de formulários** e **arquivos**.
|
||||
* Como configurar **limitações de validação** como `maximum_length` ou `regex`.
|
||||
* Um poderoso e fácil de usar sistema de **<abbr title="também conhecido como components, resources, providers, services, injectables">Injeção de Dependência</abbr>**.
|
||||
* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação com **JWT tokens** e **HTTP Basic**.
|
||||
* Técnicas mais avançadas (mas igualmente fáceis) para declaração de **modelos JSON profundamente aninhados** (graças ao Pydantic).
|
||||
* Integrações **GraphQL** com o <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> e outras bibliotecas.
|
||||
* Muitos recursos extras (graças ao Starlette) como:
|
||||
* **WebSockets**
|
||||
* testes extrememamente fáceis baseados em HTTPX e `pytest`
|
||||
* testes extremamente fáceis baseados em HTTPX e `pytest`
|
||||
* **CORS**
|
||||
* **Cookie Sessions**
|
||||
* ...e mais.
|
||||
|
||||
### Implemente sua aplicação (opcional) { #deploy-your-app-optional }
|
||||
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, inscreva-se na lista de espera se ainda não o fez. 🚀
|
||||
Você pode opcionalmente implantar sua aplicação FastAPI na <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, vá e entre na lista de espera se ainda não o fez. 🚀
|
||||
|
||||
Se você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode implantar sua aplicação com um único comando.
|
||||
|
||||
@@ -506,7 +512,7 @@ Siga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI c
|
||||
|
||||
Testes de performance da _Independent TechEmpower_ mostram aplicações **FastAPI** rodando sob Uvicorn como <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">um dos _frameworks_ Python mais rápidos disponíveis</a>, somente atrás de Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*)
|
||||
|
||||
Para entender mais sobre performance, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
|
||||
Para entender mais sobre isso, veja a seção <a href="https://fastapi.tiangolo.com/pt/benchmarks/" class="internal-link" target="_blank">Comparações</a>.
|
||||
|
||||
## Dependências { #dependencies }
|
||||
|
||||
@@ -514,7 +520,7 @@ O FastAPI depende do Pydantic e do Starlette.
|
||||
|
||||
### Dependências `standard` { #standard-dependencies }
|
||||
|
||||
Quando você instala o FastAPI com `pip install "fastapi[standard]"`, ele vêm com o grupo `standard` (padrão) de dependências opcionais:
|
||||
Quando você instala o FastAPI com `pip install "fastapi[standard]"`, ele vem com o grupo `standard` de dependências opcionais:
|
||||
|
||||
Utilizado pelo Pydantic:
|
||||
|
||||
@@ -524,7 +530,7 @@ Utilizado pelo Starlette:
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obrigatório caso você queira utilizar o `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Obrigatório se você quer utilizar a configuração padrão de templates.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obrigatório se você deseja suporte a <abbr title="converting the string that comes from an HTTP request into Python data - convertendo a string que vem de uma requisição HTTP em dados Python">"parsing"</abbr> de formulário, com `request.form()`.
|
||||
|
||||
Utilizado pelo FastAPI:
|
||||
|
||||
@@ -547,7 +553,7 @@ Existem algumas dependências adicionais que você pode querer instalar.
|
||||
Dependências opcionais adicionais do Pydantic:
|
||||
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - para gerenciamento de configurações.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - tipos extras para serem utilizados com o Pydantic.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - para tipos extras a serem utilizados com o Pydantic.
|
||||
|
||||
Dependências opcionais adicionais do FastAPI:
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Digamos que você tenha uma estrutura de arquivos como esta:
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Existem vários arquivos `__init__.py` presentes em cada diretório ou subdiretório.
|
||||
Existem vários arquivos `__init__.py`: um em cada diretório ou subdiretório.
|
||||
|
||||
Isso permite a importação de código de um arquivo para outro.
|
||||
|
||||
@@ -43,32 +43,32 @@ from app.routers import items
|
||||
|
||||
///
|
||||
|
||||
* O diretório `app` contém todo o código da aplicação. Ele possui um arquivo `app/__init__.py` vazio, o que o torna um "pacote Python" (uma coleção de "módulos Python"): `app`.
|
||||
* Dentro dele, o arquivo `app/main.py` está localizado em um pacote Python (diretório com `__init__.py`). Portanto, ele é um "módulo" desse pacote: `app.main`.
|
||||
* Existem também um arquivo `app/dependencies.py`, assim como o `app/main.py`, ele é um "módulo": `app.dependencies`.
|
||||
* O diretório `app` contém tudo. E possui um arquivo vazio `app/__init__.py`, então ele é um "pacote Python" (uma coleção de "módulos Python"): `app`.
|
||||
* Ele contém um arquivo `app/main.py`. Como está dentro de um pacote Python (um diretório com um arquivo `__init__.py`), ele é um "módulo" desse pacote: `app.main`.
|
||||
* Existe também um arquivo `app/dependencies.py`, assim como `app/main.py`, ele é um "módulo": `app.dependencies`.
|
||||
* Há um subdiretório `app/routers/` com outro arquivo `__init__.py`, então ele é um "subpacote Python": `app.routers`.
|
||||
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto, é um "submódulo": `app.routers.items`.
|
||||
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
|
||||
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python":`app.internal`.
|
||||
* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto é um submódulo: `app.routers.items`.
|
||||
* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.
|
||||
* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro "subpacote Python": `app.internal`.
|
||||
* E o arquivo `app/internal/admin.py` é outro submódulo: `app.internal.admin`.
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
A mesma estrutura de arquivos com comentários:
|
||||
|
||||
```
|
||||
```bash
|
||||
.
|
||||
├── app # "app" é um pacote Python
|
||||
│ ├── __init__.py # este arquivo torna "app" um "pacote Python"
|
||||
│ ├── main.py # "main" módulo, e.g. import app.main
|
||||
│ ├── dependencies.py # "dependencies" módulo, e.g. import app.dependencies
|
||||
│ └── routers # "routers" é um "subpacote Python"
|
||||
│ │ ├── __init__.py # torna "routers" um "subpacote Python"
|
||||
│ │ ├── items.py # "items" submódulo, e.g. import app.routers.items
|
||||
│ │ └── users.py # "users" submódulo, e.g. import app.routers.users
|
||||
│ └── internal # "internal" é um "subpacote Python"
|
||||
│ ├── __init__.py # torna "internal" um "subpacote Python"
|
||||
│ └── admin.py # "admin" submódulo, e.g. import app.internal.admin
|
||||
├── app # "app" is a Python package
|
||||
│ ├── __init__.py # this file makes "app" a "Python package"
|
||||
│ ├── main.py # "main" module, e.g. import app.main
|
||||
│ ├── dependencies.py # "dependencies" module, e.g. import app.dependencies
|
||||
│ └── routers # "routers" is a "Python subpackage"
|
||||
│ │ ├── __init__.py # makes "routers" a "Python subpackage"
|
||||
│ │ ├── items.py # "items" submodule, e.g. import app.routers.items
|
||||
│ │ └── users.py # "users" submodule, e.g. import app.routers.users
|
||||
│ └── internal # "internal" is a "Python subpackage"
|
||||
│ ├── __init__.py # makes "internal" a "Python subpackage"
|
||||
│ └── admin.py # "admin" submodule, e.g. import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
@@ -79,11 +79,11 @@ Você quer manter as *operações de rota* relacionadas aos seus usuários separ
|
||||
|
||||
Mas ele ainda faz parte da mesma aplicação/web API **FastAPI** (faz parte do mesmo "pacote Python").
|
||||
|
||||
Você pode criar as *operações de rotas* para esse módulo usando o `APIRouter`.
|
||||
Você pode criar as *operações de rota* para esse módulo usando o `APIRouter`.
|
||||
|
||||
### Importe `APIRouter` { #import-apirouter }
|
||||
|
||||
você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
|
||||
Você o importa e cria uma "instância" da mesma maneira que faria com a classe `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
@@ -91,7 +91,7 @@ você o importa e cria uma "instância" da mesma maneira que faria com a classe
|
||||
|
||||
E então você o utiliza para declarar suas *operações de rota*.
|
||||
|
||||
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
|
||||
Utilize-o da mesma maneira que utilizaria a classe `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
@@ -151,7 +151,7 @@ Então, em vez de adicionar tudo isso a cada *operação de rota*, podemos adici
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
Como o caminho de cada *operação de rota* deve começar com `/`, como em:
|
||||
Como o path de cada *operação de rota* tem que começar com `/`, como em:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@router.get("/{item_id}")
|
||||
@@ -163,9 +163,9 @@ async def read_item(item_id: str):
|
||||
|
||||
Então, o prefixo neste caso é `/items`.
|
||||
|
||||
Também podemos adicionar uma lista de `tags` e `responses` extras que serão aplicadas a todas as *operações de rota* incluídas neste roteador.
|
||||
Também podemos adicionar uma list de `tags` e `responses` extras que serão aplicadas a todas as *operações de rota* incluídas neste router.
|
||||
|
||||
E podemos adicionar uma lista de `dependencies` que serão adicionadas a todas as *operações de rota* no roteador e serão executadas/resolvidas para cada request feita a elas.
|
||||
E podemos adicionar uma list de `dependencies` que serão adicionadas a todas as *operações de rota* no router e serão executadas/resolvidas para cada request feita a elas.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -173,7 +173,7 @@ Observe que, assim como [dependências em *decoradores de operação de rota*](d
|
||||
|
||||
///
|
||||
|
||||
O resultado final é que os caminhos dos itens agora são:
|
||||
O resultado final é que os paths dos itens agora são:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
@@ -183,9 +183,9 @@ O resultado final é que os caminhos dos itens agora são:
|
||||
* Elas serão marcadas com uma lista de tags que contêm uma única string `"items"`.
|
||||
* Essas "tags" são especialmente úteis para os sistemas de documentação interativa automática (usando OpenAPI).
|
||||
* Todas elas incluirão as `responses` predefinidas.
|
||||
* Todas essas *operações de rota* terão a lista de `dependencies` avaliada/executada antes delas.
|
||||
* Todas essas *operações de rota* terão a list de `dependencies` avaliada/executada antes delas.
|
||||
* Se você também declarar dependências em uma *operação de rota* específica, **elas também serão executadas**.
|
||||
* As dependências do roteador são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} e, em seguida, as dependências de parâmetros normais.
|
||||
* As dependências do router são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} e, em seguida, as dependências de parâmetros normais.
|
||||
* Você também pode adicionar [dependências de `Segurança` com `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Dica
|
||||
@@ -246,7 +246,7 @@ from ..dependencies import get_token_header
|
||||
|
||||
significa:
|
||||
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) reside (o diretório `app/routers/`)...
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) vive (o diretório `app/routers/`)...
|
||||
* vá para o pacote pai (o diretório `app/`)...
|
||||
* e lá, encontre o módulo `dependencies` (o arquivo em `app/dependencies.py`)...
|
||||
* e dele, importe a função `get_token_header`.
|
||||
@@ -283,9 +283,9 @@ Mas ainda podemos adicionar _mais_ `tags` que serão aplicadas a uma *operação
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Esta última operação de caminho terá a combinação de tags: `["items", "custom"]`.
|
||||
Esta última operação de rota terá a combinação de tags: `["items", "custom"]`.
|
||||
|
||||
E também terá ambas as respostas na documentação, uma para `404` e uma para `403`.
|
||||
E também terá ambas as responses na documentação, uma para `404` e uma para `403`.
|
||||
|
||||
///
|
||||
|
||||
@@ -325,7 +325,7 @@ from .routers import items, users
|
||||
|
||||
significa:
|
||||
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/main.py`) reside (o diretório `app/`)...
|
||||
* Começando no mesmo pacote em que este módulo (o arquivo `app/main.py`) vive (o diretório `app/`)...
|
||||
* procure o subpacote `routers` (o diretório em `app/routers/`)...
|
||||
* e dele, importe o submódulo `items` (o arquivo em `app/routers/items.py`) e `users` (o arquivo em `app/routers/users.py`)...
|
||||
|
||||
@@ -376,7 +376,7 @@ Então, para poder usar ambos no mesmo arquivo, importamos os submódulos direta
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### Inclua os `APIRouter`s para `usuários` e `itens` { #include-the-apirouters-for-users-and-items }
|
||||
### Inclua os `APIRouter`s para `users` e `items` { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
Agora, vamos incluir os `router`s dos submódulos `users` e `items`:
|
||||
|
||||
@@ -392,7 +392,7 @@ E `items.router` contém o `APIRouter` dentro do arquivo `app/routers/items.py`.
|
||||
|
||||
Com `app.include_router()` podemos adicionar cada `APIRouter` ao aplicativo principal `FastAPI`.
|
||||
|
||||
Ele incluirá todas as rotas daquele roteador como parte dele.
|
||||
Ele incluirá todas as rotas daquele router como parte dele.
|
||||
|
||||
/// note | Detalhes Técnicos
|
||||
|
||||
@@ -404,7 +404,7 @@ Então, nos bastidores, ele realmente funcionará como se tudo fosse o mesmo apl
|
||||
|
||||
/// check | Verifique
|
||||
|
||||
Você não precisa se preocupar com desempenho ao incluir roteadores.
|
||||
Você não precisa se preocupar com desempenho ao incluir routers.
|
||||
|
||||
Isso levará microssegundos e só acontecerá na inicialização.
|
||||
|
||||
@@ -453,7 +453,7 @@ e funcionará corretamente, junto com todas as outras *operações de rota* adic
|
||||
|
||||
/// note | Detalhes Técnicos Avançados
|
||||
|
||||
**Observação**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
|
||||
**Nota**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.
|
||||
|
||||
---
|
||||
|
||||
@@ -479,15 +479,15 @@ $ fastapi dev app/main.py
|
||||
|
||||
</div>
|
||||
|
||||
E abra os documentos em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
E abra a documentação em <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Você verá a documentação automática da API, incluindo os caminhos de todos os submódulos, usando os caminhos (e prefixos) corretos e as tags corretas:
|
||||
Você verá a documentação automática da API, incluindo os paths de todos os submódulos, usando os paths (e prefixos) corretos e as tags corretas:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
## Inclua o mesmo roteador várias vezes com `prefix` diferentes { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
## Inclua o mesmo router várias vezes com `prefix` diferentes { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
|
||||
Você também pode usar `.include_router()` várias vezes com o *mesmo* roteador usando prefixos diferentes.
|
||||
Você também pode usar `.include_router()` várias vezes com o *mesmo* router usando prefixos diferentes.
|
||||
|
||||
Isso pode ser útil, por exemplo, para expor a mesma API sob prefixos diferentes, por exemplo, `/api/v1` e `/api/latest`.
|
||||
|
||||
@@ -495,10 +495,10 @@ Esse é um uso avançado que você pode não precisar, mas está lá caso precis
|
||||
|
||||
## Inclua um `APIRouter` em outro { #include-an-apirouter-in-another }
|
||||
|
||||
Da mesma forma que você pode incluir um `APIRouter` em um aplicativo `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
|
||||
Da mesma forma que você pode incluir um `APIRouter` em uma aplicação `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:
|
||||
|
||||
```Python
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
Certifique-se de fazer isso antes de incluir `router` no aplicativo `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
|
||||
Certifique-se de fazer isso antes de incluir `router` na aplicação `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Corpo - Atualizações { #body-updates }
|
||||
|
||||
## Atualização de dados existentes com `PUT` { #update-replacing-with-put }
|
||||
## Atualização substituindo com `PUT` { #update-replacing-with-put }
|
||||
|
||||
Para atualizar um item, você pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
|
||||
|
||||
@@ -22,13 +22,13 @@ Isso significa que, se você quiser atualizar o item `bar` usando `PUT` com um c
|
||||
}
|
||||
```
|
||||
|
||||
Como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
|
||||
como ele não inclui o atributo já armazenado `"tax": 20.2`, o modelo de entrada assumiria o valor padrão de `"tax": 10.5`.
|
||||
|
||||
E os dados seriam salvos com esse "novo" `tax` de `10.5`.
|
||||
|
||||
## Atualizações parciais com `PATCH` { #partial-updates-with-patch }
|
||||
|
||||
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar parcialmente os dados.
|
||||
Você também pode usar a operação <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> para atualizar dados *parcialmente*.
|
||||
|
||||
Isso significa que você pode enviar apenas os dados que deseja atualizar, deixando o restante intacto.
|
||||
|
||||
@@ -40,25 +40,17 @@ E muitas equipes usam apenas `PUT`, mesmo para atualizações parciais.
|
||||
|
||||
Você é **livre** para usá-los como preferir, **FastAPI** não impõe restrições.
|
||||
|
||||
Mas este guia te dá uma ideia de como eles são destinados a serem usados.
|
||||
Mas este guia mostra, mais ou menos, como eles são destinados a serem usados.
|
||||
|
||||
///
|
||||
|
||||
### Usando o parâmetro `exclude_unset` do Pydantic { #using-pydantics-exclude-unset-parameter }
|
||||
|
||||
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no método `.model_dump()` do modelo do Pydantic.
|
||||
Se você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no `.model_dump()` do modelo do Pydantic.
|
||||
|
||||
Como `item.model_dump(exclude_unset=True)`.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método que era chamado `.dict()` e foi descontinuado (mas ainda suportado) no Pydantic v2. Agora, deve-se usar o método `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` a partir do Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Isso gera um `dict` com apenas os dados definidos ao criar o modelo `item`, excluindo os valores padrão.
|
||||
Isso geraria um `dict` com apenas os dados que foram definidos ao criar o modelo `item`, excluindo os valores padrão.
|
||||
|
||||
Então, você pode usar isso para gerar um `dict` com apenas os dados definidos (enviados na solicitação), omitindo valores padrão:
|
||||
|
||||
@@ -68,31 +60,23 @@ Então, você pode usar isso para gerar um `dict` com apenas os dados definidos
|
||||
|
||||
Agora, você pode criar uma cópia do modelo existente usando `.model_copy()`, e passar o parâmetro `update` com um `dict` contendo os dados para atualizar.
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método era chamado `.copy()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2, e renomeado para `.model_copy()`.
|
||||
|
||||
Os exemplos aqui usam `.copy()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_copy()` com o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Como `stored_item_model.model_copy(update=update_data)`:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
|
||||
### Recapitulando as atualizações parciais { #partial-updates-recap }
|
||||
|
||||
Resumindo, para aplicar atualizações parciais você pode:
|
||||
Resumindo, para aplicar atualizações parciais você deveria:
|
||||
|
||||
* (Opcionalmente) usar `PATCH` em vez de `PUT`.
|
||||
* Recuperar os dados armazenados.
|
||||
* Colocar esses dados em um modelo do Pydantic.
|
||||
* Gerar um `dict` sem valores padrão a partir do modelo de entrada (usando `exclude_unset`).
|
||||
* Dessa forma, você pode atualizar apenas os valores definidos pelo usuário, em vez de substituir os valores já armazenados com valores padrão em seu modelo.
|
||||
* Dessa forma, você pode atualizar apenas os valores realmente definidos pelo usuário, em vez de substituir valores já armazenados por valores padrão do modelo.
|
||||
* Criar uma cópia do modelo armazenado, atualizando seus atributos com as atualizações parciais recebidas (usando o parâmetro `update`).
|
||||
* Converter o modelo copiado em algo que possa ser armazenado no seu banco de dados (por exemplo, usando o `jsonable_encoder`).
|
||||
* Isso é comparável ao uso do método `.model_dump()`, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.
|
||||
* Salvar os dados no seu banco de dados.
|
||||
* Converter o modelo copiado em algo que possa ser armazenado no seu BD (por exemplo, usando o `jsonable_encoder`).
|
||||
* Isso é comparável a usar o método `.model_dump()` do modelo novamente, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.
|
||||
* Salvar os dados no seu BD.
|
||||
* Retornar o modelo atualizado.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
|
||||
@@ -109,8 +93,8 @@ Mas o exemplo aqui usa `PATCH` porque foi criado para esses casos de uso.
|
||||
|
||||
Observe que o modelo de entrada ainda é validado.
|
||||
|
||||
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, precisará ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
|
||||
Portanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, você precisa ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).
|
||||
|
||||
Para distinguir os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md){.internal-link target=_blank}.
|
||||
Para distinguir entre os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
@@ -10,11 +10,11 @@ Para declarar um corpo da **requisição**, você utiliza os modelos do <a href=
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Para enviar dados, você deve usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||
Para enviar dados, você deveria usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.
|
||||
|
||||
Enviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos.
|
||||
|
||||
Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição para um `GET`, e proxies que intermediarem podem não suportar o corpo da requisição.
|
||||
Como é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição ao usar `GET`, e proxies intermediários podem não suportá-lo.
|
||||
|
||||
///
|
||||
|
||||
@@ -32,7 +32,8 @@ Utilize os tipos Python padrão para todos os atributos:
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele se torna opcional. Caso contrário, se torna obrigatório. Use `None` para torná-lo opcional.
|
||||
|
||||
Assim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele não é obrigatório. Caso contrário, é obrigatório. Use `None` para torná-lo apenas opcional.
|
||||
|
||||
Por exemplo, o modelo acima declara um JSON "`object`" (ou `dict` no Python) como esse:
|
||||
|
||||
@@ -66,7 +67,7 @@ Para adicioná-lo à sua *operação de rota*, declare-o da mesma maneira que vo
|
||||
|
||||
Apenas com essa declaração de tipos do Python, o **FastAPI** irá:
|
||||
|
||||
* Ler o corpo da requisição como um JSON.
|
||||
* Ler o corpo da requisição como JSON.
|
||||
* Converter os tipos correspondentes (se necessário).
|
||||
* Validar os dados.
|
||||
* Se algum dado for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que estava incorreto.
|
||||
@@ -127,14 +128,6 @@ Dentro da função, você pode acessar todos os atributos do objeto do modelo di
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2, e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
## Corpo da requisição + parâmetros de rota { #request-body-path-parameters }
|
||||
|
||||
Você pode declarar parâmetros de rota e corpo da requisição ao mesmo tempo.
|
||||
@@ -143,6 +136,7 @@ O **FastAPI** irá reconhecer que os parâmetros da função que combinam com pa
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
|
||||
## Corpo da requisição + parâmetros de rota + parâmetros de consulta { #request-body-path-query-parameters }
|
||||
|
||||
Você também pode declarar parâmetros de **corpo**, **rota** e **consulta**, ao mesmo tempo.
|
||||
|
||||
@@ -22,21 +22,13 @@ Aqui está uma ideia geral de como os modelos poderiam parecer com seus campos d
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
|
||||
/// info | Informação
|
||||
### Sobre `**user_in.model_dump()` { #about-user-in-model-dump }
|
||||
|
||||
No Pydantic v1 o método se chamava `.dict()`, ele foi descontinuado (mas ainda é suportado) no Pydantic v2 e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` por compatibilidade com o Pydantic v1, mas você deve usar `.model_dump()` se puder usar o Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
### Sobre `**user_in.dict()` { #about-user-in-dict }
|
||||
|
||||
#### O `.dict()` do Pydantic { #pydantics-dict }
|
||||
#### O `.model_dump()` do Pydantic { #pydantics-model-dump }
|
||||
|
||||
`user_in` é um modelo Pydantic da classe `UserIn`.
|
||||
|
||||
Os modelos Pydantic possuem um método `.dict()` que retorna um `dict` com os dados do modelo.
|
||||
Os modelos Pydantic possuem um método `.model_dump()` que retorna um `dict` com os dados do modelo.
|
||||
|
||||
Então, se criarmos um objeto Pydantic `user_in` como:
|
||||
|
||||
@@ -47,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
|
||||
e depois chamarmos:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
```
|
||||
|
||||
agora temos um `dict` com os dados na variável `user_dict` (é um `dict` em vez de um objeto de modelo Pydantic).
|
||||
@@ -103,20 +95,20 @@ UserInDB(
|
||||
|
||||
#### Um modelo Pydantic a partir do conteúdo de outro { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.dict()`, este código:
|
||||
Como no exemplo acima, obtivemos o `user_dict` a partir do `user_in.model_dump()`, este código:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
seria equivalente a:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict())
|
||||
UserInDB(**user_in.model_dump())
|
||||
```
|
||||
|
||||
...porque `user_in.dict()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
|
||||
...porque `user_in.model_dump()` é um `dict`, e depois fazemos o Python "desembrulhá-lo" passando-o para `UserInDB` precedido por `**`.
|
||||
|
||||
Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
|
||||
|
||||
@@ -125,7 +117,7 @@ Então, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.
|
||||
E, então, adicionando o argumento de palavra-chave extra `hashed_password=hashed_password`, como em:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
...acaba sendo como:
|
||||
|
||||
@@ -33,7 +33,7 @@ Para isso, primeiro importe:
|
||||
|
||||
O FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.
|
||||
|
||||
Se você tiver uma versão mais antiga, terá erros ao tentar usar `Annotated`.
|
||||
Se você tiver uma versão mais antiga, teria erros ao tentar usar `Annotated`.
|
||||
|
||||
Certifique-se de [Atualizar a versão do FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} para pelo menos 0.95.1 antes de usar `Annotated`.
|
||||
|
||||
@@ -109,7 +109,7 @@ Agora o FastAPI vai:
|
||||
|
||||
## Alternativa (antiga): `Query` como valor padrão { #alternative-old-query-as-the-default-value }
|
||||
|
||||
Versões anteriores do FastAPI (antes de <abbr title="antes de 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`. É muito provável que você veja código assim por aí, então vou te explicar.
|
||||
Versões anteriores do FastAPI (antes de <abbr title="before 2023-03 - antes de 2023-03">0.95.0</abbr>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`, há uma grande chance de você ver código usando isso por aí, então vou explicar.
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
@@ -192,7 +192,7 @@ Você também pode adicionar um parâmetro `min_length`:
|
||||
|
||||
## Adicione expressões regulares { #add-regular-expressions }
|
||||
|
||||
Você pode definir um `pattern` de <abbr title="Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</abbr> que o parâmetro deve corresponder:
|
||||
Você pode definir um `pattern` de <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings. - Uma expressão regular, regex ou regexp é uma sequência de caracteres que define um padrão de busca para strings.">expressão regular</abbr> que o parâmetro deve corresponder:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
@@ -206,20 +206,6 @@ Se você se sentir perdido com essas ideias de **"expressão regular"**, não se
|
||||
|
||||
Agora você sabe que, sempre que precisar delas, pode usá-las no **FastAPI**.
|
||||
|
||||
### Pydantic v1 `regex` em vez de `pattern` { #pydantic-v1-regex-instead-of-pattern }
|
||||
|
||||
Antes da versão 2 do Pydantic e antes do FastAPI 0.100.0, o parâmetro se chamava `regex` em vez de `pattern`, mas agora está descontinuado.
|
||||
|
||||
Você ainda pode ver algum código usando isso:
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
|
||||
|
||||
////
|
||||
|
||||
Mas saiba que isso está descontinuado e deve ser atualizado para usar o novo parâmetro `pattern`. 🤓
|
||||
|
||||
## Valores padrão { #default-values }
|
||||
|
||||
Você pode, claro, usar valores padrão diferentes de `None`.
|
||||
@@ -280,7 +266,7 @@ Então, com uma URL como:
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
você receberá os múltiplos valores do *parâmetro de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
|
||||
você receberia os múltiplos valores dos *parâmetros de consulta* `q` (`foo` e `bar`) em uma `list` Python dentro da sua *função de operação de rota*, no *parâmetro da função* `q`.
|
||||
|
||||
Assim, a resposta para essa URL seria:
|
||||
|
||||
@@ -350,7 +336,7 @@ Essas informações serão incluídas no OpenAPI gerado e usadas pelas interface
|
||||
|
||||
Tenha em mente que ferramentas diferentes podem ter níveis diferentes de suporte ao OpenAPI.
|
||||
|
||||
Algumas delas podem ainda não mostrar todas as informações extras declaradas, embora na maioria dos casos o recurso ausente já esteja planejado para desenvolvimento.
|
||||
Algumas delas podem ainda não mostrar todas as informações extras declaradas, embora na maioria dos casos a funcionalidade ausente já esteja planejada para desenvolvimento.
|
||||
|
||||
///
|
||||
|
||||
@@ -386,7 +372,7 @@ Então você pode declarar um `alias`, e esse alias será usado para encontrar o
|
||||
|
||||
Agora digamos que você não gosta mais desse parâmetro.
|
||||
|
||||
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsoleto, recomenda-se não usá-lo">descontinuado</abbr>.
|
||||
Você tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <abbr title="obsolete, recommended not to use it - obsoleto, recomenda-se não usá-lo">deprecated</abbr>.
|
||||
|
||||
Então passe o parâmetro `deprecated=True` para `Query`:
|
||||
|
||||
@@ -416,7 +402,7 @@ O Pydantic também tem <a href="https://docs.pydantic.dev/latest/concepts/valida
|
||||
|
||||
///
|
||||
|
||||
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
|
||||
Por exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title="ISBN means International Standard Book Number - ISBN significa Número Padrão Internacional de Livro">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title="IMDB (Internet Movie Database) is a website with information about movies - IMDB (Internet Movie Database) é um site com informações sobre filmes">IMDB</abbr>:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -428,7 +414,7 @@ Isso está disponível com a versão 2 do Pydantic ou superior. 😎
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deve usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
|
||||
Se você precisar fazer qualquer tipo de validação que exija comunicação com algum **componente externo**, como um banco de dados ou outra API, você deveria usar **Dependências do FastAPI** em vez disso; você aprenderá sobre elas mais adiante.
|
||||
|
||||
Esses validadores personalizados são para coisas que podem ser verificadas **apenas** com os **mesmos dados** fornecidos na requisição.
|
||||
|
||||
@@ -440,7 +426,7 @@ O ponto importante é apenas usar **`AfterValidator` com uma função dentro de
|
||||
|
||||
---
|
||||
|
||||
Mas se você está curioso sobre este exemplo específico e ainda entretido, aqui vão alguns detalhes extras.
|
||||
Mas se você estiver curioso sobre este exemplo de código específico e ainda entretido, aqui vão alguns detalhes extras.
|
||||
|
||||
#### String com `value.startswith()` { #string-with-value-startswith }
|
||||
|
||||
@@ -450,7 +436,7 @@ Percebeu? Uma string usando `value.startswith()` pode receber uma tupla, e verif
|
||||
|
||||
#### Um item aleatório { #a-random-item }
|
||||
|
||||
Com `data.items()` obtemos um <abbr title="Algo que podemos iterar com um laço for, como uma list, set, etc.">objeto iterável</abbr> com tuplas contendo a chave e o valor de cada item do dicionário.
|
||||
Com `data.items()` obtemos um <abbr title="Something we can iterate on with a for loop, like a list, set, etc. - Algo que podemos iterar com um laço for, como uma list, set, etc.">objeto iterável</abbr> com tuplas contendo a chave e o valor de cada item do dicionário.
|
||||
|
||||
Convertimos esse objeto iterável em uma `list` adequada com `list(data.items())`.
|
||||
|
||||
|
||||
@@ -252,20 +252,6 @@ Então, se você enviar uma solicitação para essa *operação de rota* para o
|
||||
|
||||
/// info | Informação
|
||||
|
||||
No Pydantic v1, o método era chamado `.dict()`, ele foi descontinuado (mas ainda suportado) no Pydantic v2 e renomeado para `.model_dump()`.
|
||||
|
||||
Os exemplos aqui usam `.dict()` para compatibilidade com Pydantic v1, mas você deve usar `.model_dump()` em vez disso se puder usar Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
|
||||
O FastAPI usa `.dict()` do modelo Pydantic com <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">seu parâmetro `exclude_unset`</a> para chegar a isso.
|
||||
|
||||
///
|
||||
|
||||
/// info | Informação
|
||||
|
||||
Você também pode usar:
|
||||
|
||||
* `response_model_exclude_defaults=True`
|
||||
|
||||
@@ -8,39 +8,17 @@ Aqui estão várias maneiras de fazer isso.
|
||||
|
||||
Você pode declarar `examples` para um modelo Pydantic que serão adicionados ao JSON Schema gerado.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
|
||||
|
||||
////
|
||||
|
||||
Essas informações extras serão adicionadas como estão ao **JSON Schema** de saída para esse modelo e serão usadas na documentação da API.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
Na versão 2 do Pydantic, você usaria o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
|
||||
Você pode usar o atributo `model_config`, que recebe um `dict`, conforme descrito na <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">documentação do Pydantic: Configuration</a>.
|
||||
|
||||
Você pode definir `"json_schema_extra"` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
Na versão 1 do Pydantic, você usaria uma classe interna `Config` e `schema_extra`, conforme descrito na <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">documentação do Pydantic: Schema customization</a>.
|
||||
|
||||
Você pode definir `schema_extra` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.
|
||||
|
||||
////
|
||||
|
||||
/// tip | Dica
|
||||
|
||||
Você pode usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
|
||||
Você poderia usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.
|
||||
|
||||
Por exemplo, você poderia usá-la para adicionar metadados para uma interface de usuário de front-end, etc.
|
||||
|
||||
@@ -50,7 +28,7 @@ Por exemplo, você poderia usá-la para adicionar metadados para uma interface d
|
||||
|
||||
O OpenAPI 3.1.0 (usado desde o FastAPI 0.99.0) adicionou suporte a `examples`, que faz parte do padrão **JSON Schema**.
|
||||
|
||||
Antes disso, ele suportava apenas a palavra‑chave `example` com um único exemplo. Isso ainda é suportado pelo OpenAPI 3.1.0, mas é descontinuado e não faz parte do padrão JSON Schema. Portanto, é recomendado migrar de `example` para `examples`. 🤓
|
||||
Antes disso, ele suportava apenas a palavra‑chave `example` com um único exemplo. Isso ainda é suportado pelo OpenAPI 3.1.0, mas é descontinuado e não faz parte do padrão JSON Schema. Portanto, você é incentivado a migrar de `example` para `examples`. 🤓
|
||||
|
||||
Você pode ler mais no final desta página.
|
||||
|
||||
@@ -102,7 +80,7 @@ No entanto, <abbr title="2023-08-26">no momento em que isto foi escrito</abbr>,
|
||||
|
||||
Antes do **JSON Schema** suportar `examples`, o OpenAPI já tinha suporte para um campo diferente também chamado `examples`.
|
||||
|
||||
Esse `examples` específico do OpenAPI vai em outra seção da especificação. Ele fica nos **detalhes de cada função de operação de rota**, não dentro de cada JSON Schema.
|
||||
Esse `examples` **específico do OpenAPI** vai em outra seção da especificação OpenAPI. Ele fica nos **detalhes de cada *operação de rota***, não dentro de cada JSON Schema.
|
||||
|
||||
E o Swagger UI tem suportado esse campo `examples` particular há algum tempo. Então, você pode usá-lo para **mostrar** diferentes **exemplos na UI da documentação**.
|
||||
|
||||
@@ -189,9 +167,9 @@ Depois, o JSON Schema adicionou um campo <a href="https://json-schema.org/draft/
|
||||
|
||||
E então o novo OpenAPI 3.1.0 passou a se basear na versão mais recente (JSON Schema 2020-12), que incluiu esse novo campo `examples`.
|
||||
|
||||
Agora, esse novo campo `examples` tem precedência sobre o antigo (e customizado) campo único `example`, que agora está descontinuado.
|
||||
E agora esse novo campo `examples` tem precedência sobre o antigo campo único (e customizado) `example`, que agora está descontinuado.
|
||||
|
||||
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um `dict` com metadados extras como nos outros lugares do OpenAPI (descritos acima).
|
||||
Esse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um dict com metadados extras como nos outros lugares do OpenAPI (descritos acima).
|
||||
|
||||
/// info | Informação
|
||||
|
||||
@@ -213,7 +191,7 @@ Mas agora que o FastAPI 0.99.0 e superiores usam o OpenAPI 3.1.0, que usa o JSON
|
||||
|
||||
### Swagger UI e `examples` específicos do OpenAPI { #swagger-ui-and-openapi-specific-examples }
|
||||
|
||||
Como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
|
||||
Agora, como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.
|
||||
|
||||
Para resolver isso, o FastAPI `0.103.0` **adicionou suporte** para declarar o mesmo antigo campo **específico do OpenAPI** `examples` com o novo parâmetro `openapi_examples`. 🤓
|
||||
|
||||
|
||||
@@ -10,6 +10,26 @@ Keep existing translations as they are if the term is already translated.
|
||||
|
||||
When translating documentation into Portuguese, use neutral and widely understandable language. Although Portuguese originated in Portugal and has its largest number of speakers in Brazil, it is also an official language in several countries and regions, such as Equatorial Guinea, Mozambique, Angola, Cape Verde, and São Tomé and Príncipe. Avoid words or expressions that are specific to a single country or region.
|
||||
|
||||
Only keep parentheses if they exist in the source text. Do not add parentheses to terms that do not have them.
|
||||
|
||||
### Avoiding Repetition in Translation
|
||||
|
||||
When translating sentences, avoid unnecessary repetition of words or phrases that are implied in context.
|
||||
- Merge repeated words naturally while keeping the meaning.
|
||||
- Do **not** introduce extra words to replace repeated phrases unnecessarily.
|
||||
- Keep translations fluent and concise, but maintain the original meaning.
|
||||
|
||||
**Example:**
|
||||
|
||||
Source:
|
||||
Let's see how that works and how to change it if you need to do that.
|
||||
|
||||
Avoid translating literally as:
|
||||
Vamos ver como isso funciona e como alterar isso se você precisar fazer isso.
|
||||
|
||||
Better translation:
|
||||
Vamos ver como isso funciona e como alterar se você precisar.
|
||||
|
||||
---
|
||||
|
||||
For the next terms, use the following translations:
|
||||
@@ -22,10 +42,11 @@ For the next terms, use the following translations:
|
||||
* /// note: /// note | Nota
|
||||
* /// tip: /// tip | Dica
|
||||
* /// warning: /// warning | Atenção
|
||||
* (you should): (você deveria)
|
||||
* you should: você deveria
|
||||
* async context manager: gerenciador de contexto assíncrono
|
||||
* autocomplete: autocompletar
|
||||
* autocompletion: preenchimento automático
|
||||
* auto-completion: preenchimento automático
|
||||
* bug: bug
|
||||
* context manager: gerenciador de contexto
|
||||
* cross domain: cross domain (do not translate to "domínio cruzado")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Тестовый файл LLM { #llm-test-file }
|
||||
|
||||
Этот документ проверяет, понимает ли <abbr title="Large Language Model – Большая языковая модель">LLM</abbr>, переводящая документацию, `general_prompt` в `scripts/translate.py` и языковой специфичный промпт в `docs/{language code}/llm-prompt.md`. Языковой специфичный промпт добавляется к `general_prompt`.
|
||||
Этот документ проверяет, понимает ли <abbr title="Large Language Model - Большая языковая модель">LLM</abbr>, переводящая документацию, `general_prompt` в `scripts/translate.py` и языковой специфичный промпт в `docs/{language code}/llm-prompt.md`. Языковой специфичный промпт добавляется к `general_prompt`.
|
||||
|
||||
Тесты, добавленные здесь, увидят все создатели языковых промптов.
|
||||
Тесты, добавленные здесь, увидят все создатели языковых специфичных промптов.
|
||||
|
||||
Использование:
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Проверьте, всё ли в порядке в переводе.
|
||||
* При необходимости улучшите ваш языковой специфичный промпт, общий промпт или английский документ.
|
||||
* Затем вручную исправьте оставшиеся проблемы в переводе, чтобы он был хорошим.
|
||||
* Переведите заново, имея хороший перевод на месте. Идеальным результатом будет ситуация, когда LLM больше не вносит изменений в перевод. Это означает, что общий промпт и ваш языковой специфичный промпт максимально хороши (иногда он будет делать несколько, казалось бы, случайных изменений, причина в том, что <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM — недетерминированные алгоритмы</a>).
|
||||
* Переведите заново, имея хороший перевод на месте. Идеальным результатом будет ситуация, когда LLM больше не вносит изменений в перевод. Это означает, что общий промпт и ваш языковой специфичный промпт настолько хороши, насколько это возможно (иногда он будет делать несколько, казалось бы, случайных изменений, причина в том, что <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM — недетерминированные алгоритмы</a>).
|
||||
|
||||
Тесты:
|
||||
|
||||
@@ -197,10 +197,10 @@ works(foo="bar") # Это работает 🎉
|
||||
|
||||
### abbr даёт полную расшифровку { #the-abbr-gives-a-full-phrase }
|
||||
|
||||
* <abbr title="Getting Things Done – Как привести дела в порядок">GTD</abbr>
|
||||
* <abbr title="less than – меньше чем"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token – XML веб‑токен">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface – Параллельный серверный интерфейс шлюза">PSGI</abbr>
|
||||
* <abbr title="Getting Things Done - Как привести дела в порядок">GTD</abbr>
|
||||
* <abbr title="less than - меньше чем"><code>lt</code></abbr>
|
||||
* <abbr title="XML Web Token - XML веб‑токен">XWT</abbr>
|
||||
* <abbr title="Parallel Server Gateway Interface - Параллельный серверный интерфейс шлюза">PSGI</abbr>
|
||||
|
||||
### abbr даёт объяснение { #the-abbr-gives-an-explanation }
|
||||
|
||||
@@ -209,8 +209,8 @@ works(foo="bar") # Это работает 🎉
|
||||
|
||||
### abbr даёт полную расшифровку и объяснение { #the-abbr-gives-a-full-phrase-and-an-explanation }
|
||||
|
||||
* <abbr title="Mozilla Developer Network – Сеть разработчиков Mozilla: документация для разработчиков, созданная командой Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output – Ввод/Вывод: чтение или запись на диск, сетевое взаимодействие.">I/O</abbr>.
|
||||
* <abbr title="Mozilla Developer Network - Сеть разработчиков Mozilla: документация для разработчиков, созданная командой Firefox">MDN</abbr>
|
||||
* <abbr title="Input/Output - Ввод/Вывод: чтение или запись на диск, сетевое взаимодействие.">I/O</abbr>.
|
||||
|
||||
////
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
|
||||
### Использование имени функции-обработчика пути как operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
### Использование имени *функции-обработчика пути* как operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
Если вы хотите использовать имена функций ваших API в качестве `operationId`, вы можете пройти по всем из них и переопределить `operation_id` каждой *операции пути* с помощью их `APIRoute.name`.
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
## Исключить из OpenAPI { #exclude-from-openapi }
|
||||
|
||||
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматической документации), используйте параметр `include_in_schema` и установите его в `False`:
|
||||
Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматических систем документации), используйте параметр `include_in_schema` и установите его в `False`:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
Добавление `\f` (экранированного символа «form feed») заставит **FastAPI** обрезать текст, используемый для OpenAPI, в этой точке.
|
||||
|
||||
Эта часть не попадёт в документацию, но другие инструменты (например, Sphinx) смогут использовать остальное.
|
||||
Это не отобразится в документации, но другие инструменты (например, Sphinx) смогут использовать остальное.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
Вы, вероятно, уже видели, как объявлять `response_model` и `status_code` для *операции пути*.
|
||||
|
||||
Это определяет метаданные об основном ответе *операции пути*.
|
||||
Это определяет метаданные об основном HTTP-ответе *операции пути*.
|
||||
|
||||
Также можно объявлять дополнительные ответы с их моделями, статус-кодами и т.д.
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
Там есть `tags`, `parameters`, `requestBody`, `responses` и т.д.
|
||||
|
||||
Эта спецификация OpenAPI, специфичная для *операции пути*, обычно генерируется автоматически **FastAPI**, но вы также можете её расширить.
|
||||
Эта специфичная для *операции пути* схема OpenAPI обычно генерируется автоматически **FastAPI**, но вы также можете её расширить.
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
@@ -129,13 +129,13 @@
|
||||
}
|
||||
```
|
||||
|
||||
### Пользовательская схема OpenAPI для операции пути { #custom-openapi-path-operation-schema }
|
||||
### Пользовательская схема OpenAPI для *операции пути* { #custom-openapi-path-operation-schema }
|
||||
|
||||
Словарь в `openapi_extra` будет объединён с автоматически сгенерированной схемой OpenAPI для *операции пути*.
|
||||
Словарь в `openapi_extra` будет глубоко объединён с автоматически сгенерированной схемой OpenAPI для *операции пути*.
|
||||
|
||||
Таким образом, вы можете добавить дополнительные данные к автоматически сгенерированной схеме.
|
||||
|
||||
Например, вы можете решить читать и валидировать запрос своим кодом, не используя автоматические возможности FastAPI и Pydantic, но при этом захотите описать запрос в схеме OpenAPI.
|
||||
Например, вы можете решить читать и валидировать HTTP-запрос своим кодом, не используя автоматические возможности FastAPI и Pydantic, но при этом захотите описать HTTP-запрос в схеме OpenAPI.
|
||||
|
||||
Это можно сделать с помощью `openapi_extra`:
|
||||
|
||||
@@ -149,52 +149,20 @@
|
||||
|
||||
Используя тот же приём, вы можете воспользоваться Pydantic-моделью, чтобы определить JSON Schema, которая затем будет включена в пользовательский раздел схемы OpenAPI для *операции пути*.
|
||||
|
||||
И вы можете сделать это, даже если тип данных в запросе — не JSON.
|
||||
И вы можете сделать это, даже если тип данных в HTTP-запросе — не JSON.
|
||||
|
||||
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого запроса как YAML, а не JSON:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
Например, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого HTTP-запроса как YAML, а не JSON:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic версии 1 метод для получения JSON Schema модели назывался `Item.schema()`, в Pydantic версии 2 метод называется `Item.model_json_schema()`.
|
||||
|
||||
///
|
||||
|
||||
Тем не менее, хотя мы не используем встроенную функциональность по умолчанию, мы всё равно используем Pydantic-модель, чтобы вручную сгенерировать JSON Schema для данных, которые мы хотим получить в YAML.
|
||||
|
||||
Затем мы работаем с запросом напрямую и извлекаем тело как `bytes`. Это означает, что FastAPI даже не попытается распарсить полезную нагрузку запроса как JSON.
|
||||
Затем мы работаем с HTTP-запросом напрямую и извлекаем тело как `bytes`. Это означает, что FastAPI даже не попытается распарсить полезную нагрузку HTTP-запроса как JSON.
|
||||
|
||||
А затем в нашем коде мы напрямую парсим этот YAML и снова используем ту же Pydantic-модель для валидации YAML-содержимого:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
А затем в нашем коде мы напрямую парсим это содержимое YAML и снова используем ту же Pydantic-модель, чтобы валидировать YAML-содержимое:
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
|
||||
|
||||
////
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic версии 1 метод для парсинга и валидации объекта назывался `Item.parse_obj()`, в Pydantic версии 2 метод называется `Item.model_validate()`.
|
||||
|
||||
///
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Здесь мы переиспользуем ту же Pydantic-модель.
|
||||
|
||||
@@ -46,12 +46,6 @@ $ pip install "fastapi[all]"
|
||||
|
||||
</div>
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 он входил в основной пакет. Теперь он распространяется как отдельный пакет, чтобы вы могли установить его только при необходимости.
|
||||
|
||||
///
|
||||
|
||||
### Создание объекта `Settings` { #create-the-settings-object }
|
||||
|
||||
Импортируйте `BaseSettings` из Pydantic и создайте подкласс, очень похожий на Pydantic‑модель.
|
||||
@@ -60,24 +54,8 @@ $ pip install "fastapi[all]"
|
||||
|
||||
Вы можете использовать все те же возможности валидации и инструменты, что и для Pydantic‑моделей, например разные типы данных и дополнительную валидацию через `Field()`.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 вы бы импортировали `BaseSettings` напрямую из `pydantic`, а не из `pydantic_settings`.
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
|
||||
|
||||
////
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Если вам нужно что-то быстро скопировать и вставить, не используйте этот пример — воспользуйтесь последним ниже.
|
||||
@@ -215,8 +193,6 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
Затем обновите ваш `config.py` так:
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
|
||||
|
||||
/// tip | Совет
|
||||
@@ -225,26 +201,6 @@ APP_NAME="ChimichangApp"
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Класс `Config` используется только для конфигурации Pydantic. Подробнее см. <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic версии 1 конфигурация задавалась во внутреннем классе `Config`, в Pydantic версии 2 — в атрибуте `model_config`. Этот атрибут принимает `dict`, и чтобы получить автозавершение и ошибки «на лету», вы можете импортировать и использовать `SettingsConfigDict` для описания этого `dict`.
|
||||
|
||||
///
|
||||
|
||||
Здесь мы задаем параметр конфигурации `env_file` внутри вашего класса Pydantic `Settings` и устанавливаем значение равным имени файла dotenv, который хотим использовать.
|
||||
|
||||
### Создание `Settings` только один раз с помощью `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
Если у вас старое приложение FastAPI, возможно, вы используете Pydantic версии 1.
|
||||
|
||||
FastAPI поддерживает и Pydantic v1, и v2 начиная с версии 0.100.0.
|
||||
FastAPI версии 0.100.0 поддерживал либо Pydantic v1, либо v2. Он использовал ту версию, которая была установлена.
|
||||
|
||||
Если у вас был установлен Pydantic v2, использовался он. Если вместо этого был установлен Pydantic v1 — использовался он.
|
||||
FastAPI версии 0.119.0 добавил частичную поддержку Pydantic v1 изнутри Pydantic v2 (как `pydantic.v1`), чтобы упростить миграцию на v2.
|
||||
|
||||
Сейчас Pydantic v1 объявлен устаревшим, и поддержка его будет удалена в следующих версиях FastAPI, поэтому вам следует **перейти на Pydantic v2**. Так вы получите последние возможности, улучшения и исправления.
|
||||
FastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещё некоторое время продолжал поддерживать `pydantic.v1`.
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Кроме того, команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
|
||||
Команда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.
|
||||
|
||||
Это включает `pydantic.v1`, который больше не поддерживается в Python 3.14 и выше.
|
||||
|
||||
Если вы хотите использовать последние возможности Python, вам нужно убедиться, что вы используете Pydantic v2.
|
||||
|
||||
///
|
||||
|
||||
Если у вас старое приложение FastAPI с Pydantic v1, здесь я покажу, как мигрировать на Pydantic v2, и **новые возможности в FastAPI 0.119.0**, которые помогут выполнить постепенную миграцию.
|
||||
Если у вас старое приложение FastAPI с Pydantic v1, здесь я покажу, как мигрировать на Pydantic v2, и **возможности FastAPI 0.119.0**, которые помогут выполнить постепенную миграцию.
|
||||
|
||||
## Официальное руководство { #official-guide }
|
||||
|
||||
@@ -38,13 +40,13 @@ FastAPI поддерживает и Pydantic v1, и v2 начиная с вер
|
||||
|
||||
Вы можете использовать <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a> от той же команды Pydantic.
|
||||
|
||||
Этот инструмент поможет автоматически внести большую часть необходимых изменений в код.
|
||||
Этот инструмент поможет автоматически изменить большую часть кода, который нужно изменить.
|
||||
|
||||
После этого запустите тесты и проверьте, что всё работает. Если да — на этом всё. 😎
|
||||
После этого вы можете запустить тесты и проверить, что всё работает. Если да — на этом всё. 😎
|
||||
|
||||
## Pydantic v1 в v2 { #pydantic-v1-in-v2 }
|
||||
|
||||
Pydantic v2 включает всё из Pydantic v1 как подмодуль `pydantic.v1`.
|
||||
Pydantic v2 включает всё из Pydantic v1 как подмодуль `pydantic.v1`. Но это больше не поддерживается в версиях Python выше 3.13.
|
||||
|
||||
Это означает, что вы можете установить последнюю версию Pydantic v2 и импортировать и использовать старые компоненты Pydantic v1 из этого подмодуля так, как если бы у вас был установлен старый Pydantic v1.
|
||||
|
||||
@@ -52,7 +54,7 @@ Pydantic v2 включает всё из Pydantic v1 как подмодуль `
|
||||
|
||||
### Поддержка FastAPI для Pydantic v1 внутри v2 { #fastapi-support-for-pydantic-v1-in-v2 }
|
||||
|
||||
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 в составе Pydantic v2, чтобы упростить миграцию на v2.
|
||||
Начиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 изнутри Pydantic v2, чтобы упростить миграцию на v2.
|
||||
|
||||
Таким образом, вы можете обновить Pydantic до последней версии 2 и сменить импорты на подмодуль `pydantic.v1` — во многих случаях всё просто заработает.
|
||||
|
||||
@@ -106,7 +108,7 @@ graph TB
|
||||
style V2Field fill:#f9fff3
|
||||
```
|
||||
|
||||
В некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же операции пути (обработчике пути) вашего приложения FastAPI:
|
||||
В некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же **операции пути** (обработчике пути) вашего приложения FastAPI:
|
||||
|
||||
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
|
||||
|
||||
@@ -122,12 +124,12 @@ graph TB
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Сначала попробуйте `bump-pydantic`. Если тесты проходят и всё работает, вы справились одной командой. ✨
|
||||
Сначала попробуйте `bump-pydantic`: если тесты проходят и всё работает, вы справились одной командой. ✨
|
||||
|
||||
///
|
||||
|
||||
Если `bump-pydantic` не подходит для вашего случая, вы можете использовать поддержку одновременной работы моделей Pydantic v1 и v2 в одном приложении, чтобы мигрировать на Pydantic v2 постепенно.
|
||||
|
||||
Сначала обновите Pydantic до последней 2-й версии и измените импорты так, чтобы все ваши модели использовали `pydantic.v1`.
|
||||
Сначала вы можете обновить Pydantic до последней 2-й версии и изменить импорты так, чтобы все ваши модели использовали `pydantic.v1`.
|
||||
|
||||
Затем начните мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶
|
||||
Затем вы можете начать мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
При использовании **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎
|
||||
|
||||
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON схемы** для одной и той же Pydantic‑модели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
|
||||
На самом деле, в некоторых случаях в OpenAPI будет даже **две JSON-схемы** для одной и той же Pydantic‑модели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.
|
||||
|
||||
Посмотрим, как это работает, и как это изменить при необходимости.
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
|
||||
|
||||
…то, поскольку у `description` есть значение по умолчанию, даже если вы **ничего не вернёте** для этого поля, оно всё равно будет иметь это **значение по умолчанию**.
|
||||
…то, поскольку у `description` есть значение по умолчанию, если вы **ничего не вернёте** для этого поля, оно всё равно будет иметь это **значение по умолчанию**.
|
||||
|
||||
### Модель для данных ответа { #model-for-output-response-data }
|
||||
|
||||
@@ -46,13 +46,13 @@
|
||||
|
||||
Это означает, что у него **всегда будет какое‑то значение**, просто иногда это значение может быть `None` (или `null` в JSON).
|
||||
|
||||
Следовательно, клиентам, использующим ваш API, не нужно проверять наличие этого значения: они могут **исходить из того, что поле всегда присутствует**, а в некоторых случаях имеет значение по умолчанию `None`.
|
||||
Это означает, что клиентам, использующим ваш API, не нужно проверять, существует ли это значение или нет: они могут **исходить из того, что поле всегда присутствует**, но в некоторых случаях оно будет иметь значение по умолчанию `None`.
|
||||
|
||||
В OpenAPI это описывается тем, что поле помечается как **обязательное**, поскольку оно всегда присутствует.
|
||||
|
||||
Из‑за этого JSON Schema для модели может отличаться в зависимости от использования для **входа** или **выхода**:
|
||||
|
||||
* для **входа** `description` не будет обязательным
|
||||
* для **входа** `description` **не будет обязательным**
|
||||
* для **выхода** оно будет **обязательным** (и при этом может быть `None`, или, в терминах JSON, `null`)
|
||||
|
||||
### Выходная модель в документации { #model-for-output-in-docs }
|
||||
@@ -81,9 +81,9 @@
|
||||
|
||||
Однако бывают случаи, когда вы хотите иметь **одну и ту же схему для входа и выхода**.
|
||||
|
||||
Главный сценарий — когда у вас уже есть сгенерированный клиентский код/SDK, и вы пока не хотите обновлять весь этот автогенерируемый код/SDK (рано или поздно вы это сделаете, но не сейчас).
|
||||
Главный сценарий — когда у вас уже есть сгенерированный клиентский код/SDK, и вы пока не хотите обновлять весь этот автогенерируемый клиентский код/SDK, вероятно, вы захотите сделать это в какой-то момент, но, возможно, не прямо сейчас.
|
||||
|
||||
В таком случае вы можете отключить эту функциональность в FastAPI с помощью параметра `separate_input_output_schemas=False`.
|
||||
В таком случае вы можете отключить эту функциональность в **FastAPI** с помощью параметра `separate_input_output_schemas=False`.
|
||||
|
||||
/// info | Информация
|
||||
|
||||
@@ -95,10 +95,8 @@
|
||||
|
||||
### Одна и та же схема для входной и выходной моделей в документации { #same-schema-for-input-and-output-models-in-docs }
|
||||
|
||||
Теперь для этой модели будет одна общая схема и для входа, и для выхода — только `Item`, и в ней `description` будет **не обязательным**:
|
||||
И теперь для модели будет одна общая схема и для входа, и для выхода — только `Item`, и в ней `description` будет **не обязательным**:
|
||||
|
||||
<div class="screenshot">
|
||||
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
|
||||
</div>
|
||||
|
||||
Это то же поведение, что и в Pydantic v1. 🤓
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
</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/ru"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>Фреймворк FastAPI: высокая производительность, прост в изучении, быстрый в разработке, готов к продакшн</em>
|
||||
<em>Фреймворк FastAPI: высокая производительность, прост в изучении, позволяет быстро писать код, готов к продакшн</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster" target="_blank">
|
||||
@@ -40,7 +40,7 @@ FastAPI — это современный, быстрый (высокопрои
|
||||
* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance).
|
||||
* **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200–300%. *
|
||||
* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *
|
||||
* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
|
||||
* **Интуитивность**: Отличная поддержка редактора кода. <abbr title="также известное как: автодополнение, автозавершение, IntelliSense">Автозавершение</abbr> везде. Меньше времени на отладку.
|
||||
* **Простота**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.
|
||||
* **Краткость**: Минимизируйте дублирование кода. Несколько возможностей из каждого объявления параметров. Меньше ошибок.
|
||||
* **Надежность**: Получите код, готовый к продакшн. С автоматической интерактивной документацией.
|
||||
@@ -117,6 +117,12 @@ FastAPI — это современный, быстрый (высокопрои
|
||||
|
||||
---
|
||||
|
||||
## Мини-документальный фильм о FastAPI { #fastapi-mini-documentary }
|
||||
|
||||
В конце 2025 года вышел <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">мини-документальный фильм о FastAPI</a>, вы можете посмотреть его онлайн:
|
||||
|
||||
<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**, FastAPI для CLI { #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>
|
||||
@@ -257,7 +263,7 @@ INFO: Application startup complete.
|
||||
|
||||
* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`.
|
||||
* Оба _пути_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).
|
||||
* _Путь_ `/items/{item_id}` имеет _параметр пути_ `item_id`, который должен быть `int`.
|
||||
* _Путь_ `/items/{item_id}` имеет _path-параметр_ `item_id`, который должен быть `int`.
|
||||
* _Путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.
|
||||
|
||||
### Интерактивная документация API { #interactive-api-docs }
|
||||
@@ -278,9 +284,9 @@ INFO: Application startup complete.
|
||||
|
||||
## Пример обновления { #example-upgrade }
|
||||
|
||||
Теперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` запроса.
|
||||
Теперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` HTTP-запроса.
|
||||
|
||||
Объявите тело, используя стандартные типы Python, спасибо Pydantic.
|
||||
Объявите тело запроса, используя стандартные типы Python, спасибо Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
@@ -318,7 +324,7 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||
Перейдите на <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
* Интерактивная документация API будет автоматически обновлена, включая новое тело:
|
||||
* Интерактивная документация API будет автоматически обновлена, включая новое тело запроса:
|
||||
|
||||

|
||||
|
||||
@@ -334,13 +340,13 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||
Теперь откройте <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
* Альтернативная документация также отразит новый параметр запроса и тело:
|
||||
* Альтернативная документация также отразит новый параметр запроса и тело запроса:
|
||||
|
||||

|
||||
|
||||
### Подведём итоги { #recap }
|
||||
|
||||
Итак, вы объявляете **один раз** типы параметров, тела запроса и т.д. как параметры функции.
|
||||
Итак, вы объявляете **один раз** типы параметров, тело запроса и т.д. как параметры функции.
|
||||
|
||||
Вы делаете это с помощью стандартных современных типов Python.
|
||||
|
||||
@@ -390,13 +396,13 @@ item: Item
|
||||
|
||||
Возвращаясь к предыдущему примеру кода, **FastAPI** будет:
|
||||
|
||||
* Валидировать наличие `item_id` в пути для `GET` и `PUT` запросов.
|
||||
* Валидировать, что `item_id` имеет тип `int` для `GET` и `PUT` запросов.
|
||||
* Валидировать наличие `item_id` в пути для `GET` и `PUT` HTTP-запросов.
|
||||
* Валидировать, что `item_id` имеет тип `int` для `GET` и `PUT` HTTP-запросов.
|
||||
* Если это не так, клиент увидит полезную понятную ошибку.
|
||||
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` запросов.
|
||||
* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` HTTP-запросов.
|
||||
* Поскольку параметр `q` объявлен с `= None`, он необязателен.
|
||||
* Без `None` он был бы обязательным (как тело запроса в случае с `PUT`).
|
||||
* Для `PUT` запросов к `/items/{item_id}` читать тело запроса как JSON:
|
||||
* Для `PUT` HTTP-запросов к `/items/{item_id}` читать тело запроса как JSON:
|
||||
* Проверять, что есть обязательный атрибут `name`, который должен быть `str`.
|
||||
* Проверять, что есть обязательный атрибут `price`, который должен быть `float`.
|
||||
* Проверять, что есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует.
|
||||
@@ -435,11 +441,11 @@ item: Item
|
||||
|
||||
Более полный пример с дополнительными возможностями см. в <a href="https://fastapi.tiangolo.com/ru/tutorial/">Учебник - Руководство пользователя</a>.
|
||||
|
||||
**Осторожно, спойлер**: учебник - руководство включает:
|
||||
**Осторожно, спойлер**: учебник - руководство пользователя включает:
|
||||
|
||||
* Объявление **параметров** из других источников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**.
|
||||
* Как задать **ограничения валидации** вроде `maximum_length` или `regex`.
|
||||
* Очень мощную и простую в использовании систему **<abbr title="также известная как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
|
||||
* Очень мощную и простую в использовании систему **<abbr title="также известна как: компоненты, ресурсы, провайдеры, сервисы, инъекции">внедрения зависимостей</abbr>**.
|
||||
* Безопасность и аутентификацию, включая поддержку **OAuth2** с **JWT токенами** и **HTTP Basic** аутентификацию.
|
||||
* Более продвинутые (но столь же простые) приёмы объявления **глубоко вложенных JSON-моделей** (спасибо Pydantic).
|
||||
* Интеграцию **GraphQL** с <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> и другими библиотеками.
|
||||
@@ -524,11 +530,11 @@ FastAPI зависит от Pydantic и Starlette.
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> — обязателен, если вы хотите использовать `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> — обязателен, если вы хотите использовать конфигурацию шаблонов по умолчанию.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> — обязателен, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - обязателен, если вы хотите поддерживать <abbr title="преобразование строки, полученной из HTTP-запроса, в данные Python">«парсинг»</abbr> форм через `request.form()`.
|
||||
|
||||
Используется FastAPI:
|
||||
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> — сервер, который загружает и обслуживает ваше приложение. Включает `uvicorn[standard]`, содержащий некоторые зависимости (например, `uvloop`), нужные для высокой производительности.
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> — сервер, который загружает и «отдаёт» ваше приложение. Включает `uvicorn[standard]`, содержащий некоторые зависимости (например, `uvloop`), нужные для высокой производительности.
|
||||
* `fastapi-cli[standard]` — чтобы предоставить команду `fastapi`.
|
||||
* Включает `fastapi-cloud-cli`, который позволяет развернуть ваше приложение FastAPI в <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Большие приложения, в которых много файлов { #bigger-applications-multiple-files }
|
||||
# Большие приложения — несколько файлов { #bigger-applications-multiple-files }
|
||||
|
||||
При построении приложения или веб-API нам редко удается поместить всё в один файл.
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Обратите внимание, что в каждом каталоге и подкаталоге имеется файл `__init__.py`
|
||||
Есть несколько файлов `__init__.py`: по одному в каждом каталоге или подкаталоге.
|
||||
|
||||
Это как раз то, что позволяет импортировать код из одного файла в другой.
|
||||
|
||||
@@ -43,61 +43,63 @@ from app.routers import items
|
||||
|
||||
///
|
||||
|
||||
* Всё помещается в каталоге `app`. В нём также находится пустой файл `app/__init__.py`. Таким образом, `app` является "Python-пакетом" (коллекцией модулей Python).
|
||||
* Он содержит файл `app/main.py`. Данный файл является частью пакета (т.е. находится внутри каталога, содержащего файл `__init__.py`), и, соответственно, он является модулем пакета: `app.main`.
|
||||
* Всё помещается в каталоге `app`. В нём также находится пустой файл `app/__init__.py`. Таким образом, `app` является "Python-пакетом" (коллекцией "Python-модулей"): `app`.
|
||||
* Он содержит файл `app/main.py`. Данный файл является частью Python-пакета (т.е. находится внутри каталога, содержащего файл `__init__.py`), и, соответственно, он является модулем этого пакета: `app.main`.
|
||||
* Он также содержит файл `app/dependencies.py`, который также, как и `app/main.py`, является модулем: `app.dependencies`.
|
||||
* Здесь также находится подкаталог `app/routers/`, содержащий `__init__.py`. Он является суб-пакетом: `app.routers`.
|
||||
* Файл `app/routers/items.py` находится внутри пакета `app/routers/`. Таким образом, он является суб-модулем: `app.routers.items`.
|
||||
* Точно также `app/routers/users.py` является ещё одним суб-модулем: `app.routers.users`.
|
||||
* Подкаталог `app/internal/`, содержащий файл `__init__.py`, является ещё одним суб-пакетом: `app.internal`.
|
||||
* А файл `app/internal/admin.py` является ещё одним суб-модулем: `app.internal.admin`.
|
||||
* Здесь также находится подкаталог `app/routers/`, содержащий `__init__.py`. Он является Python-подпакетом: `app.routers`.
|
||||
* Файл `app/routers/items.py` находится внутри пакета `app/routers/`. Таким образом, он является подмодулем: `app.routers.items`.
|
||||
* Точно так же `app/routers/users.py` является ещё одним подмодулем: `app.routers.users`.
|
||||
* Подкаталог `app/internal/`, содержащий файл `__init__.py`, является ещё одним Python-подпакетом: `app.internal`.
|
||||
* А файл `app/internal/admin.py` является ещё одним подмодулем: `app.internal.admin`.
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/package.drawio.svg">
|
||||
|
||||
Та же самая файловая структура приложения, но с комментариями:
|
||||
|
||||
```
|
||||
```bash
|
||||
.
|
||||
├── app # "app" пакет
|
||||
│ ├── __init__.py # этот файл превращает "app" в "Python-пакет"
|
||||
│ ├── main.py # модуль "main", напр.: import app.main
|
||||
│ ├── dependencies.py # модуль "dependencies", напр.: import app.dependencies
|
||||
│ └── routers # суб-пакет "routers"
|
||||
│ │ ├── __init__.py # превращает "routers" в суб-пакет
|
||||
│ │ ├── items.py # суб-модуль "items", напр.: import app.routers.items
|
||||
│ │ └── users.py # суб-модуль "users", напр.: import app.routers.users
|
||||
│ └── internal # суб-пакет "internal"
|
||||
│ ├── __init__.py # превращает "internal" в суб-пакет
|
||||
│ └── admin.py # суб-модуль "admin", напр.: import app.internal.admin
|
||||
│ └── routers # подпакет "routers"
|
||||
│ │ ├── __init__.py # превращает "routers" в подпакет
|
||||
│ │ ├── items.py # подмодуль "items", напр.: import app.routers.items
|
||||
│ │ └── users.py # подмодуль "users", напр.: import app.routers.users
|
||||
│ └── internal # подпакет "internal"
|
||||
│ ├── __init__.py # превращает "internal" в подпакет
|
||||
│ └── admin.py # подмодуль "admin", напр.: import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
|
||||
Давайте предположим, что для работы с пользователями используется отдельный файл (суб-модуль) `/app/routers/users.py`.
|
||||
Давайте предположим, что для работы с пользователями используется отдельный файл (подмодуль) `/app/routers/users.py`.
|
||||
|
||||
Для лучшей организации приложения, вы хотите отделить операции пути, связанные с пользователями, от остального кода.
|
||||
Вы хотите отделить *операции пути*, связанные с пользователями, от остального кода, чтобы сохранить порядок.
|
||||
|
||||
Но так, чтобы эти операции по-прежнему оставались частью **FastAPI** приложения/веб-API (частью одного пакета)
|
||||
Но это всё равно часть того же приложения/веб-API на **FastAPI** (часть того же «Python-пакета»).
|
||||
|
||||
С помощью `APIRouter` вы можете создать *операции пути* (*эндпоинты*) для данного модуля.
|
||||
С помощью `APIRouter` вы можете создать *операции пути* для этого модуля.
|
||||
|
||||
### Импорт `APIRouter` { #import-apirouter }
|
||||
|
||||
Точно также, как и в случае с классом `FastAPI`, вам нужно импортировать и создать объект класса `APIRouter`.
|
||||
Точно так же, как и в случае с классом `FastAPI`, вам нужно импортировать и создать его «экземпляр»:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *}
|
||||
|
||||
### Создание *эндпоинтов* с помощью `APIRouter` { #path-operations-with-apirouter }
|
||||
### *Операции пути* с `APIRouter` { #path-operations-with-apirouter }
|
||||
|
||||
В дальнейшем используйте `APIRouter` для объявления *эндпоинтов*, точно также, как вы используете класс `FastAPI`:
|
||||
И затем вы используете его, чтобы объявить ваши *операции пути*.
|
||||
|
||||
Используйте его так же, как вы использовали бы класс `FastAPI`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *}
|
||||
|
||||
Вы можете думать об `APIRouter` как об "уменьшенной версии" класса FastAPI`.
|
||||
Вы можете думать об `APIRouter` как об «мини-классе `FastAPI`».
|
||||
|
||||
`APIRouter` поддерживает все те же самые опции.
|
||||
Поддерживаются все те же опции.
|
||||
|
||||
`APIRouter` поддерживает все те же самые параметры, такие как `parameters`, `responses`, `dependencies`, `tags`, и т. д.
|
||||
Все те же `parameters`, `responses`, `dependencies`, `tags` и т.д.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
@@ -105,21 +107,21 @@ from app.routers import items
|
||||
|
||||
///
|
||||
|
||||
Мы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и создадим ещё один модуль с `APIRouter`.
|
||||
Мы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и ещё один `APIRouter`.
|
||||
|
||||
## Зависимости { #dependencies }
|
||||
|
||||
Нам понадобятся некоторые зависимости, которые мы будем использовать в разных местах нашего приложения.
|
||||
Мы видим, что нам понадобятся некоторые зависимости, которые будут использоваться в нескольких местах приложения.
|
||||
|
||||
Мы поместим их в отдельный модуль `dependencies` (`app/dependencies.py`).
|
||||
Поэтому мы поместим их в отдельный модуль `dependencies` (`app/dependencies.py`).
|
||||
|
||||
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомизированный `X-Token` из заголовка:
|
||||
Теперь мы воспользуемся простой зависимостью, чтобы прочитать кастомный HTTP-заголовок `X-Token`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *}
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Для простоты мы воспользовались неким воображаемым заголовоком.
|
||||
Для простоты мы воспользовались выдуманным заголовком.
|
||||
|
||||
В реальных случаях для получения наилучших результатов используйте интегрированные [утилиты безопасности](security/index.md){.internal-link target=_blank}.
|
||||
|
||||
@@ -127,30 +129,29 @@ from app.routers import items
|
||||
|
||||
## Ещё один модуль с `APIRouter` { #another-module-with-apirouter }
|
||||
|
||||
Давайте также предположим, что у вас есть *эндпоинты*, отвечающие за обработку "items", и они находятся в модуле `app/routers/items.py`.
|
||||
Давайте также предположим, что у вас есть эндпоинты, отвечающие за обработку «items» в вашем приложении, и они находятся в модуле `app/routers/items.py`.
|
||||
|
||||
У вас определены следующие *операции пути* (*эндпоинты*):
|
||||
У вас определены *операции пути* для:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
Тут всё точно также, как и в ситуации с `app/routers/users.py`.
|
||||
Тут всё та же структура, как и в случае с `app/routers/users.py`.
|
||||
|
||||
Но теперь мы хотим поступить немного умнее и слегка упростить код.
|
||||
Но мы хотим поступить умнее и слегка упростить код.
|
||||
|
||||
Мы знаем, что все *эндпоинты* данного модуля имеют некоторые общие свойства:
|
||||
Мы знаем, что все *операции пути* этого модуля имеют одинаковые:
|
||||
|
||||
* Префикс пути: `/items`.
|
||||
* Теги: (один единственный тег: `items`).
|
||||
* Дополнительные ответы (responses)
|
||||
* Зависимости: использование созданной нами зависимости `X-token`
|
||||
* `prefix` пути: `/items`.
|
||||
* `tags`: (один единственный тег: `items`).
|
||||
* Дополнительные `responses`.
|
||||
* `dependencies`: всем им нужна та зависимость `X-Token`, которую мы создали.
|
||||
|
||||
Таким образом, вместо того чтобы добавлять все эти свойства в функцию каждого отдельного *эндпоинта*,
|
||||
мы добавим их в `APIRouter`.
|
||||
Таким образом, вместо того чтобы добавлять всё это в каждую *операцию пути*, мы можем добавить это в `APIRouter`.
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *}
|
||||
|
||||
Так как каждый *эндпоинт* начинается с символа `/`:
|
||||
Так как путь каждой *операции пути* должен начинаться с `/`, как здесь:
|
||||
|
||||
```Python hl_lines="1"
|
||||
@router.get("/{item_id}")
|
||||
@@ -162,73 +163,74 @@ async def read_item(item_id: str):
|
||||
|
||||
В нашем случае префиксом является `/items`.
|
||||
|
||||
Мы также можем добавить в наш маршрутизатор (router) список `тегов` (`tags`) и дополнительных `ответов` (`responses`), которые являются общими для каждого *эндпоинта*.
|
||||
Мы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот маршрутизатор.
|
||||
|
||||
И ещё мы можем добавить в наш маршрутизатор список `зависимостей`, которые должны вызываться при каждом обращении к *эндпоинтам*.
|
||||
И ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в маршрутизаторе и будут выполняться/разрешаться для каждого HTTP-запроса к ним.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Обратите внимание, что также, как и в случае с зависимостями в декораторах *эндпоинтов* ([зависимости в декораторах операций пути](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), никакого значения в *функцию эндпоинта* передано не будет.
|
||||
Обратите внимание, что так же, как и в случае с [зависимостями в декораторах *операций пути*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, никакое значение не будет передано в вашу *функцию-обработчик пути*.
|
||||
|
||||
///
|
||||
|
||||
В результате мы получим следующие эндпоинты:
|
||||
В результате пути для items теперь такие:
|
||||
|
||||
* `/items/`
|
||||
* `/items/{item_id}`
|
||||
|
||||
...как мы и планировали.
|
||||
|
||||
* Они будут помечены тегами из заданного списка, в нашем случае это `"items"`.
|
||||
* Эти теги особенно полезны для системы автоматической интерактивной документации (с использованием OpenAPI).
|
||||
* Каждый из них будет включать предопределенные ответы `responses`.
|
||||
* Каждый *эндпоинт* будет иметь список зависимостей (`dependencies`), исполняемых перед вызовом *эндпоинта*.
|
||||
* Если вы определили зависимости в самой операции пути, **то она также будет выполнена**.
|
||||
* Сначала выполняются зависимости маршрутизатора, затем вызываются [зависимости в декораторе](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, и, наконец, обычные параметрические зависимости.
|
||||
* Вы также можете добавить [зависимости `Security` с `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
* Они будут помечены списком тегов, содержащим одну строку `"items"`.
|
||||
* Эти «теги» особенно полезны для систем автоматической интерактивной документации (с использованием OpenAPI).
|
||||
* Все они будут включать предопределённые `responses`.
|
||||
* Все эти *операции пути* будут иметь список `dependencies`, вычисляемых/выполняемых перед ними.
|
||||
* Если вы также объявите зависимости в конкретной *операции пути*, **они тоже будут выполнены**.
|
||||
* Сначала выполняются зависимости маршрутизатора, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, и затем обычные параметрические зависимости.
|
||||
* Вы также можете добавить [`Security`-зависимости с `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Например, с помощью зависимостей в `APIRouter` мы можем потребовать аутентификации для доступа ко всей группе *эндпоинтов*, не указывая зависимости для каждой отдельной функции *эндпоинта*.
|
||||
Например, с помощью зависимостей в `APIRouter` мы можем потребовать аутентификации для доступа ко всей группе *операций пути*. Даже если зависимости не добавляются по отдельности к каждой из них.
|
||||
|
||||
///
|
||||
|
||||
/// check | Заметка
|
||||
|
||||
Параметры `prefix`, `tags`, `responses` и `dependencies` относятся к функционалу **FastAPI**, помогающему избежать дублирования кода.
|
||||
Параметры `prefix`, `tags`, `responses` и `dependencies` — это (как и во многих других случаях) просто возможность **FastAPI**, помогающая избежать дублирования кода.
|
||||
|
||||
///
|
||||
|
||||
### Импорт зависимостей { #import-the-dependencies }
|
||||
|
||||
Наш код находится в модуле `app.routers.items` (файл `app/routers/items.py`).
|
||||
Этот код находится в модуле `app.routers.items`, в файле `app/routers/items.py`.
|
||||
|
||||
И нам нужно вызвать функцию зависимости из модуля `app.dependencies` (файл `app/dependencies.py`).
|
||||
И нам нужно получить функцию зависимости из модуля `app.dependencies`, файла `app/dependencies.py`.
|
||||
|
||||
Мы используем операцию относительного импорта `..` для импорта зависимости:
|
||||
Поэтому мы используем относительный импорт с `..` для зависимостей:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *}
|
||||
|
||||
#### Как работает относительный импорт? { #how-relative-imports-work }
|
||||
#### Как работает относительный импорт { #how-relative-imports-work }
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Если вы прекрасно знаете, как работает импорт в Python, то переходите к следующему разделу.
|
||||
Если вы прекрасно знаете, как работает импорт, переходите к следующему разделу ниже.
|
||||
|
||||
///
|
||||
|
||||
Одна точка `.`, как в данном примере:
|
||||
Одна точка `.`, как здесь:
|
||||
|
||||
```Python
|
||||
from .dependencies import get_token_header
|
||||
```
|
||||
|
||||
означает:
|
||||
|
||||
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` расположен в каталоге `app/routers/`)...
|
||||
* ... найдите модуль `dependencies` (файл `app/routers/dependencies.py`)...
|
||||
* ... и импортируйте из него функцию `get_token_header`.
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
|
||||
* найти модуль `dependencies` (воображаемый файл `app/routers/dependencies.py`)...
|
||||
* и импортировать из него функцию `get_token_header`.
|
||||
|
||||
К сожалению, такого файла не существует, и наши зависимости находятся в файле `app/dependencies.py`.
|
||||
Но такого файла не существует, наши зависимости находятся в файле `app/dependencies.py`.
|
||||
|
||||
Вспомните, как выглядит файловая структура нашего приложения:
|
||||
|
||||
@@ -236,7 +238,7 @@ from .dependencies import get_token_header
|
||||
|
||||
---
|
||||
|
||||
Две точки `..`, как в данном примере:
|
||||
Две точки `..`, как здесь:
|
||||
|
||||
```Python
|
||||
from ..dependencies import get_token_header
|
||||
@@ -244,12 +246,12 @@ from ..dependencies import get_token_header
|
||||
|
||||
означают:
|
||||
|
||||
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` находится в каталоге `app/routers/`)...
|
||||
* ... перейдите в родительский пакет (каталог `app/`)...
|
||||
* ... найдите в нём модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* ... и импортируйте из него функцию `get_token_header`.
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...
|
||||
* перейти в родительский пакет (каталог `app/`)...
|
||||
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* и импортировать из него функцию `get_token_header`.
|
||||
|
||||
Это работает верно! 🎉
|
||||
Это работает корректно! 🎉
|
||||
|
||||
---
|
||||
|
||||
@@ -261,29 +263,29 @@ from ...dependencies import get_token_header
|
||||
|
||||
то это бы означало:
|
||||
|
||||
* Начните с пакета, в котором находится данный модуль (файл `app/routers/items.py` находится в каталоге `app/routers/`)...
|
||||
* ... перейдите в родительский пакет (каталог `app/`)...
|
||||
* ... затем перейдите в родительский пакет текущего пакета (такого пакета не существует, `app` находится на самом верхнем уровне 😱)...
|
||||
* ... найдите в нём модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* ... и импортируйте из него функцию `get_token_header`.
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) расположен в (каталоге `app/routers/`)...
|
||||
* перейти в родительский пакет (каталог `app/`)...
|
||||
* затем перейти в родительский пакет этого пакета (родительского пакета нет, `app` — верхний уровень 😱)...
|
||||
* и там найти модуль `dependencies` (файл `app/dependencies.py`)...
|
||||
* и импортировать из него функцию `get_token_header`.
|
||||
|
||||
Это будет относиться к некоторому пакету, находящемуся на один уровень выше чем `app/` и содержащему свой собственный файл `__init__.py`. Но ничего такого у нас нет. Поэтому это приведет к ошибке в нашем примере. 🚨
|
||||
Это ссылалось бы на какой-то пакет выше `app/`, со своим файлом `__init__.py` и т.п. Но у нас такого нет. Поэтому это вызвало бы ошибку в нашем примере. 🚨
|
||||
|
||||
Теперь вы знаете, как работает импорт в Python, и сможете использовать относительное импортирование в своих собственных приложениях любого уровня сложности. 🤓
|
||||
Но теперь вы знаете, как это работает, так что можете использовать относительные импорты в своих приложениях, независимо от того, насколько они сложные. 🤓
|
||||
|
||||
### Добавление пользовательских тегов (`tags`), ответов (`responses`) и зависимостей (`dependencies`) { #add-some-custom-tags-responses-and-dependencies }
|
||||
### Добавление пользовательских `tags`, `responses` и `dependencies` { #add-some-custom-tags-responses-and-dependencies }
|
||||
|
||||
Мы не будем добавлять префикс `/items` и список тегов `tags=["items"]` для каждого *эндпоинта*, т.к. мы уже их добавили с помощью `APIRouter`.
|
||||
Мы не добавляем префикс `/items` и `tags=["items"]` к каждой *операции пути*, потому что мы добавили их в `APIRouter`.
|
||||
|
||||
Но помимо этого мы можем добавить новые теги для каждого отдельного *эндпоинта*, а также некоторые дополнительные ответы (`responses`), характерные для данного *эндпоинта*:
|
||||
Но мы всё равно можем добавить _ещё_ `tags`, которые будут применяться к конкретной *операции пути*, а также дополнительные `responses`, специфичные для этой *операции пути*:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *}
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Последний *эндпоинт* будет иметь следующую комбинацию тегов: `["items", "custom"]`.
|
||||
Эта последняя операция пути будет иметь комбинацию тегов: `["items", "custom"]`.
|
||||
|
||||
А также в его документации будут содержаться оба ответа: один для `404` и другой для `403`.
|
||||
И в документации у неё будут оба ответа: один для `404` и один для `403`.
|
||||
|
||||
///
|
||||
|
||||
@@ -293,29 +295,29 @@ from ...dependencies import get_token_header
|
||||
|
||||
Именно сюда вы импортируете и именно здесь вы используете класс `FastAPI`.
|
||||
|
||||
Это основной файл вашего приложения, который объединяет всё в одно целое.
|
||||
Это основной файл вашего приложения, который связывает всё воедино.
|
||||
|
||||
И теперь, когда большая часть логики приложения разделена на отдельные модули, основной файл `app/main.py` будет достаточно простым.
|
||||
И так как большая часть вашей логики теперь будет находиться в отдельных специфичных модулях, основной файл будет довольно простым.
|
||||
|
||||
### Импорт `FastAPI` { #import-fastapi }
|
||||
|
||||
Вы импортируете и создаете класс `FastAPI` как обычно.
|
||||
Вы импортируете и создаёте класс `FastAPI` как обычно.
|
||||
|
||||
Мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого отдельного маршрутизатора:
|
||||
И мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md){.internal-link target=_blank}, которые будут объединены с зависимостями для каждого `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *}
|
||||
|
||||
### Импорт `APIRouter` { #import-the-apirouter }
|
||||
|
||||
Теперь мы импортируем другие суб-модули, содержащие `APIRouter`:
|
||||
Теперь мы импортируем другие подмодули, содержащие `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *}
|
||||
|
||||
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются суб-модулями одного и того же Python-пакета `app`, то мы сможем их импортировать, воспользовавшись операцией относительного импорта `.`.
|
||||
Так как файлы `app/routers/users.py` и `app/routers/items.py` являются подмодулями, входящими в один и тот же Python-пакет `app`, мы можем использовать одну точку `.` для импорта через «относительные импорты».
|
||||
|
||||
### Как работает импорт? { #how-the-importing-works }
|
||||
### Как работает импорт { #how-the-importing-works }
|
||||
|
||||
Данная строка кода:
|
||||
Этот фрагмент:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
@@ -323,15 +325,15 @@ from .routers import items, users
|
||||
|
||||
означает:
|
||||
|
||||
* Начните с пакета, в котором содержится данный модуль (файл `app/main.py` содержится в каталоге `app/`)...
|
||||
* ... найдите суб-пакет `routers` (каталог `app/routers/`)...
|
||||
* ... и из него импортируйте суб-модули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...
|
||||
* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) расположен в (каталоге `app/`)...
|
||||
* найти подпакет `routers` (каталог `app/routers/`)...
|
||||
* и импортировать из него подмодули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...
|
||||
|
||||
В модуле `items` содержится переменная `router` (`items.router`), та самая, которую мы создали в файле `app/routers/items.py`, она является объектом класса `APIRouter`.
|
||||
В модуле `items` будет переменная `router` (`items.router`). Это та же самая, которую мы создали в файле `app/routers/items.py`, это объект `APIRouter`.
|
||||
|
||||
И затем мы сделаем то же самое для модуля `users`.
|
||||
И затем мы делаем то же самое для модуля `users`.
|
||||
|
||||
Мы также могли бы импортировать и другим методом:
|
||||
Мы также могли бы импортировать их так:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
@@ -339,44 +341,44 @@ from app.routers import items, users
|
||||
|
||||
/// info | Примечание
|
||||
|
||||
Первая версия является примером относительного импорта:
|
||||
Первая версия — это «относительный импорт»:
|
||||
|
||||
```Python
|
||||
from .routers import items, users
|
||||
```
|
||||
|
||||
Вторая версия является примером абсолютного импорта:
|
||||
Вторая версия — это «абсолютный импорт»:
|
||||
|
||||
```Python
|
||||
from app.routers import items, users
|
||||
```
|
||||
|
||||
Узнать больше о пакетах и модулях в Python вы можете из <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">официальной документации Python о модулях</a>
|
||||
Чтобы узнать больше о Python-пакетах и модулях, прочитайте <a href="https://docs.python.org/3/tutorial/modules.html" class="external-link" target="_blank">официальную документацию Python о модулях</a>.
|
||||
|
||||
///
|
||||
|
||||
### Избегайте конфликтов имен { #avoid-name-collisions }
|
||||
### Избегайте конфликтов имён { #avoid-name-collisions }
|
||||
|
||||
Вместо того чтобы импортировать только переменную `router`, мы импортируем непосредственно суб-модуль `items`.
|
||||
Мы импортируем подмодуль `items` напрямую, вместо того чтобы импортировать только его переменную `router`.
|
||||
|
||||
Мы делаем это потому, что у нас есть ещё одна переменная `router` в суб-модуле `users`.
|
||||
Это потому, что у нас также есть другая переменная с именем `router` в подмодуле `users`.
|
||||
|
||||
Если бы мы импортировали их одну за другой, как показано в примере:
|
||||
Если бы мы импортировали их одну за другой, как здесь:
|
||||
|
||||
```Python
|
||||
from .routers.items import router
|
||||
from .routers.users import router
|
||||
```
|
||||
|
||||
то переменная `router` из `users` переписал бы переменную `router` из `items`, и у нас не было бы возможности использовать их одновременно.
|
||||
то `router` из `users` перезаписал бы `router` из `items`, и мы не смогли бы использовать их одновременно.
|
||||
|
||||
Поэтому, для того чтобы использовать обе эти переменные в одном файле, мы импортировали соответствующие суб-модули:
|
||||
Поэтому, чтобы иметь возможность использовать обе в одном файле, мы импортируем подмодули напрямую:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *}
|
||||
|
||||
### Подключение маршрутизаторов (`APIRouter`) для `users` и для `items` { #include-the-apirouters-for-users-and-items }
|
||||
### Подключение `APIRouter` для `users` и `items` { #include-the-apirouters-for-users-and-items }
|
||||
|
||||
Давайте подключим маршрутизаторы (`router`) из суб-модулей `users` и `items`:
|
||||
Теперь давайте подключим `router` из подмодулей `users` и `items`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *}
|
||||
|
||||
@@ -388,79 +390,78 @@ from .routers.users import router
|
||||
|
||||
///
|
||||
|
||||
С помощью `app.include_router()` мы можем добавить каждый из маршрутизаторов (`APIRouter`) в основное приложение `FastAPI`.
|
||||
С помощью `app.include_router()` мы можем добавить каждый `APIRouter` в основное приложение `FastAPI`.
|
||||
|
||||
Он подключит все маршруты заданного маршрутизатора к нашему приложению.
|
||||
Он включит все маршруты этого маршрутизатора как часть приложения.
|
||||
|
||||
/// note | Технические детали
|
||||
|
||||
Фактически, внутри он создаст все *операции пути* для каждой операции пути объявленной в `APIRouter`.
|
||||
Фактически, внутри он создаст *операцию пути* для каждой *операции пути*, объявленной в `APIRouter`.
|
||||
|
||||
И под капотом всё будет работать так, как будто бы мы имеем дело с одним файлом приложения.
|
||||
Так что под капотом всё будет работать так, как будто всё было одним приложением.
|
||||
|
||||
///
|
||||
|
||||
/// check | Заметка
|
||||
|
||||
При подключении маршрутизаторов не стоит беспокоиться о производительности.
|
||||
При подключении маршрутизаторов не нужно беспокоиться о производительности.
|
||||
|
||||
Операция подключения займёт микросекунды и понадобится только при запуске приложения.
|
||||
Это займёт микросекунды и произойдёт только при старте.
|
||||
|
||||
Таким образом, это не повлияет на производительность. ⚡
|
||||
Так что это не повлияет на производительность. ⚡
|
||||
|
||||
///
|
||||
|
||||
### Подключение `APIRouter` с пользовательскими префиксом (`prefix`), тегами (`tags`), ответами (`responses`), и зависимостями (`dependencies`) { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
|
||||
### Подключение `APIRouter` с пользовательскими `prefix`, `tags`, `responses` и `dependencies` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }
|
||||
|
||||
Теперь давайте представим, что ваша организация передала вам файл `app/internal/admin.py`.
|
||||
|
||||
Он содержит `APIRouter` с некоторыми *эндпоитами* администрирования, которые ваша организация использует для нескольких проектов.
|
||||
Он содержит `APIRouter` с некоторыми административными *операциями пути*, которые ваша организация использует в нескольких проектах.
|
||||
|
||||
В данном примере это сделать очень просто. Но давайте предположим, что поскольку файл используется для нескольких проектов,
|
||||
то мы не можем модифицировать его, добавляя префиксы (`prefix`), зависимости (`dependencies`), теги (`tags`), и т.д. непосредственно в `APIRouter`:
|
||||
Для этого примера всё будет очень просто. Но допустим, что поскольку он используется совместно с другими проектами в организации, мы не можем модифицировать его и добавить `prefix`, `dependencies`, `tags` и т.д. непосредственно в `APIRouter`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *}
|
||||
|
||||
Но, несмотря на это, мы хотим использовать кастомный префикс (`prefix`) для подключенного маршрутизатора (`APIRouter`), в результате чего, каждая *операция пути* будет начинаться с `/admin`. Также мы хотим защитить наш маршрутизатор с помощью зависимостей, созданных для нашего проекта. И ещё мы хотим включить теги (`tags`) и ответы (`responses`).
|
||||
Но мы всё равно хотим задать пользовательский `prefix` при подключении `APIRouter`, чтобы все его *операции пути* начинались с `/admin`, хотим защитить его с помощью `dependencies`, которые у нас уже есть для этого проекта, и хотим включить `tags` и `responses`.
|
||||
|
||||
Мы можем применить все вышеперечисленные настройки, не изменяя начальный `APIRouter`. Нам всего лишь нужно передать нужные параметры в `app.include_router()`.
|
||||
Мы можем объявить всё это, не изменяя исходный `APIRouter`, передав эти параметры в `app.include_router()`:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *}
|
||||
|
||||
Таким образом, оригинальный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
|
||||
Таким образом исходный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.
|
||||
|
||||
В результате, в нашем приложении каждый *эндпоинт* модуля `admin` будет иметь:
|
||||
В результате в нашем приложении каждая из *операций пути* из модуля `admin` будет иметь:
|
||||
|
||||
* Префикс `/admin`.
|
||||
* Тег `admin`.
|
||||
* Зависимость `get_token_header`.
|
||||
* Ответ `418`. 🍵
|
||||
|
||||
Это будет иметь место исключительно для `APIRouter` в нашем приложении, и не затронет любой другой код, использующий его.
|
||||
Но это повлияет только на этот `APIRouter` в нашем приложении, а не на любой другой код, который его использует.
|
||||
|
||||
Например, другие проекты, могут использовать тот же самый `APIRouter` с другими методами аутентификации.
|
||||
Так что, например, другие проекты могут использовать тот же `APIRouter` с другим методом аутентификации.
|
||||
|
||||
### Подключение отдельного *эндпоинта* { #include-a-path-operation }
|
||||
### Подключение *операции пути* { #include-a-path-operation }
|
||||
|
||||
Мы также можем добавить *эндпоинт* непосредственно в основное приложение `FastAPI`.
|
||||
Мы также можем добавлять *операции пути* напрямую в приложение `FastAPI`.
|
||||
|
||||
Здесь мы это делаем ... просто, чтобы показать, что это возможно 🤷:
|
||||
Здесь мы делаем это... просто чтобы показать, что можем 🤷:
|
||||
|
||||
{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *}
|
||||
|
||||
и это будет работать корректно вместе с другими *эндпоинтами*, добавленными с помощью `app.include_router()`.
|
||||
и это будет работать корректно вместе со всеми другими *операциями пути*, добавленными через `app.include_router()`.
|
||||
|
||||
/// info | Сложные технические детали
|
||||
/// info | Очень технические детали
|
||||
|
||||
**Примечание**: это сложная техническая деталь, которую, скорее всего, **вы можете пропустить**.
|
||||
**Примечание**: это очень техническая деталь, которую, вероятно, можно **просто пропустить**.
|
||||
|
||||
---
|
||||
|
||||
Маршрутизаторы (`APIRouter`) не "монтируются" по-отдельности и не изолируются от остального приложения.
|
||||
`APIRouter` не «монтируются», они не изолированы от остального приложения.
|
||||
|
||||
Это происходит потому, что нужно включить их *эндпоинты* в OpenAPI схему и в интерфейс пользователя.
|
||||
Это потому, что мы хотим включить их *операции пути* в OpenAPI-схему и пользовательские интерфейсы.
|
||||
|
||||
В силу того, что мы не можем их изолировать и "примонтировать" независимо от остальных, *эндпоинты* клонируются (пересоздаются) и не подключаются напрямую.
|
||||
Так как мы не можем просто изолировать их и «смонтировать» независимо от остального, *операции пути* «клонируются» (пересоздаются), а не включаются напрямую.
|
||||
|
||||
///
|
||||
|
||||
@@ -480,24 +481,24 @@ $ fastapi dev app/main.py
|
||||
|
||||
Откройте документацию по адресу <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Вы увидите автоматическую API документацию. Она включает в себя маршруты из суб-модулей, используя верные маршруты, префиксы и теги:
|
||||
Вы увидите автоматическую документацию API, включая пути из всех подмодулей, с использованием корректных путей (и префиксов) и корректных тегов:
|
||||
|
||||
<img src="/img/tutorial/bigger-applications/image01.png">
|
||||
|
||||
## Подключение существующего маршрута через новый префикс (`prefix`) { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
## Подключение одного и того же маршрутизатора несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }
|
||||
|
||||
Вы можете использовать `.include_router()` несколько раз с одним и тем же маршрутом, применив различные префиксы.
|
||||
Вы можете использовать `.include_router()` несколько раз с *одним и тем же* маршрутизатором, используя разные префиксы.
|
||||
|
||||
Это может быть полезным, если нужно предоставить доступ к одному и тому же API через различные префиксы, например, `/api/v1` и `/api/latest`.
|
||||
Это может быть полезно, например, чтобы предоставить доступ к одному и тому же API с разными префиксами, например `/api/v1` и `/api/latest`.
|
||||
|
||||
Это продвинутый способ, который вам может и не пригодится. Мы приводим его на случай, если вдруг вам это понадобится.
|
||||
Это продвинутое использование, которое вам может и не понадобиться, но оно есть на случай, если понадобится.
|
||||
|
||||
## Включение одного маршрутизатора (`APIRouter`) в другой { #include-an-apirouter-in-another }
|
||||
## Подключение `APIRouter` в другой `APIRouter` { #include-an-apirouter-in-another }
|
||||
|
||||
Точно так же, как вы включаете `APIRouter` в приложение `FastAPI`, вы можете включить `APIRouter` в другой `APIRouter`:
|
||||
Точно так же, как вы можете подключить `APIRouter` к приложению `FastAPI`, вы можете подключить `APIRouter` к другому `APIRouter`, используя:
|
||||
|
||||
```Python
|
||||
router.include_router(other_router)
|
||||
```
|
||||
|
||||
Удостоверьтесь, что вы сделали это до того, как подключить маршрутизатор (`router`) к вашему `FastAPI` приложению, и *эндпоинты* маршрутизатора `other_router` были также подключены.
|
||||
Убедитесь, что вы сделали это до подключения `router` к приложению `FastAPI`, чтобы *операции пути* из `other_router` также были подключены.
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
## Обновление с заменой при помощи `PUT` { #update-replacing-with-put }
|
||||
|
||||
Для полного обновления элемента можно воспользоваться операцией <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
|
||||
Чтобы обновить элемент, вы можете использовать операцию <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT" class="external-link" target="_blank">HTTP `PUT`</a>.
|
||||
|
||||
Вы можете использовать `jsonable_encoder`, чтобы преобразовать входные данные в данные, которые можно сохранить как JSON (например, в NoSQL-базе данных). Например, преобразование `datetime` в `str`.
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
|
||||
|
||||
`PUT` используется для получения данных, которые должны полностью заменить существующие данные.
|
||||
`PUT` используется для получения данных, которые должны заменить существующие данные.
|
||||
|
||||
### Предупреждение о замене { #warning-about-replacing }
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
поскольку оно не включает уже сохраненный атрибут `"tax": 20.2`, входная модель примет значение по умолчанию `"tax": 10.5`.
|
||||
|
||||
И данные будут сохранены с этим "новым" `tax`, равным `10,5`.
|
||||
И данные будут сохранены с этим «новым» `tax`, равным `10.5`.
|
||||
|
||||
## Частичное обновление с помощью `PATCH` { #partial-updates-with-patch }
|
||||
|
||||
Также можно использовать <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> операцию для *частичного* обновления данных.
|
||||
Также можно использовать операцию <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH" class="external-link" target="_blank">HTTP `PATCH`</a> для *частичного* обновления данных.
|
||||
|
||||
Это означает, что можно передавать только те данные, которые необходимо обновить, оставляя остальные нетронутыми.
|
||||
|
||||
@@ -46,19 +46,13 @@
|
||||
|
||||
### Использование параметра `exclude_unset` в Pydantic { #using-pydantics-exclude-unset-parameter }
|
||||
|
||||
Если необходимо выполнить частичное обновление, то очень полезно использовать параметр `exclude_unset` в методе `.model_dump()` модели Pydantic.
|
||||
Если вы хотите получать частичные обновления, очень полезно использовать параметр `exclude_unset` в `.model_dump()` модели Pydantic.
|
||||
|
||||
Например, `item.model_dump(exclude_unset=True)`.
|
||||
|
||||
/// info | Информация
|
||||
В результате будет сгенерирован `dict`, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию.
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_dump()`.
|
||||
|
||||
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_dump()`.
|
||||
|
||||
///
|
||||
|
||||
В результате будет сгенерирован словарь, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию. Затем вы можете использовать это для создания словаря только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
|
||||
Затем вы можете использовать это для создания `dict` только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
|
||||
|
||||
@@ -66,14 +60,6 @@
|
||||
|
||||
Теперь можно создать копию существующей модели, используя `.model_copy()`, и передать параметр `update` с `dict`, содержащим данные для обновления.
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 метод назывался `.copy()`, в Pydantic v2 он помечен как устаревший (но все еще поддерживается) и переименован в `.model_copy()`.
|
||||
|
||||
Примеры здесь используют `.copy()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, лучше используйте `.model_copy()`.
|
||||
|
||||
///
|
||||
|
||||
Например, `stored_item_model.model_copy(update=update_data)`:
|
||||
|
||||
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
|
||||
@@ -84,9 +70,9 @@
|
||||
|
||||
* (Опционально) использовать `PATCH` вместо `PUT`.
|
||||
* Извлечь сохранённые данные.
|
||||
* Поместить эти данные в Pydantic модель.
|
||||
* Поместить эти данные в Pydantic-модель.
|
||||
* Сгенерировать `dict` без значений по умолчанию из входной модели (с использованием `exclude_unset`).
|
||||
* Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять значения, уже сохраненные в модели по умолчанию.
|
||||
* Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять уже сохраненные значения значениями по умолчанию из вашей модели.
|
||||
* Создать копию хранимой модели, обновив ее атрибуты полученными частичными обновлениями (с помощью параметра `update`).
|
||||
* Преобразовать скопированную модель в то, что может быть сохранено в вашей БД (например, с помощью `jsonable_encoder`).
|
||||
* Это сравнимо с повторным использованием метода модели `.model_dump()`, но при этом происходит проверка (и преобразование) значений в типы данных, которые могут быть преобразованы в JSON, например, `datetime` в `str`.
|
||||
@@ -97,7 +83,7 @@
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Эту же технику можно использовать и для операции HTTP `PUT`.
|
||||
На самом деле эту же технику можно использовать и для операции HTTP `PUT`.
|
||||
|
||||
Но в приведенном примере используется `PATCH`, поскольку он был создан именно для таких случаев использования.
|
||||
|
||||
|
||||
@@ -32,9 +32,10 @@
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
|
||||
Так же, как при объявлении параметров запроса: когда атрибут модели имеет значение по умолчанию, он не обязателен. Иначе он обязателен. Используйте `None`, чтобы сделать его просто необязательным.
|
||||
|
||||
Например, модель выше описывает такой JSON "объект" (или Python `dict`):
|
||||
Например, модель выше описывает такой JSON "`object`" (или Python `dict`):
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -45,7 +46,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON "объект" тоже будет корректным:
|
||||
...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON "`object`" тоже будет корректным:
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -73,7 +74,7 @@
|
||||
* Передаст полученные данные в параметр `item`.
|
||||
* Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т. п.) для всех атрибутов и их типов.
|
||||
* Сгенерирует определения <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.
|
||||
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces – Пользовательские интерфейсы">UIs</abbr>.
|
||||
* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title="User Interfaces - Пользовательские интерфейсы">UIs</abbr>.
|
||||
|
||||
## Автоматическая документация { #automatic-docs }
|
||||
|
||||
@@ -127,14 +128,6 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
|
||||
|
||||
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы можете использовать Pydantic v2, используйте `.model_dump()`.
|
||||
|
||||
///
|
||||
|
||||
## Тело запроса + параметры пути { #request-body-path-parameters }
|
||||
|
||||
Вы можете одновременно объявить параметры пути и тело запроса.
|
||||
@@ -143,6 +136,7 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
|
||||
## Тело запроса + параметры пути + параметры запроса { #request-body-path-query-parameters }
|
||||
|
||||
Вы также можете одновременно объявить параметры **тела**, **пути** и **запроса**.
|
||||
@@ -153,7 +147,7 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
Параметры функции будут распознаны следующим образом:
|
||||
|
||||
* Если параметр также объявлен в **пути**, он будет использоваться как параметр пути.
|
||||
* Если параметр также объявлен в **пути**, он будет использоваться как path-параметр.
|
||||
* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т. п.), он будет интерпретирован как параметр **запроса**.
|
||||
* Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса.
|
||||
|
||||
@@ -161,7 +155,7 @@ JSON Schema ваших моделей будет частью сгенериро
|
||||
|
||||
FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`.
|
||||
|
||||
Аннотации типов `str | None` (Python 3.10+) или `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
|
||||
Аннотации типов `str | None` (Python 3.10+) или `Union` в `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.
|
||||
|
||||
Но добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки.
|
||||
|
||||
@@ -169,4 +163,4 @@ FastAPI понимает, что значение `q` не является об
|
||||
|
||||
## Без Pydantic { #without-pydantic }
|
||||
|
||||
Если вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело — Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
Если вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело запроса - Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
|
||||
@@ -22,21 +22,13 @@
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
|
||||
|
||||
/// info | Информация
|
||||
### Про `**user_in.model_dump()` { #about-user-in-model-dump }
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
|
||||
#### `.model_dump()` из Pydantic { #pydantics-model-dump }
|
||||
|
||||
В примерах здесь используется `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, следует использовать `.model_dump()`.
|
||||
`user_in` — это Pydantic-модель класса `UserIn`.
|
||||
|
||||
///
|
||||
|
||||
### Про `**user_in.dict()` { #about-user-in-dict }
|
||||
|
||||
#### `.dict()` из Pydantic { #pydantics-dict }
|
||||
|
||||
`user_in` - это Pydantic-модель класса `UserIn`.
|
||||
|
||||
У Pydantic-моделей есть метод `.dict()`, который возвращает `dict` с данными модели.
|
||||
У Pydantic-моделей есть метод `.model_dump()`, который возвращает `dict` с данными модели.
|
||||
|
||||
Поэтому, если мы создадим Pydantic-объект `user_in` таким способом:
|
||||
|
||||
@@ -47,10 +39,10 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
|
||||
и затем вызовем:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
```
|
||||
|
||||
то теперь у нас есть `dict` с данными модели в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
|
||||
то теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
|
||||
|
||||
И если мы вызовем:
|
||||
|
||||
@@ -58,7 +50,7 @@ user_dict = user_in.dict()
|
||||
print(user_dict)
|
||||
```
|
||||
|
||||
мы можем получить `dict` с такими данными:
|
||||
мы получим Python `dict` с:
|
||||
|
||||
```Python
|
||||
{
|
||||
@@ -71,7 +63,7 @@ print(user_dict)
|
||||
|
||||
#### Распаковка `dict` { #unpacking-a-dict }
|
||||
|
||||
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python распакует его. Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
|
||||
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python его "распакует". Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
|
||||
|
||||
Поэтому, продолжая описанный выше пример с `user_dict`, написание такого кода:
|
||||
|
||||
@@ -79,7 +71,7 @@ print(user_dict)
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
Будет работать так же, как примерно такой код:
|
||||
будет эквивалентно:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -90,7 +82,7 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
Или, если для большей точности мы напрямую используем `user_dict` с любым потенциальным содержимым, то этот пример будет выглядеть так:
|
||||
Или, более точно, если использовать `user_dict` напрямую, с любым содержимым, которое он может иметь в будущем:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -101,22 +93,22 @@ UserInDB(
|
||||
)
|
||||
```
|
||||
|
||||
#### Pydantic-модель из содержимого другой модели { #a-pydantic-model-from-the-contents-of-another }
|
||||
#### Pydantic-модель из содержимого другой { #a-pydantic-model-from-the-contents-of-another }
|
||||
|
||||
Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код:
|
||||
Как в примере выше мы получили `user_dict` из `user_in.model_dump()`, этот код:
|
||||
|
||||
```Python
|
||||
user_dict = user_in.dict()
|
||||
user_dict = user_in.model_dump()
|
||||
UserInDB(**user_dict)
|
||||
```
|
||||
|
||||
будет равнозначен такому:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict())
|
||||
UserInDB(**user_in.model_dump())
|
||||
```
|
||||
|
||||
...потому что `user_in.dict()` - это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` и ставим перед ним `**`.
|
||||
...потому что `user_in.model_dump()` — это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` с префиксом `**`.
|
||||
|
||||
Таким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.
|
||||
|
||||
@@ -125,10 +117,10 @@ UserInDB(**user_in.dict())
|
||||
И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:
|
||||
|
||||
```Python
|
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password)
|
||||
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
|
||||
```
|
||||
|
||||
... то мы получим что-то подобное:
|
||||
...то в итоге получится что-то подобное:
|
||||
|
||||
```Python
|
||||
UserInDB(
|
||||
@@ -142,13 +134,13 @@ UserInDB(
|
||||
|
||||
/// warning | Предупреждение
|
||||
|
||||
Вспомогательные функции `fake_password_hasher` и `fake_save_user` используются только для демонстрации возможного потока данных и, конечно, не обеспечивают настоящую безопасность.
|
||||
Вспомогательные дополнительные функции `fake_password_hasher` и `fake_save_user` используются только для демонстрации возможного потока данных и, конечно, не обеспечивают настоящую безопасность.
|
||||
|
||||
///
|
||||
|
||||
## Сократите дублирование { #reduce-duplication }
|
||||
|
||||
Сокращение дублирования кода - это одна из главных идей **FastAPI**.
|
||||
Сокращение дублирования кода — это одна из главных идей **FastAPI**.
|
||||
|
||||
Поскольку дублирование кода повышает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д.
|
||||
|
||||
@@ -166,7 +158,7 @@ UserInDB(
|
||||
|
||||
## `Union` или `anyOf` { #union-or-anyof }
|
||||
|
||||
Вы можете определить ответ как `Union` из двух или более типов. Это означает, что ответ должен соответствовать одному из них.
|
||||
Вы можете объявить HTTP-ответ как `Union` из двух или более типов. Это означает, что HTTP-ответ может быть любым из них.
|
||||
|
||||
Он будет определён в OpenAPI как `anyOf`.
|
||||
|
||||
@@ -174,7 +166,7 @@ UserInDB(
|
||||
|
||||
/// note | Примечание
|
||||
|
||||
При объявлении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a>, сначала указывайте наиболее детальные типы, затем менее детальные. В примере ниже более детальный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
|
||||
При объявлении <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" class="external-link" target="_blank">`Union`</a> сначала указывайте наиболее специфичный тип, затем менее специфичный. В примере ниже более специфичный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
|
||||
|
||||
///
|
||||
|
||||
@@ -192,19 +184,19 @@ UserInDB(
|
||||
some_variable: PlaneItem | CarItem
|
||||
```
|
||||
|
||||
Но если мы помещаем его в `response_model=PlaneItem | CarItem` мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
|
||||
Но если мы поместим это в присваивание `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
|
||||
|
||||
## Список моделей { #list-of-models }
|
||||
|
||||
Таким же образом вы можете определять ответы как списки объектов.
|
||||
Таким же образом вы можете объявлять HTTP-ответы, возвращающие списки объектов.
|
||||
|
||||
Для этого используйте `typing.List` из стандартной библиотеки Python (или просто `list` в Python 3.9 и выше):
|
||||
Для этого используйте стандартный `typing.List` в Python (или просто `list` в Python 3.9 и выше):
|
||||
|
||||
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
|
||||
|
||||
## Ответ с произвольным `dict` { #response-with-arbitrary-dict }
|
||||
|
||||
Вы также можете определить ответ, используя произвольный одноуровневый `dict` и определяя только типы ключей и значений без использования Pydantic-моделей.
|
||||
Вы также можете объявить HTTP-ответ, используя обычный произвольный `dict`, объявив только тип ключей и значений, без использования Pydantic-модели.
|
||||
|
||||
Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).
|
||||
|
||||
@@ -214,6 +206,6 @@ some_variable: PlaneItem | CarItem
|
||||
|
||||
## Резюме { #recap }
|
||||
|
||||
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждой из них.
|
||||
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждого случая.
|
||||
|
||||
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля.
|
||||
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояние, включающее `password`, `password_hash` и отсутствие пароля.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Query-параметр `q` имеет тип `str | None`, это означает, что он имеет тип `str`, но также может быть `None`. Значение по умолчанию действительно `None`, поэтому FastAPI будет знать, что он не обязателен.
|
||||
|
||||
/// note | Технические детали
|
||||
/// note | Примечание
|
||||
|
||||
FastAPI поймёт, что значение `q` не обязательно, из‑за значения по умолчанию `= None`.
|
||||
|
||||
@@ -177,7 +177,7 @@ q: str = Query(default="rick")
|
||||
|
||||
**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌
|
||||
|
||||
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор кода** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
|
||||
Вы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.
|
||||
|
||||
Если вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.
|
||||
|
||||
@@ -191,7 +191,7 @@ q: str = Query(default="rick")
|
||||
|
||||
## Регулярные выражения { #add-regular-expressions }
|
||||
|
||||
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) — это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
|
||||
Вы можете определить <abbr title="Регулярное выражение (regex, regexp) - это последовательность символов, задающая шаблон поиска для строк.">регулярное выражение</abbr> `pattern`, которому должен соответствовать параметр:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
@@ -205,20 +205,6 @@ q: str = Query(default="rick")
|
||||
|
||||
Теперь вы знаете, что когда они понадобятся, вы сможете использовать их в **FastAPI**.
|
||||
|
||||
### `regex` из Pydantic v1 вместо `pattern` { #pydantic-v1-regex-instead-of-pattern }
|
||||
|
||||
До Pydantic версии 2 и до FastAPI 0.100.0 этот параметр назывался `regex`, а не `pattern`, но сейчас он устарел.
|
||||
|
||||
Вы всё ещё можете встретить такой код:
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
|
||||
|
||||
////
|
||||
|
||||
Имейте в виду, что это устарело, и код следует обновить на использование нового параметра `pattern`. 🤓
|
||||
|
||||
## Значения по умолчанию { #default-values }
|
||||
|
||||
Конечно, можно использовать и другие значения по умолчанию, не только `None`.
|
||||
@@ -279,7 +265,7 @@ q: Annotated[str | None, Query(min_length=3)] = None
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
вы получите множественные значения query-параметра `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
|
||||
вы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.
|
||||
|
||||
Таким образом, ответ на этот URL будет:
|
||||
|
||||
@@ -331,7 +317,7 @@ http://localhost:8000/items/
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
|
||||
|
||||
/// note | Технические детали
|
||||
/// note | Примечание
|
||||
|
||||
Имейте в виду, что в этом случае FastAPI не будет проверять содержимое списка.
|
||||
|
||||
@@ -345,7 +331,7 @@ http://localhost:8000/items/
|
||||
|
||||
Эта информация будет включена в сгенерированную OpenAPI-схему и использована интерфейсами документации и внешними инструментами.
|
||||
|
||||
/// note | Технические детали
|
||||
/// note | Примечание
|
||||
|
||||
Помните, что разные инструменты могут иметь разный уровень поддержки OpenAPI.
|
||||
|
||||
@@ -415,7 +401,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
///
|
||||
|
||||
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number – Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) — веб‑сайт с информацией о фильмах">IMDB</abbr>:
|
||||
Например, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title="ISBN означает International Standard Book Number - Международный стандартный книжный номер">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title="IMDB (Internet Movie Database) - веб‑сайт с информацией о фильмах">IMDB</abbr>:
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
@@ -455,7 +441,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
Затем с `random.choice()` можно получить **случайное значение** из списка — то есть кортеж вида `(id, name)`. Это будет что‑то вроде `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
|
||||
После этого мы **распаковываем** эти два значения кортежа в переменные `id` и `name`.
|
||||
После этого мы **присваиваем эти два значения** кортежа переменным `id` и `name`.
|
||||
|
||||
Так что, если пользователь не передал ID элемента, он всё равно получит случайную рекомендацию.
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
|
||||
|
||||
FastAPI будет использовать этот тип ответа для:
|
||||
FastAPI будет использовать этот возвращаемый тип, чтобы:
|
||||
|
||||
* **Валидации** возвращаемых данных.
|
||||
* Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру.
|
||||
* Добавления **JSON Schema** для ответа в OpenAPI *операции пути*.
|
||||
* **Валидировать** возвращаемые данные.
|
||||
* Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру данных.
|
||||
* Добавить **JSON Schema** для ответа в OpenAPI *операции пути*.
|
||||
* Это будет использовано **автоматической документацией**.
|
||||
* Это также будет использовано инструментами автоматической генерации клиентского кода.
|
||||
|
||||
@@ -23,7 +23,7 @@ FastAPI будет использовать этот тип ответа для:
|
||||
|
||||
Бывают случаи, когда вам нужно или хочется возвращать данные, которые не в точности соответствуют объявленному типу.
|
||||
|
||||
Например, вы можете хотеть **возвращать словарь (dict)** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
|
||||
Например, вы можете хотеть **возвращать словарь** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).
|
||||
|
||||
Если вы добавите аннотацию возвращаемого типа, инструменты и редакторы кода начнут жаловаться (и будут правы), что функция возвращает тип (например, dict), отличный от объявленного (например, Pydantic-модель).
|
||||
|
||||
@@ -47,13 +47,13 @@ FastAPI будет использовать этот тип ответа для:
|
||||
|
||||
`response_model` принимает тот же тип, что вы бы объявили для поля Pydantic-модели, то есть это может быть одна Pydantic-модель, а может быть, например, `list` Pydantic-моделей, как `List[Item]`.
|
||||
|
||||
FastAPI будет использовать `response_model` для документации, валидации и т. п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.
|
||||
FastAPI будет использовать этот `response_model` для документирования, валидации данных и т.п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.
|
||||
|
||||
/// tip | Совет
|
||||
|
||||
Если у вас в редакторе кода, mypy и т. п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.
|
||||
Если у вас в редакторе кода, mypy и т.п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.
|
||||
|
||||
Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документацию данных, валидацию, фильтрацию и т.д. с помощью `response_model`.
|
||||
Так вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документирование, валидацию, фильтрацию данных и т.д. с помощью `response_model`.
|
||||
|
||||
///
|
||||
|
||||
@@ -61,7 +61,7 @@ FastAPI будет использовать `response_model` для докуме
|
||||
|
||||
Если вы объявите и возвращаемый тип, и `response_model`, приоритет будет у `response_model`, именно его использует FastAPI.
|
||||
|
||||
Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.
|
||||
Так вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор кода и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.
|
||||
|
||||
Вы также можете указать `response_model=None`, чтобы отключить создание модели ответа для данной *операции пути*. Это может понадобиться, если вы добавляете аннотации типов для вещей, не являющихся валидными полями Pydantic. Пример вы увидите ниже.
|
||||
|
||||
@@ -75,7 +75,7 @@ FastAPI будет использовать `response_model` для докуме
|
||||
|
||||
Чтобы использовать `EmailStr`, сначала установите <a href="https://github.com/JoshData/python-email-validator" class="external-link" target="_blank">`email-validator`</a>.
|
||||
|
||||
Создайте [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активируйте его и затем установите пакет, например:
|
||||
Убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, активировали его, а затем установите пакет, например:
|
||||
|
||||
```console
|
||||
$ pip install email-validator
|
||||
@@ -105,7 +105,7 @@ $ pip install "pydantic[email]"
|
||||
|
||||
///
|
||||
|
||||
## Добавить модель для ответа { #add-an-output-model }
|
||||
## Добавить выходную модель { #add-an-output-model }
|
||||
|
||||
Вместо этого мы можем создать входную модель с паролем в открытом виде и выходную модель без него:
|
||||
|
||||
@@ -123,7 +123,7 @@ $ pip install "pydantic[email]"
|
||||
|
||||
### `response_model` или возвращаемый тип { #response-model-or-return-type }
|
||||
|
||||
В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.
|
||||
В этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор кода и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.
|
||||
|
||||
Поэтому в этом примере мы должны объявить тип ответа в параметре `response_model`.
|
||||
|
||||
@@ -135,33 +135,33 @@ $ pip install "pydantic[email]"
|
||||
|
||||
Мы хотим, чтобы FastAPI продолжал **фильтровать** данные с помощью модели ответа. Так что, даже если функция возвращает больше данных, в ответ будут включены только поля, объявленные в модели ответа.
|
||||
|
||||
В предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора и инструментов, проверяющих возвращаемый тип функции.
|
||||
В предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора кода и инструментов, проверяющих возвращаемый тип функции.
|
||||
|
||||
Однако в большинстве таких случаев нам нужно лишь **отфильтровать/убрать** некоторые данные, как в этом примере.
|
||||
|
||||
И в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе и инструментах и при этом получить **фильтрацию данных** от FastAPI.
|
||||
И в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе кода и инструментах и при этом получить **фильтрацию данных** от FastAPI.
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
|
||||
|
||||
Так мы получаем поддержку инструментов (редакторы, mypy) — код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.
|
||||
Так мы получаем поддержку инструментов — редакторов кода и mypy, так как этот код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.
|
||||
|
||||
Как это работает? Давайте разберёмся. 🤓
|
||||
|
||||
### Аннотации типов и инструменты { #type-annotations-and-tooling }
|
||||
|
||||
Сначала посмотрим, как это увидят редакторы, mypy и другие инструменты.
|
||||
Сначала посмотрим, как это увидят редактор кода, mypy и другие инструменты.
|
||||
|
||||
`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он включает все поля обеих моделей.
|
||||
`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он будет включать все поля обеих моделей.
|
||||
|
||||
Мы аннотируем возвращаемый тип функции как `BaseUser`, но фактически возвращаем экземпляр `UserIn`.
|
||||
|
||||
Редактор, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.
|
||||
Редактор кода, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.
|
||||
|
||||
### Фильтрация данных FastAPI { #fastapi-data-filtering }
|
||||
|
||||
Теперь, для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.
|
||||
Теперь для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.
|
||||
|
||||
FastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы вернуть гораздо больше данных, чем ожидали.
|
||||
FastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы в итоге вернуть намного больше данных, чем ожидали.
|
||||
|
||||
Таким образом вы получаете лучшее из обоих миров: аннотации типов с **поддержкой инструментов** и **фильтрацию данных**.
|
||||
|
||||
@@ -171,17 +171,17 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
<img src="/img/tutorial/response-model/image01.png">
|
||||
|
||||
И обе модели используются в интерактивной документации API:
|
||||
И обе модели будут использоваться в интерактивной документации API:
|
||||
|
||||
<img src="/img/tutorial/response-model/image02.png">
|
||||
|
||||
## Другие аннотации возвращаемых типов { #other-return-type-annotations }
|
||||
|
||||
Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор, mypy и т. д.).
|
||||
Бывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор кода, mypy и т.д.).
|
||||
|
||||
### Возврат Response напрямую { #return-a-response-directly }
|
||||
|
||||
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
|
||||
Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}.
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *}
|
||||
|
||||
@@ -195,7 +195,7 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *}
|
||||
|
||||
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот случай.
|
||||
Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай.
|
||||
|
||||
### Некорректные аннотации возвращаемых типов { #invalid-return-type-annotations }
|
||||
|
||||
@@ -209,15 +209,15 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
### Отключить модель ответа { #disable-response-model }
|
||||
|
||||
Продолжая пример выше, вы можете не хотеть использовать стандартную валидацию данных, документацию, фильтрацию и т.д., выполняемые FastAPI.
|
||||
Продолжая пример выше, вы можете не хотеть использовать стандартные валидацию данных, документирование, фильтрацию и т.п., выполняемые FastAPI.
|
||||
|
||||
Но при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов (редакторы, проверки типов вроде mypy).
|
||||
Но при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов вроде редакторов кода и инструментов проверки типов (например, mypy).
|
||||
|
||||
В этом случае вы можете отключить генерацию модели ответа, установив `response_model=None`:
|
||||
|
||||
{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
|
||||
|
||||
Так FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, не влияя на ваше приложение FastAPI. 🤓
|
||||
Так FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, которые вам нужны, без влияния на ваше приложение FastAPI. 🤓
|
||||
|
||||
## Параметры кодирования модели ответа { #response-model-encoding-parameters }
|
||||
|
||||
@@ -252,20 +252,6 @@ FastAPI делает несколько вещей внутри вместе с
|
||||
|
||||
/// info | Информация
|
||||
|
||||
В Pydantic v1 метод назывался `.dict()`, в Pydantic v2 он был помечен как устаревший (но всё ещё поддерживается) и переименован в `.model_dump()`.
|
||||
|
||||
Примеры здесь используют `.dict()` для совместимости с Pydantic v1, но если вы используете Pydantic v2, применяйте `.model_dump()`.
|
||||
|
||||
///
|
||||
|
||||
/// info | Информация
|
||||
|
||||
FastAPI использует метод `.dict()` у Pydantic-моделей с <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">параметром `exclude_unset`</a>, чтобы добиться такого поведения.
|
||||
|
||||
///
|
||||
|
||||
/// info | Информация
|
||||
|
||||
Вы также можете использовать:
|
||||
|
||||
* `response_model_exclude_defaults=True`
|
||||
@@ -312,7 +298,7 @@ FastAPI достаточно умен (на самом деле, это Pydantic
|
||||
|
||||
Обратите внимание, что значения по умолчанию могут быть любыми, не только `None`.
|
||||
|
||||
Это может быть список (`[]`), число с плавающей точкой `10.5` и т. д.
|
||||
Это может быть список (`[]`), число с плавающей точкой `10.5` и т.д.
|
||||
|
||||
///
|
||||
|
||||
@@ -346,7 +332,7 @@ FastAPI достаточно умен (на самом деле, это Pydantic
|
||||
|
||||
#### Использование `list` вместо `set` { #using-lists-instead-of-sets }
|
||||
|
||||
Если вы забыли использовать `set` и применили `list` или `tuple`, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:
|
||||
Если вы забыли использовать `set` и применили `list` или `tuple` вместо него, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:
|
||||
|
||||
{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
|
||||
|
||||
|
||||
@@ -8,36 +8,14 @@
|
||||
|
||||
Вы можете объявить `examples` для модели Pydantic, которые будут добавлены в сгенерированную JSON Schema.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
|
||||
|
||||
////
|
||||
|
||||
Эта дополнительная информация будет добавлена как есть в выходную **JSON Schema** этой модели и будет использоваться в документации API.
|
||||
|
||||
//// tab | Pydantic v2
|
||||
|
||||
В Pydantic версии 2 вы будете использовать атрибут `model_config`, который принимает `dict`, как описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Документации Pydantic: Конфигурация</a>.
|
||||
Вы можете использовать атрибут `model_config`, который принимает `dict`, как описано в <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Документации Pydantic: Конфигурация</a>.
|
||||
|
||||
Вы можете задать `"json_schema_extra"` с `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
|
||||
|
||||
////
|
||||
|
||||
//// tab | Pydantic v1
|
||||
|
||||
В Pydantic версии 1 вы будете использовать внутренний класс `Config` и `schema_extra`, как описано в <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">Документации Pydantic: Настройка схемы</a>.
|
||||
|
||||
Вы можете задать `schema_extra` со `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.
|
||||
|
||||
////
|
||||
|
||||
/// tip | Подсказка
|
||||
|
||||
Вы можете использовать тот же приём, чтобы расширить JSON Schema и добавить свою собственную дополнительную информацию.
|
||||
@@ -124,7 +102,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
|
||||
|
||||
Ключи `dict` идентифицируют каждый пример, а каждое значение — это ещё один `dict`.
|
||||
|
||||
Каждый конкретный пример‑`dict` в `examples` может содержать:
|
||||
Каждый конкретный пример `dict` в `examples` может содержать:
|
||||
|
||||
* `summary`: Краткое описание примера.
|
||||
* `description`: Подробное описание, которое может содержать текст в Markdown.
|
||||
@@ -135,7 +113,7 @@ OpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) доб
|
||||
|
||||
{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
|
||||
|
||||
### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }
|
||||
### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }
|
||||
|
||||
С `openapi_examples`, добавленным в `Body()`, страница `/docs` будет выглядеть так:
|
||||
|
||||
@@ -213,7 +191,7 @@ OpenAPI также добавила поля `example` и `examples` в друг
|
||||
|
||||
### Swagger UI и специфичные для OpenAPI `examples` { #swagger-ui-and-openapi-specific-examples }
|
||||
|
||||
Раньше, поскольку Swagger UI не поддерживал несколько примеров JSON Schema (по состоянию на 2023-08-26), у пользователей не было способа показать несколько примеров в документации.
|
||||
Теперь, поскольку Swagger UI не поддерживал несколько примеров JSON Schema (по состоянию на 2023-08-26), у пользователей не было способа показать несколько примеров в документации.
|
||||
|
||||
Чтобы решить это, FastAPI `0.103.0` **добавил поддержку** объявления того же старого, **специфичного для OpenAPI**, поля `examples` с новым параметром `openapi_examples`. 🤓
|
||||
|
||||
|
||||
@@ -4,10 +4,16 @@ Translate to Turkish (Türkçe).
|
||||
|
||||
Language code: tr.
|
||||
|
||||
### Core principle
|
||||
|
||||
Don't translate word-by-word. Rewrite naturally in Turkish as if writing the doc from scratch. Preserve meaning, but prioritize fluency over literal accuracy.
|
||||
|
||||
### Grammar and tone
|
||||
|
||||
- Use instructional Turkish, consistent with existing Turkish docs.
|
||||
- Use imperative/guide language when appropriate (e.g. “açalım”, “gidin”, “kopyalayalım”).
|
||||
- Use imperative/guide language (e.g. "açalım", "gidin", "kopyalayalım", "bir bakalım").
|
||||
- Avoid filler words and overly long sentences.
|
||||
- Ensure sentences make sense in Turkish context — adjust structure, conjunctions, and verb forms as needed for natural flow (e.g. use "Ancak" instead of "Ve" when connecting contrasting sentences, use "-maktadır/-mektedir" for formal statements).
|
||||
|
||||
### Headings
|
||||
|
||||
@@ -15,13 +21,23 @@ Language code: tr.
|
||||
|
||||
### Quotes
|
||||
|
||||
- Alıntı stili mevcut Türkçe dokümanlarla tutarlı tutun (genellikle metin içinde ASCII tırnak işaretleri kullanılır).
|
||||
- Satır içi kod, kod blokları, URL'ler veya dosya yolları içindeki tırnak işaretlerini asla değiştirmeyin.
|
||||
- Keep quote style consistent with existing Turkish docs (typically ASCII quotes in text).
|
||||
- Never modify quotes inside inline code, code blocks, URLs, or file paths.
|
||||
|
||||
### Ellipsis
|
||||
|
||||
- Üç nokta (...) stili mevcut Türkçe dokümanlarla tutarlı tutun.
|
||||
- Kod, URL veya CLI örneklerindeki `...` ifadesini asla değiştirmeyin.
|
||||
- Keep ellipsis style (`...`) consistent with existing Turkish docs.
|
||||
- Never modify `...` in code, URLs, or CLI examples.
|
||||
|
||||
### Consistency
|
||||
|
||||
- Use the same translation for the same term throughout the document.
|
||||
- If you translate a concept one way, keep it consistent across all occurrences.
|
||||
|
||||
### Links and references
|
||||
|
||||
- Never modify link syntax like `{.internal-link target=_blank}`.
|
||||
- Keep markdown link structure intact: `[text](url){.internal-link}`.
|
||||
|
||||
### Preferred translations / glossary
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from a2wsgi import WSGIMiddleware
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.wsgi import WSGIMiddleware
|
||||
from flask import Flask, request
|
||||
from markupsafe import escape
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from starlette.middleware.wsgi import WSGIMiddleware as WSGIMiddleware # noqa
|
||||
from starlette.middleware.wsgi import (
|
||||
WSGIMiddleware as WSGIMiddleware,
|
||||
) # pragma: no cover # noqa
|
||||
|
||||
@@ -178,6 +178,7 @@ tests = [
|
||||
"strawberry-graphql>=0.200.0,<1.0.0",
|
||||
"types-orjson==3.6.2",
|
||||
"types-ujson==5.10.0.20240515",
|
||||
"a2wsgi>=1.9.0,<=2.0.0",
|
||||
]
|
||||
translations = [
|
||||
"gitpython==3.1.45",
|
||||
|
||||
16
uv.lock
generated
16
uv.lock
generated
@@ -7,6 +7,18 @@ resolution-markers = [
|
||||
"python_full_version < '3.10'",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "a2wsgi"
|
||||
version = "1.10.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9a/cb/822c56fbea97e9eee201a2e434a80437f6750ebcb1ed307ee3a0a7505b14/a2wsgi-1.10.10.tar.gz", hash = "sha256:a5bcffb52081ba39df0d5e9a884fc6f819d92e3a42389343ba77cbf809fe1f45", size = 18799, upload-time = "2025-06-18T09:00:10.843Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/02/d5/349aba3dc421e73cbd4958c0ce0a4f1aa3a738bc0d7de75d2f40ed43a535/a2wsgi-1.10.10-py3-none-any.whl", hash = "sha256:d2b21379479718539dc15fce53b876251a0efe7615352dfe49f6ad1bc507848d", size = 17389, upload-time = "2025-06-18T09:00:09.676Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ag-ui-protocol"
|
||||
version = "0.1.10"
|
||||
@@ -1058,6 +1070,7 @@ standard-no-fastapi-cloud-cli = [
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "a2wsgi" },
|
||||
{ name = "anyio", extra = ["trio"] },
|
||||
{ name = "black" },
|
||||
{ name = "cairosvg" },
|
||||
@@ -1131,6 +1144,7 @@ github-actions = [
|
||||
{ name = "smokeshow" },
|
||||
]
|
||||
tests = [
|
||||
{ name = "a2wsgi" },
|
||||
{ name = "anyio", extra = ["trio"] },
|
||||
{ name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version < '3.10'" },
|
||||
{ name = "coverage", version = "7.13.1", source = { registry = "https://pypi.org/simple" }, extra = ["toml"], marker = "python_full_version >= '3.10'" },
|
||||
@@ -1197,6 +1211,7 @@ provides-extras = ["standard", "standard-no-fastapi-cloud-cli", "all"]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "a2wsgi", specifier = ">=1.9.0,<=2.0.0" },
|
||||
{ name = "anyio", extras = ["trio"], specifier = ">=3.2.1,<5.0.0" },
|
||||
{ name = "black", specifier = "==25.1.0" },
|
||||
{ name = "cairosvg", specifier = "==2.8.2" },
|
||||
@@ -1266,6 +1281,7 @@ github-actions = [
|
||||
{ name = "smokeshow", specifier = ">=0.5.0" },
|
||||
]
|
||||
tests = [
|
||||
{ name = "a2wsgi", specifier = ">=1.9.0,<=2.0.0" },
|
||||
{ name = "anyio", extras = ["trio"], specifier = ">=3.2.1,<5.0.0" },
|
||||
{ name = "coverage", extras = ["toml"], specifier = ">=6.5.0,<8.0" },
|
||||
{ name = "dirty-equals", specifier = "==0.9.0" },
|
||||
|
||||
Reference in New Issue
Block a user