From 7dc1be8b8815c5ea1d09325a973f6af7b531c62b Mon Sep 17 00:00:00 2001 From: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Date: Sat, 14 Feb 2026 09:12:41 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=90=20Update=20translations=20for=20fr?= =?UTF-8?q?=20(update-all=20and=20add-missing)=20(#14920)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update all * Add missing * 🎹 Auto format --------- Co-authored-by: github-actions[bot] --- docs/fr/docs/_llm-test.md | 503 ++++++++++ docs/fr/docs/about/index.md | 3 + docs/fr/docs/advanced/additional-responses.md | 6 +- .../docs/advanced/additional-status-codes.md | 2 +- .../fr/docs/advanced/advanced-dependencies.md | 163 ++++ .../fr/docs/advanced/advanced-python-types.md | 61 ++ docs/fr/docs/advanced/async-tests.md | 99 ++ docs/fr/docs/advanced/behind-a-proxy.md | 466 ++++++++++ docs/fr/docs/advanced/custom-response.md | 312 +++++++ docs/fr/docs/advanced/dataclasses.md | 95 ++ docs/fr/docs/advanced/events.md | 165 ++++ docs/fr/docs/advanced/generate-clients.md | 208 +++++ docs/fr/docs/advanced/middleware.md | 97 ++ docs/fr/docs/advanced/openapi-callbacks.md | 186 ++++ docs/fr/docs/advanced/openapi-webhooks.md | 55 ++ .../path-operation-advanced-configuration.md | 16 +- .../advanced/response-change-status-code.md | 31 + docs/fr/docs/advanced/response-cookies.md | 51 ++ docs/fr/docs/advanced/response-directly.md | 4 +- docs/fr/docs/advanced/response-headers.md | 41 + .../docs/advanced/security/http-basic-auth.md | 107 +++ docs/fr/docs/advanced/security/index.md | 19 + .../docs/advanced/security/oauth2-scopes.md | 274 ++++++ docs/fr/docs/advanced/settings.md | 302 ++++++ docs/fr/docs/advanced/sub-applications.md | 67 ++ docs/fr/docs/advanced/templates.md | 126 +++ docs/fr/docs/advanced/testing-dependencies.md | 52 ++ docs/fr/docs/advanced/testing-events.md | 11 + docs/fr/docs/advanced/testing-websockets.md | 13 + .../docs/advanced/using-request-directly.md | 56 ++ docs/fr/docs/advanced/websockets.md | 186 ++++ docs/fr/docs/advanced/wsgi.md | 51 ++ docs/fr/docs/alternatives.md | 152 ++- docs/fr/docs/async.md | 180 ++-- docs/fr/docs/deployment/cloud.md | 24 + docs/fr/docs/deployment/concepts.md | 321 +++++++ docs/fr/docs/deployment/docker.md | 10 +- docs/fr/docs/deployment/fastapicloud.md | 65 ++ docs/fr/docs/deployment/https.md | 2 +- docs/fr/docs/deployment/server-workers.md | 139 +++ docs/fr/docs/environment-variables.md | 298 ++++++ docs/fr/docs/fastapi-cli.md | 75 ++ docs/fr/docs/features.md | 198 ++-- docs/fr/docs/help-fastapi.md | 258 ++++-- docs/fr/docs/history-design-future.md | 22 +- .../authentication-error-status-code.md | 17 + docs/fr/docs/how-to/conditional-openapi.md | 56 ++ docs/fr/docs/how-to/configure-swagger-ui.md | 70 ++ docs/fr/docs/how-to/custom-docs-ui-assets.md | 185 ++++ .../docs/how-to/custom-request-and-route.md | 109 +++ docs/fr/docs/how-to/extending-openapi.md | 80 ++ docs/fr/docs/how-to/general.md | 39 + docs/fr/docs/how-to/graphql.md | 60 ++ docs/fr/docs/how-to/index.md | 13 + ...migrate-from-pydantic-v1-to-pydantic-v2.md | 135 +++ .../docs/how-to/separate-openapi-schemas.md | 102 +++ docs/fr/docs/how-to/testing-database.md | 7 + docs/fr/docs/index.md | 10 +- docs/fr/docs/learn/index.md | 2 +- docs/fr/docs/python-types.md | 206 +---- docs/fr/docs/resources/index.md | 3 + docs/fr/docs/translation-banner.md | 11 + docs/fr/docs/tutorial/background-tasks.md | 8 +- docs/fr/docs/tutorial/bigger-applications.md | 504 ++++++++++ docs/fr/docs/tutorial/body-fields.md | 61 ++ docs/fr/docs/tutorial/body-multiple-params.md | 6 - docs/fr/docs/tutorial/body-nested-models.md | 220 +++++ docs/fr/docs/tutorial/body-updates.md | 100 ++ docs/fr/docs/tutorial/body.md | 14 +- docs/fr/docs/tutorial/cookie-param-models.md | 76 ++ docs/fr/docs/tutorial/cookie-params.md | 45 + docs/fr/docs/tutorial/cors.md | 88 ++ docs/fr/docs/tutorial/debugging.md | 6 +- .../dependencies/classes-as-dependencies.md | 288 ++++++ ...pendencies-in-path-operation-decorators.md | 69 ++ .../dependencies/dependencies-with-yield.md | 289 ++++++ .../dependencies/global-dependencies.md | 15 + docs/fr/docs/tutorial/dependencies/index.md | 250 +++++ .../tutorial/dependencies/sub-dependencies.md | 105 +++ docs/fr/docs/tutorial/encoder.md | 35 + docs/fr/docs/tutorial/extra-data-types.md | 62 ++ docs/fr/docs/tutorial/extra-models.md | 211 +++++ docs/fr/docs/tutorial/first-steps.md | 24 +- docs/fr/docs/tutorial/handling-errors.md | 244 +++++ docs/fr/docs/tutorial/header-param-models.md | 72 ++ docs/fr/docs/tutorial/header-params.md | 91 ++ docs/fr/docs/tutorial/metadata.md | 120 +++ docs/fr/docs/tutorial/middleware.md | 95 ++ .../tutorial/path-operation-configuration.md | 107 +++ .../path-params-numeric-validations.md | 16 +- docs/fr/docs/tutorial/path-params.md | 30 +- docs/fr/docs/tutorial/query-param-models.md | 68 ++ .../tutorial/query-params-str-validations.md | 42 +- docs/fr/docs/tutorial/query-params.md | 8 +- docs/fr/docs/tutorial/request-files.md | 176 ++++ docs/fr/docs/tutorial/request-form-models.md | 78 ++ .../docs/tutorial/request-forms-and-files.md | 41 + docs/fr/docs/tutorial/request-forms.md | 73 ++ docs/fr/docs/tutorial/response-model.md | 343 +++++++ docs/fr/docs/tutorial/response-status-code.md | 101 ++ docs/fr/docs/tutorial/schema-extra-example.md | 202 ++++ docs/fr/docs/tutorial/security/first-steps.md | 203 ++++ .../tutorial/security/get-current-user.md | 105 +++ docs/fr/docs/tutorial/security/index.md | 106 +++ docs/fr/docs/tutorial/security/oauth2-jwt.md | 277 ++++++ .../docs/tutorial/security/simple-oauth2.md | 289 ++++++ docs/fr/docs/tutorial/sql-databases.md | 357 ++++++++ docs/fr/docs/tutorial/static-files.md | 40 + docs/fr/docs/tutorial/testing.md | 193 ++++ docs/fr/docs/virtual-environments.md | 864 ++++++++++++++++++ 110 files changed, 12889 insertions(+), 605 deletions(-) create mode 100644 docs/fr/docs/_llm-test.md create mode 100644 docs/fr/docs/about/index.md create mode 100644 docs/fr/docs/advanced/advanced-dependencies.md create mode 100644 docs/fr/docs/advanced/advanced-python-types.md create mode 100644 docs/fr/docs/advanced/async-tests.md create mode 100644 docs/fr/docs/advanced/behind-a-proxy.md create mode 100644 docs/fr/docs/advanced/custom-response.md create mode 100644 docs/fr/docs/advanced/dataclasses.md create mode 100644 docs/fr/docs/advanced/events.md create mode 100644 docs/fr/docs/advanced/generate-clients.md create mode 100644 docs/fr/docs/advanced/middleware.md create mode 100644 docs/fr/docs/advanced/openapi-callbacks.md create mode 100644 docs/fr/docs/advanced/openapi-webhooks.md create mode 100644 docs/fr/docs/advanced/response-change-status-code.md create mode 100644 docs/fr/docs/advanced/response-cookies.md create mode 100644 docs/fr/docs/advanced/response-headers.md create mode 100644 docs/fr/docs/advanced/security/http-basic-auth.md create mode 100644 docs/fr/docs/advanced/security/index.md create mode 100644 docs/fr/docs/advanced/security/oauth2-scopes.md create mode 100644 docs/fr/docs/advanced/settings.md create mode 100644 docs/fr/docs/advanced/sub-applications.md create mode 100644 docs/fr/docs/advanced/templates.md create mode 100644 docs/fr/docs/advanced/testing-dependencies.md create mode 100644 docs/fr/docs/advanced/testing-events.md create mode 100644 docs/fr/docs/advanced/testing-websockets.md create mode 100644 docs/fr/docs/advanced/using-request-directly.md create mode 100644 docs/fr/docs/advanced/websockets.md create mode 100644 docs/fr/docs/advanced/wsgi.md create mode 100644 docs/fr/docs/deployment/cloud.md create mode 100644 docs/fr/docs/deployment/concepts.md create mode 100644 docs/fr/docs/deployment/fastapicloud.md create mode 100644 docs/fr/docs/deployment/server-workers.md create mode 100644 docs/fr/docs/environment-variables.md create mode 100644 docs/fr/docs/fastapi-cli.md create mode 100644 docs/fr/docs/how-to/authentication-error-status-code.md create mode 100644 docs/fr/docs/how-to/conditional-openapi.md create mode 100644 docs/fr/docs/how-to/configure-swagger-ui.md create mode 100644 docs/fr/docs/how-to/custom-docs-ui-assets.md create mode 100644 docs/fr/docs/how-to/custom-request-and-route.md create mode 100644 docs/fr/docs/how-to/extending-openapi.md create mode 100644 docs/fr/docs/how-to/general.md create mode 100644 docs/fr/docs/how-to/graphql.md create mode 100644 docs/fr/docs/how-to/index.md create mode 100644 docs/fr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md create mode 100644 docs/fr/docs/how-to/separate-openapi-schemas.md create mode 100644 docs/fr/docs/how-to/testing-database.md create mode 100644 docs/fr/docs/resources/index.md create mode 100644 docs/fr/docs/translation-banner.md create mode 100644 docs/fr/docs/tutorial/bigger-applications.md create mode 100644 docs/fr/docs/tutorial/body-fields.md create mode 100644 docs/fr/docs/tutorial/body-nested-models.md create mode 100644 docs/fr/docs/tutorial/body-updates.md create mode 100644 docs/fr/docs/tutorial/cookie-param-models.md create mode 100644 docs/fr/docs/tutorial/cookie-params.md create mode 100644 docs/fr/docs/tutorial/cors.md create mode 100644 docs/fr/docs/tutorial/dependencies/classes-as-dependencies.md create mode 100644 docs/fr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md create mode 100644 docs/fr/docs/tutorial/dependencies/dependencies-with-yield.md create mode 100644 docs/fr/docs/tutorial/dependencies/global-dependencies.md create mode 100644 docs/fr/docs/tutorial/dependencies/index.md create mode 100644 docs/fr/docs/tutorial/dependencies/sub-dependencies.md create mode 100644 docs/fr/docs/tutorial/encoder.md create mode 100644 docs/fr/docs/tutorial/extra-data-types.md create mode 100644 docs/fr/docs/tutorial/extra-models.md create mode 100644 docs/fr/docs/tutorial/handling-errors.md create mode 100644 docs/fr/docs/tutorial/header-param-models.md create mode 100644 docs/fr/docs/tutorial/header-params.md create mode 100644 docs/fr/docs/tutorial/metadata.md create mode 100644 docs/fr/docs/tutorial/middleware.md create mode 100644 docs/fr/docs/tutorial/path-operation-configuration.md create mode 100644 docs/fr/docs/tutorial/query-param-models.md create mode 100644 docs/fr/docs/tutorial/request-files.md create mode 100644 docs/fr/docs/tutorial/request-form-models.md create mode 100644 docs/fr/docs/tutorial/request-forms-and-files.md create mode 100644 docs/fr/docs/tutorial/request-forms.md create mode 100644 docs/fr/docs/tutorial/response-model.md create mode 100644 docs/fr/docs/tutorial/response-status-code.md create mode 100644 docs/fr/docs/tutorial/schema-extra-example.md create mode 100644 docs/fr/docs/tutorial/security/first-steps.md create mode 100644 docs/fr/docs/tutorial/security/get-current-user.md create mode 100644 docs/fr/docs/tutorial/security/index.md create mode 100644 docs/fr/docs/tutorial/security/oauth2-jwt.md create mode 100644 docs/fr/docs/tutorial/security/simple-oauth2.md create mode 100644 docs/fr/docs/tutorial/sql-databases.md create mode 100644 docs/fr/docs/tutorial/static-files.md create mode 100644 docs/fr/docs/tutorial/testing.md create mode 100644 docs/fr/docs/virtual-environments.md diff --git a/docs/fr/docs/_llm-test.md b/docs/fr/docs/_llm-test.md new file mode 100644 index 000000000..4fdc67738 --- /dev/null +++ b/docs/fr/docs/_llm-test.md @@ -0,0 +1,503 @@ +# Fichier de test LLM { #llm-test-file } + +Ce document teste si le LLM, qui traduit la documentation, comprend le `general_prompt` dans `scripts/translate.py` et l’invite spĂ©cifique Ă  la langue dans `docs/{language code}/llm-prompt.md`. L’invite spĂ©cifique Ă  la langue est ajoutĂ©e Ă  la fin de `general_prompt`. + +Les tests ajoutĂ©s ici seront visibles par tous les concepteurs d’invites spĂ©cifiques Ă  chaque langue. + +Utiliser comme suit : + +* Avoir une invite spĂ©cifique Ă  la langue - `docs/{language code}/llm-prompt.md`. +* Effectuer une nouvelle traduction de ce document dans votre langue cible souhaitĂ©e (voir par exemple la commande `translate-page` de `translate.py`). Cela crĂ©era la traduction sous `docs/{language code}/docs/_llm-test.md`. +* VĂ©rifier si tout est correct dans la traduction. +* Si nĂ©cessaire, amĂ©liorer votre invite spĂ©cifique Ă  la langue, l’invite gĂ©nĂ©rale, ou le document anglais. +* Corriger ensuite manuellement les problĂšmes restants dans la traduction, afin que ce soit une bonne traduction. +* Retraduire, en ayant la bonne traduction en place. Le rĂ©sultat idĂ©al serait que le LLM ne fasse plus aucun changement Ă  la traduction. Cela signifie que l’invite gĂ©nĂ©rale et votre invite spĂ©cifique Ă  la langue sont aussi bonnes que possible (il fera parfois quelques changements apparemment alĂ©atoires, la raison Ă©tant que les LLM ne sont pas des algorithmes dĂ©terministes). + +Les tests : + +## Extraits de code { #code-snippets } + +//// tab | Test + +Ceci est un extrait de code : `foo`. Et ceci est un autre extrait de code : `bar`. Et encore un autre : `baz quux`. + +//// + +//// tab | Info + +Le contenu des extraits de code doit ĂȘtre laissĂ© tel quel. + +Voir la section `### Content of code snippets` dans l’invite gĂ©nĂ©rale dans `scripts/translate.py`. + +//// + +## Guillemets { #quotes } + +//// tab | Test + +Hier, mon ami a Ă©crit : « Si vous Ă©crivez « incorrectly » correctement, vous l’avez Ă©crit de façon incorrecte ». À quoi j’ai rĂ©pondu : « Correct, mais ‘incorrectly’ est incorrectement non pas ‘« incorrectly »’ ». + +/// note | Remarque + +Le LLM traduira probablement ceci de maniĂšre erronĂ©e. Il est seulement intĂ©ressant de voir s’il conserve la traduction corrigĂ©e lors d’une retraduction. + +/// + +//// + +//// tab | Info + +Le concepteur de l’invite peut choisir s’il souhaite convertir les guillemets neutres en guillemets typographiques. Il est acceptable de les laisser tels quels. + +Voir par exemple la section `### Quotes` dans `docs/de/llm-prompt.md`. + +//// + +## Guillemets dans les extraits de code { #quotes-in-code-snippets } + +//// tab | Test + +`pip install "foo[bar]"` + +Exemples de littĂ©raux de chaĂźne dans des extraits de code : `"this"`, `'that'`. + +Un exemple difficile de littĂ©raux de chaĂźne dans des extraits de code : `f"I like {'oranges' if orange else "apples"}"` + +Hardcore: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"` + +//// + +//// tab | Info + +... Cependant, les guillemets Ă  l’intĂ©rieur des extraits de code doivent rester tels quels. + +//// + +## Blocs de code { #code-blocks } + +//// tab | Test + +Un exemple de code Bash ... + +```bash +# Afficher un message de bienvenue Ă  l'univers +echo "Hello universe" +``` + +... et un exemple de code console ... + +```console +$ fastapi run main.py + FastAPI Starting server + Searching for package file structure +``` + +... et un autre exemple de code console ... + +```console +// CrĂ©er un rĂ©pertoire "Code" +$ mkdir code +// Aller dans ce rĂ©pertoire +$ cd code +``` + +... et un exemple de code Python ... + +```Python +wont_work() # Cela ne fonctionnera pas đŸ˜± +works(foo="bar") # Cela fonctionne 🎉 +``` + +... et c’est tout. + +//// + +//// tab | Info + +Le code dans les blocs de code ne doit pas ĂȘtre modifiĂ©, Ă  l’exception des commentaires. + +Voir la section `### Content of code blocks` dans l’invite gĂ©nĂ©rale dans `scripts/translate.py`. + +//// + +## Onglets et encadrĂ©s colorĂ©s { #tabs-and-colored-boxes } + +//// tab | Test + +/// info | Info +Du texte +/// + +/// note | Remarque +Du texte +/// + +/// note | DĂ©tails techniques +Du texte +/// + +/// check | VĂ©rifications +Du texte +/// + +/// tip | Astuce +Du texte +/// + +/// warning | Alertes +Du texte +/// + +/// danger | Danger +Du texte +/// + +//// + +//// tab | Info + +Les onglets et les blocs « Info »/« Note »/« Warning »/etc. doivent avoir la traduction de leur titre ajoutĂ©e aprĂšs une barre verticale (« | »). + +Voir les sections `### Special blocks` et `### Tab blocks` dans l’invite gĂ©nĂ©rale dans `scripts/translate.py`. + +//// + +## Liens Web et internes { #web-and-internal-links } + +//// tab | Test + +Le texte du lien doit ĂȘtre traduit, l’adresse du lien doit rester inchangĂ©e : + +* [Lien vers le titre ci-dessus](#code-snippets) +* [Lien interne](index.md#installation){.internal-link target=_blank} +* Lien externe +* Lien vers une feuille de style +* Lien vers un script +* Lien vers une image + +Le texte du lien doit ĂȘtre traduit, l’adresse du lien doit pointer vers la traduction : + +* Lien FastAPI + +//// + +//// tab | Info + +Les liens doivent ĂȘtre traduits, mais leur adresse doit rester inchangĂ©e. Exception faite des liens absolus vers des pages de la documentation FastAPI. Dans ce cas, il faut pointer vers la traduction. + +Voir la section `### Links` dans l’invite gĂ©nĂ©rale dans `scripts/translate.py`. + +//// + +## ÉlĂ©ments HTML « abbr » { #html-abbr-elements } + +//// tab | Test + +Voici quelques Ă©lĂ©ments entourĂ©s d’un Ă©lĂ©ment HTML « abbr » (certains sont inventĂ©s) : + +### L’abbr fournit une expression complĂšte { #the-abbr-gives-a-full-phrase } + +* GTD +* lt +* XWT +* PSGI + +### L’abbr donne une expression complĂšte et une explication { #the-abbr-gives-a-full-phrase-and-an-explanation } + +* MDN +* I/O. + +//// + +//// tab | Info + +Les attributs « title » des Ă©lĂ©ments « abbr » sont traduits en suivant des consignes spĂ©cifiques. + +Les traductions peuvent ajouter leurs propres Ă©lĂ©ments « abbr » que le LLM ne doit pas supprimer. Par exemple pour expliquer des mots anglais. + +Voir la section `### HTML abbr elements` dans l’invite gĂ©nĂ©rale dans `scripts/translate.py`. + +//// + +## ÉlĂ©ments HTML « dfn » { #html-dfn-elements } + +* grappe +* Apprentissage profond + +## Titres { #headings } + +//// tab | Test + +### CrĂ©er une application Web - un tutoriel { #develop-a-webapp-a-tutorial } + +Bonjour. + +### Annotations de type et indications de type { #type-hints-and-annotations } + +Rebonjour. + +### Superclasses et sous-classes { #super-and-subclasses } + +Rebonjour. + +//// + +//// tab | Info + +La seule rĂšgle stricte pour les titres est que le LLM laisse la partie hachage entre accolades inchangĂ©e, ce qui garantit que les liens ne se rompent pas. + +Voir la section `### Headings` dans l’invite gĂ©nĂ©rale dans `scripts/translate.py`. + +Pour certaines consignes spĂ©cifiques Ă  la langue, voir par exemple la section `### Headings` dans `docs/de/llm-prompt.md`. + +//// + +## Termes utilisĂ©s dans les documents { #terms-used-in-the-docs } + +//// tab | Test + +* vous +* votre + +* p. ex. +* etc. + +* `foo` en tant que `int` +* `bar` en tant que `str` +* `baz` en tant que `list` + +* le Tutoriel - Guide utilisateur +* le Guide utilisateur avancĂ© +* la documentation SQLModel +* la documentation de l’API +* la documentation automatique + +* Data Science +* Apprentissage profond +* Apprentissage automatique +* Injection de dĂ©pendances +* authentification HTTP Basic +* HTTP Digest +* format ISO +* la norme JSON Schema +* le schĂ©ma JSON +* la dĂ©finition de schĂ©ma +* Flux Password +* Mobile + +* dĂ©prĂ©ciĂ© +* conçu +* invalide +* Ă  la volĂ©e +* standard +* par dĂ©faut +* sensible Ă  la casse +* insensible Ă  la casse + +* servir l’application +* servir la page + +* l’app +* l’application + +* la requĂȘte +* la rĂ©ponse +* la rĂ©ponse d’erreur + +* le chemin d’accĂšs +* le dĂ©corateur de chemin d’accĂšs +* la fonction de chemin d’accĂšs + +* le corps +* le corps de la requĂȘte +* le corps de la rĂ©ponse +* le corps JSON +* le corps de formulaire +* le corps de fichier +* le corps de la fonction + +* le paramĂštre +* le paramĂštre de corps +* le paramĂštre de chemin +* le paramĂštre de requĂȘte +* le paramĂštre de cookie +* le paramĂštre d’en-tĂȘte +* le paramĂštre de formulaire +* le paramĂštre de fonction + +* l’évĂ©nement +* l’évĂ©nement de dĂ©marrage +* le dĂ©marrage du serveur +* l’évĂ©nement d’arrĂȘt +* l’évĂ©nement de cycle de vie + +* le gestionnaire +* le gestionnaire d’évĂ©nements +* le gestionnaire d’exceptions +* gĂ©rer + +* le modĂšle +* le modĂšle Pydantic +* le modĂšle de donnĂ©es +* le modĂšle de base de donnĂ©es +* le modĂšle de formulaire +* l’objet modĂšle + +* la classe +* la classe de base +* la classe parente +* la sous-classe +* la classe enfant +* la classe sƓur +* la mĂ©thode de classe + +* l’en-tĂȘte +* les en-tĂȘtes +* l’en-tĂȘte d’autorisation +* l’en-tĂȘte `Authorization` +* l’en-tĂȘte transfĂ©rĂ© + +* le systĂšme d’injection de dĂ©pendances +* la dĂ©pendance +* l’élĂ©ment dĂ©pendable +* le dĂ©pendant + +* liĂ© aux E/S +* liĂ© au processeur +* concurrence +* parallĂ©lisme +* multi-traitement + +* la variable d’env +* la variable d’environnement +* le `PATH` +* la variable `PATH` + +* l’authentification +* le fournisseur d’authentification +* l’autorisation +* le formulaire d’autorisation +* le fournisseur d’autorisation +* l’utilisateur s’authentifie +* le systĂšme authentifie l’utilisateur + +* la CLI +* l’interface en ligne de commande + +* le serveur +* le client + +* le fournisseur cloud +* le service cloud + +* le dĂ©veloppement +* les Ă©tapes de dĂ©veloppement + +* le dict +* le dictionnaire +* l’énumĂ©ration +* l’enum +* le membre d’enum + +* l’encodeur +* le dĂ©codeur +* encoder +* dĂ©coder + +* l’exception +* lever + +* l’expression +* l’instruction + +* le frontend +* le backend + +* la discussion GitHub +* le ticket GitHub + +* la performance +* l’optimisation des performances + +* le type de retour +* la valeur de retour + +* la sĂ©curitĂ© +* le schĂ©ma de sĂ©curitĂ© + +* la tĂąche +* la tĂąche d’arriĂšre-plan +* la fonction de tĂąche + +* le template +* le moteur de templates + +* l’annotation de type +* l’annotation de type + +* le worker du serveur +* le worker Uvicorn +* le Worker Gunicorn +* le processus worker +* la classe de worker +* la charge de travail + +* le dĂ©ploiement +* dĂ©ployer + +* le SDK +* le kit de dĂ©veloppement logiciel + +* le `APIRouter` +* le `requirements.txt` +* le jeton Bearer +* le changement majeur incompatible +* le bogue +* le bouton +* l’appelable +* le code +* le commit +* le gestionnaire de contexte +* la coroutine +* la session de base de donnĂ©es +* le disque +* le domaine +* le moteur +* le faux X +* la mĂ©thode HTTP GET +* l’élĂ©ment +* la bibliothĂšque +* le cycle de vie +* le verrou +* le middleware +* l’application mobile +* le module +* le montage +* le rĂ©seau +* l’origine +* la surcharge +* le payload +* le processeur +* la propriĂ©tĂ© +* le proxy +* la pull request +* la requĂȘte +* la RAM +* la machine distante +* le code d’état +* la chaĂźne +* l’étiquette +* le framework Web +* le joker +* retourner +* valider + +//// + +//// tab | Info + +Il s’agit d’une liste non exhaustive et non normative de termes (principalement) techniques prĂ©sents dans les documents. Elle peut aider le concepteur de l’invite Ă  dĂ©terminer pour quels termes le LLM a besoin d’un coup de main. Par exemple, lorsqu’il continue de remplacer une bonne traduction par une traduction sous-optimale. Ou lorsqu’il a des difficultĂ©s Ă  conjuguer/dĂ©cliner un terme dans votre langue. + +Voir par exemple la section `### List of English terms and their preferred German translations` dans `docs/de/llm-prompt.md`. + +//// diff --git a/docs/fr/docs/about/index.md b/docs/fr/docs/about/index.md new file mode 100644 index 000000000..f6ec12a4f --- /dev/null +++ b/docs/fr/docs/about/index.md @@ -0,0 +1,3 @@ +# À propos { #about } + +À propos de FastAPI, de sa conception, de ses sources d'inspiration et plus encore. đŸ€“ diff --git a/docs/fr/docs/advanced/additional-responses.md b/docs/fr/docs/advanced/additional-responses.md index dabcded52..a073dec69 100644 --- a/docs/fr/docs/advanced/additional-responses.md +++ b/docs/fr/docs/advanced/additional-responses.md @@ -8,7 +8,7 @@ Si vous dĂ©butez avec **FastAPI**, vous n'en aurez peut-ĂȘtre pas besoin. /// -Vous pouvez dĂ©clarer des rĂ©ponses supplĂ©mentaires, avec des codes HTTP, des types de mĂ©dias, des descriptions, etc. +Vous pouvez dĂ©clarer des rĂ©ponses supplĂ©mentaires, avec des codes d'Ă©tat supplĂ©mentaires, des types de mĂ©dias, des descriptions, etc. Ces rĂ©ponses supplĂ©mentaires seront incluses dans le schĂ©ma OpenAPI, elles apparaĂźtront donc Ă©galement dans la documentation de l'API. @@ -26,7 +26,7 @@ Chacun de ces `dict` de rĂ©ponse peut avoir une clĂ© `model`, contenant un modĂš 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_py310.py hl[18,22] *} /// note | Remarque @@ -203,7 +203,7 @@ Par exemple, vous pouvez dĂ©clarer une rĂ©ponse avec un code HTTP `404` qui util 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_py310.py hl[20:31] *} Tout sera combinĂ© et inclus dans votre OpenAPI, et affichĂ© dans la documentation de l'API : diff --git a/docs/fr/docs/advanced/additional-status-codes.md b/docs/fr/docs/advanced/additional-status-codes.md index b2befffa8..b9c8ab113 100644 --- a/docs/fr/docs/advanced/additional-status-codes.md +++ b/docs/fr/docs/advanced/additional-status-codes.md @@ -36,6 +36,6 @@ Pour plus de commoditĂ©s, **FastAPI** fournit les objets `starlette.responses` s ## Documents OpenAPI et API { #openapi-and-api-docs } -Si vous renvoyez directement des codes HTTP et des rĂ©ponses supplĂ©mentaires, ils ne seront pas inclus dans le schĂ©ma OpenAPI (la documentation de l'API), car FastAPI n'a aucun moyen de savoir Ă  l'avance ce que vous allez renvoyer. +Si vous renvoyez directement des codes HTTP et des rĂ©ponses supplĂ©mentaires, ils ne seront pas inclus dans le schĂ©ma OpenAPI (les documents de l'API), car FastAPI n'a aucun moyen de savoir Ă  l'avance ce que vous allez renvoyer. Mais vous pouvez documenter cela dans votre code, en utilisant : [RĂ©ponses supplĂ©mentaires](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/fr/docs/advanced/advanced-dependencies.md b/docs/fr/docs/advanced/advanced-dependencies.md new file mode 100644 index 000000000..8afd58b48 --- /dev/null +++ b/docs/fr/docs/advanced/advanced-dependencies.md @@ -0,0 +1,163 @@ +# DĂ©pendances avancĂ©es { #advanced-dependencies } + +## DĂ©pendances paramĂ©trĂ©es { #parameterized-dependencies } + +Toutes les dĂ©pendances que nous avons vues Ă©taient des fonctions ou des classes fixes. + +Mais il peut y avoir des cas oĂč vous souhaitez pouvoir dĂ©finir des paramĂštres sur la dĂ©pendance, sans devoir dĂ©clarer de nombreuses fonctions ou classes diffĂ©rentes. + +Imaginons que nous voulions avoir une dĂ©pendance qui vĂ©rifie si le paramĂštre de requĂȘte `q` contient un contenu fixe. + +Mais nous voulons pouvoir paramĂ©trer ce contenu fixe. + +## Une instance « callable » { #a-callable-instance } + +En Python, il existe un moyen de rendre une instance de classe « callable ». + +Pas la classe elle‑mĂȘme (qui est dĂ©jĂ  un callable), mais une instance de cette classe. + +Pour cela, nous dĂ©clarons une mĂ©thode `__call__` : + +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *} + +Dans ce cas, ce `__call__` est ce que **FastAPI** utilisera pour dĂ©tecter des paramĂštres supplĂ©mentaires et des sous‑dĂ©pendances, et c’est ce qui sera appelĂ© pour transmettre ensuite une valeur au paramĂštre dans votre *fonction de chemin d'accĂšs*. + +## ParamĂ©trer l'instance { #parameterize-the-instance } + +Et maintenant, nous pouvons utiliser `__init__` pour dĂ©clarer les paramĂštres de l’instance, que nous utiliserons pour « paramĂ©trer » la dĂ©pendance : + +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *} + +Dans ce cas, **FastAPI** n’accĂšdera pas Ă  `__init__` et ne s’en souciera pas ; nous l’utiliserons directement dans notre code. + +## CrĂ©er une instance { #create-an-instance } + +Nous pouvons crĂ©er une instance de cette classe avec : + +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *} + +Et de cette façon, nous pouvons « paramĂ©trer » notre dĂ©pendance, qui contient maintenant « bar », en tant qu’attribut `checker.fixed_content`. + +## Utiliser l'instance comme dĂ©pendance { #use-the-instance-as-a-dependency } + +Ensuite, nous pourrions utiliser ce `checker` dans un `Depends(checker)`, au lieu de `Depends(FixedContentQueryChecker)`, car la dĂ©pendance est l’instance, `checker`, et non la classe elle‑mĂȘme. + +Et lors de la rĂ©solution de la dĂ©pendance, **FastAPI** appellera ce `checker` comme ceci : + +```Python +checker(q="somequery") +``` + +... et passera ce que cela renvoie comme valeur de la dĂ©pendance Ă  notre *fonction de chemin d'accĂšs*, en tant que paramĂštre `fixed_content_included` : + +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *} + +/// tip | Astuce + +Tout cela peut sembler artificiel. Et il n’est peut‑ĂȘtre pas encore trĂšs clair en quoi c’est utile. + +Ces exemples sont volontairement simples, mais ils montrent comment tout cela fonctionne. + +Dans les chapitres sur la sĂ©curitĂ©, il existe des fonctions utilitaires implĂ©mentĂ©es de la mĂȘme maniĂšre. + +Si vous avez compris tout cela, vous savez dĂ©jĂ  comment ces outils utilitaires pour la sĂ©curitĂ© fonctionnent en interne. + +/// + +## DĂ©pendances avec `yield`, `HTTPException`, `except` et tĂąches d'arriĂšre‑plan { #dependencies-with-yield-httpexception-except-and-background-tasks } + +/// warning | Alertes + +Vous n’avez trĂšs probablement pas besoin de ces dĂ©tails techniques. + +Ces dĂ©tails sont utiles principalement si vous aviez une application FastAPI antĂ©rieure Ă  la version 0.121.0 et que vous rencontrez des problĂšmes avec des dĂ©pendances utilisant `yield`. + +/// + +Les dĂ©pendances avec `yield` ont Ă©voluĂ© au fil du temps pour couvrir diffĂ©rents cas d’utilisation et corriger certains problĂšmes ; voici un rĂ©sumĂ© de ce qui a changĂ©. + +### DĂ©pendances avec `yield` et `scope` { #dependencies-with-yield-and-scope } + +Dans la version 0.121.0, **FastAPI** a ajoutĂ© la prise en charge de `Depends(scope="function")` pour les dĂ©pendances avec `yield`. + +Avec `Depends(scope="function")`, le code d’arrĂȘt aprĂšs `yield` s’exĂ©cute immĂ©diatement aprĂšs la fin de la *fonction de chemin d'accĂšs*, avant que la rĂ©ponse ne soit renvoyĂ©e au client. + +Et lorsque vous utilisez `Depends(scope="request")` (valeur par dĂ©faut), le code d’arrĂȘt aprĂšs `yield` s’exĂ©cute aprĂšs l’envoi de la rĂ©ponse. + +Vous pouvez en lire davantage dans les documents pour [DĂ©pendances avec `yield` - Sortie anticipĂ©e et `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope). + +### DĂ©pendances avec `yield` et `StreamingResponse`, DĂ©tails techniques { #dependencies-with-yield-and-streamingresponse-technical-details } + +Avant FastAPI 0.118.0, si vous utilisiez une dĂ©pendance avec `yield`, elle exĂ©cutait le code d’arrĂȘt aprĂšs que la *fonction de chemin d'accĂšs* a retournĂ©, mais juste avant d’envoyer la rĂ©ponse. + +L’objectif Ă©tait d’éviter de conserver des ressources plus longtemps que nĂ©cessaire pendant que la rĂ©ponse transitait sur le rĂ©seau. + +Ce changement impliquait aussi que si vous retourniez une `StreamingResponse`, le code d’arrĂȘt de la dĂ©pendance avec `yield` aurait dĂ©jĂ  Ă©tĂ© exĂ©cutĂ©. + +Par exemple, si vous aviez une session de base de donnĂ©es dans une dĂ©pendance avec `yield`, la `StreamingResponse` ne pourrait pas utiliser cette session pendant le streaming des donnĂ©es, car la session aurait dĂ©jĂ  Ă©tĂ© fermĂ©e dans le code d’arrĂȘt aprĂšs `yield`. + +Ce comportement a Ă©tĂ© annulĂ© en 0.118.0, afin que le code d’arrĂȘt aprĂšs `yield` s’exĂ©cute aprĂšs l’envoi de la rĂ©ponse. + +/// info + +Comme vous le verrez ci‑dessous, c’est trĂšs similaire au comportement avant la version 0.106.0, mais avec plusieurs amĂ©liorations et corrections de bogues pour des cas limites. + +/// + +#### Cas d’utilisation avec sortie anticipĂ©e du code { #use-cases-with-early-exit-code } + +Il existe certains cas d’utilisation avec des conditions spĂ©cifiques qui pourraient bĂ©nĂ©ficier de l’ancien comportement, oĂč le code d’arrĂȘt des dĂ©pendances avec `yield` s’exĂ©cute avant l’envoi de la rĂ©ponse. + +Par exemple, imaginez que vous ayez du code qui utilise une session de base de donnĂ©es dans une dĂ©pendance avec `yield` uniquement pour vĂ©rifier un utilisateur, mais que la session de base de donnĂ©es ne soit plus jamais utilisĂ©e dans la *fonction de chemin d'accĂšs*, seulement dans la dĂ©pendance, et que la rĂ©ponse mette longtemps Ă  ĂȘtre envoyĂ©e, comme une `StreamingResponse` qui envoie les donnĂ©es lentement mais qui, pour une raison quelconque, n’utilise pas la base de donnĂ©es. + +Dans ce cas, la session de base de donnĂ©es serait conservĂ©e jusqu’à la fin de l’envoi de la rĂ©ponse, mais si vous ne l’utilisez pas, il ne serait pas nĂ©cessaire de la conserver. + +Voici Ă  quoi cela pourrait ressembler : + +{* ../../docs_src/dependencies/tutorial013_an_py310.py *} + +Le code d’arrĂȘt, la fermeture automatique de la `Session` dans : + +{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *} + +... serait exĂ©cutĂ© aprĂšs que la rĂ©ponse a fini d’envoyer les donnĂ©es lentes : + +{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *} + +Mais comme `generate_stream()` n’utilise pas la session de base de donnĂ©es, il n’est pas vraiment nĂ©cessaire de garder la session ouverte pendant l’envoi de la rĂ©ponse. + +Si vous avez ce cas d’utilisation spĂ©cifique avec SQLModel (ou SQLAlchemy), vous pouvez fermer explicitement la session dĂšs que vous n’en avez plus besoin : + +{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *} + +De cette maniĂšre, la session libĂ©rera la connexion Ă  la base de donnĂ©es, afin que d’autres requĂȘtes puissent l’utiliser. + +Si vous avez un autre cas d’utilisation qui nĂ©cessite une sortie anticipĂ©e depuis une dĂ©pendance avec `yield`, veuillez crĂ©er une Question de discussion GitHub avec votre cas spĂ©cifique et pourquoi vous bĂ©nĂ©ficieriez d’une fermeture anticipĂ©e pour les dĂ©pendances avec `yield`. + +S’il existe des cas d’utilisation convaincants pour une fermeture anticipĂ©e dans les dĂ©pendances avec `yield`, j’envisagerai d’ajouter une nouvelle façon d’y opter. + +### DĂ©pendances avec `yield` et `except`, DĂ©tails techniques { #dependencies-with-yield-and-except-technical-details } + +Avant FastAPI 0.110.0, si vous utilisiez une dĂ©pendance avec `yield`, puis capturiez une exception avec `except` dans cette dĂ©pendance, et que vous ne relanciez pas l’exception, l’exception Ă©tait automatiquement levĂ©e/transmise Ă  tout gestionnaire d’exceptions ou au gestionnaire d’erreur interne du serveur. + +Cela a Ă©tĂ© modifiĂ© dans la version 0.110.0 pour corriger une consommation de mĂ©moire non gĂ©rĂ©e due aux exceptions transmises sans gestionnaire (erreurs internes du serveur), et pour rendre le comportement cohĂ©rent avec celui du code Python classique. + +### TĂąches d'arriĂšre‑plan et dĂ©pendances avec `yield`, DĂ©tails techniques { #background-tasks-and-dependencies-with-yield-technical-details } + +Avant FastAPI 0.106.0, lever des exceptions aprĂšs `yield` n’était pas possible, le code d’arrĂȘt dans les dĂ©pendances avec `yield` s’exĂ©cutait aprĂšs l’envoi de la rĂ©ponse, donc les [Gestionnaires d'exceptions](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} avaient dĂ©jĂ  Ă©tĂ© exĂ©cutĂ©s. + +Cela avait Ă©tĂ© conçu ainsi principalement pour permettre d’utiliser les mĂȘmes objets « gĂ©nĂ©rĂ©s par yield » par les dĂ©pendances Ă  l’intĂ©rieur de tĂąches d’arriĂšre‑plan, car le code d’arrĂȘt s’exĂ©cutait aprĂšs la fin des tĂąches d’arriĂšre‑plan. + +Cela a Ă©tĂ© modifiĂ© dans FastAPI 0.106.0 afin de ne pas conserver des ressources pendant l’attente de la transmission de la rĂ©ponse sur le rĂ©seau. + +/// tip | Astuce + +De plus, une tĂąche d’arriĂšre‑plan est normalement un ensemble de logique indĂ©pendant qui devrait ĂȘtre gĂ©rĂ© sĂ©parĂ©ment, avec ses propres ressources (par ex. sa propre connexion Ă  la base de donnĂ©es). + +Ainsi, vous aurez probablement un code plus propre. + +/// + +Si vous comptiez sur ce comportement, vous devez dĂ©sormais crĂ©er les ressources pour les tĂąches d’arriĂšre‑plan Ă  l’intĂ©rieur de la tĂąche elle‑mĂȘme, et n’utiliser en interne que des donnĂ©es qui ne dĂ©pendent pas des ressources des dĂ©pendances avec `yield`. + +Par exemple, au lieu d’utiliser la mĂȘme session de base de donnĂ©es, vous crĂ©eriez une nouvelle session de base de donnĂ©es Ă  l’intĂ©rieur de la tĂąche d’arriĂšre‑plan, et vous obtiendriez les objets depuis la base de donnĂ©es en utilisant cette nouvelle session. Puis, au lieu de passer l’objet obtenu depuis la base de donnĂ©es en paramĂštre Ă  la fonction de tĂąche d’arriĂšre‑plan, vous passeriez l’identifiant (ID) de cet objet et vous obtiendriez Ă  nouveau l’objet Ă  l’intĂ©rieur de la fonction de la tĂąche d’arriĂšre‑plan. diff --git a/docs/fr/docs/advanced/advanced-python-types.md b/docs/fr/docs/advanced/advanced-python-types.md new file mode 100644 index 000000000..3e2d9453b --- /dev/null +++ b/docs/fr/docs/advanced/advanced-python-types.md @@ -0,0 +1,61 @@ +# Types Python avancĂ©s { #advanced-python-types } + +Voici quelques idĂ©es supplĂ©mentaires qui peuvent ĂȘtre utiles lorsque vous travaillez avec les types Python. + +## Utiliser `Union` ou `Optional` { #using-union-or-optional } + +Si votre code ne peut pas utiliser `|` pour une raison quelconque, par exemple si ce n'est pas dans une annotation de type mais dans quelque chose comme `response_model=`, au lieu d'utiliser la barre verticale (`|`) vous pouvez utiliser `Union` de `typing`. + +Par exemple, vous pourriez dĂ©clarer que quelque chose peut ĂȘtre un `str` ou `None` : + +```python +from typing import Union + + +def say_hi(name: Union[str, None]): + print(f"Hi {name}!") +``` + +`typing` propose Ă©galement un raccourci pour dĂ©clarer que quelque chose peut ĂȘtre `None`, avec `Optional`. + +Voici un conseil issu 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 interne, identiques, mais je recommande `Union` plutĂŽt que `Optional` parce que le mot « optional » semble impliquer que la valeur est facultative, alors qu'il signifie en rĂ©alitĂ© « elle peut ĂȘtre `None` », mĂȘme si elle n'est pas facultative et reste requise. + +Je pense que `Union[SomeType, None]` est plus explicite quant Ă  sa signification. + +Il ne s'agit que des mots et des noms. Mais ces mots peuvent influencer la maniĂšre dont vous et vos coĂ©quipiers pensez au code. + +À titre d'exemple, prenons cette fonction : + +```python +from typing import Optional + + +def say_hi(name: Optional[str]): + print(f"Hey {name}!") +``` + +Le paramĂštre `name` est dĂ©fini comme `Optional[str]`, mais il n'est pas facultatif, vous ne pouvez pas appeler la fonction sans le paramĂštre : + +```Python +say_hi() # Oh non, cela lĂšve une erreur ! đŸ˜± +``` + +Le paramĂštre `name` est toujours requis (pas facultatif) car il n'a pas de valeur par dĂ©faut. En revanche, `name` accepte `None` comme valeur : + +```Python +say_hi(name=None) # Ceci fonctionne, None est valide 🎉 +``` + +La bonne nouvelle, c'est que, dans la plupart des cas, vous pourrez simplement utiliser `|` pour dĂ©finir des unions de types : + +```python +def say_hi(name: str | None): + print(f"Hey {name}!") +``` + +Ainsi, normalement, vous n'avez pas Ă  vous prĂ©occuper de noms comme `Optional` et `Union`. 😎 diff --git a/docs/fr/docs/advanced/async-tests.md b/docs/fr/docs/advanced/async-tests.md new file mode 100644 index 000000000..f9cea0ad1 --- /dev/null +++ b/docs/fr/docs/advanced/async-tests.md @@ -0,0 +1,99 @@ +# Tests asynchrones { #async-tests } + +Vous avez dĂ©jĂ  vu comment tester vos applications **FastAPI** en utilisant le `TestClient` fourni. Jusqu'Ă  prĂ©sent, vous n'avez vu que comment Ă©crire des tests synchrones, sans utiliser de fonctions `async`. + +Pouvoir utiliser des fonctions asynchrones dans vos tests peut ĂȘtre utile, par exemple lorsque vous interrogez votre base de donnĂ©es de maniĂšre asynchrone. Imaginez que vous vouliez tester l'envoi de requĂȘtes Ă  votre application FastAPI puis vĂ©rifier que votre backend a bien Ă©crit les bonnes donnĂ©es dans la base, tout en utilisant une bibliothĂšque de base de donnĂ©es asynchrone. + +Voyons comment procĂ©der. + +## pytest.mark.anyio { #pytest-mark-anyio } + +Si nous voulons appeler des fonctions asynchrones dans nos tests, nos fonctions de test doivent ĂȘtre asynchrones. AnyIO fournit un plug-in pratique qui nous permet d'indiquer que certaines fonctions de test doivent ĂȘtre appelĂ©es de maniĂšre asynchrone. + +## HTTPX { #httpx } + +MĂȘme si votre application **FastAPI** utilise des fonctions `def` normales au lieu de `async def`, c'est toujours une application `async` en interne. + +Le `TestClient` fait un peu de magie pour appeler l'application FastAPI asynchrone depuis vos fonctions de test `def` normales, en utilisant pytest standard. Mais cette magie ne fonctionne plus lorsque nous l'utilisons dans des fonctions asynchrones. En exĂ©cutant nos tests de maniĂšre asynchrone, nous ne pouvons plus utiliser le `TestClient` dans nos fonctions de test. + +Le `TestClient` est basĂ© sur HTTPX et, heureusement, nous pouvons l'utiliser directement pour tester l'API. + +## Exemple { #example } + +Pour un exemple simple, considĂ©rons une structure de fichiers similaire Ă  celle dĂ©crite dans [Applications plus grandes](../tutorial/bigger-applications.md){.internal-link target=_blank} et [Tests](../tutorial/testing.md){.internal-link target=_blank} : + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +Le fichier `main.py` contiendrait : + +{* ../../docs_src/async_tests/app_a_py310/main.py *} + +Le fichier `test_main.py` contiendrait les tests pour `main.py`, il pourrait maintenant ressembler Ă  ceci : + +{* ../../docs_src/async_tests/app_a_py310/test_main.py *} + +## ExĂ©cuter { #run-it } + +Vous pouvez lancer vos tests comme d'habitude via : + +
+ +```console +$ pytest + +---> 100% +``` + +
+ +## En dĂ©tail { #in-detail } + +Le marqueur `@pytest.mark.anyio` indique Ă  pytest que cette fonction de test doit ĂȘtre appelĂ©e de maniĂšre asynchrone : + +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *} + +/// tip | Astuce + +Notez que la fonction de test est maintenant `async def` au lieu de simplement `def` comme auparavant avec le `TestClient`. + +/// + +Nous pouvons ensuite crĂ©er un `AsyncClient` avec l'application et lui envoyer des requĂȘtes asynchrones en utilisant `await`. + +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *} + +C'est l'Ă©quivalent de : + +```Python +response = client.get('/') +``` + +... que nous utilisions pour faire nos requĂȘtes avec le `TestClient`. + +/// tip | Astuce + +Notez que nous utilisons async/await avec le nouveau `AsyncClient` — la requĂȘte est asynchrone. + +/// + +/// warning | Alertes + +Si votre application s'appuie sur des Ă©vĂ©nements de cycle de vie (lifespan), le `AsyncClient` ne dĂ©clenchera pas ces Ă©vĂ©nements. Pour vous assurer qu'ils sont dĂ©clenchĂ©s, utilisez `LifespanManager` depuis florimondmanca/asgi-lifespan. + +/// + +## Autres appels de fonctions asynchrones { #other-asynchronous-function-calls } + +Comme la fonction de test est dĂ©sormais asynchrone, vous pouvez Ă©galement appeler (et `await`) d'autres fonctions `async` en plus d'envoyer des requĂȘtes Ă  votre application FastAPI dans vos tests, exactement comme vous le feriez ailleurs dans votre code. + +/// tip | Astuce + +Si vous rencontrez une erreur `RuntimeError: Task attached to a different loop` lors de l'intĂ©gration d'appels de fonctions asynchrones dans vos tests (par exemple en utilisant MotorClient de MongoDB), n'oubliez pas d'instancier les objets qui ont besoin d'une boucle d'Ă©vĂ©nements uniquement dans des fonctions async, par exemple dans un callback `@app.on_event("startup")`. + +/// diff --git a/docs/fr/docs/advanced/behind-a-proxy.md b/docs/fr/docs/advanced/behind-a-proxy.md new file mode 100644 index 000000000..4b540e1a1 --- /dev/null +++ b/docs/fr/docs/advanced/behind-a-proxy.md @@ -0,0 +1,466 @@ +# Être derriĂšre un proxy { #behind-a-proxy } + +Dans de nombreuses situations, vous utiliserez un **proxy** comme Traefik ou Nginx devant votre application FastAPI. + +Ces proxies peuvent gĂ©rer les certificats HTTPS et d'autres aspects. + +## En-tĂȘtes transfĂ©rĂ©s par le proxy { #proxy-forwarded-headers } + +Un **proxy** placĂ© devant votre application dĂ©finit normalement certains en-tĂȘtes Ă  la volĂ©e avant d'envoyer les requĂȘtes Ă  votre **serveur**, afin d'indiquer au serveur que la requĂȘte a Ă©tĂ© **transfĂ©rĂ©e** par le proxy, en lui donnant l'URL d'origine (publique), y compris le domaine, le fait qu'elle utilise HTTPS, etc. + +Le programme **serveur** (par exemple **Uvicorn** via **FastAPI CLI**) est capable d'interprĂ©ter ces en‑tĂȘtes, puis de transmettre ces informations Ă  votre application. + +Mais, par sĂ©curitĂ©, comme le serveur ne sait pas qu'il se trouve derriĂšre un proxy de confiance, il n'interprĂ©tera pas ces en‑tĂȘtes. + +/// note | DĂ©tails techniques + +Les en-tĂȘtes du proxy sont : + +* X-Forwarded-For +* X-Forwarded-Proto +* X-Forwarded-Host + +/// + +### Activer les en-tĂȘtes transfĂ©rĂ©s par le proxy { #enable-proxy-forwarded-headers } + +Vous pouvez dĂ©marrer FastAPI CLI avec l'option de CLI `--forwarded-allow-ips` et fournir les adresses IP Ă  considĂ©rer comme fiables pour lire ces en‑tĂȘtes transfĂ©rĂ©s. + +Si vous la dĂ©finissez Ă  `--forwarded-allow-ips="*"`, elle fera confiance Ă  toutes les IP entrantes. + +Si votre **serveur** est derriĂšre un **proxy** de confiance et que seul le proxy lui parle, cela fera accepter l'IP de ce **proxy**, quelle qu'elle soit. + +
+ +```console +$ fastapi run --forwarded-allow-ips="*" + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### Redirections avec HTTPS { #redirects-with-https } + +Par exemple, disons que vous dĂ©finissez un *chemin d'accĂšs* `/items/` : + +{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *} + +Si le client essaie d'aller Ă  `/items`, par dĂ©faut, il sera redirigĂ© vers `/items/`. + +Mais avant de dĂ©finir l'option de CLI `--forwarded-allow-ips`, il pourrait rediriger vers `http://localhost:8000/items/`. + +Mais peut‑ĂȘtre que votre application est hĂ©bergĂ©e Ă  `https://mysuperapp.com`, et la redirection devrait ĂȘtre vers `https://mysuperapp.com/items/`. + +En dĂ©finissant `--proxy-headers`, FastAPI pourra dĂ©sormais rediriger vers l'emplacement correct. 😎 + +``` +https://mysuperapp.com/items/ +``` + +/// tip | Astuce + +Si vous voulez en savoir plus sur HTTPS, consultez le guide [À propos de HTTPS](../deployment/https.md){.internal-link target=_blank}. + +/// + +### Comment fonctionnent les en‑tĂȘtes transfĂ©rĂ©s par le proxy { #how-proxy-forwarded-headers-work } + +Voici une reprĂ©sentation visuelle de la façon dont le **proxy** ajoute des en‑tĂȘtes transfĂ©rĂ©s entre le client et le **serveur d'application** : + +```mermaid +sequenceDiagram + participant Client + participant Proxy as Proxy/Load Balancer + participant Server as FastAPI Server + + Client->>Proxy: HTTPS Request
Host: mysuperapp.com
Path: /items + + Note over Proxy: Proxy adds forwarded headers + + Proxy->>Server: HTTP Request
X-Forwarded-For: [client IP]
X-Forwarded-Proto: https
X-Forwarded-Host: mysuperapp.com
Path: /items + + Note over Server: Server interprets headers
(if --forwarded-allow-ips is set) + + Server->>Proxy: HTTP Response
with correct HTTPS URLs + + Proxy->>Client: HTTPS Response +``` + +Le **proxy** intercepte la requĂȘte client d'origine et ajoute les en-tĂȘtes spĂ©ciaux *forwarded* (`X-Forwarded-*`) avant de transmettre la requĂȘte au **serveur d'application**. + +Ces en‑tĂȘtes conservent des informations sur la requĂȘte d'origine qui seraient autrement perdues : + +* **X-Forwarded-For** : l'adresse IP du client d'origine +* **X-Forwarded-Proto** : le protocole d'origine (`https`) +* **X-Forwarded-Host** : l'hĂŽte d'origine (`mysuperapp.com`) + +Lorsque **FastAPI CLI** est configurĂ©e avec `--forwarded-allow-ips`, elle fait confiance Ă  ces en‑tĂȘtes et les utilise, par exemple pour gĂ©nĂ©rer les bonnes URL dans les redirections. + +## Proxy avec un prĂ©fixe de chemin supprimĂ© { #proxy-with-a-stripped-path-prefix } + +Vous pouvez avoir un proxy qui ajoute un prĂ©fixe de chemin Ă  votre application. + +Dans ces cas, vous pouvez utiliser `root_path` pour configurer votre application. + +Le `root_path` est un mĂ©canisme fourni par la spĂ©cification ASGI (sur laquelle FastAPI est construit, via Starlette). + +Le `root_path` est utilisĂ© pour gĂ©rer ces cas spĂ©cifiques. + +Et il est Ă©galement utilisĂ© en interne lors du montage de sous‑applications. + +Avoir un proxy avec un prĂ©fixe de chemin supprimĂ©, dans ce cas, signifie que vous pourriez dĂ©clarer un chemin Ă  `/app` dans votre code, mais ensuite, vous ajoutez une couche au‑dessus (le proxy) qui place votre application **FastAPI** sous un chemin comme `/api/v1`. + +Dans ce cas, le chemin original `/app` serait en rĂ©alitĂ© servi Ă  `/api/v1/app`. + +MĂȘme si tout votre code est Ă©crit en supposant qu'il n'y a que `/app`. + +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *} + +Et le proxy **« stripping »** le **prĂ©fixe de chemin** Ă  la volĂ©e avant de transmettre la requĂȘte au serveur de l'application (probablement Uvicorn via FastAPI CLI), en gardant votre application convaincue qu'elle est servie Ă  `/app`, afin que vous n'ayez pas Ă  mettre Ă  jour tout votre code pour inclure le prĂ©fixe `/api/v1`. + +Jusqu'ici, tout fonctionnerait normalement. + +Mais ensuite, lorsque vous ouvrez l'interface de documentation intĂ©grĂ©e (le frontend), elle s'attendra Ă  obtenir le schĂ©ma OpenAPI Ă  `/openapi.json`, au lieu de `/api/v1/openapi.json`. + +Ainsi, le frontend (qui s'exĂ©cute dans le navigateur) essaiera d'atteindre `/openapi.json` et ne pourra pas obtenir le schĂ©ma OpenAPI. + +Parce que nous avons un proxy avec un prĂ©fixe de chemin `/api/v1` pour notre application, le frontend doit rĂ©cupĂ©rer le schĂ©ma OpenAPI Ă  `/api/v1/openapi.json`. + +```mermaid +graph LR + +browser("Browser") +proxy["Proxy on http://0.0.0.0:9999/api/v1/app"] +server["Server on http://127.0.0.1:8000/app"] + +browser --> proxy +proxy --> server +``` + +/// tip | Astuce + +L'IP `0.0.0.0` est couramment utilisĂ©e pour signifier que le programme Ă©coute sur toutes les IP disponibles de cette machine/serveur. + +/// + +L'interface de documents doit Ă©galement indiquer dans le schĂ©ma OpenAPI que ce `server` d'API se trouve Ă  `/api/v1` (derriĂšre le proxy). Par exemple : + +```JSON hl_lines="4-8" +{ + "openapi": "3.1.0", + // Plus d'Ă©lĂ©ments ici + "servers": [ + { + "url": "/api/v1" + } + ], + "paths": { + // Plus d'Ă©lĂ©ments ici + } +} +``` + +Dans cet exemple, le « Proxy » pourrait ĂȘtre quelque chose comme **Traefik**. Et le serveur serait quelque chose comme FastAPI CLI avec **Uvicorn**, exĂ©cutant votre application FastAPI. + +### Fournir le `root_path` { #providing-the-root-path } + +Pour y parvenir, vous pouvez utiliser l'option de ligne de commande `--root-path` comme suit : + +
+ +```console +$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Si vous utilisez Hypercorn, il dispose Ă©galement de l'option `--root-path`. + +/// note | DĂ©tails techniques + +La spĂ©cification ASGI dĂ©finit un `root_path` pour ce cas d'usage. + +Et l'option de ligne de commande `--root-path` fournit ce `root_path`. + +/// + +### VĂ©rifier le `root_path` actuel { #checking-the-current-root-path } + +Vous pouvez obtenir le `root_path` actuel utilisĂ© par votre application pour chaque requĂȘte, il fait partie du dictionnaire `scope` (qui fait partie de la spĂ©cification ASGI). + +Ici, nous l'incluons dans le message uniquement Ă  des fins de dĂ©monstration. + +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *} + +Ensuite, si vous dĂ©marrez Uvicorn avec : + +
+ +```console +$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +La rĂ©ponse sera semblable Ă  : + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +### DĂ©finir le `root_path` dans l'application FastAPI { #setting-the-root-path-in-the-fastapi-app } + +Autrement, si vous n'avez pas la possibilitĂ© de fournir une option de ligne de commande comme `--root-path` ou Ă©quivalent, vous pouvez dĂ©finir le paramĂštre `root_path` lors de la crĂ©ation de votre application FastAPI : + +{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *} + +Passer le `root_path` Ă  `FastAPI` Ă©quivaut Ă  passer l'option de ligne de commande `--root-path` Ă  Uvicorn ou Hypercorn. + +### À propos de `root_path` { #about-root-path } + +Gardez Ă  l'esprit que le serveur (Uvicorn) n'utilisera ce `root_path` que pour le transmettre Ă  l'application. + +Mais si vous allez avec votre navigateur sur http://127.0.0.1:8000/app, vous verrez la rĂ©ponse normale : + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +Donc, il ne s'attendra pas Ă  ĂȘtre accessible Ă  `http://127.0.0.1:8000/api/v1/app`. + +Uvicorn s'attendra Ă  ce que le proxy accĂšde Ă  Uvicorn sur `http://127.0.0.1:8000/app`, et ce sera ensuite la responsabilitĂ© du proxy d'ajouter le prĂ©fixe supplĂ©mentaire `/api/v1` au‑dessus. + +## À propos des proxies avec un prĂ©fixe de chemin supprimĂ© { #about-proxies-with-a-stripped-path-prefix } + +Gardez Ă  l'esprit qu'un proxy avec prĂ©fixe de chemin supprimĂ© n'est qu'une des façons de le configurer. + +Dans de nombreux cas, la valeur par dĂ©faut sera probablement que le proxy n'a pas de prĂ©fixe de chemin supprimĂ©. + +Dans un cas comme celui‑ci (sans prĂ©fixe de chemin supprimĂ©), le proxy Ă©coutera sur quelque chose comme `https://myawesomeapp.com`, puis si le navigateur va sur `https://myawesomeapp.com/api/v1/app` et que votre serveur (par ex. Uvicorn) Ă©coute sur `http://127.0.0.1:8000`, le proxy (sans prĂ©fixe de chemin supprimĂ©) accĂ©dera Ă  Uvicorn au mĂȘme chemin : `http://127.0.0.1:8000/api/v1/app`. + +## Tester localement avec Traefik { #testing-locally-with-traefik } + +Vous pouvez facilement faire l'expĂ©rience en local avec un prĂ©fixe de chemin supprimĂ© en utilisant Traefik. + +TĂ©lĂ©chargez Traefik ; c'est un binaire unique, vous pouvez extraire le fichier compressĂ© et l'exĂ©cuter directement depuis le terminal. + +CrĂ©ez ensuite un fichier `traefik.toml` avec : + +```TOML hl_lines="3" +[entryPoints] + [entryPoints.http] + address = ":9999" + +[providers] + [providers.file] + filename = "routes.toml" +``` + +Cela indique Ă  Traefik d'Ă©couter sur le port 9999 et d'utiliser un autre fichier `routes.toml`. + +/// tip | Astuce + +Nous utilisons le port 9999 au lieu du port HTTP standard 80 afin que vous n'ayez pas Ă  l'exĂ©cuter avec des privilĂšges administrateur (`sudo`). + +/// + +CrĂ©ez maintenant cet autre fichier `routes.toml` : + +```TOML hl_lines="5 12 20" +[http] + [http.middlewares] + + [http.middlewares.api-stripprefix.stripPrefix] + prefixes = ["/api/v1"] + + [http.routers] + + [http.routers.app-http] + entryPoints = ["http"] + service = "app" + rule = "PathPrefix(`/api/v1`)" + middlewares = ["api-stripprefix"] + + [http.services] + + [http.services.app] + [http.services.app.loadBalancer] + [[http.services.app.loadBalancer.servers]] + url = "http://127.0.0.1:8000" +``` + +Ce fichier configure Traefik pour utiliser le prĂ©fixe de chemin `/api/v1`. + +Puis Traefik redirigera ses requĂȘtes vers votre Uvicorn tournant sur `http://127.0.0.1:8000`. + +DĂ©marrez maintenant Traefik : + +
+ +```console +$ ./traefik --configFile=traefik.toml + +INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml +``` + +
+ +Et démarrez maintenant votre application, en utilisant l'option `--root-path` : + +
+ +```console +$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### VĂ©rifier les rĂ©ponses { #check-the-responses } + +Maintenant, si vous allez Ă  l'URL avec le port pour Uvicorn : http://127.0.0.1:8000/app, vous verrez la rĂ©ponse normale : + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +/// tip | Astuce + +Remarquez que mĂȘme si vous y accĂ©dez via `http://127.0.0.1:8000/app`, il affiche le `root_path` de `/api/v1`, repris depuis l'option `--root-path`. + +/// + +Et maintenant ouvrez l'URL avec le port pour Traefik, en incluant le prĂ©fixe de chemin : http://127.0.0.1:9999/api/v1/app. + +Nous obtenons la mĂȘme rĂ©ponse : + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +mais cette fois Ă  l'URL avec le prĂ©fixe fourni par le proxy : `/api/v1`. + +Bien sĂ»r, l'idĂ©e ici est que tout le monde accĂšde Ă  l'application via le proxy ; la version avec le prĂ©fixe de chemin `/api/v1` est donc la « correcte ». + +Et la version sans prĂ©fixe de chemin (`http://127.0.0.1:8000/app`), fournie directement par Uvicorn, serait exclusivement destinĂ©e au _proxy_ (Traefik) pour y accĂ©der. + +Cela montre comment le Proxy (Traefik) utilise le prĂ©fixe de chemin et comment le serveur (Uvicorn) utilise le `root_path` fourni par l'option `--root-path`. + +### VĂ©rifier l'interface de documentation { #check-the-docs-ui } + +Mais voici la partie intĂ©ressante. ✹ + +La maniĂšre « officielle » d'accĂ©der Ă  l'application serait via le proxy avec le prĂ©fixe de chemin que nous avons dĂ©fini. Donc, comme on s'y attend, si vous essayez l'interface de documentation servie directement par Uvicorn, sans le prĂ©fixe de chemin dans l'URL, cela ne fonctionne pas, car elle s'attend Ă  ĂȘtre accĂ©dĂ©e via le proxy. + +Vous pouvez le vĂ©rifier sur http://127.0.0.1:8000/docs : + + + +Mais si nous accĂ©dons Ă  l'interface de documents Ă  l'URL « officielle » en utilisant le proxy avec le port `9999`, Ă  `/api/v1/docs`, cela fonctionne correctement ! 🎉 + +Vous pouvez le vĂ©rifier sur http://127.0.0.1:9999/api/v1/docs : + + + +Exactement comme nous le voulions. ✔ + +C'est parce que FastAPI utilise ce `root_path` pour crĂ©er le `server` par dĂ©faut dans OpenAPI avec l'URL fournie par `root_path`. + +## Serveurs supplĂ©mentaires { #additional-servers } + +/// warning | Alertes + +Ceci est un cas d'utilisation plus avancĂ©. N'hĂ©sitez pas Ă  l'ignorer. + +/// + +Par dĂ©faut, **FastAPI** crĂ©era un `server` dans le schĂ©ma OpenAPI avec l'URL correspondant au `root_path`. + +Mais vous pouvez aussi fournir d'autres `servers` alternatifs, par exemple si vous voulez que la mĂȘme interface de documents interagisse avec un environnement de staging et un environnement de production. + +Si vous passez une liste personnalisĂ©e de `servers` et qu'il y a un `root_path` (parce que votre API vit derriĂšre un proxy), **FastAPI** insĂ©rera un « server » avec ce `root_path` au dĂ©but de la liste. + +Par exemple : + +{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *} + +GĂ©nĂ©rera un schĂ©ma OpenAPI comme : + +```JSON hl_lines="5-7" +{ + "openapi": "3.1.0", + // Plus d'Ă©lĂ©ments ici + "servers": [ + { + "url": "/api/v1" + }, + { + "url": "https://stag.example.com", + "description": "Staging environment" + }, + { + "url": "https://prod.example.com", + "description": "Production environment" + } + ], + "paths": { + // Plus d'Ă©lĂ©ments ici + } +} +``` + +/// tip | Astuce + +Remarquez le serveur gĂ©nĂ©rĂ© automatiquement avec une valeur `url` de `/api/v1`, reprise depuis le `root_path`. + +/// + +Dans l'interface de documents sur http://127.0.0.1:9999/api/v1/docs, cela ressemblera Ă  ceci : + + + +/// tip | Astuce + +L'interface de documents interagit avec le serveur que vous sĂ©lectionnez. + +/// + +/// note | DĂ©tails techniques + +La propriĂ©tĂ© `servers` dans la spĂ©cification OpenAPI est facultative. + +Si vous ne spĂ©cifiez pas le paramĂštre `servers` et que `root_path` est Ă©gal Ă  `/`, la propriĂ©tĂ© `servers` dans le schĂ©ma OpenAPI gĂ©nĂ©rĂ© sera entiĂšrement omise par dĂ©faut, ce qui Ă©quivaut Ă  un seul serveur avec une valeur `url` de `/`. + +/// + +### DĂ©sactiver le serveur automatique issu de `root_path` { #disable-automatic-server-from-root-path } + +Si vous ne voulez pas que **FastAPI** inclue un serveur automatique utilisant le `root_path`, vous pouvez utiliser le paramĂštre `root_path_in_servers=False` : + +{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *} + +et il ne l'inclura alors pas dans le schĂ©ma OpenAPI. + +## Monter une sous-application { #mounting-a-sub-application } + +Si vous avez besoin de monter une sous‑application (comme dĂ©crit dans [Sous‑applications - montages](sub-applications.md){.internal-link target=_blank}) tout en utilisant un proxy avec `root_path`, vous pouvez le faire normalement, comme vous vous y attendez. + +FastAPI utilisera intelligemment le `root_path` en interne, donc cela fonctionnera simplement. ✹ diff --git a/docs/fr/docs/advanced/custom-response.md b/docs/fr/docs/advanced/custom-response.md new file mode 100644 index 000000000..7eab5b53f --- /dev/null +++ b/docs/fr/docs/advanced/custom-response.md @@ -0,0 +1,312 @@ +# RĂ©ponse personnalisĂ©e - HTML, flux, fichier, autres { #custom-response-html-stream-file-others } + +Par dĂ©faut, **FastAPI** renverra les rĂ©ponses en utilisant `JSONResponse`. + +Vous pouvez le remplacer en renvoyant directement une `Response` comme expliquĂ© dans [Renvoyer directement une Response](response-directly.md){.internal-link target=_blank}. + +Mais si vous renvoyez directement une `Response` (ou n'importe quelle sous-classe, comme `JSONResponse`), les donnĂ©es ne seront pas automatiquement converties (mĂȘme si vous dĂ©clarez un `response_model`), et la documentation ne sera pas gĂ©nĂ©rĂ©e automatiquement (par exemple, l'inclusion du « media type » dans l'en-tĂȘte HTTP `Content-Type` comme partie de l'OpenAPI gĂ©nĂ©rĂ©). + +Vous pouvez aussi dĂ©clarer la `Response` que vous voulez utiliser (par ex. toute sous-classe de `Response`), dans le dĂ©corateur de chemin d'accĂšs en utilisant le paramĂštre `response_class`. + +Le contenu que vous renvoyez depuis votre fonction de chemin d'accĂšs sera placĂ© Ă  l'intĂ©rieur de cette `Response`. + +Et si cette `Response` a un « media type » JSON (`application/json`), comme c'est le cas avec `JSONResponse` et `UJSONResponse`, les donnĂ©es que vous renvoyez seront automatiquement converties (et filtrĂ©es) avec tout `response_model` Pydantic que vous avez dĂ©clarĂ© dans le dĂ©corateur de chemin d'accĂšs. + +/// note | Remarque + +Si vous utilisez une classe de rĂ©ponse sans « media type », FastAPI s'attendra Ă  ce que votre rĂ©ponse n'ait pas de contenu ; il ne documentera donc pas le format de la rĂ©ponse dans les documents OpenAPI gĂ©nĂ©rĂ©s. + +/// + +## Utiliser `ORJSONResponse` { #use-orjsonresponse } + +Par exemple, si vous cherchez Ă  maximiser la performance, vous pouvez installer et utiliser `orjson` et dĂ©finir la rĂ©ponse sur `ORJSONResponse`. + +Importez la classe (sous-classe) `Response` que vous voulez utiliser et dĂ©clarez-la dans le dĂ©corateur de chemin d'accĂšs. + +Pour de grandes rĂ©ponses, renvoyer directement une `Response` est bien plus rapide que de renvoyer un dictionnaire. + +Cela vient du fait que, par dĂ©faut, FastAPI inspectera chaque Ă©lĂ©ment et s'assurera qu'il est sĂ©rialisable en JSON, en utilisant le mĂȘme [Encodeur compatible JSON](../tutorial/encoder.md){.internal-link target=_blank} expliquĂ© dans le didacticiel. C'est ce qui vous permet de renvoyer des objets arbitraires, par exemple des modĂšles de base de donnĂ©es. + +Mais si vous ĂȘtes certain que le contenu que vous renvoyez est sĂ©rialisable en JSON, vous pouvez le passer directement Ă  la classe de rĂ©ponse et Ă©viter le surcoĂ»t supplĂ©mentaire qu'aurait FastAPI en faisant passer votre contenu de retour par le `jsonable_encoder` avant de le transmettre Ă  la classe de rĂ©ponse. + +{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *} + +/// info + +Le paramĂštre `response_class` sera aussi utilisĂ© pour dĂ©finir le « media type » de la rĂ©ponse. + +Dans ce cas, l'en-tĂȘte HTTP `Content-Type` sera dĂ©fini Ă  `application/json`. + +Et il sera documentĂ© comme tel dans OpenAPI. + +/// + +/// tip | Astuce + +`ORJSONResponse` est disponible uniquement dans FastAPI, pas dans Starlette. + +/// + +## RĂ©ponse HTML { #html-response } + +Pour renvoyer une rĂ©ponse avec du HTML directement depuis **FastAPI**, utilisez `HTMLResponse`. + +- Importez `HTMLResponse`. +- Passez `HTMLResponse` comme paramĂštre `response_class` de votre dĂ©corateur de chemin d'accĂšs. + +{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *} + +/// info + +Le paramĂštre `response_class` sera aussi utilisĂ© pour dĂ©finir le « media type » de la rĂ©ponse. + +Dans ce cas, l'en-tĂȘte HTTP `Content-Type` sera dĂ©fini Ă  `text/html`. + +Et il sera documentĂ© comme tel dans OpenAPI. + +/// + +### Renvoyer une `Response` { #return-a-response } + +Comme vu dans [Renvoyer directement une Response](response-directly.md){.internal-link target=_blank}, vous pouvez aussi remplacer la rĂ©ponse directement dans votre chemin d'accĂšs, en la renvoyant. + +Le mĂȘme exemple ci-dessus, renvoyant une `HTMLResponse`, pourrait ressembler Ă  : + +{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *} + +/// warning | Alertes + +Une `Response` renvoyĂ©e directement par votre fonction de chemin d'accĂšs ne sera pas documentĂ©e dans OpenAPI (par exemple, le `Content-Type` ne sera pas documentĂ©) et ne sera pas visible dans les documents interactifs automatiques. + +/// + +/// info + +Bien sĂ»r, l'en-tĂȘte `Content-Type` rĂ©el, le code d'Ă©tat, etc., proviendront de l'objet `Response` que vous avez renvoyĂ©. + +/// + +### Documenter dans OpenAPI et remplacer `Response` { #document-in-openapi-and-override-response } + +Si vous voulez remplacer la rĂ©ponse depuis l'intĂ©rieur de la fonction mais en mĂȘme temps documenter le « media type » dans OpenAPI, vous pouvez utiliser le paramĂštre `response_class` ET renvoyer un objet `Response`. + +`response_class` sera alors utilisĂ© uniquement pour documenter l'opĂ©ration de chemin d'accĂšs OpenAPI, mais votre `Response` sera utilisĂ©e telle quelle. + +#### Renvoyer directement une `HTMLResponse` { #return-an-htmlresponse-directly } + +Par exemple, cela pourrait ĂȘtre quelque chose comme : + +{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *} + +Dans cet exemple, la fonction `generate_html_response()` gĂ©nĂšre dĂ©jĂ  et renvoie une `Response` au lieu de renvoyer le HTML dans une `str`. + +En renvoyant le rĂ©sultat de l'appel Ă  `generate_html_response()`, vous renvoyez dĂ©jĂ  une `Response` qui remplacera le comportement par dĂ©faut de **FastAPI**. + +Mais comme vous avez aussi passĂ© `HTMLResponse` dans `response_class`, **FastAPI** saura comment la documenter dans OpenAPI et les documents interactifs comme HTML avec `text/html` : + + + +## RĂ©ponses disponibles { #available-responses } + +Voici certaines des rĂ©ponses disponibles. + +Gardez Ă  l'esprit que vous pouvez utiliser `Response` pour renvoyer autre chose, ou mĂȘme crĂ©er une sous-classe personnalisĂ©e. + +/// note | DĂ©tails techniques + +Vous pourriez aussi utiliser `from starlette.responses import HTMLResponse`. + +**FastAPI** fournit les mĂȘmes `starlette.responses` sous `fastapi.responses` simplement pour votre confort de dĂ©veloppement. Mais la plupart des rĂ©ponses disponibles viennent directement de Starlette. + +/// + +### `Response` { #response } + +La classe principale `Response`, toutes les autres rĂ©ponses en hĂ©ritent. + +Vous pouvez la renvoyer directement. + +Elle accepte les paramĂštres suivants : + +- `content` - Une `str` ou des `bytes`. +- `status_code` - Un code d'Ă©tat HTTP de type `int`. +- `headers` - Un `dict` de chaĂźnes. +- `media_type` - Une `str` donnant le media type. Par exemple « text/html ». + +FastAPI (en fait Starlette) inclura automatiquement un en-tĂȘte Content-Length. Il inclura aussi un en-tĂȘte Content-Type, basĂ© sur `media_type` et en ajoutant un charset pour les types textuels. + +{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *} + +### `HTMLResponse` { #htmlresponse } + +Prend du texte ou des octets et renvoie une rĂ©ponse HTML, comme vous l'avez lu ci-dessus. + +### `PlainTextResponse` { #plaintextresponse } + +Prend du texte ou des octets et renvoie une rĂ©ponse en texte brut. + +{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *} + +### `JSONResponse` { #jsonresponse } + +Prend des donnĂ©es et renvoie une rĂ©ponse encodĂ©e en `application/json`. + +C'est la rĂ©ponse par dĂ©faut utilisĂ©e dans **FastAPI**, comme vous l'avez lu ci-dessus. + +### `ORJSONResponse` { #orjsonresponse } + +Une rĂ©ponse JSON alternative rapide utilisant `orjson`, comme vous l'avez lu ci-dessus. + +/// info + +Cela nĂ©cessite l'installation de `orjson`, par exemple avec `pip install orjson`. + +/// + +### `UJSONResponse` { #ujsonresponse } + +Une rĂ©ponse JSON alternative utilisant `ujson`. + +/// info + +Cela nĂ©cessite l'installation de `ujson`, par exemple avec `pip install ujson`. + +/// + +/// warning | Alertes + +`ujson` est moins rigoureux que l'implĂ©mentation intĂ©grĂ©e de Python dans sa gestion de certains cas limites. + +/// + +{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *} + +/// tip | Astuce + +Il est possible que `ORJSONResponse` soit une alternative plus rapide. + +/// + +### `RedirectResponse` { #redirectresponse } + +Renvoie une redirection HTTP. Utilise par dĂ©faut un code d'Ă©tat 307 (Temporary Redirect). + +Vous pouvez renvoyer directement une `RedirectResponse` : + +{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *} + +--- + +Ou vous pouvez l'utiliser dans le paramĂštre `response_class` : + +{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *} + +Si vous faites cela, vous pouvez alors renvoyer directement l'URL depuis votre fonction de chemin d'accĂšs. + +Dans ce cas, le `status_code` utilisĂ© sera celui par dĂ©faut pour `RedirectResponse`, c'est-Ă -dire `307`. + +--- + +Vous pouvez aussi utiliser le paramĂštre `status_code` combinĂ© avec le paramĂštre `response_class` : + +{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *} + +### `StreamingResponse` { #streamingresponse } + +Prend un gĂ©nĂ©rateur async ou un gĂ©nĂ©rateur/itĂ©rateur normal et diffuse le corps de la rĂ©ponse. + +{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *} + +#### Utiliser `StreamingResponse` avec des objets de type fichier { #using-streamingresponse-with-file-like-objects } + +Si vous avez un objet de type fichier (par ex. l'objet renvoyĂ© par `open()`), vous pouvez crĂ©er une fonction gĂ©nĂ©ratrice pour itĂ©rer sur cet objet de type fichier. + +De cette façon, vous n'avez pas Ă  tout lire en mĂ©moire au prĂ©alable, et vous pouvez passer cette fonction gĂ©nĂ©ratrice Ă  `StreamingResponse`, puis la renvoyer. + +Cela inclut de nombreuses bibliothĂšques pour interagir avec du stockage cloud, du traitement vidĂ©o, et autres. + +{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *} + +1. C'est la fonction gĂ©nĂ©ratrice. C'est une « fonction gĂ©nĂ©ratrice » parce qu'elle contient des instructions `yield` Ă  l'intĂ©rieur. +2. En utilisant un bloc `with`, nous nous assurons que l'objet de type fichier est fermĂ© aprĂšs l'exĂ©cution de la fonction gĂ©nĂ©ratrice. Donc, aprĂšs qu'elle a fini d'envoyer la rĂ©ponse. +3. Ce `yield from` indique Ă  la fonction d'itĂ©rer sur l'objet nommĂ© `file_like`. Puis, pour chaque partie itĂ©rĂ©e, de produire cette partie comme provenant de cette fonction gĂ©nĂ©ratrice (`iterfile`). + + Ainsi, c'est une fonction gĂ©nĂ©ratrice qui transfĂšre le travail de « gĂ©nĂ©ration » Ă  autre chose en interne. + + En procĂ©dant ainsi, nous pouvons la placer dans un bloc `with` et, de cette façon, garantir que l'objet de type fichier est fermĂ© aprĂšs la fin. + +/// tip | Astuce + +Remarquez qu'ici, comme nous utilisons le `open()` standard qui ne prend pas en charge `async` et `await`, nous dĂ©clarons le chemin d'accĂšs avec un `def` normal. + +/// + +### `FileResponse` { #fileresponse } + +Diffuse de façon asynchrone un fichier comme rĂ©ponse. + +Prend un ensemble de paramĂštres diffĂ©rent Ă  l'instanciation par rapport aux autres types de rĂ©ponse : + +- `path` - Le chemin du fichier Ă  diffuser. +- `headers` - D'Ă©ventuels en-tĂȘtes personnalisĂ©s Ă  inclure, sous forme de dictionnaire. +- `media_type` - Une chaĂźne donnant le media type. Si non dĂ©fini, le nom du fichier ou le chemin sera utilisĂ© pour en dĂ©duire un media type. +- `filename` - Si dĂ©fini, sera inclus dans l'en-tĂȘte `Content-Disposition` de la rĂ©ponse. + +Les rĂ©ponses de type fichier incluront les en-tĂȘtes appropriĂ©s `Content-Length`, `Last-Modified` et `ETag`. + +{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *} + +Vous pouvez aussi utiliser le paramĂštre `response_class` : + +{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *} + +Dans ce cas, vous pouvez renvoyer directement le chemin du fichier depuis votre fonction de chemin d'accĂšs. + +## Classe de rĂ©ponse personnalisĂ©e { #custom-response-class } + +Vous pouvez crĂ©er votre propre classe de rĂ©ponse personnalisĂ©e, hĂ©ritant de `Response`, et l'utiliser. + +Par exemple, disons que vous voulez utiliser `orjson`, mais avec certains rĂ©glages personnalisĂ©s non utilisĂ©s dans la classe `ORJSONResponse` incluse. + +Disons que vous voulez renvoyer du JSON indentĂ© et formatĂ©, donc vous voulez utiliser l'option orjson `orjson.OPT_INDENT_2`. + +Vous pourriez crĂ©er une `CustomORJSONResponse`. L'essentiel est de crĂ©er une mĂ©thode `Response.render(content)` qui renvoie le contenu en `bytes` : + +{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *} + +Maintenant, au lieu de renvoyer : + +```json +{"message": "Hello World"} +``` + +... cette rĂ©ponse renverra : + +```json +{ + "message": "Hello World" +} +``` + +Bien sĂ»r, vous trouverez probablement des moyens bien meilleurs de tirer parti de cela que de formater du JSON. 😉 + +## Classe de rĂ©ponse par dĂ©faut { #default-response-class } + +Lors de la crĂ©ation d'une instance de classe **FastAPI** ou d'un `APIRouter`, vous pouvez spĂ©cifier quelle classe de rĂ©ponse utiliser par dĂ©faut. + +Le paramĂštre qui le dĂ©finit est `default_response_class`. + +Dans l'exemple ci-dessous, **FastAPI** utilisera `ORJSONResponse` par dĂ©faut, dans tous les chemins d'accĂšs, au lieu de `JSONResponse`. + +{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *} + +/// tip | Astuce + +Vous pouvez toujours remplacer `response_class` dans les chemins d'accĂšs comme auparavant. + +/// + +## Documentation supplĂ©mentaire { #additional-documentation } + +Vous pouvez aussi dĂ©clarer le media type et de nombreux autres dĂ©tails dans OpenAPI en utilisant `responses` : [RĂ©ponses supplĂ©mentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/fr/docs/advanced/dataclasses.md b/docs/fr/docs/advanced/dataclasses.md new file mode 100644 index 000000000..2bd77157e --- /dev/null +++ b/docs/fr/docs/advanced/dataclasses.md @@ -0,0 +1,95 @@ +# Utiliser des dataclasses { #using-dataclasses } + +FastAPI est construit au‑dessus de **Pydantic**, et je vous ai montrĂ© comment utiliser des modĂšles Pydantic pour dĂ©clarer les requĂȘtes et les rĂ©ponses. + +Mais FastAPI prend aussi en charge l'utilisation de `dataclasses` de la mĂȘme maniĂšre : + +{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *} + +Cela fonctionne grĂące Ă  **Pydantic**, qui offre une prise en charge interne des `dataclasses`. + +Ainsi, mĂȘme avec le code ci‑dessus qui n'emploie pas explicitement Pydantic, FastAPI utilise Pydantic pour convertir ces dataclasses standard en la variante de dataclasses de Pydantic. + +Et bien sĂ»r, cela prend en charge la mĂȘme chose : + +* validation des donnĂ©es +* sĂ©rialisation des donnĂ©es +* documentation des donnĂ©es, etc. + +Cela fonctionne de la mĂȘme maniĂšre qu'avec les modĂšles Pydantic. Et, en rĂ©alitĂ©, c'est mis en Ɠuvre de la mĂȘme façon en interne, en utilisant Pydantic. + +/// info | Info + +Gardez Ă  l'esprit que les dataclasses ne peuvent pas tout ce que peuvent faire les modĂšles Pydantic. + +Vous pourriez donc avoir encore besoin d'utiliser des modĂšles Pydantic. + +Mais si vous avez dĂ©jĂ  un ensemble de dataclasses sous la main, c'est une astuce pratique pour les utiliser afin d'alimenter une API Web avec FastAPI. đŸ€“ + +/// + +## Utiliser des dataclasses dans `response_model` { #dataclasses-in-response-model } + +Vous pouvez aussi utiliser `dataclasses` dans le paramĂštre `response_model` : + +{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *} + +La dataclass sera automatiquement convertie en dataclass Pydantic. + +Ainsi, son schĂ©ma apparaĂźtra dans l'interface utilisateur de la documentation de l'API : + + + +## Utiliser des dataclasses dans des structures de donnĂ©es imbriquĂ©es { #dataclasses-in-nested-data-structures } + +Vous pouvez aussi combiner `dataclasses` avec d'autres annotations de type pour crĂ©er des structures de donnĂ©es imbriquĂ©es. + +Dans certains cas, vous devrez peut‑ĂȘtre encore utiliser la version `dataclasses` de Pydantic. Par exemple, si vous rencontrez des erreurs avec la documentation d'API gĂ©nĂ©rĂ©e automatiquement. + +Dans ce cas, vous pouvez simplement remplacer les `dataclasses` standard par `pydantic.dataclasses`, qui est un remplacement drop‑in : + +{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *} + +1. Nous continuons Ă  importer `field` depuis les `dataclasses` standard. + +2. `pydantic.dataclasses` est un remplacement drop‑in pour `dataclasses`. + +3. La dataclass `Author` inclut une liste de dataclasses `Item`. + +4. La dataclass `Author` est utilisĂ©e comme paramĂštre `response_model`. + +5. Vous pouvez utiliser d'autres annotations de type standard avec des dataclasses comme corps de la requĂȘte. + + Dans ce cas, il s'agit d'une liste de dataclasses `Item`. + +6. Ici, nous renvoyons un dictionnaire qui contient `items`, qui est une liste de dataclasses. + + FastAPI est toujours capable de sĂ©rialiser les donnĂ©es en JSON. + +7. Ici, `response_model` utilise une annotation de type correspondant Ă  une liste de dataclasses `Author`. + + LĂ  encore, vous pouvez combiner `dataclasses` avec des annotations de type standard. + +8. Notez que cette *fonction de chemin d'accĂšs* utilise un `def` classique au lieu de `async def`. + + Comme toujours, avec FastAPI vous pouvez combiner `def` et `async def` selon vos besoins. + + Si vous avez besoin d'un rappel sur quand utiliser l'un ou l'autre, consultez la section _« In a hurry? »_ dans la documentation Ă  propos de [`async` et `await`](../async.md#in-a-hurry){.internal-link target=_blank}. + +9. Cette *fonction de chemin d'accĂšs* ne renvoie pas des dataclasses (mĂȘme si elle le pourrait), mais une liste de dictionnaires contenant des donnĂ©es internes. + + FastAPI utilisera le paramĂštre `response_model` (qui inclut des dataclasses) pour convertir la rĂ©ponse. + +Vous pouvez combiner `dataclasses` avec d'autres annotations de type, selon de nombreuses combinaisons, pour former des structures de donnĂ©es complexes. + +Reportez‑vous aux annotations dans le code ci‑dessus pour voir plus de dĂ©tails spĂ©cifiques. + +## En savoir plus { #learn-more } + +Vous pouvez aussi combiner `dataclasses` avec d'autres modĂšles Pydantic, en hĂ©riter, les inclure dans vos propres modĂšles, etc. + +Pour en savoir plus, consultez la documentation Pydantic sur les dataclasses. + +## Version { #version } + +C'est disponible depuis FastAPI version `0.67.0`. 🔖 diff --git a/docs/fr/docs/advanced/events.md b/docs/fr/docs/advanced/events.md new file mode 100644 index 000000000..6d0907a8b --- /dev/null +++ b/docs/fr/docs/advanced/events.md @@ -0,0 +1,165 @@ +# ÉvĂ©nements de cycle de vie { #lifespan-events } + +Vous pouvez dĂ©finir une logique (du code) qui doit ĂȘtre exĂ©cutĂ©e avant que l'application ne **dĂ©marre**. Cela signifie que ce code sera exĂ©cutĂ© **une seule fois**, **avant** que l'application ne **commence Ă  recevoir des requĂȘtes**. + +De la mĂȘme maniĂšre, vous pouvez dĂ©finir une logique (du code) qui doit ĂȘtre exĂ©cutĂ©e lorsque l'application **s'arrĂȘte**. Dans ce cas, ce code sera exĂ©cutĂ© **une seule fois**, **aprĂšs** avoir traitĂ© potentiellement **de nombreuses requĂȘtes**. + +Comme ce code est exĂ©cutĂ© avant que l'application ne **commence** Ă  recevoir des requĂȘtes, et juste aprĂšs qu'elle **termine** de les traiter, il couvre tout le **cycle de vie** de l'application (le mot « lifespan » va ĂȘtre important dans un instant 😉). + +Cela peut ĂȘtre trĂšs utile pour configurer des **ressources** dont vous avez besoin pour l'ensemble de l'application, qui sont **partagĂ©es** entre les requĂȘtes, et/ou que vous devez **nettoyer** ensuite. Par exemple, un pool de connexions Ă  une base de donnĂ©es, ou le chargement d'un modĂšle d'apprentissage automatique partagĂ©. + +## Cas d'utilisation { #use-case } + +Commençons par un exemple de **cas d'utilisation**, puis voyons comment le rĂ©soudre avec ceci. + +Imaginons que vous ayez des **modĂšles d'apprentissage automatique** que vous souhaitez utiliser pour traiter des requĂȘtes. đŸ€– + +Les mĂȘmes modĂšles sont partagĂ©s entre les requĂȘtes, ce n'est donc pas un modĂšle par requĂȘte, ni un par utilisateur, ou quelque chose de similaire. + +Imaginons que le chargement du modĂšle puisse **prendre pas mal de temps**, car il doit lire beaucoup de **donnĂ©es depuis le disque**. Vous ne voulez donc pas le faire pour chaque requĂȘte. + +Vous pourriez le charger au niveau supĂ©rieur du module/fichier, mais cela signifierait aussi qu'il **chargerait le modĂšle** mĂȘme si vous exĂ©cutez simplement un test automatisĂ© simple ; ce test serait alors **lent** car il devrait attendre le chargement du modĂšle avant de pouvoir exĂ©cuter une partie indĂ©pendante du code. + +C'est ce que nous allons rĂ©soudre : chargeons le modĂšle avant que les requĂȘtes ne soient traitĂ©es, mais seulement juste avant que l'application ne commence Ă  recevoir des requĂȘtes, pas pendant le chargement du code. + +## Cycle de vie { #lifespan } + +Vous pouvez dĂ©finir cette logique de *dĂ©marrage* et d'*arrĂȘt* en utilisant le paramĂštre `lifespan` de l'application `FastAPI`, et un « gestionnaire de contexte » (je vais vous montrer ce que c'est dans un instant). + +Commençons par un exemple, puis voyons-le en dĂ©tail. + +Nous crĂ©ons une fonction async `lifespan()` avec `yield` comme ceci : + +{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *} + +Ici, nous simulons l'opĂ©ration de *dĂ©marrage* coĂ»teuse de chargement du modĂšle en plaçant la fonction (factice) du modĂšle dans le dictionnaire avec les modĂšles d'apprentissage automatique avant le `yield`. Ce code sera exĂ©cutĂ© **avant** que l'application ne **commence Ă  recevoir des requĂȘtes**, pendant le *dĂ©marrage*. + +Puis, juste aprĂšs le `yield`, nous dĂ©chargeons le modĂšle. Ce code sera exĂ©cutĂ© **aprĂšs** que l'application **a fini de traiter les requĂȘtes**, juste avant l'*arrĂȘt*. Cela pourrait, par exemple, libĂ©rer des ressources comme la mĂ©moire ou un GPU. + +/// tip | Astuce + +L’« arrĂȘt » se produit lorsque vous **arrĂȘtez** l'application. + +Peut-ĂȘtre devez-vous dĂ©marrer une nouvelle version, ou vous en avez simplement assez de l'exĂ©cuter. đŸ€· + +/// + +### Fonction de cycle de vie { #lifespan-function } + +La premiĂšre chose Ă  remarquer est que nous dĂ©finissons une fonction async avec `yield`. C'est trĂšs similaire aux DĂ©pendances avec `yield`. + +{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *} + +La premiĂšre partie de la fonction, avant le `yield`, sera exĂ©cutĂ©e **avant** le dĂ©marrage de l'application. + +Et la partie aprĂšs le `yield` sera exĂ©cutĂ©e **aprĂšs** que l'application a terminĂ©. + +### Gestionnaire de contexte asynchrone { #async-context-manager } + +Si vous regardez, la fonction est dĂ©corĂ©e avec `@asynccontextmanager`. + +Cela convertit la fonction en quelque chose appelĂ© un « **gestionnaire de contexte asynchrone** ». + +{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *} + +Un **gestionnaire de contexte** en Python est quelque chose que vous pouvez utiliser dans une instruction `with`. Par exemple, `open()` peut ĂȘtre utilisĂ© comme gestionnaire de contexte : + +```Python +with open("file.txt") as file: + file.read() +``` + +Dans les versions rĂ©centes de Python, il existe aussi un **gestionnaire de contexte asynchrone**. Vous l'utiliseriez avec `async with` : + +```Python +async with lifespan(app): + await do_stuff() +``` + +Quand vous crĂ©ez un gestionnaire de contexte ou un gestionnaire de contexte asynchrone comme ci-dessus, ce qu'il fait, c'est qu'avant d'entrer dans le bloc `with`, il exĂ©cute le code avant le `yield`, et aprĂšs ĂȘtre sorti du bloc `with`, il exĂ©cute le code aprĂšs le `yield`. + +Dans notre exemple de code ci-dessus, nous ne l'utilisons pas directement, mais nous le transmettons Ă  FastAPI pour qu'il l'utilise. + +Le paramĂštre `lifespan` de l'application `FastAPI` accepte un **gestionnaire de contexte asynchrone**, nous pouvons donc lui passer notre nouveau gestionnaire de contexte asynchrone `lifespan`. + +{* ../../docs_src/events/tutorial003_py310.py hl[22] *} + +## ÉvĂ©nements alternatifs (dĂ©prĂ©ciĂ©) { #alternative-events-deprecated } + +/// warning | Alertes + +La mĂ©thode recommandĂ©e pour gĂ©rer le *dĂ©marrage* et l'*arrĂȘt* est d'utiliser le paramĂštre `lifespan` de l'application `FastAPI` comme dĂ©crit ci-dessus. Si vous fournissez un paramĂštre `lifespan`, les gestionnaires d'Ă©vĂ©nements `startup` et `shutdown` ne seront plus appelĂ©s. C'est soit tout en `lifespan`, soit tout en Ă©vĂ©nements, pas les deux. + +Vous pouvez probablement passer cette partie. + +/// + +Il existe une autre maniĂšre de dĂ©finir cette logique Ă  exĂ©cuter au *dĂ©marrage* et Ă  l'*arrĂȘt*. + +Vous pouvez dĂ©finir des gestionnaires d'Ă©vĂ©nements (fonctions) qui doivent ĂȘtre exĂ©cutĂ©s avant le dĂ©marrage de l'application, ou lorsque l'application s'arrĂȘte. + +Ces fonctions peuvent ĂȘtre dĂ©clarĂ©es avec `async def` ou un `def` normal. + +### ÉvĂ©nement `startup` { #startup-event } + +Pour ajouter une fonction qui doit ĂȘtre exĂ©cutĂ©e avant le dĂ©marrage de l'application, dĂ©clarez-la avec l'Ă©vĂ©nement « startup » : + +{* ../../docs_src/events/tutorial001_py310.py hl[8] *} + +Dans ce cas, la fonction gestionnaire de l'Ă©vĂ©nement `startup` initialisera la « base de donnĂ©es » des items (juste un `dict`) avec quelques valeurs. + +Vous pouvez ajouter plusieurs fonctions de gestion d'Ă©vĂ©nements. + +Et votre application ne commencera pas Ă  recevoir des requĂȘtes avant que tous les gestionnaires de l'Ă©vĂ©nement `startup` aient terminĂ©. + +### ÉvĂ©nement `shutdown` { #shutdown-event } + +Pour ajouter une fonction qui doit ĂȘtre exĂ©cutĂ©e lorsque l'application s'arrĂȘte, dĂ©clarez-la avec l'Ă©vĂ©nement « shutdown » : + +{* ../../docs_src/events/tutorial002_py310.py hl[6] *} + +Ici, la fonction gestionnaire de l'Ă©vĂ©nement `shutdown` Ă©crira une ligne de texte « Application shutdown » dans un fichier `log.txt`. + +/// info + +Dans la fonction `open()`, le `mode="a"` signifie « append » (ajouter) ; la ligne sera donc ajoutĂ©e aprĂšs ce qui se trouve dĂ©jĂ  dans ce fichier, sans Ă©craser le contenu prĂ©cĂ©dent. + +/// + +/// tip | Astuce + +Notez que dans ce cas, nous utilisons une fonction Python standard `open()` qui interagit avec un fichier. + +Cela implique des E/S (input/output), qui nĂ©cessitent « d'attendre » que des choses soient Ă©crites sur le disque. + +Mais `open()` n'utilise pas `async` et `await`. + +Nous dĂ©clarons donc la fonction gestionnaire d'Ă©vĂ©nement avec un `def` standard plutĂŽt qu'avec `async def`. + +/// + +### `startup` et `shutdown` ensemble { #startup-and-shutdown-together } + +Il y a de fortes chances que la logique de votre *dĂ©marrage* et de votre *arrĂȘt* soit liĂ©e : vous pourriez vouloir dĂ©marrer quelque chose puis le terminer, acquĂ©rir une ressource puis la libĂ©rer, etc. + +Faire cela dans des fonctions sĂ©parĂ©es qui ne partagent pas de logique ni de variables est plus difficile, car vous devriez stocker des valeurs dans des variables globales ou recourir Ă  des astuces similaires. + +Pour cette raison, il est dĂ©sormais recommandĂ© d'utiliser plutĂŽt le `lifespan` comme expliquĂ© ci-dessus. + +## DĂ©tails techniques { #technical-details } + +Juste un dĂ©tail technique pour les nerds curieux. đŸ€“ + +Sous le capot, dans la spĂ©cification technique ASGI, cela fait partie du protocole Lifespan, et il y dĂ©finit des Ă©vĂ©nements appelĂ©s `startup` et `shutdown`. + +/// info + +Vous pouvez en lire plus sur les gestionnaires `lifespan` de Starlette dans la documentation « Lifespan » de Starlette. + +Y compris comment gĂ©rer l'Ă©tat de cycle de vie qui peut ĂȘtre utilisĂ© dans d'autres parties de votre code. + +/// + +## Sous-applications { #sub-applications } + +🚹 Gardez Ă  l'esprit que ces Ă©vĂ©nements de cycle de vie (dĂ©marrage et arrĂȘt) ne seront exĂ©cutĂ©s que pour l'application principale, pas pour [Sous-applications - Montages](sub-applications.md){.internal-link target=_blank}. diff --git a/docs/fr/docs/advanced/generate-clients.md b/docs/fr/docs/advanced/generate-clients.md new file mode 100644 index 000000000..6f51ac7be --- /dev/null +++ b/docs/fr/docs/advanced/generate-clients.md @@ -0,0 +1,208 @@ +# GĂ©nĂ©rer des SDK { #generating-sdks } + +Parce que **FastAPI** est basĂ© sur la spĂ©cification **OpenAPI**, ses API peuvent ĂȘtre dĂ©crites dans un format standard compris par de nombreux outils. + +Cela facilite la gĂ©nĂ©ration de **documentation** Ă  jour, de bibliothĂšques clientes (**SDKs**) dans plusieurs langages, ainsi que de **tests** ou de **workflows d’automatisation** qui restent synchronisĂ©s avec votre code. + +Dans ce guide, vous apprendrez Ă  gĂ©nĂ©rer un **SDK TypeScript** pour votre backend FastAPI. + +## GĂ©nĂ©rateurs de SDK open source { #open-source-sdk-generators } + +Une option polyvalente est OpenAPI Generator, qui prend en charge **de nombreux langages de programmation** et peut gĂ©nĂ©rer des SDK Ă  partir de votre spĂ©cification OpenAPI. + +Pour les **clients TypeScript**, Hey API est une solution dĂ©diĂ©e, offrant une expĂ©rience optimisĂ©e pour l’écosystĂšme TypeScript. + +Vous pouvez dĂ©couvrir davantage de gĂ©nĂ©rateurs de SDK sur OpenAPI.Tools. + +/// tip | Astuce + +FastAPI gĂ©nĂšre automatiquement des spĂ©cifications **OpenAPI 3.1**, donc tout outil que vous utilisez doit prendre en charge cette version. + +/// + +## GĂ©nĂ©rateurs de SDK par les sponsors de FastAPI { #sdk-generators-from-fastapi-sponsors } + +Cette section met en avant des solutions **soutenues par des fonds** et **par des entreprises** qui sponsorisent FastAPI. Ces produits offrent **des fonctionnalitĂ©s supplĂ©mentaires** et **des intĂ©grations** en plus de SDK de haute qualitĂ© gĂ©nĂ©rĂ©s. + +En ✹ [**sponsorisant FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✹, ces entreprises contribuent Ă  garantir que le framework et son **Ă©cosystĂšme** restent sains et **durables**. + +Leur sponsoring dĂ©montre Ă©galement un fort engagement envers la **communautĂ©** FastAPI (vous), montrant qu’elles se soucient non seulement d’offrir un **excellent service**, mais aussi de soutenir un **framework robuste et florissant**, FastAPI. 🙇 + +Par exemple, vous pourriez essayer : + +* Speakeasy +* Stainless +* liblab + +Certaines de ces solutions peuvent aussi ĂȘtre open source ou proposer des niveaux gratuits, afin que vous puissiez les essayer sans engagement financier. D’autres gĂ©nĂ©rateurs de SDK commerciaux existent et peuvent ĂȘtre trouvĂ©s en ligne. đŸ€“ + +## CrĂ©er un SDK TypeScript { #create-a-typescript-sdk } + +Commençons par une application FastAPI simple : + +{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *} + +Remarquez que les *chemins d'accĂšs* dĂ©finissent les modĂšles qu’ils utilisent pour le payload de requĂȘte et le payload de rĂ©ponse, en utilisant les modĂšles `Item` et `ResponseMessage`. + +### Documentation de l’API { #api-docs } + +Si vous allez sur `/docs`, vous verrez qu’elle contient les **schĂ©mas** pour les donnĂ©es Ă  envoyer dans les requĂȘtes et reçues dans les rĂ©ponses : + + + +Vous voyez ces schĂ©mas parce qu’ils ont Ă©tĂ© dĂ©clarĂ©s avec les modĂšles dans l’application. + +Ces informations sont disponibles dans le **schĂ©ma OpenAPI** de l’application, puis affichĂ©es dans la documentation de l’API. + +Ces mĂȘmes informations issues des modĂšles, incluses dans OpenAPI, peuvent ĂȘtre utilisĂ©es pour **gĂ©nĂ©rer le code client**. + +### Hey API { #hey-api } + +Une fois que vous avez une application FastAPI avec les modĂšles, vous pouvez utiliser Hey API pour gĂ©nĂ©rer un client TypeScript. Le moyen le plus rapide de le faire est via npx. + +```sh +npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client +``` + +Cela gĂ©nĂ©rera un SDK TypeScript dans `./src/client`. + +Vous pouvez apprendre Ă  installer `@hey-api/openapi-ts` et lire Ă  propos du rĂ©sultat gĂ©nĂ©rĂ© sur leur site. + +### Utiliser le SDK { #using-the-sdk } + +Vous pouvez maintenant importer et utiliser le code client. Cela pourrait ressembler Ă  ceci, remarquez que vous obtenez l’autocomplĂ©tion pour les mĂ©thodes : + + + +Vous obtiendrez Ă©galement l’autocomplĂ©tion pour le payload Ă  envoyer : + + + +/// tip | Astuce + +Remarquez l’autocomplĂ©tion pour `name` et `price`, qui a Ă©tĂ© dĂ©finie dans l’application FastAPI, dans le modĂšle `Item`. + +/// + +Vous aurez des erreurs en ligne pour les donnĂ©es que vous envoyez : + + + +L’objet de rĂ©ponse aura Ă©galement l’autocomplĂ©tion : + + + +## Application FastAPI avec des tags { #fastapi-app-with-tags } + +Dans de nombreux cas, votre application FastAPI sera plus grande, et vous utiliserez probablement des tags pour sĂ©parer diffĂ©rents groupes de *chemins d'accĂšs*. + +Par exemple, vous pourriez avoir une section pour les **items** et une autre section pour les **users**, et elles pourraient ĂȘtre sĂ©parĂ©es par des tags : + +{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *} + +### GĂ©nĂ©rer un client TypeScript avec des tags { #generate-a-typescript-client-with-tags } + +Si vous gĂ©nĂ©rez un client pour une application FastAPI utilisant des tags, il sĂ©parera normalement aussi le code client en fonction des tags. + +De cette façon, vous pourrez avoir les Ă©lĂ©ments ordonnĂ©s et correctement groupĂ©s cĂŽtĂ© client : + + + +Dans ce cas, vous avez : + +* `ItemsService` +* `UsersService` + +### Noms des mĂ©thodes du client { #client-method-names } + +À l’heure actuelle, les noms de mĂ©thodes gĂ©nĂ©rĂ©s comme `createItemItemsPost` ne sont pas trĂšs propres : + +```TypeScript +ItemsService.createItemItemsPost({name: "Plumbus", price: 5}) +``` + +... c’est parce que le gĂ©nĂ©rateur de client utilise l’**operation ID** interne OpenAPI pour chaque *chemin d'accĂšs*. + +OpenAPI exige que chaque operation ID soit unique parmi tous les *chemins d'accĂšs*, donc FastAPI utilise le **nom de la fonction**, le **chemin**, et la **mĂ©thode/opĂ©ration HTTP** pour gĂ©nĂ©rer cet operation ID, car de cette façon il peut s’assurer que les operation IDs sont uniques. + +Mais je vais vous montrer comment amĂ©liorer cela ensuite. đŸ€“ + +## IDs d’opĂ©ration personnalisĂ©s et meilleurs noms de mĂ©thodes { #custom-operation-ids-and-better-method-names } + +Vous pouvez **modifier** la façon dont ces operation IDs sont **gĂ©nĂ©rĂ©s** pour les simplifier et obtenir des **noms de mĂ©thodes plus simples** dans les clients. + +Dans ce cas, vous devez vous assurer que chaque operation ID est **unique** d’une autre maniĂšre. + +Par exemple, vous pouvez vous assurer que chaque *chemin d'accĂšs* a un tag, puis gĂ©nĂ©rer l’operation ID Ă  partir du **tag** et du **nom** du *chemin d'accĂšs* (le nom de la fonction). + +### Fonction personnalisĂ©e de gĂ©nĂ©ration d’ID unique { #custom-generate-unique-id-function } + +FastAPI utilise un **ID unique** pour chaque *chemin d'accĂšs*, qui est utilisĂ© pour l’**operation ID** et Ă©galement pour les noms des modĂšles personnalisĂ©s nĂ©cessaires, pour les requĂȘtes ou les rĂ©ponses. + +Vous pouvez personnaliser cette fonction. Elle prend un `APIRoute` et retourne une chaĂźne. + +Par exemple, ici elle utilise le premier tag (vous n’en aurez probablement qu’un) et le nom du *chemin d'accĂšs* (le nom de la fonction). + +Vous pouvez ensuite passer cette fonction personnalisĂ©e Ă  **FastAPI** via le paramĂštre `generate_unique_id_function` : + +{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *} + +### GĂ©nĂ©rer un client TypeScript avec des IDs d’opĂ©ration personnalisĂ©s { #generate-a-typescript-client-with-custom-operation-ids } + +Maintenant, si vous rĂ©gĂ©nĂ©rez le client, vous verrez qu’il possĂšde des noms de mĂ©thodes amĂ©liorĂ©s : + + + +Comme vous le voyez, les noms de mĂ©thodes contiennent maintenant le tag puis le nom de la fonction ; ils n’incluent plus d’informations provenant du chemin d’URL et de l’opĂ©ration HTTP. + +### PrĂ©traiter la spĂ©cification OpenAPI pour le gĂ©nĂ©rateur de client { #preprocess-the-openapi-specification-for-the-client-generator } + +Le code gĂ©nĂ©rĂ© contient encore des **informations dupliquĂ©es**. + +Nous savons dĂ©jĂ  que cette mĂ©thode est liĂ©e aux **items** parce que ce mot figure dans `ItemsService` (issu du tag), mais nous avons encore le nom du tag prĂ©fixĂ© dans le nom de la mĂ©thode. 😕 + +Nous voudrons probablement le conserver pour OpenAPI en gĂ©nĂ©ral, car cela garantira que les operation IDs sont **uniques**. + +Mais pour le client gĂ©nĂ©rĂ©, nous pourrions **modifier** les operation IDs d’OpenAPI juste avant de gĂ©nĂ©rer les clients, simplement pour rendre ces noms de mĂ©thodes plus agrĂ©ables et **plus clairs**. + +Nous pourrions tĂ©lĂ©charger le JSON OpenAPI dans un fichier `openapi.json` puis **supprimer ce tag prĂ©fixĂ©** avec un script comme celui-ci : + +{* ../../docs_src/generate_clients/tutorial004_py310.py *} + +//// tab | Node.js + +```Javascript +{!> ../../docs_src/generate_clients/tutorial004.js!} +``` + +//// + +Avec cela, les operation IDs seraient renommĂ©s de `items-get_items` en simplement `get_items`, de sorte que le gĂ©nĂ©rateur de client puisse produire des noms de mĂ©thodes plus simples. + +### GĂ©nĂ©rer un client TypeScript avec l’OpenAPI prĂ©traitĂ© { #generate-a-typescript-client-with-the-preprocessed-openapi } + +Puisque le rĂ©sultat final se trouve maintenant dans un fichier `openapi.json`, vous devez mettre Ă  jour l’emplacement d’entrĂ©e : + +```sh +npx @hey-api/openapi-ts -i ./openapi.json -o src/client +``` + +AprĂšs avoir gĂ©nĂ©rĂ© le nouveau client, vous aurez dĂ©sormais des **noms de mĂ©thodes propres**, avec toute l’**autocomplĂ©tion**, les **erreurs en ligne**, etc. : + + + +## Avantages { #benefits } + +En utilisant les clients gĂ©nĂ©rĂ©s automatiquement, vous obtiendrez de l’**autocomplĂ©tion** pour : + +* MĂ©thodes. +* Payloads de requĂȘte dans le corps, paramĂštres de requĂȘte, etc. +* Payloads de rĂ©ponse. + +Vous auriez Ă©galement des **erreurs en ligne** pour tout. + +Et chaque fois que vous mettez Ă  jour le code du backend et **rĂ©gĂ©nĂ©rez** le frontend, il inclura les nouveaux *chemins d'accĂšs* disponibles en tant que mĂ©thodes, supprimera les anciens, et tout autre changement sera reflĂ©tĂ© dans le code gĂ©nĂ©rĂ©. đŸ€“ + +Cela signifie aussi que si quelque chose change, cela sera **reflĂ©tĂ©** automatiquement dans le code client. Et si vous **bĂątissez** le client, il Ă©chouera en cas de **discordance** dans les donnĂ©es utilisĂ©es. + +Ainsi, vous **dĂ©tecterez de nombreuses erreurs** trĂšs tĂŽt dans le cycle de dĂ©veloppement au lieu d’attendre qu’elles apparaissent pour vos utilisateurs finaux en production puis de tenter de dĂ©boguer l’origine du problĂšme. ✹ diff --git a/docs/fr/docs/advanced/middleware.md b/docs/fr/docs/advanced/middleware.md new file mode 100644 index 000000000..934c91041 --- /dev/null +++ b/docs/fr/docs/advanced/middleware.md @@ -0,0 +1,97 @@ +# Utiliser des middlewares avancĂ©s { #advanced-middleware } + +Dans le tutoriel principal, vous avez vu comment ajouter des [middlewares personnalisĂ©s](../tutorial/middleware.md){.internal-link target=_blank} Ă  votre application. + +Vous avez Ă©galement vu comment gĂ©rer [CORS avec le `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}. + +Dans cette section, nous allons voir comment utiliser d'autres middlewares. + +## Ajouter des middlewares ASGI { #adding-asgi-middlewares } + +Comme **FastAPI** est basĂ© sur Starlette et implĂ©mente la spĂ©cification ASGI, vous pouvez utiliser n'importe quel middleware ASGI. + +Un middleware n'a pas besoin d'ĂȘtre conçu pour FastAPI ou Starlette pour fonctionner, tant qu'il suit la spĂ©cification ASGI. + +En gĂ©nĂ©ral, les middlewares ASGI sont des classes qui s'attendent Ă  recevoir une application ASGI en premier argument. + +Ainsi, dans la documentation de middlewares ASGI tiers, on vous indiquera probablement de faire quelque chose comme : + +```Python +from unicorn import UnicornMiddleware + +app = SomeASGIApp() + +new_app = UnicornMiddleware(app, some_config="rainbow") +``` + +Mais FastAPI (en fait Starlette) fournit une maniĂšre plus simple de le faire, qui garantit que les middlewares internes gĂšrent les erreurs serveur et que les gestionnaires d'exceptions personnalisĂ©s fonctionnent correctement. + +Pour cela, vous utilisez `app.add_middleware()` (comme dans l'exemple pour CORS). + +```Python +from fastapi import FastAPI +from unicorn import UnicornMiddleware + +app = FastAPI() + +app.add_middleware(UnicornMiddleware, some_config="rainbow") +``` + +`app.add_middleware()` reçoit une classe de middleware en premier argument, ainsi que tout argument supplĂ©mentaire Ă  transmettre au middleware. + +## Utiliser les middlewares intĂ©grĂ©s { #integrated-middlewares } + +**FastAPI** inclut plusieurs middlewares pour des cas d'usage courants ; voyons comment les utiliser. + +/// note | DĂ©tails techniques + +Pour les prochains exemples, vous pourriez aussi utiliser `from starlette.middleware.something import SomethingMiddleware`. + +**FastAPI** fournit plusieurs middlewares dans `fastapi.middleware` simplement pour vous faciliter la vie, en tant que dĂ©veloppeur. Mais la plupart des middlewares disponibles viennent directement de Starlette. + +/// + +## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware } + +Impose que toutes les requĂȘtes entrantes soient soit `https`, soit `wss`. + +Toute requĂȘte entrante en `http` ou `ws` sera redirigĂ©e vers le schĂ©ma sĂ©curisĂ© correspondant. + +{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *} + +## `TrustedHostMiddleware` { #trustedhostmiddleware } + +Impose que toutes les requĂȘtes entrantes aient un en-tĂȘte `Host` correctement dĂ©fini, afin de se prĂ©munir contre les attaques de type HTTP Host Header. + +{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *} + +Les arguments suivants sont pris en charge : + +- `allowed_hosts` - Une liste de noms de domaine autorisĂ©s comme noms d'hĂŽte. Les domaines gĂ©nĂ©riques tels que `*.example.com` sont pris en charge pour faire correspondre les sous-domaines. Pour autoriser n'importe quel nom d'hĂŽte, utilisez `allowed_hosts=["*"]` ou omettez le middleware. +- `www_redirect` - Si dĂ©fini Ă  `True`, les requĂȘtes vers les versions sans www des hĂŽtes autorisĂ©s seront redirigĂ©es vers leurs Ă©quivalents avec www. Valeur par dĂ©faut : `True`. + +Si une requĂȘte entrante n'est pas valide, une rĂ©ponse `400` sera envoyĂ©e. + +## `GZipMiddleware` { #gzipmiddleware } + +GĂšre les rĂ©ponses GZip pour toute requĂȘte qui inclut « gzip » dans l'en-tĂȘte `Accept-Encoding`. + +Le middleware gĂ©rera les rĂ©ponses standard et en streaming. + +{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *} + +Les arguments suivants sont pris en charge : + +- `minimum_size` - Ne pas compresser en GZip les rĂ©ponses dont la taille est infĂ©rieure Ă  ce minimum en octets. Valeur par dĂ©faut : `500`. +- `compresslevel` - UtilisĂ© pendant la compression GZip. Entier compris entre 1 et 9. Valeur par dĂ©faut : `9`. Une valeur plus faible entraĂźne une compression plus rapide mais des fichiers plus volumineux, tandis qu'une valeur plus Ă©levĂ©e entraĂźne une compression plus lente mais des fichiers plus petits. + +## Autres middlewares { #other-middlewares } + +Il existe de nombreux autres middlewares ASGI. + +Par exemple : + +- Le `ProxyHeadersMiddleware` d'Uvicorn +- MessagePack + +Pour voir d'autres middlewares disponibles, consultez la documentation des middlewares de Starlette et la liste ASGI Awesome. diff --git a/docs/fr/docs/advanced/openapi-callbacks.md b/docs/fr/docs/advanced/openapi-callbacks.md new file mode 100644 index 000000000..669d9447a --- /dev/null +++ b/docs/fr/docs/advanced/openapi-callbacks.md @@ -0,0 +1,186 @@ +# Callbacks OpenAPI { #openapi-callbacks } + +Vous pourriez crĂ©er une API avec un *chemin d'accĂšs* qui dĂ©clenche une requĂȘte vers une *API externe* créée par quelqu'un d'autre (probablement la mĂȘme personne dĂ©veloppeuse qui utiliserait votre API). + +Le processus qui se produit lorsque votre application API appelle l’*API externe* s’appelle un « callback ». Parce que le logiciel Ă©crit par la personne dĂ©veloppeuse externe envoie une requĂȘte Ă  votre API puis votre API « rappelle », en envoyant une requĂȘte Ă  une *API externe* (probablement créée par la mĂȘme personne dĂ©veloppeuse). + +Dans ce cas, vous pourriez vouloir documenter Ă  quoi cette API externe devrait ressembler. Quel *chemin d'accĂšs* elle devrait avoir, quel corps elle devrait attendre, quelle rĂ©ponse elle devrait renvoyer, etc. + +## Une application avec des callbacks { #an-app-with-callbacks } + +Voyons tout cela avec un exemple. + +Imaginez que vous dĂ©veloppiez une application qui permet de crĂ©er des factures. + +Ces factures auront un `id`, un `title` (facultatif), un `customer` et un `total`. + +L’utilisateur de votre API (une personne dĂ©veloppeuse externe) crĂ©era une facture dans votre API avec une requĂȘte POST. + +Ensuite votre API va (imaginons) : + +* Envoyer la facture Ă  un client de la personne dĂ©veloppeuse externe. +* Encaisser l’argent. +* Renvoyer une notification Ă  l’utilisateur de l’API (la personne dĂ©veloppeuse externe). + * Cela sera fait en envoyant une requĂȘte POST (depuis *votre API*) vers une *API externe* fournie par cette personne dĂ©veloppeuse externe (c’est le « callback »). + +## L’application **FastAPI** normale { #the-normal-fastapi-app } + +Voyons d’abord Ă  quoi ressemble l’application API normale avant d’ajouter le callback. + +Elle aura un *chemin d'accĂšs* qui recevra un corps `Invoice`, et un paramĂštre de requĂȘte `callback_url` qui contiendra l’URL pour le callback. + +Cette partie est assez normale, la plupart du code vous est probablement dĂ©jĂ  familier : + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *} + +/// tip | Astuce + +Le paramĂštre de requĂȘte `callback_url` utilise un type Pydantic Url. + +/// + +La seule nouveautĂ© est `callbacks=invoices_callback_router.routes` comme argument du *dĂ©corateur de chemin d'accĂšs*. Nous allons voir ce que c’est ensuite. + +## Documenter le callback { #documenting-the-callback } + +Le code rĂ©el du callback dĂ©pendra fortement de votre application API. + +Et il variera probablement beaucoup d’une application Ă  l’autre. + +Cela pourrait ĂȘtre seulement une ou deux lignes de code, comme : + +```Python +callback_url = "https://example.com/api/v1/invoices/events/" +httpx.post(callback_url, json={"description": "Invoice paid", "paid": True}) +``` + +Mais la partie la plus importante du callback est sans doute de vous assurer que l’utilisateur de votre API (la personne dĂ©veloppeuse externe) implĂ©mente correctement l’*API externe*, conformĂ©ment aux donnĂ©es que *votre API* va envoyer dans le corps de la requĂȘte du callback, etc. + +Ainsi, ce que nous allons faire ensuite, c’est ajouter le code pour documenter Ă  quoi cette *API externe* devrait ressembler pour recevoir le callback de *votre API*. + +Cette documentation apparaĂźtra dans Swagger UI Ă  `/docs` dans votre API, et permettra aux personnes dĂ©veloppeuses externes de savoir comment construire l’*API externe*. + +Cet exemple n’implĂ©mente pas le callback lui-mĂȘme (qui pourrait ĂȘtre une simple ligne de code), uniquement la partie documentation. + +/// tip | Astuce + +Le callback rĂ©el n’est qu’une requĂȘte HTTP. + +En implĂ©mentant vous-mĂȘme le callback, vous pourriez utiliser quelque chose comme HTTPX ou Requests. + +/// + +## Écrire le code de documentation du callback { #write-the-callback-documentation-code } + +Ce code ne sera pas exĂ©cutĂ© dans votre application, nous en avons seulement besoin pour *documenter* Ă  quoi devrait ressembler cette *API externe*. + +Mais vous savez dĂ©jĂ  comment crĂ©er facilement une documentation automatique pour une API avec **FastAPI**. + +Nous allons donc utiliser ce mĂȘme savoir pour documenter Ă  quoi l’*API externe* devrait ressembler ... en crĂ©ant le(s) *chemin(s) d'accĂšs* que l’API externe devrait implĂ©menter (ceux que votre API appellera). + +/// tip | Astuce + +Lorsque vous Ă©crivez le code pour documenter un callback, il peut ĂȘtre utile d’imaginer que vous ĂȘtes cette *personne dĂ©veloppeuse externe*. Et que vous implĂ©mentez actuellement l’*API externe*, pas *votre API*. + +Adopter temporairement ce point de vue (celui de la *personne dĂ©veloppeuse externe*) peut vous aider Ă  trouver plus Ă©vident oĂč placer les paramĂštres, le modĂšle Pydantic pour le corps, pour la rĂ©ponse, etc., pour cette *API externe*. + +/// + +### CrĂ©er un `APIRouter` de callback { #create-a-callback-apirouter } + +Commencez par crĂ©er un nouveau `APIRouter` qui contiendra un ou plusieurs callbacks. + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *} + +### CrĂ©er le *chemin d'accĂšs* du callback { #create-the-callback-path-operation } + +Pour crĂ©er le *chemin d'accĂšs* du callback, utilisez le mĂȘme `APIRouter` que vous avez créé ci-dessus. + +Il devrait ressembler exactement Ă  un *chemin d'accĂšs* FastAPI normal : + +* Il devrait probablement dĂ©clarer le corps qu’il doit recevoir, par exemple `body: InvoiceEvent`. +* Et il pourrait aussi dĂ©clarer la rĂ©ponse qu’il doit renvoyer, par exemple `response_model=InvoiceEventReceived`. + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *} + +Il y a 2 principales diffĂ©rences par rapport Ă  un *chemin d'accĂšs* normal : + +* Il n’a pas besoin d’avoir de code rĂ©el, car votre application n’appellera jamais ce code. Il sert uniquement Ă  documenter l’*API externe*. La fonction peut donc simplement contenir `pass`. +* Le *chemin* peut contenir une expression OpenAPI 3 (voir plus bas) oĂč il peut utiliser des variables avec des paramĂštres et des parties de la requĂȘte originale envoyĂ©e Ă  *votre API*. + +### L’expression du chemin de callback { #the-callback-path-expression } + +Le *chemin* du callback peut contenir une expression OpenAPI 3 qui peut inclure des parties de la requĂȘte originale envoyĂ©e Ă  *votre API*. + +Dans ce cas, c’est la `str` : + +```Python +"{$callback_url}/invoices/{$request.body.id}" +``` + +Ainsi, si l’utilisateur de votre API (la personne dĂ©veloppeuse externe) envoie une requĂȘte Ă  *votre API* vers : + +``` +https://yourapi.com/invoices/?callback_url=https://www.external.org/events +``` + +avec un corps JSON : + +```JSON +{ + "id": "2expen51ve", + "customer": "Mr. Richie Rich", + "total": "9999" +} +``` + +alors *votre API* traitera la facture et, Ă  un moment ultĂ©rieur, enverra une requĂȘte de callback Ă  `callback_url` (l’*API externe*) : + +``` +https://www.external.org/events/invoices/2expen51ve +``` + +avec un corps JSON contenant quelque chose comme : + +```JSON +{ + "description": "Payment celebration", + "paid": true +} +``` + +et elle s’attendra Ă  une rĂ©ponse de cette *API externe* avec un corps JSON comme : + +```JSON +{ + "ok": true +} +``` + +/// tip | Astuce + +Remarquez que l’URL de callback utilisĂ©e contient l’URL reçue en paramĂštre de requĂȘte dans `callback_url` (`https://www.external.org/events`) et aussi l’`id` de la facture Ă  l’intĂ©rieur du corps JSON (`2expen51ve`). + +/// + +### Ajouter le routeur de callback { #add-the-callback-router } + +À ce stade, vous avez le(s) *chemin(s) d'accĂšs de callback* nĂ©cessaire(s) (celui/ceux que la *personne dĂ©veloppeuse externe* doit implĂ©menter dans l’*API externe*) dans le routeur de callback que vous avez créé ci-dessus. + +Utilisez maintenant le paramĂštre `callbacks` dans *le dĂ©corateur de chemin d'accĂšs de votre API* pour passer l’attribut `.routes` (qui est en fait juste une `list` de routes/*chemins d'accĂšs*) depuis ce routeur de callback : + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *} + +/// tip | Astuce + +Remarquez que vous ne passez pas le routeur lui-mĂȘme (`invoices_callback_router`) Ă  `callback=`, mais l’attribut `.routes`, comme dans `invoices_callback_router.routes`. + +/// + +### VĂ©rifier la documentation { #check-the-docs } + +Vous pouvez maintenant dĂ©marrer votre application et aller sur http://127.0.0.1:8000/docs. + +Vous verrez votre documentation incluant une section « Callbacks » pour votre *chemin d'accĂšs* qui montre Ă  quoi l’*API externe* devrait ressembler : + + diff --git a/docs/fr/docs/advanced/openapi-webhooks.md b/docs/fr/docs/advanced/openapi-webhooks.md new file mode 100644 index 000000000..21b6f5f00 --- /dev/null +++ b/docs/fr/docs/advanced/openapi-webhooks.md @@ -0,0 +1,55 @@ +# Webhooks OpenAPI { #openapi-webhooks } + +Il existe des cas oĂč vous voulez informer les utilisateurs de votre API que votre application peut appeler leur application (en envoyant une requĂȘte) avec des donnĂ©es, gĂ©nĂ©ralement pour notifier un type d'Ă©vĂ©nement. + +Cela signifie qu'au lieu du processus habituel oĂč vos utilisateurs envoient des requĂȘtes Ă  votre API, c'est votre API (ou votre application) qui peut envoyer des requĂȘtes vers leur systĂšme (vers leur API, leur application). + +On appelle gĂ©nĂ©ralement cela un webhook. + +## Étapes des webhooks { #webhooks-steps } + +Le processus consiste gĂ©nĂ©ralement Ă  dĂ©finir dans votre code le message que vous enverrez, c'est-Ă -dire le corps de la requĂȘte. + +Vous dĂ©finissez Ă©galement, d'une maniĂšre ou d'une autre, Ă  quels moments votre application enverra ces requĂȘtes ou Ă©vĂ©nements. + +Et vos utilisateurs dĂ©finissent aussi, d'une maniĂšre ou d'une autre (par exemple dans un tableau de bord Web), l'URL Ă  laquelle votre application doit envoyer ces requĂȘtes. + +Toute la logique de gestion des URL des webhooks et le code qui envoie effectivement ces requĂȘtes vous incombent. Vous l'implĂ©mentez comme vous le souhaitez dans votre propre code. + +## Documenter des webhooks avec FastAPI et OpenAPI { #documenting-webhooks-with-fastapi-and-openapi } + +Avec FastAPI, en utilisant OpenAPI, vous pouvez dĂ©finir les noms de ces webhooks, les types d'opĂ©rations HTTP que votre application peut envoyer (par exemple `POST`, `PUT`, etc.) et les corps des requĂȘtes que votre application enverra. + +Cela peut grandement faciliter la tĂąche de vos utilisateurs pour implĂ©menter leurs API afin de recevoir vos requĂȘtes de webhook ; ils pourront mĂȘme peut-ĂȘtre gĂ©nĂ©rer automatiquement une partie de leur propre code d'API. + +/// info + +Les webhooks sont disponibles dans OpenAPI 3.1.0 et versions ultĂ©rieures, pris en charge par FastAPI `0.99.0` et versions ultĂ©rieures. + +/// + +## CrĂ©er une application avec des webhooks { #an-app-with-webhooks } + +Lorsque vous crĂ©ez une application FastAPI, il existe un attribut `webhooks` que vous pouvez utiliser pour dĂ©finir des webhooks, de la mĂȘme maniĂšre que vous dĂ©finiriez des chemins d'accĂšs, par exemple avec `@app.webhooks.post()`. + +{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *} + +Les webhooks que vous dĂ©finissez apparaĂźtront dans le schĂ©ma **OpenAPI** et dans l'interface de **documentation** automatique. + +/// info + +L'objet `app.webhooks` est en fait simplement un `APIRouter`, le mĂȘme type que vous utiliseriez pour structurer votre application en plusieurs fichiers. + +/// + +Notez qu'avec les webhooks, vous ne dĂ©clarez pas rĂ©ellement un chemin (comme `/items/`), le texte que vous y passez est simplement un identifiant du webhook (le nom de l'Ă©vĂ©nement). Par exemple, dans `@app.webhooks.post("new-subscription")`, le nom du webhook est `new-subscription`. + +C'est parce qu'on s'attend Ă  ce que vos utilisateurs dĂ©finissent, par un autre moyen (par exemple un tableau de bord Web), le vĂ©ritable chemin d'URL oĂč ils souhaitent recevoir la requĂȘte de webhook. + +### Consulter la documentation { #check-the-docs } + +Vous pouvez maintenant dĂ©marrer votre application et aller sur http://127.0.0.1:8000/docs. + +Vous verrez que votre documentation contient les chemins d'accĂšs habituels et dĂ©sormais aussi des webhooks : + + diff --git a/docs/fr/docs/advanced/path-operation-advanced-configuration.md b/docs/fr/docs/advanced/path-operation-advanced-configuration.md index fc88f3363..b482f97cc 100644 --- a/docs/fr/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/fr/docs/advanced/path-operation-advanced-configuration.md @@ -12,7 +12,7 @@ Vous pouvez dĂ©finir l’OpenAPI `operationId` Ă  utiliser dans votre chemin d 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_py310.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 } @@ -20,7 +20,7 @@ Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, Vous devez le faire aprĂšs avoir ajoutĂ© tous vos chemins d’accĂšs. -{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *} /// tip | Astuce @@ -40,7 +40,7 @@ MĂȘme si elles se trouvent dans des modules diffĂ©rents (fichiers Python). Pour exclure un chemin d’accĂšs du schĂ©ma OpenAPI gĂ©nĂ©rĂ© (et donc des systĂšmes de documentation automatiques), utilisez le paramĂštre `include_in_schema` et dĂ©finissez-le Ă  `False` : -{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *} ## Description avancĂ©e depuis la docstring { #advanced-description-from-docstring } @@ -92,7 +92,7 @@ Vous pouvez Ă©tendre le schĂ©ma OpenAPI pour un chemin d’accĂšs en utilisant l Cet `openapi_extra` peut ĂȘtre utile, par exemple, pour dĂ©clarer des [Extensions OpenAPI](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_py310.py hl[6] *} Si vous ouvrez la documentation automatique de l’API, votre extension apparaĂźtra en bas du chemin d’accĂšs spĂ©cifique. @@ -139,9 +139,9 @@ Par exemple, vous pourriez dĂ©cider de lire et de valider la requĂȘte avec votre Vous pourriez 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_py310.py hl[19:36, 39:40] *} -Dans cet exemple, nous n’avons dĂ©clarĂ© aucun modĂšle Pydantic. En fait, le corps de la requĂȘte n’est mĂȘme pas parsĂ© en 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 parsĂ© en 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. NĂ©anmoins, nous pouvons dĂ©clarer le schĂ©ma attendu pour le corps de la requĂȘte. @@ -153,7 +153,7 @@ Et vous pourriez le faire mĂȘme si le type de donnĂ©es dans la requĂȘte n’est Par exemple, dans cette application nous n’utilisons pas la fonctionnalitĂ© intĂ©grĂ©e de FastAPI pour extraire le JSON Schema des modĂšles Pydantic ni la validation automatique pour le JSON. En fait, nous dĂ©clarons le type de contenu de la requĂȘte comme YAML, pas JSON : -{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *} NĂ©anmoins, bien que nous n’utilisions pas la fonctionnalitĂ© intĂ©grĂ©e par dĂ©faut, nous utilisons toujours un modĂšle Pydantic pour gĂ©nĂ©rer manuellement le JSON Schema pour les donnĂ©es que nous souhaitons recevoir en YAML. @@ -161,7 +161,7 @@ Ensuite, nous utilisons directement la requĂȘte et extrayons le corps en tant qu Ensuite, dans notre code, 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_py310.py hl[24:31] *} /// tip | Astuce diff --git a/docs/fr/docs/advanced/response-change-status-code.md b/docs/fr/docs/advanced/response-change-status-code.md new file mode 100644 index 000000000..d08e87099 --- /dev/null +++ b/docs/fr/docs/advanced/response-change-status-code.md @@ -0,0 +1,31 @@ +# RĂ©ponse - Modifier le code d'Ă©tat { #response-change-status-code } + +Vous avez probablement dĂ©jĂ  lu que vous pouvez dĂ©finir un [Code d'Ă©tat de la rĂ©ponse](../tutorial/response-status-code.md){.internal-link target=_blank} par dĂ©faut. + +Mais dans certains cas, vous devez renvoyer un code d'Ă©tat diffĂ©rent de celui par dĂ©faut. + +## Cas d'utilisation { #use-case } + +Par exemple, imaginez que vous vouliez renvoyer par dĂ©faut un code d'Ă©tat HTTP « OK » `200`. + +Mais si les donnĂ©es n'existent pas, vous voulez les crĂ©er et renvoyer un code d'Ă©tat HTTP « CREATED » `201`. + +Mais vous souhaitez toujours pouvoir filtrer et convertir les donnĂ©es que vous renvoyez avec un `response_model`. + +Pour ces cas, vous pouvez utiliser un paramĂštre `Response`. + +## Utiliser un paramĂštre `Response` { #use-a-response-parameter } + +Vous pouvez dĂ©clarer un paramĂštre de type `Response` dans votre fonction de chemin d'accĂšs (comme vous pouvez le faire pour les cookies et les en-tĂȘtes). + +Vous pouvez ensuite dĂ©finir le `status_code` dans cet objet de rĂ©ponse *temporaire*. + +{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *} + +Vous pouvez ensuite renvoyer n'importe quel objet nĂ©cessaire, comme d'habitude (un `dict`, un modĂšle de base de donnĂ©es, etc.). + +Et si vous avez dĂ©clarĂ© un `response_model`, il sera toujours utilisĂ© pour filtrer et convertir l'objet que vous avez renvoyĂ©. + +**FastAPI** utilisera cette rĂ©ponse *temporaire* pour extraire le code d'Ă©tat (ainsi que les cookies et les en-tĂȘtes), et les placera dans la rĂ©ponse finale qui contient la valeur que vous avez renvoyĂ©e, filtrĂ©e par tout `response_model`. + +Vous pouvez Ă©galement dĂ©clarer le paramĂštre `Response` dans des dĂ©pendances et y dĂ©finir le code d'Ă©tat. Mais gardez Ă  l'esprit que la derniĂšre valeur dĂ©finie prĂ©vaut. diff --git a/docs/fr/docs/advanced/response-cookies.md b/docs/fr/docs/advanced/response-cookies.md new file mode 100644 index 000000000..d3e51f331 --- /dev/null +++ b/docs/fr/docs/advanced/response-cookies.md @@ -0,0 +1,51 @@ +# Cookies de rĂ©ponse { #response-cookies } + +## Utiliser un paramĂštre `Response` { #use-a-response-parameter } + +Vous pouvez dĂ©clarer un paramĂštre de type `Response` dans votre fonction de chemin d'accĂšs. + +Vous pouvez ensuite dĂ©finir des cookies dans cet objet de rĂ©ponse *temporaire*. + +{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *} + +Vous pouvez ensuite renvoyer n'importe quel objet dont vous avez besoin, comme d'habitude (un `dict`, un modĂšle de base de donnĂ©es, etc.). + +Et si vous avez dĂ©clarĂ© un `response_model`, il sera toujours utilisĂ© pour filtrer et convertir l'objet que vous avez renvoyĂ©. + +**FastAPI** utilisera cette rĂ©ponse *temporaire* pour extraire les cookies (ainsi que les en-tĂȘtes et le code d'Ă©tat), et les placera dans la rĂ©ponse finale qui contient la valeur que vous avez renvoyĂ©e, filtrĂ©e par tout `response_model`. + +Vous pouvez Ă©galement dĂ©clarer le paramĂštre `Response` dans des dĂ©pendances, et y dĂ©finir des cookies (et des en-tĂȘtes). + +## Renvoyer une `Response` directement { #return-a-response-directly } + +Vous pouvez Ă©galement crĂ©er des cookies en renvoyant une `Response` directement dans votre code. + +Pour ce faire, vous pouvez crĂ©er une rĂ©ponse comme dĂ©crit dans [Renvoyer une Response directement](response-directly.md){.internal-link target=_blank}. + +DĂ©finissez ensuite des cookies dessus, puis renvoyez-la : + +{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *} + +/// tip | Astuce + +Gardez Ă  l'esprit que si vous renvoyez une rĂ©ponse directement au lieu d'utiliser le paramĂštre `Response`, FastAPI la renverra telle quelle. + +Vous devez donc vous assurer que vos donnĂ©es sont du type correct. Par exemple, qu'elles sont compatibles avec JSON si vous renvoyez une `JSONResponse`. + +Et Ă©galement que vous n'envoyez pas de donnĂ©es qui auraient dĂ» ĂȘtre filtrĂ©es par un `response_model`. + +/// + +### En savoir plus { #more-info } + +/// note | DĂ©tails techniques + +Vous pouvez Ă©galement utiliser `from starlette.responses import Response` ou `from starlette.responses import JSONResponse`. + +**FastAPI** fournit les mĂȘmes `starlette.responses` que `fastapi.responses` simplement pour votre commoditĂ©, en tant que dĂ©veloppeur. Mais la plupart des rĂ©ponses disponibles proviennent directement de Starlette. + +Et comme `Response` peut ĂȘtre utilisĂ© frĂ©quemment pour dĂ©finir des en-tĂȘtes et des cookies, **FastAPI** la met Ă©galement Ă  disposition via `fastapi.Response`. + +/// + +Pour voir tous les paramĂštres et options disponibles, consultez la documentation de Starlette. diff --git a/docs/fr/docs/advanced/response-directly.md b/docs/fr/docs/advanced/response-directly.md index f35c39c06..4a4951864 100644 --- a/docs/fr/docs/advanced/response-directly.md +++ b/docs/fr/docs/advanced/response-directly.md @@ -22,7 +22,7 @@ En fait, vous pouvez retourner n'importe quelle `Response` ou n'importe quelle s Et quand vous retournez une `Response`, **FastAPI** la transmet directement. -Elle ne fera aucune conversion de donnĂ©es avec les modĂšles Pydantic, elle ne convertira pas le contenu en un type quelconque. +Elle ne fera aucune conversion de donnĂ©es avec les modĂšles Pydantic, elle ne convertira pas le contenu en un type quelconque, etc. Cela vous donne beaucoup de flexibilitĂ©. Vous pouvez retourner n'importe quel type de donnĂ©es, surcharger n'importe quelle dĂ©claration ou validation de donnĂ©es, etc. @@ -54,7 +54,7 @@ Disons que vous voulez retourner une rĂ©ponse en utilisant le prĂ©fixe `X-`. + +Mais si vous avez des en-tĂȘtes personnalisĂ©s que vous voulez qu'un client dans un navigateur puisse voir, vous devez les ajouter Ă  vos configurations CORS (en savoir plus dans [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), en utilisant le paramĂštre `expose_headers` documentĂ© dans la documentation CORS de Starlette. diff --git a/docs/fr/docs/advanced/security/http-basic-auth.md b/docs/fr/docs/advanced/security/http-basic-auth.md new file mode 100644 index 000000000..a8742ce7c --- /dev/null +++ b/docs/fr/docs/advanced/security/http-basic-auth.md @@ -0,0 +1,107 @@ +# Authentification HTTP Basic { #http-basic-auth } + +Pour les cas les plus simples, vous pouvez utiliser l'authentification HTTP Basic. + +Avec l'authentification HTTP Basic, l'application attend un en-tĂȘte contenant un nom d'utilisateur et un mot de passe. + +Si elle ne le reçoit pas, elle renvoie une erreur HTTP 401 « Unauthorized ». + +Et elle renvoie un en-tĂȘte `WWW-Authenticate` avec la valeur `Basic`, et un paramĂštre optionnel `realm`. + +Cela indique au navigateur d'afficher l'invite intĂ©grĂ©e pour saisir un nom d'utilisateur et un mot de passe. + +Ensuite, lorsque vous saisissez ce nom d'utilisateur et ce mot de passe, le navigateur les envoie automatiquement dans l'en-tĂȘte. + +## Authentification HTTP Basic simple { #simple-http-basic-auth } + +- Importer `HTTPBasic` et `HTTPBasicCredentials`. +- CrĂ©er un « schĂ©ma de sĂ©curitĂ© » en utilisant `HTTPBasic`. +- Utiliser ce `security` avec une dĂ©pendance dans votre chemin d'accĂšs. +- Cela renvoie un objet de type `HTTPBasicCredentials` : + - Il contient le `username` et le `password` envoyĂ©s. + +{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *} + +Lorsque vous essayez d'ouvrir l'URL pour la premiĂšre fois (ou cliquez sur le bouton « Execute » dans les documents) le navigateur vous demandera votre nom d'utilisateur et votre mot de passe : + + + +## VĂ©rifier le nom d'utilisateur { #check-the-username } + +Voici un exemple plus complet. + +Utilisez une dĂ©pendance pour vĂ©rifier si le nom d'utilisateur et le mot de passe sont corrects. + +Pour cela, utilisez le module standard Python `secrets` pour vĂ©rifier le nom d'utilisateur et le mot de passe. + +`secrets.compare_digest()` doit recevoir des `bytes` ou une `str` ne contenant que des caractĂšres ASCII (ceux de l'anglais), ce qui signifie qu'elle ne fonctionnerait pas avec des caractĂšres comme `ĂĄ`, comme dans `SebastiĂĄn`. + +Pour gĂ©rer cela, nous convertissons d'abord `username` et `password` en `bytes` en les encodant en UTF-8. + +Nous pouvons ensuite utiliser `secrets.compare_digest()` pour vĂ©rifier que `credentials.username` est « stanleyjobson » et que `credentials.password` est « swordfish ». + +{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *} + +Cela serait Ă©quivalent Ă  : + +```Python +if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"): + # Renvoyer une erreur + ... +``` + +Mais en utilisant `secrets.compare_digest()`, cela sera sĂ©curisĂ© contre un type d'attaques appelĂ© « attaques par chronomĂ©trage ». + +### Attaques par chronomĂ©trage { #timing-attacks } + +Mais qu'est-ce qu'une « attaque par chronomĂ©trage » ? + +Imaginons que des attaquants essaient de deviner le nom d'utilisateur et le mot de passe. + +Ils envoient alors une requĂȘte avec un nom d'utilisateur `johndoe` et un mot de passe `love123`. + +Le code Python de votre application serait alors Ă©quivalent Ă  quelque chose comme : + +```Python +if "johndoe" == "stanleyjobson" and "love123" == "swordfish": + ... +``` + +Mais au moment oĂč Python compare le premier `j` de `johndoe` au premier `s` de `stanleyjobson`, il retournera `False`, car il sait dĂ©jĂ  que ces deux chaĂźnes ne sont pas identiques, en se disant qu'« il n'est pas nĂ©cessaire de gaspiller plus de calcul pour comparer le reste des lettres ». Et votre application dira « Nom d'utilisateur ou mot de passe incorrect ». + +Mais ensuite, les attaquants essaient avec le nom d'utilisateur `stanleyjobsox` et le mot de passe `love123`. + +Et le code de votre application fait quelque chose comme : + +```Python +if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish": + ... +``` + +Python devra comparer tout `stanleyjobso` dans `stanleyjobsox` et `stanleyjobson` avant de rĂ©aliser que les deux chaĂźnes ne sont pas identiques. Cela prendra donc quelques microsecondes supplĂ©mentaires pour rĂ©pondre « Nom d'utilisateur ou mot de passe incorrect ». + +#### Le temps de rĂ©ponse aide les attaquants { #the-time-to-answer-helps-the-attackers } + +À ce stade, en remarquant que le serveur a mis quelques microsecondes de plus Ă  envoyer la rĂ©ponse « Nom d'utilisateur ou mot de passe incorrect », les attaquants sauront qu'ils ont trouvĂ© quelque chose de juste : certaines des premiĂšres lettres Ă©taient correctes. + +Ils peuvent alors rĂ©essayer en sachant que c'est probablement quelque chose de plus proche de `stanleyjobsox` que de `johndoe`. + +#### Une attaque « professionnelle » { #a-professional-attack } + +Bien sĂ»r, les attaquants n'essaieraient pas tout cela Ă  la main ; ils Ă©criraient un programme pour le faire, avec Ă©ventuellement des milliers ou des millions de tests par seconde. Ils obtiendraient une lettre correcte supplĂ©mentaire Ă  la fois. + +Ce faisant, en quelques minutes ou heures, les attaquants devineraient le nom d'utilisateur et le mot de passe corrects, avec « l'aide » de notre application, simplement en se basant sur le temps de rĂ©ponse. + +#### Corrigez-le avec `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest } + +Mais dans notre code nous utilisons justement `secrets.compare_digest()`. + +En bref, il faudra le mĂȘme temps pour comparer `stanleyjobsox` Ă  `stanleyjobson` que pour comparer `johndoe` Ă  `stanleyjobson`. Il en va de mĂȘme pour le mot de passe. + +Ainsi, en utilisant `secrets.compare_digest()` dans le code de votre application, votre application sera protĂ©gĂ©e contre toute cette gamme d'attaques de sĂ©curitĂ©. + +### Renvoyer l'erreur { #return-the-error } + +AprĂšs avoir dĂ©tectĂ© que les identifiants sont incorrects, renvoyez une `HTTPException` avec un code d'Ă©tat 401 (le mĂȘme que lorsque aucun identifiant n'est fourni) et ajoutez l'en-tĂȘte `WWW-Authenticate` pour que le navigateur affiche Ă  nouveau l'invite de connexion : + +{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *} diff --git a/docs/fr/docs/advanced/security/index.md b/docs/fr/docs/advanced/security/index.md new file mode 100644 index 000000000..e84fcef62 --- /dev/null +++ b/docs/fr/docs/advanced/security/index.md @@ -0,0 +1,19 @@ +# SĂ©curitĂ© avancĂ©e { #advanced-security } + +## FonctionnalitĂ©s supplĂ©mentaires { #additional-features } + +Il existe des fonctionnalitĂ©s supplĂ©mentaires pour gĂ©rer la sĂ©curitĂ© en plus de celles couvertes dans le [Tutoriel - Guide utilisateur : SĂ©curitĂ©](../../tutorial/security/index.md){.internal-link target=_blank}. + +/// tip | Astuce + +Les sections suivantes ne sont pas nĂ©cessairement « advanced ». + +Et il est possible que, pour votre cas d’utilisation, la solution se trouve dans l’une d’entre elles. + +/// + +## Lire d’abord le tutoriel { #read-the-tutorial-first } + +Les sections suivantes partent du principe que vous avez dĂ©jĂ  lu le [Tutoriel - Guide utilisateur : SĂ©curitĂ©](../../tutorial/security/index.md){.internal-link target=_blank} principal. + +Elles s’appuient toutes sur les mĂȘmes concepts, mais permettent des fonctionnalitĂ©s supplĂ©mentaires. diff --git a/docs/fr/docs/advanced/security/oauth2-scopes.md b/docs/fr/docs/advanced/security/oauth2-scopes.md new file mode 100644 index 000000000..c890a5129 --- /dev/null +++ b/docs/fr/docs/advanced/security/oauth2-scopes.md @@ -0,0 +1,274 @@ +# Scopes OAuth2 { #oauth2-scopes } + +Vous pouvez utiliser des scopes OAuth2 directement avec **FastAPI**, ils sont intĂ©grĂ©s pour fonctionner de maniĂšre transparente. + +Cela vous permettrait d’avoir un systĂšme d’autorisations plus fin, conforme au standard OAuth2, intĂ©grĂ© Ă  votre application OpenAPI (et Ă  la documentation de l’API). + +OAuth2 avec scopes est le mĂ©canisme utilisĂ© par de nombreux grands fournisseurs d’authentification, comme Facebook, Google, GitHub, Microsoft, X (Twitter), etc. Ils l’utilisent pour fournir des permissions spĂ©cifiques aux utilisateurs et aux applications. + +Chaque fois que vous « log in with » Facebook, Google, GitHub, Microsoft, X (Twitter), cette application utilise OAuth2 avec scopes. + +Dans cette section, vous verrez comment gĂ©rer l’authentification et l’autorisation avec le mĂȘme OAuth2 avec scopes dans votre application **FastAPI**. + +/// warning | Alertes + +C’est une section plus ou moins avancĂ©e. Si vous dĂ©butez, vous pouvez la passer. + +Vous n’avez pas nĂ©cessairement besoin des scopes OAuth2, et vous pouvez gĂ©rer l’authentification et l’autorisation comme vous le souhaitez. + +Mais OAuth2 avec scopes peut s’intĂ©grer Ă©lĂ©gamment Ă  votre API (avec OpenAPI) et Ă  votre documentation d’API. + +NĂ©anmoins, c’est toujours Ă  vous de faire appliquer ces scopes, ou toute autre exigence de sĂ©curitĂ©/autorisation, selon vos besoins, dans votre code. + +Dans de nombreux cas, OAuth2 avec scopes peut ĂȘtre excessif. + +Mais si vous savez que vous en avez besoin, ou si vous ĂȘtes curieux, continuez Ă  lire. + +/// + +## Scopes OAuth2 et OpenAPI { #oauth2-scopes-and-openapi } + +La spĂ©cification OAuth2 dĂ©finit des « scopes » comme une liste de chaĂźnes sĂ©parĂ©es par des espaces. + +Le contenu de chacune de ces chaĂźnes peut avoir n’importe quel format, mais ne doit pas contenir d’espaces. + +Ces scopes reprĂ©sentent des « permissions ». + +Dans OpenAPI (par ex. la documentation de l’API), vous pouvez dĂ©finir des « schĂ©mas de sĂ©curitĂ© ». + +Lorsqu’un de ces schĂ©mas de sĂ©curitĂ© utilise OAuth2, vous pouvez aussi dĂ©clarer et utiliser des scopes. + +Chaque « scope » est juste une chaĂźne (sans espaces). + +Ils sont gĂ©nĂ©ralement utilisĂ©s pour dĂ©clarer des permissions de sĂ©curitĂ© spĂ©cifiques, par exemple : + +* `users:read` ou `users:write` sont des exemples courants. +* `instagram_basic` est utilisĂ© par Facebook / Instagram. +* `https://www.googleapis.com/auth/drive` est utilisĂ© par Google. + +/// info + +Dans OAuth2, un « scope » est simplement une chaĂźne qui dĂ©clare une permission spĂ©cifique requise. + +Peu importe s’il contient d’autres caractĂšres comme `:` ou si c’est une URL. + +Ces dĂ©tails dĂ©pendent de l’implĂ©mentation. + +Pour OAuth2, ce ne sont que des chaĂźnes. + +/// + +## Vue d’ensemble { #global-view } + +Voyons d’abord rapidement les parties qui changent par rapport aux exemples du **Tutoriel - Guide utilisateur** pour [OAuth2 avec mot de passe (et hachage), Bearer avec jetons JWT](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Cette fois, en utilisant des scopes OAuth2 : + +{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *} + +Passons maintenant en revue ces changements Ă©tape par Ă©tape. + +## DĂ©clarer le schĂ©ma de sĂ©curitĂ© OAuth2 { #oauth2-security-scheme } + +Le premier changement est que nous dĂ©clarons maintenant le schĂ©ma de sĂ©curitĂ© OAuth2 avec deux scopes disponibles, `me` et `items`. + +Le paramĂštre `scopes` reçoit un `dict` avec chaque scope en clĂ© et la description en valeur : + +{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *} + +Comme nous dĂ©clarons maintenant ces scopes, ils apparaĂźtront dans la documentation de l’API lorsque vous vous authentifiez/autorisez. + +Et vous pourrez sĂ©lectionner Ă  quels scopes vous souhaitez accorder l’accĂšs : `me` et `items`. + +C’est le mĂȘme mĂ©canisme utilisĂ© lorsque vous donnez des permissions en vous connectant avec Facebook, Google, GitHub, etc. : + + + +## Jeton JWT avec scopes { #jwt-token-with-scopes } + +Modifiez maintenant le *chemin d’accĂšs* du jeton pour renvoyer les scopes demandĂ©s. + +Nous utilisons toujours le mĂȘme `OAuth2PasswordRequestForm`. Il inclut une propriĂ©tĂ© `scopes` avec une `list` de `str`, contenant chaque scope reçu dans la requĂȘte. + +Et nous renvoyons les scopes comme partie du jeton JWT. + +/// danger | Danger + +Pour simplifier, ici nous ajoutons directement au jeton les scopes reçus. + +Mais dans votre application, pour la sĂ©curitĂ©, vous devez vous assurer de n’ajouter que les scopes que l’utilisateur est rĂ©ellement autorisĂ© Ă  avoir, ou ceux que vous avez prĂ©dĂ©finis. + +/// + +{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *} + +## DĂ©clarer des scopes dans les chemins d’accĂšs et les dĂ©pendances { #declare-scopes-in-path-operations-and-dependencies } + +Nous dĂ©clarons maintenant que le *chemin d’accĂšs* `/users/me/items/` nĂ©cessite le scope `items`. + +Pour cela, nous importons et utilisons `Security` depuis `fastapi`. + +Vous pouvez utiliser `Security` pour dĂ©clarer des dĂ©pendances (comme `Depends`), mais `Security` reçoit aussi un paramĂštre `scopes` avec une liste de scopes (chaĂźnes). + +Dans ce cas, nous passons une fonction de dĂ©pendance `get_current_active_user` Ă  `Security` (de la mĂȘme maniĂšre que nous le ferions avec `Depends`). + +Mais nous passons aussi une `list` de scopes, ici avec un seul scope : `items` (il pourrait y en avoir plus). + +Et la fonction de dĂ©pendance `get_current_active_user` peut Ă©galement dĂ©clarer des sous-dĂ©pendances, non seulement avec `Depends` mais aussi avec `Security`. En dĂ©clarant sa propre fonction de sous-dĂ©pendance (`get_current_user`), et davantage d’exigences de scopes. + +Dans ce cas, elle nĂ©cessite le scope `me` (elle pourrait en exiger plusieurs). + +/// note | Remarque + +Vous n’avez pas nĂ©cessairement besoin d’ajouter des scopes diffĂ©rents Ă  diffĂ©rents endroits. + +Nous le faisons ici pour montrer comment **FastAPI** gĂšre des scopes dĂ©clarĂ©s Ă  diffĂ©rents niveaux. + +/// + +{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *} + +/// info | DĂ©tails techniques + +`Security` est en rĂ©alitĂ© une sous-classe de `Depends`, et elle n’a qu’un paramĂštre supplĂ©mentaire que nous verrons plus tard. + +Mais en utilisant `Security` au lieu de `Depends`, **FastAPI** saura qu’il peut dĂ©clarer des scopes de sĂ©curitĂ©, les utiliser en interne et documenter l’API avec OpenAPI. + +Cependant, lorsque vous importez `Query`, `Path`, `Depends`, `Security` et d’autres depuis `fastapi`, ce sont en fait des fonctions qui renvoient des classes spĂ©ciales. + +/// + +## Utiliser `SecurityScopes` { #use-securityscopes } + +Mettez maintenant Ă  jour la dĂ©pendance `get_current_user`. + +C’est celle utilisĂ©e par les dĂ©pendances ci-dessus. + +C’est ici que nous utilisons le mĂȘme schĂ©ma OAuth2 que nous avons créé auparavant, en le dĂ©clarant comme dĂ©pendance : `oauth2_scheme`. + +Comme cette fonction de dĂ©pendance n’a pas elle-mĂȘme d’exigences de scope, nous pouvons utiliser `Depends` avec `oauth2_scheme`, nous n’avons pas Ă  utiliser `Security` quand nous n’avons pas besoin de spĂ©cifier des scopes de sĂ©curitĂ©. + +Nous dĂ©clarons Ă©galement un paramĂštre spĂ©cial de type `SecurityScopes`, importĂ© de `fastapi.security`. + +Cette classe `SecurityScopes` est similaire Ă  `Request` (`Request` servait Ă  obtenir directement l’objet requĂȘte). + +{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *} + +## Utiliser les `scopes` { #use-the-scopes } + +Le paramĂštre `security_scopes` sera de type `SecurityScopes`. + +Il aura une propriĂ©tĂ© `scopes` avec une liste contenant tous les scopes requis par lui-mĂȘme et par toutes les dĂ©pendances qui l’utilisent comme sous-dĂ©pendance. Cela signifie, tous les « dĂ©pendants » ... cela peut paraĂźtre dĂ©routant, c’est expliquĂ© Ă  nouveau plus bas. + +L’objet `security_scopes` (de classe `SecurityScopes`) fournit aussi un attribut `scope_str` avec une chaĂźne unique, contenant ces scopes sĂ©parĂ©s par des espaces (nous allons l’utiliser). + +Nous crĂ©ons une `HTTPException` que nous pouvons rĂ©utiliser (`raise`) plus tard Ă  plusieurs endroits. + +Dans cette exception, nous incluons les scopes requis (le cas Ă©chĂ©ant) sous forme de chaĂźne sĂ©parĂ©e par des espaces (en utilisant `scope_str`). Nous plaçons cette chaĂźne contenant les scopes dans l’en-tĂȘte `WWW-Authenticate` (cela fait partie de la spĂ©cification). + +{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *} + +## VĂ©rifier le `username` et la structure des donnĂ©es { #verify-the-username-and-data-shape } + +Nous vĂ©rifions que nous obtenons un `username`, et extrayons les scopes. + +Nous validons ensuite ces donnĂ©es avec le modĂšle Pydantic (en capturant l’exception `ValidationError`), et si nous obtenons une erreur lors de la lecture du jeton JWT ou de la validation des donnĂ©es avec Pydantic, nous levons la `HTTPException` que nous avons créée auparavant. + +Pour cela, nous mettons Ă  jour le modĂšle Pydantic `TokenData` avec une nouvelle propriĂ©tĂ© `scopes`. + +En validant les donnĂ©es avec Pydantic, nous pouvons nous assurer que nous avons, par exemple, exactement une `list` de `str` pour les scopes et un `str` pour le `username`. + +Au lieu, par exemple, d’un `dict`, ou autre chose, ce qui pourrait casser l’application plus tard et constituer un risque de sĂ©curitĂ©. + +Nous vĂ©rifions Ă©galement que nous avons un utilisateur avec ce nom d’utilisateur, et sinon, nous levons la mĂȘme exception que prĂ©cĂ©demment. + +{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *} + +## VĂ©rifier les `scopes` { #verify-the-scopes } + +Nous vĂ©rifions maintenant que tous les scopes requis, par cette dĂ©pendance et tous les dĂ©pendants (y compris les *chemins d’accĂšs*), sont inclus dans les scopes fournis dans le jeton reçu, sinon nous levons une `HTTPException`. + +Pour cela, nous utilisons `security_scopes.scopes`, qui contient une `list` avec tous ces scopes en `str`. + +{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *} + +## Arbre de dĂ©pendances et scopes { #dependency-tree-and-scopes } + +Revoyons encore cet arbre de dĂ©pendances et les scopes. + +Comme la dĂ©pendance `get_current_active_user` a une sous-dĂ©pendance `get_current_user`, le scope « me » dĂ©clarĂ© dans `get_current_active_user` sera inclus dans la liste des scopes requis dans `security_scopes.scopes` passĂ© Ă  `get_current_user`. + +Le *chemin d’accĂšs* lui-mĂȘme dĂ©clare Ă©galement un scope, « items », il sera donc aussi prĂ©sent dans la liste `security_scopes.scopes` passĂ©e Ă  `get_current_user`. + +Voici Ă  quoi ressemble la hiĂ©rarchie des dĂ©pendances et des scopes : + +* Le *chemin d’accĂšs* `read_own_items` a : + * Des scopes requis `["items"]` avec la dĂ©pendance : + * `get_current_active_user` : + * La fonction de dĂ©pendance `get_current_active_user` a : + * Des scopes requis `["me"]` avec la dĂ©pendance : + * `get_current_user` : + * La fonction de dĂ©pendance `get_current_user` a : + * Aucun scope requis par elle-mĂȘme. + * Une dĂ©pendance utilisant `oauth2_scheme`. + * Un paramĂštre `security_scopes` de type `SecurityScopes` : + * Ce paramĂštre `security_scopes` a une propriĂ©tĂ© `scopes` avec une `list` contenant tous les scopes dĂ©clarĂ©s ci-dessus, donc : + * `security_scopes.scopes` contiendra `["me", "items"]` pour le *chemin d’accĂšs* `read_own_items`. + * `security_scopes.scopes` contiendra `["me"]` pour le *chemin d’accĂšs* `read_users_me`, car il est dĂ©clarĂ© dans la dĂ©pendance `get_current_active_user`. + * `security_scopes.scopes` contiendra `[]` (rien) pour le *chemin d’accĂšs* `read_system_status`, car il n’a dĂ©clarĂ© aucun `Security` avec des `scopes`, et sa dĂ©pendance, `get_current_user`, ne dĂ©clare pas non plus de `scopes`. + +/// tip | Astuce + +L’élĂ©ment important et « magique » ici est que `get_current_user` aura une liste diffĂ©rente de `scopes` Ă  vĂ©rifier pour chaque *chemin d’accĂšs*. + +Tout dĂ©pend des `scopes` dĂ©clarĂ©s dans chaque *chemin d’accĂšs* et chaque dĂ©pendance dans l’arbre de dĂ©pendances pour ce *chemin d’accĂšs* spĂ©cifique. + +/// + +## DĂ©tails supplĂ©mentaires sur `SecurityScopes` { #more-details-about-securityscopes } + +Vous pouvez utiliser `SecurityScopes` Ă  n’importe quel endroit, et Ă  de multiples endroits, il n’a pas besoin d’ĂȘtre dans la dĂ©pendance « root ». + +Il aura toujours les scopes de sĂ©curitĂ© dĂ©clarĂ©s dans les dĂ©pendances `Security` actuelles et tous les dĂ©pendants pour **ce** *chemin d’accĂšs* spĂ©cifique et **cet** arbre de dĂ©pendances spĂ©cifique. + +Comme `SecurityScopes` contient tous les scopes dĂ©clarĂ©s par les dĂ©pendants, vous pouvez l’utiliser pour vĂ©rifier qu’un jeton possĂšde les scopes requis dans une fonction de dĂ©pendance centrale, puis dĂ©clarer des exigences de scopes diffĂ©rentes dans diffĂ©rents *chemins d’accĂšs*. + +Elles seront vĂ©rifiĂ©es indĂ©pendamment pour chaque *chemin d’accĂšs*. + +## Tester { #check-it } + +Si vous ouvrez la documentation de l’API, vous pouvez vous authentifier et spĂ©cifier quels scopes vous voulez autoriser. + + + +Si vous ne sĂ©lectionnez aucun scope, vous serez « authenticated », mais lorsque vous essayerez d’accĂ©der Ă  `/users/me/` ou `/users/me/items/`, vous obtiendrez une erreur indiquant que vous n’avez pas suffisamment de permissions. Vous pourrez toujours accĂ©der Ă  `/status/`. + +Et si vous sĂ©lectionnez le scope `me` mais pas le scope `items`, vous pourrez accĂ©der Ă  `/users/me/` mais pas Ă  `/users/me/items/`. + +C’est ce qui arriverait Ă  une application tierce qui tenterait d’accĂ©der Ă  l’un de ces *chemins d’accĂšs* avec un jeton fourni par un utilisateur, selon le nombre de permissions que l’utilisateur a accordĂ©es Ă  l’application. + +## À propos des intĂ©grations tierces { #about-third-party-integrations } + +Dans cet exemple, nous utilisons le flux OAuth2 « password ». + +C’est appropriĂ© lorsque nous nous connectons Ă  notre propre application, probablement avec notre propre frontend. + +Parce que nous pouvons lui faire confiance pour recevoir le `username` et le `password`, puisque nous le contrĂŽlons. + +Mais si vous construisez une application OAuth2 Ă  laquelle d’autres se connecteraient (c.-Ă -d., si vous construisez un fournisseur d’authentification Ă©quivalent Ă  Facebook, Google, GitHub, etc.), vous devez utiliser l’un des autres flux. + +Le plus courant est le flux implicite. + +Le plus sĂ»r est le flux « code », mais il est plus complexe Ă  implĂ©menter car il nĂ©cessite plus d’étapes. Comme il est plus complexe, de nombreux fournisseurs finissent par recommander le flux implicite. + +/// note | Remarque + +Il est courant que chaque fournisseur d’authentification nomme ses flux diffĂ©remment, pour en faire une partie de sa marque. + +Mais au final, ils implĂ©mentent le mĂȘme standard OAuth2. + +/// + +**FastAPI** inclut des utilitaires pour tous ces flux d’authentification OAuth2 dans `fastapi.security.oauth2`. + +## `Security` dans les dĂ©pendances du dĂ©corateur `dependencies` { #security-in-decorator-dependencies } + +De la mĂȘme maniĂšre que vous pouvez dĂ©finir une `list` de `Depends` dans le paramĂštre `dependencies` du dĂ©corateur (comme expliquĂ© dans [DĂ©pendances dans les dĂ©corateurs de chemins d’accĂšs](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), vous pouvez aussi utiliser `Security` avec des `scopes` Ă  cet endroit. diff --git a/docs/fr/docs/advanced/settings.md b/docs/fr/docs/advanced/settings.md new file mode 100644 index 000000000..ed724bf4f --- /dev/null +++ b/docs/fr/docs/advanced/settings.md @@ -0,0 +1,302 @@ +# ParamĂštres et variables d'environnement { #settings-and-environment-variables } + +Dans de nombreux cas, votre application peut avoir besoin de paramĂštres ou de configurations externes, par exemple des clĂ©s secrĂštes, des identifiants de base de donnĂ©es, des identifiants pour des services d'e-mail, etc. + +La plupart de ces paramĂštres sont variables (peuvent changer), comme les URL de base de donnĂ©es. Et beaucoup peuvent ĂȘtre sensibles, comme les secrets. + +C'est pourquoi il est courant de les fournir via des variables d'environnement lues par l'application. + +/// tip | Astuce + +Pour comprendre les variables d'environnement, vous pouvez lire [Variables d'environnement](../environment-variables.md){.internal-link target=_blank}. + +/// + +## Types et validation { #types-and-validation } + +Ces variables d'environnement ne gĂšrent que des chaĂźnes de texte, car elles sont externes Ă  Python et doivent ĂȘtre compatibles avec d'autres programmes et le reste du systĂšme (et mĂȘme avec diffĂ©rents systĂšmes d'exploitation, comme Linux, Windows, macOS). + +Cela signifie que toute valeur lue en Python depuis une variable d'environnement sera une `str`, et toute conversion vers un autre type ou toute validation doit ĂȘtre effectuĂ©e dans le code. + +## Pydantic `Settings` { #pydantic-settings } + +Heureusement, Pydantic fournit un excellent utilitaire pour gĂ©rer ces paramĂštres provenant des variables d'environnement avec Pydantic : gestion des paramĂštres. + +### Installer `pydantic-settings` { #install-pydantic-settings } + +D'abord, vous devez crĂ©er votre [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l'activer, puis installer le paquet `pydantic-settings` : + +
+ +```console +$ pip install pydantic-settings +---> 100% +``` + +
+ +Il est également inclus lorsque vous installez les extras `all` avec : + +
+ +```console +$ pip install "fastapi[all]" +---> 100% +``` + +
+ +### CrĂ©er l'objet `Settings` { #create-the-settings-object } + +Importez `BaseSettings` depuis Pydantic et crĂ©ez une sous-classe, comme pour un modĂšle Pydantic. + +De la mĂȘme maniĂšre qu'avec les modĂšles Pydantic, vous dĂ©clarez des attributs de classe avec des annotations de type, et Ă©ventuellement des valeurs par dĂ©faut. + +Vous pouvez utiliser toutes les mĂȘmes fonctionnalitĂ©s et outils de validation que pour les modĂšles Pydantic, comme diffĂ©rents types de donnĂ©es et des validations supplĂ©mentaires avec `Field()`. + +{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *} + +/// tip | Astuce + +Si vous voulez quelque chose Ă  copier-coller rapidement, n'utilisez pas cet exemple, utilisez le dernier ci-dessous. + +/// + +Ensuite, lorsque vous crĂ©ez une instance de cette classe `Settings` (dans ce cas, l'objet `settings`), Pydantic lira les variables d'environnement de maniĂšre insensible Ă  la casse, donc une variable en majuscules `APP_NAME` sera tout de mĂȘme lue pour l'attribut `app_name`. + +Il convertira ensuite et validera les donnĂ©es. Ainsi, lorsque vous utilisez cet objet `settings`, vous aurez des donnĂ©es des types que vous avez dĂ©clarĂ©s (par exemple, `items_per_user` sera un `int`). + +### Utiliser `settings` { #use-the-settings } + +Vous pouvez ensuite utiliser le nouvel objet `settings` dans votre application : + +{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *} + +### ExĂ©cuter le serveur { #run-the-server } + +Ensuite, vous exĂ©cutez le serveur en passant les configurations comme variables d'environnement ; par exemple, vous pouvez dĂ©finir un `ADMIN_EMAIL` et `APP_NAME` avec : + +
+ +```console +$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +/// tip | Astuce + +Pour dĂ©finir plusieurs variables d'environnement pour une seule commande, sĂ©parez-les simplement par un espace et placez-les toutes avant la commande. + +/// + +Ainsi, le paramĂštre `admin_email` sera dĂ©fini sur « deadpool@example.com ». + +Le `app_name` sera « ChimichangApp ». + +Et `items_per_user` conservera sa valeur par dĂ©faut de `50`. + +## ParamĂštres dans un autre module { #settings-in-another-module } + +Vous pouvez placer ces paramĂštres dans un autre module comme vous l'avez vu dans [Applications plus grandes - Plusieurs fichiers](../tutorial/bigger-applications.md){.internal-link target=_blank}. + +Par exemple, vous pourriez avoir un fichier `config.py` avec : + +{* ../../docs_src/settings/app01_py310/config.py *} + +Puis l'utiliser dans un fichier `main.py` : + +{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *} + +/// tip | Astuce + +Vous aurez Ă©galement besoin d'un fichier `__init__.py` comme vous l'avez vu dans [Applications plus grandes - Plusieurs fichiers](../tutorial/bigger-applications.md){.internal-link target=_blank}. + +/// + +## ParamĂštres dans une dĂ©pendance { #settings-in-a-dependency } + +Dans certains cas, il peut ĂȘtre utile de fournir les paramĂštres via une dĂ©pendance, au lieu d'avoir un objet global `settings` utilisĂ© partout. + +Cela peut ĂȘtre particuliĂšrement utile pendant les tests, car il est trĂšs facile de surcharger une dĂ©pendance avec vos propres paramĂštres personnalisĂ©s. + +### Le fichier de configuration { #the-config-file } + +En repartant de l'exemple prĂ©cĂ©dent, votre fichier `config.py` pourrait ressembler Ă  : + +{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *} + +Notez que maintenant, nous ne crĂ©ons pas d'instance par dĂ©faut `settings = Settings()`. + +### Le fichier principal de l'application { #the-main-app-file } + +Nous crĂ©ons maintenant une dĂ©pendance qui renvoie un nouveau `config.Settings()`. + +{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *} + +/// tip | Astuce + +Nous parlerons de `@lru_cache` dans un instant. + +Pour l'instant, vous pouvez supposer que `get_settings()` est une fonction normale. + +/// + +Nous pouvons ensuite l'exiger depuis la fonction de chemin d'accĂšs comme dĂ©pendance et l'utiliser oĂč nous en avons besoin. + +{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *} + +### ParamĂštres et tests { #settings-and-testing } + +Il devient alors trĂšs simple de fournir un autre objet de paramĂštres pendant les tests en crĂ©ant une surcharge de dĂ©pendance pour `get_settings` : + +{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *} + +Dans la surcharge de dĂ©pendance, nous dĂ©finissons une nouvelle valeur pour `admin_email` lors de la crĂ©ation du nouvel objet `Settings`, puis nous renvoyons ce nouvel objet. + +Nous pouvons ensuite tester qu'il est bien utilisĂ©. + +## Lire un fichier `.env` { #reading-a-env-file } + +Si vous avez de nombreux paramĂštres susceptibles de beaucoup changer, peut-ĂȘtre selon les environnements, il peut ĂȘtre utile de les placer dans un fichier, puis de les lire comme s'il s'agissait de variables d'environnement. + +Cette pratique est suffisamment courante pour avoir un nom ; ces variables d'environnement sont frĂ©quemment placĂ©es dans un fichier `.env`, et le fichier est appelĂ© un « dotenv ». + +/// tip | Astuce + +Un fichier commençant par un point (`.`) est un fichier cachĂ© dans les systĂšmes de type Unix, comme Linux et macOS. + +Mais un fichier dotenv n'a pas forcĂ©ment exactement ce nom de fichier. + +/// + +Pydantic prend en charge la lecture depuis ce type de fichiers en utilisant une bibliothĂšque externe. Vous pouvez en lire davantage ici : Pydantic Settings : prise en charge de Dotenv (.env). + +/// tip | Astuce + +Pour que cela fonctionne, vous devez exĂ©cuter `pip install python-dotenv`. + +/// + +### Le fichier `.env` { #the-env-file } + +Vous pouvez avoir un fichier `.env` avec : + +```bash +ADMIN_EMAIL="deadpool@example.com" +APP_NAME="ChimichangApp" +``` + +### Lire les paramĂštres depuis `.env` { #read-settings-from-env } + +Puis mettre Ă  jour votre `config.py` avec : + +{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *} + +/// tip | Astuce + +L'attribut `model_config` est utilisĂ© uniquement pour la configuration Pydantic. Vous pouvez en lire davantage ici : Pydantic : Concepts : Configuration. + +/// + +Ici, nous dĂ©finissons la configuration `env_file` Ă  l'intĂ©rieur de votre classe Pydantic `Settings` et lui attribuons le nom du fichier dotenv que nous voulons utiliser. + +### CrĂ©er `Settings` une seule fois avec `lru_cache` { #creating-the-settings-only-once-with-lru-cache } + +Lire un fichier depuis le disque est normalement une opĂ©ration coĂ»teuse (lente), vous voudrez donc probablement le faire une seule fois puis rĂ©utiliser le mĂȘme objet de paramĂštres, au lieu de le lire Ă  chaque requĂȘte. + +Mais chaque fois que nous faisons : + +```Python +Settings() +``` + +un nouvel objet `Settings` serait créé, et Ă  sa crĂ©ation il lirait Ă  nouveau le fichier `.env`. + +Si la fonction de dĂ©pendance Ă©tait simplement : + +```Python +def get_settings(): + return Settings() +``` + +nous crĂ©erions cet objet pour chaque requĂȘte, et nous lirions le fichier `.env` pour chaque requĂȘte. ⚠ + +Mais comme nous utilisons le dĂ©corateur `@lru_cache` au-dessus, l'objet `Settings` sera créé une seule fois, la premiĂšre fois qu'il est appelĂ©. ✔ + +{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *} + +Ensuite, pour tout appel ultĂ©rieur de `get_settings()` dans les dĂ©pendances pour les requĂȘtes suivantes, au lieu d'exĂ©cuter le code interne de `get_settings()` et de crĂ©er un nouvel objet `Settings`, il renverra le mĂȘme objet que celui retournĂ© au premier appel, encore et encore. + +#### DĂ©tails techniques de `lru_cache` { #lru-cache-technical-details } + +`@lru_cache` modifie la fonction qu'il dĂ©core pour renvoyer la mĂȘme valeur que celle qui a Ă©tĂ© retournĂ©e la premiĂšre fois, au lieu de la recalculer en exĂ©cutant le code de la fonction Ă  chaque fois. + +Ainsi, la fonction situĂ©e en dessous sera exĂ©cutĂ©e une fois pour chaque combinaison d'arguments. Ensuite, les valeurs renvoyĂ©es par chacune de ces combinaisons d'arguments seront rĂ©utilisĂ©es Ă  chaque fois que la fonction sera appelĂ©e avec exactement la mĂȘme combinaison d'arguments. + +Par exemple, si vous avez une fonction : + +```Python +@lru_cache +def say_hi(name: str, salutation: str = "Ms."): + return f"Hello {salutation} {name}" +``` + +votre programme pourrait s'exĂ©cuter comme ceci : + +```mermaid +sequenceDiagram + +participant code as Code +participant function as say_hi() +participant execute as Execute function + + rect rgba(0, 255, 0, .1) + code ->> function: say_hi(name="Camila") + function ->> execute: execute function code + execute ->> code: return the result + end + + rect rgba(0, 255, 255, .1) + code ->> function: say_hi(name="Camila") + function ->> code: return stored result + end + + rect rgba(0, 255, 0, .1) + code ->> function: say_hi(name="Rick") + function ->> execute: execute function code + execute ->> code: return the result + end + + rect rgba(0, 255, 0, .1) + code ->> function: say_hi(name="Rick", salutation="Mr.") + function ->> execute: execute function code + execute ->> code: return the result + end + + rect rgba(0, 255, 255, .1) + code ->> function: say_hi(name="Rick") + function ->> code: return stored result + end + + rect rgba(0, 255, 255, .1) + code ->> function: say_hi(name="Camila") + function ->> code: return stored result + end +``` + +Dans le cas de notre dĂ©pendance `get_settings()`, la fonction ne prend mĂȘme aucun argument, elle renvoie donc toujours la mĂȘme valeur. + +De cette façon, elle se comporte presque comme s'il s'agissait simplement d'une variable globale. Mais comme elle utilise une fonction de dĂ©pendance, nous pouvons alors la surcharger facilement pour les tests. + +`@lru_cache` fait partie de `functools` qui fait partie de la bibliothĂšque standard de Python, vous pouvez en lire davantage dans la documentation Python pour `@lru_cache`. + +## RĂ©capitulatif { #recap } + +Vous pouvez utiliser Pydantic Settings pour gĂ©rer les paramĂštres ou configurations de votre application, avec toute la puissance des modĂšles Pydantic. + +* En utilisant une dĂ©pendance, vous pouvez simplifier les tests. +* Vous pouvez utiliser des fichiers `.env`. +* Utiliser `@lru_cache` vous permet d'Ă©viter de relire le fichier dotenv Ă  chaque requĂȘte, tout en vous permettant de le surcharger pendant les tests. diff --git a/docs/fr/docs/advanced/sub-applications.md b/docs/fr/docs/advanced/sub-applications.md new file mode 100644 index 000000000..777056040 --- /dev/null +++ b/docs/fr/docs/advanced/sub-applications.md @@ -0,0 +1,67 @@ +# Sous-applications - Montage { #sub-applications-mounts } + +Si vous avez besoin de deux applications FastAPI indĂ©pendantes, avec leur propre OpenAPI et leurs propres interfaces de la documentation, vous pouvez avoir une application principale et « monter » une (ou plusieurs) sous‑application(s). + +## Monter une application **FastAPI** { #mounting-a-fastapi-application } + +« Monter » signifie ajouter une application entiĂšrement « indĂ©pendante » Ă  un chemin spĂ©cifique, qui se chargera ensuite de tout gĂ©rer sous ce chemin, avec les _chemins d'accĂšs_ dĂ©clarĂ©s dans cette sous‑application. + +### Application de premier niveau { #top-level-application } + +CrĂ©ez d'abord l'application **FastAPI** principale (de premier niveau) et ses *chemins d'accĂšs* : + +{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *} + +### Sous-application { #sub-application } + +Ensuite, crĂ©ez votre sous‑application et ses *chemins d'accĂšs*. + +Cette sous‑application est simplement une autre application FastAPI standard, mais c'est celle qui sera « montĂ©e » : + +{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *} + +### Monter la sous-application { #mount-the-sub-application } + +Dans votre application de premier niveau, `app`, montez la sous‑application, `subapi`. + +Dans ce cas, elle sera montĂ©e au chemin `/subapi` : + +{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *} + +### VĂ©rifier la documentation API automatique { #check-the-automatic-api-docs } + +ExĂ©cutez maintenant la commande `fastapi` avec votre fichier : + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Puis ouvrez la documentation Ă  http://127.0.0.1:8000/docs. + +Vous verrez la documentation API automatique pour l'application principale, n'incluant que ses propres _chemins d'accĂšs_ : + + + +Ensuite, ouvrez la documentation de la sous‑application Ă  http://127.0.0.1:8000/subapi/docs. + +Vous verrez la documentation API automatique pour la sous‑application, n'incluant que ses propres _chemins d'accĂšs_, tous sous le prĂ©fixe de sous‑chemin correct `/subapi` : + + + +Si vous essayez d'interagir avec l'une ou l'autre des deux interfaces, elles fonctionneront correctement, car le navigateur pourra communiquer avec chaque application ou sous‑application spĂ©cifique. + +### DĂ©tails techniques : `root_path` { #technical-details-root-path } + +Lorsque vous montez une sous‑application comme ci‑dessus, FastAPI se charge de communiquer le chemin de montage Ă  la sous‑application au moyen d'un mĂ©canisme de la spĂ©cification ASGI appelĂ© `root_path`. + +De cette maniĂšre, la sous‑application saura utiliser ce prĂ©fixe de chemin pour l'interface de documentation. + +La sous‑application peut Ă©galement avoir ses propres sous‑applications montĂ©es et tout fonctionnera correctement, car FastAPI gĂšre automatiquement tous ces `root_path`. + +Vous en apprendrez davantage sur `root_path` et sur la façon de l'utiliser explicitement dans la section [DerriĂšre un proxy](behind-a-proxy.md){.internal-link target=_blank}. diff --git a/docs/fr/docs/advanced/templates.md b/docs/fr/docs/advanced/templates.md new file mode 100644 index 000000000..7c886ab69 --- /dev/null +++ b/docs/fr/docs/advanced/templates.md @@ -0,0 +1,126 @@ +# Templates { #templates } + +Vous pouvez utiliser n'importe quel moteur de templates avec **FastAPI**. + +Un choix courant est Jinja2, le mĂȘme que celui utilisĂ© par Flask et d'autres outils. + +Il existe des utilitaires pour le configurer facilement que vous pouvez utiliser directement dans votre application **FastAPI** (fournis par Starlette). + +## Installer les dĂ©pendances { #install-dependencies } + +Vous devez crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l'activer, puis installer `jinja2` : + +
+ +```console +$ pip install jinja2 + +---> 100% +``` + +
+ +## Utiliser `Jinja2Templates` { #using-jinja2templates } + +- Importez `Jinja2Templates`. +- CrĂ©ez un objet `templates` que vous pourrez rĂ©utiliser par la suite. +- DĂ©clarez un paramĂštre `Request` dans le *chemin d'accĂšs* qui renverra un template. +- Utilisez l'objet `templates` que vous avez créé pour rendre et retourner une `TemplateResponse`, en transmettant le nom du template, l'objet de requĂȘte et un dictionnaire de « context » avec des paires clĂ©-valeur Ă  utiliser dans le template Jinja2. + +{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *} + +/// note | Remarque + +Avant FastAPI 0.108.0 et Starlette 0.29.0, `name` Ă©tait le premier paramĂštre. + +De plus, auparavant, dans les versions prĂ©cĂ©dentes, l'objet `request` faisait partie des paires clĂ©-valeur du contexte pour Jinja2. + +/// + +/// tip | Astuce + +En dĂ©clarant `response_class=HTMLResponse`, l'interface de la documentation saura que la rĂ©ponse sera en HTML. + +/// + +/// note | DĂ©tails techniques + +Vous pouvez aussi utiliser `from starlette.templating import Jinja2Templates`. + +**FastAPI** expose le mĂȘme `starlette.templating` sous `fastapi.templating` par simple commoditĂ© pour vous, dĂ©veloppeur. Mais la plupart des rĂ©ponses disponibles proviennent directement de Starlette. C'est Ă©galement le cas pour `Request` et `StaticFiles`. + +/// + +## Écrire des templates { #writing-templates } + +Vous pouvez ensuite Ă©crire un template dans `templates/item.html`, par exemple : + +```jinja hl_lines="7" +{!../../docs_src/templates/templates/item.html!} +``` + +### Valeurs de contexte du template { #template-context-values } + +Dans le HTML qui contient : + +{% raw %} + +```jinja +Item ID: {{ id }} +``` + +{% endraw %} + +... il affichera l’`id` rĂ©cupĂ©rĂ© Ă  partir du `dict` « context » que vous avez passĂ© : + +```Python +{"id": id} +``` + +Par exemple, avec un ID de `42`, cela rendrait : + +```html +Item ID: 42 +``` + +### Arguments de `url_for` dans le template { #template-url-for-arguments } + +Vous pouvez aussi utiliser `url_for()` dans le template ; elle prend en paramĂštres les mĂȘmes arguments que ceux utilisĂ©s par votre *fonction de chemin d'accĂšs*. + +Ainsi, la section suivante : + +{% raw %} + +```jinja + +``` + +{% endraw %} + +... gĂ©nĂ©rera un lien vers la mĂȘme URL que celle gĂ©rĂ©e par la *fonction de chemin d'accĂšs* `read_item(id=id)`. + +Par exemple, avec un ID de `42`, cela rendrait : + +```html + +``` + +## Templates et fichiers statiques { #templates-and-static-files } + +Vous pouvez aussi utiliser `url_for()` dans le template, par exemple avec les `StaticFiles` que vous avez montĂ©s avec `name="static"`. + +```jinja hl_lines="4" +{!../../docs_src/templates/templates/item.html!} +``` + +Dans cet exemple, cela crĂ©era un lien vers un fichier CSS `static/styles.css` avec : + +```CSS hl_lines="4" +{!../../docs_src/templates/static/styles.css!} +``` + +Et comme vous utilisez `StaticFiles`, ce fichier CSS est servi automatiquement par votre application **FastAPI** Ă  l’URL `/static/styles.css`. + +## En savoir plus { #more-details } + +Pour plus de dĂ©tails, y compris sur la façon de tester des templates, consultez la documentation de Starlette sur les templates. diff --git a/docs/fr/docs/advanced/testing-dependencies.md b/docs/fr/docs/advanced/testing-dependencies.md new file mode 100644 index 000000000..d6fc576bf --- /dev/null +++ b/docs/fr/docs/advanced/testing-dependencies.md @@ -0,0 +1,52 @@ +# Tester des dĂ©pendances avec des surcharges { #testing-dependencies-with-overrides } + +## Surcharger des dĂ©pendances pendant les tests { #overriding-dependencies-during-testing } + +Il existe des cas oĂč vous souhaiterez surcharger une dĂ©pendance pendant les tests. + +Vous ne voulez pas exĂ©cuter la dĂ©pendance originale (ni ses Ă©ventuelles sous‑dĂ©pendances). + +À la place, vous souhaitez fournir une dĂ©pendance diffĂ©rente, utilisĂ©e uniquement pendant les tests (Ă©ventuellement seulement pour certains tests), et qui fournira une valeur utilisable partout oĂč l’on utilisait celle de la dĂ©pendance originale. + +### Cas d’usage : service externe { #use-cases-external-service } + +Par exemple, vous avez un fournisseur d’authentification externe Ă  appeler. + +Vous lui envoyez un token et il renvoie un utilisateur authentifiĂ©. + +Ce fournisseur peut vous facturer Ă  la requĂȘte, et l’appeler peut prendre plus de temps que si vous aviez un utilisateur factice fixe pour les tests. + +Vous voudrez probablement tester le fournisseur externe une fois, mais pas nĂ©cessairement l’appeler pour chaque test exĂ©cutĂ©. + +Dans ce cas, vous pouvez surcharger la dĂ©pendance qui appelle ce fournisseur et utiliser une dĂ©pendance personnalisĂ©e qui renvoie un utilisateur factice, uniquement pour vos tests. + +### Utiliser l’attribut `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute } + +Pour ces cas, votre **FastAPI** application possĂšde un attribut `app.dependency_overrides` ; c’est un simple `dict`. + +Pour surcharger une dĂ©pendance lors des tests, vous mettez comme clĂ© la dĂ©pendance originale (une fonction) et comme valeur votre surcharge de dĂ©pendance (une autre fonction). + +Ensuite, **FastAPI** appellera cette surcharge au lieu de la dĂ©pendance originale. + +{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *} + +/// tip | Astuce + +Vous pouvez dĂ©finir une surcharge de dĂ©pendance pour une dĂ©pendance utilisĂ©e n’importe oĂč dans votre application **FastAPI**. + +La dĂ©pendance originale peut ĂȘtre utilisĂ©e dans une fonction de chemin d'accĂšs, un dĂ©corateur de chemin d'accĂšs (quand vous n’utilisez pas la valeur de retour), un appel Ă  `.include_router()`, etc. + +FastAPI pourra toujours la surcharger. + +/// + +Vous pouvez ensuite rĂ©initialiser vos surcharges (les supprimer) en affectant Ă  `app.dependency_overrides` un `dict` vide : + +```Python +app.dependency_overrides = {} +``` +/// tip | Astuce + +Si vous souhaitez surcharger une dĂ©pendance uniquement pendant certains tests, vous pouvez dĂ©finir la surcharge au dĂ©but du test (dans la fonction de test) et la rĂ©initialiser Ă  la fin (Ă  la fin de la fonction de test). + +/// diff --git a/docs/fr/docs/advanced/testing-events.md b/docs/fr/docs/advanced/testing-events.md new file mode 100644 index 000000000..c4f9141b3 --- /dev/null +++ b/docs/fr/docs/advanced/testing-events.md @@ -0,0 +1,11 @@ +# Tester les Ă©vĂ©nements : lifespan et startup - shutdown { #testing-events-lifespan-and-startup-shutdown } + +Lorsque vous avez besoin d'exĂ©cuter `lifespan` dans vos tests, vous pouvez utiliser `TestClient` avec une instruction `with` : + +{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *} + +Vous pouvez lire plus de dĂ©tails dans [« ExĂ©cuter lifespan dans les tests sur le site de documentation officiel de Starlette. »](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) + +Pour les Ă©vĂ©nements dĂ©prĂ©ciĂ©s `startup` et `shutdown`, vous pouvez utiliser le `TestClient` comme suit : + +{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *} diff --git a/docs/fr/docs/advanced/testing-websockets.md b/docs/fr/docs/advanced/testing-websockets.md new file mode 100644 index 000000000..e9f97ab5f --- /dev/null +++ b/docs/fr/docs/advanced/testing-websockets.md @@ -0,0 +1,13 @@ +# Tester les WebSockets { #testing-websockets } + +Vous pouvez utiliser le mĂȘme `TestClient` pour tester les WebSockets. + +Pour cela, vous utilisez `TestClient` dans une instruction `with`, en vous connectant au WebSocket : + +{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *} + +/// note | Remarque + +Pour plus de dĂ©tails, consultez la documentation de Starlette sur le test des WebSockets. + +/// diff --git a/docs/fr/docs/advanced/using-request-directly.md b/docs/fr/docs/advanced/using-request-directly.md new file mode 100644 index 000000000..4df3f90e8 --- /dev/null +++ b/docs/fr/docs/advanced/using-request-directly.md @@ -0,0 +1,56 @@ +# Utiliser Request directement { #using-the-request-directly } + +Jusqu'Ă  prĂ©sent, vous avez dĂ©clarĂ© les parties de la requĂȘte dont vous avez besoin, avec leurs types. + +En rĂ©cupĂ©rant des donnĂ©es depuis : + +* Le chemin, sous forme de paramĂštres. +* En-tĂȘtes. +* Cookies. +* etc. + +Et ce faisant, **FastAPI** valide ces donnĂ©es, les convertit et gĂ©nĂšre automatiquement la documentation de votre API. + +Mais il existe des situations oĂč vous pouvez avoir besoin d'accĂ©der directement Ă  l'objet `Request`. + +## DĂ©tails sur l'objet `Request` { #details-about-the-request-object } + +Comme **FastAPI** est en fait **Starlette** en dessous, avec une couche de plusieurs outils au-dessus, vous pouvez utiliser directement l'objet `Request` de Starlette lorsque vous en avez besoin. + +Cela signifie aussi que si vous rĂ©cupĂ©rez des donnĂ©es directement Ă  partir de l'objet `Request` (par exemple, lire le corps), elles ne seront pas validĂ©es, converties ni documentĂ©es (avec OpenAPI, pour l'interface utilisateur automatique de l'API) par FastAPI. + +En revanche, tout autre paramĂštre dĂ©clarĂ© normalement (par exemple, le corps avec un modĂšle Pydantic) sera toujours validĂ©, converti, annotĂ©, etc. + +Mais il existe des cas spĂ©cifiques oĂč il est utile d'obtenir l'objet `Request`. + +## Utiliser l'objet `Request` directement { #use-the-request-object-directly } + +Imaginons que vous souhaitiez obtenir l'adresse IP/l'hĂŽte du client dans votre fonction de chemin d'accĂšs. + +Pour cela, vous devez accĂ©der directement Ă  la requĂȘte. + +{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *} + +En dĂ©clarant un paramĂštre de fonction de chemin d'accĂšs de type `Request`, **FastAPI** saura passer la `Request` dans ce paramĂštre. + +/// tip | Astuce + +Notez que, dans ce cas, nous dĂ©clarons un paramĂštre de chemin en plus du paramĂštre de requĂȘte. + +Ainsi, le paramĂštre de chemin sera extrait, validĂ©, converti vers le type spĂ©cifiĂ© et annotĂ© avec OpenAPI. + +De la mĂȘme façon, vous pouvez dĂ©clarer tout autre paramĂštre normalement, et en plus, obtenir aussi la `Request`. + +/// + +## Documentation de `Request` { #request-documentation } + +Vous pouvez lire plus de dĂ©tails sur l'objet `Request` sur le site de documentation officiel de Starlette. + +/// note | DĂ©tails techniques + +Vous pouvez Ă©galement utiliser `from starlette.requests import Request`. + +**FastAPI** le fournit directement pour votre commoditĂ©, en tant que dĂ©veloppeur. Mais il provient directement de Starlette. + +/// diff --git a/docs/fr/docs/advanced/websockets.md b/docs/fr/docs/advanced/websockets.md new file mode 100644 index 000000000..6f5c3e703 --- /dev/null +++ b/docs/fr/docs/advanced/websockets.md @@ -0,0 +1,186 @@ +# WebSockets { #websockets } + +Vous pouvez utiliser API WebSockets avec **FastAPI**. + +## Installer `websockets` { #install-websockets } + +Vous devez crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l'activer, et installer `websockets` (une bibliothĂšque Python qui facilite l'utilisation du protocole « WebSocket ») : + +
+ +```console +$ pip install websockets + +---> 100% +``` + +
+ +## Client WebSocket { #websockets-client } + +### En production { #in-production } + +Dans votre systĂšme de production, vous avez probablement un frontend créé avec un framework moderne comme React, Vue.js ou Angular. + +Et pour communiquer en utilisant WebSockets avec votre backend, vous utiliseriez probablement les outils fournis par votre frontend. + +Ou vous pouvez avoir une application mobile native qui communique directement avec votre backend WebSocket, en code natif. + +Ou vous pouvez avoir toute autre façon de communiquer avec l'endpoint WebSocket. + +--- + +Mais pour cet exemple, nous utiliserons un document HTML trĂšs simple avec un peu de JavaScript, le tout dans une longue chaĂźne. + +Cela, bien entendu, n'est pas optimal et vous ne l'utiliseriez pas en production. + +En production, vous auriez l'une des options ci-dessus. + +Mais c'est la façon la plus simple de se concentrer sur la partie serveur des WebSockets et d'avoir un exemple fonctionnel : + +{* ../../docs_src/websockets/tutorial001_py310.py hl[2,6:38,41:43] *} + +## CrĂ©er un `websocket` { #create-a-websocket } + +Dans votre application **FastAPI**, crĂ©ez un `websocket` : + +{* ../../docs_src/websockets/tutorial001_py310.py hl[1,46:47] *} + +/// note | DĂ©tails techniques + +Vous pourriez aussi utiliser `from starlette.websockets import WebSocket`. + +**FastAPI** fournit le mĂȘme `WebSocket` directement, simplement pour vous faciliter la vie en tant que dĂ©veloppeur. Mais il provient directement de Starlette. + +/// + +## Attendre des messages et envoyer des messages { #await-for-messages-and-send-messages } + +Dans votre route WebSocket, vous pouvez `await` des messages et envoyer des messages. + +{* ../../docs_src/websockets/tutorial001_py310.py hl[48:52] *} + +Vous pouvez recevoir et envoyer des donnĂ©es binaires, texte et JSON. + +## Essayer { #try-it } + +Si votre fichier s'appelle `main.py`, exĂ©cutez votre application avec : + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Ouvrez votre navigateur Ă  l'adresse http://127.0.0.1:8000. + +Vous verrez une page simple comme : + + + +Vous pouvez saisir des messages dans le champ de saisie et les envoyer : + + + +Et votre application **FastAPI** avec WebSockets vous rĂ©pondra : + + + +Vous pouvez envoyer (et recevoir) de nombreux messages : + + + +Et tous utiliseront la mĂȘme connexion WebSocket. + +## Utiliser `Depends` et autres { #using-depends-and-others } + +Dans les endpoints WebSocket, vous pouvez importer depuis `fastapi` et utiliser : + +* `Depends` +* `Security` +* `Cookie` +* `Header` +* `Path` +* `Query` + +Ils fonctionnent de la mĂȘme maniĂšre que pour les autres endpoints/*chemins d'accĂšs* FastAPI : + +{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *} + +/// info + +Comme il s'agit d'un WebSocket, il n'est pas vraiment logique de lever une `HTTPException`, nous levons plutĂŽt une `WebSocketException`. + +Vous pouvez utiliser un code de fermeture parmi les codes valides dĂ©finis dans la spĂ©cification. + +/// + +### Essayez les WebSockets avec des dĂ©pendances { #try-the-websockets-with-dependencies } + +Si votre fichier s'appelle `main.py`, exĂ©cutez votre application avec : + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Ouvrez votre navigateur Ă  l'adresse http://127.0.0.1:8000. + +LĂ , vous pouvez dĂ©finir : + +* « Item ID », utilisĂ© dans le chemin. +* « Token » utilisĂ© comme paramĂštre de requĂȘte. + +/// tip | Astuce + +Notez que le `token` de requĂȘte sera gĂ©rĂ© par une dĂ©pendance. + +/// + +Avec cela, vous pouvez connecter le WebSocket puis envoyer et recevoir des messages : + + + +## GĂ©rer les dĂ©connexions et plusieurs clients { #handling-disconnections-and-multiple-clients } + +Lorsqu'une connexion WebSocket est fermĂ©e, l'instruction `await websocket.receive_text()` lĂšvera une exception `WebSocketDisconnect`, que vous pouvez ensuite intercepter et gĂ©rer comme dans cet exemple. + +{* ../../docs_src/websockets/tutorial003_py310.py hl[79:81] *} + +Pour l'essayer : + +* Ouvrez l'application dans plusieurs onglets du navigateur. +* Écrivez des messages depuis ceux-ci. +* Puis fermez l'un des onglets. + +Cela lĂšvera l'exception `WebSocketDisconnect`, et tous les autres clients recevront un message comme : + +``` +Client #1596980209979 left the chat +``` + +/// tip | Astuce + +L'application ci-dessus est un exemple minimal et simple pour montrer comment gĂ©rer et diffuser des messages Ă  plusieurs connexions WebSocket. + +Mais gardez Ă  l'esprit que, comme tout est gĂ©rĂ© en mĂ©moire, dans une seule liste, cela ne fonctionnera que tant que le processus s'exĂ©cute et uniquement avec un seul processus. + +Si vous avez besoin de quelque chose de facile Ă  intĂ©grer avec FastAPI mais plus robuste, pris en charge par Redis, PostgreSQL ou autres, consultez encode/broadcaster. + +/// + +## Plus d'informations { #more-info } + +Pour en savoir plus sur les options, consultez la documentation de Starlette concernant : + +* La classe `WebSocket`. +* Gestion des WebSocket basĂ©e sur des classes. diff --git a/docs/fr/docs/advanced/wsgi.md b/docs/fr/docs/advanced/wsgi.md new file mode 100644 index 000000000..fc89819d2 --- /dev/null +++ b/docs/fr/docs/advanced/wsgi.md @@ -0,0 +1,51 @@ +# Inclure WSGI - Flask, Django, autres { #including-wsgi-flask-django-others } + +Vous pouvez monter des applications WSGI comme vous l'avez vu avec [Sous-applications - Montages](sub-applications.md){.internal-link target=_blank}, [DerriĂšre un proxy](behind-a-proxy.md){.internal-link target=_blank}. + +Pour cela, vous pouvez utiliser `WSGIMiddleware` et l'utiliser pour envelopper votre application WSGI, par exemple Flask, Django, etc. + +## Utiliser `WSGIMiddleware` { #using-wsgimiddleware } + +/// info + +Cela nĂ©cessite l'installation de `a2wsgi`, par exemple avec `pip install a2wsgi`. + +/// + +Vous devez importer `WSGIMiddleware` depuis `a2wsgi`. + +Ensuite, enveloppez l'application WSGI (par ex. Flask) avec le middleware. + +Puis, montez-la sous un chemin. + +{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *} + +/// note | Remarque + +Auparavant, il Ă©tait recommandĂ© d'utiliser `WSGIMiddleware` depuis `fastapi.middleware.wsgi`, mais il est dĂ©sormais dĂ©prĂ©ciĂ©. + +Il est conseillĂ© d'utiliser le package `a2wsgi` Ă  la place. L'utilisation reste la mĂȘme. + +Assurez-vous simplement que le package `a2wsgi` est installĂ© et importez `WSGIMiddleware` correctement depuis `a2wsgi`. + +/// + +## VĂ©rifiez { #check-it } + +DĂ©sormais, chaque requĂȘte sous le chemin `/v1/` sera gĂ©rĂ©e par l'application Flask. + +Et le reste sera gĂ©rĂ© par **FastAPI**. + +Si vous l'exĂ©cutez et allez Ă  http://localhost:8000/v1/, vous verrez la rĂ©ponse de Flask : + +```txt +Hello, World from Flask! +``` + +Et si vous allez Ă  http://localhost:8000/v2, vous verrez la rĂ©ponse de FastAPI : + +```JSON +{ + "message": "Hello World" +} +``` diff --git a/docs/fr/docs/alternatives.md b/docs/fr/docs/alternatives.md index 9d8d85705..c344bd1f8 100644 --- a/docs/fr/docs/alternatives.md +++ b/docs/fr/docs/alternatives.md @@ -1,8 +1,8 @@ -# Alternatives, inspiration et comparaisons +# Alternatives, inspiration et comparaisons { #alternatives-inspiration-and-comparisons } Ce qui a inspirĂ© **FastAPI**, comment il se compare Ă  d'autres solutions et ce qu'il en a appris. -## Intro +## Intro { #intro } **FastAPI** n'existerait pas sans les prĂ©cĂ©dentes contributions d'autres projets. @@ -13,11 +13,11 @@ fonctionnalitĂ©s couvertes par **FastAPI** en utilisant de nombreux frameworks, Mais Ă  un moment donnĂ© il n'y avait pas d'autre option que de crĂ©er quelque chose qui offrait toutes ces fonctionnalitĂ©s, en reprenant et en combinant de la meilleure façon possible les meilleures idĂ©es des outils -prĂ©cĂ©dents, en utilisant des fonctionnalitĂ©s du langage qui n'Ă©taient mĂȘme pas disponibles auparavant (type hints depuis Python 3.6+). +prĂ©cĂ©dents, en utilisant des fonctionnalitĂ©s du langage qui n'Ă©taient mĂȘme pas disponibles auparavant (annotations de type depuis Python 3.6+). -## Outils prĂ©cĂ©dents +## Outils prĂ©cĂ©dents { #previous-tools } -### Django +### Django { #django } C'est le framework Python le plus populaire et il bĂ©nĂ©ficie d'une grande confiance. Il est utilisĂ© pour construire des systĂšmes tel qu'Instagram. @@ -26,18 +26,18 @@ Il est relativement fortement couplĂ© aux bases de donnĂ©es relationnelles (comm n'est pas trĂšs facile d'utiliser une base de donnĂ©es NoSQL (comme Couchbase, MongoDB, Cassandra, etc.) comme principal moyen de stockage. -Il a Ă©tĂ© créé pour gĂ©nĂ©rer le HTML en backend, pas pour crĂ©er des API consommĂ©es par un frontend moderne (comme React, Vue.js et Angular) ou par d'autres systĂšmes (comme les appareils IoT) communiquant avec lui. +Il a Ă©tĂ© créé pour gĂ©nĂ©rer le HTML en backend, pas pour crĂ©er des API consommĂ©es par un frontend moderne (comme React, Vue.js et Angular) ou par d'autres systĂšmes (comme les appareils IoT) communiquant avec lui. -### Django REST Framework +### Django REST Framework { #django-rest-framework } Django REST framework a Ă©tĂ© conçu comme une boĂźte Ă  outils flexible permettant de construire des API Web Ă  partir de Django, afin d'amĂ©liorer ses capacitĂ©s en matiĂšre d'API. Il est utilisĂ© par de nombreuses entreprises, dont Mozilla, Red Hat et Eventbrite. Il s'agissait de l'un des premiers exemples de **documentation automatique pour API**, et c'est prĂ©cisĂ©ment l'une des -premiĂšres idĂ©es qui a inspirĂ© "la recherche de" **FastAPI**. +premiĂšres idĂ©es qui a inspirĂ© « la recherche de » **FastAPI**. -/// note +/// note | Remarque Django REST framework a Ă©tĂ© créé par Tom Christie. Le crĂ©ateur de Starlette et Uvicorn, sur lesquels **FastAPI** est basĂ©. @@ -49,9 +49,9 @@ Avoir une interface de documentation automatique de l'API. /// -### Flask +### Flask { #flask } -Flask est un "micro-framework", il ne comprend pas d'intĂ©grations de bases de donnĂ©es ni beaucoup de choses qui sont fournies par dĂ©faut dans Django. +Flask est un « micro‑framework », il ne comprend pas d'intĂ©grations de bases de donnĂ©es ni beaucoup de choses qui sont fournies par dĂ©faut dans Django. Cette simplicitĂ© et cette flexibilitĂ© permettent d'utiliser des bases de donnĂ©es NoSQL comme principal systĂšme de stockage de donnĂ©es. @@ -60,20 +60,20 @@ technique par moments. Il est aussi couramment utilisĂ© pour d'autres applications qui n'ont pas nĂ©cessairement besoin d'une base de donnĂ©es, de gestion des utilisateurs ou de l'une des nombreuses fonctionnalitĂ©s prĂ©installĂ©es dans Django. Bien que beaucoup de ces fonctionnalitĂ©s puissent ĂȘtre ajoutĂ©es avec des plug-ins. -Ce dĂ©couplage des parties, et le fait d'ĂȘtre un "micro-framework" qui puisse ĂȘtre Ă©tendu pour couvrir exactement ce +Ce dĂ©couplage des parties, et le fait d'ĂȘtre un « micro‑framework » qui puisse ĂȘtre Ă©tendu pour couvrir exactement ce qui est nĂ©cessaire, Ă©tait une caractĂ©ristique clĂ© que je voulais conserver. -Compte tenu de la simplicitĂ© de Flask, il semblait bien adaptĂ© Ă  la crĂ©ation d'API. La prochaine chose Ă  trouver Ă©tait un "Django REST Framework" pour Flask. +Compte tenu de la simplicitĂ© de Flask, il semblait bien adaptĂ© Ă  la crĂ©ation d'API. La prochaine chose Ă  trouver Ă©tait un « Django REST Framework » pour Flask. /// check | A inspirĂ© **FastAPI** Ă  -Être un micro-framework. Il est donc facile de combiner les outils et les piĂšces nĂ©cessaires. +Être un micro‑framework. Il est donc facile de combiner les outils et les piĂšces nĂ©cessaires. Proposer un systĂšme de routage simple et facile Ă  utiliser. /// -### Requests +### Requests { #requests } **FastAPI** n'est pas rĂ©ellement une alternative Ă  **Requests**. Leur cadre est trĂšs diffĂ©rent. @@ -97,7 +97,7 @@ La façon dont vous l'utilisez est trĂšs simple. Par exemple, pour faire une req response = requests.get("http://example.com/some/url") ``` -En contrepartie l'API _des opĂ©rations de chemin_ de FastAPI pourrait ressembler Ă  ceci : +L’opĂ©ration de chemin d'accĂšs correspondante dans **FastAPI** pourrait ressembler Ă  ceci : ```Python hl_lines="1" @app.get("/some/url") @@ -109,13 +109,13 @@ Notez les similitudes entre `requests.get(...)` et `@app.get(...)`. /// check | A inspirĂ© **FastAPI** Ă  -Avoir une API simple et intuitive. - -Utiliser les noms de mĂ©thodes HTTP (opĂ©rations) directement, de maniĂšre simple et intuitive. \* Avoir des valeurs par dĂ©faut raisonnables, mais des personnalisations puissantes. +* Avoir une API simple et intuitive. +* Utiliser les noms de mĂ©thodes HTTP (opĂ©rations) directement, de maniĂšre simple et intuitive. +* Avoir des valeurs par dĂ©faut raisonnables, mais des personnalisations puissantes. /// -### Swagger / OpenAPI +### Swagger / OpenAPI { #swagger-openapi } La principale fonctionnalitĂ© que j'ai empruntĂ© Ă  Django REST Framework Ă©tait la documentation automatique des API. @@ -126,7 +126,7 @@ Swagger pour une API permettrait d'utiliser cette interface utilisateur web auto À un moment donnĂ©, Swagger a Ă©tĂ© cĂ©dĂ© Ă  la Fondation Linux, puis a Ă©tĂ© rebaptisĂ© OpenAPI. -C'est pourquoi, lorsqu'on parle de la version 2.0, il est courant de dire "Swagger", et pour la version 3+ "OpenAPI". +C'est pourquoi, lorsqu'on parle de la version 2.0, il est courant de dire « Swagger », et pour la version 3+ « OpenAPI ». /// check | A inspirĂ© **FastAPI** Ă  @@ -141,16 +141,15 @@ Ces deux-lĂ  ont Ă©tĂ© choisis parce qu'ils sont populaires et stables, mais en /// -### Frameworks REST pour Flask +### Frameworks REST pour Flask { #flask-rest-frameworks } Il y a plusieurs frameworks REST pour Flask, mais aprĂšs avoir investi du temps et du travail pour les Ă©tudier, j'ai dĂ©couvert que le dĂ©veloppement de beaucoup d'entre eux sont suspendus ou abandonnĂ©s, avec plusieurs problĂšmes permanents qui les rendent inadaptĂ©s. -### Marshmallow +### Marshmallow { #marshmallow } -L'une des principales fonctionnalitĂ©s nĂ©cessaires aux systĂšmes API est la "sĂ©rialisation" des donnĂ©es, qui consiste Ă  prendre les donnĂ©es du code (Python) et Ă  +L'une des principales fonctionnalitĂ©s nĂ©cessaires aux systĂšmes API est la « sĂ©rialisation » des donnĂ©es, qui consiste Ă  prendre les donnĂ©es du code (Python) et Ă  les convertir en quelque chose qui peut ĂȘtre envoyĂ© sur le rĂ©seau. Par exemple, convertir un objet contenant des donnĂ©es provenant d'une base de donnĂ©es en un objet JSON. Convertir des objets `datetime` en strings, etc. @@ -163,19 +162,17 @@ Sans un systĂšme de validation des donnĂ©es, vous devriez effectuer toutes les v Ces fonctionnalitĂ©s sont ce pourquoi Marshmallow a Ă©tĂ© construit. C'est une excellente bibliothĂšque, et je l'ai dĂ©jĂ  beaucoup utilisĂ©e. -Mais elle a Ă©tĂ© créée avant que les type hints n'existent en Python. Ainsi, pour dĂ©finir chaque schĂ©ma, vous devez utiliser des utilitaires et des classes spĂ©cifiques fournies par Marshmallow. +Mais elle a Ă©tĂ© créée avant que les annotations de type n'existent en Python. Ainsi, pour dĂ©finir chaque schĂ©ma, vous devez utiliser des utilitaires et des classes spĂ©cifiques fournies par Marshmallow. /// check | A inspirĂ© **FastAPI** Ă  -Utilisez du code pour dĂ©finir des "schĂ©mas" qui fournissent automatiquement les types de donnĂ©es et la validation. +Utilisez du code pour dĂ©finir des « schĂ©mas » qui fournissent automatiquement les types de donnĂ©es et la validation. /// -### Webargs +### Webargs { #webargs } -Une autre grande fonctionnalitĂ© requise par les API est le parsing des donnĂ©es provenant des requĂȘtes entrantes. +Une autre grande fonctionnalitĂ© requise par les API est l’analyse des donnĂ©es provenant des requĂȘtes entrantes. Webargs est un outil qui a Ă©tĂ© créé pour fournir cela par-dessus plusieurs frameworks, dont Flask. @@ -195,7 +192,7 @@ Disposer d'une validation automatique des donnĂ©es des requĂȘtes entrantes. /// -### APISpec +### APISpec { #apispec } Marshmallow et Webargs fournissent la validation, l'analyse et la sĂ©rialisation en tant que plug-ins. @@ -225,7 +222,7 @@ Supporter la norme ouverte pour les API, OpenAPI. /// -### Flask-apispec +### Flask-apispec { #flask-apispec } C'est un plug-in pour Flask, qui relie Webargs, Marshmallow et APISpec. @@ -240,11 +237,11 @@ Cette combinaison de Flask, Flask-apispec avec Marshmallow et Webargs Ă©tait ma Son utilisation a conduit Ă  la crĂ©ation de plusieurs gĂ©nĂ©rateurs Flask full-stack. Ce sont les principales stacks que j'ai (ainsi que plusieurs Ă©quipes externes) utilisĂ©es jusqu'Ă  prĂ©sent : -- https://github.com/tiangolo/full-stack -- https://github.com/tiangolo/full-stack-flask-couchbase -- https://github.com/tiangolo/full-stack-flask-couchdb +* https://github.com/tiangolo/full-stack +* https://github.com/tiangolo/full-stack-flask-couchbase +* https://github.com/tiangolo/full-stack-flask-couchdb -Ces mĂȘmes gĂ©nĂ©rateurs full-stack ont servi de base aux [GĂ©nĂ©rateurs de projets pour **FastAPI**](project-generation.md){.internal-link target=\_blank}. +Ces mĂȘmes gĂ©nĂ©rateurs full-stack ont servi de base aux [GĂ©nĂ©rateurs de projets pour **FastAPI**](project-generation.md){.internal-link target=_blank}. /// info @@ -258,15 +255,15 @@ GĂ©nĂ©rer le schĂ©ma OpenAPI automatiquement, Ă  partir du mĂȘme code qui dĂ©fin /// -### NestJS (et Angular) +### NestJS (et Angular) { #nestjs-and-angular } Ce n'est mĂȘme pas du Python, NestJS est un framework JavaScript (TypeScript) NodeJS inspirĂ© d'Angular. Il rĂ©alise quelque chose de similaire Ă  ce qui peut ĂȘtre fait avec Flask-apispec. -Il possĂšde un systĂšme d'injection de dĂ©pendances intĂ©grĂ©, inspirĂ© d'Angular 2. Il nĂ©cessite de prĂ©-enregistrer les "injectables" (comme tous les autres systĂšmes d'injection de dĂ©pendances que je connais), donc, cela ajoute Ă  la verbositĂ© et Ă  la rĂ©pĂ©tition du code. +Il possĂšde un systĂšme d'injection de dĂ©pendances intĂ©grĂ©, inspirĂ© d'Angular 2. Il nĂ©cessite de prĂ©-enregistrer les « injectables » (comme tous les autres systĂšmes d'injection de dĂ©pendances que je connais), donc, cela ajoute Ă  la verbositĂ© et Ă  la rĂ©pĂ©tition du code. -Comme les paramĂštres sont dĂ©crits avec des types TypeScript (similaires aux type hints de Python), la prise en charge +Comme les paramĂštres sont dĂ©crits avec des types TypeScript (similaires aux annotations de type de Python), la prise en charge par l'Ă©diteur est assez bonne. Mais comme les donnĂ©es TypeScript ne sont pas prĂ©servĂ©es aprĂšs la compilation en JavaScript, il ne peut pas compter sur les types pour dĂ©finir la validation, la sĂ©rialisation et la documentation en mĂȘme temps. En raison de cela et de certaines dĂ©cisions de conception, pour obtenir la validation, la sĂ©rialisation et la gĂ©nĂ©ration automatique de schĂ©mas, il est nĂ©cessaire d'ajouter des dĂ©corateurs Ă  de nombreux endroits. Cela devient donc assez verbeux. @@ -281,7 +278,7 @@ Disposer d'un puissant systĂšme d'injection de dĂ©pendances. Trouver un moyen de /// -### Sanic +### Sanic { #sanic } C'Ă©tait l'un des premiers frameworks Python extrĂȘmement rapides basĂ©s sur `asyncio`. Il a Ă©tĂ© conçu pour ĂȘtre trĂšs similaire Ă  Flask. @@ -301,14 +298,12 @@ C'est pourquoi **FastAPI** est basĂ© sur Starlette, car il s'agit du framework l /// -### Falcon +### Falcon { #falcon } Falcon est un autre framework Python haute performance, il est conçu pour ĂȘtre minimal, et est utilisĂ© comme fondation pour d'autres frameworks comme Hug. -Il utilise le standard prĂ©cĂ©dent pour les frameworks web Python (WSGI) qui est synchrone, donc il ne peut pas gĂ©rer les WebSockets et d'autres cas d'utilisation. NĂ©anmoins, il offre de trĂšs bonnes performances. - -Il est conçu pour avoir des fonctions qui reçoivent deux paramĂštres, une "requĂȘte" et une "rĂ©ponse". Ensuite, vous -"lisez" des parties de la requĂȘte et "Ă©crivez" des parties dans la rĂ©ponse. En raison de cette conception, il n'est +Il est conçu pour avoir des fonctions qui reçoivent deux paramĂštres, une « requĂȘte » et une « rĂ©ponse ». Ensuite, vous +« lisez » des parties de la requĂȘte et « Ă©crivez » des parties dans la rĂ©ponse. En raison de cette conception, il n'est pas possible de dĂ©clarer des paramĂštres de requĂȘte et des corps avec des indications de type Python standard comme paramĂštres de fonction. Ainsi, la validation, la sĂ©rialisation et la documentation des donnĂ©es doivent ĂȘtre effectuĂ©es dans le code, et non pas automatiquement. Ou bien elles doivent ĂȘtre implĂ©mentĂ©es comme un framework au-dessus de Falcon, comme Hug. Cette mĂȘme distinction se retrouve dans d'autres frameworks qui s'inspirent de la conception de Falcon, qui consiste Ă  avoir un objet de requĂȘte et un objet de rĂ©ponse comme paramĂštres. @@ -323,20 +318,20 @@ Bien que dans FastAPI, il est facultatif, et est utilisĂ© principalement pour d /// -### Molten +### Molten { #molten } J'ai dĂ©couvert Molten lors des premiĂšres Ă©tapes de dĂ©veloppement de **FastAPI**. Et il a des idĂ©es assez similaires : -- BasĂ© sur les type hints Python. -- Validation et documentation via ces types. -- SystĂšme d'injection de dĂ©pendances. +* BasĂ© sur les annotations de type Python. +* Validation et documentation via ces types. +* SystĂšme d'injection de dĂ©pendances. Il n'utilise pas une librairie tiers de validation, sĂ©rialisation et de documentation tel que Pydantic, il utilise son propre systĂšme. Ainsi, ces dĂ©finitions de types de donnĂ©es ne sont pas rĂ©utilisables aussi facilement. -Il nĂ©cessite une configuration un peu plus verbeuse. Et comme il est basĂ© sur WSGI (au lieu dASGI), il n'est pas +Il nĂ©cessite une configuration un peu plus verbeuse. Et comme il est basĂ© sur WSGI (au lieu d'ASGI), il n'est pas conçu pour profiter des hautes performances fournies par des outils comme Uvicorn, Starlette et Sanic. -Le systĂšme d'injection de dĂ©pendances exige le prĂ©-enregistrement des dĂ©pendances et les dĂ©pendances sont rĂ©solues sur la base des types dĂ©clarĂ©s. Ainsi, il n'est pas possible de dĂ©clarer plus d'un "composant" qui fournit un certain type. +Le systĂšme d'injection de dĂ©pendances exige le prĂ©-enregistrement des dĂ©pendances et les dĂ©pendances sont rĂ©solues sur la base des types dĂ©clarĂ©s. Ainsi, il n'est pas possible de dĂ©clarer plus d'un « composant » qui fournit un certain type. Les routes sont dĂ©clarĂ©es Ă  un seul endroit, en utilisant des fonctions dĂ©clarĂ©es Ă  d'autres endroits (au lieu d'utiliser des dĂ©corateurs qui peuvent ĂȘtre placĂ©s juste au-dessus de la fonction qui gĂšre l'endpoint). Cette @@ -345,15 +340,15 @@ qui sont relativement fortement couplĂ©es. /// check | A inspirĂ© **FastAPI** Ă  -DĂ©finir des validations supplĂ©mentaires pour les types de donnĂ©es utilisant la valeur "par dĂ©faut" des attributs du modĂšle. Ceci amĂ©liore le support de l'Ă©diteur, et n'Ă©tait pas disponible dans Pydantic auparavant. +DĂ©finir des validations supplĂ©mentaires pour les types de donnĂ©es utilisant la valeur « par dĂ©faut » des attributs du modĂšle. Ceci amĂ©liore le support de l'Ă©diteur, et n'Ă©tait pas disponible dans Pydantic auparavant. Cela a en fait inspirĂ© la mise Ă  jour de certaines parties de Pydantic, afin de supporter le mĂȘme style de dĂ©claration de validation (toute cette fonctionnalitĂ© est maintenant dĂ©jĂ  disponible dans Pydantic). /// -### Hug +### Hug { #hug } -Hug a Ă©tĂ© l'un des premiers frameworks Ă  implĂ©menter la dĂ©claration des types de paramĂštres d'API en utilisant les type hints Python. C'Ă©tait une excellente idĂ©e qui a inspirĂ© d'autres outils Ă  faire de mĂȘme. +Hug a Ă©tĂ© l'un des premiers frameworks Ă  implĂ©menter la dĂ©claration des types de paramĂštres d'API en utilisant les annotations de type Python. C'Ă©tait une excellente idĂ©e qui a inspirĂ© d'autres outils Ă  faire de mĂȘme. Il utilisait des types personnalisĂ©s dans ses dĂ©clarations au lieu des types Python standard, mais c'Ă©tait tout de mĂȘme un Ă©norme pas en avant. @@ -372,28 +367,28 @@ Hug a Ă©tĂ© créé par Timothy Crosley, le crĂ©ateur de APIStar (<= 0.5) +### APIStar (<= 0.5) { #apistar-0-5 } Juste avant de dĂ©cider de dĂ©velopper **FastAPI**, j'ai trouvĂ© le serveur **APIStar**. Il contenait presque tout ce que je recherchais et avait un beau design. -C'Ă©tait l'une des premiĂšres implĂ©mentations d'un framework utilisant les type hints Python pour dĂ©clarer les paramĂštres +C'Ă©tait l'une des premiĂšres implĂ©mentations d'un framework utilisant les annotations de type Python pour dĂ©clarer les paramĂštres et les requĂȘtes que j'ai vues (avant NestJS et Molten). Je l'ai trouvĂ© plus ou moins en mĂȘme temps que Hug. Mais APIStar utilisait le standard OpenAPI. -Il disposait de la validation automatique, sĂ©rialisation des donnĂ©es et d'une gĂ©nĂ©ration de schĂ©ma OpenAPI basĂ©e sur les mĂȘmes type hints Ă  plusieurs endroits. +Il disposait de la validation automatique, sĂ©rialisation des donnĂ©es et d'une gĂ©nĂ©ration de schĂ©ma OpenAPI basĂ©e sur les mĂȘmes annotations de type Ă  plusieurs endroits. -La dĂ©finition du schĂ©ma de corps de requĂȘte n'utilisait pas les mĂȘmes type hints Python que Pydantic, il Ă©tait un peu plus proche de Marshmallow, donc le support de l'Ă©diteur n'Ă©tait pas aussi bon, mais APIStar Ă©tait quand mĂȘme la meilleure option disponible. +La dĂ©finition du schĂ©ma de corps de requĂȘte n'utilisait pas les mĂȘmes annotations de type Python que Pydantic, il Ă©tait un peu plus proche de Marshmallow, donc le support de l'Ă©diteur n'Ă©tait pas aussi bon, mais APIStar Ă©tait quand mĂȘme la meilleure option disponible. Il avait les meilleures performances d'aprĂšs les benchmarks de l'Ă©poque (seulement surpassĂ© par Starlette). @@ -429,20 +424,20 @@ Et aprĂšs avoir longtemps cherchĂ© un framework similaire et testĂ© de nombreuse Puis APIStar a cessĂ© d'exister en tant que serveur et Starlette a Ă©tĂ© créé, et a constituĂ© une meilleure base pour un tel systĂšme. Ce fut l'inspiration finale pour construire **FastAPI**. -Je considĂšre **FastAPI** comme un "successeur spirituel" d'APIStar, tout en amĂ©liorant et en augmentant les fonctionnalitĂ©s, le systĂšme de typage et d'autres parties, sur la base des enseignements tirĂ©s de tous ces outils prĂ©cĂ©dents. +Je considĂšre **FastAPI** comme un « successeur spirituel » d'APIStar, tout en amĂ©liorant et en augmentant les fonctionnalitĂ©s, le systĂšme de typage et d'autres parties, sur la base des enseignements tirĂ©s de tous ces outils prĂ©cĂ©dents. /// -## UtilisĂ©s par **FastAPI** +## UtilisĂ©s par **FastAPI** { #used-by-fastapi } -### Pydantic +### Pydantic { #pydantic } -Pydantic est une bibliothĂšque permettant de dĂ©finir la validation, la sĂ©rialisation et la documentation des donnĂ©es (Ă  l'aide de JSON Schema) en se basant sur les Python type hints. +Pydantic est une bibliothĂšque permettant de dĂ©finir la validation, la sĂ©rialisation et la documentation des donnĂ©es (Ă  l'aide de JSON Schema) en se basant sur les annotations de type Python. Cela le rend extrĂȘmement intuitif. Il est comparable Ă  Marshmallow. Bien qu'il soit plus rapide que Marshmallow dans les benchmarks. Et comme il est -basĂ© sur les mĂȘmes type hints Python, le support de l'Ă©diteur est grand. +basĂ© sur les mĂȘmes annotations de type Python, le support de l'Ă©diteur est grand. /// check | **FastAPI** l'utilise pour @@ -452,9 +447,9 @@ GĂ©rer toute la validation des donnĂ©es, leur sĂ©rialisation et la documentation /// -### Starlette +### Starlette { #starlette } -Starlette est un framework/toolkit lĂ©ger ASGI, qui est idĂ©al pour construire des services asyncio performants. +Starlette est un framework/toolkit lĂ©ger ASGI, qui est idĂ©al pour construire des services asyncio performants. Il est trĂšs simple et intuitif. Il est conçu pour ĂȘtre facilement extensible et avoir des composants modulaires. @@ -462,29 +457,28 @@ Il offre : - Des performances vraiment impressionnantes. - Le support des WebSockets. -- Le support de GraphQL. - Les tĂąches d'arriĂšre-plan. - Les Ă©vĂ©nements de dĂ©marrage et d'arrĂȘt. -- Un client de test basĂ© sur request. +- Un client de test basĂ© sur HTTPX. - CORS, GZip, fichiers statiques, streaming des rĂ©ponses. - Le support des sessions et des cookies. - Une couverture de test Ă  100 %. - 100 % de la base de code avec des annotations de type. -- ZĂ©ro forte dĂ©pendance Ă  d'autres packages. +- Peu de dĂ©pendances strictes. Starlette est actuellement le framework Python le plus rapide testĂ©. Seulement dĂ©passĂ© par Uvicorn, qui n'est pas un framework, mais un serveur. -Starlette fournit toutes les fonctionnalitĂ©s de base d'un micro-framework web. +Starlette fournit toutes les fonctionnalitĂ©s de base d'un micro‑framework web. Mais il ne fournit pas de validation automatique des donnĂ©es, de sĂ©rialisation ou de documentation. -C'est l'une des principales choses que **FastAPI** ajoute par-dessus, le tout basĂ© sur les type hints Python (en utilisant Pydantic). Cela, plus le systĂšme d'injection de dĂ©pendances, les utilitaires de sĂ©curitĂ©, la gĂ©nĂ©ration de schĂ©mas OpenAPI, etc. +C'est l'une des principales choses que **FastAPI** ajoute par-dessus, le tout basĂ© sur les annotations de type Python (en utilisant Pydantic). Cela, plus le systĂšme d'injection de dĂ©pendances, les utilitaires de sĂ©curitĂ©, la gĂ©nĂ©ration de schĂ©mas OpenAPI, etc. /// note | DĂ©tails techniques -ASGI est une nouvelle "norme" dĂ©veloppĂ©e par les membres de l'Ă©quipe principale de Django. Il ne s'agit pas encore d'une "norme Python" (un PEP), bien qu'ils soient en train de le faire. +ASGI est une nouvelle « norme » dĂ©veloppĂ©e par les membres de l'Ă©quipe principale de Django. Il ne s'agit pas encore d'une « norme Python » (un PEP), bien qu'ils soient en train de le faire. -NĂ©anmoins, il est dĂ©jĂ  utilisĂ© comme "standard" par plusieurs outils. Cela amĂ©liore grandement l'interopĂ©rabilitĂ©, puisque vous pouvez remplacer Uvicorn par n'importe quel autre serveur ASGI (comme Daphne ou Hypercorn), ou vous pouvez ajouter des outils compatibles ASGI, comme `python-socketio`. +NĂ©anmoins, il est dĂ©jĂ  utilisĂ© comme « standard » par plusieurs outils. Cela amĂ©liore grandement l'interopĂ©rabilitĂ©, puisque vous pouvez remplacer Uvicorn par n'importe quel autre serveur ASGI (comme Daphne ou Hypercorn), ou vous pouvez ajouter des outils compatibles ASGI, comme `python-socketio`. /// @@ -498,7 +492,7 @@ Ainsi, tout ce que vous pouvez faire avec Starlette, vous pouvez le faire direct /// -### Uvicorn +### Uvicorn { #uvicorn } Uvicorn est un serveur ASGI rapide comme l'Ă©clair, basĂ© sur uvloop et httptools. @@ -511,12 +505,12 @@ C'est le serveur recommandĂ© pour Starlette et **FastAPI**. Le serveur web principal pour exĂ©cuter les applications **FastAPI**. -Vous pouvez le combiner avec Gunicorn, pour avoir un serveur multi-processus asynchrone. +Vous pouvez Ă©galement utiliser l'option de ligne de commande `--workers` pour avoir un serveur multi‑processus asynchrone. Pour plus de dĂ©tails, consultez la section [DĂ©ploiement](deployment/index.md){.internal-link target=_blank}. /// -## Benchmarks et vitesse +## Benchmarks et vitesse { #benchmarks-and-speed } -Pour comprendre, comparer et voir la diffĂ©rence entre Uvicorn, Starlette et FastAPI, consultez la section sur les [Benchmarks](benchmarks.md){.internal-link target=\_blank}. +Pour comprendre, comparer et voir la diffĂ©rence entre Uvicorn, Starlette et FastAPI, consultez la section sur les [Benchmarks](benchmarks.md){.internal-link target=_blank}. diff --git a/docs/fr/docs/async.md b/docs/fr/docs/async.md index 1437ae517..72923e03b 100644 --- a/docs/fr/docs/async.md +++ b/docs/fr/docs/async.md @@ -1,17 +1,18 @@ -# Concurrence et les mots-clĂ©s async et await +# Concurrence et async / await { #concurrency-and-async-await } -Cette page vise Ă  fournir des dĂ©tails sur la syntaxe `async def` pour les *fonctions de chemins* et quelques rappels sur le code asynchrone, la concurrence et le parallĂ©lisme. +DĂ©tails sur la syntaxe `async def` pour les *fonctions de chemin d'accĂšs* et quelques rappels sur le code asynchrone, la concurrence et le parallĂ©lisme. -## Vous ĂȘtes pressĂ©s ? +## Vous ĂȘtes pressĂ©s ? { #in-a-hurry } -TL;DR : +TL;DR : Si vous utilisez des bibliothĂšques tierces qui nĂ©cessitent d'ĂȘtre appelĂ©es avec `await`, telles que : ```Python results = await some_library() ``` -Alors, dĂ©clarez vos *fonctions de chemins* avec `async def` comme ceci : + +Alors, dĂ©clarez vos *fonctions de chemin d'accĂšs* avec `async def` comme ceci : ```Python hl_lines="2" @app.get('/') @@ -20,7 +21,7 @@ async def read_results(): return results ``` -/// note +/// note | Remarque Vous pouvez uniquement utiliser `await` dans les fonctions créées avec `async def`. @@ -28,7 +29,7 @@ Vous pouvez uniquement utiliser `await` dans les fonctions créées avec `async --- -Si vous utilisez une bibliothĂšque externe qui communique avec quelque chose (une BDD, une API, un systĂšme de fichiers, etc.) et qui ne supporte pas l'utilisation d'`await` (ce qui est actuellement le cas pour la majoritĂ© des bibliothĂšques de BDD), alors dĂ©clarez vos *fonctions de chemin* normalement, avec le classique `def`, comme ceci : +Si vous utilisez une bibliothĂšque externe qui communique avec quelque chose (une base de donnĂ©es, une API, le systĂšme de fichiers, etc.) et qui ne supporte pas l'utilisation d'`await` (ce qui est actuellement le cas pour la majoritĂ© des bibliothĂšques de base de donnĂ©es), alors dĂ©clarez vos *fonctions de chemin d'accĂšs* normalement, avec le classique `def`, comme ceci : ```Python hl_lines="2" @app.get('/') @@ -39,7 +40,7 @@ def results(): --- -Si votre application n'a pas Ă  communiquer avec une bibliothĂšque externe et pas Ă  attendre de rĂ©ponse, utilisez `async def`. +Si votre application n'a pas Ă  communiquer avec une autre chose et Ă  attendre sa rĂ©ponse, utilisez `async def`, mĂȘme si vous n'avez pas besoin d'utiliser `await` Ă  l'intĂ©rieur. --- @@ -47,15 +48,15 @@ Si vous ne savez pas, utilisez seulement `def` comme vous le feriez habituelleme --- -**Note** : vous pouvez mĂ©langer `def` et `async def` dans vos *fonctions de chemin* autant que nĂ©cessaire, **FastAPI** saura faire ce qu'il faut avec. +Note : vous pouvez mĂ©langer `def` et `async def` dans vos *fonctions de chemin d'accĂšs* autant que nĂ©cessaire, et dĂ©finir chacune avec l’option la plus adaptĂ©e pour vous. FastAPI fera ce qu'il faut avec elles. -Au final, peu importe le cas parmi ceux ci-dessus, **FastAPI** fonctionnera de maniĂšre asynchrone et sera extrĂȘmement rapide. +Au final, peu importe le cas parmi ceux ci-dessus, FastAPI fonctionnera de maniĂšre asynchrone et sera extrĂȘmement rapide. -Mais si vous suivez bien les instructions ci-dessus, alors **FastAPI** pourra effectuer quelques optimisations et ainsi amĂ©liorer les performances. +Mais si vous suivez bien les instructions ci-dessus, il pourra effectuer quelques optimisations et ainsi amĂ©liorer les performances. -## DĂ©tails techniques +## DĂ©tails techniques { #technical-details } -Les versions modernes de Python supportent le **code asynchrone** grĂące aux **"coroutines"** avec les syntaxes **`async` et `await`**. +Les versions modernes de Python supportent le **code asynchrone** grĂące aux **« coroutines »** avec les syntaxes **`async` et `await`**. Analysons les diffĂ©rentes parties de cette phrase dans les sections suivantes : @@ -63,46 +64,46 @@ Analysons les diffĂ©rentes parties de cette phrase dans les sections suivantes : * **`async` et `await`** * **Coroutines** -## Code asynchrone +## Code asynchrone { #asynchronous-code } -Faire du code asynchrone signifie que le langage 💬 est capable de dire Ă  l'ordinateur / au programme đŸ€– qu'Ă  un moment du code, il đŸ€– devra attendre que *quelque chose d'autre* se termine autre part. Disons que ce *quelque chose d'autre* est appelĂ© "fichier-lent" 📝. +Faire du code asynchrone signifie que le langage 💬 est capable de dire Ă  l'ordinateur / au programme đŸ€– qu'Ă  un moment du code, il đŸ€– devra attendre que *quelque chose d'autre* se termine autre part. Disons que ce *quelque chose d'autre* est appelĂ© « slow-file » 📝. -Donc, pendant ce temps, l'ordinateur pourra effectuer d'autres tĂąches, pendant que "fichier-lent" 📝 se termine. +Donc, pendant ce temps, l'ordinateur pourra effectuer d'autres tĂąches, pendant que « slow-file » 📝 se termine. Ensuite l'ordinateur / le programme đŸ€– reviendra Ă  chaque fois qu'il en a la chance que ce soit parce qu'il attend Ă  nouveau, ou car il đŸ€– a fini tout le travail qu'il avait Ă  faire. Il đŸ€– regardera donc si les tĂąches qu'il attend ont terminĂ© d'ĂȘtre effectuĂ©es. -Ensuite, il đŸ€– prendra la premiĂšre tĂąche Ă  finir (disons, notre "fichier-lent" 📝) et continuera Ă  faire avec cette derniĂšre ce qu'il Ă©tait censĂ©. +Ensuite, il đŸ€– prendra la premiĂšre tĂąche Ă  finir (disons, notre « slow-file » 📝) et continuera Ă  faire avec cette derniĂšre ce qu'il Ă©tait censĂ©. -Ce "attendre quelque chose d'autre" fait gĂ©nĂ©ralement rĂ©fĂ©rence Ă  des opĂ©rations I/O qui sont relativement "lentes" (comparĂ©es Ă  la vitesse du processeur et de la mĂ©moire RAM) telles qu'attendre que : +Ce « attendre quelque chose d'autre » fait gĂ©nĂ©ralement rĂ©fĂ©rence Ă  des opĂ©rations I/O qui sont relativement « lentes » (comparĂ©es Ă  la vitesse du processeur et de la mĂ©moire RAM) telles qu'attendre que : * de la donnĂ©e soit envoyĂ©e par le client Ă  travers le rĂ©seau * de la donnĂ©e envoyĂ©e depuis votre programme soit reçue par le client Ă  travers le rĂ©seau * le contenu d'un fichier sur le disque soit lu par le systĂšme et passĂ© Ă  votre programme * le contenu que votre programme a passĂ© au systĂšme soit Ă©crit sur le disque * une opĂ©ration effectuĂ©e Ă  distance par une API se termine -* une opĂ©ration en BDD se termine -* une requĂȘte Ă  une BDD renvoie un rĂ©sultat +* une opĂ©ration en base de donnĂ©es se termine +* une requĂȘte Ă  une base de donnĂ©es renvoie un rĂ©sultat * etc. -Le temps d'exĂ©cution Ă©tant consommĂ© majoritairement par l'attente d'opĂ©rations I/O on appelle ceci des opĂ©rations "I/O bound". +Le temps d'exĂ©cution Ă©tant consommĂ© majoritairement par l'attente d'opĂ©rations I/O, on appelle ceci des opĂ©rations « I/O bound ». -Ce concept se nomme l'"asynchronisme" car l'ordinateur / le programme n'a pas besoin d'ĂȘtre "synchronisĂ©" avec la tĂąche, attendant le moment exact oĂč cette derniĂšre se terminera en ne faisant rien, pour ĂȘtre capable de rĂ©cupĂ©rer le rĂ©sultat de la tĂąche et l'utiliser dans la suite des opĂ©rations. +Ce concept se nomme « asynchrone » car l'ordinateur / le programme n'a pas besoin d'ĂȘtre « synchronisĂ© » avec la tĂąche, attendant le moment exact oĂč cette derniĂšre se terminera en ne faisant rien, pour ĂȘtre capable de rĂ©cupĂ©rer le rĂ©sultat de la tĂąche et l'utiliser dans la suite des opĂ©rations. -À la place, en Ă©tant "asynchrone", une fois terminĂ©e, une tĂąche peut lĂ©gĂšrement attendre (quelques microsecondes) que l'ordinateur / le programme finisse ce qu'il Ă©tait en train de faire, et revienne rĂ©cupĂ©rer le rĂ©sultat. +À la place, en Ă©tant « asynchrone », une fois terminĂ©e, une tĂąche peut lĂ©gĂšrement attendre (quelques microsecondes) que l'ordinateur / le programme finisse ce qu'il Ă©tait en train de faire, et revienne rĂ©cupĂ©rer le rĂ©sultat. -Pour parler de tĂąches "synchrones" (en opposition Ă  "asynchrones"), on utilise souvent le terme "sĂ©quentiel", car l'ordinateur / le programme va effectuer toutes les Ă©tapes d'une tĂąche sĂ©quentiellement avant de passer Ă  une autre tĂąche, mĂȘme si ces Ă©tapes impliquent de l'attente. +Pour parler de tĂąches « synchrones » (en opposition Ă  « asynchrones »), on utilise souvent le terme « sĂ©quentiel », car l'ordinateur / le programme va effectuer toutes les Ă©tapes d'une tĂąche sĂ©quentiellement avant de passer Ă  une autre tĂąche, mĂȘme si ces Ă©tapes impliquent de l'attente. -### Concurrence et Burgers +### Concurrence et Burgers { #concurrency-and-burgers } -L'idĂ©e de code **asynchrone** dĂ©crite ci-dessus est parfois aussi appelĂ©e **"concurrence"**. Ce qui est diffĂ©rent du **"parallĂ©lisme"**. +L'idĂ©e de code **asynchrone** dĂ©crite ci-dessus est parfois aussi appelĂ©e **« concurrence »**. Ce qui est diffĂ©rent du **« parallĂ©lisme »**. -La **concurrence** et le **parallĂ©lisme** sont tous deux liĂ©s Ă  l'idĂ©e de "diffĂ©rentes choses arrivant plus ou moins au mĂȘme moment". +La **concurrence** et le **parallĂ©lisme** sont tous deux liĂ©s Ă  l'idĂ©e de « diffĂ©rentes choses arrivant plus ou moins au mĂȘme moment ». Mais les dĂ©tails entre la **concurrence** et le **parallĂ©lisme** diffĂšrent sur de nombreux points. Pour expliquer la diffĂ©rence, voici une histoire de burgers : -#### Burgers concurrents +### Burgers concurrents { #concurrent-burgers } Vous amenez votre crush 😍 dans votre fast food 🍔 favori, et faites la queue pendant que le serveur 💁 prend les commandes des personnes devant vous. @@ -122,13 +123,13 @@ Le serveur 💁 vous donne le numĂ©ro assignĂ© Ă  votre commande. -Pendant que vous attendez, vous allez choisir une table avec votre crush 😍, vous discutez avec votre crush 😍 pendant un long moment (les burgers Ă©tant "magnifiques" ils sont trĂšs longs Ă  prĂ©parer ✹🍔✹). +Pendant que vous attendez, vous allez choisir une table avec votre crush 😍, vous discutez avec votre crush 😍 pendant un long moment (les burgers Ă©tant « magnifiques » ils sont trĂšs longs Ă  prĂ©parer ✹🍔✹). Pendant que vous ĂȘtes assis Ă  table, en attendant que les burgers 🍔 soient prĂȘts, vous pouvez passer ce temps Ă  admirer Ă  quel point votre crush 😍 est gĂ©niale, mignonne et intelligente ✹😍✹. -Pendant que vous discutez avec votre crush 😍, de temps en temps vous jetez un coup d'oeil au nombre affichĂ© au-dessus du comptoir pour savoir si c'est Ă  votre tour d'ĂȘtre servis. +Pendant que vous discutez avec votre crush 😍, de temps en temps vous jetez un coup d’Ɠil au nombre affichĂ© au-dessus du comptoir pour savoir si c'est Ă  votre tour d'ĂȘtre servis. Jusqu'au moment oĂč c'est (enfin) votre tour. Vous allez au comptoir, rĂ©cupĂ©rez vos burgers 🍔 et revenez Ă  votre table. @@ -148,23 +149,23 @@ Illustrations proposĂ©es par @@ -212,7 +213,7 @@ Illustrations proposĂ©es par (tout ça grĂące Ă  Starlette). +Et comme on peut avoir du parallĂ©lisme et de l'asynchronicitĂ© en mĂȘme temps, on obtient des performances plus hautes que la plupart des frameworks NodeJS testĂ©s et Ă©gales Ă  celles du Go, qui est un langage compilĂ© plus proche du C (tout ça grĂące Ă  Starlette). -### Est-ce que la concurrence est mieux que le parallĂ©lisme ? +### Est-ce que la concurrence est mieux que le parallĂ©lisme ? { #is-concurrency-better-than-parallelism } Nope ! C'est ça la morale de l'histoire. @@ -276,11 +277,11 @@ Mais dans ce cas, si pouviez amener 8 ex-serveurs/cuisiniers/devenus-nettoyeurs Dans ce scĂ©nario, chacun des nettoyeurs (vous y compris) serait un processeur, faisant sa partie du travail. -Et comme la plupart du temps d'exĂ©cution est pris par du "vrai" travail (et non de l'attente), et que le travail dans un ordinateur est fait par un CPU, ce sont des problĂšmes dits "CPU bound". +Et comme la plupart du temps d'exĂ©cution est pris par du « vrai » travail (et non de l'attente), et que le travail dans un ordinateur est fait par un CPU, ce sont des problĂšmes dits « CPU bound ». --- -Des exemples communs d'opĂ©rations "CPU bounds" sont les procĂ©dĂ©s qui requiĂšrent des traitements mathĂ©matiques complexes. +Des exemples communs d'opĂ©rations « CPU bound » sont les procĂ©dĂ©s qui requiĂšrent des traitements mathĂ©matiques complexes. Par exemple : @@ -289,19 +290,19 @@ Par exemple : * L'apprentissage automatique (ou **Machine Learning**) : cela nĂ©cessite de nombreuses multiplications de matrices et vecteurs. Imaginez une Ă©norme feuille de calcul remplie de nombres que vous multiplierez entre eux tous au mĂȘme moment. * L'apprentissage profond (ou **Deep Learning**) : est un sous-domaine du **Machine Learning**, donc les mĂȘmes raisons s'appliquent. Avec la diffĂ©rence qu'il n'y a pas une unique feuille de calcul de nombres Ă  multiplier, mais une Ă©norme quantitĂ© d'entre elles, et dans de nombreux cas, on utilise un processeur spĂ©cial pour construire et / ou utiliser ces modĂšles. -### Concurrence + ParallĂ©lisme : Web + Machine Learning +### Concurrence + ParallĂ©lisme : Web + Machine Learning { #concurrency-parallelism-web-machine-learning } Avec **FastAPI** vous pouvez bĂ©nĂ©ficier de la concurrence qui est trĂšs courante en dĂ©veloppement web (c'est l'attrait principal de NodeJS). -Mais vous pouvez aussi profiter du parallĂ©lisme et multiprocessing afin de gĂ©rer des charges **CPU bound** qui sont rĂ©currentes dans les systĂšmes de *Machine Learning*. +Mais vous pouvez aussi profiter du parallĂ©lisme et du multiprocessing (plusieurs processus s'exĂ©cutant en parallĂšle) afin de gĂ©rer des charges **CPU bound** qui sont rĂ©currentes dans les systĂšmes de *Machine Learning*. Ça, ajoutĂ© au fait que Python soit le langage le plus populaire pour la **Data Science**, le **Machine Learning** et surtout le **Deep Learning**, font de **FastAPI** un trĂšs bon choix pour les APIs et applications de **Data Science** / **Machine Learning**. Pour comprendre comment mettre en place ce parallĂ©lisme en production, allez lire la section [DĂ©ploiement](deployment/index.md){.internal-link target=_blank}. -## `async` et `await` +## `async` et `await` { #async-and-await } -Les versions modernes de Python ont une maniĂšre trĂšs intuitive de dĂ©finir le code asynchrone, tout en gardant une apparence de code "sĂ©quentiel" classique en laissant Python faire l'attente pour vous au bon moment. +Les versions modernes de Python ont une maniĂšre trĂšs intuitive de dĂ©finir le code asynchrone, tout en gardant une apparence de code « sĂ©quentiel » classique en laissant Python faire l'attente pour vous au bon moment. Pour une opĂ©ration qui nĂ©cessite de l'attente avant de donner un rĂ©sultat et qui supporte ces nouvelles fonctionnalitĂ©s Python, vous pouvez l'utiliser comme tel : @@ -319,12 +320,12 @@ async def get_burgers(number: int): return burgers ``` -...et non `def` : +... et non `def` : ```Python hl_lines="2" # Ceci n'est pas asynchrone def get_sequential_burgers(number: int): - # OpĂ©rations asynchrones pour crĂ©er les burgers + # OpĂ©rations sĂ©quentielles pour crĂ©er les burgers return burgers ``` @@ -339,7 +340,7 @@ burgers = get_burgers(2) --- -Donc, si vous utilisez une bibliothĂšque qui nĂ©cessite que ses fonctions soient appelĂ©es avec `await`, vous devez dĂ©finir la *fonction de chemin* en utilisant `async def` comme dans : +Donc, si vous utilisez une bibliothĂšque qui nĂ©cessite que ses fonctions soient appelĂ©es avec `await`, vous devez dĂ©finir la *fonction de chemin d'accĂšs* en utilisant `async def` comme dans : ```Python hl_lines="2-3" @app.get('/burgers') @@ -348,52 +349,61 @@ async def read_burgers(): return burgers ``` -### Plus de dĂ©tails techniques +### Plus de dĂ©tails techniques { #more-technical-details } Vous avez donc compris que `await` peut seulement ĂȘtre utilisĂ© dans des fonctions dĂ©finies avec `async def`. Mais en mĂȘme temps, les fonctions dĂ©finies avec `async def` doivent ĂȘtre appelĂ©es avec `await` et donc dans des fonctions dĂ©finies elles aussi avec `async def`. -Vous avez donc remarquĂ© ce paradoxe d'oeuf et de la poule, comment appelle-t-on la premiĂšre fonction `async` ? +Vous avez donc remarquĂ© ce paradoxe d'Ɠuf et de la poule, comment appelle-t-on la premiĂšre fonction `async` ? -Si vous utilisez **FastAPI**, pas besoin de vous en inquiĂ©ter, car cette "premiĂšre" fonction sera votre *fonction de chemin* ; et **FastAPI** saura comment arriver au rĂ©sultat attendu. +Si vous utilisez **FastAPI**, pas besoin de vous en inquiĂ©ter, car cette « premiĂšre » fonction sera votre *fonction de chemin d'accĂšs* ; et **FastAPI** saura comment arriver au rĂ©sultat attendu. -Mais si vous utilisez `async` / `await` sans **FastAPI**, allez jetez un coup d'oeil Ă  la documentation officielle de Python. +Mais si vous souhaitez utiliser `async` / `await` sans FastAPI, vous pouvez Ă©galement le faire. -### Autres formes de code asynchrone +### Écrire votre propre code async { #write-your-own-async-code } + +Starlette (et **FastAPI**) s’appuie sur AnyIO, ce qui le rend compatible Ă  la fois avec la bibliothĂšque standard asyncio de Python et avec Trio. + +En particulier, vous pouvez utiliser directement AnyIO pour vos cas d’usage de concurrence avancĂ©s qui nĂ©cessitent des schĂ©mas plus Ă©laborĂ©s dans votre propre code. + +Et mĂȘme si vous n’utilisiez pas FastAPI, vous pourriez aussi Ă©crire vos propres applications async avec AnyIO pour une grande compatibilitĂ© et pour bĂ©nĂ©ficier de ses avantages (par ex. la « structured concurrency »). + +J’ai créé une autre bibliothĂšque au-dessus d’AnyIO, comme une fine surcouche, pour amĂ©liorer un peu les annotations de type et obtenir une meilleure **autocomplĂ©tion**, des **erreurs en ligne**, etc. Elle propose Ă©galement une introduction et un tutoriel accessibles pour vous aider Ă  **comprendre** et Ă©crire **votre propre code async** : Asyncer. Elle sera particuliĂšrement utile si vous devez **combiner du code async avec du code classique** (bloquant/synchrone). + +### Autres formes de code asynchrone { #other-forms-of-asynchronous-code } L'utilisation d'`async` et `await` est relativement nouvelle dans ce langage. Mais cela rend la programmation asynchrone bien plus simple. -Cette mĂȘme syntaxe (ou presque) Ă©tait aussi incluse dans les versions modernes de Javascript (dans les versions navigateur et NodeJS). +Cette mĂȘme syntaxe (ou presque) a aussi Ă©tĂ© incluse rĂ©cemment dans les versions modernes de JavaScript (dans les navigateurs et NodeJS). Mais avant ça, gĂ©rer du code asynchrone Ă©tait bien plus complexe et difficile. -Dans les versions prĂ©cĂ©dentes de Python, vous auriez utilisĂ© des *threads* ou Gevent. Mais le code aurait Ă©tĂ© bien plus difficile Ă  comprendre, dĂ©bugger, et concevoir. +Dans les versions prĂ©cĂ©dentes de Python, vous auriez utilisĂ© des threads ou Gevent. Mais le code aurait Ă©tĂ© bien plus difficile Ă  comprendre, dĂ©bugger, et concevoir. -Dans les versions prĂ©cĂ©dentes de Javascript NodeJS / Navigateur, vous auriez utilisĂ© des "callbacks". Menant potentiellement Ă  ce que l'on appelle le "callback hell". +Dans les versions prĂ©cĂ©dentes de JavaScript cĂŽtĂ© navigateur / NodeJS, vous auriez utilisĂ© des « callbacks ». Menant potentiellement Ă  ce que l'on appelle le « callback hell ». +## Coroutines { #coroutines } -## Coroutines +« Coroutine » est juste un terme Ă©laborĂ© pour dĂ©signer ce qui est retournĂ© par une fonction dĂ©finie avec `async def`. Python sait que c'est comme une fonction classique qui va dĂ©marrer Ă  un moment et terminer Ă  un autre, mais qu'elle peut aussi ĂȘtre mise en pause ⏞, du moment qu'il y a un `await` dans son contenu. -**Coroutine** est juste un terme Ă©laborĂ© pour dĂ©signer ce qui est retournĂ© par une fonction dĂ©finie avec `async def`. Python sait que c'est comme une fonction classique qui va dĂ©marrer Ă  un moment et terminer Ă  un autre, mais qu'elle peut aussi ĂȘtre mise en pause ⏞, du moment qu'il y a un `await` dans son contenu. +Mais toutes ces fonctionnalitĂ©s d'utilisation de code asynchrone avec `async` et `await` sont souvent rĂ©sumĂ©es comme l'utilisation des « coroutines ». On peut comparer cela Ă  la principale fonctionnalitĂ© clĂ© de Go, les « Goroutines ». -Mais toutes ces fonctionnalitĂ©s d'utilisation de code asynchrone avec `async` et `await` sont souvent rĂ©sumĂ©es comme l'utilisation des *coroutines*. On peut comparer cela Ă  la principale fonctionnalitĂ© clĂ© de Go, les "Goroutines". - -## Conclusion +## Conclusion { #conclusion } Reprenons la phrase du dĂ©but de la page : -> Les versions modernes de Python supportent le **code asynchrone** grĂące aux **"coroutines"** avec les syntaxes **`async` et `await`**. +> Les versions modernes de Python supportent le **code asynchrone** grĂące aux **« coroutines »** avec les syntaxes **`async` et `await`**. Ceci devrait ĂȘtre plus comprĂ©hensible dĂ©sormais. ✹ -Tout ceci est donc ce qui donne sa force Ă  **FastAPI** (Ă  travers Starlette) et lui permet d'avoir des performances aussi impressionnantes. +Tout ceci est donc ce qui donne sa force Ă  FastAPI (Ă  travers Starlette) et lui permet d'avoir une performance aussi impressionnante. -## DĂ©tails trĂšs techniques +## DĂ©tails trĂšs techniques { #very-technical-details } -/// warning | Attention ! +/// warning | Alertes Vous pouvez probablement ignorer cela. @@ -403,32 +413,32 @@ Si vous avez de bonnes connaissances techniques (coroutines, threads, code bloqu /// -### Fonctions de chemin +### Fonctions de chemin d'accĂšs { #path-operation-functions } -Quand vous dĂ©clarez une *fonction de chemin* avec un `def` normal et non `async def`, elle est exĂ©cutĂ©e dans un groupe de threads (threadpool) externe qui est ensuite attendu, plutĂŽt que d'ĂȘtre appelĂ©e directement (car cela bloquerait le serveur). +Quand vous dĂ©clarez une *fonction de chemin d'accĂšs* avec un `def` normal et non `async def`, elle est exĂ©cutĂ©e dans un groupe de threads (threadpool) externe qui est ensuite attendu, plutĂŽt que d'ĂȘtre appelĂ©e directement (car cela bloquerait le serveur). -Si vous venez d'un autre framework asynchrone qui ne fonctionne pas comme de la façon dĂ©crite ci-dessus et que vous ĂȘtes habituĂ©s Ă  dĂ©finir des *fonctions de chemin* basiques avec un simple `def` pour un faible gain de performance (environ 100 nanosecondes), veuillez noter que dans **FastAPI**, l'effet serait plutĂŽt contraire. Dans ces cas-lĂ , il vaut mieux utiliser `async def` Ă  moins que votre *fonction de chemin* utilise du code qui effectue des opĂ©rations I/O bloquantes. +Si vous venez d'un autre framework asynchrone qui ne fonctionne pas comme de la façon dĂ©crite ci-dessus et que vous ĂȘtes habituĂ© Ă  dĂ©finir des *fonctions de chemin d'accĂšs* basiques et purement calculatoires avec un simple `def` pour un faible gain de performance (environ 100 nanosecondes), veuillez noter que dans **FastAPI**, l'effet serait plutĂŽt contraire. Dans ces cas-lĂ , il vaut mieux utiliser `async def` Ă  moins que votre *fonction de chemin d'accĂšs* utilise du code qui effectue des opĂ©rations I/O bloquantes. Au final, dans les deux situations, il est fort probable que **FastAPI** soit tout de mĂȘme [plus rapide](index.md#performance){.internal-link target=_blank} que (ou au moins de vitesse Ă©gale Ă ) votre framework prĂ©cĂ©dent. -### DĂ©pendances +### DĂ©pendances { #dependencies } -La mĂȘme chose s'applique aux dĂ©pendances. Si une dĂ©pendance est dĂ©finie avec `def` plutĂŽt que `async def`, elle est exĂ©cutĂ©e dans la threadpool externe. +La mĂȘme chose s'applique aux [dĂ©pendances](tutorial/dependencies/index.md){.internal-link target=_blank}. Si une dĂ©pendance est dĂ©finie avec `def` plutĂŽt que `async def`, elle est exĂ©cutĂ©e dans la threadpool externe. -### Sous-dĂ©pendances +### Sous-dĂ©pendances { #sub-dependencies } -Vous pouvez avoir de multiples dĂ©pendances et sous-dĂ©pendances dĂ©pendant les unes des autres (en tant que paramĂštres de la dĂ©finition de la *fonction de chemin*), certaines créées avec `async def` et d'autres avec `def`. Cela fonctionnerait aussi, et celles dĂ©finies avec un simple `def` seraient exĂ©cutĂ©es sur un thread externe (venant de la threadpool) plutĂŽt que d'ĂȘtre "attendues". +Vous pouvez avoir de multiples dĂ©pendances et [sous-dĂ©pendances](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} dĂ©pendant les unes des autres (en tant que paramĂštres de la dĂ©finition de la *fonction de chemin d'accĂšs*), certaines créées avec `async def` et d'autres avec `def`. Cela fonctionnerait aussi, et celles dĂ©finies avec un simple `def` seraient exĂ©cutĂ©es sur un thread externe (venant de la threadpool) plutĂŽt que d'ĂȘtre « attendues ». -### Autres fonctions utilitaires +### Autres fonctions utilitaires { #other-utility-functions } -Toute autre fonction utilitaire que vous appelez directement peut ĂȘtre créée avec un classique `def` ou avec `async def` et **FastAPI** n'aura pas d'impact sur la façon dont vous l'appelez. +Toute autre fonction utilitaire que vous appelez directement peut ĂȘtre créée avec un classique `def` ou avec `async def` et FastAPI n'aura pas d'impact sur la façon dont vous l'appelez. -Contrairement aux fonctions que **FastAPI** appelle pour vous : les *fonctions de chemin* et dĂ©pendances. +Contrairement aux fonctions que FastAPI appelle pour vous : les *fonctions de chemin d'accĂšs* et dĂ©pendances. -Si votre fonction utilitaire est une fonction classique dĂ©finie avec `def`, elle sera appelĂ©e directement (telle qu'Ă©crite dans votre code), pas dans une threadpool, si la fonction est dĂ©finie avec `async def` alors vous devrez attendre (avec `await`) que cette fonction se termine avant de passer Ă  la suite du code. +Si votre fonction utilitaire est une fonction classique dĂ©finie avec `def`, elle sera appelĂ©e directement (telle qu'Ă©crite dans votre code), pas dans une threadpool ; si la fonction est dĂ©finie avec `async def` alors vous devrez attendre (avec `await`) que cette fonction se termine avant de passer Ă  la suite du code. --- Encore une fois, ce sont des dĂ©tails trĂšs techniques qui peuvent ĂȘtre utiles si vous venez ici les chercher. -Sinon, les instructions de la section Vous ĂȘtes pressĂ©s ? ci-dessus sont largement suffisantes. +Sinon, les instructions de la section Vous ĂȘtes pressĂ©s ? ci-dessus sont largement suffisantes. diff --git a/docs/fr/docs/deployment/cloud.md b/docs/fr/docs/deployment/cloud.md new file mode 100644 index 000000000..798a72a74 --- /dev/null +++ b/docs/fr/docs/deployment/cloud.md @@ -0,0 +1,24 @@ +# DĂ©ployer FastAPI sur des fournisseurs cloud { #deploy-fastapi-on-cloud-providers } + +Vous pouvez utiliser pratiquement n'importe quel fournisseur cloud pour dĂ©ployer votre application FastAPI. + +Dans la plupart des cas, les principaux fournisseurs cloud proposent des guides pour dĂ©ployer FastAPI avec leurs services. + +## FastAPI Cloud { #fastapi-cloud } + +**FastAPI Cloud** est créée par le mĂȘme auteur et l'Ă©quipe Ă  l'origine de **FastAPI**. + +Elle simplifie le processus de **crĂ©ation**, de **dĂ©ploiement** et **d'accĂšs** Ă  une API avec un effort minimal. + +Elle apporte la mĂȘme **expĂ©rience dĂ©veloppeur** que celle de la crĂ©ation d'applications avec FastAPI au **dĂ©ploiement** de celles-ci dans le cloud. 🎉 + +FastAPI Cloud est le sponsor principal et le financeur des projets open source *FastAPI and friends*. ✹ + +## Fournisseurs cloud - Sponsors { #cloud-providers-sponsors } + +D'autres fournisseurs cloud ✹ [**parrainent FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✹ Ă©galement. 🙇 + +Vous pouvez Ă©galement envisager ces fournisseurs pour suivre leurs guides et essayer leurs services : + +* Render +* Railway diff --git a/docs/fr/docs/deployment/concepts.md b/docs/fr/docs/deployment/concepts.md new file mode 100644 index 000000000..59b8ddd1b --- /dev/null +++ b/docs/fr/docs/deployment/concepts.md @@ -0,0 +1,321 @@ +# Concepts de dĂ©ploiement { #deployments-concepts } + +Lorsque vous dĂ©ployez une application **FastAPI**, ou en fait n'importe quel type de web API, il existe plusieurs concepts qui vous importent probablement, et en les utilisant vous pouvez trouver la maniĂšre la **plus appropriĂ©e** de **dĂ©ployer votre application**. + +Parmi les concepts importants, on trouve : + +* SĂ©curitĂ© - HTTPS +* ExĂ©cuter 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 + +Nous allons voir comment ils affectent les **dĂ©ploiements**. + +Au final, l'objectif ultime est de pouvoir **servir vos clients d'API** de maniĂšre **sĂ©curisĂ©e**, d'**Ă©viter les interruptions**, et d'utiliser les **ressources de calcul** (par exemple des serveurs/VM distants) aussi efficacement que possible. 🚀 + +Je vais vous en dire un peu plus ici sur ces **concepts**, ce qui devrait vous donner l'**intuition** nĂ©cessaire pour dĂ©cider comment dĂ©ployer votre API dans des environnements trĂšs diffĂ©rents, voire mĂȘme dans des environnements **futurs** qui n'existent pas encore. + +En tenant compte de ces concepts, vous serez en mesure **d'Ă©valuer et de concevoir** la meilleure façon de dĂ©ployer **vos propres API**. + +Dans les chapitres suivants, je vous donnerai des **recettes concrĂštes** pour dĂ©ployer des applications FastAPI. + +Mais pour l'instant, voyons ces **idĂ©es conceptuelles** importantes. Ces concepts s'appliquent aussi Ă  tout autre type de web API. 💡 + +## SĂ©curitĂ© - HTTPS { #security-https } + +Dans le [chapitre prĂ©cĂ©dent Ă  propos de HTTPS](https.md){.internal-link target=_blank}, nous avons vu comment HTTPS fournit le chiffrement pour votre API. + +Nous avons Ă©galement vu que HTTPS est normalement fourni par un composant **externe** Ă  votre serveur d'application, un **TLS Termination Proxy**. + +Et il doit y avoir quelque chose chargĂ© de **renouveler les certificats HTTPS** ; cela peut ĂȘtre le mĂȘme composant ou quelque chose de diffĂ©rent. + +### Exemples d’outils pour HTTPS { #example-tools-for-https } + +Parmi les outils que vous pourriez utiliser comme TLS Termination Proxy : + +* Traefik + * GĂšre automatiquement le renouvellement des certificats ✹ +* Caddy + * GĂšre automatiquement le renouvellement des certificats ✹ +* Nginx + * Avec un composant externe comme Certbot pour le renouvellement des certificats +* HAProxy + * Avec un composant externe comme Certbot pour le renouvellement des certificats +* Kubernetes avec un Ingress Controller comme Nginx + * Avec un composant externe comme cert-manager pour le renouvellement des certificats +* Pris en charge en interne par un fournisseur cloud dans le cadre de ses services (lisez ci-dessous 👇) + +Une autre option consiste Ă  utiliser un **service cloud** qui fait davantage de travail, y compris la mise en place de HTTPS. Il peut avoir certaines restrictions ou vous facturer davantage, etc. Mais dans ce cas, vous n'auriez pas Ă  configurer vous‑mĂȘme un TLS Termination Proxy. + +Je vous montrerai des exemples concrets dans les prochains chapitres. + +--- + +Les concepts suivants Ă  considĂ©rer concernent tous le programme qui exĂ©cute votre API rĂ©elle (par ex. Uvicorn). + +## Programme et processus { #program-and-process } + +Nous allons beaucoup parler du « **processus** » en cours d'exĂ©cution, il est donc utile d'ĂȘtre clair sur ce que cela signifie, et sur la diffĂ©rence avec le mot « **programme** ». + +### Qu'est-ce qu'un programme { #what-is-a-program } + +Le mot **programme** est couramment utilisĂ© pour dĂ©crire plusieurs choses : + +* Le **code** que vous Ă©crivez, les **fichiers Python**. +* Le **fichier** qui peut ĂȘtre **exĂ©cutĂ©** par le systĂšme d'exploitation, par exemple : `python`, `python.exe` ou `uvicorn`. +* Un programme particulier lorsqu'il **s'exĂ©cute** sur le systĂšme d'exploitation, utilisant le CPU et stockant des choses en mĂ©moire. On appelle aussi cela un **processus**. + +### Qu'est-ce qu'un processus { #what-is-a-process } + +Le mot **processus** est normalement utilisĂ© de maniĂšre plus spĂ©cifique, en ne se rĂ©fĂ©rant qu'Ă  l'Ă©lĂ©ment qui s'exĂ©cute dans le systĂšme d'exploitation (comme dans le dernier point ci‑dessus) : + +* Un programme particulier lorsqu'il **s'exĂ©cute** sur le systĂšme d'exploitation. + * Cela ne se rĂ©fĂšre ni au fichier, ni au code ; cela se rĂ©fĂšre **spĂ©cifiquement** Ă  l'Ă©lĂ©ment qui est **exĂ©cutĂ©** et gĂ©rĂ© par le systĂšme d'exploitation. +* N'importe quel programme, n'importe quel code, **ne peut faire des choses** que lorsqu'il est **exĂ©cutĂ©**. Donc, lorsqu'il y a un **processus en cours**. +* Le processus peut ĂȘtre **arrĂȘtĂ©** (ou « tuĂ© ») par vous ou par le systĂšme d'exploitation. À ce moment‑lĂ , il cesse de s'exĂ©cuter/d'ĂȘtre exĂ©cutĂ©, et il **ne peut plus rien faire**. +* Chaque application que vous avez en cours d'exĂ©cution sur votre ordinateur a un processus derriĂšre elle, chaque programme lancĂ©, chaque fenĂȘtre, etc. Et il y a normalement de nombreux processus exĂ©cutĂ©s **en mĂȘme temps** tant qu'un ordinateur est allumĂ©. +* Il peut y avoir **plusieurs processus** du **mĂȘme programme** exĂ©cutĂ©s simultanĂ©ment. + +Si vous ouvrez le « gestionnaire des tĂąches » ou le « moniteur systĂšme » (ou des outils similaires) de votre systĂšme d'exploitation, vous verrez nombre de ces processus en cours d'exĂ©cution. + +Et, par exemple, vous verrez probablement qu'il y a plusieurs processus exĂ©cutant le mĂȘme navigateur (Firefox, Chrome, Edge, etc.). Ils exĂ©cutent normalement un processus par onglet, plus quelques processus supplĂ©mentaires. + + + +--- + +Maintenant que nous connaissons la diffĂ©rence entre les termes **processus** et **programme**, continuons Ă  parler des dĂ©ploiements. + +## ExĂ©cuter au dĂ©marrage { #running-on-startup } + +Dans la plupart des cas, lorsque vous crĂ©ez une web API, vous voulez qu'elle **tourne en permanence**, sans interruption, afin que vos clients puissent toujours y accĂ©der. Bien sĂ»r, sauf si vous avez une raison spĂ©cifique de ne vouloir l'exĂ©cuter que dans certaines situations, mais la plupart du temps vous la voulez constamment en cours et **disponible**. + +### Sur un serveur distant { #in-a-remote-server } + +Lorsque vous configurez un serveur distant (un serveur cloud, une machine virtuelle, etc.), la chose la plus simple Ă  faire est d'utiliser `fastapi run` (qui utilise Uvicorn) ou quelque chose de similaire, manuellement, de la mĂȘme maniĂšre que lorsque vous dĂ©veloppez en local. + +Et cela fonctionnera et sera utile **pendant le dĂ©veloppement**. + +Mais si votre connexion au serveur est coupĂ©e, le **processus en cours** va probablement s'arrĂȘter. + +Et si le serveur est redĂ©marrĂ© (par exemple aprĂšs des mises Ă  jour, ou des migrations chez le fournisseur cloud) vous **ne le remarquerez probablement pas**. Et Ă  cause de cela, vous ne saurez mĂȘme pas que vous devez redĂ©marrer le processus manuellement. Ainsi, votre API restera tout simplement Ă  l'arrĂȘt. đŸ˜± + +### Lancer automatiquement au dĂ©marrage { #run-automatically-on-startup } + +En gĂ©nĂ©ral, vous voudrez probablement que le programme serveur (par ex. Uvicorn) soit dĂ©marrĂ© automatiquement au dĂ©marrage du serveur, et sans aucune **intervention humaine**, afin d'avoir en permanence un processus exĂ©cutant votre API (par ex. Uvicorn exĂ©cutant votre app FastAPI). + +### Programme sĂ©parĂ© { #separate-program } + +Pour y parvenir, vous aurez normalement un **programme sĂ©parĂ©** qui s'assure que votre application est lancĂ©e au dĂ©marrage. Et dans de nombreux cas, il s'assurera Ă©galement que d'autres composants ou applications sont Ă©galement lancĂ©s, par exemple une base de donnĂ©es. + +### Exemples d’outils pour lancer au dĂ©marrage { #example-tools-to-run-at-startup } + +Voici quelques exemples d'outils capables de faire ce travail : + +* Docker +* Kubernetes +* Docker Compose +* Docker en mode Swarm +* Systemd +* Supervisor +* Pris en charge en interne par un fournisseur cloud dans le cadre de ses services +* Autres ... + +Je vous donnerai des exemples plus concrets dans les prochains chapitres. + +## RedĂ©marrages { #restarts } + +De la mĂȘme maniĂšre que vous voulez vous assurer que votre application est lancĂ©e au dĂ©marrage, vous voulez probablement aussi vous assurer qu'elle est **redĂ©marrĂ©e** aprĂšs des Ă©checs. + +### Nous faisons des erreurs { #we-make-mistakes } + +Nous, humains, faisons des **erreurs**, tout le temps. Les logiciels ont presque *toujours* des **bugs** cachĂ©s Ă  diffĂ©rents endroits. 🐛 + +Et nous, dĂ©veloppeurs, continuons Ă  amĂ©liorer le code au fur et Ă  mesure que nous trouvons ces bugs et que nous implĂ©mentons de nouvelles fonctionnalitĂ©s (en ajoutant Ă©ventuellement de nouveaux bugs aussi 😅). + +### Petites erreurs gĂ©rĂ©es automatiquement { #small-errors-automatically-handled } + +Lors de la crĂ©ation de web API avec FastAPI, s'il y a une erreur dans notre code, FastAPI la contiendra normalement Ă  la seule requĂȘte qui a dĂ©clenchĂ© l'erreur. 🛡 + +Le client recevra un **500 Internal Server Error** pour cette requĂȘte, mais l'application continuera de fonctionner pour les requĂȘtes suivantes au lieu de simplement s'effondrer complĂštement. + +### Erreurs plus importantes - plantages { #bigger-errors-crashes } + +NĂ©anmoins, il peut y avoir des cas oĂč nous Ă©crivons du code qui **fait planter l'application entiĂšre**, faisant planter Uvicorn et Python. đŸ’„ + +Et malgrĂ© cela, vous ne voudrez probablement pas que l'application reste Ă  l'arrĂȘt parce qu'il y a eu une erreur Ă  un endroit ; vous voudrez probablement qu'elle **continue de tourner**, au moins pour les *chemins d'accĂšs* qui ne sont pas cassĂ©s. + +### RedĂ©marrer aprĂšs un plantage { #restart-after-crash } + +Mais dans ces cas avec de trĂšs mauvaises erreurs qui font planter le **processus** en cours, vous voudrez un composant externe chargĂ© de **redĂ©marrer** le processus, au moins quelques fois ... + +/// tip | Astuce + +... Bien que si l'application entiĂšre **plante immĂ©diatement**, il n'est probablement pas logique de continuer Ă  la redĂ©marrer indĂ©finiment. Mais dans ces cas, vous le remarquerez probablement pendant le dĂ©veloppement, ou au moins juste aprĂšs le dĂ©ploiement. + +Concentrons‑nous donc sur les cas principaux, oĂč elle pourrait planter entiĂšrement dans certaines situations particuliĂšres **Ă  l'avenir**, et oĂč il est toujours logique de la redĂ©marrer. + +/// + +Vous voudrez probablement que l'Ă©lĂ©ment chargĂ© de redĂ©marrer votre application soit un **composant externe**, car Ă  ce stade, l'application elle‑mĂȘme avec Uvicorn et Python a dĂ©jĂ  plantĂ©, donc il n'y a rien dans le mĂȘme code de la mĂȘme app qui pourrait y faire quoi que ce soit. + +### Exemples d’outils pour redĂ©marrer automatiquement { #example-tools-to-restart-automatically } + +Dans la plupart des cas, le mĂȘme outil qui est utilisĂ© pour **lancer le programme au dĂ©marrage** est Ă©galement utilisĂ© pour gĂ©rer les **redĂ©marrages** automatiques. + +Par exemple, cela peut ĂȘtre gĂ©rĂ© par : + +* Docker +* Kubernetes +* Docker Compose +* Docker en mode Swarm +* Systemd +* Supervisor +* Pris en charge en interne par un fournisseur cloud dans le cadre de ses services +* Autres ... + +## RĂ©plication - Processus et mĂ©moire { #replication-processes-and-memory } + +Avec une application FastAPI, en utilisant un programme serveur comme la commande `fastapi` qui exĂ©cute Uvicorn, l'exĂ©cuter une fois dans **un processus** peut servir plusieurs clients simultanĂ©ment. + +Mais dans de nombreux cas, vous voudrez exĂ©cuter plusieurs processus de travail en mĂȘme temps. + +### Multiples processus - Workers { #multiple-processes-workers } + +Si vous avez plus de clients que ce qu'un seul processus peut gĂ©rer (par exemple si la machine virtuelle n'est pas trĂšs grande) et que vous avez **plusieurs cƓurs** dans le CPU du serveur, alors vous pouvez avoir **plusieurs processus** exĂ©cutant la mĂȘme application simultanĂ©ment, et distribuer toutes les requĂȘtes entre eux. + +Quand vous exĂ©cutez **plusieurs processus** du mĂȘme programme d'API, on les appelle couramment des **workers**. + +### Processus workers et ports { #worker-processes-and-ports } + +Rappelez‑vous, d'aprĂšs les documents [À propos de HTTPS](https.md){.internal-link target=_blank}, qu'un seul processus peut Ă©couter une combinaison de port et d'adresse IP sur un serveur ? + +C'est toujours vrai. + +Donc, pour pouvoir avoir **plusieurs processus** en mĂȘme temps, il doit y avoir un **seul processus Ă  l'Ă©coute sur un port** qui transmet ensuite la communication Ă  chaque processus worker d'une maniĂšre ou d'une autre. + +### MĂ©moire par processus { #memory-per-process } + +Maintenant, lorsque le programme charge des choses en mĂ©moire, par exemple, un modĂšle de machine learning dans une variable, ou le contenu d'un gros fichier dans une variable, tout cela **consomme une partie de la mĂ©moire (RAM)** du serveur. + +Et plusieurs processus **ne partagent normalement pas de mĂ©moire**. Cela signifie que chaque processus en cours a ses propres Ă©lĂ©ments, variables et mĂ©moire. Et si vous consommez une grande quantitĂ© de mĂ©moire dans votre code, **chaque processus** consommera une quantitĂ© Ă©quivalente de mĂ©moire. + +### MĂ©moire du serveur { #server-memory } + +Par exemple, si votre code charge un modĂšle de Machine Learning de **1 Go**, lorsque vous exĂ©cutez un processus avec votre API, il consommera au moins 1 Go de RAM. Et si vous dĂ©marrez **4 processus** (4 workers), chacun consommera 1 Go de RAM. Donc au total, votre API consommera **4 Go de RAM**. + +Et si votre serveur distant ou votre machine virtuelle n'a que 3 Go de RAM, essayer de charger plus de 4 Go de RAM posera problĂšme. 🚹 + +### Multiples processus - Un exemple { #multiple-processes-an-example } + +Dans cet exemple, il y a un **processus gestionnaire** qui dĂ©marre et contrĂŽle deux **processus workers**. + +Ce processus gestionnaire serait probablement celui qui Ă©coute sur le **port** de l'IP. Et il transmettrait toute la communication aux processus workers. + +Ces processus workers seraient ceux qui exĂ©cutent votre application, ils effectueraient les calculs principaux pour recevoir une **requĂȘte** et renvoyer une **rĂ©ponse**, et ils chargeraient tout ce que vous mettez dans des variables en RAM. + + + +Et bien sĂ»r, la mĂȘme machine aurait probablement **d'autres processus** en cours d'exĂ©cution Ă©galement, en plus de votre application. + +Un dĂ©tail intĂ©ressant est que le pourcentage de **CPU utilisĂ©** par chaque processus peut **varier** fortement dans le temps, mais la **mĂ©moire (RAM)** reste normalement plus ou moins **stable**. + +Si vous avez une API qui effectue une quantitĂ© comparable de calculs Ă  chaque fois et que vous avez beaucoup de clients, alors l'**utilisation du CPU** sera probablement *Ă©galement stable* (au lieu de monter et descendre rapidement en permanence). + +### Exemples d’outils et de stratĂ©gies de rĂ©plication { #examples-of-replication-tools-and-strategies } + +Il peut y avoir plusieurs approches pour y parvenir, et je vous en dirai plus sur des stratĂ©gies spĂ©cifiques dans les prochains chapitres, par exemple en parlant de Docker et des conteneurs. + +La principale contrainte Ă  considĂ©rer est qu'il doit y avoir un **seul** composant gĂ©rant le **port** sur l'**IP publique**. Et il doit ensuite avoir un moyen de **transmettre** la communication aux **processus/workers** rĂ©pliquĂ©s. + +Voici quelques combinaisons et stratĂ©gies possibles : + +* **Uvicorn** avec `--workers` + * Un **gestionnaire de processus** Uvicorn Ă©couterait sur l'**IP** et le **port**, et il dĂ©marrerait **plusieurs processus workers Uvicorn**. +* **Kubernetes** et autres systĂšmes **de conteneurs** distribuĂ©s + * Quelque chose dans la couche **Kubernetes** Ă©couterait sur l'**IP** et le **port**. La rĂ©plication se ferait en ayant **plusieurs conteneurs**, chacun avec **un processus Uvicorn** en cours. +* **Services cloud** qui s'en chargent pour vous + * Le service cloud **gĂ©rera probablement la rĂ©plication pour vous**. Il vous permettra Ă©ventuellement de dĂ©finir **un processus Ă  exĂ©cuter**, ou une **image de conteneur** Ă  utiliser ; dans tous les cas, ce sera trĂšs probablement **un seul processus Uvicorn**, et le service cloud sera chargĂ© de le rĂ©pliquer. + +/// tip | Astuce + +Ne vous inquiĂ©tez pas si certains de ces Ă©lĂ©ments concernant les **conteneurs**, Docker ou Kubernetes ne sont pas encore trĂšs clairs. + +Je vous en dirai plus sur les images de conteneurs, Docker, Kubernetes, etc. dans un chapitre Ă  venir : [FastAPI dans des conteneurs - Docker](docker.md){.internal-link target=_blank}. + +/// + +## Étapes prĂ©alables avant de dĂ©marrer { #previous-steps-before-starting } + +Il existe de nombreux cas oĂč vous souhaitez effectuer certaines Ă©tapes **avant de dĂ©marrer** votre application. + +Par exemple, vous pourriez vouloir exĂ©cuter des **migrations de base de donnĂ©es**. + +Mais dans la plupart des cas, vous voudrez effectuer ces Ă©tapes **une seule fois**. + +Vous voudrez donc avoir un **processus unique** pour effectuer ces **Ă©tapes prĂ©alables**, avant de dĂ©marrer l'application. + +Et vous devez vous assurer que c'est un processus unique qui exĂ©cute ces Ă©tapes prĂ©alables *mĂȘme si*, ensuite, vous dĂ©marrez **plusieurs processus** (plusieurs workers) pour l'application elle‑mĂȘme. Si ces Ă©tapes Ă©taient exĂ©cutĂ©es par **plusieurs processus**, ils **dupliqueraient** le travail en l'exĂ©cutant **en parallĂšle**, et si les Ă©tapes Ă©taient dĂ©licates comme une migration de base de donnĂ©es, elles pourraient entrer en conflit les unes avec les autres. + +Bien sĂ»r, il y a des cas oĂč il n'y a aucun problĂšme Ă  exĂ©cuter les Ă©tapes prĂ©alables plusieurs fois ; dans ce cas, c'est beaucoup plus simple Ă  gĂ©rer. + +/// tip | Astuce + +Gardez aussi Ă  l'esprit que selon votre configuration, dans certains cas vous **n'aurez peut‑ĂȘtre mĂȘme pas besoin d'Ă©tapes prĂ©alables** avant de dĂ©marrer votre application. + +Dans ce cas, vous n'auriez pas Ă  vous soucier de tout cela. đŸ€· + +/// + +### Exemples de stratĂ©gies pour les Ă©tapes prĂ©alables { #examples-of-previous-steps-strategies } + +Cela **dĂ©pendra fortement** de la maniĂšre dont vous **dĂ©ployez votre systĂšme**, et sera probablement liĂ© Ă  votre maniĂšre de dĂ©marrer les programmes, de gĂ©rer les redĂ©marrages, etc. + +Voici quelques idĂ©es possibles : + +* Un « Init Container » dans Kubernetes qui s'exĂ©cute avant votre conteneur d'application +* Un script bash qui exĂ©cute les Ă©tapes prĂ©alables puis dĂ©marre votre application + * Vous aurez toujours besoin d'un moyen de dĂ©marrer/redĂ©marrer *ce* script bash, de dĂ©tecter les erreurs, etc. + +/// tip | Astuce + +Je vous donnerai des exemples plus concrets pour faire cela avec des conteneurs dans un chapitre Ă  venir : [FastAPI dans des conteneurs - Docker](docker.md){.internal-link target=_blank}. + +/// + +## Utilisation des ressources { #resource-utilization } + +Votre ou vos serveurs constituent une **ressource** que vos programmes peuvent consommer ou **utiliser** : le temps de calcul des CPU et la mĂ©moire RAM disponible. + +Quelle quantitĂ© des ressources systĂšme voulez‑vous consommer/utiliser ? Il peut ĂȘtre facile de penser « pas beaucoup », mais en rĂ©alitĂ©, vous voudrez probablement consommer **le plus possible sans planter**. + +Si vous payez pour 3 serveurs mais que vous n'utilisez qu'un petit peu de leur RAM et CPU, vous **gaspillez probablement de l'argent** 💾, et **gaspillez probablement l'Ă©lectricitĂ© des serveurs** 🌎, etc. + +Dans ce cas, il pourrait ĂȘtre prĂ©fĂ©rable de n'avoir que 2 serveurs et d'utiliser un pourcentage plus Ă©levĂ© de leurs ressources (CPU, mĂ©moire, disque, bande passante rĂ©seau, etc.). + +À l'inverse, si vous avez 2 serveurs et que vous utilisez **100 % de leur CPU et de leur RAM**, Ă  un moment donnĂ© un processus demandera plus de mĂ©moire, et le serveur devra utiliser le disque comme « mĂ©moire » (ce qui peut ĂȘtre des milliers de fois plus lent), voire **planter**. Ou un processus pourrait avoir besoin de faire un calcul et devrait attendre que le CPU soit Ă  nouveau libre. + +Dans ce cas, il serait prĂ©fĂ©rable d'obtenir **un serveur supplĂ©mentaire** et d'y exĂ©cuter certains processus afin qu'ils aient tous **suffisamment de RAM et de temps CPU**. + +Il est Ă©galement possible que, pour une raison quelconque, vous ayez un **pic** d'utilisation de votre API. Peut‑ĂȘtre qu'elle devient virale, ou peut‑ĂȘtre que d'autres services ou bots commencent Ă  l'utiliser. Et vous voudrez peut‑ĂȘtre disposer de ressources supplĂ©mentaires pour ĂȘtre en sĂ©curitĂ© dans ces cas. + +Vous pouvez dĂ©finir un **chiffre arbitraire** comme cible, par exemple **entre 50 % et 90 %** d'utilisation des ressources. L'idĂ©e est que ce sont probablement les principaux Ă©lĂ©ments que vous voudrez mesurer et utiliser pour ajuster vos dĂ©ploiements. + +Vous pouvez utiliser des outils simples comme `htop` pour voir le CPU et la RAM utilisĂ©s sur votre serveur ou la quantitĂ© utilisĂ©e par chaque processus. Ou vous pouvez utiliser des outils de supervision plus complexes, Ă©ventuellement distribuĂ©s sur plusieurs serveurs, etc. + +## RĂ©capitulatif { #recap } + +Vous venez de lire ici certains des principaux concepts que vous devrez probablement garder Ă  l'esprit lorsque vous dĂ©cidez comment dĂ©ployer votre application : + +* SĂ©curitĂ© - HTTPS +* ExĂ©cuter 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 + +Comprendre ces idĂ©es et comment les appliquer devrait vous donner l'intuition nĂ©cessaire pour prendre toutes les dĂ©cisions lors de la configuration et de l'ajustement de vos dĂ©ploiements. đŸ€“ + +Dans les sections suivantes, je vous donnerai des exemples plus concrets de stratĂ©gies possibles Ă  suivre. 🚀 diff --git a/docs/fr/docs/deployment/docker.md b/docs/fr/docs/deployment/docker.md index ec30f9607..2d86d4a40 100644 --- a/docs/fr/docs/deployment/docker.md +++ b/docs/fr/docs/deployment/docker.md @@ -14,7 +14,7 @@ Vous ĂȘtes pressĂ© et vous connaissez dĂ©jĂ  tout ça ? Allez directement au [`D Aperçu du Dockerfile 👀 ```Dockerfile -FROM python:3.9 +FROM python:3.14 WORKDIR /code @@ -166,7 +166,7 @@ Maintenant, dans le mĂȘme rĂ©pertoire de projet, crĂ©ez un fichier `Dockerfile` ```{ .dockerfile .annotate } # (1)! -FROM python:3.9 +FROM python:3.14 # (2)! WORKDIR /code @@ -390,7 +390,7 @@ Si votre FastAPI est un seul fichier, par exemple `main.py` sans rĂ©pertoire `./ Vous n'auriez alors qu'Ă  changer les chemins correspondants pour copier le fichier dans le `Dockerfile` : ```{ .dockerfile .annotate hl_lines="10 13" } -FROM python:3.9 +FROM python:3.14 WORKDIR /code @@ -454,7 +454,7 @@ Sans utiliser de conteneurs, faire en sorte que les applications s'exĂ©cutent au ## RĂ©plication - Nombre de processus { #replication-number-of-processes } -Si vous avez un cluster 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** plutĂŽt que d'utiliser un **gestionnaire de processus** (comme Uvicorn avec workers) dans chaque conteneur. +Si vous avez un cluster 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** plutĂŽt que d'utiliser un **gestionnaire de processus** (comme Uvicorn avec workers) dans chaque conteneur. L'un de ces systĂšmes de gestion de conteneurs distribuĂ©s comme Kubernetes dispose normalement d'une maniĂšre intĂ©grĂ©e de gĂ©rer la **rĂ©plication des conteneurs** tout en supportant l'**Ă©quilibrage de charge** des requĂȘtes entrantes. Le tout au **niveau du cluster**. @@ -499,7 +499,7 @@ Bien sĂ»r, il existe des **cas particuliers** oĂč vous pourriez vouloir avoir ** Dans ces cas, vous pouvez utiliser l'option de ligne de commande `--workers` pour dĂ©finir le nombre de workers que vous souhaitez exĂ©cuter : ```{ .dockerfile .annotate } -FROM python:3.9 +FROM python:3.14 WORKDIR /code diff --git a/docs/fr/docs/deployment/fastapicloud.md b/docs/fr/docs/deployment/fastapicloud.md new file mode 100644 index 000000000..72f275cf6 --- /dev/null +++ b/docs/fr/docs/deployment/fastapicloud.md @@ -0,0 +1,65 @@ +# FastAPI Cloud { #fastapi-cloud } + +Vous pouvez dĂ©ployer votre application FastAPI sur FastAPI Cloud avec une **seule commande**, allez vous inscrire sur la liste d’attente si ce n’est pas dĂ©jĂ  fait. 🚀 + +## Se connecter { #login } + +Vous devez vous assurer que vous avez dĂ©jĂ  un compte **FastAPI Cloud** (nous vous avons invitĂ© depuis la liste d’attente 😉). + +Connectez-vous ensuite : + +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
+ +## Déployer { #deploy } + +Déployez maintenant votre application, avec une **seule commande** : + +
+ +```console +$ fastapi deploy + +Deploying to FastAPI Cloud... + +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
+ +C’est tout ! Vous pouvez maintenant accĂ©der Ă  votre application Ă  cette URL. ✹ + +## À propos de FastAPI Cloud { #about-fastapi-cloud } + +**FastAPI Cloud** est dĂ©veloppĂ© par le mĂȘme auteur et la mĂȘme Ă©quipe Ă  l’origine de **FastAPI**. + +Cela simplifie le processus de **crĂ©ation**, de **dĂ©ploiement** et **d’accĂšs** Ă  une API avec un effort minimal. + +Cela apporte la mĂȘme **expĂ©rience dĂ©veloppeur** que pour crĂ©er des applications avec FastAPI au **dĂ©ploiement** dans le cloud. 🎉 + +Cela prend Ă©galement en charge la plupart des Ă©lĂ©ments nĂ©cessaires lors du dĂ©ploiement d’une application, notamment : + +* HTTPS +* RĂ©plication, avec mise Ă  l’échelle automatique basĂ©e sur les requĂȘtes +* etc. + +FastAPI Cloud est le sponsor principal et le financeur 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 standards. Vous pouvez dĂ©ployer des applications FastAPI sur n’importe quel fournisseur cloud de votre choix. + +Suivez les guides de votre fournisseur cloud pour dĂ©ployer des applications FastAPI avec eux. đŸ€“ + +## DĂ©ployer votre propre serveur { #deploy-your-own-server } + +Je vous expliquerai Ă©galement plus loin dans ce guide de **DĂ©ploiement** tous les dĂ©tails, afin que vous compreniez ce qui se passe, ce qui doit ĂȘtre fait, et comment dĂ©ployer des applications FastAPI par vous-mĂȘme, y compris sur vos propres serveurs. đŸ€“ diff --git a/docs/fr/docs/deployment/https.md b/docs/fr/docs/deployment/https.md index 74d38cdb9..1b3c7be56 100644 --- a/docs/fr/docs/deployment/https.md +++ b/docs/fr/docs/deployment/https.md @@ -65,7 +65,7 @@ Voici un exemple de ce Ă  quoi pourrait ressembler une API HTTPS, Ă©tape par Ă©t Tout commencerait probablement par le fait que vous **acquĂ©riez** un **nom de domaine**. Ensuite, vous le configureriez dans un serveur DNS (possiblement le mĂȘme que votre fournisseur cloud). -Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une adresse IP **publique** fixe. +Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une adresse IP publique fixe. Dans le ou les serveurs DNS, vous configureriez un enregistrement (un « `A record` ») pour faire pointer **votre domaine** vers l'**adresse IP publique de votre serveur**. diff --git a/docs/fr/docs/deployment/server-workers.md b/docs/fr/docs/deployment/server-workers.md new file mode 100644 index 000000000..338a5003d --- /dev/null +++ b/docs/fr/docs/deployment/server-workers.md @@ -0,0 +1,139 @@ +# Workers du serveur - Uvicorn avec workers { #server-workers-uvicorn-with-workers } + +Reprenons ces concepts de dĂ©ploiement vus prĂ©cĂ©demment : + +* 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 le dĂ©marrage + +Jusqu'Ă  prĂ©sent, avec tous les tutoriels dans les documents, vous avez probablement exĂ©cutĂ© un programme serveur, par exemple avec la commande `fastapi`, qui lance Uvicorn en exĂ©cutant un seul processus. + +Lors du dĂ©ploiement d'applications, vous voudrez probablement avoir une rĂ©plication de processus pour tirer parti de plusieurs cƓurs et pouvoir gĂ©rer davantage de requĂȘtes. + +Comme vous l'avez vu dans le chapitre prĂ©cĂ©dent sur les [Concepts de dĂ©ploiement](concepts.md){.internal-link target=_blank}, il existe plusieurs stratĂ©gies possibles. + +Ici, je vais vous montrer comment utiliser Uvicorn avec des processus workers en utilisant la commande `fastapi` ou directement la commande `uvicorn`. + +/// info | Info + +Si vous utilisez des conteneurs, par exemple avec Docker ou Kubernetes, je vous en dirai plus Ă  ce sujet dans le prochain chapitre : [FastAPI dans des conteneurs - Docker](docker.md){.internal-link target=_blank}. + +En particulier, lorsque vous exĂ©cutez sur Kubernetes, vous ne voudrez probablement pas utiliser de workers et plutĂŽt exĂ©cuter un seul processus Uvicorn par conteneur, mais je vous en parlerai plus en dĂ©tail dans ce chapitre. + +/// + +## Utiliser plusieurs workers { #multiple-workers } + +Vous pouvez dĂ©marrer plusieurs workers avec l'option de ligne de commande `--workers` : + +//// tab | `fastapi` + +Si vous utilisez la commande `fastapi` : + +
+ +```console +$ fastapi run --workers 4 main.py + + FastAPI Starting production server 🚀 + + Searching for package file structure from directories with + __init__.py files + Importing from /home/user/code/awesomeapp + + module 🐍 main.py + + code Importing the FastAPI app object from the module with the + following code: + + from main import app + + app Using import string: main:app + + server Server started at http://0.0.0.0:8000 + server Documentation at http://0.0.0.0:8000/docs + + Logs: + + INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to + quit) + INFO Started parent process [27365] + INFO Started server process [27368] + INFO Started server process [27369] + INFO Started server process [27370] + INFO Started server process [27367] + INFO Waiting for application startup. + INFO Waiting for application startup. + INFO Waiting for application startup. + INFO Waiting for application startup. + INFO Application startup complete. + INFO Application startup complete. + INFO Application startup complete. + INFO Application startup complete. +``` + +
+ +//// + +//// tab | `uvicorn` + +Si vous préférez utiliser directement la commande `uvicorn` : + +
+ +```console +$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4 +INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit) +INFO: Started parent process [27365] +INFO: Started server process [27368] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Started server process [27369] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Started server process [27370] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Started server process [27367] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +//// + +La seule option nouvelle ici est `--workers` qui indique Ă  Uvicorn de dĂ©marrer 4 processus workers. + +Vous pouvez aussi voir qu'il affiche le PID de chaque processus, `27365` pour le processus parent (c'est le gestionnaire de processus) et un pour chaque processus worker : `27368`, `27369`, `27370` et `27367`. + +## Concepts de dĂ©ploiement { #deployment-concepts } + +Ici, vous avez vu comment utiliser plusieurs workers pour parallĂ©liser l'exĂ©cution de l'application, tirer parti de plusieurs cƓurs du CPU et ĂȘtre en mesure de servir davantage de requĂȘtes. + +Dans la liste des concepts de dĂ©ploiement ci-dessus, l'utilisation de workers aide principalement Ă  la partie rĂ©plication, et un peu aux redĂ©marrages, mais vous devez toujours vous occuper des autres : + +* 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 le dĂ©marrage + +## Conteneurs et Docker { #containers-and-docker } + +Dans le prochain chapitre sur [FastAPI dans des conteneurs - Docker](docker.md){.internal-link target=_blank}, j'expliquerai quelques stratĂ©gies que vous pourriez utiliser pour gĂ©rer les autres concepts de dĂ©ploiement. + +Je vous montrerai comment crĂ©er votre propre image Ă  partir de zĂ©ro pour exĂ©cuter un seul processus Uvicorn. C'est un processus simple et c'est probablement ce que vous voudrez faire lorsque vous utilisez un systĂšme distribuĂ© de gestion de conteneurs comme Kubernetes. + +## RĂ©capitulatif { #recap } + +Vous pouvez utiliser plusieurs processus workers avec l'option CLI `--workers` des commandes `fastapi` ou `uvicorn` pour tirer parti des CPU multicƓurs, et exĂ©cuter plusieurs processus en parallĂšle. + +Vous pourriez utiliser ces outils et idĂ©es si vous mettez en place votre propre systĂšme de dĂ©ploiement tout en prenant vous-mĂȘme en charge les autres concepts de dĂ©ploiement. + +Consultez le prochain chapitre pour en savoir plus sur FastAPI avec des conteneurs (par exemple Docker et Kubernetes). Vous verrez que ces outils offrent aussi des moyens simples de rĂ©soudre les autres concepts de dĂ©ploiement. ✹ diff --git a/docs/fr/docs/environment-variables.md b/docs/fr/docs/environment-variables.md new file mode 100644 index 000000000..57479852a --- /dev/null +++ b/docs/fr/docs/environment-variables.md @@ -0,0 +1,298 @@ +# Variables d'environnement { #environment-variables } + +/// tip | Astuce + +Si vous savez dĂ©jĂ  ce que sont les « variables d'environnement » et comment les utiliser, vous pouvez passer cette section. + +/// + +Une variable d'environnement (Ă©galement appelĂ©e « env var ») est une variable qui vit en dehors du code Python, dans le systĂšme d'exploitation, et qui peut ĂȘtre lue par votre code Python (ou par d'autres programmes Ă©galement). + +Les variables d'environnement peuvent ĂȘtre utiles pour gĂ©rer des **paramĂštres** d'application, dans le cadre de l'**installation** de Python, etc. + +## CrĂ©er et utiliser des variables d'environnement { #create-and-use-env-vars } + +Vous pouvez crĂ©er et utiliser des variables d'environnement dans le **shell (terminal)**, sans avoir besoin de Python : + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +// Vous pouvez créer une variable d'environnement MY_NAME avec +$ export MY_NAME="Wade Wilson" + +// Vous pouvez ensuite l'utiliser avec d'autres programmes, par exemple +$ echo "Hello $MY_NAME" + +Hello Wade Wilson +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +// Créer une variable d'environnement MY_NAME +$ $Env:MY_NAME = "Wade Wilson" + +// L'utiliser avec d'autres programmes, par exemple +$ echo "Hello $Env:MY_NAME" + +Hello Wade Wilson +``` + +
+ +//// + +## Lire des variables d'environnement en Python { #read-env-vars-in-python } + +Vous pouvez également créer des variables d'environnement **en dehors** de Python, dans le terminal (ou par tout autre moyen), puis les **lire en Python**. + +Par exemple, vous pouvez avoir un fichier `main.py` contenant : + +```Python hl_lines="3" +import os + +name = os.getenv("MY_NAME", "World") +print(f"Hello {name} from Python") +``` + +/// tip | Astuce + +Le deuxiÚme argument de `os.getenv()` est la valeur par défaut à retourner. + +S'il n'est pas fourni, c'est `None` par défaut ; ici, nous fournissons `"World"` comme valeur par défaut à utiliser. + +/// + +Vous pouvez ensuite exécuter ce programme Python : + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +// Ici, nous ne définissons pas encore la variable d'environnement +$ python main.py + +// Comme nous ne l'avons pas définie, nous obtenons la valeur par défaut + +Hello World from Python + +// Mais si nous créons d'abord une variable d'environnement +$ export MY_NAME="Wade Wilson" + +// Puis que nous relançons le programme +$ python main.py + +// Il peut maintenant lire la variable d'environnement + +Hello Wade Wilson from Python +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +// Ici, nous ne définissons pas encore la variable d'environnement +$ python main.py + +// Comme nous ne l'avons pas définie, nous obtenons la valeur par défaut + +Hello World from Python + +// Mais si nous créons d'abord une variable d'environnement +$ $Env:MY_NAME = "Wade Wilson" + +// Puis que nous relançons le programme +$ python main.py + +// Il peut maintenant lire la variable d'environnement + +Hello Wade Wilson from Python +``` + +
+ +//// + +Comme les variables d'environnement peuvent ĂȘtre dĂ©finies en dehors du code, mais lues par le code, et qu'elles n'ont pas besoin d'ĂȘtre stockĂ©es (validĂ©es dans `git`) avec le reste des fichiers, il est courant de les utiliser pour les configurations ou les **paramĂštres**. + +Vous pouvez Ă©galement crĂ©er une variable d'environnement uniquement pour l'**invocation d'un programme spĂ©cifique**, qui ne sera disponible que pour ce programme et uniquement pendant sa durĂ©e d'exĂ©cution. + +Pour cela, crĂ©ez-la juste avant le programme, sur la mĂȘme ligne : + +
+ +```console +// Créer en ligne une variable d'environnement MY_NAME pour cet appel de programme +$ MY_NAME="Wade Wilson" python main.py + +// Il peut maintenant lire la variable d'environnement + +Hello Wade Wilson from Python + +// La variable d'environnement n'existe plus ensuite +$ python main.py + +Hello World from Python +``` + +
+ +/// tip | Astuce + +Vous pouvez en lire davantage sur The Twelve-Factor App : Config. + +/// + +## GĂ©rer les types et la validation { #types-and-validation } + +Ces variables d'environnement ne peuvent gĂ©rer que des **chaĂźnes de texte**, car elles sont externes Ă  Python et doivent ĂȘtre compatibles avec les autres programmes et le reste du systĂšme (et mĂȘme avec diffĂ©rents systĂšmes d'exploitation, comme Linux, Windows, macOS). + +Cela signifie que **toute valeur** lue en Python Ă  partir d'une variable d'environnement **sera une `str`**, et que toute conversion vers un autre type ou toute validation doit ĂȘtre effectuĂ©e dans le code. + +Vous en apprendrez davantage sur l'utilisation des variables d'environnement pour gĂ©rer les **paramĂštres d'application** dans le [Guide utilisateur avancĂ© - ParamĂštres et variables d'environnement](./advanced/settings.md){.internal-link target=_blank}. + +## Variable d'environnement `PATH` { #path-environment-variable } + +Il existe une **variable d'environnement spĂ©ciale** appelĂ©e **`PATH`** qui est utilisĂ©e par les systĂšmes d'exploitation (Linux, macOS, Windows) pour trouver les programmes Ă  exĂ©cuter. + +La valeur de la variable `PATH` est une longue chaĂźne composĂ©e de rĂ©pertoires sĂ©parĂ©s par deux-points `:` sous Linux et macOS, et par point-virgule `;` sous Windows. + +Par exemple, la variable d'environnement `PATH` peut ressembler Ă  ceci : + +//// tab | Linux, macOS + +```plaintext +/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin +``` + +Cela signifie que le systĂšme doit rechercher les programmes dans les rĂ©pertoires : + +* `/usr/local/bin` +* `/usr/bin` +* `/bin` +* `/usr/sbin` +* `/sbin` + +//// + +//// tab | Windows + +```plaintext +C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32 +``` + +Cela signifie que le systĂšme doit rechercher les programmes dans les rĂ©pertoires : + +* `C:\Program Files\Python312\Scripts` +* `C:\Program Files\Python312` +* `C:\Windows\System32` + +//// + +Lorsque vous tapez une **commande** dans le terminal, le systĂšme d'exploitation **cherche** le programme dans **chacun de ces rĂ©pertoires** listĂ©s dans la variable d'environnement `PATH`. + +Par exemple, lorsque vous tapez `python` dans le terminal, le systĂšme d'exploitation cherche un programme nommĂ© `python` dans le **premier rĂ©pertoire** de cette liste. + +S'il le trouve, alors il **l'utilise**. Sinon, il continue Ă  chercher dans les **autres rĂ©pertoires**. + +### Installer Python et mettre Ă  jour `PATH` { #installing-python-and-updating-the-path } + +Lorsque vous installez Python, il est possible que l'on vous demande si vous souhaitez mettre Ă  jour la variable d'environnement `PATH`. + +//// tab | Linux, macOS + +Supposons que vous installiez Python et qu'il se retrouve dans un rĂ©pertoire `/opt/custompython/bin`. + +Si vous acceptez de mettre Ă  jour la variable d'environnement `PATH`, l'installateur ajoutera `/opt/custompython/bin` Ă  la variable d'environnement `PATH`. + +Cela pourrait ressembler Ă  ceci : + +```plaintext +/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin +``` + +Ainsi, lorsque vous tapez `python` dans le terminal, le systĂšme trouvera le programme Python dans `/opt/custompython/bin` (le dernier rĂ©pertoire) et utilisera celui-lĂ . + +//// + +//// tab | Windows + +Supposons que vous installiez Python et qu'il se retrouve dans un rĂ©pertoire `C:\opt\custompython\bin`. + +Si vous acceptez de mettre Ă  jour la variable d'environnement `PATH`, l'installateur ajoutera `C:\opt\custompython\bin` Ă  la variable d'environnement `PATH`. + +```plaintext +C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin +``` + +Ainsi, lorsque vous tapez `python` dans le terminal, le systĂšme trouvera le programme Python dans `C:\opt\custompython\bin` (le dernier rĂ©pertoire) et utilisera celui-lĂ . + +//// + +Ainsi, si vous tapez : + +
+ +```console +$ python +``` + +
+ +//// tab | Linux, macOS + +Le systÚme va **trouver** le programme `python` dans `/opt/custompython/bin` et l'exécuter. + +Cela reviendrait à peu prÚs à taper : + +
+ +```console +$ /opt/custompython/bin/python +``` + +
+ +//// + +//// tab | Windows + +Le systÚme va **trouver** le programme `python` dans `C:\opt\custompython\bin\python` et l'exécuter. + +Cela reviendrait à peu prÚs à taper : + +
+ +```console +$ C:\opt\custompython\bin\python +``` + +
+ +//// + +Ces informations vous seront utiles lors de l'apprentissage des [Environnements virtuels](virtual-environments.md){.internal-link target=_blank}. + +## Conclusion { #conclusion } + +Avec cela, vous devriez avoir une compréhension de base de ce que sont les **variables d'environnement** et de la façon de les utiliser en Python. + +Vous pouvez également en lire davantage sur la page Wikipédia dédiée aux variables d'environnement. + +Dans de nombreux cas, il n'est pas évident de voir immédiatement en quoi les variables d'environnement seraient utiles et applicables. Mais elles réapparaissent dans de nombreux scénarios lorsque vous développez, il est donc bon de les connaßtre. + +Par exemple, vous aurez besoin de ces informations dans la section suivante, sur les [Environnements virtuels](virtual-environments.md). diff --git a/docs/fr/docs/fastapi-cli.md b/docs/fr/docs/fastapi-cli.md new file mode 100644 index 000000000..9f31e8a2f --- /dev/null +++ b/docs/fr/docs/fastapi-cli.md @@ -0,0 +1,75 @@ +# FastAPI CLI { #fastapi-cli } + +**FastAPI CLI** est un programme en ligne de commande que vous pouvez utiliser pour servir votre application FastAPI, gérer votre projet FastAPI, et plus encore. + +Lorsque vous installez FastAPI (par exemple avec `pip install "fastapi[standard]"`), cela inclut un package appelé `fastapi-cli` ; ce package fournit la commande `fastapi` dans le terminal. + +Pour exécuter votre application FastAPI en développement, vous pouvez utiliser la commande `fastapi dev` : + +
+ +```console +$ fastapi dev main.py + + FastAPI Starting development server 🚀 + + Searching for package file structure from directories with + __init__.py files + Importing from /home/user/code/awesomeapp + + module 🐍 main.py + + code Importing the FastAPI app object from the module with the + following code: + + from main import app + + app Using import string: main:app + + server Server started at http://127.0.0.1:8000 + server Documentation at http://127.0.0.1:8000/docs + + tip Running in development mode, for production use: + fastapi run + + Logs: + + 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 [383138] using WatchFiles + INFO Started server process [383153] + INFO Waiting for application startup. + INFO Application startup complete. +``` + +
+ +Le programme en ligne de commande nommĂ© `fastapi` est **FastAPI CLI**. + +FastAPI CLI prend le chemin vers votre programme Python (par exemple `main.py`), dĂ©tecte automatiquement l’instance `FastAPI` (gĂ©nĂ©ralement nommĂ©e `app`), dĂ©termine la procĂ©dure d’importation correcte, puis la sert. + +Pour la production, vous utiliserez plutĂŽt `fastapi run`. 🚀 + +En interne, **FastAPI CLI** utilise Uvicorn, un serveur ASGI haute performance, prĂȘt pour la production. 😎 + +## `fastapi dev` { #fastapi-dev } + +L’exĂ©cution de `fastapi dev` lance le mode dĂ©veloppement. + +Par dĂ©faut, l’**auto-reload** est activĂ© et recharge automatiquement le serveur lorsque vous modifiez votre code. Cela consomme des ressources et peut ĂȘtre moins stable que lorsqu’il est dĂ©sactivĂ©. Vous devez l’utiliser uniquement pour le dĂ©veloppement. Il Ă©coute aussi sur l’adresse IP `127.0.0.1`, qui est l’adresse IP permettant Ă  votre machine de communiquer uniquement avec elle‑mĂȘme (`localhost`). + +## `fastapi run` { #fastapi-run } + +ExĂ©cuter `fastapi run` dĂ©marre FastAPI en mode production par dĂ©faut. + +Par dĂ©faut, l’**auto-reload** est dĂ©sactivĂ©. Il Ă©coute aussi sur l’adresse IP `0.0.0.0`, ce qui signifie toutes les adresses IP disponibles ; de cette maniĂšre, il sera accessible publiquement Ă  toute personne pouvant communiquer avec la machine. C’est ainsi que vous l’exĂ©cutez normalement en production, par exemple dans un conteneur. + +Dans la plupart des cas, vous avez (et devez avoir) un « termination proxy » au‑dessus qui gĂšre le HTTPS pour vous ; cela dĂ©pend de la façon dont vous dĂ©ployez votre application : votre fournisseur peut le faire pour vous, ou vous devrez le configurer vous‑mĂȘme. + +/// tip | Astuce + +Vous pouvez en savoir plus Ă  ce sujet dans la [documentation de dĂ©ploiement](deployment/index.md){.internal-link target=_blank}. + +/// diff --git a/docs/fr/docs/features.md b/docs/fr/docs/features.md index bc63e11b4..e5e809940 100644 --- a/docs/fr/docs/features.md +++ b/docs/fr/docs/features.md @@ -1,43 +1,43 @@ -# FonctionnalitĂ©s +# FonctionnalitĂ©s { #features } -## FonctionnalitĂ©s de FastAPI +## FonctionnalitĂ©s de FastAPI { #fastapi-features } -**FastAPI** vous offre ceci: +**FastAPI** vous offre les Ă©lĂ©ments suivants : -### BasĂ© sur des standards ouverts +### BasĂ© sur des standards ouverts { #based-on-open-standards } -* OpenAPI pour la crĂ©ation d'API, incluant la dĂ©claration de path operations, paramĂštres, corps de requĂȘtes, sĂ©curitĂ©, etc. -* Documentation automatique des modĂšles de donnĂ©es avec JSON Schema (comme OpenAPI est aussi basĂ©e sur JSON Schema). -* Conçue avec ces standards aprĂšs une analyse mĂ©ticuleuse. PlutĂŽt qu'en rajoutant des surcouches aprĂšs coup. -* Cela permet d'utiliser de la **gĂ©nĂ©ration automatique de code client** dans beaucoup de langages. +* OpenAPI pour la crĂ©ation d'API, incluant la dĂ©claration de chemin opĂ©rations, paramĂštres, corps de requĂȘtes, sĂ©curitĂ©, etc. +* Documentation automatique des modĂšles de donnĂ©es avec JSON Schema (puisque OpenAPI est lui-mĂȘme basĂ© sur JSON Schema). +* Conçu autour de ces standards, aprĂšs une Ă©tude mĂ©ticuleuse. PlutĂŽt qu'une couche ajoutĂ©e aprĂšs coup. +* Cela permet Ă©galement d'utiliser la **gĂ©nĂ©ration automatique de code client** dans de nombreux langages. -### Documentation automatique +### Documentation automatique { #automatic-docs } -Documentation d'API interactive et interface web d'exploration. Comme le framework est basĂ© sur OpenAPI, de nombreuses options sont disponibles. Deux d'entre-elles sont incluses par dĂ©faut. +Documentation d'API interactive et interfaces web d'exploration. Comme le framework est basĂ© sur OpenAPI, plusieurs options existent, 2 incluses par dĂ©faut. -* Swagger UI, propose une documentation interactive. Vous permet de directement tester l'API depuis votre navigateur. +* Swagger UI, avec exploration interactive, appelez et testez votre API directement depuis le navigateur. ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) -* Une autre documentation d'API est fournie par ReDoc. +* Documentation d'API alternative avec ReDoc. ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### Faite en python moderne +### Uniquement du Python moderne { #just-modern-python } -Tout est basĂ© sur la dĂ©claration de type standard de **Python 3.8** (grĂące Ă  Pydantic). Pas de nouvelles syntaxes Ă  apprendre. Juste du Python standard et moderne. +Tout est basĂ© sur les dĂ©clarations de **types Python** standard (grĂące Ă  Pydantic). Aucune nouvelle syntaxe Ă  apprendre. Juste du Python moderne standard. -Si vous souhaitez un rappel de 2 minutes sur l'utilisation des types en Python (mĂȘme si vous ne comptez pas utiliser FastAPI), jetez un oeil au tutoriel suivant: [Python Types](python-types.md){.internal-link target=_blank}. +Si vous avez besoin d'un rappel de 2 minutes sur l'utilisation des types en Python (mĂȘme si vous n'utilisez pas FastAPI), consultez le court tutoriel : [Types Python](python-types.md){.internal-link target=_blank}. -Vous Ă©crivez du python standard avec des annotations de types: +Vous Ă©crivez du Python standard avec des types : ```Python from datetime import date from pydantic import BaseModel -# DĂ©clare une variable comme Ă©tant une str -# et profitez de l'aide de votre IDE dans cette fonction +# DĂ©clarez une variable comme Ă©tant une str +# et profitez de l'aide de l'Ă©diteur dans cette fonction def main(user_id: str): return user_id @@ -48,7 +48,8 @@ class User(BaseModel): name: str joined: date ``` -Qui peuvent ensuite ĂȘtre utilisĂ©s comme cela: + +Qui peuvent ensuite ĂȘtre utilisĂ©s comme ceci : ```Python my_user: User = User(id=3, name="John Doe", joined="2018-07-19") @@ -64,138 +65,137 @@ my_second_user: User = User(**second_user_data) /// info -`**second_user_data` signifie: +`**second_user_data` signifie : -Utilise les clĂ©s et valeurs du dictionnaire `second_user_data` directement comme des arguments clĂ©-valeur. C'est Ă©quivalent Ă : `User(id=4, name="Mary", joined="2018-11-30")` +Passez les clĂ©s et valeurs du dictionnaire `second_user_data` directement comme arguments clĂ©-valeur, Ă©quivalent Ă  : `User(id=4, name="Mary", joined="2018-11-30")` /// -### Support d'Ă©diteurs +### Support des Ă©diteurs { #editor-support } -Tout le framework a Ă©tĂ© conçu pour ĂȘtre facile et intuitif d'utilisation, toutes les dĂ©cisions de design ont Ă©tĂ© testĂ©es sur de nombreux Ă©diteurs avant mĂȘme de commencer le dĂ©veloppement final afin d'assurer la meilleure expĂ©rience de dĂ©veloppement possible. +Tout le framework a Ă©tĂ© conçu pour ĂȘtre facile et intuitif Ă  utiliser, toutes les dĂ©cisions ont Ă©tĂ© testĂ©es sur plusieurs Ă©diteurs avant mĂȘme de commencer le dĂ©veloppement, pour assurer la meilleure expĂ©rience de dĂ©veloppement. -Dans le dernier sondage effectuĂ© auprĂšs de dĂ©veloppeurs python il Ă©tait clair que la fonctionnalitĂ© la plus utilisĂ©e est "l’autocomplĂ©tion". +Dans les enquĂȘtes auprĂšs des dĂ©veloppeurs Python, il est clair que l’une des fonctionnalitĂ©s les plus utilisĂ©es est « autocomplĂ©tion ». -Tout le framework **FastAPI** a Ă©tĂ© conçu avec cela en tĂȘte. L'autocomplĂ©tion fonctionne partout. +L'ensemble du framework **FastAPI** est conçu pour satisfaire cela. L'autocomplĂ©tion fonctionne partout. -Vous devrez rarement revenir Ă  la documentation. +Vous aurez rarement besoin de revenir aux documents. -Voici comment votre Ă©diteur peut vous aider: +Voici comment votre Ă©diteur peut vous aider : -* dans Visual Studio Code: +* dans Visual Studio Code : ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -* dans PyCharm: +* dans PyCharm : ![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png) -Vous aurez des propositions de complĂ©tion que vous n'auriez jamais imaginĂ©es. Par exemple la clĂ© `prix` dans le corps d'un document JSON (qui est peut-ĂȘtre imbriquĂ©) venant d'une requĂȘte. +Vous obtiendrez de l'autocomplĂ©tion dans du code que vous auriez pu considĂ©rer impossible auparavant. Par exemple, la clĂ© `price` Ă  l'intĂ©rieur d'un corps JSON (qui aurait pu ĂȘtre imbriquĂ©) provenant d'une requĂȘte. -Plus jamais vous ne vous tromperez en tapant le nom d'une clĂ©, vous ne ferez des aller-retour entre votre code et la documentation ou vous ne scrollerez de haut en bas afin d'enfin savoir si vous devez taper `username` ou `user_name`. +Fini de taper des noms de clĂ©s erronĂ©s, de faire des allers-retours entre les documents, ou de faire dĂ©filer vers le haut et vers le bas pour savoir si vous avez finalement utilisĂ© `username` ou `user_name`. -### Court +### Court { #short } -Des **valeurs par dĂ©faut** sont dĂ©finies pour tout, des configurations optionnelles sont prĂ©sentent partout. Tous ces paramĂštres peuvent ĂȘtre ajustĂ©s afin de faire ce que vous voulez et dĂ©finir l'API dont vous avez besoin. +Des **valeurs par dĂ©faut** sensĂ©es pour tout, avec des configurations optionnelles partout. Tous les paramĂštres peuvent ĂȘtre ajustĂ©s finement pour faire ce dont vous avez besoin et dĂ©finir l'API dont vous avez besoin. -Mais, **tout fonctionne** par dĂ©faut. +Mais par dĂ©faut, tout **« just works »**. -### Validation +### Validation { #validation } -* Validation pour la plupart (ou tous?) les **types de donnĂ©es** Python incluant: +* Validation pour la plupart (ou tous ?) des **types de donnĂ©es** Python, y compris : * objets JSON (`dict`). - * listes JSON (`list`) dĂ©finissant des types d'Ă©lĂ©ments. - * Champs String (`str`), dĂ©finition de longueur minimum ou maximale. - * Nombres (`int`, `float`) avec valeur minimale and maximale, etc. + * tableaux JSON (`list`) dĂ©finissant les types d'Ă©lĂ©ments. + * champs String (`str`), dĂ©finition des longueurs minimale et maximale. + * nombres (`int`, `float`) avec valeurs minimale et maximale, etc. -* Validation pour des types plus exotiques, tel que: +* Validation pour des types plus exotiques, comme : * URL. * Email. * UUID. - * ...et autres. + * ... et autres. -Toutes les validations sont gĂ©rĂ©es par le bien Ă©tabli et robuste **Pydantic**. +Toutes les validations sont gĂ©rĂ©es par le **Pydantic** bien Ă©tabli et robuste. -### SĂ©curitĂ© et authentification +### SĂ©curitĂ© et authentification { #security-and-authentication } -La sĂ©curitĂ© et l'authentification sont intĂ©grĂ©es. Sans aucun compromis avec les bases de donnĂ©es ou les modĂšles de donnĂ©es. +SĂ©curitĂ© et authentification intĂ©grĂ©es. Sans aucun compromis avec les bases de donnĂ©es ou les modĂšles de donnĂ©es. -Tous les protocoles de sĂ©curitĂ©s sont dĂ©finis dans OpenAPI, incluant: +Tous les schĂ©mas de sĂ©curitĂ© dĂ©finis dans OpenAPI, y compris : * HTTP Basic. -* **OAuth2** (aussi avec **JWT tokens**). Jetez un oeil au tutoriel [OAuth2 avec JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. -* ClĂ©s d'API dans: - * Le header. - * Les paramĂštres de requĂȘtes. - * Les cookies, etc. +* **OAuth2** (Ă©galement avec des **tokens JWT**). Consultez le tutoriel [OAuth2 avec JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. +* ClĂ©s d'API dans : + * les en-tĂȘtes. + * les paramĂštres de requĂȘte. + * les cookies, etc. -Plus toutes les fonctionnalitĂ©s de sĂ©curitĂ©s venant de Starlette (incluant les **cookies de sessions**). +Plus toutes les fonctionnalitĂ©s de sĂ©curitĂ© de Starlette (y compris les **cookies de session**). -Le tout conçu en composant rĂ©utilisable facilement intĂ©grable Ă  vos systĂšmes, data stores, base de donnĂ©es relationnelle ou NoSQL, etc. +Le tout construit comme des outils et composants rĂ©utilisables, faciles Ă  intĂ©grer Ă  vos systĂšmes, magasins de donnĂ©es, bases de donnĂ©es relationnelles et NoSQL, etc. -### Injection de dĂ©pendances +### Injection de dĂ©pendances { #dependency-injection } -FastAPI contient un systĂšme simple mais extrĂȘmement puissant d'Injection de DĂ©pendances. +FastAPI inclut un systĂšme d’Injection de dĂ©pendances extrĂȘmement simple Ă  utiliser, mais extrĂȘmement puissant. -* MĂȘme les dĂ©pendances peuvent avoir des dĂ©pendances, crĂ©ant une hiĂ©rarchie ou un **"graph" de dĂ©pendances** -* Tout est **automatiquement gĂ©rĂ©** par le framework -* Toutes les dĂ©pendances peuvent exiger des donnĂ©es d'une requĂȘtes et **Augmenter les contraintes d'un path operation** et de la documentation automatique. -* **Validation automatique** mĂȘme pour les paramĂštres de *path operation* dĂ©finis dans les dĂ©pendances. -* Supporte les systĂšmes d'authentification d'utilisateurs complexes, les **connexions de base de donnĂ©es**, etc. -* **Aucun compromis** avec les bases de donnĂ©es, les frontends, etc. Mais une intĂ©gration facile avec n'importe lequel d'entre eux. +* MĂȘme les dĂ©pendances peuvent avoir des dĂ©pendances, crĂ©ant une hiĂ©rarchie ou un **« graphe » de dĂ©pendances**. +* Le tout **gĂ©rĂ© automatiquement** par le framework. +* Toutes les dĂ©pendances peuvent exiger des donnĂ©es des requĂȘtes et **augmenter les contraintes du chemin d'accĂšs** ainsi que la documentation automatique. +* **Validation automatique** mĂȘme pour les paramĂštres de *chemin d'accĂšs* dĂ©finis dans les dĂ©pendances. +* Prise en charge des systĂšmes d'authentification d'utilisateurs complexes, des **connexions de base de donnĂ©es**, etc. +* **Aucun compromis** avec les bases de donnĂ©es, les frontends, etc. Mais une intĂ©gration facile avec tous. -### "Plug-ins" illimitĂ©s +### « Plug-ins » illimitĂ©s { #unlimited-plug-ins } -Ou, en d'autres termes, pas besoin d'eux, importez le code que vous voulez et utilisez le. +Ou, autrement dit, pas besoin d'eux, importez et utilisez le code dont vous avez besoin. -Tout intĂ©gration est conçue pour ĂȘtre si simple Ă  utiliser (avec des dĂ©pendances) que vous pouvez crĂ©er un "plug-in" pour votre application en deux lignes de code utilisant la mĂȘme syntaxe que celle de vos *path operations* +Toute intĂ©gration est conçue pour ĂȘtre si simple Ă  utiliser (avec des dĂ©pendances) que vous pouvez crĂ©er un « plug-in » pour votre application en 2 lignes de code en utilisant la mĂȘme structure et la mĂȘme syntaxe que pour vos *chemins d'accĂšs*. -### TestĂ© +### TestĂ© { #tested } -* 100% de couverture de test. -* 100% d'annotations de type dans le code. -* UtilisĂ© dans des applications mises en production. +* 100 % de couverture de test. +* 100 % de base de code annotĂ©e avec des types. +* UtilisĂ© dans des applications en production. -## FonctionnalitĂ©s de Starlette +## FonctionnalitĂ©s de Starlette { #starlette-features } -**FastAPI** est complĂštement compatible (et basĂ© sur) Starlette. Le code utilisant Starlette que vous ajouterez fonctionnera donc aussi. +**FastAPI** est entiĂšrement compatible avec (et basĂ© sur) Starlette. Donc, tout code Starlette additionnel que vous avez fonctionnera aussi. -En fait, `FastAPI` est un sous composant de `Starlette`. Donc, si vous savez dĂ©jĂ  comment utiliser Starlette, la plupart des fonctionnalitĂ©s fonctionneront de la mĂȘme maniĂšre. +`FastAPI` est en fait une sous-classe de `Starlette`. Ainsi, si vous connaissez ou utilisez dĂ©jĂ  Starlette, la plupart des fonctionnalitĂ©s fonctionneront de la mĂȘme maniĂšre. -Avec **FastAPI** vous aurez toutes les fonctionnalitĂ©s de **Starlette** (FastAPI est juste Starlette sous stĂ©roĂŻdes): +Avec **FastAPI** vous obtenez toutes les fonctionnalitĂ©s de **Starlette** (puisque FastAPI est juste Starlette sous stĂ©roĂŻdes) : -* Des performances vraiment impressionnantes. C'est l'un des framework Python les plus rapide, Ă  Ă©galitĂ© avec **NodeJS** et **GO**. -* Le support des **WebSockets**. -* Le support de **GraphQL**. -* Les tĂąches d'arriĂšre-plan. -* Des Ă©vĂšnements de dĂ©marrages et d'arrĂȘt. -* Un client de test basĂ© sur `request` -* **CORS**, GZip, Static Files, Streaming responses. -* Le support des **Sessions et Cookies**. -* Une couverture de test Ă  100 %. -* 100 % de la base de code avec des annotations de type. +* Des performances vraiment impressionnantes. C'est l’un des frameworks Python les plus rapides disponibles, Ă  l’égal de **NodeJS** et **Go**. +* Prise en charge des **WebSocket**. +* TĂąches d'arriĂšre-plan dans le processus. +* ÉvĂšnements de dĂ©marrage et d'arrĂȘt. +* Client de test basĂ© sur HTTPX. +* **CORS**, GZip, fichiers statiques, rĂ©ponses en streaming. +* Prise en charge des **Sessions et Cookies**. +* Couverture de test Ă  100 %. +* Base de code annotĂ©e Ă  100 % avec des types. -## FonctionnalitĂ©s de Pydantic +## FonctionnalitĂ©s de Pydantic { #pydantic-features } -**FastAPI** est totalement compatible avec (et basĂ© sur) Pydantic. Le code utilisant Pydantic que vous ajouterez fonctionnera donc aussi. +**FastAPI** est entiĂšrement compatible avec (et basĂ© sur) Pydantic. Donc, tout code Pydantic additionnel que vous avez fonctionnera aussi. -Inclus des librairies externes basĂ©es, aussi, sur Pydantic, servent d'ORMs, ODMs pour les bases de donnĂ©es. +Y compris des bibliothĂšques externes Ă©galement basĂ©es sur Pydantic, servant d’ORM, d’ODM pour les bases de donnĂ©es. -Cela signifie aussi que, dans la plupart des cas, vous pouvez fournir l'objet reçu d'une requĂȘte **directement Ă  la base de donnĂ©es**, comme tout est validĂ© automatiquement. +Cela signifie Ă©galement que, dans de nombreux cas, vous pouvez passer l'objet que vous recevez d'une requĂȘte **directement Ă  la base de donnĂ©es**, puisque tout est validĂ© automatiquement. -Inversement, dans la plupart des cas vous pourrez juste envoyer l'objet rĂ©cupĂ©rĂ© de la base de donnĂ©es **directement au client** +L’inverse est Ă©galement vrai, dans de nombreux cas, vous pouvez simplement passer l'objet que vous rĂ©cupĂ©rez de la base de donnĂ©es **directement au client**. -Avec **FastAPI** vous aurez toutes les fonctionnalitĂ©s de **Pydantic** (comme FastAPI est basĂ© sur Pydantic pour toutes les manipulations de donnĂ©es): +Avec **FastAPI** vous obtenez toutes les fonctionnalitĂ©s de **Pydantic** (puisque FastAPI est basĂ© sur Pydantic pour toute la gestion des donnĂ©es) : -* **Pas de prise de tĂȘte**: - * Pas de nouveau langage de dĂ©finition de schĂ©ma Ă  apprendre. - * Si vous connaissez le typage en python vous savez comment utiliser Pydantic. -* Aide votre **IDE/linter/cerveau**: - * Parce que les structures de donnĂ©es de pydantic consistent seulement en une instance de classe que vous dĂ©finissez; l'auto-complĂ©tion, le linting, mypy et votre intuition devrait ĂȘtre largement suffisante pour valider vos donnĂ©es. -* Valide les **structures complexes**: - * Utilise les modĂšles hiĂ©rarchique de Pydantic, le `typage` Python pour les `Lists`, `Dict`, etc. - * Et les validateurs permettent aux schĂ©mas de donnĂ©es complexes d'ĂȘtre clairement et facilement dĂ©finis, validĂ©s et documentĂ©s sous forme d'un schĂ©ma JSON. - * Vous pouvez avoir des objets **JSON fortement imbriquĂ©s** tout en ayant, pour chacun, de la validation et des annotations. -* **Renouvelable**: - * Pydantic permet de dĂ©finir de nouveaux types de donnĂ©es ou vous pouvez Ă©tendre la validation avec des mĂ©thodes sur un modĂšle dĂ©corĂ© avec le dĂ©corateur de validation -* 100% de couverture de test. +* **Pas de prise de tĂȘte** : + * Pas de micro-langage de dĂ©finition de schĂ©ma Ă  apprendre. + * Si vous connaissez les types Python vous savez utiliser Pydantic. +* Fonctionne bien avec votre **IDE/linter/cerveau** : + * Parce que les structures de donnĂ©es de Pydantic sont simplement des instances de classes que vous dĂ©finissez ; l'autocomplĂ©tion, le linting, mypy et votre intuition devraient tous bien fonctionner avec vos donnĂ©es validĂ©es. +* Valider des **structures complexes** : + * Utilisation de modĂšles Pydantic hiĂ©rarchiques, de `List` et `Dict` du `typing` Python, etc. + * Et les validateurs permettent de dĂ©finir, vĂ©rifier et documenter clairement et facilement des schĂ©mas de donnĂ©es complexes en tant que JSON Schema. + * Vous pouvez avoir des objets **JSON fortement imbriquĂ©s** et les faire tous valider et annoter. +* **Extensible** : + * Pydantic permet de dĂ©finir des types de donnĂ©es personnalisĂ©s ou vous pouvez Ă©tendre la validation avec des mĂ©thodes sur un modĂšle dĂ©corĂ© avec le dĂ©corateur de validation. +* Couverture de test Ă  100 %. diff --git a/docs/fr/docs/help-fastapi.md b/docs/fr/docs/help-fastapi.md index 9b75f463b..08d9a7a72 100644 --- a/docs/fr/docs/help-fastapi.md +++ b/docs/fr/docs/help-fastapi.md @@ -1,103 +1,255 @@ -# Help FastAPI - Obtenir de l'aide +# Aider FastAPI - Obtenir de l'aide { #help-fastapi-get-help } Aimez-vous **FastAPI** ? -Vous souhaitez aider FastAPI, les autres utilisateurs et l'auteur ? +Souhaitez-vous aider FastAPI, les autres utilisateurs et l'auteur ? -Ou souhaitez-vous obtenir de l'aide avec le **FastAPI** ? +Ou souhaitez-vous obtenir de l'aide avec **FastAPI** ? Il existe des moyens trĂšs simples d'aider (plusieurs ne nĂ©cessitent qu'un ou deux clics). -Il existe Ă©galement plusieurs façons d'obtenir de l'aide. +Et il existe aussi plusieurs façons d'obtenir de l'aide. -## Star **FastAPI** sur GitHub +## S'abonner Ă  la newsletter { #subscribe-to-the-newsletter } -Vous pouvez "star" FastAPI dans GitHub (en cliquant sur le bouton Ă©toile en haut Ă  droite) : https://github.com/fastapi/fastapi. ⭐ +Vous pouvez vous abonner Ă  la (peu frĂ©quente) [newsletter **FastAPI and friends**](newsletter.md){.internal-link target=_blank} pour rester informĂ© Ă  propos : -En ajoutant une Ă©toile, les autres utilisateurs pourront la trouver plus facilement et constater qu'elle a dĂ©jĂ  Ă©tĂ© utile Ă  d'autres. +* Nouvelles sur FastAPI et ses amis 🚀 +* Guides 📝 +* FonctionnalitĂ©s ✹ +* Changements majeurs 🚹 +* Astuces et conseils ✅ -## Watch le dĂ©pĂŽt GitHub pour les releases +## Suivre FastAPI sur X (Twitter) { #follow-fastapi-on-x-twitter } -Vous pouvez "watch" FastAPI dans GitHub (en cliquant sur le bouton "watch" en haut Ă  droite) : https://github.com/fastapi/fastapi. 👀 +Suivez @fastapi sur **X (Twitter)** pour obtenir les derniĂšres nouvelles sur **FastAPI**. 🐩 -Vous pouvez y sĂ©lectionner "Releases only". +## Mettre une Ă©toile Ă  **FastAPI** sur GitHub { #star-fastapi-in-github } -Ainsi, vous recevrez des notifications (dans votre courrier Ă©lectronique) chaque fois qu'il y aura une nouvelle version de **FastAPI** avec des corrections de bugs et de nouvelles fonctionnalitĂ©s. +Vous pouvez « star » FastAPI sur GitHub (en cliquant sur le bouton Ă©toile en haut Ă  droite) : https://github.com/fastapi/fastapi. ⭐ -## Se rapprocher de l'auteur +En ajoutant une Ă©toile, les autres utilisateurs pourront le trouver plus facilement et voir qu'il a dĂ©jĂ  Ă©tĂ© utile Ă  d'autres. -Vous pouvez vous rapprocher de moi (SebastiĂĄn RamĂ­rez / `tiangolo`), l'auteur. +## Suivre le dĂ©pĂŽt GitHub pour les releases { #watch-the-github-repository-for-releases } -Vous pouvez : +Vous pouvez « watch » FastAPI sur GitHub (en cliquant sur le bouton « watch » en haut Ă  droite) : https://github.com/fastapi/fastapi. 👀 + +Vous pouvez y sĂ©lectionner « Releases only ». + +Ainsi, vous recevrez des notifications (par e‑mail) chaque fois qu'il y aura une nouvelle release (une nouvelle version) de **FastAPI** avec des corrections de bugs et de nouvelles fonctionnalitĂ©s. + +## Entrer en contact avec l'auteur { #connect-with-the-author } + +Vous pouvez entrer en contact avec moi (SebastiĂĄn RamĂ­rez / `tiangolo`), l'auteur. + +Vous pouvez : * Me suivre sur **GitHub**. * Voir d'autres projets Open Source que j'ai créés et qui pourraient vous aider. - * Suivez-moi pour voir quand je crĂ©e un nouveau projet Open Source. -* Me suivre sur **X (Twitter)**. - * Dites-moi comment vous utilisez FastAPI (j'adore entendre ça). - * Entendre quand je fais des annonces ou que je lance de nouveaux outils. -* Vous connectez Ă  moi sur **LinkedIn**. - * Etre notifiĂ© quand je fais des annonces ou que je lance de nouveaux outils (bien que j'utilise plus souvent X (Twitter) đŸ€·â€â™‚). -* Lire ce que j’écris (ou me suivre) sur **Dev.to** ou **Medium**. - * Lire d'autres idĂ©es, articles, et sur les outils que j'ai créés. - * Suivez-moi pour lire quand je publie quelque chose de nouveau. + * Me suivre pour voir quand je crĂ©e un nouveau projet Open Source. +* Me suivre sur **X (Twitter)** ou sur Mastodon. + * Me dire comment vous utilisez FastAPI (j'adore l'entendre). + * Être informĂ© quand je fais des annonces ou publie de nouveaux outils. + * Vous pouvez aussi suivre @fastapi sur X (Twitter) (un compte sĂ©parĂ©). +* Me suivre sur **LinkedIn**. + * Être informĂ© quand je fais des annonces ou publie de nouveaux outils (mĂȘme si j'utilise plus souvent X (Twitter) đŸ€·â€â™‚). +* Lire ce que j'Ă©cris (ou me suivre) sur **Dev.to** ou **Medium**. + * Lire d'autres idĂ©es, des articles, et dĂ©couvrir des outils que j'ai créés. + * Me suivre pour lire quand je publie quelque chose de nouveau. -## Tweeter sur **FastAPI** +## Tweeter Ă  propos de **FastAPI** { #tweet-about-fastapi } -Tweetez Ă  propos de **FastAPI** et faites-moi savoir, ainsi qu'aux autres, pourquoi vous aimez ça. 🎉 +Tweetez Ă  propos de **FastAPI** et faites savoir Ă  moi et aux autres pourquoi vous l'apprĂ©ciez. 🎉 -J'aime entendre parler de l'utilisation du **FastAPI**, de ce que vous avez aimĂ© dedans, dans quel projet/entreprise l'utilisez-vous, etc. +J'adore entendre comment **FastAPI** est utilisĂ©, ce que vous avez aimĂ©, dans quel projet/quelle entreprise vous l'utilisez, etc. -## Voter pour FastAPI +## Voter pour FastAPI { #vote-for-fastapi } * Votez pour **FastAPI** sur Slant. -* Votez pour **FastAPI** sur AlternativeTo. -* Votez pour **FastAPI** sur awesome-rest. +* Votez pour **FastAPI** sur AlternativeTo. +* Indiquez que vous utilisez **FastAPI** sur StackShare. -## Aider les autres Ă  rĂ©soudre les problĂšmes dans GitHub +## Aider les autres avec des questions sur GitHub { #help-others-with-questions-in-github } -Vous pouvez voir les problĂšmes existants et essayer d'aider les autres, la plupart du temps il s'agit de questions dont vous connaissez peut-ĂȘtre dĂ©jĂ  la rĂ©ponse. đŸ€“ +Vous pouvez essayer d'aider les autres avec leurs questions dans : -## Watch le dĂ©pĂŽt GitHub +* GitHub Discussions +* GitHub Issues -Vous pouvez "watch" FastAPI dans GitHub (en cliquant sur le bouton "watch" en haut Ă  droite) : https://github.com/fastapi/fastapi. 👀 +Dans de nombreux cas, vous connaissez peut-ĂȘtre dĂ©jĂ  la rĂ©ponse Ă  ces questions. đŸ€“ -Si vous sĂ©lectionnez "Watching" au lieu de "Releases only", vous recevrez des notifications lorsque quelqu'un crĂ©e une nouvelle Issue. +Si vous aidez beaucoup de personnes avec leurs questions, vous deviendrez un [Expert FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank} officiel. 🎉 -Vous pouvez alors essayer de les aider Ă  rĂ©soudre ces problĂšmes. +N'oubliez pas, le point le plus important est : essayez d'ĂȘtre aimable. Les gens viennent avec leurs frustrations et, dans bien des cas, ne posent pas la question de la meilleure façon, mais faites de votre mieux pour rester aimable. đŸ€— -## CrĂ©er une Issue +L'idĂ©e est que la communautĂ© **FastAPI** soit bienveillante et accueillante. En mĂȘme temps, n'acceptez pas l'intimidation ni les comportements irrespectueux envers les autres. Nous devons prendre soin les uns des autres. -Vous pouvez crĂ©er une Issue dans le dĂ©pĂŽt GitHub, par exemple pour : +--- -* Poser une question ou s'informer sur un problĂšme. -* SuggĂ©rer une nouvelle fonctionnalitĂ©. +Voici comment aider les autres avec des questions (dans les discussions ou les issues) : -**Note** : si vous crĂ©ez un problĂšme, alors je vais vous demander d'aider aussi les autres. 😉 +### Comprendre la question { #understand-the-question } -## CrĂ©er une Pull Request +* VĂ©rifiez si vous comprenez quel est l’**objectif** et le cas d'utilisation de la personne qui pose la question. -Vous pouvez crĂ©er une Pull Request, par exemple : +* Ensuite, vĂ©rifiez si la question (la grande majoritĂ© sont des questions) est **claire**. -* Pour corriger une faute de frappe que vous avez trouvĂ©e sur la documentation. +* Dans de nombreux cas, la question porte sur une solution imaginaire de l'utilisateur, mais il pourrait y en avoir une **meilleure**. Si vous comprenez mieux le problĂšme et le cas d'utilisation, vous pourriez suggĂ©rer une **solution alternative** plus adaptĂ©e. + +* Si vous ne comprenez pas la question, demandez plus de **dĂ©tails**. + +### Reproduire le problĂšme { #reproduce-the-problem } + +Dans la plupart des cas et pour la plupart des questions, il y a quelque chose liĂ© au **code original** de la personne. + +Dans de nombreux cas, elle ne copiera qu'un fragment de code, mais ce n'est pas suffisant pour **reproduire le problĂšme**. + +* Vous pouvez leur demander de fournir un exemple minimal, complet et vĂ©rifiable, que vous pouvez **copier‑coller** et exĂ©cuter localement pour voir la mĂȘme erreur ou le mĂȘme comportement qu'ils observent, ou pour mieux comprendre leur cas d'utilisation. + +* Si vous vous sentez trĂšs gĂ©nĂ©reux, vous pouvez essayer de **crĂ©er un tel exemple** vous‑mĂȘme, simplement Ă  partir de la description du problĂšme. Gardez simplement Ă  l'esprit que cela peut prendre beaucoup de temps et qu'il peut ĂȘtre prĂ©fĂ©rable de leur demander d'abord de clarifier le problĂšme. + +### SuggĂ©rer des solutions { #suggest-solutions } + +* AprĂšs avoir compris la question, vous pouvez leur donner une **rĂ©ponse** possible. + +* Dans de nombreux cas, il est prĂ©fĂ©rable de comprendre leur **problĂšme sous‑jacent ou cas d'utilisation**, car il pourrait exister une meilleure façon de le rĂ©soudre que ce qu'ils essaient de faire. + +### Demander la clĂŽture { #ask-to-close } + +S'ils rĂ©pondent, il y a de fortes chances que vous ayez rĂ©solu leur problĂšme, bravo, **vous ĂȘtes un hĂ©ros** ! 🩾 + +* Maintenant, si cela a rĂ©solu leur problĂšme, vous pouvez leur demander de : + + * Dans GitHub Discussions : marquer le commentaire comme **rĂ©ponse**. + * Dans GitHub Issues : **fermer** l'issue. + +## Suivre le dĂ©pĂŽt GitHub { #watch-the-github-repository } + +Vous pouvez « watch » FastAPI sur GitHub (en cliquant sur le bouton « watch » en haut Ă  droite) : https://github.com/fastapi/fastapi. 👀 + +Si vous sĂ©lectionnez « Watching » au lieu de « Releases only », vous recevrez des notifications lorsque quelqu'un crĂ©e une nouvelle issue ou question. Vous pouvez aussi prĂ©ciser que vous ne souhaitez ĂȘtre notifiĂ© que pour les nouvelles issues, ou les discussions, ou les PR, etc. + +Vous pouvez alors essayer de les aider Ă  rĂ©soudre ces questions. + +## Poser des questions { #ask-questions } + +Vous pouvez crĂ©er une nouvelle question dans le dĂ©pĂŽt GitHub, par exemple pour : + +* Poser une **question** ou demander Ă  propos d'un **problĂšme**. +* SuggĂ©rer une nouvelle **fonctionnalitĂ©**. + +**Remarque** : si vous le faites, je vais vous demander d'aider aussi les autres. 😉 + +## Relire des Pull Requests { #review-pull-requests } + +Vous pouvez m'aider Ă  relire les pull requests des autres. + +Encore une fois, essayez autant que possible d'ĂȘtre aimable. đŸ€— + +--- + +Voici ce Ă  garder Ă  l'esprit et comment relire une pull request : + +### Comprendre le problĂšme { #understand-the-problem } + +* D'abord, assurez‑vous de **comprendre le problĂšme** que la pull request essaie de rĂ©soudre. Il peut y avoir une discussion plus longue dans une GitHub Discussion ou une issue. + +* Il y a aussi de bonnes chances que la pull request ne soit pas rĂ©ellement nĂ©cessaire parce que le problĂšme peut ĂȘtre rĂ©solu d'une **autre maniĂšre**. Vous pouvez alors le suggĂ©rer ou poser la question. + +### Ne pas s'inquiĂ©ter du style { #dont-worry-about-style } + +* Ne vous souciez pas trop des choses comme les styles de messages de commit, je ferai un squash and merge en personnalisant le commit manuellement. + +* Ne vous inquiĂ©tez pas non plus des rĂšgles de style, il existe dĂ©jĂ  des outils automatisĂ©s qui vĂ©rifient cela. + +Et s'il y a d'autres besoins de style ou de cohĂ©rence, je le demanderai directement, ou j'ajouterai des commits par‑dessus avec les changements nĂ©cessaires. + +### VĂ©rifier le code { #check-the-code } + +* VĂ©rifiez et lisez le code, voyez s'il a du sens, **exĂ©cutez‑le localement** et voyez s'il rĂ©sout effectivement le problĂšme. + +* Ensuite, **commentez** en disant que vous l'avez fait, c'est ainsi que je saurai que vous l'avez vraiment vĂ©rifiĂ©. + +/// info + +Malheureusement, je ne peux pas simplement faire confiance aux PR qui ont juste plusieurs approbations. + +Plusieurs fois, il est arrivĂ© qu'il y ait des PR avec 3, 5 ou plus approbations, probablement parce que la description est attrayante, mais lorsque je vĂ©rifie les PR, elles sont en fait cassĂ©es, ont un bug, ou ne rĂ©solvent pas le problĂšme qu'elles prĂ©tendent rĂ©soudre. 😅 + +Donc, il est vraiment important que vous lisiez et exĂ©cutiez le code, et que vous me le disiez dans les commentaires. đŸ€“ + +/// + +* Si la PR peut ĂȘtre simplifiĂ©e d'une certaine maniĂšre, vous pouvez le demander, mais il n'est pas nĂ©cessaire d'ĂȘtre trop pointilleux, il peut y avoir beaucoup de points de vue subjectifs (et j'aurai les miens aussi 🙈), donc il est prĂ©fĂ©rable de vous concentrer sur les choses fondamentales. + +### Tests { #tests } + +* Aidez‑moi Ă  vĂ©rifier que la PR a des **tests**. + +* VĂ©rifiez que les tests **Ă©chouent** avant la PR. 🚹 + +* Puis vĂ©rifiez que les tests **rĂ©ussissent** aprĂšs la PR. ✅ + +* Beaucoup de PR n'ont pas de tests, vous pouvez leur **rappeler** d'ajouter des tests, ou mĂȘme **suggĂ©rer** des tests vous‑mĂȘme. C'est l'une des choses qui consomment le plus de temps et vous pouvez beaucoup aider. + +* Commentez aussi ce que vous avez essayĂ©, ainsi je saurai que vous l'avez vĂ©rifiĂ©. đŸ€“ + +## CrĂ©er une Pull Request { #create-a-pull-request } + +Vous pouvez [contribuer](contributing.md){.internal-link target=_blank} au code source avec des Pull Requests, par exemple : + +* Corriger une coquille que vous avez trouvĂ©e dans la documentation. +* Partager un article, une vidĂ©o ou un podcast que vous avez créé ou trouvĂ© Ă  propos de FastAPI en modifiant ce fichier. + * Vous devez vous assurer d'ajouter votre lien au dĂ©but de la section correspondante. +* Aider Ă  [traduire la documentation](contributing.md#translations){.internal-link target=_blank} dans votre langue. + * Vous pouvez aussi aider Ă  relire les traductions créées par d'autres. * Proposer de nouvelles sections de documentation. -* Pour corriger une Issue/Bug existant. -* Pour ajouter une nouvelle fonctionnalitĂ©. +* Corriger une issue/un bug existant. + * Vous devez ajouter des tests. +* Ajouter une nouvelle fonctionnalitĂ©. + * Vous devez ajouter des tests. + * Vous devez ajouter de la documentation si c'est pertinent. -## Parrainer l'auteur +## Aider Ă  maintenir FastAPI { #help-maintain-fastapi } -Vous pouvez Ă©galement soutenir financiĂšrement l'auteur (moi) via GitHub sponsors. +Aidez‑moi Ă  maintenir **FastAPI** ! đŸ€“ -LĂ , vous pourriez m'offrir un cafĂ© ☕ pour me remercier 😄. +Il y a beaucoup de travail Ă  faire, et pour la plupart, **VOUS** pouvez le faire. -## Sponsoriser les outils qui font fonctionner FastAPI +Les principales tĂąches que vous pouvez faire dĂšs maintenant sont : -Comme vous l'avez vu dans la documentation, FastAPI se tient sur les Ă©paules des gĂ©ants, Starlette et Pydantic. +* [Aider les autres avec des questions sur GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (voir la section ci‑dessus). +* [Relire des Pull Requests](#review-pull-requests){.internal-link target=_blank} (voir la section ci‑dessus). -Vous pouvez Ă©galement parrainer : +Ces deux tĂąches sont celles qui **consomment le plus de temps**. C'est le travail principal de la maintenance de FastAPI. -* Samuel Colvin (Pydantic) -* Encode (Starlette, Uvicorn) +Si vous pouvez m'aider avec cela, **vous m'aidez Ă  maintenir FastAPI** et Ă  vous assurer qu'il continue **d'avancer plus vite et mieux**. 🚀 + +## Rejoindre le chat { #join-the-chat } + +Rejoignez le đŸ‘„ serveur Discord đŸ‘„ et Ă©changez avec d'autres membres de la communautĂ© FastAPI. + +/// tip | Astuce + +Pour les questions, posez‑les dans GitHub Discussions, vous avez bien plus de chances de recevoir de l'aide par les [Experts FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}. + +Utilisez le chat uniquement pour d'autres conversations gĂ©nĂ©rales. + +/// + +### N'utilisez pas le chat pour les questions { #dont-use-the-chat-for-questions } + +Gardez Ă  l'esprit que, comme les chats permettent une « conversation libre », il est facile de poser des questions trop gĂ©nĂ©rales et plus difficiles Ă  rĂ©pondre ; vous pourriez donc ne pas recevoir de rĂ©ponses. + +Sur GitHub, le modĂšle vous guidera pour rĂ©diger la bonne question afin que vous puissiez plus facilement obtenir une bonne rĂ©ponse, ou mĂȘme rĂ©soudre le problĂšme vous‑mĂȘme avant de demander. Et sur GitHub, je peux m'assurer de toujours tout rĂ©pondre, mĂȘme si cela prend du temps. Je ne peux pas personnellement faire cela avec les systĂšmes de chat. 😅 + +Les conversations dans les systĂšmes de chat ne sont pas non plus aussi facilement recherchables que sur GitHub, donc les questions et rĂ©ponses peuvent se perdre dans la conversation. Et seules celles sur GitHub comptent pour devenir un [Expert FastAPI](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, vous aurez donc trĂšs probablement plus d'attention sur GitHub. + +D'un autre cĂŽtĂ©, il y a des milliers d'utilisateurs dans les systĂšmes de chat, il y a donc de fortes chances que vous trouviez presque toujours quelqu'un avec qui parler. 😄 + +## Sponsoriser l'auteur { #sponsor-the-author } + +Si votre **produit/entreprise** dĂ©pend de **FastAPI** ou y est liĂ© et que vous souhaitez atteindre ses utilisateurs, vous pouvez sponsoriser l'auteur (moi) via GitHub sponsors. Selon le niveau, vous pourriez obtenir des avantages supplĂ©mentaires, comme un badge dans la documentation. 🎁 --- diff --git a/docs/fr/docs/history-design-future.md b/docs/fr/docs/history-design-future.md index 15be545ee..300f2e0f5 100644 --- a/docs/fr/docs/history-design-future.md +++ b/docs/fr/docs/history-design-future.md @@ -1,4 +1,4 @@ -# Histoire, conception et avenir +# Histoire, conception et avenir { #history-design-and-future } Il y a quelque temps, un utilisateur de **FastAPI** a demandĂ© : @@ -6,7 +6,7 @@ Il y a quelque temps, @@ -28,7 +28,7 @@ Mais Ă  un moment donnĂ©, il n'y avait pas d'autre option que de crĂ©er quelque -## Recherche +## Recherche { #investigation } En utilisant toutes les alternatives prĂ©cĂ©dentes, j'ai eu la chance d'apprendre de toutes, de prendre des idĂ©es, et de les combiner de la meilleure façon que j'ai pu trouver pour moi-mĂȘme et les Ă©quipes de dĂ©veloppeurs avec lesquelles j'ai travaillĂ©. @@ -38,9 +38,9 @@ De plus, la meilleure approche Ă©tait d'utiliser des normes dĂ©jĂ  existantes. Ainsi, avant mĂȘme de commencer Ă  coder **FastAPI**, j'ai passĂ© plusieurs mois Ă  Ă©tudier les spĂ©cifications d'OpenAPI, JSON Schema, OAuth2, etc. Comprendre leurs relations, leurs similaritĂ©s et leurs diffĂ©rences. -## Conception +## Conception { #design } -Ensuite, j'ai passĂ© du temps Ă  concevoir l'"API" de dĂ©veloppeur que je voulais avoir en tant qu'utilisateur (en tant que dĂ©veloppeur utilisant FastAPI). +Ensuite, j'ai passĂ© du temps Ă  concevoir l'« API » de dĂ©veloppeur que je voulais avoir en tant qu'utilisateur (en tant que dĂ©veloppeur utilisant FastAPI). J'ai testĂ© plusieurs idĂ©es dans les Ă©diteurs Python les plus populaires : PyCharm, VS Code, les Ă©diteurs basĂ©s sur Jedi. @@ -48,11 +48,11 @@ D'aprĂšs la derniĂšre **Pydantic** pour ses avantages. @@ -60,11 +60,11 @@ J'y ai ensuite contribuĂ©, pour le rendre entiĂšrement compatible avec JSON Sche Pendant le dĂ©veloppement, j'ai Ă©galement contribuĂ© Ă  **Starlette**, l'autre exigence clĂ©. -## DĂ©veloppement +## DĂ©veloppement { #development } Au moment oĂč j'ai commencĂ© Ă  crĂ©er **FastAPI** lui-mĂȘme, la plupart des piĂšces Ă©taient dĂ©jĂ  en place, la conception Ă©tait dĂ©finie, les exigences et les outils Ă©taient prĂȘts, et la connaissance des normes et des spĂ©cifications Ă©tait claire et fraĂźche. -## Futur +## Futur { #future } À ce stade, il est dĂ©jĂ  clair que **FastAPI** et ses idĂ©es sont utiles pour de nombreuses personnes. @@ -76,4 +76,4 @@ Mais il y a encore de nombreuses amĂ©liorations et fonctionnalitĂ©s Ă  venir. **FastAPI** a un grand avenir devant lui. -Et [votre aide](help-fastapi.md){.internal-link target=\_blank} est grandement apprĂ©ciĂ©e. +Et [votre aide](help-fastapi.md){.internal-link target=_blank} est grandement apprĂ©ciĂ©e. diff --git a/docs/fr/docs/how-to/authentication-error-status-code.md b/docs/fr/docs/how-to/authentication-error-status-code.md new file mode 100644 index 000000000..b8e87ee71 --- /dev/null +++ b/docs/fr/docs/how-to/authentication-error-status-code.md @@ -0,0 +1,17 @@ +# Utiliser les anciens codes d'erreur d'authentification 403 { #use-old-403-authentication-error-status-codes } + +Avant FastAPI version `0.122.0`, lorsque les utilitaires de sĂ©curitĂ© intĂ©grĂ©s renvoyaient une erreur au client aprĂšs un Ă©chec d'authentification, ils utilisaient le code d'Ă©tat HTTP `403 Forbidden`. + +À partir de FastAPI version `0.122.0`, ils utilisent le code d'Ă©tat HTTP plus appropriĂ© `401 Unauthorized`, et renvoient un en-tĂȘte `WWW-Authenticate` pertinent dans la rĂ©ponse, conformĂ©ment aux spĂ©cifications HTTP, RFC 7235, RFC 9110. + +Mais si, pour une raison quelconque, vos clients dĂ©pendent de l'ancien comportement, vous pouvez y revenir en surchargeant la mĂ©thode `make_not_authenticated_error` dans vos classes de sĂ©curitĂ©. + +Par exemple, vous pouvez crĂ©er une sous-classe de `HTTPBearer` qui renvoie une erreur `403 Forbidden` au lieu de l'erreur par dĂ©faut `401 Unauthorized` : + +{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *} + +/// tip | Astuce + +Remarquez que la fonction renvoie l'instance de l'exception, elle ne la lĂšve pas. La levĂ©e est effectuĂ©e dans le reste du code interne. + +/// diff --git a/docs/fr/docs/how-to/conditional-openapi.md b/docs/fr/docs/how-to/conditional-openapi.md new file mode 100644 index 000000000..61aa187cc --- /dev/null +++ b/docs/fr/docs/how-to/conditional-openapi.md @@ -0,0 +1,56 @@ +# Configurer OpenAPI de maniĂšre conditionnelle { #conditional-openapi } + +Si nĂ©cessaire, vous pouvez utiliser des paramĂštres et des variables d'environnement pour configurer OpenAPI de maniĂšre conditionnelle selon l'environnement, et mĂȘme le dĂ©sactiver complĂštement. + +## À propos de la sĂ©curitĂ©, des API et de la documentation { #about-security-apis-and-docs } + +Masquer vos interfaces utilisateur de la documentation en production ne devrait pas ĂȘtre la maniĂšre de protĂ©ger votre API. + +Cela n'ajoute aucune sĂ©curitĂ© supplĂ©mentaire Ă  votre API, les *chemins d'accĂšs* resteront disponibles lĂ  oĂč ils se trouvent. + +S'il y a une faille de sĂ©curitĂ© dans votre code, elle existera toujours. + +Masquer la documentation rend simplement plus difficile la comprĂ©hension de la maniĂšre d'interagir avec votre API et pourrait aussi rendre son dĂ©bogage en production plus difficile. Cela pourrait ĂȘtre considĂ©rĂ© simplement comme une forme de SĂ©curitĂ© par l'obscuritĂ©. + +Si vous voulez sĂ©curiser votre API, il y a plusieurs meilleures approches possibles, par exemple : + +* Vous devez vous assurer d'avoir des modĂšles Pydantic bien dĂ©finis pour le corps de la requĂȘte et la rĂ©ponse. +* Configurez toutes les autorisations et tous les rĂŽles nĂ©cessaires Ă  l'aide de dĂ©pendances. +* Ne stockez jamais de mots de passe en clair, seulement des hachages de mots de passe. +* ImplĂ©mentez et utilisez des outils cryptographiques reconnus, comme pwdlib et des jetons JWT, ... etc. +* Ajoutez des contrĂŽles d'autorisation plus granulaires avec des scopes OAuth2 lorsque nĂ©cessaire. +* ... etc. + +NĂ©anmoins, vous pourriez avoir un cas d'utilisation trĂšs spĂ©cifique oĂč vous devez vraiment dĂ©sactiver la documentation de l'API pour un certain environnement (par exemple pour la production) ou selon des configurations provenant de variables d'environnement. + +## Configurer OpenAPI de maniĂšre conditionnelle avec des paramĂštres et des variables d'environnement { #conditional-openapi-from-settings-and-env-vars } + +Vous pouvez facilement utiliser les mĂȘmes paramĂštres Pydantic pour configurer votre OpenAPI gĂ©nĂ©rĂ© et les interfaces utilisateur de la documentation. + +Par exemple : + +{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *} + +Ici nous dĂ©clarons le paramĂštre `openapi_url` avec la mĂȘme valeur par dĂ©faut `"/openapi.json"`. + +Nous l'utilisons ensuite lors de la crĂ©ation de l'application `FastAPI`. + +Vous pouvez alors dĂ©sactiver OpenAPI (y compris les interfaces utilisateur de la documentation) en dĂ©finissant la variable d'environnement `OPENAPI_URL` sur la chaĂźne vide, comme ceci : + +
+ +```console +$ OPENAPI_URL= uvicorn main:app + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Ensuite, si vous allez aux URL `/openapi.json`, `/docs` ou `/redoc`, vous obtiendrez simplement une erreur `404 Not Found` comme : + +```JSON +{ + "detail": "Not Found" +} +``` diff --git a/docs/fr/docs/how-to/configure-swagger-ui.md b/docs/fr/docs/how-to/configure-swagger-ui.md new file mode 100644 index 000000000..73d0f00e8 --- /dev/null +++ b/docs/fr/docs/how-to/configure-swagger-ui.md @@ -0,0 +1,70 @@ +# Configurer Swagger UI { #configure-swagger-ui } + +Vous pouvez configurer des paramĂštres supplĂ©mentaires de Swagger UI. + +Pour les configurer, passez l'argument `swagger_ui_parameters` lors de la crĂ©ation de l'objet d'application `FastAPI()` ou Ă  la fonction `get_swagger_ui_html()`. + +`swagger_ui_parameters` reçoit un dictionnaire avec les configurations passĂ©es directement Ă  Swagger UI. + +FastAPI convertit les configurations en **JSON** pour les rendre compatibles avec JavaScript, car c'est ce dont Swagger UI a besoin. + +## DĂ©sactiver la coloration syntaxique { #disable-syntax-highlighting } + +Par exemple, vous pourriez dĂ©sactiver la coloration syntaxique dans Swagger UI. + +Sans modifier les paramĂštres, la coloration syntaxique est activĂ©e par dĂ©faut : + + + +Mais vous pouvez la dĂ©sactiver en dĂ©finissant `syntaxHighlight` Ă  `False` : + +{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *} + +... et ensuite Swagger UI n'affichera plus la coloration syntaxique : + + + +## Modifier le thĂšme { #change-the-theme } + +De la mĂȘme maniĂšre, vous pouvez dĂ©finir le thĂšme de la coloration syntaxique avec la clĂ© « syntaxHighlight.theme » (remarquez le point au milieu) : + +{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *} + +Cette configuration modifierait le thĂšme de couleurs de la coloration syntaxique : + + + +## Modifier les paramĂštres Swagger UI par dĂ©faut { #change-default-swagger-ui-parameters } + +FastAPI inclut des paramĂštres de configuration par dĂ©faut adaptĂ©s Ă  la plupart des cas d'utilisation. + +Il inclut ces configurations par dĂ©faut : + +{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *} + +Vous pouvez remplacer n'importe lequel d'entre eux en dĂ©finissant une valeur diffĂ©rente dans l'argument `swagger_ui_parameters`. + +Par exemple, pour dĂ©sactiver `deepLinking`, vous pourriez passer ces paramĂštres Ă  `swagger_ui_parameters` : + +{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *} + +## Autres paramĂštres de Swagger UI { #other-swagger-ui-parameters } + +Pour voir toutes les autres configurations possibles que vous pouvez utiliser, lisez la documentation officielle des paramĂštres de Swagger UI. + +## ParamĂštres JavaScript uniquement { #javascript-only-settings } + +Swagger UI permet Ă©galement d'autres configurations qui sont des objets rĂ©servĂ©s Ă  JavaScript (par exemple, des fonctions JavaScript). + +FastAPI inclut aussi ces paramĂštres `presets` rĂ©servĂ©s Ă  JavaScript : + +```JavaScript +presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIBundle.SwaggerUIStandalonePreset +] +``` + +Ce sont des objets **JavaScript**, pas des chaĂźnes, vous ne pouvez donc pas les passer directement depuis du code Python. + +Si vous devez utiliser des configurations rĂ©servĂ©es Ă  JavaScript comme celles-ci, vous pouvez utiliser l'une des mĂ©thodes ci-dessus. Surchargez entiĂšrement le *chemin d'accĂšs* Swagger UI et Ă©crivez manuellement tout JavaScript nĂ©cessaire. diff --git a/docs/fr/docs/how-to/custom-docs-ui-assets.md b/docs/fr/docs/how-to/custom-docs-ui-assets.md new file mode 100644 index 000000000..d239a9696 --- /dev/null +++ b/docs/fr/docs/how-to/custom-docs-ui-assets.md @@ -0,0 +1,185 @@ +# HĂ©berger en propre les ressources statiques de l’UI des docs personnalisĂ©es { #custom-docs-ui-static-assets-self-hosting } + +Les documents de l’API utilisent **Swagger UI** et **ReDoc**, et chacune nĂ©cessite des fichiers JavaScript et CSS. + +Par dĂ©faut, ces fichiers sont servis depuis un CDN. + +Mais il est possible de le personnaliser : vous pouvez dĂ©finir un CDN spĂ©cifique, ou servir vous‑mĂȘme les fichiers. + +## Configurer un CDN personnalisĂ© pour JavaScript et CSS { #custom-cdn-for-javascript-and-css } + +Supposons que vous souhaitiez utiliser un autre CDN, par exemple vous voulez utiliser `https://unpkg.com/`. + +Cela peut ĂȘtre utile si, par exemple, vous vivez dans un pays qui restreint certaines URL. + +### DĂ©sactiver les docs automatiques { #disable-the-automatic-docs } + +La premiĂšre Ă©tape consiste Ă  dĂ©sactiver les docs automatiques, car par dĂ©faut elles utilisent le CDN par dĂ©faut. + +Pour les dĂ©sactiver, dĂ©finissez leurs URL sur `None` lors de la crĂ©ation de votre application `FastAPI` : + +{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *} + +### Inclure les docs personnalisĂ©es { #include-the-custom-docs } + +Vous pouvez maintenant crĂ©er les chemins d'accĂšs pour les docs personnalisĂ©es. + +Vous pouvez rĂ©utiliser les fonctions internes de FastAPI pour crĂ©er les pages HTML de la documentation et leur passer les arguments nĂ©cessaires : + +- `openapi_url` : l’URL oĂč la page HTML des docs peut rĂ©cupĂ©rer le schĂ©ma OpenAPI de votre API. Vous pouvez utiliser ici l’attribut `app.openapi_url`. +- `title` : le titre de votre API. +- `oauth2_redirect_url` : vous pouvez utiliser `app.swagger_ui_oauth2_redirect_url` ici pour utiliser la valeur par dĂ©faut. +- `swagger_js_url` : l’URL oĂč la page HTML de Swagger UI peut rĂ©cupĂ©rer le fichier **JavaScript**. C’est l’URL du CDN personnalisĂ©. +- `swagger_css_url` : l’URL oĂč la page HTML de Swagger UI peut rĂ©cupĂ©rer le fichier **CSS**. C’est l’URL du CDN personnalisĂ©. + +Et de mĂȘme pour ReDoc ... + +{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *} + +/// tip | Astuce + +Le chemin d'accĂšs pour `swagger_ui_redirect` est un assistant lorsque vous utilisez OAuth2. + +Si vous intĂ©grez votre API Ă  un fournisseur OAuth2, vous pourrez vous authentifier et revenir aux docs de l’API avec les identifiants acquis. Et interagir avec elle en utilisant la vĂ©ritable authentification OAuth2. + +Swagger UI s’en chargera en arriĂšre‑plan pour vous, mais il a besoin de cet assistant « redirect ». + +/// + +### CrĂ©er un chemin d'accĂšs pour tester { #create-a-path-operation-to-test-it } + +Maintenant, pour pouvoir vĂ©rifier que tout fonctionne, crĂ©ez un chemin d'accĂšs : + +{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *} + +### Tester { #test-it } + +Vous devriez maintenant pouvoir aller Ă  vos docs sur http://127.0.0.1:8000/docs, puis recharger la page : elle chargera ces ressources depuis le nouveau CDN. + +## HĂ©berger en propre JavaScript et CSS pour les docs { #self-hosting-javascript-and-css-for-docs } + +HĂ©berger vous‑mĂȘme le JavaScript et le CSS peut ĂȘtre utile si, par exemple, votre application doit continuer de fonctionner mĂȘme hors ligne, sans accĂšs Internet ouvert, ou sur un rĂ©seau local. + +Vous verrez ici comment servir ces fichiers vous‑mĂȘme, dans la mĂȘme application FastAPI, et configurer les docs pour les utiliser. + +### Structure des fichiers du projet { #project-file-structure } + +Supposons que la structure de vos fichiers de projet ressemble Ă  ceci : + +``` +. +├── app +│ ├── __init__.py +│ ├── main.py +``` + +CrĂ©ez maintenant un rĂ©pertoire pour stocker ces fichiers statiques. + +Votre nouvelle structure de fichiers pourrait ressembler Ă  ceci : + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +└── static/ +``` + +### TĂ©lĂ©charger les fichiers { #download-the-files } + +TĂ©lĂ©chargez les fichiers statiques nĂ©cessaires aux docs et placez‑les dans ce rĂ©pertoire `static/`. + +Vous pouvez probablement cliquer avec le bouton droit sur chaque lien et choisir une option similaire Ă  « Enregistrer le lien sous ... ». + +**Swagger UI** utilise les fichiers : + +- `swagger-ui-bundle.js` +- `swagger-ui.css` + +Et **ReDoc** utilise le fichier : + +- `redoc.standalone.js` + +AprĂšs cela, votre structure de fichiers pourrait ressembler Ă  : + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +└── static + ├── redoc.standalone.js + ├── swagger-ui-bundle.js + └── swagger-ui.css +``` + +### Servir les fichiers statiques { #serve-the-static-files } + +- Importer `StaticFiles`. +- « Monter » une instance `StaticFiles()` sur un chemin spĂ©cifique. + +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *} + +### Tester les fichiers statiques { #test-the-static-files } + +DĂ©marrez votre application et rendez‑vous sur http://127.0.0.1:8000/static/redoc.standalone.js. + +Vous devriez voir un trĂšs long fichier JavaScript pour **ReDoc**. + +Il pourrait commencer par quelque chose comme : + +```JavaScript +/*! For license information please see redoc.standalone.js.LICENSE.txt */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")): +... +``` + +Cela confirme que vous parvenez Ă  servir des fichiers statiques depuis votre application et que vous avez placĂ© les fichiers statiques des docs au bon endroit. + +Nous pouvons maintenant configurer l’application pour utiliser ces fichiers statiques pour les docs. + +### DĂ©sactiver les docs automatiques pour les fichiers statiques { #disable-the-automatic-docs-for-static-files } + +Comme lors de l’utilisation d’un CDN personnalisĂ©, la premiĂšre Ă©tape consiste Ă  dĂ©sactiver les docs automatiques, car elles utilisent un CDN par dĂ©faut. + +Pour les dĂ©sactiver, dĂ©finissez leurs URL sur `None` lors de la crĂ©ation de votre application `FastAPI` : + +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *} + +### Inclure les docs personnalisĂ©es pour les fichiers statiques { #include-the-custom-docs-for-static-files } + +Et comme avec un CDN personnalisĂ©, vous pouvez maintenant crĂ©er les chemins d'accĂšs pour les docs personnalisĂ©es. + +LĂ  encore, vous pouvez rĂ©utiliser les fonctions internes de FastAPI pour crĂ©er les pages HTML de la documentation et leur passer les arguments nĂ©cessaires : + +- `openapi_url` : l’URL oĂč la page HTML des docs peut rĂ©cupĂ©rer le schĂ©ma OpenAPI de votre API. Vous pouvez utiliser ici l’attribut `app.openapi_url`. +- `title` : le titre de votre API. +- `oauth2_redirect_url` : vous pouvez utiliser `app.swagger_ui_oauth2_redirect_url` ici pour utiliser la valeur par dĂ©faut. +- `swagger_js_url` : l’URL oĂč la page HTML de Swagger UI peut rĂ©cupĂ©rer le fichier **JavaScript**. **C’est celui que votre propre application sert dĂ©sormais**. +- `swagger_css_url` : l’URL oĂč la page HTML de Swagger UI peut rĂ©cupĂ©rer le fichier **CSS**. **C’est celui que votre propre application sert dĂ©sormais**. + +Et de mĂȘme pour ReDoc ... + +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *} + +/// tip | Astuce + +Le chemin d'accĂšs pour `swagger_ui_redirect` est un assistant lorsque vous utilisez OAuth2. + +Si vous intĂ©grez votre API Ă  un fournisseur OAuth2, vous pourrez vous authentifier et revenir aux docs de l’API avec les identifiants acquis. Et interagir avec elle en utilisant la vĂ©ritable authentification OAuth2. + +Swagger UI s’en chargera en arriĂšre‑plan pour vous, mais il a besoin de cet assistant « redirect ». + +/// + +### CrĂ©er un chemin d'accĂšs pour tester les fichiers statiques { #create-a-path-operation-to-test-static-files } + +Maintenant, pour pouvoir vĂ©rifier que tout fonctionne, crĂ©ez un chemin d'accĂšs : + +{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *} + +### Tester l’UI avec des fichiers statiques { #test-static-files-ui } + +Vous devriez maintenant pouvoir couper votre Wi‑Fi, aller Ă  vos docs sur http://127.0.0.1:8000/docs et recharger la page. + +Et mĂȘme sans Internet, vous pourrez voir la documentation de votre API et interagir avec elle. diff --git a/docs/fr/docs/how-to/custom-request-and-route.md b/docs/fr/docs/how-to/custom-request-and-route.md new file mode 100644 index 000000000..506187d9f --- /dev/null +++ b/docs/fr/docs/how-to/custom-request-and-route.md @@ -0,0 +1,109 @@ +# Personnaliser les classes Request et APIRoute { #custom-request-and-apiroute-class } + +Dans certains cas, vous pouvez vouloir surcharger la logique utilisĂ©e par les classes `Request` et `APIRoute`. + +En particulier, cela peut ĂȘtre une bonne alternative Ă  une logique dans un middleware. + +Par exemple, si vous voulez lire ou manipuler le corps de la requĂȘte avant qu'il ne soit traitĂ© par votre application. + +/// danger | Danger + +Ceci est une fonctionnalitĂ© « avancĂ©e ». + +Si vous dĂ©butez avec **FastAPI**, vous pouvez ignorer cette section. + +/// + +## Cas d'utilisation { #use-cases } + +Voici quelques cas d'utilisation : + +* Convertir des corps de requĂȘte non JSON en JSON (par exemple `msgpack`). +* DĂ©compresser des corps de requĂȘte compressĂ©s en gzip. +* Journaliser automatiquement tous les corps de requĂȘte. + +## GĂ©rer les encodages personnalisĂ©s du corps de la requĂȘte { #handling-custom-request-body-encodings } + +Voyons comment utiliser une sous-classe personnalisĂ©e de `Request` pour dĂ©compresser des requĂȘtes gzip. + +Et une sous-classe d'`APIRoute` pour utiliser cette classe de requĂȘte personnalisĂ©e. + +### CrĂ©er une classe `GzipRequest` personnalisĂ©e { #create-a-custom-gziprequest-class } + +/// tip | Astuce + +Il s'agit d'un exemple simplifiĂ© pour montrer le fonctionnement ; si vous avez besoin de la prise en charge de Gzip, vous pouvez utiliser le [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank} fourni. + +/// + +Commencez par crĂ©er une classe `GzipRequest`, qui va surcharger la mĂ©thode `Request.body()` pour dĂ©compresser le corps en prĂ©sence d'un en-tĂȘte appropriĂ©. + +S'il n'y a pas `gzip` dans l'en-tĂȘte, elle n'essaiera pas de dĂ©compresser le corps. + +De cette maniĂšre, la mĂȘme classe de route peut gĂ©rer des requĂȘtes gzip compressĂ©es ou non compressĂ©es. + +{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *} + +### CrĂ©er une classe `GzipRoute` personnalisĂ©e { #create-a-custom-gziproute-class } + +Ensuite, nous crĂ©ons une sous-classe personnalisĂ©e de `fastapi.routing.APIRoute` qui utilisera `GzipRequest`. + +Cette fois, elle va surcharger la mĂ©thode `APIRoute.get_route_handler()`. + +Cette mĂ©thode renvoie une fonction. Et c'est cette fonction qui recevra une requĂȘte et retournera une rĂ©ponse. + +Ici, nous l'utilisons pour crĂ©er une `GzipRequest` Ă  partir de la requĂȘte originale. + +{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *} + +/// note | DĂ©tails techniques + +Un `Request` possĂšde un attribut `request.scope`, qui n'est qu'un `dict` Python contenant les mĂ©tadonnĂ©es liĂ©es Ă  la requĂȘte. + +Un `Request` a Ă©galement un `request.receive`, qui est une fonction pour « recevoir » le corps de la requĂȘte. + +Le `dict` `scope` et la fonction `receive` font tous deux partie de la spĂ©cification ASGI. + +Et ces deux Ă©lĂ©ments, `scope` et `receive`, sont ce dont on a besoin pour crĂ©er une nouvelle instance de `Request`. + +Pour en savoir plus sur `Request`, consultez la documentation de Starlette sur les requĂȘtes. + +/// + +La seule chose que fait diffĂ©remment la fonction renvoyĂ©e par `GzipRequest.get_route_handler`, c'est de convertir la `Request` en `GzipRequest`. + +Ce faisant, notre `GzipRequest` se chargera de dĂ©compresser les donnĂ©es (si nĂ©cessaire) avant de les transmettre Ă  nos *chemins d'accĂšs*. + +AprĂšs cela, toute la logique de traitement est identique. + +Mais grĂące Ă  nos modifications dans `GzipRequest.body`, le corps de la requĂȘte sera automatiquement dĂ©compressĂ© lorsque **FastAPI** le chargera, si nĂ©cessaire. + +## AccĂ©der au corps de la requĂȘte dans un gestionnaire d'exceptions { #accessing-the-request-body-in-an-exception-handler } + +/// tip | Astuce + +Pour rĂ©soudre ce mĂȘme problĂšme, il est probablement beaucoup plus simple d'utiliser `body` dans un gestionnaire personnalisĂ© pour `RequestValidationError` ([GĂ©rer les erreurs](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}). + +Mais cet exemple reste valable et montre comment interagir avec les composants internes. + +/// + +Nous pouvons Ă©galement utiliser cette mĂȘme approche pour accĂ©der au corps de la requĂȘte dans un gestionnaire d'exceptions. + +Il suffit de traiter la requĂȘte dans un bloc `try`/`except` : + +{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *} + +Si une exception se produit, l'instance de `Request` sera toujours dans la portĂ©e, ce qui nous permet de lire et d'utiliser le corps de la requĂȘte lors du traitement de l'erreur : + +{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *} + +## Utiliser une classe `APIRoute` personnalisĂ©e dans un routeur { #custom-apiroute-class-in-a-router } + +Vous pouvez Ă©galement dĂ©finir le paramĂštre `route_class` d'un `APIRouter` : + +{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *} + +Dans cet exemple, les *chemins d'accĂšs* sous le `router` utiliseront la classe personnalisĂ©e `TimedRoute`, et auront un en-tĂȘte supplĂ©mentaire `X-Response-Time` dans la rĂ©ponse avec le temps nĂ©cessaire pour gĂ©nĂ©rer la rĂ©ponse : + +{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *} diff --git a/docs/fr/docs/how-to/extending-openapi.md b/docs/fr/docs/how-to/extending-openapi.md new file mode 100644 index 000000000..1c540ea6c --- /dev/null +++ b/docs/fr/docs/how-to/extending-openapi.md @@ -0,0 +1,80 @@ +# Étendre OpenAPI { #extending-openapi } + +Il existe des cas oĂč vous pouvez avoir besoin de modifier le schĂ©ma OpenAPI gĂ©nĂ©rĂ©. + +Dans cette section, vous verrez comment faire. + +## Le processus normal { #the-normal-process } + +Le processus normal (par dĂ©faut) est le suivant. + +Une application (instance) `FastAPI` a une mĂ©thode `.openapi()` censĂ©e retourner le schĂ©ma OpenAPI. + +Lors de la crĂ©ation de l'objet application, un *chemin d'accĂšs* pour `/openapi.json` (ou pour l'URL que vous avez dĂ©finie dans votre `openapi_url`) est enregistrĂ©. + +Il renvoie simplement une rĂ©ponse JSON avec le rĂ©sultat de la mĂ©thode `.openapi()` de l'application. + +Par dĂ©faut, la mĂ©thode `.openapi()` vĂ©rifie la propriĂ©tĂ© `.openapi_schema` pour voir si elle contient des donnĂ©es et les renvoie. + +Sinon, elle les gĂ©nĂšre Ă  l'aide de la fonction utilitaire `fastapi.openapi.utils.get_openapi`. + +Et cette fonction `get_openapi()` reçoit comme paramĂštres : + +* `title` : Le titre OpenAPI, affichĂ© dans les documents. +* `version` : La version de votre API, p. ex. `2.5.0`. +* `openapi_version` : La version de la spĂ©cification OpenAPI utilisĂ©e. Par dĂ©faut, la plus rĂ©cente : `3.1.0`. +* `summary` : Un court rĂ©sumĂ© de l'API. +* `description` : La description de votre API ; elle peut inclure du markdown et sera affichĂ©e dans la documentation. +* `routes` : Une liste de routes ; chacune correspond Ă  un *chemin d'accĂšs* enregistrĂ©. Elles sont extraites de `app.routes`. + +/// info + +Le paramĂštre `summary` est disponible Ă  partir d'OpenAPI 3.1.0, pris en charge par FastAPI 0.99.0 et versions ultĂ©rieures. + +/// + +## Remplacer les valeurs par dĂ©faut { #overriding-the-defaults } + +En vous appuyant sur les informations ci-dessus, vous pouvez utiliser la mĂȘme fonction utilitaire pour gĂ©nĂ©rer le schĂ©ma OpenAPI et remplacer chaque partie dont vous avez besoin. + +Par exemple, ajoutons l’extension OpenAPI de ReDoc pour inclure un logo personnalisĂ©. + +### **FastAPI** normal { #normal-fastapi } + +Tout d’abord, Ă©crivez votre application **FastAPI** comme d’habitude : + +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *} + +### GĂ©nĂ©rer le schĂ©ma OpenAPI { #generate-the-openapi-schema } + +Ensuite, utilisez la mĂȘme fonction utilitaire pour gĂ©nĂ©rer le schĂ©ma OpenAPI, dans une fonction `custom_openapi()` : + +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *} + +### Modifier le schĂ©ma OpenAPI { #modify-the-openapi-schema } + +Vous pouvez maintenant ajouter l’extension ReDoc, en ajoutant un `x-logo` personnalisĂ© Ă  l’« objet » `info` dans le schĂ©ma OpenAPI : + +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *} + +### Mettre en cache le schĂ©ma OpenAPI { #cache-the-openapi-schema } + +Vous pouvez utiliser la propriĂ©tĂ© `.openapi_schema` comme « cache » pour stocker votre schĂ©ma gĂ©nĂ©rĂ©. + +Ainsi, votre application n’aura pas Ă  gĂ©nĂ©rer le schĂ©ma Ă  chaque fois qu’un utilisateur ouvre les documents de votre API. + +Il ne sera gĂ©nĂ©rĂ© qu’une seule fois, puis le mĂȘme schĂ©ma en cache sera utilisĂ© pour les requĂȘtes suivantes. + +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *} + +### Remplacer la mĂ©thode { #override-the-method } + +Vous pouvez maintenant remplacer la mĂ©thode `.openapi()` par votre nouvelle fonction. + +{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *} + +### VĂ©rifier { #check-it } + +Une fois que vous allez sur http://127.0.0.1:8000/redoc, vous verrez que vous utilisez votre logo personnalisĂ© (dans cet exemple, le logo de **FastAPI**) : + + diff --git a/docs/fr/docs/how-to/general.md b/docs/fr/docs/how-to/general.md new file mode 100644 index 000000000..09d4498ac --- /dev/null +++ b/docs/fr/docs/how-to/general.md @@ -0,0 +1,39 @@ +# GĂ©nĂ©ral - Guides pratiques - Recettes { #general-how-to-recipes } + +Voici plusieurs renvois vers d'autres endroits de la documentation, pour des questions gĂ©nĂ©rales ou frĂ©quentes. + +## Filtrer des donnĂ©es - SĂ©curitĂ© { #filter-data-security } + +Pour vous assurer que vous ne renvoyez pas plus de donnĂ©es que nĂ©cessaire, lisez la documentation [Tutoriel - ModĂšle de rĂ©ponse - Type de retour](../tutorial/response-model.md){.internal-link target=_blank}. + +## Étiquettes de documentation - OpenAPI { #documentation-tags-openapi } + +Pour ajouter des Ă©tiquettes Ă  vos *chemins d'accĂšs* et les regrouper dans l'interface utilisateur de la documentation, lisez la documentation [Tutoriel - Configurations de chemin d'accĂšs - Tags](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}. + +## RĂ©sumĂ© et description de la documentation - OpenAPI { #documentation-summary-and-description-openapi } + +Pour ajouter un rĂ©sumĂ© et une description Ă  vos *chemins d'accĂšs* et les afficher dans l'interface utilisateur de la documentation, lisez la documentation [Tutoriel - Configurations de chemin d'accĂšs - RĂ©sumĂ© et description](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}. + +## Description de la rĂ©ponse dans la documentation - OpenAPI { #documentation-response-description-openapi } + +Pour dĂ©finir la description de la rĂ©ponse, affichĂ©e dans l'interface utilisateur de la documentation, lisez la documentation [Tutoriel - Configurations de chemin d'accĂšs - Description de la rĂ©ponse](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}. + +## DĂ©prĂ©cier un *chemin d'accĂšs* dans la documentation - OpenAPI { #documentation-deprecate-a-path-operation-openapi } + +Pour dĂ©prĂ©cier un *chemin d'accĂšs* et l'indiquer dans l'interface utilisateur de la documentation, lisez la documentation [Tutoriel - Configurations de chemin d'accĂšs - DĂ©prĂ©cier un chemin d'accĂšs](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}. + +## Convertir n'importe quelles donnĂ©es au format compatible JSON { #convert-any-data-to-json-compatible } + +Pour convertir des donnĂ©es vers un format compatible JSON, lisez la documentation [Tutoriel - Encodeur compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}. + +## MĂ©tadonnĂ©es OpenAPI - Documentation { #openapi-metadata-docs } + +Pour ajouter des mĂ©tadonnĂ©es Ă  votre schĂ©ma OpenAPI, y compris une licence, une version, un contact, etc., lisez la documentation [Tutoriel - MĂ©tadonnĂ©es et URLs de la documentation](../tutorial/metadata.md){.internal-link target=_blank}. + +## URL OpenAPI personnalisĂ©e { #openapi-custom-url } + +Pour personnaliser l'URL OpenAPI (ou la supprimer), lisez la documentation [Tutoriel - MĂ©tadonnĂ©es et URLs de la documentation](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}. + +## URL de la documentation OpenAPI { #openapi-docs-urls } + +Pour mettre Ă  jour les URL utilisĂ©es pour les interfaces utilisateur de documentation gĂ©nĂ©rĂ©es automatiquement, lisez la documentation [Tutoriel - MĂ©tadonnĂ©es et URLs de la documentation](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}. diff --git a/docs/fr/docs/how-to/graphql.md b/docs/fr/docs/how-to/graphql.md new file mode 100644 index 000000000..59cd1590f --- /dev/null +++ b/docs/fr/docs/how-to/graphql.md @@ -0,0 +1,60 @@ +# GraphQL { #graphql } + +Comme **FastAPI** est basĂ© sur la norme **ASGI**, il est trĂšs facile d'intĂ©grer toute bibliothĂšque **GraphQL** Ă©galement compatible avec ASGI. + +Vous pouvez combiner des *chemins d'accĂšs* FastAPI classiques avec GraphQL dans la mĂȘme application. + +/// tip | Astuce + +**GraphQL** rĂ©sout des cas d'utilisation trĂšs spĂ©cifiques. + +Il prĂ©sente des **avantages** et des **inconvĂ©nients** par rapport aux **API web** classiques. + +Assurez-vous d'Ă©valuer si les **bĂ©nĂ©fices** pour votre cas d'utilisation compensent les **inconvĂ©nients**. đŸ€“ + +/// + +## BibliothĂšques GraphQL { #graphql-libraries } + +Voici quelques bibliothĂšques **GraphQL** qui prennent en charge **ASGI**. Vous pouvez les utiliser avec **FastAPI** : + +* Strawberry 🍓 + * Avec la documentation pour FastAPI +* Ariadne + * Avec la documentation pour FastAPI +* Tartiflette + * Avec Tartiflette ASGI pour fournir l'intĂ©gration ASGI +* Graphene + * Avec starlette-graphene3 + +## GraphQL avec Strawberry { #graphql-with-strawberry } + +Si vous avez besoin ou souhaitez travailler avec **GraphQL**, **Strawberry** est la bibliothĂšque **recommandĂ©e** car sa conception est la plus proche de celle de **FastAPI**, tout est basĂ© sur des **annotations de type**. + +Selon votre cas d'utilisation, vous pourriez prĂ©fĂ©rer une autre bibliothĂšque, mais si vous me le demandiez, je vous suggĂ©rerais probablement d'essayer **Strawberry**. + +Voici un petit aperçu de la maniĂšre dont vous pouvez intĂ©grer Strawberry avec FastAPI : + +{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *} + +Vous pouvez en apprendre davantage sur Strawberry dans la documentation de Strawberry. + +Et Ă©galement la documentation sur Strawberry avec FastAPI. + +## Ancien `GraphQLApp` de Starlette { #older-graphqlapp-from-starlette } + +Les versions prĂ©cĂ©dentes de Starlette incluaient une classe `GraphQLApp` pour s'intĂ©grer Ă  Graphene. + +Elle a Ă©tĂ© dĂ©prĂ©ciĂ©e dans Starlette, mais si vous avez du code qui l'utilisait, vous pouvez facilement **migrer** vers starlette-graphene3, qui couvre le mĂȘme cas d'utilisation et propose une **interface presque identique**. + +/// tip | Astuce + +Si vous avez besoin de GraphQL, je vous recommande tout de mĂȘme de regarder Strawberry, car il est basĂ© sur des annotations de type plutĂŽt que sur des classes et types personnalisĂ©s. + +/// + +## En savoir plus { #learn-more } + +Vous pouvez en apprendre davantage sur **GraphQL** dans la documentation officielle de GraphQL. + +Vous pouvez Ă©galement en lire davantage sur chacune des bibliothĂšques dĂ©crites ci-dessus via leurs liens. diff --git a/docs/fr/docs/how-to/index.md b/docs/fr/docs/how-to/index.md new file mode 100644 index 000000000..03736fa43 --- /dev/null +++ b/docs/fr/docs/how-to/index.md @@ -0,0 +1,13 @@ +# Comment faire - Recettes { #how-to-recipes } + +Vous trouverez ici diffĂ©rentes recettes ou des guides « comment faire » pour **plusieurs sujets**. + +La plupart de ces idĂ©es sont plus ou moins **indĂ©pendantes**, et dans la plupart des cas vous n'avez besoin de les Ă©tudier que si elles s'appliquent directement Ă  **votre projet**. + +Si quelque chose vous paraĂźt intĂ©ressant et utile pour votre projet, allez-y et consultez-le ; sinon, vous pouvez probablement simplement les ignorer. + +/// tip | Astuce + +Si vous voulez **apprendre FastAPI** de façon structurĂ©e (recommandĂ©), allez lire le [Tutoriel - Guide utilisateur](../tutorial/index.md){.internal-link target=_blank} chapitre par chapitre Ă  la place. + +/// diff --git a/docs/fr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/fr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md new file mode 100644 index 000000000..681cf697b --- /dev/null +++ b/docs/fr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md @@ -0,0 +1,135 @@ +# Migrer de Pydantic v1 Ă  Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 } + +Si vous avez une ancienne application FastAPI, vous utilisez peut-ĂȘtre Pydantic version 1. + +FastAPI version 0.100.0 prenait en charge soit Pydantic v1 soit v2. Il utilisait celle que vous aviez installĂ©e. + +FastAPI version 0.119.0 a introduit une prise en charge partielle de Pydantic v1 depuis l'intĂ©rieur de Pydantic v2 (comme `pydantic.v1`), pour faciliter la migration vers v2. + +FastAPI 0.126.0 a supprimĂ© la prise en charge de Pydantic v1, tout en continuant Ă  prendre en charge `pydantic.v1` pendant un certain temps. + +/// warning | Alertes + +L'Ă©quipe Pydantic a arrĂȘtĂ© la prise en charge de Pydantic v1 pour les derniĂšres versions de Python, Ă  partir de Python 3.14. + +Cela inclut `pydantic.v1`, qui n'est plus pris en charge Ă  partir de Python 3.14. + +Si vous souhaitez utiliser les derniĂšres fonctionnalitĂ©s de Python, vous devez vous assurer que vous utilisez Pydantic v2. + +/// + +Si vous avez une ancienne application FastAPI avec Pydantic v1, je vais vous montrer comment la migrer vers Pydantic v2, et les fonctionnalitĂ©s de FastAPI 0.119.0 pour vous aider Ă  une migration progressive. + +## Guide officiel { #official-guide } + +Pydantic propose un Guide de migration officiel de la v1 Ă  la v2. + +Il inclut aussi ce qui a changĂ©, comment les validations sont dĂ©sormais plus correctes et strictes, les piĂšges possibles, etc. + +Vous pouvez le lire pour mieux comprendre ce qui a changĂ©. + +## Tests { #tests } + +Vous devez vous assurer d'avoir des [tests](../tutorial/testing.md){.internal-link target=_blank} pour votre application et de les exĂ©cuter en intĂ©gration continue (CI). + +De cette façon, vous pouvez effectuer la mise Ă  niveau et vous assurer que tout fonctionne toujours comme prĂ©vu. + +## `bump-pydantic` { #bump-pydantic } + +Dans de nombreux cas, lorsque vous utilisez des modĂšles Pydantic classiques sans personnalisations, vous pourrez automatiser la majeure partie du processus de migration de Pydantic v1 Ă  Pydantic v2. + +Vous pouvez utiliser `bump-pydantic` de la mĂȘme Ă©quipe Pydantic. + +Cet outil vous aidera Ă  modifier automatiquement la majeure partie du code Ă  adapter. + +AprĂšs cela, vous pouvez exĂ©cuter les tests et vĂ©rifier que tout fonctionne. Si c'est le cas, vous avez terminĂ©. 😎 + +## Pydantic v1 dans v2 { #pydantic-v1-in-v2 } + +Pydantic v2 inclut tout Pydantic v1 sous la forme du sous-module `pydantic.v1`. Mais cela n'est plus pris en charge dans les versions au-delĂ  de Python 3.13. + +Cela signifie que vous pouvez installer la derniĂšre version de Pydantic v2 et importer/utiliser les anciens composants de Pydantic v1 depuis ce sous-module, comme si vous aviez l'ancien Pydantic v1 installĂ©. + +{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *} + +### Prise en charge de FastAPI pour Pydantic v1 dans v2 { #fastapi-support-for-pydantic-v1-in-v2 } + +Depuis FastAPI 0.119.0, il existe Ă©galement une prise en charge partielle de Pydantic v1 depuis l'intĂ©rieur de Pydantic v2, pour faciliter la migration vers v2. + +Vous pouvez donc mettre Ă  niveau Pydantic vers la derniĂšre version 2 et modifier les imports pour utiliser le sous-module `pydantic.v1`, et dans de nombreux cas cela fonctionnera tel quel. + +{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *} + +/// warning | Alertes + +Gardez Ă  l'esprit que, puisque l'Ă©quipe Pydantic ne prend plus en charge Pydantic v1 dans les versions rĂ©centes de Python Ă  partir de Python 3.14, l'utilisation de `pydantic.v1` n'est pas non plus prise en charge Ă  partir de Python 3.14. + +/// + +### Pydantic v1 et v2 dans la mĂȘme application { #pydantic-v1-and-v2-on-the-same-app } + +Pydantic ne prend pas en charge le fait d'avoir un modĂšle Pydantic v2 contenant des champs eux-mĂȘmes dĂ©finis comme des modĂšles Pydantic v1, et inversement. + +```mermaid +graph TB + subgraph "❌ Not Supported" + direction TB + subgraph V2["Pydantic v2 Model"] + V1Field["Pydantic v1 Model"] + end + subgraph V1["Pydantic v1 Model"] + V2Field["Pydantic v2 Model"] + end + end + + style V2 fill:#f9fff3 + style V1 fill:#fff6f0 + style V1Field fill:#fff6f0 + style V2Field fill:#f9fff3 +``` + +... mais vous pouvez avoir des modĂšles sĂ©parĂ©s utilisant Pydantic v1 et v2 dans la mĂȘme application. + +```mermaid +graph TB + subgraph "✅ Supported" + direction TB + subgraph V2["Pydantic v2 Model"] + V2Field["Pydantic v2 Model"] + end + subgraph V1["Pydantic v1 Model"] + V1Field["Pydantic v1 Model"] + end + end + + style V2 fill:#f9fff3 + style V1 fill:#fff6f0 + style V1Field fill:#fff6f0 + style V2Field fill:#f9fff3 +``` + +Dans certains cas, il est mĂȘme possible d'avoir des modĂšles Pydantic v1 et v2 dans le mĂȘme chemin d'accĂšs de votre application FastAPI : + +{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *} + +Dans l'exemple ci-dessus, le modĂšle d'entrĂ©e est un modĂšle Pydantic v1 et le modĂšle de sortie (dĂ©fini dans `response_model=ItemV2`) est un modĂšle Pydantic v2. + +### ParamĂštres Pydantic v1 { #pydantic-v1-parameters } + +Si vous devez utiliser certains des outils spĂ©cifiques Ă  FastAPI pour les paramĂštres comme `Body`, `Query`, `Form`, etc., avec des modĂšles Pydantic v1, vous pouvez les importer depuis `fastapi.temp_pydantic_v1_params` le temps de terminer la migration vers Pydantic v2 : + +{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *} + +### Migrer par Ă©tapes { #migrate-in-steps } + +/// tip | Astuce + +Essayez d'abord avec `bump-pydantic` ; si vos tests passent et que cela fonctionne, vous avez tout terminĂ© en une seule commande. ✹ + +/// + +Si `bump-pydantic` ne fonctionne pas pour votre cas d'usage, vous pouvez utiliser la prise en charge des modĂšles Pydantic v1 et v2 dans la mĂȘme application pour effectuer la migration vers Pydantic v2 progressivement. + +Vous pouvez d'abord mettre Ă  niveau Pydantic pour utiliser la derniĂšre version 2 et modifier les imports pour utiliser `pydantic.v1` pour tous vos modĂšles. + +Ensuite, vous pouvez commencer Ă  migrer vos modĂšles de Pydantic v1 vers v2 par groupes, par Ă©tapes progressives. đŸš¶ diff --git a/docs/fr/docs/how-to/separate-openapi-schemas.md b/docs/fr/docs/how-to/separate-openapi-schemas.md new file mode 100644 index 000000000..fd767d738 --- /dev/null +++ b/docs/fr/docs/how-to/separate-openapi-schemas.md @@ -0,0 +1,102 @@ +# SĂ©parer les schĂ©mas OpenAPI pour l'entrĂ©e et la sortie ou non { #separate-openapi-schemas-for-input-and-output-or-not } + +Depuis la sortie de **Pydantic v2**, l'OpenAPI gĂ©nĂ©rĂ© est un peu plus prĂ©cis et **correct** qu'avant. 😎 + +En fait, dans certains cas, il y aura mĂȘme **deux schĂ©mas JSON** dans OpenAPI pour le mĂȘme modĂšle Pydantic, pour l'entrĂ©e et pour la sortie, selon s'ils ont des **valeurs par dĂ©faut**. + +Voyons comment cela fonctionne et comment le modifier si vous devez le faire. + +## Utiliser des modĂšles Pydantic pour l'entrĂ©e et la sortie { #pydantic-models-for-input-and-output } + +Supposons que vous ayez un modĂšle Pydantic avec des valeurs par dĂ©faut, comme celui‑ci : + +{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *} + +### ModĂšle pour l'entrĂ©e { #model-for-input } + +Si vous utilisez ce modĂšle en entrĂ©e comme ici : + +{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *} + +... alors, le champ `description` ne sera **pas requis**. Parce qu'il a une valeur par dĂ©faut de `None`. + +### ModĂšle d'entrĂ©e dans les documents { #input-model-in-docs } + +Vous pouvez le confirmer dans les documents, le champ `description` n'a pas d'**astĂ©risque rouge**, il n'est pas indiquĂ© comme requis : + +
+ +
+ +### ModĂšle pour la sortie { #model-for-output } + +Mais si vous utilisez le mĂȘme modĂšle en sortie, comme ici : + +{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *} + +... alors, comme `description` a une valeur par dĂ©faut, si vous ne retournez rien pour ce champ, il aura tout de mĂȘme cette **valeur par dĂ©faut**. + +### ModĂšle pour les donnĂ©es de rĂ©ponse en sortie { #model-for-output-response-data } + +Si vous interagissez avec les documents et vĂ©rifiez la rĂ©ponse, mĂȘme si le code n'a rien ajoutĂ© dans l'un des champs `description`, la rĂ©ponse JSON contient la valeur par dĂ©faut (`null`) : + +
+ +
+ +Cela signifie qu'il aura **toujours une valeur**, simplement, parfois la valeur pourra ĂȘtre `None` (ou `null` en JSON). + +Cela signifie que les clients utilisant votre API n'ont pas Ă  vĂ©rifier si la valeur existe ou non, ils peuvent **supposer que le champ sera toujours prĂ©sent**, mais que, dans certains cas, il aura la valeur par dĂ©faut `None`. + +La maniĂšre de dĂ©crire cela dans OpenAPI est de marquer ce champ comme **requis**, car il sera toujours prĂ©sent. + +Pour cette raison, le schĂ©ma JSON d'un modĂšle peut ĂȘtre diffĂ©rent selon qu'il est utilisĂ© pour **l'entrĂ©e ou la sortie** : + +- pour **l'entrĂ©e**, `description` ne sera **pas requis** +- pour **la sortie**, il sera **requis** (et Ă©ventuellement `None`, ou en termes JSON, `null`) + +### ModĂšle de sortie dans les documents { #model-for-output-in-docs } + +Vous pouvez Ă©galement vĂ©rifier le modĂšle de sortie dans les documents, **Ă  la fois** `name` et `description` sont marquĂ©s comme **requis** avec un **astĂ©risque rouge** : + +
+ +
+ +### ModÚle pour l'entrée et la sortie dans les documents { #model-for-input-and-output-in-docs } + +Et si vous consultez tous les schémas disponibles (schémas JSON) dans OpenAPI, vous verrez qu'il y en a deux, un `Item-Input` et un `Item-Output`. + +Pour `Item-Input`, `description` n'est **pas requis**, il n'a pas d'astérisque rouge. + +Mais pour `Item-Output`, `description` est **requis**, il a un astérisque rouge. + +
+ +
+ +Avec cette fonctionnalitĂ© de **Pydantic v2**, la documentation de votre API est plus **prĂ©cise**, et si vous avez des clients et SDKs gĂ©nĂ©rĂ©s automatiquement, ils seront eux aussi plus prĂ©cis, avec une meilleure **expĂ©rience dĂ©veloppeur** et davantage de cohĂ©rence. 🎉 + +## Ne pas sĂ©parer les schĂ©mas { #do-not-separate-schemas } + +Il existe des cas oĂč vous pourriez vouloir avoir le **mĂȘme schĂ©ma pour l'entrĂ©e et la sortie**. + +Le cas d'usage principal est probablement que vous avez dĂ©jĂ  du code client/SDKs gĂ©nĂ©rĂ©s automatiquement et que vous ne souhaitez pas encore mettre Ă  jour tout ce code client/ces SDKs gĂ©nĂ©rĂ©s automatiquement ; vous le ferez sans doute Ă  un moment donnĂ©, mais peut‑ĂȘtre pas tout de suite. + +Dans ce cas, vous pouvez dĂ©sactiver cette fonctionnalitĂ© dans **FastAPI**, avec le paramĂštre `separate_input_output_schemas=False`. + +/// info | info + +La prise en charge de `separate_input_output_schemas` a Ă©tĂ© ajoutĂ©e dans FastAPI `0.102.0`. đŸ€“ + +/// + +{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *} + +### Utiliser le mĂȘme schĂ©ma pour les modĂšles d'entrĂ©e et de sortie dans les documents { #same-schema-for-input-and-output-models-in-docs } + +DĂ©sormais, il n'y aura qu'un seul schĂ©ma pour l'entrĂ©e et la sortie du modĂšle, uniquement `Item`, et `description` ne sera pas requis : + +
+ +
diff --git a/docs/fr/docs/how-to/testing-database.md b/docs/fr/docs/how-to/testing-database.md new file mode 100644 index 000000000..3179bc4c6 --- /dev/null +++ b/docs/fr/docs/how-to/testing-database.md @@ -0,0 +1,7 @@ +# Tester une base de donnĂ©es { #testing-a-database } + +Vous pouvez Ă©tudier les bases de donnĂ©es, SQL et SQLModel dans les documents SQLModel. đŸ€“ + +Il existe un mini tutoriel sur l'utilisation de SQLModel avec FastAPI. ✹ + +Ce tutoriel comprend une section sur les tests des bases de donnĂ©es SQL. 😎 diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 2aeaa1c69..bf4446b94 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -40,7 +40,7 @@ Les principales fonctionnalitĂ©s sont : * **Rapide** : trĂšs hautes performances, au niveau de **NodeJS** et **Go** (grĂące Ă  Starlette et Pydantic). [L'un des frameworks Python les plus rapides](#performance). * **Rapide Ă  coder** : augmente la vitesse de dĂ©veloppement des fonctionnalitĂ©s d'environ 200 % Ă  300 %. * * **Moins de bugs** : rĂ©duit d'environ 40 % les erreurs induites par le dĂ©veloppeur. * -* **Intuitif** : excellente compatibilitĂ© avec les Ă©diteurs. AutocomplĂ©tion partout. Moins de temps passĂ© Ă  dĂ©boguer. +* **Intuitif** : excellente compatibilitĂ© avec les Ă©diteurs. AutocomplĂ©tion partout. Moins de temps passĂ© Ă  dĂ©boguer. * **Facile** : conçu pour ĂȘtre facile Ă  utiliser et Ă  apprendre. Moins de temps passĂ© Ă  lire les documents. * **Concis** : diminue la duplication de code. Plusieurs fonctionnalitĂ©s Ă  partir de chaque dĂ©claration de paramĂštre. Moins de bugs. * **Robuste** : obtenez un code prĂȘt pour la production. Avec une documentation interactive automatique. @@ -368,7 +368,7 @@ item: Item * 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. -* Conversion des donnĂ©es d'entrĂ©e : venant du rĂ©seau vers les donnĂ©es et types Python. Lecture depuis : +* Conversion des donnĂ©es d'entrĂ©e : venant du rĂ©seau vers les donnĂ©es et types Python. Lecture depuis : * JSON. * ParamĂštres de chemin. * ParamĂštres de requĂȘte. @@ -376,7 +376,7 @@ item: Item * En-tĂȘtes. * Formulaires. * Fichiers. -* Conversion des donnĂ©es de sortie : conversion des donnĂ©es et types Python en donnĂ©es rĂ©seau (au format JSON) : +* Conversion des donnĂ©es de sortie : conversion des donnĂ©es et types Python en donnĂ©es rĂ©seau (au format JSON) : * Conversion des types Python (`str`, `int`, `float`, `bool`, `list`, etc). * Objets `datetime`. * Objets `UUID`. @@ -439,7 +439,7 @@ Pour un exemple plus complet comprenant plus de fonctionnalitĂ©s, voir le d'injection de dĂ©pendances** trĂšs puissant et facile Ă  utiliser. +* Un systĂšme **d'injection de dĂ©pendances** trĂšs puissant et facile Ă  utiliser. * SĂ©curitĂ© et authentification, y compris la prise en charge de **OAuth2** avec des **JWT tokens** et l'authentification **HTTP Basic**. * Des techniques plus avancĂ©es (mais tout aussi faciles) pour dĂ©clarer des **modĂšles JSON profondĂ©ment imbriquĂ©s** (grĂące Ă  Pydantic). * IntĂ©gration **GraphQL** avec Strawberry et d'autres bibliothĂšques. @@ -524,7 +524,7 @@ UtilisĂ©es par Starlette : * httpx - Obligatoire si vous souhaitez utiliser le `TestClient`. * jinja2 - Obligatoire si vous souhaitez utiliser la configuration de template par dĂ©faut. -* python-multipart - Obligatoire si vous souhaitez prendre en charge l’« parsing » de formulaires avec `request.form()`. +* python-multipart - Obligatoire si vous souhaitez prendre en charge l’« parsing » de formulaires avec `request.form()`. UtilisĂ©es par FastAPI : diff --git a/docs/fr/docs/learn/index.md b/docs/fr/docs/learn/index.md index 552687703..e595ecf78 100644 --- a/docs/fr/docs/learn/index.md +++ b/docs/fr/docs/learn/index.md @@ -2,4 +2,4 @@ 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 **livre**, un **cours**, la mĂ©thode **officielle** et recommandĂ©e pour apprendre FastAPI. 😎 diff --git a/docs/fr/docs/python-types.md b/docs/fr/docs/python-types.md index f393b0f5c..770f1514a 100644 --- a/docs/fr/docs/python-types.md +++ b/docs/fr/docs/python-types.md @@ -1,8 +1,8 @@ # Introduction aux types Python { #python-types-intro } -Python prend en charge des « type hints » (aussi appelĂ©es « annotations de type ») facultatives. +Python prend en charge des « annotations de type » (aussi appelĂ©es « type hints ») facultatives. -Ces « type hints » ou annotations sont une syntaxe spĂ©ciale qui permet de dĂ©clarer le type d'une variable. +Ces **« annotations de type »** sont une syntaxe spĂ©ciale qui permet de dĂ©clarer le type d'une variable. En dĂ©clarant les types de vos variables, les Ă©diteurs et outils peuvent vous offrir un meilleur support. @@ -22,7 +22,7 @@ Si vous ĂȘtes un expert Python, et que vous savez dĂ©jĂ  tout sur les annotation Commençons par un exemple simple : -{* ../../docs_src/python_types/tutorial001_py39.py *} +{* ../../docs_src/python_types/tutorial001_py310.py *} ExĂ©cuter ce programme affiche : @@ -34,9 +34,9 @@ La fonction fait ce qui suit : * Prend un `first_name` et un `last_name`. * Convertit la premiĂšre lettre de chacun en majuscule avec `title()`. -* ConcatĂšne ces deux valeurs avec un espace au milieu. +* ConcatĂšne ces deux valeurs avec un espace au milieu. -{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *} ### Modifier le code { #edit-it } @@ -78,7 +78,7 @@ C'est tout. Ce sont les « annotations de type » : -{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *} Ce n'est pas la mĂȘme chose que de dĂ©clarer des valeurs par dĂ©faut, ce qui serait : @@ -106,7 +106,7 @@ Avec cela, vous pouvez faire dĂ©filer en voyant les options, jusqu'Ă  trouver ce Regardez cette fonction, elle a dĂ©jĂ  des annotations de type : -{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *} Comme l'Ă©diteur connaĂźt les types des variables, vous n'obtenez pas seulement l'autocomplĂ©tion, vous obtenez aussi des vĂ©rifications d'erreurs : @@ -114,7 +114,7 @@ Comme l'Ă©diteur connaĂźt les types des variables, vous n'obtenez pas seulement Vous savez maintenant qu'il faut corriger, convertir `age` en chaĂźne avec `str(age)` : -{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *} ## DĂ©clarer des types { #declaring-types } @@ -133,29 +133,32 @@ Vous pouvez utiliser, par exemple : * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *} -### Types gĂ©nĂ©riques avec paramĂštres de type { #generic-types-with-type-parameters } +### Module `typing` { #typing-module } -Il existe certaines structures de donnĂ©es qui peuvent contenir d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent aussi avoir leur propre type. +Pour certains cas d'utilisation supplĂ©mentaires, vous pourriez avoir besoin d'importer certains Ă©lĂ©ments depuis le module standard `typing`, par exemple lorsque vous voulez dĂ©clarer que quelque chose a « n'importe quel type », vous pouvez utiliser `Any` depuis `typing` : -Ces types qui ont des types internes sont appelĂ©s types « gĂ©nĂ©riques ». Et il est possible de les dĂ©clarer, mĂȘme avec leurs types internes. +```python +from typing import Any -Pour dĂ©clarer ces types et les types internes, vous pouvez utiliser le module standard Python `typing`. Il existe spĂ©cifiquement pour prendre en charge ces annotations de type. -#### Versions plus rĂ©centes de Python { #newer-versions-of-python } +def some_function(data: Any): + print(data) +``` -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. +### Types gĂ©nĂ©riques { #generic-types } -Au fur et Ă  mesure que Python Ă©volue, les versions plus rĂ©centes apportent un meilleur support 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 les dĂ©clarer. +Certains types peuvent prendre des « paramĂštres de type » entre crochets, pour dĂ©finir leurs types internes, par exemple une « liste de chaĂźnes » se dĂ©clarerait `list[str]`. -Si vous pouvez choisir une version plus rĂ©cente de Python pour votre projet, vous pourrez profiter de cette simplicitĂ© supplĂ©mentaire. +Ces types qui peuvent prendre des paramĂštres de type sont appelĂ©s des **types gĂ©nĂ©riques** ou **Generics**. -Dans toute la documentation, il y a des exemples compatibles avec chaque version de Python (lorsqu'il y a une diffĂ©rence). +Vous pouvez utiliser les mĂȘmes types intĂ©grĂ©s comme gĂ©nĂ©riques (avec des crochets et des types Ă  l'intĂ©rieur) : -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). - -Si vous pouvez utiliser les derniĂšres versions de Python, utilisez les exemples pour la derniĂšre version, ils auront la meilleure et la plus simple syntaxe, par exemple, « Python 3.10+ ». +* `list` +* `tuple` +* `set` +* `dict` #### Liste { #list } @@ -167,9 +170,9 @@ Comme type, mettez `list`. Comme la liste est un type qui contient des types internes, mettez-les entre crochets : -{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *} -/// info +/// info | Info Ces types internes entre crochets sont appelĂ©s « paramĂštres de type ». @@ -193,7 +196,7 @@ Et pourtant, l'Ă©diteur sait que c'est un `str` et fournit le support appropriĂ© Vous feriez la mĂȘme chose pour dĂ©clarer des `tuple` et des `set` : -{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *} Cela signifie : @@ -208,7 +211,7 @@ Le premier paramĂštre de type est pour les clĂ©s du `dict`. Le second paramĂštre de type est pour les valeurs du `dict` : -{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *} Cela signifie : @@ -218,46 +221,22 @@ Cela signifie : #### Union { #union } -Vous pouvez dĂ©clarer qu'une variable peut ĂȘtre de plusieurs types, par exemple, un `int` ou un `str`. +Vous pouvez dĂ©clarer qu'une variable peut ĂȘtre **plusieurs types**, par exemple, un `int` ou un `str`. -Dans 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. +Pour le dĂ©finir, vous utilisez la barre verticale (`|`) pour sĂ©parer les deux types. -Dans Python 3.10, il existe aussi une nouvelle syntaxe oĂč vous pouvez mettre les types possibles sĂ©parĂ©s par une barre verticale (`|`). - -//// tab | Python 3.10+ +C'est ce qu'on appelle une « union », car la variable peut ĂȘtre n'importe quoi dans l'union de ces deux ensembles de types. ```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` peut ĂȘtre un `int` ou un `str`. +Cela signifie que `item` peut ĂȘtre un `int` ou un `str`. #### Possiblement `None` { #possibly-none } Vous pouvez dĂ©clarer qu'une valeur peut avoir un type, comme `str`, mais qu'elle peut aussi ĂȘtre `None`. -Dans 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 simplement `str` permettra Ă  l'Ă©diteur de vous aider Ă  dĂ©tecter des erreurs oĂč vous supposeriez qu'une valeur est toujours un `str`, alors qu'elle pourrait en fait aussi ĂȘtre `None`. - -`Optional[Something]` est en rĂ©alitĂ© un raccourci pour `Union[Something, None]`, ils sont Ă©quivalents. - -Cela signifie aussi que dans Python 3.10, vous pouvez utiliser `Something | None` : - //// tab | Python 3.10+ ```Python hl_lines="1" @@ -266,96 +245,7 @@ Cela signifie aussi que dans Python 3.10, vous pouvez utiliser `Something | None //// -//// tab | Python 3.9+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009_py39.py!} -``` - -//// - -//// tab | Python 3.9+ alternative - -```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 un conseil de mon point de vue trĂšs **subjectif** : - -* 🚹 Évitez d'utiliser `Optional[SomeType]` -* À la place ✹ **utilisez `Union[SomeType, None]`** ✹. - -Les deux sont Ă©quivalents et sous le capot ce sont les mĂȘmes, mais je recommanderais `Union` plutĂŽt que `Optional` parce que le mot « facultatif » semble impliquer que la valeur est optionnelle, alors que cela signifie en fait « elle peut ĂȘtre `None` », mĂȘme si elle n'est pas facultative et est toujours requise. - -Je pense que `Union[SomeType, None]` est plus explicite sur ce que cela signifie. - -Il ne s'agit que des mots et des noms. Mais ces mots peuvent influencer la maniĂšre 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 facultatif, vous ne pouvez pas appeler la fonction sans le paramĂštre : - -```Python -say_hi() # Oh non, cela lĂšve une erreur ! đŸ˜± -``` - -Le paramĂštre `name` est toujours requis (pas « optionnel ») parce qu'il n'a pas de valeur par dĂ©faut. NĂ©anmoins, `name` accepte `None` comme valeur : - -```Python -say_hi(name=None) # Cela fonctionne, None est valide 🎉 -``` - -La bonne nouvelle est que, dĂšs que vous ĂȘtes sur Python 3.10, vous n'avez 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 alors 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 **types gĂ©nĂ©riques** ou **Generics**, par exemple : - -//// tab | Python 3.10+ - -Vous pouvez utiliser les mĂȘmes types intĂ©grĂ©s comme gĂ©nĂ©riques (avec des crochets et des types Ă  l'intĂ©rieur) : - -* `list` -* `tuple` -* `set` -* `dict` - -Et, comme avec les versions prĂ©cĂ©dentes de Python, depuis le module `typing` : - -* `Union` -* `Optional` -* ... et d'autres. - -Dans Python 3.10, comme alternative Ă  l'utilisation des gĂ©nĂ©riques `Union` et `Optional`, vous pouvez utiliser la barre verticale (`|`) pour dĂ©clarer des unions de types, c'est bien mieux et plus simple. - -//// - -//// tab | Python 3.9+ - -Vous pouvez utiliser les mĂȘmes types intĂ©grĂ©s comme gĂ©nĂ©riques (avec des crochets et des types Ă  l'intĂ©rieur) : - -* `list` -* `tuple` -* `set` -* `dict` - -Et des gĂ©nĂ©riques depuis le module `typing` : - -* `Union` -* `Optional` -* ... et d'autres. - -//// +Utiliser `str | None` au lieu de simplement `str` permettra Ă  l'Ă©diteur de vous aider Ă  dĂ©tecter des erreurs oĂč vous supposeriez qu'une valeur est toujours un `str`, alors qu'elle pourrait en fait aussi ĂȘtre `None`. ### Classes en tant que types { #classes-as-types } @@ -363,19 +253,19 @@ Vous pouvez aussi dĂ©clarer une classe comme type d'une variable. Disons que vous avez une classe `Person`, avec un nom : -{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py310.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_py310.py hl[6] *} Et lĂ  encore, vous obtenez tout le support de l'Ă©diteur : -Remarquez que cela signifie « `one_person` est une instance de la classe `Person` ». +Remarquez que cela signifie « `one_person` est une **instance** de la classe `Person` ». -Cela ne signifie pas « `one_person` est la classe appelĂ©e `Person` ». +Cela ne signifie pas « `one_person` est la **classe** appelĂ©e `Person` ». ## ModĂšles Pydantic { #pydantic-models } @@ -393,7 +283,7 @@ Un exemple tirĂ© de la documentation officielle de Pydantic : {* ../../docs_src/python_types/tutorial011_py310.py *} -/// info +/// info | Info Pour en savoir plus Ă  propos de Pydantic, consultez sa documentation. @@ -403,33 +293,27 @@ Pour en savoir plus Ă  propos de champs Optionals requis. - -/// - ## Annotations de type avec mĂ©tadonnĂ©es { #type-hints-with-metadata-annotations } -Python dispose Ă©galement d'une fonctionnalitĂ© qui permet de mettre des **mĂ©tadonnĂ©es supplĂ©mentaires** dans ces annotations de type en utilisant `Annotated`. +Python dispose Ă©galement d'une fonctionnalitĂ© qui permet de mettre des **mĂ©tadonnĂ©es supplĂ©mentaires** dans ces annotations de type en utilisant `Annotated`. -Depuis Python 3.9, `Annotated` fait partie de la bibliothĂšque standard, vous pouvez donc l'importer depuis `typing`. +Vous pouvez importer `Annotated` depuis `typing`. -{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *} Python lui-mĂȘme ne fait rien avec ce `Annotated`. Et pour les Ă©diteurs et 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 façon dont vous voulez que votre application se comporte. -L'important Ă  retenir est que le premier paramĂštre de type que vous passez Ă  `Annotated` est le type rĂ©el. Le reste n'est que des mĂ©tadonnĂ©es pour d'autres outils. +L'important Ă  retenir est que **le premier « paramĂštre de type »** que vous passez Ă  `Annotated` est le **type rĂ©el**. Le reste n'est que des mĂ©tadonnĂ©es pour d'autres outils. Pour l'instant, vous avez juste besoin de savoir que `Annotated` existe, et que c'est du Python standard. 😎 -Plus tard, vous verrez Ă  quel point cela peut ĂȘtre puissant. +Plus tard, vous verrez Ă  quel point cela peut ĂȘtre **puissant**. /// tip | Astuce -Le fait que ce soit du Python standard signifie que vous bĂ©nĂ©ficierez toujours de la meilleure expĂ©rience dĂ©veloppeur possible dans votre Ă©diteur, avec les outils que vous utilisez pour analyser et refactoriser votre code, etc. ✹ +Le fait que ce soit du **Python standard** signifie que vous bĂ©nĂ©ficierez toujours de 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. 🚀 @@ -457,7 +341,7 @@ Tout cela peut sembler abstrait. Ne vous inquiĂ©tez pas. Vous verrez tout cela e L'important est qu'en utilisant les types standards de Python, en un seul endroit (au lieu d'ajouter plus de classes, de dĂ©corateurs, etc.), **FastAPI** fera une grande partie du travail pour vous. -/// info +/// info | Info Si vous avez dĂ©jĂ  parcouru tout le tutoriel et ĂȘtes revenu pour en voir plus sur les types, une bonne ressource est l'« aide-mĂ©moire » de `mypy`. diff --git a/docs/fr/docs/resources/index.md b/docs/fr/docs/resources/index.md new file mode 100644 index 000000000..e62db346d --- /dev/null +++ b/docs/fr/docs/resources/index.md @@ -0,0 +1,3 @@ +# Ressources { #resources } + +Ressources supplĂ©mentaires, liens externes et plus encore. ✈ diff --git a/docs/fr/docs/translation-banner.md b/docs/fr/docs/translation-banner.md new file mode 100644 index 000000000..9eaedf1b1 --- /dev/null +++ b/docs/fr/docs/translation-banner.md @@ -0,0 +1,11 @@ +/// details | 🌐 Traduction par IA et humains + +Cette traduction a Ă©tĂ© rĂ©alisĂ©e par une IA guidĂ©e par des humains. đŸ€ + +Elle peut contenir des erreurs d'interprĂ©tation du sens original, ou paraĂźtre peu naturelle, etc. đŸ€– + +Vous pouvez amĂ©liorer cette traduction en [nous aidant Ă  mieux guider le LLM d'IA](https://fastapi.tiangolo.com/fr/contributing/#translations). + +[Version anglaise](ENGLISH_VERSION_URL) + +/// diff --git a/docs/fr/docs/tutorial/background-tasks.md b/docs/fr/docs/tutorial/background-tasks.md index ed7494669..a8444ba27 100644 --- a/docs/fr/docs/tutorial/background-tasks.md +++ b/docs/fr/docs/tutorial/background-tasks.md @@ -15,12 +15,14 @@ Cela comprend, par exemple : Pour commencer, importez `BackgroundTasks` et dĂ©finissez un paramĂštre dans votre *fonction de chemin d'accĂšs* avec `BackgroundTasks` comme type dĂ©clarĂ©. -{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py310.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Ă©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. Elle peut ĂȘtre une fonction asynchrone (`async def`) ou une fonction normale (`def`), **FastAPI** saura la gĂ©rer correctement. @@ -29,13 +31,13 @@ Dans cet exemple, la fonction de tĂąche Ă©crira dans un fichier (afin de simuler L'opĂ©ration d'Ă©criture n'utilisant ni `async` ni `await`, on dĂ©finit la fonction avec un `def` normal. -{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *} ## Ajouter une tĂąche d'arriĂšre-plan { #add-the-background-task } Dans votre *fonction de chemin d'accĂšs*, passez votre fonction de tĂąche Ă  l'objet de type `BackgroundTasks` (`background_tasks` ici) grĂące Ă  la mĂ©thode `.add_task()` : -{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *} `.add_task()` reçoit comme arguments : diff --git a/docs/fr/docs/tutorial/bigger-applications.md b/docs/fr/docs/tutorial/bigger-applications.md new file mode 100644 index 000000000..065962236 --- /dev/null +++ b/docs/fr/docs/tutorial/bigger-applications.md @@ -0,0 +1,504 @@ +# CrĂ©er des applications plus grandes - Plusieurs fichiers { #bigger-applications-multiple-files } + +Si vous crĂ©ez une application ou une API web, il est rare que vous puissiez tout mettre dans un seul fichier. + +**FastAPI** fournit un outil pratique pour structurer votre application tout en conservant toute la flexibilitĂ©. + +/// info + +Si vous venez de Flask, cela Ă©quivaut aux Blueprints de Flask. + +/// + +## Exemple de structure de fichiers { #an-example-file-structure } + +Supposons que vous ayez une structure de fichiers comme ceci : + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   ├── dependencies.py +│   └── routers +│   │ ├── __init__.py +│   │ ├── items.py +│   │ └── users.py +│   └── internal +│   ├── __init__.py +│   └── admin.py +``` + +/// tip | Astuce + +Il y a plusieurs fichiers `__init__.py` : un dans chaque rĂ©pertoire ou sous-rĂ©pertoire. + +C'est cela qui permet d'importer du code d'un fichier dans un autre. + +Par exemple, dans `app/main.py` vous pourriez avoir une ligne comme : + +``` +from app.routers import items +``` + +/// + +* Le rĂ©pertoire `app` contient tout. Et il a un fichier vide `app/__init__.py`, c'est donc un « package Python » (une collection de « modules Python ») : `app`. +* Il contient un fichier `app/main.py`. Comme il se trouve dans un package Python (un rĂ©pertoire avec un fichier `__init__.py`), c'est un « module » de ce package : `app.main`. +* Il y a aussi un fichier `app/dependencies.py`, tout comme `app/main.py`, c'est un « module » : `app.dependencies`. +* Il y a un sous-rĂ©pertoire `app/routers/` avec un autre fichier `__init__.py`, c'est donc un « sous-package Python » : `app.routers`. +* Le fichier `app/routers/items.py` est dans un package, `app/routers/`, c'est donc un sous-module : `app.routers.items`. +* De mĂȘme pour `app/routers/users.py`, c'est un autre sous-module : `app.routers.users`. +* Il y a aussi un sous-rĂ©pertoire `app/internal/` avec un autre fichier `__init__.py`, c'est donc un autre « sous-package Python » : `app.internal`. +* Et le fichier `app/internal/admin.py` est un autre sous-module : `app.internal.admin`. + + + +La mĂȘme structure de fichiers avec des commentaires : + +```bash +. +├── app # "app" est un package Python +│   ├── __init__.py # ce fichier fait de "app" un "package Python" +│   ├── main.py # module "main", ex. import app.main +│   ├── dependencies.py # module "dependencies", ex. import app.dependencies +│   └── routers # "routers" est un "sous-package Python" +│   │ ├── __init__.py # fait de "routers" un "sous-package Python" +│   │ ├── items.py # sous-module "items", ex. import app.routers.items +│   │ └── users.py # sous-module "users", ex. import app.routers.users +│   └── internal # "internal" est un "sous-package Python" +│   ├── __init__.py # fait de "internal" un "sous-package Python" +│   └── admin.py # sous-module "admin", ex. import app.internal.admin +``` + +## `APIRouter` { #apirouter } + +Supposons que le fichier dĂ©diĂ© Ă  la gestion des utilisateurs soit le sous-module `/app/routers/users.py`. + +Vous voulez sĂ©parer les *chemins d'accĂšs* liĂ©s Ă  vos utilisateurs du reste du code pour le garder organisĂ©. + +Mais cela fait toujours partie de la mĂȘme application/API web **FastAPI** (cela fait partie du mĂȘme « package Python »). + +Vous pouvez crĂ©er les *chemins d'accĂšs* pour ce module Ă  l'aide de `APIRouter`. + +### Importer `APIRouter` { #import-apirouter } + +Vous l'importez et crĂ©ez une « instance » de la mĂȘme maniĂšre que vous le feriez avec la classe `FastAPI` : + +{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title["app/routers/users.py"] *} + +### DĂ©clarer des *chemins d'accĂšs* avec `APIRouter` { #path-operations-with-apirouter } + +Puis vous l'utilisez pour dĂ©clarer vos *chemins d'accĂšs*. + +Utilisez-le de la mĂȘme maniĂšre que vous utiliseriez la classe `FastAPI` : + +{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title["app/routers/users.py"] *} + +Vous pouvez considĂ©rer `APIRouter` comme une « mini `FastAPI` ». + +Toutes les mĂȘmes options sont prises en charge. + +Tous les mĂȘmes `parameters`, `responses`, `dependencies`, `tags`, etc. + +/// tip | Astuce + +Dans cet exemple, la variable s'appelle `router`, mais vous pouvez la nommer comme vous le souhaitez. + +/// + +Nous allons inclure ce `APIRouter` dans l'application principale `FastAPI`, mais d'abord, examinons les dĂ©pendances et un autre `APIRouter`. + +## GĂ©rer les dĂ©pendances { #dependencies } + +Nous voyons que nous allons avoir besoin de certaines dĂ©pendances utilisĂ©es Ă  plusieurs endroits de l'application. + +Nous les mettons donc dans leur propre module `dependencies` (`app/dependencies.py`). + +Nous allons maintenant utiliser une dĂ©pendance simple pour lire un en-tĂȘte personnalisĂ© `X-Token` : + +{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title["app/dependencies.py"] *} + +/// tip | Astuce + +Nous utilisons un en-tĂȘte inventĂ© pour simplifier cet exemple. + +Mais dans les cas rĂ©els, vous obtiendrez de meilleurs rĂ©sultats en utilisant les [utilitaires de sĂ©curitĂ©](security/index.md){.internal-link target=_blank} intĂ©grĂ©s. + +/// + +## CrĂ©er un autre module avec `APIRouter` { #another-module-with-apirouter } + +Supposons que vous ayez Ă©galement les endpoints dĂ©diĂ©s Ă  la gestion des « items » de votre application dans le module `app/routers/items.py`. + +Vous avez des *chemins d'accĂšs* pour : + +* `/items/` +* `/items/{item_id}` + +C'est exactement la mĂȘme structure que pour `app/routers/users.py`. + +Mais nous voulons ĂȘtre plus malins et simplifier un peu le code. + +Nous savons que tous les *chemins d'accĂšs* de ce module ont les mĂȘmes Ă©lĂ©ments : + +* PrĂ©fixe de chemin `prefix` : `/items`. +* `tags` : (un seul tag : `items`). +* `responses` supplĂ©mentaires. +* `dependencies` : ils ont tous besoin de la dĂ©pendance `X-Token` que nous avons créée. + +Donc, au lieu d'ajouter tout cela Ă  chaque *chemin d'accĂšs*, nous pouvons l'ajouter au `APIRouter`. + +{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *} + +Comme le chemin de chaque *chemin d'accĂšs* doit commencer par `/`, comme dans : + +```Python hl_lines="1" +@router.get("/{item_id}") +async def read_item(item_id: str): + ... +``` + +... le prĂ©fixe ne doit pas inclure un `/` final. + +Ainsi, le prĂ©fixe dans ce cas est `/items`. + +Nous pouvons Ă©galement ajouter une liste de `tags` et des `responses` supplĂ©mentaires qui seront appliquĂ©s Ă  tous les *chemins d'accĂšs* inclus dans ce routeur. + +Et nous pouvons ajouter une liste de `dependencies` qui seront ajoutĂ©es Ă  tous les *chemins d'accĂšs* du routeur et seront exĂ©cutĂ©es/rĂ©solues pour chaque requĂȘte qui leur est faite. + +/// tip | Astuce + +Notez que, tout comme pour les [dĂ©pendances dans les dĂ©corateurs de *chemin d'accĂšs*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, aucune valeur ne sera transmise Ă  votre *fonction de chemin d'accĂšs*. + +/// + +Le rĂ©sultat final est que les chemins d'item sont dĂ©sormais : + +* `/items/` +* `/items/{item_id}` + +... comme prĂ©vu. + +* Ils seront marquĂ©s avec une liste de tags qui contient une seule chaĂźne « items ». + * Ces « tags » sont particuliĂšrement utiles pour les systĂšmes de documentation interactive automatique (utilisant OpenAPI). +* Ils incluront tous les `responses` prĂ©dĂ©finies. +* Tous ces *chemins d'accĂšs* auront la liste des `dependencies` Ă©valuĂ©es/exĂ©cutĂ©es avant eux. + * Si vous dĂ©clarez Ă©galement des dĂ©pendances dans un *chemin d'accĂšs* spĂ©cifique, **elles seront aussi exĂ©cutĂ©es**. + * Les dĂ©pendances du routeur sont exĂ©cutĂ©es en premier, puis les [`dependencies` dans le dĂ©corateur](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, puis les dĂ©pendances des paramĂštres normaux. + * Vous pouvez Ă©galement ajouter des [`Security` dependencies avec des `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}. + +/// tip | Astuce + +Avoir des `dependencies` dans le `APIRouter` peut servir, par exemple, Ă  exiger une authentification pour tout un groupe de *chemins d'accĂšs*. MĂȘme si les dĂ©pendances ne sont pas ajoutĂ©es individuellement Ă  chacun d'eux. + +/// + +/// check | VĂ©rifications + +Les paramĂštres `prefix`, `tags`, `responses` et `dependencies` sont (comme dans de nombreux autres cas) simplement une fonctionnalitĂ© de **FastAPI** pour vous aider Ă  Ă©viter la duplication de code. + +/// + +### Importer les dĂ©pendances { #import-the-dependencies } + +Ce code se trouve dans le module `app.routers.items`, le fichier `app/routers/items.py`. + +Et nous devons rĂ©cupĂ©rer la fonction de dĂ©pendance depuis le module `app.dependencies`, le fichier `app/dependencies.py`. + +Nous utilisons donc un import relatif avec `..` pour les dĂ©pendances : + +{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title["app/routers/items.py"] *} + +#### Comprendre le fonctionnement des imports relatifs { #how-relative-imports-work } + +/// tip | Astuce + +Si vous savez parfaitement comment fonctionnent les imports, passez Ă  la section suivante ci-dessous. + +/// + +Un seul point `.`, comme dans : + +```Python +from .dependencies import get_token_header +``` + +signifierait : + +* En partant du mĂȘme package dans lequel vit ce module (le fichier `app/routers/items.py`) (le rĂ©pertoire `app/routers/`)... +* trouver le module `dependencies` (un fichier imaginaire `app/routers/dependencies.py`)... +* et en importer la fonction `get_token_header`. + +Mais ce fichier n'existe pas, nos dĂ©pendances sont dans un fichier `app/dependencies.py`. + +Rappelez-vous Ă  quoi ressemble la structure de notre app/fichiers : + + + +--- + +Les deux points `..`, comme dans : + +```Python +from ..dependencies import get_token_header +``` + +veulent dire : + +* En partant du mĂȘme package dans lequel vit ce module (le fichier `app/routers/items.py`) (le rĂ©pertoire `app/routers/`)... +* aller au package parent (le rĂ©pertoire `app/`)... +* et lĂ , trouver le module `dependencies` (le fichier `app/dependencies.py`)... +* et en importer la fonction `get_token_header`. + +Cela fonctionne correctement ! 🎉 + +--- + +De la mĂȘme maniĂšre, si nous avions utilisĂ© trois points `...`, comme dans : + +```Python +from ...dependencies import get_token_header +``` + +cela voudrait dire : + +* En partant du mĂȘme package dans lequel vit ce module (le fichier `app/routers/items.py`) (le rĂ©pertoire `app/routers/`)... +* aller au package parent (le rĂ©pertoire `app/`)... +* puis aller au parent de ce package (il n'y a pas de package parent, `app` est le niveau supĂ©rieur đŸ˜±)... +* et lĂ , trouver le module `dependencies` (le fichier `app/dependencies.py`)... +* et en importer la fonction `get_token_header`. + +Cela ferait rĂ©fĂ©rence Ă  un package au-dessus de `app/`, avec son propre fichier `__init__.py`, etc. Mais nous n'avons pas cela. Donc, cela lĂšverait une erreur dans notre exemple. 🚹 + +Mais maintenant vous savez comment cela fonctionne, vous pouvez donc utiliser des imports relatifs dans vos propres applications, aussi complexes soient-elles. đŸ€“ + +### Ajouter des `tags`, `responses` et `dependencies` personnalisĂ©s { #add-some-custom-tags-responses-and-dependencies } + +Nous n'ajoutons pas le prĂ©fixe `/items` ni `tags=["items"]` Ă  chaque *chemin d'accĂšs* parce que nous les avons ajoutĂ©s au `APIRouter`. + +Mais nous pouvons toujours ajouter _davantage_ de `tags` qui seront appliquĂ©s Ă  un *chemin d'accĂšs* spĂ©cifique, ainsi que des `responses` supplĂ©mentaires propres Ă  ce *chemin d'accĂšs* : + +{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title["app/routers/items.py"] *} + +/// tip | Astuce + +Ce dernier *chemin d'accĂšs* aura la combinaison de tags : `["items", "custom"]`. + +Et il aura Ă©galement les deux rĂ©ponses dans la documentation, une pour `404` et une pour `403`. + +/// + +## CrĂ©er l'application `FastAPI` principale { #the-main-fastapi } + +Voyons maintenant le module `app/main.py`. + +C'est ici que vous importez et utilisez la classe `FastAPI`. + +Ce sera le fichier principal de votre application qui reliera tout ensemble. + +Et comme la plupart de votre logique vivra dĂ©sormais dans son propre module, le fichier principal sera assez simple. + +### Importer `FastAPI` { #import-fastapi } + +Vous importez et crĂ©ez une classe `FastAPI` comme d'habitude. + +Et nous pouvons mĂȘme dĂ©clarer des [dĂ©pendances globales](dependencies/global-dependencies.md){.internal-link target=_blank} qui seront combinĂ©es avec les dĂ©pendances de chaque `APIRouter` : + +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title["app/main.py"] *} + +### Importer les `APIRouter` { #import-the-apirouter } + +Nous importons maintenant les autres sous-modules qui ont des `APIRouter` : + +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title["app/main.py"] *} + +Comme les fichiers `app/routers/users.py` et `app/routers/items.py` sont des sous-modules qui font partie du mĂȘme package Python `app`, nous pouvons utiliser un seul point `.` pour les importer en utilisant des « imports relatifs ». + +### Comprendre le fonctionnement de l'import { #how-the-importing-works } + +La section : + +```Python +from .routers import items, users +``` + +signifie : + +* En partant du mĂȘme package dans lequel vit ce module (le fichier `app/main.py`) (le rĂ©pertoire `app/`)... +* chercher le sous-package `routers` (le rĂ©pertoire `app/routers/`)... +* et en importer le sous-module `items` (le fichier `app/routers/items.py`) et `users` (le fichier `app/routers/users.py`)... + +Le module `items` aura une variable `router` (`items.router`). C'est celle que nous avons créée dans le fichier `app/routers/items.py`, c'est un objet `APIRouter`. + +Nous faisons ensuite la mĂȘme chose pour le module `users`. + +Nous pourrions aussi les importer ainsi : + +```Python +from app.routers import items, users +``` + +/// info + +La premiĂšre version est un « import relatif » : + +```Python +from .routers import items, users +``` + +La deuxiĂšme version est un « import absolu » : + +```Python +from app.routers import items, users +``` + +Pour en savoir plus sur les Packages et Modules Python, lisez la documentation officielle de Python sur les modules. + +/// + +### Éviter les collisions de noms { #avoid-name-collisions } + +Nous importons le sous-module `items` directement, au lieu d'importer uniquement sa variable `router`. + +C'est parce que nous avons Ă©galement une autre variable nommĂ©e `router` dans le sous-module `users`. + +Si nous les avions importĂ©es l'une aprĂšs l'autre, comme : + +```Python +from .routers.items import router +from .routers.users import router +``` + +le `router` de `users` Ă©craserait celui de `items` et nous ne pourrions pas les utiliser en mĂȘme temps. + +Donc, pour pouvoir utiliser les deux dans le mĂȘme fichier, nous importons directement les sous-modules : + +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title["app/main.py"] *} + +### Inclure les `APIRouter` pour `users` et `items` { #include-the-apirouters-for-users-and-items } + +Incluons maintenant les `router` des sous-modules `users` et `items` : + +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title["app/main.py"] *} + +/// info + +`users.router` contient le `APIRouter` Ă  l'intĂ©rieur du fichier `app/routers/users.py`. + +Et `items.router` contient le `APIRouter` Ă  l'intĂ©rieur du fichier `app/routers/items.py`. + +/// + +Avec `app.include_router()`, nous pouvons ajouter chaque `APIRouter` Ă  l'application principale `FastAPI`. + +Cela inclura toutes les routes de ce routeur comme faisant partie de l'application. + +/// note | DĂ©tails techniques + +En interne, cela crĂ©era en fait un *chemin d'accĂšs* pour chaque *chemin d'accĂšs* qui a Ă©tĂ© dĂ©clarĂ© dans le `APIRouter`. + +Donc, en coulisses, cela fonctionnera comme si tout faisait partie d'une seule et mĂȘme application. + +/// + +/// check | VĂ©rifications + +Vous n'avez pas Ă  vous soucier de la performance lors de l'inclusion de routeurs. + +Cela prendra des microsecondes et ne se produira qu'au dĂ©marrage. + +Donc cela n'affectera pas la performance. ⚡ + +/// + +### Inclure un `APIRouter` avec un `prefix`, des `tags`, des `responses` et des `dependencies` personnalisĂ©s { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies } + +Imaginons maintenant que votre organisation vous ait fourni le fichier `app/internal/admin.py`. + +Il contient un `APIRouter` avec quelques *chemins d'accĂšs* d'administration que votre organisation partage entre plusieurs projets. + +Pour cet exemple, il sera trĂšs simple. Mais supposons que, parce qu'il est partagĂ© avec d'autres projets de l'organisation, nous ne puissions pas le modifier et ajouter un `prefix`, des `dependencies`, des `tags`, etc. directement au `APIRouter` : + +{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title["app/internal/admin.py"] *} + +Mais nous voulons quand mĂȘme dĂ©finir un `prefix` personnalisĂ© lors de l'inclusion du `APIRouter` afin que tous ses *chemins d'accĂšs* commencent par `/admin`, nous voulons le sĂ©curiser avec les `dependencies` que nous avons dĂ©jĂ  pour ce projet, et nous voulons inclure des `tags` et des `responses`. + +Nous pouvons dĂ©clarer tout cela sans avoir Ă  modifier le `APIRouter` d'origine en passant ces paramĂštres Ă  `app.include_router()` : + +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title["app/main.py"] *} + +De cette façon, le `APIRouter` original restera inchangĂ©, afin que nous puissions toujours partager ce mĂȘme fichier `app/internal/admin.py` avec d'autres projets de l'organisation. + +Le rĂ©sultat est que, dans notre application, chacun des *chemins d'accĂšs* du module `admin` aura : + +* Le prĂ©fixe `/admin`. +* Le tag `admin`. +* La dĂ©pendance `get_token_header`. +* La rĂ©ponse `418`. đŸ” + +Mais cela n'affectera que ce `APIRouter` dans notre application, pas dans tout autre code qui l'utilise. + +Ainsi, par exemple, d'autres projets pourraient utiliser le mĂȘme `APIRouter` avec une mĂ©thode d'authentification diffĂ©rente. + +### Inclure un *chemin d'accĂšs* { #include-a-path-operation } + +Nous pouvons Ă©galement ajouter des *chemins d'accĂšs* directement Ă  l'application `FastAPI`. + +Ici, nous le faisons... juste pour montrer que nous le pouvons đŸ€· : + +{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title["app/main.py"] *} + +et cela fonctionnera correctement, avec tous les autres *chemins d'accĂšs* ajoutĂ©s avec `app.include_router()`. + +/// info | DĂ©tails trĂšs techniques + +Note : c'est un dĂ©tail trĂšs technique que vous pouvez probablement **simplement ignorer**. + +--- + +Les `APIRouter` ne sont pas « montĂ©s », ils ne sont pas isolĂ©s du reste de l'application. + +C'est parce que nous voulons inclure leurs *chemins d'accĂšs* dans le schĂ©ma OpenAPI et les interfaces utilisateur. + +Comme nous ne pouvons pas simplement les isoler et les « monter » indĂ©pendamment du reste, les *chemins d'accĂšs* sont « clonĂ©s » (recréés), pas inclus directement. + +/// + +## Consulter la documentation API automatique { #check-the-automatic-api-docs } + +Maintenant, exĂ©cutez votre application : + +
+ +```console +$ fastapi dev app/main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Et ouvrez les documents Ă  http://127.0.0.1:8000/docs. + +Vous verrez la documentation API automatique, incluant les chemins de tous les sous-modules, utilisant les bons chemins (et prĂ©fixes) et les bons tags : + + + +## Inclure le mĂȘme routeur plusieurs fois avec des `prefix` diffĂ©rents { #include-the-same-router-multiple-times-with-different-prefix } + +Vous pouvez aussi utiliser `.include_router()` plusieurs fois avec le mĂȘme routeur en utilisant des prĂ©fixes diffĂ©rents. + +Cela peut ĂȘtre utile, par exemple, pour exposer la mĂȘme API sous des prĂ©fixes diffĂ©rents, p. ex. `/api/v1` et `/api/latest`. + +C'est un usage avancĂ© dont vous n'aurez peut-ĂȘtre pas vraiment besoin, mais il est lĂ  au cas oĂč. + +## Inclure un `APIRouter` dans un autre { #include-an-apirouter-in-another } + +De la mĂȘme maniĂšre que vous pouvez inclure un `APIRouter` dans une application `FastAPI`, vous pouvez inclure un `APIRouter` dans un autre `APIRouter` en utilisant : + +```Python +router.include_router(other_router) +``` + +Vous devez vous assurer de le faire avant d'inclure `router` dans l'application `FastAPI`, afin que les *chemins d'accĂšs* de `other_router` soient Ă©galement inclus. diff --git a/docs/fr/docs/tutorial/body-fields.md b/docs/fr/docs/tutorial/body-fields.md new file mode 100644 index 000000000..9830292c9 --- /dev/null +++ b/docs/fr/docs/tutorial/body-fields.md @@ -0,0 +1,61 @@ +# Corps - Champs { #body-fields } + +De la mĂȘme maniĂšre que vous pouvez dĂ©clarer des validations supplĂ©mentaires et des mĂ©tadonnĂ©es dans les paramĂštres d'une fonction de chemin d'accĂšs avec `Query`, `Path` et `Body`, vous pouvez dĂ©clarer des validations et des mĂ©tadonnĂ©es Ă  l'intĂ©rieur des modĂšles Pydantic en utilisant `Field` de Pydantic. + +## Importer `Field` { #import-field } + +D'abord, vous devez l'importer : + +{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *} + + +/// warning | Alertes + +Notez que `Field` est importĂ© directement depuis `pydantic`, et non depuis `fastapi` comme le sont les autres (`Query`, `Path`, `Body`, etc.). + +/// + +## DĂ©clarer les attributs du modĂšle { #declare-model-attributes } + +Vous pouvez ensuite utiliser `Field` avec des attributs de modĂšle : + +{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *} + +`Field` fonctionne de la mĂȘme maniĂšre que `Query`, `Path` et `Body`, il dispose des mĂȘmes paramĂštres, etc. + +/// note | DĂ©tails techniques + +En rĂ©alitĂ©, `Query`, `Path` et d'autres que vous verrez ensuite crĂ©ent des objets de sous-classes d'une classe commune `Param`, qui est elle-mĂȘme une sous-classe de la classe `FieldInfo` de Pydantic. + +Et `Field` de Pydantic renvoie Ă©galement une instance de `FieldInfo`. + +`Body` renvoie aussi directement des objets d'une sous-classe de `FieldInfo`. Et il y en a d'autres que vous verrez plus tard qui sont des sous-classes de la classe `Body`. + +Rappelez-vous que lorsque vous importez `Query`, `Path` et d'autres depuis `fastapi`, ce sont en rĂ©alitĂ© des fonctions qui renvoient des classes spĂ©ciales. + +/// + +/// tip | Astuce + +Remarquez comment chaque attribut de modĂšle avec un type, une valeur par dĂ©faut et `Field` a la mĂȘme structure qu'un paramĂštre de fonction de chemin d'accĂšs, avec `Field` au lieu de `Path`, `Query` et `Body`. + +/// + +## Ajouter des informations supplĂ©mentaires { #add-extra-information } + +Vous pouvez dĂ©clarer des informations supplĂ©mentaires dans `Field`, `Query`, `Body`, etc. Elles seront incluses dans le JSON Schema gĂ©nĂ©rĂ©. + +Vous en apprendrez davantage sur l'ajout d'informations supplĂ©mentaires plus loin dans les documents, lorsque vous apprendrez Ă  dĂ©clarer des exemples. + +/// warning | Alertes + +Les clĂ©s supplĂ©mentaires passĂ©es Ă  `Field` seront Ă©galement prĂ©sentes dans le schĂ©ma OpenAPI rĂ©sultant pour votre application. +Comme ces clĂ©s ne font pas nĂ©cessairement partie de la spĂ©cification OpenAPI, certains outils OpenAPI, par exemple [le validateur OpenAPI](https://validator.swagger.io/), peuvent ne pas fonctionner avec votre schĂ©ma gĂ©nĂ©rĂ©. + +/// + +## RĂ©capitulatif { #recap } + +Vous pouvez utiliser `Field` de Pydantic pour dĂ©clarer des validations supplĂ©mentaires et des mĂ©tadonnĂ©es pour les attributs de modĂšle. + +Vous pouvez Ă©galement utiliser des arguments nommĂ©s supplĂ©mentaires pour transmettre des mĂ©tadonnĂ©es JSON Schema additionnelles. diff --git a/docs/fr/docs/tutorial/body-multiple-params.md b/docs/fr/docs/tutorial/body-multiple-params.md index 92ca2afc3..1c1ab0fca 100644 --- a/docs/fr/docs/tutorial/body-multiple-params.md +++ b/docs/fr/docs/tutorial/body-multiple-params.md @@ -104,12 +104,6 @@ Comme, par dĂ©faut, les valeurs singuliĂšres sont interprĂ©tĂ©es comme des param q: str | None = None ``` -Ou en Python 3.9 : - -```Python -q: Union[str, None] = None -``` - Par exemple : {* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *} diff --git a/docs/fr/docs/tutorial/body-nested-models.md b/docs/fr/docs/tutorial/body-nested-models.md new file mode 100644 index 000000000..dccfdb6c5 --- /dev/null +++ b/docs/fr/docs/tutorial/body-nested-models.md @@ -0,0 +1,220 @@ +# Corps - ModĂšles imbriquĂ©s { #body-nested-models } + +Avec FastAPI, vous pouvez dĂ©finir, valider, documenter et utiliser des modĂšles imbriquĂ©s Ă  n'importe quelle profondeur (grĂące Ă  Pydantic). + +## DĂ©clarer des champs de liste { #list-fields } + +Vous pouvez dĂ©finir un attribut comme Ă©tant un sous-type. Par exemple, une `list` Python : + +{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *} + +Cela fera de `tags` une liste, bien que le type des Ă©lĂ©ments de la liste ne soit pas dĂ©clarĂ©. + +## Champs de liste avec paramĂštre de type { #list-fields-with-type-parameter } + +Mais Python a une maniĂšre spĂ©cifique de dĂ©clarer des listes avec des types internes, ou « paramĂštres de type » : + +### DĂ©clarer une `list` avec un paramĂštre de type { #declare-a-list-with-a-type-parameter } + +Pour dĂ©clarer des types qui ont des paramĂštres de type (types internes), comme `list`, `dict`, `tuple`, +passez le(s) type(s) interne(s) comme « paramĂštres de type » Ă  l'aide de crochets : `[` et `]` + +```Python +my_list: list[str] +``` + +C'est simplement la syntaxe Python standard pour les dĂ©clarations de type. + +Utilisez cette mĂȘme syntaxe standard pour les attributs de modĂšles avec des types internes. + +Ainsi, dans notre exemple, nous pouvons faire de `tags` spĂ©cifiquement une « liste de chaĂźnes » : + +{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *} + +## Types set { #set-types } + +Mais en y rĂ©flĂ©chissant, nous rĂ©alisons que les tags ne devraient pas se rĂ©pĂ©ter, ce seraient probablement des chaĂźnes uniques. + +Et Python dispose d'un type de donnĂ©es spĂ©cial pour les ensembles d'Ă©lĂ©ments uniques, le `set`. + +Nous pouvons alors dĂ©clarer `tags` comme un set de chaĂźnes : + +{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *} + +Avec cela, mĂȘme si vous recevez une requĂȘte contenant des doublons, elle sera convertie en un set d'Ă©lĂ©ments uniques. + +Et chaque fois que vous renverrez ces donnĂ©es, mĂȘme si la source contenait des doublons, elles seront renvoyĂ©es sous la forme d'un set d'Ă©lĂ©ments uniques. + +Elles seront Ă©galement annotĂ©es / documentĂ©es en consĂ©quence. + +## ModĂšles imbriquĂ©s { #nested-models } + +Chaque attribut d'un modĂšle Pydantic a un type. + +Mais ce type peut lui-mĂȘme ĂȘtre un autre modĂšle Pydantic. + +Ainsi, vous pouvez dĂ©clarer des « objets » JSON profondĂ©ment imbriquĂ©s avec des noms d'attributs, des types et des validations spĂ©cifiques. + +Tout cela, de maniĂšre arbitrairement imbriquĂ©e. + +### DĂ©finir un sous-modĂšle { #define-a-submodel } + +Par exemple, nous pouvons dĂ©finir un modĂšle `Image` : + +{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *} + +### Utiliser le sous-modĂšle comme type { #use-the-submodel-as-a-type } + +Nous pouvons ensuite l'utiliser comme type d'un attribut : + +{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *} + +Cela signifie que FastAPI attendrait un corps similaire Ă  : + +```JSON +{ + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2, + "tags": ["rock", "metal", "bar"], + "image": { + "url": "http://example.com/baz.jpg", + "name": "The Foo live" + } +} +``` + +LĂ  encore, avec cette simple dĂ©claration, avec FastAPI vous obtenez : + +- Prise en charge par l'Ă©diteur (autocomplĂ©tion, etc.), mĂȘme pour les modĂšles imbriquĂ©s +- Conversion des donnĂ©es +- Validation des donnĂ©es +- Documentation automatique + +## Types spĂ©ciaux et validation { #special-types-and-validation } + +Outre les types singuliers normaux comme `str`, `int`, `float`, etc. vous pouvez utiliser des types singuliers plus complexes qui hĂ©ritent de `str`. + +Pour voir toutes les options dont vous disposez, consultez l’aperçu des types de Pydantic. Vous verrez quelques exemples au chapitre suivant. + +Par exemple, comme dans le modĂšle `Image` nous avons un champ `url`, nous pouvons le dĂ©clarer comme instance de `HttpUrl` de Pydantic au lieu de `str` : + +{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *} + +La chaĂźne sera vĂ©rifiĂ©e comme URL valide et documentĂ©e comme telle dans JSON Schema / OpenAPI. + +## Attributs avec des listes de sous-modĂšles { #attributes-with-lists-of-submodels } + +Vous pouvez Ă©galement utiliser des modĂšles Pydantic comme sous-types de `list`, `set`, etc. : + +{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *} + +Cela attendra (convertira, validera, documentera, etc.) un corps JSON comme : + +```JSON hl_lines="11" +{ + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2, + "tags": [ + "rock", + "metal", + "bar" + ], + "images": [ + { + "url": "http://example.com/baz.jpg", + "name": "The Foo live" + }, + { + "url": "http://example.com/dave.jpg", + "name": "The Baz" + } + ] +} +``` +/// info + +Remarquez que la clĂ© `images` contient maintenant une liste d'objets image. + +/// + +## ModĂšles profondĂ©ment imbriquĂ©s { #deeply-nested-models } + +Vous pouvez dĂ©finir des modĂšles imbriquĂ©s Ă  une profondeur arbitraire : + +{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *} + +/// info + +Remarquez que `Offer` a une liste d’`Item`, qui Ă  leur tour ont une liste optionnelle d’`Image`. + +/// + +## Corps de listes pures { #bodies-of-pure-lists } + +Si la valeur de premier niveau du corps JSON attendu est un `array` JSON (une `list` Python), vous pouvez dĂ©clarer le type dans le paramĂštre de la fonction, de la mĂȘme maniĂšre que dans les modĂšles Pydantic : + +```Python +images: list[Image] +``` + +comme : + +{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *} + +## BĂ©nĂ©ficier de la prise en charge de l'Ă©diteur partout { #editor-support-everywhere } + +Et vous bĂ©nĂ©ficiez de la prise en charge de l'Ă©diteur partout. + +MĂȘme pour les Ă©lĂ©ments Ă  l'intĂ©rieur des listes : + + + +Vous ne pourriez pas obtenir ce type de prise en charge de l'Ă©diteur si vous travailliez directement avec des `dict` au lieu de modĂšles Pydantic. + +Mais vous n'avez pas Ă  vous en soucier non plus, les `dict` entrants sont convertis automatiquement et votre sortie est Ă©galement convertie automatiquement en JSON. + +## Corps de `dict` arbitraires { #bodies-of-arbitrary-dicts } + +Vous pouvez Ă©galement dĂ©clarer un corps comme un `dict` avec des clĂ©s d’un certain type et des valeurs d’un autre type. + +De cette façon, vous n'avez pas besoin de savoir Ă  l'avance quels sont les noms de champs/attributs valides (comme ce serait le cas avec des modĂšles Pydantic). + +Cela serait utile si vous voulez recevoir des clĂ©s que vous ne connaissez pas Ă  l'avance. + +--- + +Un autre cas utile est lorsque vous souhaitez avoir des clĂ©s d'un autre type (par exemple `int`). + +C'est ce que nous allons voir ici. + +Dans ce cas, vous accepteriez n'importe quel `dict` tant qu'il a des clĂ©s `int` avec des valeurs `float` : + +{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *} + +/// tip | Astuce + +Gardez Ă  l'esprit que JSON ne prend en charge que des `str` comme clĂ©s. + +Mais Pydantic dispose d'une conversion automatique des donnĂ©es. + +Cela signifie que, mĂȘme si vos clients d'API ne peuvent envoyer que des chaĂźnes comme clĂ©s, tant que ces chaĂźnes contiennent des entiers purs, Pydantic les convertira et les validera. + +Et le `dict` que vous recevez dans `weights` aura en rĂ©alitĂ© des clĂ©s `int` et des valeurs `float`. + +/// + +## RĂ©capitulatif { #recap } + +Avec FastAPI, vous bĂ©nĂ©ficiez de la flexibilitĂ© maximale fournie par les modĂšles Pydantic, tout en gardant votre code simple, concis et Ă©lĂ©gant. + +Mais avec tous les avantages : + +- Prise en charge par l'Ă©diteur (autocomplĂ©tion partout !) +- Conversion des donnĂ©es (a.k.a. parsing / sĂ©rialisation) +- Validation des donnĂ©es +- Documentation des schĂ©mas +- Documentation automatique diff --git a/docs/fr/docs/tutorial/body-updates.md b/docs/fr/docs/tutorial/body-updates.md new file mode 100644 index 000000000..36ad12681 --- /dev/null +++ b/docs/fr/docs/tutorial/body-updates.md @@ -0,0 +1,100 @@ +# Corps - Mises Ă  jour { #body-updates } + +## Mettre Ă  jour en remplaçant avec `PUT` { #update-replacing-with-put } + +Pour mettre Ă  jour un Ă©lĂ©ment, vous pouvez utiliser l’opĂ©ration HTTP `PUT`. + +Vous pouvez utiliser le `jsonable_encoder` pour convertir les donnĂ©es d’entrĂ©e en donnĂ©es pouvant ĂȘtre stockĂ©es au format JSON (par exemple, avec une base de donnĂ©es NoSQL). Par exemple, convertir `datetime` en `str`. + +{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *} + +On utilise `PUT` pour recevoir des donnĂ©es qui doivent remplacer les donnĂ©es existantes. + +### Avertissement concernant le remplacement { #warning-about-replacing } + +Cela signifie que si vous souhaitez mettre Ă  jour l’élĂ©ment `bar` avec `PUT` et un corps contenant : + +```Python +{ + "name": "Barz", + "price": 3, + "description": None, +} +``` + +comme il n’inclut pas l’attribut dĂ©jĂ  enregistrĂ© « tax »: 20.2, le modĂšle d’entrĂ©e prendrait la valeur par dĂ©faut « tax »: 10.5. + +Et les donnĂ©es seraient enregistrĂ©es avec cette « nouvelle » `tax` de `10.5`. + +## Effectuer des mises Ă  jour partielles avec `PATCH` { #partial-updates-with-patch } + +Vous pouvez Ă©galement utiliser l’opĂ©ration HTTP `PATCH` pour mettre Ă  jour des donnĂ©es de maniĂšre partielle. + +Cela signifie que vous pouvez n’envoyer que les donnĂ©es que vous souhaitez mettre Ă  jour, en laissant le reste intact. + +/// note | Remarque + +`PATCH` est moins utilisĂ© et moins connu que `PUT`. + +Et de nombreuses Ă©quipes n’utilisent que `PUT`, mĂȘme pour les mises Ă  jour partielles. + +Vous ĂȘtes libre de les utiliser comme vous le souhaitez, **FastAPI** n’impose aucune restriction. + +Mais ce guide vous montre, plus ou moins, la façon dont ils sont censĂ©s ĂȘtre utilisĂ©s. + +/// + +### Utiliser le paramĂštre `exclude_unset` de Pydantic { #using-pydantics-exclude-unset-parameter } + +Si vous souhaitez recevoir des mises Ă  jour partielles, il est trĂšs utile d’utiliser le paramĂštre `exclude_unset` dans la mĂ©thode `.model_dump()` du modĂšle Pydantic. + +Comme `item.model_dump(exclude_unset=True)`. + +Cela gĂ©nĂšre un `dict` ne contenant que les donnĂ©es dĂ©finies lors de la crĂ©ation du modĂšle `item`, en excluant les valeurs par dĂ©faut. + +Vous pouvez ensuite l’utiliser pour produire un `dict` avec uniquement les donnĂ©es dĂ©finies (envoyĂ©es dans la requĂȘte), en omettant les valeurs par dĂ©faut : + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *} + +### Utiliser le paramĂštre `update` de Pydantic { #using-pydantics-update-parameter } + +Vous pouvez maintenant crĂ©er une copie du modĂšle existant avec `.model_copy()`, et passer le paramĂštre `update` avec un `dict` contenant les donnĂ©es Ă  mettre Ă  jour. + +Comme `stored_item_model.model_copy(update=update_data)` : + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *} + +### RĂ©capitulatif des mises Ă  jour partielles { #partial-updates-recap } + +En rĂ©sumĂ©, pour appliquer des mises Ă  jour partielles, vous procĂ©dez ainsi : + +* (Optionnel) utilisez `PATCH` au lieu de `PUT`. +* RĂ©cupĂ©rez les donnĂ©es stockĂ©es. +* Placez ces donnĂ©es dans un modĂšle Pydantic. +* GĂ©nĂ©rez un `dict` sans valeurs par dĂ©faut Ă  partir du modĂšle d’entrĂ©e (en utilisant `exclude_unset`). + * De cette façon, vous mettez Ă  jour uniquement les valeurs effectivement dĂ©finies par l’utilisateur, au lieu d’écraser des valeurs dĂ©jĂ  stockĂ©es par des valeurs par dĂ©faut de votre modĂšle. +* CrĂ©ez une copie du modĂšle stockĂ©, en mettant Ă  jour ses attributs avec les mises Ă  jour partielles reçues (en utilisant le paramĂštre `update`). +* Convertissez le modĂšle copiĂ© en quelque chose qui peut ĂȘtre stockĂ© dans votre base de donnĂ©es (par exemple en utilisant le `jsonable_encoder`). + * Cela est comparable Ă  l’utilisation Ă  nouveau de la mĂ©thode `.model_dump()` du modĂšle, mais cela vĂ©rifie (et convertit) les valeurs vers des types pouvant ĂȘtre convertis en JSON, par exemple `datetime` en `str`. +* Enregistrez les donnĂ©es dans votre base de donnĂ©es. +* Retournez le modĂšle mis Ă  jour. + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *} + +/// tip | Astuce + +Vous pouvez en rĂ©alitĂ© utiliser cette mĂȘme technique avec une opĂ©ration HTTP `PUT`. + +Mais l’exemple ici utilise `PATCH` car il a Ă©tĂ© créé pour ces cas d’usage. + +/// + +/// note | Remarque + +Remarquez que le modĂšle d’entrĂ©e est toujours validĂ©. + +Ainsi, si vous souhaitez recevoir des mises Ă  jour partielles pouvant omettre tous les attributs, vous devez disposer d’un modĂšle avec tous les attributs marquĂ©s comme optionnels (avec des valeurs par dĂ©faut ou `None`). + +Pour distinguer les modĂšles avec toutes les valeurs optionnelles pour les mises Ă  jour et les modĂšles avec des valeurs requises pour la crĂ©ation, vous pouvez utiliser les idĂ©es dĂ©crites dans [ModĂšles supplĂ©mentaires](extra-models.md){.internal-link target=_blank}. + +/// diff --git a/docs/fr/docs/tutorial/body.md b/docs/fr/docs/tutorial/body.md index ca115fabc..a8703e030 100644 --- a/docs/fr/docs/tutorial/body.md +++ b/docs/fr/docs/tutorial/body.md @@ -10,7 +10,7 @@ Pour dĂ©clarer un corps de **requĂȘte**, on utilise les modĂšles de -Et seront aussi utilisĂ©s dans chaque *opĂ©ration de chemin* de la documentation utilisant ces modĂšles : +Et seront aussi utilisĂ©s dans chaque *chemin d'accĂšs* de la documentation utilisant ces modĂšles : @@ -115,7 +115,7 @@ Ce qui amĂ©liore le support pour les modĂšles Pydantic avec : * de l'autocomplĂ©tion * des vĂ©rifications de type -* du « refactoring » (ou remaniement de code) +* du « refactoring » * de la recherche * des inspections @@ -129,7 +129,7 @@ Dans la fonction, vous pouvez accĂ©der Ă  tous les attributs de l'objet du modĂš ## Corps de la requĂȘte + paramĂštres de chemin { #request-body-path-parameters } -Vous pouvez dĂ©clarer des paramĂštres de chemin et un corps de requĂȘte pour la mĂȘme *opĂ©ration de chemin*. +Vous pouvez dĂ©clarer des paramĂštres de chemin et un corps de requĂȘte pour la mĂȘme *chemin d'accĂšs*. **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**. @@ -137,7 +137,7 @@ Vous pouvez dĂ©clarer des paramĂštres de chemin et un corps de requĂȘte pour la ## 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 un **corps**, et des paramĂštres de **chemin** et de **requĂȘte** dans la mĂȘme *chemin d'accĂšs*. **FastAPI** saura reconnaĂźtre chacun d'entre eux et rĂ©cupĂ©rer la bonne donnĂ©e au bon endroit. @@ -153,7 +153,7 @@ Les paramĂštres de la fonction seront reconnus comme tel : **FastAPI** saura que la valeur de `q` n'est pas requise grĂące Ă  la valeur par dĂ©faut `= None`. -L'annotation de type `str | None` (Python 3.10+) ou `Union` dans `Union[str, None]` (Python 3.9+) n'est pas utilisĂ©e par **FastAPI** pour dĂ©terminer que la valeur n'est pas requise, il le saura parce qu'elle a une valeur par dĂ©faut `= None`. +L'annotation de type `str | None` n'est pas utilisĂ©e par **FastAPI** pour dĂ©terminer que la valeur n'est pas requise, il le saura parce qu'elle a une valeur par dĂ©faut `= None`. Mais ajouter ces annotations de type permettra Ă  votre Ă©diteur de vous offrir un meilleur support et de dĂ©tecter des erreurs. diff --git a/docs/fr/docs/tutorial/cookie-param-models.md b/docs/fr/docs/tutorial/cookie-param-models.md new file mode 100644 index 000000000..c6fc2f826 --- /dev/null +++ b/docs/fr/docs/tutorial/cookie-param-models.md @@ -0,0 +1,76 @@ +# ModĂšles de paramĂštres de cookies { #cookie-parameter-models } + +Si vous avez un groupe de **cookies** liĂ©s, vous pouvez crĂ©er un **modĂšle Pydantic** pour les dĂ©clarer. đŸȘ + +Cela vous permet de **rĂ©utiliser le modĂšle** Ă  **plusieurs endroits** et aussi de dĂ©clarer des validations et des mĂ©tadonnĂ©es pour tous les paramĂštres en une seule fois. 😎 + +/// note | Remarque + +Ceci est pris en charge depuis la version `0.115.0` de FastAPI. đŸ€“ + +/// + +/// tip | Astuce + +Cette mĂȘme technique s'applique Ă  `Query`, `Cookie` et `Header`. 😎 + +/// + +## DĂ©clarer des cookies avec un modĂšle Pydantic { #cookies-with-a-pydantic-model } + +DĂ©clarez les paramĂštres de **cookie** dont vous avez besoin dans un **modĂšle Pydantic**, puis dĂ©clarez le paramĂštre comme `Cookie` : + +{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *} + +**FastAPI** va **extraire** les donnĂ©es pour **chaque champ** Ă  partir des **cookies** reçus dans la requĂȘte et vous fournir le modĂšle Pydantic que vous avez dĂ©fini. + +## Consulter la documentation { #check-the-docs } + +Vous pouvez voir les cookies dĂ©finis dans l'interface de la documentation Ă  `/docs` : + +
+ +
+ +/// info + +Gardez Ă  l'esprit que, comme les **navigateurs gĂšrent les cookies** de maniĂšre particuliĂšre et en arriĂšre-plan, ils **n'autorisent pas** facilement **JavaScript** Ă  y accĂ©der. + +Si vous allez dans **l'interface de la documentation de l'API** Ă  `/docs`, vous pourrez voir la **documentation** des cookies pour vos *chemins d'accĂšs*. + +Mais mĂȘme si vous **remplissez les donnĂ©es** et cliquez sur « Execute », comme l'interface de la documentation fonctionne avec **JavaScript**, les cookies ne seront pas envoyĂ©s et vous verrez un **message d'erreur** comme si vous n'aviez saisi aucune valeur. + +/// + +## Interdire les cookies supplĂ©mentaires { #forbid-extra-cookies } + +Dans certains cas d'utilisation particuliers (probablement peu courants), vous pourriez vouloir **restreindre** les cookies que vous souhaitez recevoir. + +Votre API a dĂ©sormais le pouvoir de contrĂŽler son propre consentement aux cookies. đŸ€ȘđŸȘ + +Vous pouvez utiliser la configuration du modĂšle de Pydantic pour `forbid` tout champ `extra` : + +{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *} + +Si un client tente d'envoyer des **cookies supplĂ©mentaires**, il recevra une **rĂ©ponse d'erreur**. + +Pauvres banniĂšres de cookies, avec tous leurs efforts pour obtenir votre consentement pour que l'API pour le rejeter. đŸȘ + +Par exemple, si le client tente d'envoyer un cookie `santa_tracker` avec la valeur `good-list-please`, il recevra une **rĂ©ponse d'erreur** lui indiquant que le `santa_tracker` le cookie n'est pas autorisĂ© : + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["cookie", "santa_tracker"], + "msg": "Extra inputs are not permitted", + "input": "good-list-please", + } + ] +} +``` + +## RĂ©capitulatif { #summary } + +Vous pouvez utiliser des **modĂšles Pydantic** pour dĂ©clarer des **cookies** dans **FastAPI**. 😎 diff --git a/docs/fr/docs/tutorial/cookie-params.md b/docs/fr/docs/tutorial/cookie-params.md new file mode 100644 index 000000000..8f77d35dc --- /dev/null +++ b/docs/fr/docs/tutorial/cookie-params.md @@ -0,0 +1,45 @@ +# ParamĂštres de cookie { #cookie-parameters } + +Vous pouvez dĂ©finir des paramĂštres de cookie de la mĂȘme maniĂšre que vous dĂ©finissez les paramĂštres `Query` et `Path`. + +## Importer `Cookie` { #import-cookie } + +Commencez par importer `Cookie` : + +{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *} + +## DĂ©clarer des paramĂštres `Cookie` { #declare-cookie-parameters } + +DĂ©clarez ensuite les paramĂštres de cookie en utilisant la mĂȘme structure qu'avec `Path` et `Query`. + +Vous pouvez dĂ©finir la valeur par dĂ©faut ainsi que tous les paramĂštres supplĂ©mentaires de validation ou d'annotation : + +{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *} + +/// note | DĂ©tails techniques + +`Cookie` est une classe « sƓur » de `Path` et `Query`. Elle hĂ©rite Ă©galement de la mĂȘme classe commune `Param`. + +Mais rappelez-vous que lorsque vous importez `Query`, `Path`, `Cookie` et d'autres depuis `fastapi`, il s'agit en rĂ©alitĂ© de fonctions qui renvoient des classes spĂ©ciales. + +/// + +/// info + +Pour dĂ©clarer des cookies, vous devez utiliser `Cookie`, sinon les paramĂštres seraient interprĂ©tĂ©s comme des paramĂštres de requĂȘte. + +/// + +/// info + +Gardez Ă  l'esprit que, comme **les navigateurs gĂšrent les cookies** de maniĂšre particuliĂšre et en coulisses, ils **n'autorisent pas** facilement **JavaScript** Ă  y accĂ©der. + +Si vous allez dans l'**interface de la documentation de l'API** Ă  `/docs`, vous pourrez voir la **documentation** des cookies pour vos *chemins d'accĂšs*. + +Mais mĂȘme si vous **renseignez les donnĂ©es** et cliquez sur « Execute », comme l'interface de documentation fonctionne avec **JavaScript**, les cookies ne seront pas envoyĂ©s et vous verrez un message **d'erreur** comme si vous n'aviez saisi aucune valeur. + +/// + +## RĂ©capitulatif { #recap } + +DĂ©clarez les cookies avec `Cookie`, en utilisant le mĂȘme schĂ©ma commun que `Query` et `Path`. diff --git a/docs/fr/docs/tutorial/cors.md b/docs/fr/docs/tutorial/cors.md new file mode 100644 index 000000000..3ae7de07c --- /dev/null +++ b/docs/fr/docs/tutorial/cors.md @@ -0,0 +1,88 @@ +# CORS (Partage des ressources entre origines) { #cors-cross-origin-resource-sharing } + +
CORS ou « Cross-Origin Resource Sharing » fait rĂ©fĂ©rence aux situations oĂč un frontend exĂ©cutĂ© dans un navigateur contient du code JavaScript qui communique avec un backend, et oĂč le backend se trouve dans une « origine » diffĂ©rente de celle du frontend. + +## Origine { #origin } + +Une origine est la combinaison du protocole (`http`, `https`), du domaine (`myapp.com`, `localhost`, `localhost.tiangolo.com`) et du port (`80`, `443`, `8080`). + +Ainsi, toutes celles-ci sont des origines diffĂ©rentes : + +* `http://localhost` +* `https://localhost` +* `http://localhost:8080` + +MĂȘme si elles sont toutes sur `localhost`, elles utilisent des protocoles ou des ports diffĂ©rents, ce sont donc des « origines » diffĂ©rentes. + +## Étapes { #steps } + +Disons donc que vous avez un frontend exĂ©cutĂ© dans votre navigateur Ă  `http://localhost:8080`, et que son JavaScript essaie de communiquer avec un backend exĂ©cutĂ© Ă  `http://localhost` (comme nous ne spĂ©cifions pas de port, le navigateur supposera le port par dĂ©faut `80`). + +Le navigateur enverra alors une requĂȘte HTTP `OPTIONS` au backend `:80`, et si le backend envoie les en-tĂȘtes appropriĂ©s autorisant la communication depuis cette origine diffĂ©rente (`http://localhost:8080`), alors le navigateur `:8080` permettra au JavaScript du frontend d’envoyer sa requĂȘte au backend `:80`. + +Pour y parvenir, le backend `:80` doit disposer d’une liste « d’origines autorisĂ©es ». + +Dans ce cas, la liste devrait inclure `http://localhost:8080` pour que le frontend `:8080` fonctionne correctement. + +## CaractĂšres gĂ©nĂ©riques { #wildcards } + +Il est Ă©galement possible de dĂ©clarer la liste comme « * » (un « wildcard ») pour indiquer que toutes sont autorisĂ©es. + +Mais cela n’autorisera que certains types de communication, en excluant tout ce qui implique des informations d’identification : cookies, en-tĂȘtes Authorization comme ceux utilisĂ©s avec les Bearer Tokens, etc. + +Ainsi, pour que tout fonctionne correctement, il est prĂ©fĂ©rable d’indiquer explicitement les origines autorisĂ©es. + +## Utiliser `CORSMiddleware` { #use-corsmiddleware } + +Vous pouvez le configurer dans votre application **FastAPI** Ă  l’aide de `CORSMiddleware`. + +* Importer `CORSMiddleware`. +* CrĂ©er une liste d’origines autorisĂ©es (sous forme de chaĂźnes). +* L’ajouter comme « middleware » Ă  votre application **FastAPI**. + +Vous pouvez Ă©galement spĂ©cifier si votre backend autorise : + +* Les informations d’identification (en-tĂȘtes Authorization, cookies, etc.). +* Des mĂ©thodes HTTP spĂ©cifiques (`POST`, `PUT`) ou toutes avec le caractĂšre gĂ©nĂ©rique « * ». +* Des en-tĂȘtes HTTP spĂ©cifiques ou tous avec le caractĂšre gĂ©nĂ©rique « * ». + +{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *} + +Les paramĂštres utilisĂ©s par dĂ©faut par l’implĂ©mentation de `CORSMiddleware` sont restrictifs, vous devez donc activer explicitement des origines, mĂ©thodes ou en-tĂȘtes particuliers afin que les navigateurs soient autorisĂ©s Ă  les utiliser dans un contexte inter‑domaine. + +Les arguments suivants sont pris en charge : + +* `allow_origins` - Une liste d’origines autorisĂ©es Ă  effectuer des requĂȘtes cross-origin. Par ex. `['https://example.org', 'https://www.example.org']`. Vous pouvez utiliser `['*']` pour autoriser n’importe quelle origine. +* `allow_origin_regex` - Une chaĂźne regex pour faire correspondre les origines autorisĂ©es Ă  effectuer des requĂȘtes cross-origin. Par ex. `'https://.*\.example\.org'`. +* `allow_methods` - Une liste de mĂ©thodes HTTP qui doivent ĂȘtre autorisĂ©es pour les requĂȘtes cross-origin. Par dĂ©faut `['GET']`. Vous pouvez utiliser `['*']` pour autoriser toutes les mĂ©thodes standard. +* `allow_headers` - Une liste d’en-tĂȘtes HTTP de requĂȘte qui doivent ĂȘtre pris en charge pour les requĂȘtes cross-origin. Par dĂ©faut `[]`. Vous pouvez utiliser `['*']` pour autoriser tous les en-tĂȘtes. Les en-tĂȘtes `Accept`, `Accept-Language`, `Content-Language` et `Content-Type` sont toujours autorisĂ©s pour les requĂȘtes CORS simples. +* `allow_credentials` - Indique que les cookies doivent ĂȘtre pris en charge pour les requĂȘtes cross-origin. Par dĂ©faut `False`. + + Aucun de `allow_origins`, `allow_methods` et `allow_headers` ne peut ĂȘtre dĂ©fini Ă  `['*']` si `allow_credentials` est dĂ©fini Ă  `True`. Ils doivent tous ĂȘtre spĂ©cifiĂ©s explicitement. + +* `expose_headers` - Indique les en-tĂȘtes de rĂ©ponse qui doivent ĂȘtre accessibles au navigateur. Par dĂ©faut `[]`. +* `max_age` - DĂ©finit un temps maximum (en secondes) pendant lequel les navigateurs peuvent mettre en cache les rĂ©ponses CORS. Par dĂ©faut `600`. + +Le middleware rĂ©pond Ă  deux types particuliers de requĂȘtes HTTP ... + +### RequĂȘtes CORS de pré‑vĂ©rification { #cors-preflight-requests } + +Il s’agit de toute requĂȘte `OPTIONS` avec les en-tĂȘtes `Origin` et `Access-Control-Request-Method`. + +Dans ce cas, le middleware interceptera la requĂȘte entrante et rĂ©pondra avec les en-tĂȘtes CORS appropriĂ©s, et soit une rĂ©ponse `200`, soit `400` Ă  titre informatif. + +### RequĂȘtes simples { #simple-requests } + +Toute requĂȘte avec un en-tĂȘte `Origin`. Dans ce cas, le middleware laissera passer la requĂȘte normalement, mais inclura les en-tĂȘtes CORS appropriĂ©s dans la rĂ©ponse. + +## En savoir plus { #more-info } + +Pour plus d’informations sur CORS, consultez la documentation CORS de Mozilla. + +/// note | DĂ©tails techniques + +Vous pouvez Ă©galement utiliser `from starlette.middleware.cors import CORSMiddleware`. + +**FastAPI** fournit plusieurs middlewares dans `fastapi.middleware` uniquement pour votre confort, en tant que dĂ©veloppeur. Mais la plupart des middlewares disponibles proviennent directement de Starlette. + +/// diff --git a/docs/fr/docs/tutorial/debugging.md b/docs/fr/docs/tutorial/debugging.md index a88fa2b23..d69e6a3ba 100644 --- a/docs/fr/docs/tutorial/debugging.md +++ b/docs/fr/docs/tutorial/debugging.md @@ -6,7 +6,7 @@ Vous pouvez connecter le dĂ©bogueur da Dans votre application FastAPI, importez et exĂ©cutez directement `uvicorn` : -{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *} ### À propos de `__name__ == "__main__"` { #about-name-main } @@ -87,7 +87,7 @@ Parce que vous exĂ©cutez le serveur Uvicorn directement depuis votre code, vous Par exemple, dans Visual Studio Code, vous pouvez : - Allez dans le panneau « Debug ». -- « Add configuration... ». +- « Add configuration ... ». - SĂ©lectionnez « Python ». - Lancez le dĂ©bogueur avec l'option « Python: Current File (Integrated Terminal) ». @@ -102,7 +102,7 @@ Voici Ă  quoi cela pourrait ressembler : Si vous utilisez Pycharm, vous pouvez : - Ouvrez le menu « Run ». -- SĂ©lectionnez l'option « Debug... ». +- SĂ©lectionnez l'option « Debug ... ». - Un menu contextuel s'affiche alors. - SĂ©lectionnez le fichier Ă  dĂ©boguer (dans ce cas, `main.py`). diff --git a/docs/fr/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/fr/docs/tutorial/dependencies/classes-as-dependencies.md new file mode 100644 index 000000000..69bc6008a --- /dev/null +++ b/docs/fr/docs/tutorial/dependencies/classes-as-dependencies.md @@ -0,0 +1,288 @@ +# Utiliser des classes comme dĂ©pendances { #classes-as-dependencies } + +Avant d'aller plus loin dans le systĂšme d'**Injection de dĂ©pendances**, mettons Ă  niveau l'exemple prĂ©cĂ©dent. + +## Un `dict` de l'exemple prĂ©cĂ©dent { #a-dict-from-the-previous-example } + +Dans l'exemple prĂ©cĂ©dent, nous renvoyions un `dict` depuis notre dĂ©pendance (« dependable ») : + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *} + +Mais nous recevons alors un `dict` dans le paramĂštre `commons` de la fonction de chemin d'accĂšs. + +Et les Ă©diteurs ne peuvent pas apporter beaucoup d'assistance (comme l'autocomplĂ©tion) pour les `dict`, car ils ne peuvent pas connaĂźtre leurs clĂ©s ni les types de valeurs. + +Nous pouvons faire mieux ... + +## Ce qui fait d'un objet une dĂ©pendance { #what-makes-a-dependency } + +Jusqu'Ă  prĂ©sent, vous avez vu des dĂ©pendances dĂ©clarĂ©es sous forme de fonctions. + +Mais ce n'est pas la seule maniĂšre de dĂ©clarer des dĂ©pendances (mĂȘme si c'est probablement la plus courante). + +L'Ă©lĂ©ment clĂ© est qu'une dĂ©pendance doit ĂȘtre un « callable ». + +Un « callable » en Python est tout ce que Python peut « appeler » comme une fonction. + +Ainsi, si vous avez un objet `something` (qui n'est peut‑ĂȘtre pas une fonction) et que vous pouvez « l'appeler » (l'exĂ©cuter) comme : + +```Python +something() +``` + +ou + +```Python +something(some_argument, some_keyword_argument="foo") +``` + +alors c'est un « callable ». + +## Utiliser des classes comme dĂ©pendances { #classes-as-dependencies_1 } + +Vous remarquerez que pour crĂ©er une instance d'une classe Python, vous utilisez la mĂȘme syntaxe. + +Par exemple : + +```Python +class Cat: + def __init__(self, name: str): + self.name = name + + +fluffy = Cat(name="Mr Fluffy") +``` + +Dans ce cas, `fluffy` est une instance de la classe `Cat`. + +Et pour crĂ©er `fluffy`, vous « appelez » `Cat`. + +Donc, une classe Python est aussi un « callable ». + +Ainsi, avec **FastAPI**, vous pouvez utiliser une classe Python comme dĂ©pendance. + +Ce que **FastAPI** vĂ©rifie rĂ©ellement, c'est qu'il s'agit d'un « callable » (fonction, classe ou autre) et des paramĂštres qui y sont dĂ©finis. + +Si vous passez un « callable » comme dĂ©pendance dans **FastAPI**, il en analysera les paramĂštres et les traitera de la mĂȘme maniĂšre que les paramĂštres d'une fonction de chemin d'accĂšs. Y compris les sous‑dĂ©pendances. + +Cela s'applique Ă©galement aux callables sans aucun paramĂštre. Comme ce serait le cas pour des fonctions de chemin d'accĂšs sans paramĂštres. + +Nous pouvons alors remplacer la dĂ©pendance « dependable » `common_parameters` ci‑dessus par la classe `CommonQueryParams` : + +{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *} + +Faites attention Ă  la mĂ©thode `__init__` utilisĂ©e pour crĂ©er l'instance de la classe : + +{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *} + +... il a les mĂȘmes paramĂštres que notre prĂ©cĂ©dent `common_parameters` : + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *} + +Ce sont ces paramĂštres que **FastAPI** utilisera pour « rĂ©soudre » la dĂ©pendance. + +Dans les deux cas, il y aura : + +- Un paramĂštre de requĂȘte optionnel `q` qui est un `str`. +- Un paramĂštre de requĂȘte `skip` qui est un `int`, avec une valeur par dĂ©faut de `0`. +- Un paramĂštre de requĂȘte `limit` qui est un `int`, avec une valeur par dĂ©faut de `100`. + +Dans les deux cas, les donnĂ©es seront converties, validĂ©es, documentĂ©es dans le schĂ©ma OpenAPI, etc. + +## Utiliser { #use-it } + +Vous pouvez maintenant dĂ©clarer votre dĂ©pendance en utilisant cette classe. + +{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *} + +**FastAPI** appelle la classe `CommonQueryParams`. Cela crĂ©e une « instance » de cette classe et l'instance sera passĂ©e comme paramĂštre `commons` Ă  votre fonction. + +## Annotation de type vs `Depends` { #type-annotation-vs-depends } + +Remarquez que nous Ă©crivons `CommonQueryParams` deux fois dans le code ci‑dessus : + +//// tab | Python 3.10+ + +```Python +commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.10+ sans Annotated + +/// tip | Astuce + +PrivilĂ©giez la version avec `Annotated` si possible. + +/// + +```Python +commons: CommonQueryParams = Depends(CommonQueryParams) +``` + +//// + +Le dernier `CommonQueryParams`, dans : + +```Python +... Depends(CommonQueryParams) +``` + +... est ce que **FastAPI** utilisera rĂ©ellement pour savoir quelle est la dĂ©pendance. + +C'est Ă  partir de celui‑ci que FastAPI extraira les paramĂštres dĂ©clarĂ©s et c'est ce que FastAPI appellera effectivement. + +--- + +Dans ce cas, le premier `CommonQueryParams`, dans : + +//// tab | Python 3.10+ + +```Python +commons: Annotated[CommonQueryParams, ... +``` + +//// + +//// tab | Python 3.10+ sans Annotated + +/// tip | Astuce + +PrivilĂ©giez la version avec `Annotated` si possible. + +/// + +```Python +commons: CommonQueryParams ... +``` + +//// + +... n'a aucune signification particuliĂšre pour **FastAPI**. FastAPI ne l'utilisera pas pour la conversion des donnĂ©es, la validation, etc. (car il utilise `Depends(CommonQueryParams)` pour cela). + +Vous pourriez en fait Ă©crire simplement : + +//// tab | Python 3.10+ + +```Python +commons: Annotated[Any, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.10+ sans Annotated + +/// tip | Astuce + +PrivilĂ©giez la version avec `Annotated` si possible. + +/// + +```Python +commons = Depends(CommonQueryParams) +``` + +//// + +... comme dans : + +{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *} + +Mais il est recommandĂ© de dĂ©clarer le type ; ainsi, votre Ă©diteur saura ce qui sera passĂ© comme paramĂštre `commons`, et pourra vous aider avec l'autocomplĂ©tion, les vĂ©rifications de type, etc. : + + + +## Raccourci { #shortcut } + +Mais vous voyez qu'il y a ici de la duplication de code : nous Ă©crivons `CommonQueryParams` deux fois : + +//// tab | Python 3.10+ + +```Python +commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.10+ sans Annotated + +/// tip | Astuce + +PrivilĂ©giez la version avec `Annotated` si possible. + +/// + +```Python +commons: CommonQueryParams = Depends(CommonQueryParams) +``` + +//// + +**FastAPI** fournit un raccourci pour ces cas, lorsque la dĂ©pendance est spĂ©cifiquement une classe que **FastAPI** va « appeler » pour crĂ©er une instance de la classe elle‑mĂȘme. + +Pour ces cas prĂ©cis, vous pouvez faire ce qui suit : + +Au lieu d'Ă©crire : + +//// tab | Python 3.10+ + +```Python +commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.10+ sans Annotated + +/// tip | Astuce + +PrivilĂ©giez la version avec `Annotated` si possible. + +/// + +```Python +commons: CommonQueryParams = Depends(CommonQueryParams) +``` + +//// + +... vous Ă©crivez : + +//// tab | Python 3.10+ + +```Python +commons: Annotated[CommonQueryParams, Depends()] +``` + +//// + +//// tab | Python 3.10+ sans Annotated + +/// tip | Astuce + +PrivilĂ©giez la version avec `Annotated` si possible. + +/// + +```Python +commons: CommonQueryParams = Depends() +``` + +//// + +Vous dĂ©clarez la dĂ©pendance comme type du paramĂštre et vous utilisez `Depends()` sans aucun paramĂštre, au lieu d'avoir Ă  réécrire la classe entiĂšre Ă  l'intĂ©rieur de `Depends(CommonQueryParams)`. + +Le mĂȘme exemple ressemblerait alors Ă  ceci : + +{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *} + +... et **FastAPI** saura quoi faire. + +/// tip | Astuce + +Si cela vous semble plus dĂ©routant qu'utile, ignorez‑le, vous n'en avez pas besoin. + +Ce n'est qu'un raccourci. Parce que **FastAPI** tient Ă  vous aider Ă  minimiser la duplication de code. + +/// diff --git a/docs/fr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/fr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md new file mode 100644 index 000000000..bf697fe8d --- /dev/null +++ b/docs/fr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -0,0 +1,69 @@ +# GĂ©rer les dĂ©pendances dans les dĂ©corateurs de chemins d'accĂšs { #dependencies-in-path-operation-decorators } + +Dans certains cas, vous n'avez pas vraiment besoin de la valeur de retour d'une dĂ©pendance dans votre *fonction de chemin d'accĂšs*. + +Ou la dĂ©pendance ne retourne aucune valeur. + +Mais vous avez quand mĂȘme besoin qu'elle soit exĂ©cutĂ©e/rĂ©solue. + +Dans ces cas, au lieu de dĂ©clarer un paramĂštre de *fonction de chemin d'accĂšs* avec `Depends`, vous pouvez ajouter une `list` de `dependencies` au *dĂ©corateur de chemin d'accĂšs*. + +## Ajouter `dependencies` au *dĂ©corateur de chemin d'accĂšs* { #add-dependencies-to-the-path-operation-decorator } + +Le *dĂ©corateur de chemin d'accĂšs* accepte un argument optionnel `dependencies`. + +Il doit s'agir d'une `list` de `Depends()` : + +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *} + +Ces dĂ©pendances seront exĂ©cutĂ©es/rĂ©solues de la mĂȘme maniĂšre que des dĂ©pendances normales. Mais leur valeur (si elles en retournent une) ne sera pas transmise Ă  votre *fonction de chemin d'accĂšs*. + +/// tip | Astuce + +Certains Ă©diteurs vĂ©rifient les paramĂštres de fonction non utilisĂ©s et les signalent comme des erreurs. + +En utilisant ces `dependencies` dans le *dĂ©corateur de chemin d'accĂšs*, vous pouvez vous assurer qu'elles sont exĂ©cutĂ©es tout en Ă©vitant des erreurs de l'Ă©diteur/des outils. + +Cela peut Ă©galement Ă©viter toute confusion pour les nouveaux dĂ©veloppeurs qui voient un paramĂštre inutilisĂ© dans votre code et pourraient penser qu'il est superflu. + +/// + +/// info | Info + +Dans cet exemple, nous utilisons des en-tĂȘtes personnalisĂ©s fictifs `X-Key` et `X-Token`. + +Mais dans des cas rĂ©els, lors de l'implĂ©mentation de la sĂ©curitĂ©, vous tirerez davantage d'avantages en utilisant les [utilitaires de sĂ©curitĂ© (chapitre suivant)](../security/index.md){.internal-link target=_blank} intĂ©grĂ©s. + +/// + +## GĂ©rer les erreurs et les valeurs de retour des dĂ©pendances { #dependencies-errors-and-return-values } + +Vous pouvez utiliser les mĂȘmes *fonctions* de dĂ©pendance que d'habitude. + +### DĂ©finir les exigences des dĂ©pendances { #dependency-requirements } + +Elles peuvent dĂ©clarer des exigences pour la requĂȘte (comme des en-tĂȘtes) ou d'autres sous-dĂ©pendances : + +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *} + +### Lever des exceptions { #raise-exceptions } + +Ces dĂ©pendances peuvent `raise` des exceptions, comme des dĂ©pendances normales : + +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *} + +### GĂ©rer les valeurs de retour { #return-values } + +Elles peuvent retourner des valeurs ou non, ces valeurs ne seront pas utilisĂ©es. + +Vous pouvez donc rĂ©utiliser une dĂ©pendance normale (qui retourne une valeur) que vous utilisez dĂ©jĂ  ailleurs ; mĂȘme si la valeur n'est pas utilisĂ©e, la dĂ©pendance sera exĂ©cutĂ©e : + +{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *} + +## DĂ©finir des dĂ©pendances pour un groupe de chemins d'accĂšs { #dependencies-for-a-group-of-path-operations } + +Plus tard, en lisant comment structurer des applications plus grandes ([Applications plus grandes - Plusieurs fichiers](../../tutorial/bigger-applications.md){.internal-link target=_blank}), Ă©ventuellement avec plusieurs fichiers, vous apprendrez Ă  dĂ©clarer un unique paramĂštre `dependencies` pour un groupe de *chemins d'accĂšs*. + +## DĂ©finir des dĂ©pendances globales { #global-dependencies } + +Ensuite, nous verrons comment ajouter des dĂ©pendances Ă  l'application `FastAPI` entiĂšre, afin qu'elles s'appliquent Ă  chaque *chemin d'accĂšs*. diff --git a/docs/fr/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/fr/docs/tutorial/dependencies/dependencies-with-yield.md new file mode 100644 index 000000000..3f06df767 --- /dev/null +++ b/docs/fr/docs/tutorial/dependencies/dependencies-with-yield.md @@ -0,0 +1,289 @@ +# Utiliser des dĂ©pendances avec `yield` { #dependencies-with-yield } + +FastAPI prend en charge des dĂ©pendances qui effectuent des Ă©tapes supplĂ©mentaires aprĂšs l'exĂ©cution. + +Pour cela, utilisez `yield` au lieu de `return`, et Ă©crivez les Ă©tapes supplĂ©mentaires (code) aprĂšs. + +/// tip | Astuce + +Vous devez vous assurer d'utiliser `yield` une seule fois par dĂ©pendance. + +/// + +/// note | DĂ©tails techniques + +Toute fonction valide Ă  utiliser avec : + +* `@contextlib.contextmanager` ou +* `@contextlib.asynccontextmanager` + +sera valide comme dĂ©pendance **FastAPI**. + +En fait, FastAPI utilise ces deux dĂ©corateurs en interne. + +/// + +## CrĂ©er une dĂ©pendance de base de donnĂ©es avec `yield` { #a-database-dependency-with-yield } + +Par exemple, vous pouvez l'utiliser pour crĂ©er une session de base de donnĂ©es et la fermer aprĂšs la fin. + +Seul le code prĂ©cĂ©dant et incluant l'instruction `yield` est exĂ©cutĂ© avant la crĂ©ation de la rĂ©ponse : + +{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *} + +La valeur transmise par `yield` est celle qui est injectĂ©e dans les *chemins d'accĂšs* et autres dĂ©pendances : + +{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *} + +Le code suivant l'instruction `yield` est exĂ©cutĂ© aprĂšs la rĂ©ponse : + +{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *} + +/// tip | Astuce + +Vous pouvez utiliser des fonctions `async` ou des fonctions classiques. + +**FastAPI** fera ce qu'il faut dans chaque cas, comme avec des dĂ©pendances normales. + +/// + +## CrĂ©er une dĂ©pendance avec `yield` et `try` { #a-dependency-with-yield-and-try } + +Si vous utilisez un bloc `try` dans une dĂ©pendance avec `yield`, vous recevrez toute exception qui a Ă©tĂ© levĂ©e lors de l'utilisation de la dĂ©pendance. + +Par exemple, si Ă  un moment donnĂ©, dans une autre dĂ©pendance ou dans un *chemin d'accĂšs*, un code a effectuĂ© un « rollback » de transaction de base de donnĂ©es ou a créé une autre exception, vous recevrez l'exception dans votre dĂ©pendance. + +Vous pouvez donc rechercher cette exception spĂ©cifique dans la dĂ©pendance avec `except SomeException`. + +De la mĂȘme maniĂšre, vous pouvez utiliser `finally` pour vous assurer que les Ă©tapes de sortie sont exĂ©cutĂ©es, qu'il y ait eu une exception ou non. + +{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *} + +## Utiliser des sous-dĂ©pendances avec `yield` { #sub-dependencies-with-yield } + +Vous pouvez avoir des sous-dĂ©pendances et des « arbres » de sous-dĂ©pendances de toute taille et forme, et certaines ou toutes peuvent utiliser `yield`. + +**FastAPI** s'assurera que le « code de sortie » dans chaque dĂ©pendance avec `yield` est exĂ©cutĂ© dans le bon ordre. + +Par exemple, `dependency_c` peut dĂ©pendre de `dependency_b`, et `dependency_b` de `dependency_a` : + +{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *} + +Et elles peuvent toutes utiliser `yield`. + +Dans ce cas, `dependency_c`, pour exĂ©cuter son code de sortie, a besoin que la valeur de `dependency_b` (appelĂ©e ici `dep_b`) soit toujours disponible. + +Et, Ă  son tour, `dependency_b` a besoin que la valeur de `dependency_a` (appelĂ©e ici `dep_a`) soit disponible pour son code de sortie. + +{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *} + +De la mĂȘme maniĂšre, vous pouvez avoir certaines dĂ©pendances avec `yield` et d'autres avec `return`, et faire en sorte que certaines dĂ©pendent des autres. + +Et vous pouvez avoir une seule dĂ©pendance qui exige plusieurs autres dĂ©pendances avec `yield`, etc. + +Vous pouvez combiner les dĂ©pendances comme vous le souhaitez. + +**FastAPI** s'assurera que tout est exĂ©cutĂ© dans le bon ordre. + +/// note | DĂ©tails techniques + +Cela fonctionne grĂące aux gestionnaires de contexte de Python. + +**FastAPI** les utilise en interne pour y parvenir. + +/// + +## Utiliser des dĂ©pendances avec `yield` et `HTTPException` { #dependencies-with-yield-and-httpexception } + +Vous avez vu que vous pouvez utiliser des dĂ©pendances avec `yield` et avoir des blocs `try` qui tentent d'exĂ©cuter du code puis exĂ©cutent du code de sortie aprĂšs `finally`. + +Vous pouvez Ă©galement utiliser `except` pour intercepter l'exception qui a Ă©tĂ© levĂ©e et faire quelque chose avec. + +Par exemple, vous pouvez lever une autre exception, comme `HTTPException`. + +/// tip | Astuce + +C'est une technique plutĂŽt avancĂ©e, et dans la plupart des cas vous n'en aurez pas vraiment besoin, car vous pouvez lever des exceptions (y compris `HTTPException`) depuis le reste de votre code applicatif, par exemple, dans la *fonction de chemin d'accĂšs*. + +Mais elle est Ă  votre disposition si vous en avez besoin. đŸ€“ + +/// + +{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *} + +Si vous souhaitez intercepter des exceptions et crĂ©er une rĂ©ponse personnalisĂ©e en fonction de cela, crĂ©ez un [Gestionnaire d'exceptions personnalisĂ©](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. + +## Utiliser des dĂ©pendances avec `yield` et `except` { #dependencies-with-yield-and-except } + +Si vous interceptez une exception avec `except` dans une dĂ©pendance avec `yield` et que vous ne la relancez pas (ou que vous ne levez pas une nouvelle exception), FastAPI ne pourra pas remarquer qu'il y a eu une exception, de la mĂȘme maniĂšre que cela se produirait avec Python classique : + +{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *} + +Dans ce cas, le client verra une rĂ©ponse *HTTP 500 Internal Server Error* comme il se doit, Ă©tant donnĂ© que nous ne levons pas de `HTTPException` ou similaire, mais le serveur **n'aura aucun logs** ni aucune autre indication de l'erreur. đŸ˜± + +### Toujours `raise` dans les dĂ©pendances avec `yield` et `except` { #always-raise-in-dependencies-with-yield-and-except } + +Si vous interceptez une exception dans une dĂ©pendance avec `yield`, Ă  moins de lever une autre `HTTPException` ou similaire, **vous devez relancer l'exception d'origine**. + +Vous pouvez relancer la mĂȘme exception avec `raise` : + +{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *} + +À prĂ©sent, le client recevra la mĂȘme rĂ©ponse *HTTP 500 Internal Server Error*, mais le serveur aura notre `InternalError` personnalisĂ© dans les logs. 😎 + +## Comprendre l'exĂ©cution des dĂ©pendances avec `yield` { #execution-of-dependencies-with-yield } + +La sĂ©quence d'exĂ©cution ressemble plus ou moins Ă  ce diagramme. Le temps s'Ă©coule de haut en bas. Et chaque colonne reprĂ©sente une des parties qui interagit ou exĂ©cute du code. + +```mermaid +sequenceDiagram + +participant client as Client +participant handler as Exception handler +participant dep as Dep with yield +participant operation as Path Operation +participant tasks as Background tasks + + Note over client,operation: Can raise exceptions, including HTTPException + client ->> dep: Start request + Note over dep: Run code up to yield + opt raise Exception + dep -->> handler: Raise Exception + handler -->> client: HTTP error response + end + dep ->> operation: Run dependency, e.g. DB session + opt raise + operation -->> dep: Raise Exception (e.g. HTTPException) + opt handle + dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception + end + handler -->> client: HTTP error response + end + + operation ->> client: Return response to client + Note over client,operation: Response is already sent, can't change it anymore + opt Tasks + operation -->> tasks: Send background tasks + end + opt Raise other exception + tasks -->> tasks: Handle exceptions in the background task code + end +``` + +/// info + +Une **seule rĂ©ponse** sera envoyĂ©e au client. Il peut s'agir d'une des rĂ©ponses d'erreur ou de la rĂ©ponse provenant du *chemin d'accĂšs*. + +AprĂšs l'envoi de l'une de ces rĂ©ponses, aucune autre rĂ©ponse ne peut ĂȘtre envoyĂ©e. + +/// + +/// tip | Astuce + +Si vous levez une exception dans le code de la *fonction de chemin d'accĂšs*, elle sera transmise aux dĂ©pendances avec `yield`, y compris `HTTPException`. Dans la plupart des cas, vous voudrez relancer cette mĂȘme exception ou en lever une nouvelle depuis la dĂ©pendance avec `yield` pour vous assurer qu'elle est correctement gĂ©rĂ©e. + +/// + +## Utiliser la sortie anticipĂ©e et `scope` { #early-exit-and-scope } + +Normalement, le code de sortie des dĂ©pendances avec `yield` est exĂ©cutĂ© **aprĂšs la rĂ©ponse** envoyĂ©e au client. + +Mais si vous savez que vous n'aurez pas besoin d'utiliser la dĂ©pendance aprĂšs ĂȘtre revenu de la *fonction de chemin d'accĂšs*, vous pouvez utiliser `Depends(scope="function")` pour indiquer Ă  FastAPI qu'il doit fermer la dĂ©pendance aprĂšs le retour de la *fonction de chemin d'accĂšs*, mais **avant** que la **rĂ©ponse ne soit envoyĂ©e**. + +{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *} + +`Depends()` reçoit un paramĂštre `scope` qui peut ĂȘtre : + +* « function » : dĂ©marrer la dĂ©pendance avant la *fonction de chemin d'accĂšs* qui gĂšre la requĂȘte, terminer la dĂ©pendance aprĂšs la fin de la *fonction de chemin d'accĂšs*, mais **avant** que la rĂ©ponse ne soit renvoyĂ©e au client. Ainsi, la fonction de dĂ©pendance sera exĂ©cutĂ©e **autour** de la *fonction de chemin d'accĂšs*. +* « request » : dĂ©marrer la dĂ©pendance avant la *fonction de chemin d'accĂšs* qui gĂšre la requĂȘte (similaire Ă  l'utilisation de « function »), mais terminer **aprĂšs** que la rĂ©ponse a Ă©tĂ© renvoyĂ©e au client. Ainsi, la fonction de dĂ©pendance sera exĂ©cutĂ©e **autour** du cycle **requĂȘte** et rĂ©ponse. + +S'il n'est pas spĂ©cifiĂ© et que la dĂ©pendance utilise `yield`, le `scope` sera par dĂ©faut « request ». + +### DĂ©finir `scope` pour les sous-dĂ©pendances { #scope-for-sub-dependencies } + +Lorsque vous dĂ©clarez une dĂ©pendance avec un `scope="request"` (par dĂ©faut), toute sous-dĂ©pendance doit Ă©galement avoir un `scope` de « request ». + +Mais une dĂ©pendance avec un `scope` de « function » peut avoir des dĂ©pendances avec un `scope` de « function » et un `scope` de « request ». + +Cela vient du fait que toute dĂ©pendance doit pouvoir exĂ©cuter son code de sortie avant ses sous-dĂ©pendances, car elle pourrait encore avoir besoin de les utiliser pendant son code de sortie. + +```mermaid +sequenceDiagram + +participant client as Client +participant dep_req as Dep scope="request" +participant dep_func as Dep scope="function" +participant operation as Path Operation + + client ->> dep_req: Start request + Note over dep_req: Run code up to yield + dep_req ->> dep_func: Pass dependency + Note over dep_func: Run code up to yield + dep_func ->> operation: Run path operation with dependency + operation ->> dep_func: Return from path operation + Note over dep_func: Run code after yield + Note over dep_func: ✅ Dependency closed + dep_func ->> client: Send response to client + Note over client: Response sent + Note over dep_req: Run code after yield + Note over dep_req: ✅ Dependency closed +``` + +## Utiliser des dĂ©pendances avec `yield`, `HTTPException`, `except` et Background Tasks { #dependencies-with-yield-httpexception-except-and-background-tasks } + +Les dĂ©pendances avec `yield` ont Ă©voluĂ© au fil du temps pour couvrir diffĂ©rents cas d'utilisation et corriger certains problĂšmes. + +Si vous souhaitez voir ce qui a changĂ© dans diffĂ©rentes versions de FastAPI, vous pouvez en savoir plus dans le guide avancĂ©, dans [DĂ©pendances avancĂ©es - DĂ©pendances avec `yield`, `HTTPException`, `except` et Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}. +## Gestionnaires de contexte { #context-managers } + +### Que sont les « Context Managers » { #what-are-context-managers } + +Les « Context Managers » sont des objets Python que vous pouvez utiliser dans une instruction `with`. + +Par exemple, vous pouvez utiliser `with` pour lire un fichier : + +```Python +with open("./somefile.txt") as f: + contents = f.read() + print(contents) +``` + +En coulisse, `open("./somefile.txt")` crĂ©e un objet appelĂ© « Context Manager ». + +Lorsque le bloc `with` se termine, il s'assure de fermer le fichier, mĂȘme s'il y a eu des exceptions. + +Lorsque vous crĂ©ez une dĂ©pendance avec `yield`, **FastAPI** crĂ©era en interne un gestionnaire de contexte pour celle-ci et le combinera avec d'autres outils associĂ©s. + +### Utiliser des gestionnaires de contexte dans des dĂ©pendances avec `yield` { #using-context-managers-in-dependencies-with-yield } + +/// warning | Alertes + +C'est, plus ou moins, une idĂ©e « avancĂ©e ». + +Si vous dĂ©butez avec **FastAPI**, vous voudrez peut-ĂȘtre l'ignorer pour le moment. + +/// + +En Python, vous pouvez crĂ©er des gestionnaires de contexte en crĂ©ant une classe avec deux mĂ©thodes : `__enter__()` et `__exit__()`. + +Vous pouvez Ă©galement les utiliser dans des dĂ©pendances **FastAPI** avec `yield` en utilisant +des instructions `with` ou `async with` Ă  l'intĂ©rieur de la fonction de dĂ©pendance : + +{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *} + +/// tip | Astuce + +Une autre façon de crĂ©er un gestionnaire de contexte consiste Ă  utiliser : + +* `@contextlib.contextmanager` ou +* `@contextlib.asynccontextmanager` + +pour dĂ©corer une fonction avec un unique `yield`. + +C'est ce que **FastAPI** utilise en interne pour les dĂ©pendances avec `yield`. + +Mais vous n'avez pas Ă  utiliser ces dĂ©corateurs pour les dĂ©pendances FastAPI (et vous ne devriez pas). + +FastAPI le fera pour vous en interne. + +/// diff --git a/docs/fr/docs/tutorial/dependencies/global-dependencies.md b/docs/fr/docs/tutorial/dependencies/global-dependencies.md new file mode 100644 index 000000000..2c418ee4a --- /dev/null +++ b/docs/fr/docs/tutorial/dependencies/global-dependencies.md @@ -0,0 +1,15 @@ +# DĂ©pendances globales { #global-dependencies } + +Pour certains types d'applications, vous pourriez vouloir ajouter des dĂ©pendances Ă  l'application entiĂšre. + +Comme vous pouvez [ajouter des `dependencies` aux *dĂ©corateurs de chemin d'accĂšs*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, vous pouvez les ajouter Ă  l'application `FastAPI`. + +Dans ce cas, elles seront appliquĂ©es Ă  tous les *chemins d'accĂšs* de l'application : + +{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *} + +Et toutes les idĂ©es de la section sur [l'ajout de `dependencies` aux *dĂ©corateurs de chemin d'accĂšs*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} s'appliquent toujours, mais dans ce cas Ă  tous les *chemins d'accĂšs* de l'application. + +## DĂ©pendances pour des groupes de *chemins d'accĂšs* { #dependencies-for-groups-of-path-operations } + +Plus tard, en lisant comment structurer des applications plus grandes ([Applications plus grandes - Plusieurs fichiers](../../tutorial/bigger-applications.md){.internal-link target=_blank}), Ă©ventuellement avec plusieurs fichiers, vous apprendrez comment dĂ©clarer un unique paramĂštre `dependencies` pour un groupe de *chemins d'accĂšs*. diff --git a/docs/fr/docs/tutorial/dependencies/index.md b/docs/fr/docs/tutorial/dependencies/index.md new file mode 100644 index 000000000..8fad77f62 --- /dev/null +++ b/docs/fr/docs/tutorial/dependencies/index.md @@ -0,0 +1,250 @@ +# DĂ©pendances { #dependencies } + +**FastAPI** dispose d’un systĂšme d’**Injection de dĂ©pendances** trĂšs puissant mais intuitif. + +Il est conçu pour ĂȘtre trĂšs simple Ă  utiliser, et pour faciliter l’intĂ©gration d’autres composants Ă  **FastAPI** pour n’importe quel dĂ©veloppeur. + +## Qu’est-ce que « l’injection de dĂ©pendances » { #what-is-dependency-injection } + +L’**« injection de dĂ©pendances »** signifie, en programmation, qu’il existe un moyen pour votre code (dans ce cas, vos fonctions de chemins d’accĂšs) de dĂ©clarer ce dont il a besoin pour fonctionner et utiliser : « dĂ©pendances ». + +Ensuite, ce systĂšme (dans ce cas **FastAPI**) se charge de faire tout le nĂ©cessaire pour fournir Ă  votre code ces dĂ©pendances requises (« injecter » les dĂ©pendances). + +C’est trĂšs utile lorsque vous avez besoin de : + +* Avoir de la logique partagĂ©e (la mĂȘme logique de code encore et encore). +* Partager des connexions Ă  la base de donnĂ©es. +* Imposer la sĂ©curitĂ©, l’authentification, des exigences de rĂŽles, etc. +* Et bien d’autres choses ... + +Tout cela, en minimisant la rĂ©pĂ©tition de code. + +## Premiers pas { #first-steps } + +Voyons un exemple trĂšs simple. Il sera tellement simple qu’il n’est pas trĂšs utile, pour l’instant. + +Mais de cette façon nous pouvons nous concentrer sur le fonctionnement du systĂšme d’**injection de dĂ©pendances**. + +### CrĂ©er une dĂ©pendance, ou « dependable » { #create-a-dependency-or-dependable } + +Concentrons-nous d’abord sur la dĂ©pendance. + +C’est simplement une fonction qui peut prendre tous les mĂȘmes paramĂštres qu’une fonction de chemin d’accĂšs peut prendre : + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *} + +C’est tout. + +**2 lignes**. + +Et elle a la mĂȘme forme et structure que toutes vos fonctions de chemins d’accĂšs. + +Vous pouvez la considĂ©rer comme une fonction de chemin d’accĂšs sans le « dĂ©corateur » (sans le `@app.get("/some-path")`). + +Et elle peut retourner tout ce que vous voulez. + +Dans ce cas, cette dĂ©pendance attend : + +* Un paramĂštre de requĂȘte optionnel `q` qui est une `str`. +* Un paramĂštre de requĂȘte optionnel `skip` qui est un `int`, et vaut `0` par dĂ©faut. +* Un paramĂštre de requĂȘte optionnel `limit` qui est un `int`, et vaut `100` par dĂ©faut. + +Puis elle retourne simplement un `dict` contenant ces valeurs. + +/// info | Info + +FastAPI a ajoutĂ© la prise en charge de `Annotated` (et a commencĂ© Ă  le recommander) dans la version 0.95.0. + +Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d’utiliser `Annotated`. + +Vous devez vous assurer de [mettre Ă  niveau la version de FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} vers au moins la 0.95.1 avant d’utiliser `Annotated`. + +/// + +### Importer `Depends` { #import-depends } + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *} + +### DĂ©clarer la dĂ©pendance, dans le « dependant » { #declare-the-dependency-in-the-dependant } + +De la mĂȘme maniĂšre que vous utilisez `Body`, `Query`, etc. avec les paramĂštres de votre fonction de chemin d’accĂšs, utilisez `Depends` avec un nouveau paramĂštre : + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *} + +MĂȘme si vous utilisez `Depends` dans les paramĂštres de votre fonction de la mĂȘme façon que `Body`, `Query`, etc., `Depends` fonctionne un peu diffĂ©remment. + +Vous ne donnez Ă  `Depends` qu’un seul paramĂštre. + +Ce paramĂštre doit ĂȘtre quelque chose comme une fonction. + +Vous ne l’appelez pas directement (n’ajoutez pas de parenthĂšses Ă  la fin), vous le passez simplement en paramĂštre Ă  `Depends()`. + +Et cette fonction prend des paramĂštres de la mĂȘme maniĂšre que les fonctions de chemins d’accĂšs. + +/// tip | Astuce + +Vous verrez quelles autres « choses », en plus des fonctions, peuvent ĂȘtre utilisĂ©es comme dĂ©pendances dans le prochain chapitre. + +/// + +Chaque fois qu’une nouvelle requĂȘte arrive, **FastAPI** se charge de : + +* Appeler votre fonction de dĂ©pendance (« dependable ») avec les bons paramĂštres. +* RĂ©cupĂ©rer le rĂ©sultat de votre fonction. +* Affecter ce rĂ©sultat au paramĂštre dans votre fonction de chemin d’accĂšs. + +```mermaid +graph TB + +common_parameters(["common_parameters"]) +read_items["/items/"] +read_users["/users/"] + +common_parameters --> read_items +common_parameters --> read_users +``` + +De cette façon vous Ă©crivez le code partagĂ© une seule fois et **FastAPI** se charge de l’appeler pour vos chemins d’accĂšs. + +/// check | VĂ©rifications + +Notez que vous n’avez pas Ă  crĂ©er une classe spĂ©ciale et Ă  la passer quelque part Ă  **FastAPI** pour l’« enregistrer » ou quoi que ce soit de similaire. + +Vous la passez simplement Ă  `Depends` et **FastAPI** sait faire le reste. + +/// + +## Partager des dĂ©pendances `Annotated` { #share-annotated-dependencies } + +Dans les exemples ci-dessus, vous voyez qu’il y a un tout petit peu de **duplication de code**. + +Lorsque vous devez utiliser la dĂ©pendance `common_parameters()`, vous devez Ă©crire tout le paramĂštre avec l’annotation de type et `Depends()` : + +```Python +commons: Annotated[dict, Depends(common_parameters)] +``` + +Mais comme nous utilisons `Annotated`, nous pouvons stocker cette valeur `Annotated` dans une variable et l’utiliser Ă  plusieurs endroits : + +{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *} + +/// tip | Astuce + +C’est simplement du Python standard, cela s’appelle un « alias de type », ce n’est en fait pas spĂ©cifique Ă  **FastAPI**. + +Mais comme **FastAPI** est basĂ© sur les standards Python, y compris `Annotated`, vous pouvez utiliser cette astuce dans votre code. 😎 + +/// + +Les dĂ©pendances continueront de fonctionner comme prĂ©vu, et la **meilleure partie** est que **l’information de type sera conservĂ©e**, ce qui signifie que votre Ă©diteur pourra continuer Ă  vous fournir **l’autocomplĂ©tion**, **des erreurs en ligne**, etc. Idem pour d’autres outils comme `mypy`. + +Cela sera particuliĂšrement utile lorsque vous l’utiliserez dans une **grande base de code** oĂč vous utilisez **les mĂȘmes dĂ©pendances** encore et encore dans **de nombreux chemins d’accĂšs**. + +## Utiliser `async` ou non { #to-async-or-not-to-async } + +Comme les dĂ©pendances seront aussi appelĂ©es par **FastAPI** (tout comme vos fonctions de chemins d’accĂšs), les mĂȘmes rĂšgles s’appliquent lors de la dĂ©finition de vos fonctions. + +Vous pouvez utiliser `async def` ou un `def` normal. + +Et vous pouvez dĂ©clarer des dĂ©pendances avec `async def` Ă  l’intĂ©rieur de fonctions de chemins d’accĂšs `def` normales, ou des dĂ©pendances `def` Ă  l’intĂ©rieur de fonctions de chemins d’accĂšs `async def`, etc. + +Peu importe. **FastAPI** saura quoi faire. + +/// note | Remarque + +Si vous ne savez pas, consultez la section [Async : *« PressĂ© ? »*](../../async.md#in-a-hurry){.internal-link target=_blank} Ă  propos de `async` et `await` dans la documentation. + +/// + +## IntĂ©grer Ă  OpenAPI { #integrated-with-openapi } + +Toutes les dĂ©clarations de requĂȘte, validations et exigences de vos dĂ©pendances (et sous-dĂ©pendances) seront intĂ©grĂ©es dans le mĂȘme schĂ©ma OpenAPI. + +Ainsi, la documentation interactive contiendra aussi toutes les informations issues de ces dĂ©pendances : + + + +## Utilisation simple { #simple-usage } + +Si vous y regardez de prĂšs, les fonctions de chemins d’accĂšs sont dĂ©clarĂ©es pour ĂȘtre utilisĂ©es chaque fois qu’un « chemin » et une « opĂ©ration » correspondent, puis **FastAPI** se charge d’appeler la fonction avec les bons paramĂštres, en extrayant les donnĂ©es de la requĂȘte. + +En rĂ©alitĂ©, tous (ou la plupart) des frameworks web fonctionnent de cette maniĂšre. + +Vous n’appelez jamais ces fonctions directement. Elles sont appelĂ©es par votre framework (dans ce cas, **FastAPI**). + +Avec le systĂšme d’injection de dĂ©pendances, vous pouvez aussi indiquer Ă  **FastAPI** que votre fonction de chemin d’accĂšs « dĂ©pend » Ă©galement d’autre chose qui doit ĂȘtre exĂ©cutĂ© avant votre fonction de chemin d’accĂšs, et **FastAPI** se chargera de l’exĂ©cuter et d’« injecter » les rĂ©sultats. + +D’autres termes courants pour cette mĂȘme idĂ©e « d’injection de dĂ©pendances » sont : + +* ressources +* fournisseurs +* services +* injectables +* composants + +## Plug-ins **FastAPI** { #fastapi-plug-ins } + +Les intĂ©grations et « plug-ins » peuvent ĂȘtre construits en utilisant le systĂšme d’**injection de dĂ©pendances**. Mais en rĂ©alitĂ©, il n’y a **pas besoin de crĂ©er des « plug-ins »**, car en utilisant des dĂ©pendances il est possible de dĂ©clarer un nombre infini d’intĂ©grations et d’interactions qui deviennent disponibles pour vos fonctions de chemins d’accĂšs. + +Et les dĂ©pendances peuvent ĂȘtre créées de maniĂšre trĂšs simple et intuitive, ce qui vous permet d’importer juste les packages Python dont vous avez besoin, et de les intĂ©grer Ă  vos fonctions d’API en quelques lignes de code, *littĂ©ralement*. + +Vous verrez des exemples de cela dans les prochains chapitres, Ă  propos des bases de donnĂ©es relationnelles et NoSQL, de la sĂ©curitĂ©, etc. + +## CompatibilitĂ© **FastAPI** { #fastapi-compatibility } + +La simplicitĂ© du systĂšme d’injection de dĂ©pendances rend **FastAPI** compatible avec : + +* toutes les bases de donnĂ©es relationnelles +* les bases de donnĂ©es NoSQL +* les packages externes +* les API externes +* les systĂšmes d’authentification et d’autorisation +* les systĂšmes de supervision d’usage d’API +* les systĂšmes d’injection de donnĂ©es de rĂ©ponse +* etc. + +## Simple et puissant { #simple-and-powerful } + +Bien que le systĂšme hiĂ©rarchique d’injection de dĂ©pendances soit trĂšs simple Ă  dĂ©finir et Ă  utiliser, il reste trĂšs puissant. + +Vous pouvez dĂ©finir des dĂ©pendances qui, Ă  leur tour, peuvent dĂ©finir leurs propres dĂ©pendances. + +Au final, un arbre hiĂ©rarchique de dĂ©pendances est construit, et le systĂšme d’**injection de dĂ©pendances** se charge de rĂ©soudre toutes ces dĂ©pendances pour vous (et leurs sous-dĂ©pendances) et de fournir (injecter) les rĂ©sultats Ă  chaque Ă©tape. + +Par exemple, supposons que vous ayez 4 endpoints d’API (chemins d’accĂšs) : + +* `/items/public/` +* `/items/private/` +* `/users/{user_id}/activate` +* `/items/pro/` + +alors vous pourriez ajouter diffĂ©rentes exigences d’autorisations pour chacun d’eux uniquement avec des dĂ©pendances et des sous-dĂ©pendances : + +```mermaid +graph TB + +current_user(["current_user"]) +active_user(["active_user"]) +admin_user(["admin_user"]) +paying_user(["paying_user"]) + +public["/items/public/"] +private["/items/private/"] +activate_user["/users/{user_id}/activate"] +pro_items["/items/pro/"] + +current_user --> active_user +active_user --> admin_user +active_user --> paying_user + +current_user --> public +active_user --> private +admin_user --> activate_user +paying_user --> pro_items +``` + +## IntĂ©grer Ă  **OpenAPI** { #integrated-with-openapi_1 } + +Toutes ces dĂ©pendances, tout en dĂ©clarant leurs exigences, ajoutent Ă©galement des paramĂštres, des validations, etc. Ă  vos chemins d’accĂšs. + +**FastAPI** se chargera d’ajouter le tout au schĂ©ma OpenAPI, afin que cela apparaisse dans les systĂšmes de documentation interactive. diff --git a/docs/fr/docs/tutorial/dependencies/sub-dependencies.md b/docs/fr/docs/tutorial/dependencies/sub-dependencies.md new file mode 100644 index 000000000..473ff02ba --- /dev/null +++ b/docs/fr/docs/tutorial/dependencies/sub-dependencies.md @@ -0,0 +1,105 @@ +# Sous-dĂ©pendances { #sub-dependencies } + +Vous pouvez crĂ©er des dĂ©pendances qui ont des sous-dĂ©pendances. + +Elles peuvent ĂȘtre aussi profondes que nĂ©cessaire. + +**FastAPI** se chargera de les rĂ©soudre. + +## CrĂ©er une premiĂšre dĂ©pendance « dependable » { #first-dependency-dependable } + +Vous pouvez crĂ©er une premiĂšre dĂ©pendance (« dependable ») comme : + +{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *} + +Elle dĂ©clare un paramĂštre de requĂȘte optionnel `q` de type `str`, puis le retourne simplement. + +C'est assez simple (pas trĂšs utile), mais cela nous aidera Ă  nous concentrer sur le fonctionnement des sous-dĂ©pendances. + +## CrĂ©er une seconde dĂ©pendance, « dependable » et « dependant » { #second-dependency-dependable-and-dependant } + +Vous pouvez ensuite crĂ©er une autre fonction de dĂ©pendance (un « dependable ») qui, en mĂȘme temps, dĂ©clare sa propre dĂ©pendance (elle est donc aussi un « dependant ») : + +{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *} + +Concentrons-nous sur les paramĂštres dĂ©clarĂ©s : + +- MĂȘme si cette fonction est elle‑mĂȘme une dĂ©pendance (« dependable »), elle dĂ©clare aussi une autre dĂ©pendance (elle « dĂ©pend » d'autre chose). + - Elle dĂ©pend de `query_extractor` et affecte la valeur renvoyĂ©e au paramĂštre `q`. +- Elle dĂ©clare Ă©galement un cookie `last_query` optionnel, de type `str`. + - Si l'utilisateur n'a fourni aucune requĂȘte `q`, nous utilisons la derniĂšre requĂȘte utilisĂ©e, que nous avons enregistrĂ©e auparavant dans un cookie. + +## Utiliser la dĂ©pendance { #use-the-dependency } + +Nous pouvons ensuite utiliser la dĂ©pendance avec : + +{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *} + +/// info + +Notez que nous ne dĂ©clarons qu'une seule dĂ©pendance dans la *fonction de chemin d'accĂšs*, `query_or_cookie_extractor`. + +Mais **FastAPI** saura qu'il doit d'abord rĂ©soudre `query_extractor`, pour passer ses rĂ©sultats Ă  `query_or_cookie_extractor` lors de son appel. + +/// + +```mermaid +graph TB + +query_extractor(["query_extractor"]) +query_or_cookie_extractor(["query_or_cookie_extractor"]) + +read_query["/items/"] + +query_extractor --> query_or_cookie_extractor --> read_query +``` + +## Utiliser la mĂȘme dĂ©pendance plusieurs fois { #using-the-same-dependency-multiple-times } + +Si l'une de vos dĂ©pendances est dĂ©clarĂ©e plusieurs fois pour le mĂȘme *chemin d'accĂšs*, par exemple si plusieurs dĂ©pendances ont une sous-dĂ©pendance commune, **FastAPI** saura n'appeler cette sous-dĂ©pendance qu'une seule fois par requĂȘte. + +Et il enregistrera la valeur renvoyĂ©e dans un « cache » et la transmettra Ă  tous les « dependants » qui en ont besoin dans cette requĂȘte spĂ©cifique, au lieu d'appeler la dĂ©pendance plusieurs fois pour la mĂȘme requĂȘte. + +Dans un scĂ©nario avancĂ© oĂč vous savez que vous avez besoin que la dĂ©pendance soit appelĂ©e Ă  chaque Ă©tape (Ă©ventuellement plusieurs fois) dans la mĂȘme requĂȘte au lieu d'utiliser la valeur « mise en cache », vous pouvez dĂ©finir le paramĂštre `use_cache=False` lors de l'utilisation de `Depends` : + +//// tab | Python 3.10+ + +```Python hl_lines="1" +async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]): + return {"fresh_value": fresh_value} +``` + +//// + +//// tab | Python 3.10+ non annotĂ© + +/// tip | Astuce + +PrivilĂ©giez la version `Annotated` si possible. + +/// + +```Python hl_lines="1" +async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)): + return {"fresh_value": fresh_value} +``` + +//// + +## RĂ©capituler { #recap } + +En dehors de tout le jargon utilisĂ© ici, le systĂšme d'**injection de dĂ©pendances** est assez simple. + +Ce ne sont que des fonctions qui ressemblent aux *fonctions de chemin d'accĂšs*. + +Mais il est trĂšs puissant et vous permet de dĂ©clarer des « graphes » (arbres) de dĂ©pendances imbriquĂ©es aussi profondĂ©ment que vous le souhaitez. + +/// tip | Astuce + +Tout cela peut ne pas sembler trĂšs utile avec ces exemples simples. + +Mais vous verrez Ă  quel point c'est utile dans les chapitres sur la **sĂ©curitĂ©**. + +Et vous verrez aussi la quantitĂ© de code que cela vous fera Ă©conomiser. + +/// diff --git a/docs/fr/docs/tutorial/encoder.md b/docs/fr/docs/tutorial/encoder.md new file mode 100644 index 000000000..f94be429c --- /dev/null +++ b/docs/fr/docs/tutorial/encoder.md @@ -0,0 +1,35 @@ +# Encodeur compatible JSON { #json-compatible-encoder } + +Il existe des cas oĂč vous pourriez avoir besoin de convertir un type de donnĂ©es (comme un modĂšle Pydantic) en quelque chose de compatible avec JSON (comme un `dict`, `list`, etc.). + +Par exemple, si vous devez le stocker dans une base de donnĂ©es. + +Pour cela, **FastAPI** fournit une fonction `jsonable_encoder()`. + +## Utiliser `jsonable_encoder` { #using-the-jsonable-encoder } + +Imaginons que vous ayez une base de donnĂ©es `fake_db` qui ne reçoit que des donnĂ©es compatibles JSON. + +Par exemple, elle ne reçoit pas d'objets `datetime`, car ceux-ci ne sont pas compatibles avec JSON. + +Ainsi, un objet `datetime` doit ĂȘtre converti en une `str` contenant les donnĂ©es au format ISO. + +De la mĂȘme maniĂšre, cette base de donnĂ©es n'accepterait pas un modĂšle Pydantic (un objet avec des attributs), seulement un `dict`. + +Vous pouvez utiliser `jsonable_encoder` pour cela. + +Elle reçoit un objet, comme un modĂšle Pydantic, et renvoie une version compatible JSON : + +{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *} + +Dans cet exemple, elle convertirait le modĂšle Pydantic en `dict`, et le `datetime` en `str`. + +Le rĂ©sultat de son appel est quelque chose qui peut ĂȘtre encodĂ© avec la fonction standard de Python `json.dumps()`. + +Elle ne renvoie pas une grande `str` contenant les donnĂ©es au format JSON (sous forme de chaĂźne). Elle renvoie une structure de donnĂ©es standard de Python (par ex. un `dict`) avec des valeurs et sous-valeurs toutes compatibles avec JSON. + +/// note | Remarque + +`jsonable_encoder` est en fait utilisĂ©e par **FastAPI** en interne pour convertir des donnĂ©es. Mais elle est utile dans de nombreux autres scĂ©narios. + +/// diff --git a/docs/fr/docs/tutorial/extra-data-types.md b/docs/fr/docs/tutorial/extra-data-types.md new file mode 100644 index 000000000..edaa7bd4c --- /dev/null +++ b/docs/fr/docs/tutorial/extra-data-types.md @@ -0,0 +1,62 @@ +# Types de donnĂ©es supplĂ©mentaires { #extra-data-types } + +Jusqu'Ă  prĂ©sent, vous avez utilisĂ© des types de donnĂ©es courants, comme : + +* `int` +* `float` +* `str` +* `bool` + +Mais vous pouvez aussi utiliser des types de donnĂ©es plus complexes. + +Et vous bĂ©nĂ©ficierez toujours des mĂȘmes fonctionnalitĂ©s que jusqu'Ă  prĂ©sent : + +* Excellente prise en charge dans l'Ă©diteur. +* Conversion des donnĂ©es Ă  partir des requĂȘtes entrantes. +* Conversion des donnĂ©es pour les donnĂ©es de rĂ©ponse. +* Validation des donnĂ©es. +* Annotations et documentation automatiques. + +## Autres types de donnĂ©es { #other-data-types } + +Voici quelques types de donnĂ©es supplĂ©mentaires que vous pouvez utiliser : + +* `UUID` : + * Un « identifiant universel unique » standard, couramment utilisĂ© comme ID dans de nombreuses bases de donnĂ©es et systĂšmes. + * Dans les requĂȘtes et les rĂ©ponses, il sera reprĂ©sentĂ© sous forme de `str`. +* `datetime.datetime` : + * Un `datetime.datetime` Python. + * Dans les requĂȘtes et les rĂ©ponses, il sera reprĂ©sentĂ© sous forme de `str` au format ISO 8601, par exemple : `2008-09-15T15:53:00+05:00`. +* `datetime.date` : + * `datetime.date` Python. + * Dans les requĂȘtes et les rĂ©ponses, il sera reprĂ©sentĂ© sous forme de `str` au format ISO 8601, par exemple : `2008-09-15`. +* `datetime.time` : + * Un `datetime.time` Python. + * Dans les requĂȘtes et les rĂ©ponses, il sera reprĂ©sentĂ© sous forme de `str` au format ISO 8601, par exemple : `14:23:55.003`. +* `datetime.timedelta` : + * Un `datetime.timedelta` Python. + * Dans les requĂȘtes et les rĂ©ponses, il sera reprĂ©sentĂ© sous forme de `float` de secondes totales. + * Pydantic permet aussi de le reprĂ©senter sous la forme d'un « encodage de diffĂ©rence de temps ISO 8601 », voir la documentation pour plus d'informations. +* `frozenset` : + * Dans les requĂȘtes et les rĂ©ponses, traitĂ© de la mĂȘme maniĂšre qu'un `set` : + * Dans les requĂȘtes, une liste sera lue, les doublons Ă©liminĂ©s, puis convertie en `set`. + * Dans les rĂ©ponses, le `set` sera converti en `list`. + * Le schĂ©ma gĂ©nĂ©rĂ© indiquera que les valeurs du `set` sont uniques (en utilisant `uniqueItems` de JSON Schema). +* `bytes` : + * `bytes` Python standard. + * Dans les requĂȘtes et les rĂ©ponses, traitĂ© comme une `str`. + * Le schĂ©ma gĂ©nĂ©rĂ© indiquera qu'il s'agit d'une `str` avec le « format » `binary`. +* `Decimal` : + * `Decimal` Python standard. + * Dans les requĂȘtes et les rĂ©ponses, gĂ©rĂ© de la mĂȘme maniĂšre qu'un `float`. +* Vous pouvez consulter tous les types de donnĂ©es Pydantic valides ici : Types de donnĂ©es Pydantic. + +## Exemple { #example } + +Voici un exemple de *chemin d'accĂšs* avec des paramĂštres utilisant certains des types ci-dessus. + +{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *} + +Notez que les paramĂštres Ă  l'intĂ©rieur de la fonction ont leur type de donnĂ©es naturel et que vous pouvez, par exemple, effectuer des manipulations de dates normales, comme : + +{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *} diff --git a/docs/fr/docs/tutorial/extra-models.md b/docs/fr/docs/tutorial/extra-models.md new file mode 100644 index 000000000..1f9eb1561 --- /dev/null +++ b/docs/fr/docs/tutorial/extra-models.md @@ -0,0 +1,211 @@ +# ModĂšles supplĂ©mentaires { #extra-models } + +En poursuivant l'exemple prĂ©cĂ©dent, il est courant d'avoir plusieurs modĂšles liĂ©s. + +C'est particuliĂšrement vrai pour les modĂšles d'utilisateur, car : + +* Le modĂšle d'entrĂ©e doit pouvoir contenir un mot de passe. +* Le modĂšle de sortie ne doit pas avoir de mot de passe. +* Le modĂšle de base de donnĂ©es devra probablement avoir un mot de passe hachĂ©. + +/// danger | Danger + +Ne stockez jamais les mots de passe des utilisateurs en clair. Stockez toujours un « hachage sĂ©curisĂ© » que vous pourrez ensuite vĂ©rifier. + +Si vous ne savez pas ce que c'est, vous apprendrez ce qu'est un « hachage de mot de passe » dans les [chapitres sur la sĂ©curitĂ©](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}. + +/// + +## Utiliser plusieurs modĂšles { #multiple-models } + +Voici une idĂ©e gĂ©nĂ©rale de l'apparence des modĂšles avec leurs champs de mot de passe et les endroits oĂč ils sont utilisĂ©s : + +{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} + +### À propos de `**user_in.model_dump()` { #about-user-in-model-dump } + +#### La mĂ©thode `.model_dump()` de Pydantic { #pydantics-model-dump } + +`user_in` est un modĂšle Pydantic de classe `UserIn`. + +Les modĂšles Pydantic ont une mĂ©thode `.model_dump()` qui renvoie un `dict` avec les donnĂ©es du modĂšle. + +Ainsi, si nous crĂ©ons un objet Pydantic `user_in` comme : + +```Python +user_in = UserIn(username="john", password="secret", email="john.doe@example.com") +``` + +et que nous appelons ensuite : + +```Python +user_dict = user_in.model_dump() +``` + +nous avons maintenant un `dict` avec les donnĂ©es dans la variable `user_dict` (c'est un `dict` au lieu d'un objet modĂšle Pydantic). + +Et si nous appelons : + +```Python +print(user_dict) +``` + +nous obtiendrions un `dict` Python contenant : + +```Python +{ + 'username': 'john', + 'password': 'secret', + 'email': 'john.doe@example.com', + 'full_name': None, +} +``` + +#### DĂ©baller un `dict` { #unpacking-a-dict } + +Si nous prenons un `dict` comme `user_dict` et que nous le passons Ă  une fonction (ou une classe) avec `**user_dict`, Python va « dĂ©baller » ce `dict`. Il passera les clĂ©s et valeurs de `user_dict` directement comme arguments nommĂ©s. + +Ainsi, en reprenant `user_dict` ci-dessus, Ă©crire : + +```Python +UserInDB(**user_dict) +``` + +aurait pour rĂ©sultat quelque chose d'Ă©quivalent à : + +```Python +UserInDB( + username="john", + password="secret", + email="john.doe@example.com", + full_name=None, +) +``` + +Ou plus exactement, en utilisant `user_dict` directement, quels que soient ses contenus futurs : + +```Python +UserInDB( + username = user_dict["username"], + password = user_dict["password"], + email = user_dict["email"], + full_name = user_dict["full_name"], +) +``` + +#### CrĂ©er un modĂšle Pydantic Ă  partir du contenu d'un autre { #a-pydantic-model-from-the-contents-of-another } + +Comme dans l'exemple ci-dessus nous avons obtenu `user_dict` depuis `user_in.model_dump()`, ce code : + +```Python +user_dict = user_in.model_dump() +UserInDB(**user_dict) +``` + +serait Ă©quivalent à : + +```Python +UserInDB(**user_in.model_dump()) +``` + +... parce que `user_in.model_dump()` est un `dict`, et nous demandons ensuite Ă  Python de « dĂ©baller » ce `dict` en le passant Ă  `UserInDB` prĂ©cĂ©dĂ© de `**`. + +Ainsi, nous obtenons un modĂšle Pydantic Ă  partir des donnĂ©es d'un autre modĂšle Pydantic. + +#### DĂ©baller un `dict` et ajouter des mots-clĂ©s supplĂ©mentaires { #unpacking-a-dict-and-extra-keywords } + +Et en ajoutant ensuite l'argument nommĂ© supplĂ©mentaire `hashed_password=hashed_password`, comme ici : + +```Python +UserInDB(**user_in.model_dump(), hashed_password=hashed_password) +``` + +... revient à : + +```Python +UserInDB( + username = user_dict["username"], + password = user_dict["password"], + email = user_dict["email"], + full_name = user_dict["full_name"], + hashed_password = hashed_password, +) +``` + +/// warning | Alertes + +Les fonctions auxiliaires `fake_password_hasher` et `fake_save_user` ne servent qu'Ă  dĂ©montrer un flux de donnĂ©es possible, mais elles n'offrent Ă©videmment aucune sĂ©curitĂ© rĂ©elle. + +/// + +## RĂ©duire la duplication { #reduce-duplication } + +RĂ©duire la duplication de code est l'une des idĂ©es centrales de **FastAPI**. + +La duplication de code augmente les risques de bogues, de problĂšmes de sĂ©curitĂ©, de dĂ©synchronisation du code (lorsque vous mettez Ă  jour un endroit mais pas les autres), etc. + +Et ces modĂšles partagent beaucoup de donnĂ©es et dupliquent des noms et types d'attributs. + +Nous pouvons faire mieux. + +Nous pouvons dĂ©clarer un modĂšle `UserBase` qui sert de base Ă  nos autres modĂšles. Ensuite, nous pouvons crĂ©er des sous-classes de ce modĂšle qui hĂ©ritent de ses attributs (dĂ©clarations de type, validation, etc.). + +Toutes les conversions de donnĂ©es, validations, documentation, etc., fonctionneront comme d'habitude. + +De cette façon, nous pouvons ne dĂ©clarer que les diffĂ©rences entre les modĂšles (avec `password` en clair, avec `hashed_password` et sans mot de passe) : + +{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *} + +## `Union` ou `anyOf` { #union-or-anyof } + +Vous pouvez dĂ©clarer qu'une rĂ©ponse est l'`Union` de deux types ou plus, ce qui signifie que la rĂ©ponse peut ĂȘtre n'importe lequel d'entre eux. + +Cela sera dĂ©fini dans OpenAPI avec `anyOf`. + +Pour ce faire, utilisez l'annotation de type Python standard `typing.Union` : + +/// note | Remarque + +Lors de la dĂ©finition d'une `Union`, incluez d'abord le type le plus spĂ©cifique, suivi du type le moins spĂ©cifique. Dans l'exemple ci-dessous, le type le plus spĂ©cifique `PlaneItem` prĂ©cĂšde `CarItem` dans `Union[PlaneItem, CarItem]`. + +/// + +{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *} + +### `Union` en Python 3.10 { #union-in-python-3-10 } + +Dans cet exemple, nous passons `Union[PlaneItem, CarItem]` comme valeur de l'argument `response_model`. + +Comme nous le passons comme valeur d'un argument au lieu de l'utiliser dans une annotation de type, nous devons utiliser `Union` mĂȘme en Python 3.10. + +S'il s'agissait d'une annotation de type, nous pourrions utiliser la barre verticale, comme : + +```Python +some_variable: PlaneItem | CarItem +``` + +Mais si nous Ă©crivons cela dans l'affectation `response_model=PlaneItem | CarItem`, nous obtiendrons une erreur, car Python essaierait d'effectuer une « opĂ©ration invalide » entre `PlaneItem` et `CarItem` au lieu de l'interprĂ©ter comme une annotation de type. + +## Liste de modĂšles { #list-of-models } + +De la mĂȘme maniĂšre, vous pouvez dĂ©clarer des rĂ©ponses contenant des listes d'objets. + +Pour cela, utilisez le `list` Python standard : + +{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *} + +## RĂ©ponse avec un `dict` arbitraire { #response-with-arbitrary-dict } + +Vous pouvez Ă©galement dĂ©clarer une rĂ©ponse en utilisant un simple `dict` arbitraire, en dĂ©clarant uniquement le type des clĂ©s et des valeurs, sans utiliser de modĂšle Pydantic. + +C'est utile si vous ne connaissez pas Ă  l'avance les noms de champs/attributs valides (qui seraient nĂ©cessaires pour un modĂšle Pydantic). + +Dans ce cas, vous pouvez utiliser `dict` : + +{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *} + +## RĂ©capitulatif { #recap } + +Utilisez plusieurs modĂšles Pydantic et hĂ©ritez librement selon chaque cas. + +Vous n'avez pas besoin d'avoir un seul modĂšle de donnĂ©es par entitĂ© si cette entitĂ© doit pouvoir avoir diffĂ©rents « Ă©tats ». Comme pour l'« entitĂ© » utilisateur, avec un Ă©tat incluant `password`, `password_hash` et sans mot de passe. diff --git a/docs/fr/docs/tutorial/first-steps.md b/docs/fr/docs/tutorial/first-steps.md index b2693b3e5..ae2358468 100644 --- a/docs/fr/docs/tutorial/first-steps.md +++ b/docs/fr/docs/tutorial/first-steps.md @@ -1,8 +1,8 @@ -# DĂ©marrage { #first-steps } +# DĂ©marrer { #first-steps } Le fichier **FastAPI** le plus simple possible pourrait ressembler Ă  ceci : -{* ../../docs_src/first_steps/tutorial001_py39.py *} +{* ../../docs_src/first_steps/tutorial001_py310.py *} Copiez cela dans un fichier `main.py`. @@ -56,7 +56,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) Cette ligne montre l’URL oĂč votre application est servie, sur votre machine locale. -### VĂ©rifiez { #check-it } +### VĂ©rifier { #check-it } Ouvrez votre navigateur Ă  l’adresse http://127.0.0.1:8000. @@ -183,7 +183,7 @@ C’est tout ! Vous pouvez maintenant accĂ©der Ă  votre application Ă  cette URL ### Étape 1 : importer `FastAPI` { #step-1-import-fastapi } -{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *} +{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *} `FastAPI` est une classe Python qui fournit toutes les fonctionnalitĂ©s nĂ©cessaires Ă  votre API. @@ -197,7 +197,7 @@ Vous pouvez donc aussi utiliser toutes les fonctionnalitĂ©s de get opĂ©ration +* en utilisant une get opĂ©ration -/// info | `@dĂ©corateur` Info +/// info | `@decorator` Info Cette syntaxe `@something` en Python est appelĂ©e un « dĂ©corateur ». @@ -320,7 +320,7 @@ Voici notre « fonction de chemin d’accĂšs » : * **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_py310.py hl[7] *} C’est une fonction Python. @@ -332,9 +332,9 @@ Dans ce cas, c’est une fonction `async`. Vous pouvez aussi la dĂ©finir comme une fonction normale au lieu de `async def` : -{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *} +{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *} -/// note +/// note | Remarque Si vous ne connaissez pas la diffĂ©rence, consultez [Asynchrone : « PressĂ© ? »](../async.md#in-a-hurry){.internal-link target=_blank}. @@ -342,7 +342,7 @@ Si vous ne connaissez pas la diffĂ©rence, consultez [Asynchrone : « PressĂ© ? ### Étape 5 : retourner le contenu { #step-5-return-the-content } -{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *} +{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *} Vous pouvez retourner un `dict`, une `list`, des valeurs uniques comme `str`, `int`, etc. diff --git a/docs/fr/docs/tutorial/handling-errors.md b/docs/fr/docs/tutorial/handling-errors.md new file mode 100644 index 000000000..38935c21c --- /dev/null +++ b/docs/fr/docs/tutorial/handling-errors.md @@ -0,0 +1,244 @@ +# GĂ©rer les erreurs { #handling-errors } + +Il existe de nombreuses situations oĂč vous devez signaler une erreur Ă  un client qui utilise votre API. + +Ce client peut ĂȘtre un navigateur avec un frontend, un code d'un tiers, un appareil IoT, etc. + +Vous pourriez avoir besoin d'indiquer au client que : + +* Le client n'a pas les privilĂšges suffisants pour cette opĂ©ration. +* Le client n'a pas accĂšs Ă  cette ressource. +* L'Ă©lĂ©ment auquel le client tentait d'accĂ©der n'existe pas. +* etc. + +Dans ces cas, vous retournez normalement un **code d'Ă©tat HTTP** dans la plage de **400** (de 400 Ă  499). + +C'est similaire aux codes d'Ă©tat HTTP 200 (de 200 Ă  299). Ces codes « 200 » signifient que, d'une certaine maniĂšre, la requĂȘte a Ă©tĂ© un « succĂšs ». + +Les codes d'Ă©tat dans la plage des 400 signifient qu'il y a eu une erreur cĂŽtĂ© client. + +Vous souvenez-vous de toutes ces erreurs **« 404 Not Found »** (et des blagues) ? + +## Utiliser `HTTPException` { #use-httpexception } + +Pour renvoyer au client des rĂ©ponses HTTP avec des erreurs, vous utilisez `HTTPException`. + +### Importer `HTTPException` { #import-httpexception } + +{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *} + +### Lever une `HTTPException` dans votre code { #raise-an-httpexception-in-your-code } + +`HTTPException` est une exception Python normale avec des donnĂ©es supplĂ©mentaires pertinentes pour les API. + +Comme il s'agit d'une exception Python, vous ne la `return` pas, vous la `raise`. + +Cela signifie aussi que si vous ĂȘtes dans une fonction utilitaire appelĂ©e depuis votre fonction de chemin d'accĂšs, et que vous levez la `HTTPException` Ă  l'intĂ©rieur de cette fonction utilitaire, le reste du code de la fonction de chemin d'accĂšs ne s'exĂ©cutera pas : la requĂȘte sera immĂ©diatement interrompue et l'erreur HTTP issue de la `HTTPException` sera envoyĂ©e au client. + +L'avantage de lever une exception plutĂŽt que de retourner une valeur apparaĂźtra plus clairement dans la section sur les DĂ©pendances et la SĂ©curitĂ©. + +Dans cet exemple, lorsque le client demande un Ă©lĂ©ment par un ID qui n'existe pas, levez une exception avec un code d'Ă©tat `404` : + +{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *} + +### RĂ©ponse rĂ©sultante { #the-resulting-response } + +Si le client demande `http://example.com/items/foo` (un `item_id` « foo »), il recevra un code d'Ă©tat HTTP 200 et une rĂ©ponse JSON : + +```JSON +{ + "item": "The Foo Wrestlers" +} +``` + +Mais si le client demande `http://example.com/items/bar` (un `item_id` inexistant « bar »), il recevra un code d'Ă©tat HTTP 404 (l'erreur « not found ») et une rĂ©ponse JSON : + +```JSON +{ + "detail": "Item not found" +} +``` + +/// tip | Astuce + +Lorsque vous levez une `HTTPException`, vous pouvez passer n'importe quelle valeur convertible en JSON comme paramĂštre `detail`, pas uniquement un `str`. + +Vous pouvez passer un `dict`, une `list`, etc. + +Elles sont gĂ©rĂ©es automatiquement par **FastAPI** et converties en JSON. + +/// + +## Ajouter des en-tĂȘtes personnalisĂ©s { #add-custom-headers } + +Dans certaines situations, il est utile de pouvoir ajouter des en-tĂȘtes personnalisĂ©s Ă  l'erreur HTTP. Par exemple, pour certains types de sĂ©curitĂ©. + +Vous n'aurez probablement pas besoin de l'utiliser directement dans votre code. + +Mais si vous en aviez besoin pour un scĂ©nario avancĂ©, vous pouvez ajouter des en-tĂȘtes personnalisĂ©s : + +{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *} + +## Installer des gestionnaires d'exception personnalisĂ©s { #install-custom-exception-handlers } + +Vous pouvez ajouter des gestionnaires d'exception personnalisĂ©s avec les mĂȘmes utilitaires d'exception de Starlette. + +Supposons que vous ayez une exception personnalisĂ©e `UnicornException` que vous (ou une bibliothĂšque que vous utilisez) pourriez `raise`. + +Et vous souhaitez gĂ©rer cette exception globalement avec FastAPI. + +Vous pouvez ajouter un gestionnaire d'exception personnalisĂ© avec `@app.exception_handler()` : + +{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *} + +Ici, si vous appelez `/unicorns/yolo`, le chemin d'accĂšs va `raise` une `UnicornException`. + +Mais elle sera gĂ©rĂ©e par `unicorn_exception_handler`. + +Ainsi, vous recevrez une erreur propre, avec un code d'Ă©tat HTTP `418` et un contenu JSON : + +```JSON +{"message": "Oops! yolo did something. There goes a rainbow..."} +``` + +/// note | DĂ©tails techniques + +Vous pourriez aussi utiliser `from starlette.requests import Request` et `from starlette.responses import JSONResponse`. + +**FastAPI** fournit les mĂȘmes `starlette.responses` sous `fastapi.responses` par simple commoditĂ© pour vous, dĂ©veloppeur. Mais la plupart des rĂ©ponses disponibles proviennent directement de Starlette. Il en va de mĂȘme pour `Request`. + +/// + +## Remplacer les gestionnaires d'exception par dĂ©faut { #override-the-default-exception-handlers } + +**FastAPI** fournit des gestionnaires d'exception par dĂ©faut. + +Ces gestionnaires se chargent de renvoyer les rĂ©ponses JSON par dĂ©faut lorsque vous `raise` une `HTTPException` et lorsque la requĂȘte contient des donnĂ©es invalides. + +Vous pouvez remplacer ces gestionnaires d'exception par les vĂŽtres. + +### Remplacer les exceptions de validation de la requĂȘte { #override-request-validation-exceptions } + +Lorsqu'une requĂȘte contient des donnĂ©es invalides, **FastAPI** lĂšve en interne une `RequestValidationError`. + +Et il inclut Ă©galement un gestionnaire d'exception par dĂ©faut pour cela. + +Pour la remplacer, importez `RequestValidationError` et utilisez-la avec `@app.exception_handler(RequestValidationError)` pour dĂ©corer le gestionnaire d'exception. + +Le gestionnaire d'exception recevra une `Request` et l'exception. + +{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *} + +À prĂ©sent, si vous allez sur `/items/foo`, au lieu d'obtenir l'erreur JSON par dĂ©faut suivante : + +```JSON +{ + "detail": [ + { + "loc": [ + "path", + "item_id" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ] +} +``` + +vous obtiendrez une version texte, avec : + +``` +Validation errors: +Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer +``` + +### Remplacer le gestionnaire d'erreurs `HTTPException` { #override-the-httpexception-error-handler } + +De la mĂȘme maniĂšre, vous pouvez remplacer le gestionnaire de `HTTPException`. + +Par exemple, vous pourriez vouloir renvoyer une rĂ©ponse en texte brut au lieu de JSON pour ces erreurs : + +{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *} + +/// note | DĂ©tails techniques + +Vous pourriez aussi utiliser `from starlette.responses import PlainTextResponse`. + +**FastAPI** fournit les mĂȘmes `starlette.responses` sous `fastapi.responses` par simple commoditĂ© pour vous, le dĂ©veloppeur. Mais la plupart des rĂ©ponses disponibles proviennent directement de Starlette. + +/// + +/// warning | Alertes + +Gardez Ă  l'esprit que la `RequestValidationError` contient l'information du nom de fichier et de la ligne oĂč l'erreur de validation se produit, afin que vous puissiez l'afficher dans vos journaux avec les informations pertinentes si vous le souhaitez. + +Mais cela signifie que si vous vous contentez de la convertir en chaĂźne et de renvoyer cette information directement, vous pourriez divulguer un peu d'information sur votre systĂšme. C'est pourquoi, ici, le code extrait et affiche chaque erreur indĂ©pendamment. + +/// + +### Utiliser le corps de `RequestValidationError` { #use-the-requestvalidationerror-body } + +La `RequestValidationError` contient le `body` qu'elle a reçu avec des donnĂ©es invalides. + +Vous pouvez l'utiliser pendant le dĂ©veloppement de votre application pour journaliser le corps et le dĂ©boguer, le renvoyer Ă  l'utilisateur, etc. + +{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *} + +Essayez maintenant d'envoyer un Ă©lĂ©ment invalide comme : + +```JSON +{ + "title": "towel", + "size": "XL" +} +``` + +Vous recevrez une rĂ©ponse vous indiquant que les donnĂ©es sont invalides et contenant le corps reçu : + +```JSON hl_lines="12-15" +{ + "detail": [ + { + "loc": [ + "body", + "size" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ], + "body": { + "title": "towel", + "size": "XL" + } +} +``` + +#### `HTTPException` de FastAPI vs `HTTPException` de Starlette { #fastapis-httpexception-vs-starlettes-httpexception } + +**FastAPI** a sa propre `HTTPException`. + +Et la classe d'erreur `HTTPException` de **FastAPI** hĂ©rite de la classe d'erreur `HTTPException` de Starlette. + +La seule diffĂ©rence est que la `HTTPException` de **FastAPI** accepte toute donnĂ©e sĂ©rialisable en JSON pour le champ `detail`, tandis que la `HTTPException` de Starlette n'accepte que des chaĂźnes. + +Ainsi, vous pouvez continuer Ă  lever la `HTTPException` de **FastAPI** normalement dans votre code. + +Mais lorsque vous enregistrez un gestionnaire d'exception, vous devez l'enregistrer pour la `HTTPException` de Starlette. + +De cette façon, si une partie du code interne de Starlette, ou une extension ou un plug-in Starlette, lĂšve une `HTTPException` de Starlette, votre gestionnaire pourra l'intercepter et la traiter. + +Dans cet exemple, afin de pouvoir avoir les deux `HTTPException` dans le mĂȘme code, les exceptions de Starlette sont renommĂ©es en `StarletteHTTPException` : + +```Python +from starlette.exceptions import HTTPException as StarletteHTTPException +``` + +### RĂ©utiliser les gestionnaires d'exception de **FastAPI** { #reuse-fastapis-exception-handlers } + +Si vous souhaitez utiliser l'exception avec les mĂȘmes gestionnaires d'exception par dĂ©faut de **FastAPI**, vous pouvez importer et rĂ©utiliser les gestionnaires d'exception par dĂ©faut depuis `fastapi.exception_handlers` : + +{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *} + +Dans cet exemple, vous vous contentez d'afficher l'erreur avec un message trĂšs expressif, mais vous voyez l'idĂ©e. Vous pouvez utiliser l'exception puis simplement rĂ©utiliser les gestionnaires d'exception par dĂ©faut. diff --git a/docs/fr/docs/tutorial/header-param-models.md b/docs/fr/docs/tutorial/header-param-models.md new file mode 100644 index 000000000..8fc1a3d36 --- /dev/null +++ b/docs/fr/docs/tutorial/header-param-models.md @@ -0,0 +1,72 @@ +# ModĂšles de paramĂštres d'en-tĂȘte { #header-parameter-models } + +Si vous avez un groupe de **paramĂštres d'en-tĂȘte** liĂ©s, vous pouvez crĂ©er un **modĂšle Pydantic** pour les dĂ©clarer. + +Cela vous permet de **rĂ©utiliser le modĂšle** Ă  **plusieurs endroits** et aussi de dĂ©clarer des validations et des mĂ©tadonnĂ©es pour tous les paramĂštres en une seule fois. 😎 + +/// note | Remarque + +Cela est pris en charge depuis la version `0.115.0` de FastAPI. đŸ€“ + +/// + +## ParamĂštres d'en-tĂȘte avec un modĂšle Pydantic { #header-parameters-with-a-pydantic-model } + +DĂ©clarez les **paramĂštres d'en-tĂȘte** dont vous avez besoin dans un **modĂšle Pydantic**, puis dĂ©clarez le paramĂštre comme `Header` : + +{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *} + +**FastAPI** extrait les donnĂ©es de **chaque champ** depuis les **en-tĂȘtes** de la requĂȘte et vous fournit le modĂšle Pydantic que vous avez dĂ©fini. + +## Consulter la documentation { #check-the-docs } + +Vous pouvez voir les en-tĂȘtes requis dans l'interface de la documentation Ă  `/docs` : + +
+ +
+ +## Interdire les en-tĂȘtes supplĂ©mentaires { #forbid-extra-headers } + +Dans certains cas d'utilisation particuliers (probablement pas trĂšs courants), vous pourriez vouloir **restreindre** les en-tĂȘtes que vous souhaitez recevoir. + +Vous pouvez utiliser la configuration du modĂšle de Pydantic pour `forbid` tout champ `extra` : + +{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *} + +Si un client essaie d'envoyer des **en-tĂȘtes supplĂ©mentaires**, il recevra une **rĂ©ponse d'erreur**. + +Par exemple, si le client essaie d'envoyer un en-tĂȘte `tool` avec la valeur `plumbus`, il recevra une **rĂ©ponse d'erreur** lui indiquant que le paramĂštre d'en-tĂȘte `tool` n'est pas autorisĂ© : + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["header", "tool"], + "msg": "Extra inputs are not permitted", + "input": "plumbus", + } + ] +} +``` + +## DĂ©sactiver convert_underscores { #disable-convert-underscores } + +Comme pour les paramĂštres d'en-tĂȘte classiques, lorsque vous avez des caractĂšres de soulignement dans les noms de paramĂštres, ils sont **automatiquement convertis en tirets**. + +Par exemple, si vous avez un paramĂštre d'en-tĂȘte `save_data` dans le code, l'en-tĂȘte HTTP attendu sera `save-data`, et il apparaĂźtra ainsi dans la documentation. + +Si, pour une raison quelconque, vous devez dĂ©sactiver cette conversion automatique, vous pouvez aussi le faire pour les modĂšles Pydantic de paramĂštres d'en-tĂȘte. + +{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *} + +/// warning | Alertes + +Avant de dĂ©finir `convert_underscores` Ă  `False`, gardez Ă  l'esprit que certains proxys et serveurs HTTP interdisent l'utilisation d'en-tĂȘtes contenant des underscores. + +/// + +## RĂ©sumĂ© { #summary } + +Vous pouvez utiliser des **modĂšles Pydantic** pour dĂ©clarer des **en-tĂȘtes** dans **FastAPI**. 😎 diff --git a/docs/fr/docs/tutorial/header-params.md b/docs/fr/docs/tutorial/header-params.md new file mode 100644 index 000000000..608559c85 --- /dev/null +++ b/docs/fr/docs/tutorial/header-params.md @@ -0,0 +1,91 @@ +# ParamĂštres d'en-tĂȘte { #header-parameters } + +Vous pouvez dĂ©finir des paramĂštres `Header` de la mĂȘme maniĂšre que vous dĂ©finissez des paramĂštres `Query`, `Path` et `Cookie`. + +## Importer `Header` { #import-header } + +Commencez par importer `Header` : + +{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *} + +## DĂ©clarer des paramĂštres `Header` { #declare-header-parameters } + +DĂ©clarez ensuite les paramĂštres d'en-tĂȘte en utilisant la mĂȘme structure qu'avec `Path`, `Query` et `Cookie`. + +Vous pouvez dĂ©finir la valeur par dĂ©faut ainsi que tous les paramĂštres supplĂ©mentaires de validation ou d'annotation : + +{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *} + +/// note | DĂ©tails techniques + +`Header` est une classe « sƓur » de `Path`, `Query` et `Cookie`. Elle hĂ©rite Ă©galement de la mĂȘme classe commune `Param`. + +Mais rappelez-vous que lorsque vous importez `Query`, `Path`, `Header` et d'autres depuis `fastapi`, ce sont en rĂ©alitĂ© des fonctions qui renvoient des classes spĂ©ciales. + +/// + +/// info + +Pour dĂ©clarer des en-tĂȘtes, vous devez utiliser `Header`, sinon les paramĂštres seraient interprĂ©tĂ©s comme des paramĂštres de requĂȘte. + +/// + +## Conversion automatique { #automatic-conversion } + +`Header` offre un peu de fonctionnalitĂ© supplĂ©mentaire par rapport Ă  `Path`, `Query` et `Cookie`. + +La plupart des en-tĂȘtes standards sont sĂ©parĂ©s par un caractĂšre « trait d'union », Ă©galement appelĂ© « signe moins » (`-`). + +Mais une variable comme `user-agent` est invalide en Python. + +Ainsi, par dĂ©faut, `Header` convertit les caractĂšres des noms de paramĂštres du tiret bas (`_`) en trait d'union (`-`) pour extraire et documenter les en-tĂȘtes. + +De plus, les en-tĂȘtes HTTP ne sont pas sensibles Ă  la casse, vous pouvez donc les dĂ©clarer avec le style Python standard (aussi appelĂ© « snake_case »). + +Vous pouvez donc utiliser `user_agent` comme vous le feriez normalement dans du code Python, au lieu d'avoir Ă  mettre des majuscules aux premiĂšres lettres comme `User_Agent` ou quelque chose de similaire. + +Si, pour une raison quelconque, vous devez dĂ©sactiver la conversion automatique des traits bas en traits d'union, dĂ©finissez le paramĂštre `convert_underscores` de `Header` sur `False` : + +{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *} + +/// warning | Alertes + +Avant de dĂ©finir `convert_underscores` sur `False`, gardez Ă  l'esprit que certains proxies et serveurs HTTP interdisent l'utilisation d'en-tĂȘtes contenant des traits bas. + +/// + +## GĂ©rer les en-tĂȘtes dupliquĂ©s { #duplicate-headers } + +Il est possible de recevoir des en-tĂȘtes en double. Autrement dit, le mĂȘme en-tĂȘte avec plusieurs valeurs. + +Vous pouvez dĂ©finir ces cas Ă  l'aide d'une liste dans la dĂ©claration de type. + +Vous recevrez toutes les valeurs de l'en-tĂȘte dupliquĂ© sous forme de `list` Python. + +Par exemple, pour dĂ©clarer un en-tĂȘte `X-Token` qui peut apparaĂźtre plusieurs fois, vous pouvez Ă©crire : + +{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *} + +Si vous communiquez avec ce *chemin d'accĂšs* en envoyant deux en-tĂȘtes HTTP comme : + +``` +X-Token: foo +X-Token: bar +``` + +La rĂ©ponse ressemblerait Ă  ceci : + +```JSON +{ + "X-Token values": [ + "bar", + "foo" + ] +} +``` + +## RĂ©capitulatif { #recap } + +DĂ©clarez les en-tĂȘtes avec `Header`, en suivant le mĂȘme modĂšle que pour `Query`, `Path` et `Cookie`. + +Et ne vous souciez pas des traits bas dans vos variables, **FastAPI** s'occupe de les convertir. diff --git a/docs/fr/docs/tutorial/metadata.md b/docs/fr/docs/tutorial/metadata.md new file mode 100644 index 000000000..3ea3865ba --- /dev/null +++ b/docs/fr/docs/tutorial/metadata.md @@ -0,0 +1,120 @@ +# MĂ©tadonnĂ©es et URL des documents { #metadata-and-docs-urls } + +Vous pouvez personnaliser plusieurs configurations de mĂ©tadonnĂ©es dans votre application **FastAPI**. + +## MĂ©tadonnĂ©es pour l'API { #metadata-for-api } + +Vous pouvez dĂ©finir les champs suivants qui sont utilisĂ©s dans la spĂ©cification OpenAPI et les interfaces utilisateur de documentation automatique de l’API : + +| ParamĂštre | Type | Description | +|------------|------|-------------| +| `title` | `str` | Le titre de l’API. | +| `summary` | `str` | Un court rĂ©sumĂ© de l’API. Disponible depuis OpenAPI 3.1.0, FastAPI 0.99.0. | +| `description` | `str` | Une brĂšve description de l’API. Elle peut utiliser Markdown. | +| `version` | `string` | La version de l’API. C’est la version de votre propre application, pas d’OpenAPI. Par exemple `2.5.0`. | +| `terms_of_service` | `str` | Une URL vers les Conditions d’utilisation de l’API. Le cas Ă©chĂ©ant, il doit s’agir d’une URL. | +| `contact` | `dict` | Les informations de contact pour l’API exposĂ©e. Cela peut contenir plusieurs champs.
champs de contact
ParamĂštreTypeDescription
namestrLe nom identifiant de la personne/organisation de contact.
urlstrL’URL pointant vers les informations de contact. DOIT ĂȘtre au format d’une URL.
emailstrL’adresse e-mail de la personne/organisation de contact. DOIT ĂȘtre au format d’une adresse e-mail.
| +| `license_info` | `dict` | Les informations de licence pour l’API exposĂ©e. Cela peut contenir plusieurs champs.
champs de license_info
ParamĂštreTypeDescription
namestrOBLIGATOIRE (si un license_info est dĂ©fini). Le nom de la licence utilisĂ©e pour l’API.
identifierstrUne expression de licence SPDX pour l’API. Le champ identifier est mutuellement exclusif du champ url. Disponible depuis OpenAPI 3.1.0, FastAPI 0.99.0.
urlstrUne URL vers la licence utilisĂ©e pour l’API. DOIT ĂȘtre au format d’une URL.
| + +Vous pouvez les dĂ©finir comme suit : + +{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *} + +/// tip | Astuce + +Vous pouvez Ă©crire du Markdown dans le champ `description` et il sera rendu dans la sortie. + +/// + +Avec cette configuration, les documents API automatiques ressembleraient à : + + + +## Identifiant de licence { #license-identifier } + +Depuis OpenAPI 3.1.0 et FastAPI 0.99.0, vous pouvez Ă©galement dĂ©finir `license_info` avec un `identifier` au lieu d’une `url`. + +Par exemple : + +{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *} + +## MĂ©tadonnĂ©es pour les tags { #metadata-for-tags } + +Vous pouvez Ă©galement ajouter des mĂ©tadonnĂ©es supplĂ©mentaires pour les diffĂ©rents tags utilisĂ©s pour regrouper vos chemins d'accĂšs avec le paramĂštre `openapi_tags`. + +Il prend une liste contenant un dictionnaire pour chaque tag. + +Chaque dictionnaire peut contenir : + +* `name` (**requis**) : un `str` avec le mĂȘme nom de tag que vous utilisez dans le paramĂštre `tags` de vos *chemins d'accĂšs* et `APIRouter`s. +* `description` : un `str` avec une courte description pour le tag. Il peut contenir du Markdown et sera affichĂ© dans l’interface utilisateur de la documentation. +* `externalDocs` : un `dict` dĂ©crivant une documentation externe avec : + * `description` : un `str` avec une courte description pour la documentation externe. + * `url` (**requis**) : un `str` avec l’URL de la documentation externe. + +### CrĂ©er des mĂ©tadonnĂ©es pour les tags { #create-metadata-for-tags } + +Essayons cela avec un exemple de tags pour `users` et `items`. + +CrĂ©ez des mĂ©tadonnĂ©es pour vos tags et transmettez-les au paramĂštre `openapi_tags` : + +{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *} + +Notez que vous pouvez utiliser Markdown Ă  l’intĂ©rieur des descriptions, par exemple « login » sera affichĂ© en gras (**login**) et « fancy » sera affichĂ© en italique (_fancy_). + +/// tip | Astuce + +Vous n’avez pas Ă  ajouter des mĂ©tadonnĂ©es pour tous les tags que vous utilisez. + +/// + +### Utiliser vos tags { #use-your-tags } + +Utilisez le paramĂštre `tags` avec vos *chemins d'accĂšs* (et `APIRouter`s) pour les affecter Ă  diffĂ©rents tags : + +{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *} + +/// info + +En savoir plus sur les tags dans [Configuration de chemins d'accĂšs](path-operation-configuration.md#tags){.internal-link target=_blank}. + +/// + +### Consultez les documents { #check-the-docs } + +DĂ©sormais, si vous consultez les documents, ils afficheront toutes les mĂ©tadonnĂ©es supplĂ©mentaires : + + + +### DĂ©finir l’ordre des tags { #order-of-tags } + +L’ordre de chaque dictionnaire de mĂ©tadonnĂ©es de tag dĂ©finit Ă©galement l’ordre affichĂ© dans l’interface utilisateur de la documentation. + +Par exemple, mĂȘme si `users` viendrait aprĂšs `items` par ordre alphabĂ©tique, il est affichĂ© avant, car nous avons ajoutĂ© ses mĂ©tadonnĂ©es comme premier dictionnaire de la liste. + +## URL OpenAPI { #openapi-url } + +Par dĂ©faut, le schĂ©ma OpenAPI est servi Ă  `/openapi.json`. + +Mais vous pouvez le configurer avec le paramĂštre `openapi_url`. + +Par exemple, pour qu’il soit servi Ă  `/api/v1/openapi.json` : + +{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *} + +Si vous souhaitez dĂ©sactiver complĂštement le schĂ©ma OpenAPI, vous pouvez dĂ©finir `openapi_url=None`, cela dĂ©sactivera Ă©galement les interfaces utilisateur de la documentation qui l’utilisent. + +## URL des documents { #docs-urls } + +Vous pouvez configurer les deux interfaces utilisateur de documentation incluses : + +* **Swagger UI** : servie Ă  `/docs`. + * Vous pouvez dĂ©finir son URL avec le paramĂštre `docs_url`. + * Vous pouvez la dĂ©sactiver en dĂ©finissant `docs_url=None`. +* **ReDoc** : servie Ă  `/redoc`. + * Vous pouvez dĂ©finir son URL avec le paramĂštre `redoc_url`. + * Vous pouvez la dĂ©sactiver en dĂ©finissant `redoc_url=None`. + +Par exemple, pour que Swagger UI soit servi Ă  `/documentation` et dĂ©sactiver ReDoc : + +{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *} diff --git a/docs/fr/docs/tutorial/middleware.md b/docs/fr/docs/tutorial/middleware.md new file mode 100644 index 000000000..6cbbc3e45 --- /dev/null +++ b/docs/fr/docs/tutorial/middleware.md @@ -0,0 +1,95 @@ +# Middleware { #middleware } + +Vous pouvez ajouter des middlewares aux applications **FastAPI**. + +Un « middleware » est une fonction qui agit sur chaque **requĂȘte** avant qu’elle ne soit traitĂ©e par un *chemin d'accĂšs* spĂ©cifique. Et aussi sur chaque **rĂ©ponse** avant son renvoi. + +* Il intercepte chaque **requĂȘte** qui parvient Ă  votre application. +* Il peut alors faire quelque chose avec cette **requĂȘte** ou exĂ©cuter tout code nĂ©cessaire. +* Ensuite, il transmet la **requĂȘte** pour qu’elle soit traitĂ©e par le reste de l’application (par un *chemin d'accĂšs*). +* Puis il rĂ©cupĂšre la **rĂ©ponse** gĂ©nĂ©rĂ©e par l’application (par un *chemin d'accĂšs*). +* Il peut faire quelque chose avec cette **rĂ©ponse** ou exĂ©cuter tout code nĂ©cessaire. +* Enfin, il renvoie la **rĂ©ponse**. + +/// note | DĂ©tails techniques + +Si vous avez des dĂ©pendances avec `yield`, le code de sortie s’exĂ©cutera aprĂšs le middleware. + +S’il y avait des tĂąches d’arriĂšre-plan (prĂ©sentĂ©es dans la section [TĂąches d’arriĂšre-plan](background-tasks.md){.internal-link target=_blank}, que vous verrez plus tard), elles s’exĂ©cuteront aprĂšs tous les middlewares. + +/// + +## CrĂ©er un middleware { #create-a-middleware } + +Pour crĂ©er un middleware, utilisez le dĂ©corateur `@app.middleware("http")` au-dessus d’une fonction. + +La fonction de middleware reçoit : + +* La `request`. +* Une fonction `call_next` qui recevra la `request` en paramĂštre. + * Cette fonction transmettra la `request` au *chemin d'accĂšs* correspondant. + * Puis elle renverra la `response` gĂ©nĂ©rĂ©e par le *chemin d'accĂšs* correspondant. +* Vous pouvez ensuite modifier la `response` avant de la renvoyer. + +{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *} + +/// tip | Astuce + +Gardez Ă  l’esprit que des en-tĂȘtes propriĂ©taires personnalisĂ©s peuvent ĂȘtre ajoutĂ©s en utilisant le prĂ©fixe `X-`. + +Mais si vous avez des en-tĂȘtes personnalisĂ©s que vous voulez rendre visibles pour un client dans un navigateur, vous devez les ajouter Ă  votre configuration CORS ([CORS (Partage des ressources entre origines)](cors.md){.internal-link target=_blank}) en utilisant le paramĂštre `expose_headers` documentĂ© dans la documentation CORS de Starlette. + +/// + +/// note | DĂ©tails techniques + +Vous pourriez aussi utiliser `from starlette.requests import Request`. + +**FastAPI** le fournit pour votre confort de dĂ©veloppeur. Mais cela provient directement de Starlette. + +/// + +### Avant et aprĂšs la `response` { #before-and-after-the-response } + +Vous pouvez ajouter du code Ă  exĂ©cuter avec la `request`, avant que tout *chemin d'accĂšs* ne la reçoive. + +Et aussi aprĂšs que la `response` a Ă©tĂ© gĂ©nĂ©rĂ©e, avant de la renvoyer. + +Par exemple, vous pourriez ajouter un en-tĂȘte personnalisĂ© `X-Process-Time` contenant le temps en secondes nĂ©cessaire pour traiter la requĂȘte et gĂ©nĂ©rer une rĂ©ponse : + +{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *} + +/// tip | Astuce + +Ici, nous utilisons `time.perf_counter()` au lieu de `time.time()` car cela peut ĂȘtre plus prĂ©cis pour ces cas d’usage. đŸ€“ + +/// + +## Ordre d’exĂ©cution de plusieurs middlewares { #multiple-middleware-execution-order } + +Quand vous ajoutez plusieurs middlewares en utilisant soit le dĂ©corateur `@app.middleware()`, soit la mĂ©thode `app.add_middleware()`, chaque nouveau middleware enveloppe l’application, formant une pile. Le dernier middleware ajoutĂ© est le plus externe, et le premier est le plus interne. + +Sur le chemin de la requĂȘte, le plus externe s’exĂ©cute en premier. + +Sur le chemin de la rĂ©ponse, il s’exĂ©cute en dernier. + +Par exemple : + +```Python +app.add_middleware(MiddlewareA) +app.add_middleware(MiddlewareB) +``` + +Cela aboutit Ă  l’ordre d’exĂ©cution suivant : + +* **RequĂȘte** : MiddlewareB → MiddlewareA → route + +* **RĂ©ponse** : route → MiddlewareA → MiddlewareB + +Ce comportement d’empilement garantit que les middlewares s’exĂ©cutent dans un ordre prĂ©visible et contrĂŽlable. + +## Autres middlewares { #other-middlewares } + +Vous pouvez en lire davantage sur d’autres middlewares dans le [Guide de l’utilisateur avancĂ© : Middleware avancĂ©](../advanced/middleware.md){.internal-link target=_blank}. + +Vous verrez comment gĂ©rer CORS avec un middleware dans la section suivante. diff --git a/docs/fr/docs/tutorial/path-operation-configuration.md b/docs/fr/docs/tutorial/path-operation-configuration.md new file mode 100644 index 000000000..f8041fa69 --- /dev/null +++ b/docs/fr/docs/tutorial/path-operation-configuration.md @@ -0,0 +1,107 @@ +# Configurer les chemins d'accĂšs { #path-operation-configuration } + +Vous pouvez passer plusieurs paramĂštres Ă  votre *dĂ©corateur de chemin d'accĂšs* pour le configurer. + +/// warning | Alertes + +Notez que ces paramĂštres sont passĂ©s directement au *dĂ©corateur de chemin d'accĂšs*, et non Ă  votre *fonction de chemin d'accĂšs*. + +/// + +## DĂ©finir le code d'Ă©tat de la rĂ©ponse { #response-status-code } + +Vous pouvez dĂ©finir le `status_code` (HTTP) Ă  utiliser dans la rĂ©ponse de votre *chemin d'accĂšs*. + +Vous pouvez passer directement le code `int`, comme `404`. + +Mais si vous ne vous souvenez pas Ă  quoi correspond chaque code numĂ©rique, vous pouvez utiliser les constantes abrĂ©gĂ©es dans `status` : + +{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *} + +Ce code d'Ă©tat sera utilisĂ© dans la rĂ©ponse et ajoutĂ© au schĂ©ma OpenAPI. + +/// note | DĂ©tails techniques + +Vous pouvez Ă©galement utiliser `from starlette import status`. + +**FastAPI** fournit le mĂȘme `starlette.status` sous le nom `fastapi.status` pour votre commoditĂ©, en tant que dĂ©veloppeur. Mais cela provient directement de Starlette. + +/// + +## Ajouter des tags { #tags } + +Vous pouvez ajouter des tags Ă  votre *chemin d'accĂšs*, en passant le paramĂštre `tags` avec une `list` de `str` (gĂ©nĂ©ralement un seul `str`) : + +{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *} + +Ils seront ajoutĂ©s au schĂ©ma OpenAPI et utilisĂ©s par les interfaces de documentation automatiques : + + + +### Utiliser des tags avec Enum { #tags-with-enums } + +Si vous avez une grande application, vous pourriez finir par accumuler **plusieurs tags**, et vous voudrez vous assurer d'utiliser toujours le **mĂȘme tag** pour les *chemins d'accĂšs* associĂ©s. + +Dans ces cas, il peut ĂȘtre judicieux de stocker les tags dans un `Enum`. + +**FastAPI** le prend en charge de la mĂȘme maniĂšre qu'avec des chaĂźnes simples : + +{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *} + +## Ajouter un rĂ©sumĂ© et une description { #summary-and-description } + +Vous pouvez ajouter un `summary` et une `description` : + +{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *} + +## Utiliser la description depuis la docstring { #description-from-docstring } + +Comme les descriptions ont tendance Ă  ĂȘtre longues et Ă  couvrir plusieurs lignes, vous pouvez dĂ©clarer la description du *chemin d'accĂšs* dans la docstring de la fonction et **FastAPI** la lira Ă  partir de lĂ . + +Vous pouvez Ă©crire Markdown dans la docstring, il sera interprĂ©tĂ© et affichĂ© correctement (en tenant compte de l'indentation de la docstring). + +{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *} + +Elle sera utilisĂ©e dans les documents interactifs : + + + +## DĂ©finir la description de la rĂ©ponse { #response-description } + +Vous pouvez spĂ©cifier la description de la rĂ©ponse avec le paramĂštre `response_description` : + +{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *} + +/// info + +Notez que `response_description` se rĂ©fĂšre spĂ©cifiquement Ă  la rĂ©ponse, tandis que `description` se rĂ©fĂšre au *chemin d'accĂšs* en gĂ©nĂ©ral. + +/// + +/// check | VĂ©rifications + +OpenAPI spĂ©cifie que chaque *chemin d'accĂšs* requiert une description de rĂ©ponse. + +Donc, si vous n'en fournissez pas, **FastAPI** en gĂ©nĂ©rera automatiquement une « RĂ©ponse rĂ©ussie ». + +/// + + + +## DĂ©prĂ©cier un *chemin d'accĂšs* { #deprecate-a-path-operation } + +Si vous devez marquer un *chemin d'accĂšs* comme dĂ©prĂ©ciĂ©, sans pour autant le supprimer, passez le paramĂštre `deprecated` : + +{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *} + +Il sera clairement marquĂ© comme dĂ©prĂ©ciĂ© dans les documents interactifs : + + + +Voyez Ă  quoi ressemblent les *chemins d'accĂšs* dĂ©prĂ©ciĂ©s et non dĂ©prĂ©ciĂ©s : + + + +## RĂ©capitulatif { #recap } + +Vous pouvez facilement configurer et ajouter des mĂ©tadonnĂ©es Ă  vos *chemins d'accĂšs* en passant des paramĂštres aux *dĂ©corateurs de chemin d'accĂšs*. diff --git a/docs/fr/docs/tutorial/path-params-numeric-validations.md b/docs/fr/docs/tutorial/path-params-numeric-validations.md index c80710777..2dbaaa8ca 100644 --- a/docs/fr/docs/tutorial/path-params-numeric-validations.md +++ b/docs/fr/docs/tutorial/path-params-numeric-validations.md @@ -54,11 +54,11 @@ Cela n'a pas d'importance pour **FastAPI**. Il dĂ©tectera les paramĂštres par le 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_py310.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_py310.py *} ## Ordonner les paramĂštres comme vous le souhaitez, astuces { #order-the-parameters-as-you-need-tricks } @@ -81,15 +81,15 @@ Si vous voulez : Passez `*`, comme premier paramĂštre de la fonction. -Python ne fera rien avec ce `*`, mais il saura que tous les paramĂštres suivants doivent ĂȘtre appelĂ©s comme arguments "mots-clĂ©s" (paires clĂ©-valeur), Ă©galement connus sous le nom de kwargs. 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 kwargs. 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_py310.py hl[7] *} ### Mieux avec `Annotated` { #better-with-annotated } Gardez Ă  l'esprit que si vous utilisez `Annotated`, comme vous n'utilisez pas les valeurs par dĂ©faut des paramĂštres de fonction, vous n'aurez pas ce problĂšme, et vous n'aurez probablement pas besoin d'utiliser `*`. -{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *} ## Validations numĂ©riques : supĂ©rieur ou Ă©gal { #number-validations-greater-than-or-equal } @@ -97,7 +97,7 @@ Avec `Query` et `Path` (et d'autres que vous verrez plus tard) vous pouvez dĂ©cl 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] *} +{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *} ## Validations numĂ©riques : supĂ©rieur et infĂ©rieur ou Ă©gal { #number-validations-greater-than-and-less-than-or-equal } @@ -106,7 +106,7 @@ 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/tutorial005_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *} ## Validations numĂ©riques : flottants, supĂ©rieur et infĂ©rieur { #number-validations-floats-greater-than-and-less-than } @@ -118,7 +118,7 @@ Ainsi, `0.5` serait une valeur valide. Mais `0.0` ou `0` ne le serait pas. Et la mĂȘme chose pour lt. -{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *} +{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *} ## Pour rĂ©sumer { #recap } diff --git a/docs/fr/docs/tutorial/path-params.md b/docs/fr/docs/tutorial/path-params.md index 3b2955a95..985eff635 100644 --- a/docs/fr/docs/tutorial/path-params.md +++ b/docs/fr/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ Vous pouvez dĂ©clarer des « paramĂštres » ou « variables » de chemin avec la mĂȘme syntaxe utilisĂ©e par les chaĂźnes de format Python : -{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *} La valeur du paramĂštre de chemin `item_id` sera transmise Ă  votre fonction dans l'argument `item_id`. @@ -16,7 +16,7 @@ Donc, si vous exĂ©cutez cet exemple et allez sur Conversion de donnĂ©es { #data-conversion } +## Conversion de donnĂ©es { #data-conversion } Si vous exĂ©cutez cet exemple et ouvrez votre navigateur sur http://127.0.0.1:8000/items/3, vous verrez comme rĂ©ponse : @@ -38,7 +38,7 @@ Si vous exĂ©cutez cet exemple et ouvrez votre navigateur sur « parsing » de la requĂȘte. +Ainsi, avec cette dĂ©claration de type, **FastAPI** vous fournit automatiquement le « parsing » de la requĂȘte. /// @@ -118,19 +118,19 @@ Et vous pouvez aussi avoir un chemin `/users/{user_id}` pour rĂ©cupĂ©rer des don Comme les *chemins d'accĂšs* sont Ă©valuĂ©s dans l'ordre, vous devez vous assurer que le chemin `/users/me` est dĂ©clarĂ© avant celui de `/users/{user_id}` : -{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *} +{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *} Sinon, le chemin `/users/{user_id}` correspondrait aussi Ă  `/users/me`, « pensant » qu'il reçoit un paramĂštre `user_id` avec la valeur « me ». De mĂȘme, vous ne pouvez pas redĂ©finir un chemin d'accĂšs : -{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *} +{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *} Le premier sera toujours utilisĂ© puisque le chemin correspond en premier. ## Valeurs prĂ©dĂ©finies { #predefined-values } -Si vous avez un *chemin d'accĂšs* qui reçoit un *paramĂštre de chemin*, mais que vous voulez que les valeurs possibles de ce *paramĂštre de chemin* soient prĂ©dĂ©finies, vous pouvez utiliser une `Enum` Python standard. +Si vous avez un *chemin d'accĂšs* qui reçoit un *paramĂštre de chemin*, mais que vous voulez que les valeurs possibles de ce *paramĂštre de chemin* soient prĂ©dĂ©finies, vous pouvez utiliser une `Enum` Python standard. ### CrĂ©er une classe `Enum` { #create-an-enum-class } @@ -140,11 +140,11 @@ En hĂ©ritant de `str`, la documentation de l'API saura que les valeurs doivent 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] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *} /// tip | Astuce -Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des noms de modĂšles de Machine Learning. +Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des noms de modĂšles de Machine Learning. /// @@ -152,7 +152,7 @@ Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des CrĂ©ez ensuite un *paramĂštre de chemin* avec une annotation de type utilisant la classe d'Ă©numĂ©ration que vous avez créée (`ModelName`) : -{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *} ### Consulter la documentation { #check-the-docs } @@ -168,13 +168,13 @@ La valeur du *paramĂštre de chemin* sera un *membre d'Ă©numĂ©ration*. Vous pouvez le comparer avec le *membre d'Ă©numĂ©ration* dans votre enum `ModelName` : -{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *} #### Obtenir la *valeur de l'Ă©numĂ©ration* { #get-the-enumeration-value } Vous pouvez obtenir la valeur rĂ©elle (une `str` dans ce cas) 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_py310.py hl[20] *} /// tip | Astuce @@ -188,7 +188,7 @@ Vous pouvez retourner des *membres d'Ă©numĂ©ration* depuis votre *chemin d'accĂš Ils seront convertis vers leurs valeurs correspondantes (des chaĂźnes de caractĂšres ici) avant d'ĂȘtre renvoyĂ©s au client : -{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *} +{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *} Dans votre client, vous recevrez une rĂ©ponse JSON comme : @@ -227,7 +227,7 @@ Dans ce cas, le nom du paramĂštre est `file_path`, et la derniĂšre partie, `:pat Vous pouvez donc l'utiliser ainsi : -{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *} +{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *} /// tip | Astuce @@ -242,7 +242,7 @@ Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double sl Avec **FastAPI**, en utilisant des dĂ©clarations de type Python courtes, intuitives et standard, vous obtenez : * Support de l'Ă©diteur : vĂ©rifications d'erreurs, autocomplĂ©tion, etc. -* DonnĂ©es « parsing » +* DonnĂ©es « parsing » * Validation de donnĂ©es * Annotations d'API et documentation automatique diff --git a/docs/fr/docs/tutorial/query-param-models.md b/docs/fr/docs/tutorial/query-param-models.md new file mode 100644 index 000000000..b9bb1d137 --- /dev/null +++ b/docs/fr/docs/tutorial/query-param-models.md @@ -0,0 +1,68 @@ +# ModĂšles de paramĂštres de requĂȘte { #query-parameter-models } + +Si vous avez un groupe de paramĂštres de requĂȘte liĂ©s, vous pouvez crĂ©er un modĂšle Pydantic pour les dĂ©clarer. + +Cela vous permet de rĂ©utiliser le modĂšle Ă  plusieurs endroits et aussi de dĂ©clarer des validations et des mĂ©tadonnĂ©es pour tous les paramĂštres en une seule fois. 😎 + +/// note | Remarque + +Pris en charge depuis FastAPI version `0.115.0`. đŸ€“ + +/// + +## DĂ©clarer des paramĂštres de requĂȘte avec un modĂšle Pydantic { #query-parameters-with-a-pydantic-model } + +DĂ©clarez les paramĂštres de requĂȘte dont vous avez besoin dans un modĂšle Pydantic, puis dĂ©clarez le paramĂštre en tant que `Query` : + +{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *} + +FastAPI extrait les donnĂ©es pour chaque champ Ă  partir des paramĂštres de requĂȘte de la requĂȘte et vous fournit le modĂšle Pydantic que vous avez dĂ©fini. + +## Consulter les documents { #check-the-docs } + +Vous pouvez voir les paramĂštres de requĂȘte dans l'interface des documents Ă  `/docs` : + +
+ +
+ +## Interdire des paramĂštres de requĂȘte supplĂ©mentaires { #forbid-extra-query-parameters } + +Dans certains cas d'utilisation particuliers (probablement peu courants), vous pouvez vouloir restreindre les paramĂštres de requĂȘte que vous souhaitez recevoir. + +Vous pouvez utiliser la configuration du modĂšle Pydantic pour `forbid` tout champ `extra` : + +{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *} + +Si un client tente d'envoyer des donnĂ©es supplĂ©mentaires dans les paramĂštres de requĂȘte, il recevra une rĂ©ponse d'erreur. + +Par exemple, si le client tente d'envoyer un paramĂštre de requĂȘte `tool` avec la valeur `plumbus`, comme : + +```http +https://example.com/items/?limit=10&tool=plumbus +``` + +Il recevra une rĂ©ponse d'erreur lui indiquant que le paramĂštre de requĂȘte `tool` n'est pas autorisĂ© : + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["query", "tool"], + "msg": "Extra inputs are not permitted", + "input": "plumbus" + } + ] +} +``` + +## RĂ©sumĂ© { #summary } + +Vous pouvez utiliser des modĂšles Pydantic pour dĂ©clarer des paramĂštres de requĂȘte dans FastAPI. 😎 + +/// tip | Astuce + +Alerte spoiler : vous pouvez aussi utiliser des modĂšles Pydantic pour dĂ©clarer des cookies et des en-tĂȘtes, mais vous lirez cela plus tard dans le tutoriel. đŸ€« + +/// diff --git a/docs/fr/docs/tutorial/query-params-str-validations.md b/docs/fr/docs/tutorial/query-params-str-validations.md index 544d10328..17b751f23 100644 --- a/docs/fr/docs/tutorial/query-params-str-validations.md +++ b/docs/fr/docs/tutorial/query-params-str-validations.md @@ -47,40 +47,16 @@ C’est le moment de l’utiliser avec FastAPI. 🚀 Nous avions cette annotation de type : -//// tab | Python 3.10+ - ```Python q: str | None = None ``` -//// - -//// tab | Python 3.9+ - -```Python -q: Union[str, None] = None -``` - -//// - Ce que nous allons faire, c’est l’englober avec `Annotated`, de sorte que cela devienne : -//// tab | Python 3.10+ - ```Python q: Annotated[str | None] = None ``` -//// - -//// tab | Python 3.9+ - -```Python -q: Annotated[Union[str, None]] = None -``` - -//// - Les deux versions signifient la mĂȘme chose, `q` est un paramĂštre qui peut ĂȘtre une `str` ou `None`, et par dĂ©faut, c’est `None`. Passons maintenant aux choses amusantes. 🎉 @@ -109,7 +85,7 @@ FastAPI va maintenant : ## Alternative (ancienne) : `Query` comme valeur par dĂ©faut { #alternative-old-query-as-the-default-value } -Les versions prĂ©cĂ©dentes de FastAPI (avant 0.95.0) exigeaient 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 encore, je vais donc vous l’expliquer. +Les versions prĂ©cĂ©dentes de FastAPI (avant 0.95.0) exigeaient 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 encore, je vais donc vous l’expliquer. /// tip | Astuce @@ -191,7 +167,7 @@ Vous pouvez Ă©galement ajouter un paramĂštre `min_length` : ## Ajouter des expressions rĂ©guliĂšres { #add-regular-expressions } -Vous pouvez dĂ©finir un `pattern` d’expression rĂ©guliĂšre auquel le paramĂštre doit correspondre : +Vous pouvez dĂ©finir un `pattern` d’expression rĂ©guliĂšre auquel le paramĂštre doit correspondre : {* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *} @@ -211,7 +187,7 @@ Vous pouvez, bien sĂ»r, utiliser des valeurs par dĂ©faut autres que `None`. Disons que vous voulez dĂ©clarer le paramĂštre de requĂȘte `q` avec un `min_length` de `3`, et avec une valeur par dĂ©faut de « fixedquery » : -{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *} /// note | Remarque @@ -241,7 +217,7 @@ q: Annotated[str | None, Query(min_length=3)] = None Donc, lorsque vous avez besoin de dĂ©clarer une valeur comme requise tout en utilisant `Query`, vous pouvez simplement ne pas dĂ©clarer de valeur par dĂ©faut : -{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *} ### Requis, peut valoir `None` { #required-can-be-none } @@ -292,7 +268,7 @@ L’interface de documentation interactive de l’API sera mise Ă  jour en cons Vous pouvez Ă©galement dĂ©finir une `list` 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_an_py310.py hl[9] *} Si vous allez Ă  : @@ -315,7 +291,7 @@ la valeur par dĂ©faut de `q` sera : `["foo", "bar"]` et votre rĂ©ponse sera : Vous pouvez aussi utiliser `list` directement au lieu de `list[str]` : -{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *} /// note | Remarque @@ -371,7 +347,7 @@ Vous pouvez alors dĂ©clarer un `alias`, et cet alias sera utilisĂ© pour trouver Disons que vous n’aimez plus ce paramĂštre. -Vous devez le laisser lĂ  quelque temps car des clients l’utilisent, mais vous voulez que les documents l’affichent clairement comme dĂ©prĂ©ciĂ©. +Vous devez le laisser lĂ  quelque temps car des clients l’utilisent, mais vous voulez que les documents l’affichent clairement comme dĂ©prĂ©ciĂ©. Passez alors le paramĂštre `deprecated=True` Ă  `Query` : @@ -401,7 +377,7 @@ Pydantic a aussi
ISBN ou par `imdb-` pour un ID d’URL de film IMDB : +Par exemple, ce validateur personnalisĂ© vĂ©rifie que l’ID d’item commence par `isbn-` pour un numĂ©ro de livre ISBN ou par `imdb-` pour un ID d’URL de film IMDB : {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *} @@ -435,7 +411,7 @@ Avez-vous remarquĂ© ? Une chaĂźne utilisant `value.startswith()` peut prendre un #### Un Ă©lĂ©ment alĂ©atoire { #a-random-item } -Avec `data.items()` nous obtenons un objet itĂ©rable avec des tuples contenant la clĂ© et la valeur pour chaque Ă©lĂ©ment du dictionnaire. +Avec `data.items()` nous obtenons un objet itĂ©rable avec des tuples contenant la clĂ© et la valeur pour chaque Ă©lĂ©ment du dictionnaire. Nous convertissons cet objet itĂ©rable en une `list` propre avec `list(data.items())`. diff --git a/docs/fr/docs/tutorial/query-params.md b/docs/fr/docs/tutorial/query-params.md index 1a4880ced..01540ad17 100644 --- a/docs/fr/docs/tutorial/query-params.md +++ b/docs/fr/docs/tutorial/query-params.md @@ -2,7 +2,7 @@ Quand vous dĂ©clarez d'autres paramĂštres de fonction qui ne font pas partie des paramĂštres de chemin, ils sont automatiquement interprĂ©tĂ©s comme des paramĂštres de « query ». -{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *} +{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *} La query est l'ensemble des paires clĂ©-valeur placĂ©es aprĂšs le `?` dans une URL, sĂ©parĂ©es par des caractĂšres `&`. @@ -24,7 +24,7 @@ Mais lorsque vous les dĂ©clarez avec des types Python (dans l'exemple ci-dessus, Tous les mĂȘmes processus qui s'appliquaient aux paramĂštres de chemin s'appliquent aussi aux paramĂštres de requĂȘte : * Prise en charge de l'Ă©diteur (Ă©videmment) -* « parsing » des donnĂ©es +* « parsing » des donnĂ©es * Validation des donnĂ©es * Documentation automatique @@ -67,7 +67,7 @@ Dans ce cas, le paramĂštre de fonction `q` sera optionnel et vaudra `None` par d /// check | VĂ©rifications -Notez Ă©galement que FastAPI est suffisamment intelligent pour remarquer que le paramĂštre de chemin `item_id` est un paramĂštre de chemin et que `q` ne l'est pas, c'est donc un paramĂštre de requĂȘte. +Notez Ă©galement que **FastAPI** est suffisamment intelligent pour remarquer que le paramĂštre de chemin `item_id` est un paramĂštre de chemin et que `q` ne l'est pas, c'est donc un paramĂštre de requĂȘte. /// @@ -127,7 +127,7 @@ Si vous ne voulez pas leur donner de valeur spĂ©cifique mais simplement les rend Mais si vous voulez rendre un paramĂštre de requĂȘte obligatoire, vous pouvez simplement ne dĂ©clarer aucune valeur par dĂ©faut : -{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *} Ici, le paramĂštre de requĂȘte `needy` est un paramĂštre de requĂȘte requis de type `str`. diff --git a/docs/fr/docs/tutorial/request-files.md b/docs/fr/docs/tutorial/request-files.md new file mode 100644 index 000000000..01a0b72eb --- /dev/null +++ b/docs/fr/docs/tutorial/request-files.md @@ -0,0 +1,176 @@ +# Envoyer des fichiers { #request-files } + +Vous pouvez dĂ©finir des fichiers Ă  tĂ©lĂ©verser par le client en utilisant `File`. + +/// info + +Pour recevoir des fichiers tĂ©lĂ©versĂ©s, installez d'abord `python-multipart`. + +Assurez-vous de crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis d'installer le paquet, par exemple : + +```console +$ pip install python-multipart +``` + +C'est parce que les fichiers tĂ©lĂ©versĂ©s sont envoyĂ©s en « donnĂ©es de formulaire ». + +/// + +## Importer `File` { #import-file } + +Importez `File` et `UploadFile` depuis `fastapi` : + +{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *} + +## DĂ©finir des paramĂštres `File` { #define-file-parameters } + +CrĂ©ez des paramĂštres de fichier de la mĂȘme maniĂšre que pour `Body` ou `Form` : + +{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *} + +/// info + +`File` est une classe qui hĂ©rite directement de `Form`. + +Mais souvenez-vous que lorsque vous importez `Query`, `Path`, `File` et d'autres depuis `fastapi`, ce sont en rĂ©alitĂ© des fonctions qui renvoient des classes spĂ©ciales. + +/// + +/// tip | Astuce + +Pour dĂ©clarer des fichiers dans le corps de la requĂȘte, vous devez utiliser `File`, sinon les paramĂštres seraient interprĂ©tĂ©s comme des paramĂštres de requĂȘte ou des paramĂštres de corps (JSON). + +/// + +Les fichiers seront tĂ©lĂ©versĂ©s en « donnĂ©es de formulaire ». + +Si vous dĂ©clarez le type de votre paramĂštre de *fonction de chemin d'accĂšs* comme `bytes`, **FastAPI** lira le fichier pour vous et vous recevrez le contenu sous forme de `bytes`. + +Gardez Ă  l'esprit que cela signifie que tout le contenu sera stockĂ© en mĂ©moire. Cela fonctionnera bien pour de petits fichiers. + +Mais dans plusieurs cas, vous pourriez bĂ©nĂ©ficier de l'utilisation d'`UploadFile`. + +## ParamĂštres de fichier avec `UploadFile` { #file-parameters-with-uploadfile } + +DĂ©finissez un paramĂštre de fichier de type `UploadFile` : + +{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *} + +Utiliser `UploadFile` prĂ©sente plusieurs avantages par rapport Ă  `bytes` : + +- Vous n'avez pas besoin d'utiliser `File()` comme valeur par dĂ©faut du paramĂštre. +- Il utilise un fichier « spooled » : + - Un fichier stockĂ© en mĂ©moire jusqu'Ă  une taille maximale, puis, au-delĂ  de cette limite, stockĂ© sur le disque. +- Cela fonctionne donc bien pour des fichiers volumineux comme des images, des vidĂ©os, de gros binaires, etc., sans consommer toute la mĂ©moire. +- Vous pouvez obtenir des mĂ©tadonnĂ©es Ă  partir du fichier tĂ©lĂ©versĂ©. +- Il offre une interface `async` de type file-like. +- Il expose un vĂ©ritable objet Python `SpooledTemporaryFile` que vous pouvez passer directement Ă  d'autres bibliothĂšques qui attendent un objet « file-like ». + +### `UploadFile` { #uploadfile } + +`UploadFile` a les attributs suivants : + +- `filename` : une `str` contenant le nom de fichier original tĂ©lĂ©versĂ© (par ex. `myimage.jpg`). +- `content_type` : une `str` avec le type de contenu (type MIME / type mĂ©dia) (par ex. `image/jpeg`). +- `file` : un `SpooledTemporaryFile` (un objet de type fichier). C'est l'objet fichier Python rĂ©el que vous pouvez passer directement Ă  d'autres fonctions ou bibliothĂšques qui attendent un objet « file-like ». + +`UploadFile` a les mĂ©thodes `async` suivantes. Elles appellent toutes les mĂ©thodes correspondantes du fichier sous-jacent (en utilisant le `SpooledTemporaryFile` interne). + +- `write(data)` : Ă©crit `data` (`str` ou `bytes`) dans le fichier. +- `read(size)` : lit `size` (`int`) octets/caractĂšres du fichier. +- `seek(offset)` : se dĂ©place Ă  la position d'octet `offset` (`int`) dans le fichier. + - Par ex., `await myfile.seek(0)` irait au dĂ©but du fichier. + - C'est particuliĂšrement utile si vous exĂ©cutez `await myfile.read()` une fois puis devez relire le contenu. +- `close()` : ferme le fichier. + +Comme toutes ces mĂ©thodes sont `async`, vous devez les « await ». + +Par exemple, Ă  l'intĂ©rieur d'une *fonction de chemin d'accĂšs* `async`, vous pouvez obtenir le contenu avec : + +```Python +contents = await myfile.read() +``` + +Si vous ĂȘtes dans une *fonction de chemin d'accĂšs* `def` normale, vous pouvez accĂ©der directement Ă  `UploadFile.file`, par exemple : + +```Python +contents = myfile.file.read() +``` + +/// note | DĂ©tails techniques `async` + +Lorsque vous utilisez les mĂ©thodes `async`, **FastAPI** exĂ©cute les mĂ©thodes de fichier dans un pool de threads et les attend. + +/// + +/// note | DĂ©tails techniques Starlette + +L'`UploadFile` de **FastAPI** hĂ©rite directement de l'`UploadFile` de **Starlette**, mais ajoute certaines parties nĂ©cessaires pour le rendre compatible avec **Pydantic** et les autres parties de FastAPI. + +/// + +## Qu'est-ce que les « donnĂ©es de formulaire » { #what-is-form-data } + +La façon dont les formulaires HTML (`
`) envoient les donnĂ©es au serveur utilise normalement un encodage « spĂ©cial » pour ces donnĂ©es, diffĂ©rent de JSON. + +**FastAPI** s'assure de lire ces donnĂ©es au bon endroit plutĂŽt que depuis JSON. + +/// note | DĂ©tails techniques + +Les donnĂ©es des formulaires sont normalement encodĂ©es avec le « type de mĂ©dia » `application/x-www-form-urlencoded` lorsqu'elles n'incluent pas de fichiers. + +Mais lorsque le formulaire inclut des fichiers, il est encodĂ© en `multipart/form-data`. Si vous utilisez `File`, **FastAPI** saura qu'il doit rĂ©cupĂ©rer les fichiers depuis la partie appropriĂ©e du corps. + +Si vous souhaitez en savoir plus sur ces encodages et les champs de formulaire, consultez la MDN Web Docs pour POST. + +/// + +/// warning | Alertes + +Vous pouvez dĂ©clarer plusieurs paramĂštres `File` et `Form` dans un *chemin d'accĂšs*, mais vous ne pouvez pas Ă©galement dĂ©clarer des champs `Body` que vous vous attendez Ă  recevoir en JSON, car la requĂȘte aura le corps encodĂ© en `multipart/form-data` au lieu de `application/json`. + +Ce n'est pas une limitation de **FastAPI**, cela fait partie du protocole HTTP. + +/// + +## TĂ©lĂ©versement de fichier facultatif { #optional-file-upload } + +Vous pouvez rendre un fichier facultatif en utilisant des annotations de type standard et en dĂ©finissant une valeur par dĂ©faut Ă  `None` : + +{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *} + +## `UploadFile` avec des mĂ©tadonnĂ©es supplĂ©mentaires { #uploadfile-with-additional-metadata } + +Vous pouvez aussi utiliser `File()` avec `UploadFile`, par exemple pour dĂ©finir des mĂ©tadonnĂ©es supplĂ©mentaires : + +{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *} + +## TĂ©lĂ©verser plusieurs fichiers { #multiple-file-uploads } + +Il est possible de tĂ©lĂ©verser plusieurs fichiers en mĂȘme temps. + +Ils seraient associĂ©s au mĂȘme « champ de formulaire » envoyĂ© en « donnĂ©es de formulaire ». + +Pour cela, dĂ©clarez une `list` de `bytes` ou d'`UploadFile` : + +{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *} + +Vous recevrez, comme dĂ©clarĂ©, une `list` de `bytes` ou d'`UploadFile`. + +/// note | DĂ©tails techniques + +Vous pourriez aussi utiliser `from starlette.responses import HTMLResponse`. + +**FastAPI** fournit les mĂȘmes `starlette.responses` sous `fastapi.responses` simplement pour votre convenance en tant que dĂ©veloppeur. Mais la plupart des rĂ©ponses disponibles proviennent directement de Starlette. + +/// + +### TĂ©lĂ©versements multiples avec mĂ©tadonnĂ©es supplĂ©mentaires { #multiple-file-uploads-with-additional-metadata } + +Et de la mĂȘme maniĂšre que prĂ©cĂ©demment, vous pouvez utiliser `File()` pour dĂ©finir des paramĂštres supplĂ©mentaires, mĂȘme pour `UploadFile` : + +{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *} + +## RĂ©capitulatif { #recap } + +Utilisez `File`, `bytes` et `UploadFile` pour dĂ©clarer des fichiers Ă  tĂ©lĂ©verser dans la requĂȘte, envoyĂ©s en « donnĂ©es de formulaire ». diff --git a/docs/fr/docs/tutorial/request-form-models.md b/docs/fr/docs/tutorial/request-form-models.md new file mode 100644 index 000000000..3fbac9c74 --- /dev/null +++ b/docs/fr/docs/tutorial/request-form-models.md @@ -0,0 +1,78 @@ +# ModĂšles de formulaire { #form-models } + +Vous pouvez utiliser des **modĂšles Pydantic** pour dĂ©clarer des **champs de formulaire** dans FastAPI. + +/// info + +Pour utiliser les formulaires, installez d'abord `python-multipart`. + +Assurez-vous de crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis d'installer le paquet, par exemple : + +```console +$ pip install python-multipart +``` + +/// + +/// note | Remarque + +Ceci est pris en charge depuis la version `0.113.0` de FastAPI. đŸ€“ + +/// + +## ModĂšles Pydantic pour les formulaires { #pydantic-models-for-forms } + +Vous avez simplement besoin de dĂ©clarer un **modĂšle Pydantic** avec les champs que vous souhaitez recevoir comme **champs de formulaire**, puis de dĂ©clarer le paramĂštre comme `Form` : + +{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *} + +**FastAPI** va **extraire** les donnĂ©es pour **chaque champ** Ă  partir des **donnĂ©es de formulaire** de la requĂȘte et vous fournir le modĂšle Pydantic que vous avez dĂ©fini. + +## Consulter les documents { #check-the-docs } + +Vous pouvez le vĂ©rifier dans l'interface des documents Ă  `/docs` : + +
+ +
+ +## Interdire les champs de formulaire supplĂ©mentaires { #forbid-extra-form-fields } + +Dans certains cas d'utilisation particuliers (probablement peu courants), vous pourriez vouloir **restreindre** les champs de formulaire Ă  ceux dĂ©clarĂ©s dans le modĂšle Pydantic, et **interdire** tout champ **supplĂ©mentaire**. + +/// note | Remarque + +Ceci est pris en charge depuis la version `0.114.0` de FastAPI. đŸ€“ + +/// + +Vous pouvez utiliser la configuration du modĂšle Pydantic pour `forbid` tout champ `extra` : + +{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *} + +Si un client tente d'envoyer des donnĂ©es supplĂ©mentaires, il recevra une **rĂ©ponse d'erreur**. + +Par exemple, si le client essaie d'envoyer les champs de formulaire : + +* `username`: `Rick` +* `password`: `Portal Gun` +* `extra`: `Mr. Poopybutthole` + +Il recevra une rĂ©ponse d'erreur lui indiquant que le champ `extra` n'est pas autorisĂ© : + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["body", "extra"], + "msg": "Extra inputs are not permitted", + "input": "Mr. Poopybutthole" + } + ] +} +``` + +## RĂ©sumer { #summary } + +Vous pouvez utiliser des modĂšles Pydantic pour dĂ©clarer des champs de formulaire dans FastAPI. 😎 diff --git a/docs/fr/docs/tutorial/request-forms-and-files.md b/docs/fr/docs/tutorial/request-forms-and-files.md new file mode 100644 index 000000000..6774eec8e --- /dev/null +++ b/docs/fr/docs/tutorial/request-forms-and-files.md @@ -0,0 +1,41 @@ +# Utiliser des formulaires et des fichiers de requĂȘte { #request-forms-and-files } + +Vous pouvez dĂ©finir des fichiers et des champs de formulaire en mĂȘme temps Ă  l'aide de `File` et `Form`. + +/// info + +Pour recevoir des fichiers tĂ©lĂ©versĂ©s et/ou des donnĂ©es de formulaire, installez d'abord `python-multipart`. + +Vous devez crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l'activer, puis installer ce paquet, par exemple : + +```console +$ pip install python-multipart +``` + +/// + +## Importer `File` et `Form` { #import-file-and-form } + +{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *} + +## DĂ©finir des paramĂštres `File` et `Form` { #define-file-and-form-parameters } + +CrĂ©ez des paramĂštres de fichier et de formulaire de la mĂȘme maniĂšre que pour `Body` ou `Query` : + +{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *} + +Les fichiers et les champs de formulaire seront tĂ©lĂ©versĂ©s en tant que donnĂ©es de formulaire et vous les recevrez. + +Et vous pouvez dĂ©clarer certains fichiers comme `bytes` et d'autres comme `UploadFile`. + +/// warning | Alertes + +Vous pouvez dĂ©clarer plusieurs paramĂštres `File` et `Form` dans un *chemin d'accĂšs*, mais vous ne pouvez pas aussi dĂ©clarer des champs `Body` que vous vous attendez Ă  recevoir en JSON, car la requĂȘte aura le corps encodĂ© en `multipart/form-data` au lieu de `application/json`. + +Ce n'est pas une limitation de **FastAPI**, cela fait partie du protocole HTTP. + +/// + +## RĂ©capitulatif { #recap } + +Utilisez `File` et `Form` ensemble lorsque vous devez recevoir des donnĂ©es et des fichiers dans la mĂȘme requĂȘte. diff --git a/docs/fr/docs/tutorial/request-forms.md b/docs/fr/docs/tutorial/request-forms.md new file mode 100644 index 000000000..cea47c93e --- /dev/null +++ b/docs/fr/docs/tutorial/request-forms.md @@ -0,0 +1,73 @@ +# DonnĂ©es de formulaire { #form-data } + +Lorsque vous devez recevoir des champs de formulaire au lieu de JSON, vous pouvez utiliser `Form`. + +/// info + +Pour utiliser les formulaires, installez d'abord `python-multipart`. + +Assurez-vous de crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis d'installer ce paquet, par exemple : + +```console +$ pip install python-multipart +``` + +/// + +## Importer `Form` { #import-form } + +Importez `Form` depuis `fastapi` : + +{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *} + +## DĂ©finir les paramĂštres `Form` { #define-form-parameters } + +CrĂ©ez des paramĂštres de formulaire comme vous le feriez pour `Body` ou `Query` : + +{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *} + +Par exemple, dans l'une des maniĂšres dont la spĂ©cification OAuth2 peut ĂȘtre utilisĂ©e (appelĂ©e « password flow »), il est requis d'envoyer un `username` et un `password` comme champs de formulaire. + +La spĂ©cification exige que les champs soient exactement nommĂ©s `username` et `password`, et qu'ils soient envoyĂ©s en tant que champs de formulaire, pas en JSON. + +Avec `Form`, vous pouvez dĂ©clarer les mĂȘmes configurations que pour `Body` (ainsi que `Query`, `Path`, `Cookie`), y compris la validation, des exemples, un alias (p. ex. `user-name` au lieu de `username`), etc. + +/// info + +`Form` est une classe qui hĂ©rite directement de `Body`. + +/// + +/// tip | Astuce + +Pour dĂ©clarer des corps de formulaire, vous devez utiliser `Form` explicitement, car sinon les paramĂštres seraient interprĂ©tĂ©s comme des paramĂštres de requĂȘte ou des paramĂštres de corps (JSON). + +/// + +## À propos des « champs de formulaire » { #about-form-fields } + +La maniĂšre dont les formulaires HTML (`
`) envoient les donnĂ©es au serveur utilise normalement un encodage « spĂ©cial » pour ces donnĂ©es, diffĂ©rent de JSON. + +**FastAPI** s'assure de lire ces donnĂ©es au bon endroit au lieu de JSON. + +/// note | DĂ©tails techniques + +Les donnĂ©es issues des formulaires sont normalement encodĂ©es avec le « type de mĂ©dia » `application/x-www-form-urlencoded`. + +Mais lorsque le formulaire inclut des fichiers, il est encodĂ© en `multipart/form-data`. Vous lirez la gestion des fichiers dans le chapitre suivant. + +Si vous voulez en savoir plus sur ces encodages et les champs de formulaire, consultez la MDN web docs pour POST. + +/// + +/// warning | Alertes + +Vous pouvez dĂ©clarer plusieurs paramĂštres `Form` dans un chemin d'accĂšs, mais vous ne pouvez pas aussi dĂ©clarer des champs `Body` que vous vous attendez Ă  recevoir en JSON, car la requĂȘte aura le corps encodĂ© en `application/x-www-form-urlencoded` au lieu de `application/json`. + +Ce n'est pas une limitation de **FastAPI**, cela fait partie du protocole HTTP. + +/// + +## RĂ©capitulatif { #recap } + +Utilisez `Form` pour dĂ©clarer les paramĂštres d'entrĂ©e des donnĂ©es de formulaire. diff --git a/docs/fr/docs/tutorial/response-model.md b/docs/fr/docs/tutorial/response-model.md new file mode 100644 index 000000000..337b1aa48 --- /dev/null +++ b/docs/fr/docs/tutorial/response-model.md @@ -0,0 +1,343 @@ +# ModĂšle de rĂ©ponse - Type de retour { #response-model-return-type } + +Vous pouvez dĂ©clarer le type utilisĂ© pour la rĂ©ponse en annotant le **type de retour** de la *fonction de chemin d'accĂšs*. + +Vous pouvez utiliser des **annotations de type** de la mĂȘme maniĂšre que pour les donnĂ©es d'entrĂ©e dans les **paramĂštres** de fonction. Vous pouvez utiliser des modĂšles Pydantic, des listes, des dictionnaires, des valeurs scalaires comme des entiers, des boolĂ©ens, etc. + +{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *} + +FastAPI utilisera ce type de retour pour : + +* **Valider** les donnĂ©es renvoyĂ©es. + * Si les donnĂ©es sont invalides (par exemple, il manque un champ), cela signifie que le code de *votre* application est dĂ©fectueux, qu'il ne renvoie pas ce qu'il devrait, et un erreur serveur sera renvoyĂ©e au lieu de renvoyer des donnĂ©es incorrectes. De cette façon, vous et vos clients pouvez ĂȘtre certains de recevoir les donnĂ©es attendues et avec la structure attendue. +* Ajouter un **JSON Schema** pour la rĂ©ponse, dans l’OpenAPI du *chemin d'accĂšs*. + * Ceci sera utilisĂ© par la **documentation automatique**. + * Ceci sera Ă©galement utilisĂ© par les outils de gĂ©nĂ©ration automatique de code client. + +Mais surtout : + +* Il **limitera et filtrera** les donnĂ©es de sortie Ă  ce qui est dĂ©fini dans le type de retour. + * C'est particuliĂšrement important pour la **sĂ©curitĂ©**, nous verrons cela plus bas. + +## ParamĂštre `response_model` { #response-model-parameter } + +Il existe des cas oĂč vous devez ou souhaitez renvoyer des donnĂ©es qui ne correspondent pas exactement Ă  ce que dĂ©clare le type. + +Par exemple, vous pourriez vouloir **renvoyer un dictionnaire** ou un objet de base de donnĂ©es, mais **le dĂ©clarer comme un modĂšle Pydantic**. Ainsi, le modĂšle Pydantic ferait toute la documentation des donnĂ©es, la validation, etc. pour l'objet que vous avez renvoyĂ© (par exemple un dictionnaire ou un objet de base de donnĂ©es). + +Si vous ajoutez l'annotation du type de retour, les outils et Ă©diteurs se plaindront avec une (juste) erreur vous indiquant que votre fonction renvoie un type (par exemple un dict) diffĂ©rent de ce que vous avez dĂ©clarĂ© (par exemple un modĂšle Pydantic). + +Dans ces cas, vous pouvez utiliser le paramĂštre `response_model` du *dĂ©corateur de chemin d'accĂšs* au lieu du type de retour. + +Vous pouvez utiliser le paramĂštre `response_model` dans n'importe lequel des *chemins d'accĂšs* : + +* `@app.get()` +* `@app.post()` +* `@app.put()` +* `@app.delete()` +* etc. + +{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *} + +/// note | Remarque + +Notez que `response_model` est un paramĂštre de la mĂ©thode « decorator » (`get`, `post`, etc.). Pas de votre *fonction de chemin d'accĂšs*, comme tous les paramĂštres et le corps. + +/// + +`response_model` reçoit le mĂȘme type que vous dĂ©clareriez pour un champ de modĂšle Pydantic, il peut donc s'agir d'un modĂšle Pydantic, mais il peut aussi ĂȘtre, par exemple, une `list` de modĂšles Pydantic, comme `List[Item]`. + +FastAPI utilisera ce `response_model` pour toute la documentation des donnĂ©es, la validation, etc. et aussi pour **convertir et filtrer les donnĂ©es de sortie** selon sa dĂ©claration de type. + +/// tip | Astuce + +Si vous avez des vĂ©rifications de type strictes dans votre Ă©diteur, mypy, etc., vous pouvez dĂ©clarer le type de retour de la fonction en `Any`. + +Ainsi, vous indiquez Ă  l'Ă©diteur que vous renvoyez intentionnellement n'importe quoi. Mais FastAPI effectuera quand mĂȘme la documentation, la validation, le filtrage, etc. des donnĂ©es avec `response_model`. + +/// + +### PrioritĂ© de `response_model` { #response-model-priority } + +Si vous dĂ©clarez Ă  la fois un type de retour et un `response_model`, c'est `response_model` qui aura la prioritĂ© et sera utilisĂ© par FastAPI. + +De cette maniĂšre, vous pouvez ajouter des annotations de type correctes Ă  vos fonctions mĂȘme si vous renvoyez un type diffĂ©rent du modĂšle de rĂ©ponse, pour qu'il soit utilisĂ© par l'Ă©diteur et des outils comme mypy. Et vous pouvez toujours laisser FastAPI faire la validation des donnĂ©es, la documentation, etc. avec `response_model`. + +Vous pouvez Ă©galement utiliser `response_model=None` pour dĂ©sactiver la crĂ©ation d’un modĂšle de rĂ©ponse pour ce *chemin d'accĂšs* ; vous pourriez en avoir besoin si vous ajoutez des annotations de type pour des choses qui ne sont pas des champs valides Pydantic, vous verrez un exemple de cela dans une des sections ci-dessous. + +## Renvoyer les mĂȘmes donnĂ©es d'entrĂ©e { #return-the-same-input-data } + +Ici, nous dĂ©clarons un modĂšle `UserIn`, il contiendra un mot de passe en clair : + +{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *} + +/// info | Info + +Pour utiliser `EmailStr`, installez d'abord `email-validator`. + +Assurez-vous de crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis de l'installer, par exemple : + +```console +$ pip install email-validator +``` + +ou avec : + +```console +$ pip install "pydantic[email]" +``` + +/// + +Et nous utilisons ce modĂšle pour dĂ©clarer notre entrĂ©e et le mĂȘme modĂšle pour dĂ©clarer notre sortie : + +{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *} + +DĂ©sormais, chaque fois qu'un navigateur crĂ©e un utilisateur avec un mot de passe, l'API renverra le mĂȘme mot de passe dans la rĂ©ponse. + +Dans ce cas, cela peut ne pas poser de problĂšme, car c'est le mĂȘme utilisateur qui envoie le mot de passe. + +Mais si nous utilisons le mĂȘme modĂšle pour un autre *chemin d'accĂšs*, nous pourrions envoyer les mots de passe de nos utilisateurs Ă  tous les clients. + +/// danger | Danger + +Ne stockez jamais le mot de passe en clair d'un utilisateur et ne l'envoyez pas dans une rĂ©ponse de cette maniĂšre, Ă  moins de connaĂźtre tous les Ă©cueils et de savoir exactement ce que vous faites. + +/// + +## Ajouter un modĂšle de sortie { #add-an-output-model } + +Nous pouvons Ă  la place crĂ©er un modĂšle d'entrĂ©e avec le mot de passe en clair et un modĂšle de sortie sans celui-ci : + +{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *} + +Ici, mĂȘme si notre *fonction de chemin d'accĂšs* renvoie le mĂȘme utilisateur d'entrĂ©e qui contient le mot de passe : + +{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *} + +... nous avons dĂ©clarĂ© `response_model` comme Ă©tant notre modĂšle `UserOut`, qui n'inclut pas le mot de passe : + +{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *} + +Ainsi, **FastAPI** se chargera de filtrer toutes les donnĂ©es qui ne sont pas dĂ©clarĂ©es dans le modĂšle de sortie (en utilisant Pydantic). + +### `response_model` ou type de retour { #response-model-or-return-type } + +Dans ce cas, comme les deux modĂšles sont diffĂ©rents, si nous annotions le type de retour de la fonction en `UserOut`, l’éditeur et les outils se plaindraient que nous renvoyons un type invalide, car ce sont des classes diffĂ©rentes. + +C'est pourquoi, dans cet exemple, nous devons le dĂ©clarer dans le paramĂštre `response_model`. + +... mais continuez Ă  lire ci-dessous pour voir comment contourner cela. + +## Type de retour et filtrage des donnĂ©es { #return-type-and-data-filtering } + +Continuons l'exemple prĂ©cĂ©dent. Nous voulions **annoter la fonction avec un type**, mais nous voulions pouvoir renvoyer depuis la fonction quelque chose qui inclut **plus de donnĂ©es**. + +Nous voulons que FastAPI continue de **filtrer** les donnĂ©es Ă  l’aide du modĂšle de rĂ©ponse. Ainsi, mĂȘme si la fonction renvoie plus de donnĂ©es, la rĂ©ponse n’inclura que les champs dĂ©clarĂ©s dans le modĂšle de rĂ©ponse. + +Dans l'exemple prĂ©cĂ©dent, comme les classes Ă©taient diffĂ©rentes, nous avons dĂ» utiliser le paramĂštre `response_model`. Mais cela signifie aussi que nous ne bĂ©nĂ©ficions pas de la prise en charge de l'Ă©diteur et des outils pour la vĂ©rification du type de retour de la fonction. + +Mais dans la plupart des cas oĂč nous avons besoin de quelque chose comme cela, nous voulons que le modĂšle **filtre/supprime** simplement une partie des donnĂ©es comme dans cet exemple. + +Et dans ces cas, nous pouvons utiliser des classes et l'hĂ©ritage pour tirer parti des **annotations de type** de fonction afin d'obtenir une meilleure prise en charge dans l'Ă©diteur et les outils, tout en bĂ©nĂ©ficiant du **filtrage de donnĂ©es** de FastAPI. + +{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *} + +Avec cela, nous obtenons la prise en charge des outils, des Ă©diteurs et de mypy car ce code est correct en termes de types, et nous bĂ©nĂ©ficions Ă©galement du filtrage des donnĂ©es par FastAPI. + +Comment cela fonctionne-t-il ? Voyons cela. đŸ€“ + +### Annotations de type et outils { #type-annotations-and-tooling } + +Voyons d'abord comment les Ă©diteurs, mypy et autres outils considĂšreraient cela. + +`BaseUser` a les champs de base. Puis `UserIn` hĂ©rite de `BaseUser` et ajoute le champ `password`, il inclura donc tous les champs des deux modĂšles. + +Nous annotons le type de retour de la fonction en `BaseUser`, mais nous renvoyons en rĂ©alitĂ© une instance de `UserIn`. + +L’éditeur, mypy et d'autres outils ne s’en plaindront pas car, en termes de typage, `UserIn` est une sous-classe de `BaseUser`, ce qui signifie que c’est un type *valide* lorsque ce qui est attendu est n'importe quoi de type `BaseUser`. + +### Filtrage des donnĂ©es par FastAPI { #fastapi-data-filtering } + +Maintenant, pour FastAPI, il verra le type de retour et s'assurera que ce que vous renvoyez inclut **uniquement** les champs qui sont dĂ©clarĂ©s dans le type. + +FastAPI fait plusieurs choses en interne avec Pydantic pour s'assurer que ces mĂȘmes rĂšgles d'hĂ©ritage de classes ne sont pas utilisĂ©es pour le filtrage des donnĂ©es renvoyĂ©es, sinon vous pourriez finir par renvoyer beaucoup plus de donnĂ©es que prĂ©vu. + +De cette façon, vous obtenez le meilleur des deux mondes : annotations de type avec **prise en charge par les outils** et **filtrage des donnĂ©es**. + +## Le voir dans la documentation { #see-it-in-the-docs } + +Dans la documentation automatique, vous pouvez vĂ©rifier que le modĂšle d'entrĂ©e et le modĂšle de sortie auront chacun leur propre JSON Schema : + + + +Et les deux modĂšles seront utilisĂ©s pour la documentation API interactive : + + + +## Autres annotations de type de retour { #other-return-type-annotations } + +Il peut y avoir des cas oĂč vous renvoyez quelque chose qui n'est pas un champ Pydantic valide et vous l'annotez dans la fonction, uniquement pour obtenir la prise en charge fournie par les outils (l’éditeur, mypy, etc.). + +### Renvoyer directement une Response { #return-a-response-directly } + +Le cas le plus courant serait [de renvoyer directement une Response comme expliquĂ© plus loin dans la documentation avancĂ©e](../advanced/response-directly.md){.internal-link target=_blank}. + +{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *} + +Ce cas simple est gĂ©rĂ© automatiquement par FastAPI car l'annotation du type de retour est la classe (ou une sous-classe de) `Response`. + +Et les outils seront Ă©galement satisfaits car `RedirectResponse` et `JSONResponse` sont des sous-classes de `Response`, donc l'annotation de type est correcte. + +### Annoter une sous-classe de Response { #annotate-a-response-subclass } + +Vous pouvez aussi utiliser une sous-classe de `Response` dans l'annotation de type : + +{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *} + +Cela fonctionnera Ă©galement car `RedirectResponse` est une sous-classe de `Response`, et FastAPI gĂ©rera automatiquement ce cas simple. + +### Annotations de type de retour invalides { #invalid-return-type-annotations } + +Mais lorsque vous renvoyez un autre objet arbitraire qui n'est pas un type Pydantic valide (par exemple un objet de base de donnĂ©es) et que vous l'annotez ainsi dans la fonction, FastAPI essaiera de crĂ©er un modĂšle de rĂ©ponse Pydantic Ă  partir de cette annotation de type, et Ă©chouera. + +Il en serait de mĂȘme si vous aviez quelque chose comme une union entre diffĂ©rents types dont un ou plusieurs ne sont pas des types Pydantic valides, par exemple ceci Ă©chouerait đŸ’„ : + +{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *} + +... cela Ă©choue parce que l'annotation de type n'est pas un type Pydantic et n'est pas juste une unique classe `Response` ou une sous-classe, c'est une union (l'un des deux) entre une `Response` et un `dict`. + +### DĂ©sactiver le modĂšle de rĂ©ponse { #disable-response-model } + +En reprenant l'exemple ci-dessus, vous pourriez ne pas vouloir avoir la validation par dĂ©faut des donnĂ©es, la documentation, le filtrage, etc. effectuĂ©s par FastAPI. + +Mais vous pourriez vouloir tout de mĂȘme conserver l’annotation du type de retour dans la fonction pour bĂ©nĂ©ficier de la prise en charge des outils comme les Ă©diteurs et les vĂ©rificateurs de type (par exemple mypy). + +Dans ce cas, vous pouvez dĂ©sactiver la gĂ©nĂ©ration du modĂšle de rĂ©ponse en dĂ©finissant `response_model=None` : + +{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *} + +Cela fera en sorte que FastAPI ignore la gĂ©nĂ©ration du modĂšle de rĂ©ponse et vous permettra ainsi d’avoir toutes les annotations de type de retour dont vous avez besoin sans que cela n’affecte votre application FastAPI. đŸ€“ + +## ParamĂštres d'encodage du modĂšle de rĂ©ponse { #response-model-encoding-parameters } + +Votre modĂšle de rĂ©ponse peut avoir des valeurs par dĂ©faut, par exemple : + +{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *} + +* `description: Union[str, None] = None` (ou `str | None = None` en Python 3.10) a une valeur par dĂ©faut `None`. +* `tax: float = 10.5` a une valeur par dĂ©faut `10.5`. +* `tags: List[str] = []` a une valeur par dĂ©faut de liste vide : `[]`. + +mais vous pourriez vouloir les omettre du rĂ©sultat si elles n'ont pas Ă©tĂ© rĂ©ellement stockĂ©es. + +Par exemple, si vous avez des modĂšles avec de nombreux attributs optionnels dans une base NoSQL, mais que vous ne voulez pas envoyer de trĂšs longues rĂ©ponses JSON remplies de valeurs par dĂ©faut. + +### Utiliser le paramĂštre `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter } + +Vous pouvez dĂ©finir le paramĂštre du *dĂ©corateur de chemin d'accĂšs* `response_model_exclude_unset=True` : + +{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *} + +et ces valeurs par dĂ©faut ne seront pas incluses dans la rĂ©ponse, uniquement les valeurs effectivement dĂ©finies. + +Ainsi, si vous envoyez une requĂȘte Ă  ce *chemin d'accĂšs* pour l'article avec l'ID `foo`, la rĂ©ponse (sans les valeurs par dĂ©faut) sera : + +```JSON +{ + "name": "Foo", + "price": 50.2 +} +``` + +/// info | Info + +Vous pouvez Ă©galement utiliser : + +* `response_model_exclude_defaults=True` +* `response_model_exclude_none=True` + +comme dĂ©crit dans la documentation Pydantic pour `exclude_defaults` et `exclude_none`. + +/// + +#### DonnĂ©es avec des valeurs pour des champs avec des valeurs par dĂ©faut { #data-with-values-for-fields-with-defaults } + +Mais si vos donnĂ©es ont des valeurs pour les champs du modĂšle avec des valeurs par dĂ©faut, comme l'article avec l'ID `bar` : + +```Python hl_lines="3 5" +{ + "name": "Bar", + "description": "The bartenders", + "price": 62, + "tax": 20.2 +} +``` + +elles seront incluses dans la rĂ©ponse. + +#### DonnĂ©es avec les mĂȘmes valeurs que les valeurs par dĂ©faut { #data-with-the-same-values-as-the-defaults } + +Si les donnĂ©es ont les mĂȘmes valeurs que les valeurs par dĂ©faut, comme l'article avec l'ID `baz` : + +```Python hl_lines="3 5-6" +{ + "name": "Baz", + "description": None, + "price": 50.2, + "tax": 10.5, + "tags": [] +} +``` + +FastAPI est suffisamment intelligent (en fait, Pydantic l’est) pour comprendre que, mĂȘme si `description`, `tax` et `tags` ont les mĂȘmes valeurs que les valeurs par dĂ©faut, elles ont Ă©tĂ© dĂ©finies explicitement (au lieu d'ĂȘtre prises depuis les valeurs par dĂ©faut). + +Elles seront donc incluses dans la rĂ©ponse JSON. + +/// tip | Astuce + +Notez que les valeurs par dĂ©faut peuvent ĂȘtre n'importe quoi, pas seulement `None`. + +Elles peuvent ĂȘtre une liste (`[]`), un `float` de `10.5`, etc. + +/// + +### `response_model_include` et `response_model_exclude` { #response-model-include-and-response-model-exclude } + +Vous pouvez Ă©galement utiliser les paramĂštres du *dĂ©corateur de chemin d'accĂšs* `response_model_include` et `response_model_exclude`. + +Ils prennent un `set` de `str` avec les noms des attributs Ă  inclure (en omettant le reste) ou Ă  exclure (en incluant le reste). + +Cela peut ĂȘtre utilisĂ© comme un raccourci rapide si vous n'avez qu'un seul modĂšle Pydantic et que vous souhaitez supprimer certaines donnĂ©es de la sortie. + +/// tip | Astuce + +Mais il est toujours recommandĂ© d'utiliser les idĂ©es ci-dessus, en utilisant plusieurs classes, plutĂŽt que ces paramĂštres. + +En effet, le JSON Schema gĂ©nĂ©rĂ© dans l’OpenAPI de votre application (et la documentation) restera celui du modĂšle complet, mĂȘme si vous utilisez `response_model_include` ou `response_model_exclude` pour omettre certains attributs. + +Cela s'applique Ă©galement Ă  `response_model_by_alias` qui fonctionne de maniĂšre similaire. + +/// + +{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *} + +/// tip | Astuce + +La syntaxe `{"name", "description"}` crĂ©e un `set` avec ces deux valeurs. + +Elle est Ă©quivalente Ă  `set(["name", "description"])`. + +/// + +#### Utiliser des `list` au lieu de `set` { #using-lists-instead-of-sets } + +Si vous oubliez d'utiliser un `set` et utilisez une `list` ou un `tuple` Ă  la place, FastAPI le convertira quand mĂȘme en `set` et cela fonctionnera correctement : + +{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *} + +## RĂ©capitulatif { #recap } + +Utilisez le paramĂštre du *dĂ©corateur de chemin d'accĂšs* `response_model` pour dĂ©finir les modĂšles de rĂ©ponse et surtout pour garantir que les donnĂ©es privĂ©es sont filtrĂ©es. + +Utilisez `response_model_exclude_unset` pour ne renvoyer que les valeurs dĂ©finies explicitement. diff --git a/docs/fr/docs/tutorial/response-status-code.md b/docs/fr/docs/tutorial/response-status-code.md new file mode 100644 index 000000000..388a53b3d --- /dev/null +++ b/docs/fr/docs/tutorial/response-status-code.md @@ -0,0 +1,101 @@ +# Code d'Ă©tat de la rĂ©ponse { #response-status-code } + +De la mĂȘme maniĂšre que vous pouvez spĂ©cifier un modĂšle de rĂ©ponse, vous pouvez Ă©galement dĂ©clarer le code d'Ă©tat HTTP utilisĂ© pour la rĂ©ponse avec le paramĂštre `status_code` dans n'importe lequel des chemins d'accĂšs : + +* `@app.get()` +* `@app.post()` +* `@app.put()` +* `@app.delete()` +* etc. + +{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *} + +/// note | Remarque + +Remarquez que `status_code` est un paramĂštre de la mĂ©thode « decorator » (`get`, `post`, etc.). Pas de votre fonction de chemin d'accĂšs, comme tous les paramĂštres et le corps. + +/// + +Le paramĂštre `status_code` reçoit un nombre correspondant au code d'Ă©tat HTTP. + +/// info + +`status_code` peut aussi recevoir un `IntEnum`, comme le `http.HTTPStatus` de Python. + +/// + +Il va : + +* Renvoyer ce code d'Ă©tat dans la rĂ©ponse. +* Le documenter comme tel dans le schĂ©ma OpenAPI (et donc dans les interfaces utilisateur) : + + + +/// note | Remarque + +Certains codes de rĂ©ponse (voir la section suivante) indiquent que la rĂ©ponse n'a pas de corps. + +FastAPI le sait et produira une documentation OpenAPI indiquant qu'il n'y a pas de corps de rĂ©ponse. + +/// + +## À propos des codes d'Ă©tat HTTP { #about-http-status-codes } + +/// note | Remarque + +Si vous savez dĂ©jĂ  ce que sont les codes d'Ă©tat HTTP, passez Ă  la section suivante. + +/// + +En HTTP, vous envoyez un code d'Ă©tat numĂ©rique de 3 chiffres dans la rĂ©ponse. + +Ces codes d'Ă©tat ont un nom associĂ© pour les reconnaĂźtre, mais la partie importante est le nombre. + +En bref : + +* `100 - 199` sont pour « Information ». Vous les utilisez rarement directement. Les rĂ©ponses avec ces codes d'Ă©tat ne peuvent pas avoir de corps. +* **`200 - 299`** sont pour les rĂ©ponses de « SuccĂšs ». Ce sont celles que vous utiliserez le plus. + * `200` est le code d'Ă©tat par dĂ©faut, ce qui signifie que tout Ă©tait « OK ». + * Un autre exemple est `201`, « Créé ». Il est couramment utilisĂ© aprĂšs la crĂ©ation d'un nouvel enregistrement dans la base de donnĂ©es. + * Un cas particulier est `204`, « Aucun contenu ». Cette rĂ©ponse est utilisĂ©e lorsqu'il n'y a aucun contenu Ă  renvoyer au client ; la rĂ©ponse ne doit donc pas avoir de corps. +* **`300 - 399`** sont pour la « Redirection ». Les rĂ©ponses avec ces codes d'Ă©tat peuvent avoir ou non un corps, sauf `304`, « Non modifiĂ© », qui ne doit pas en avoir. +* **`400 - 499`** sont pour les rĂ©ponses d'« Erreur cĂŽtĂ© client ». C'est probablement le deuxiĂšme type que vous utiliserez le plus. + * Un exemple est `404`, pour une rĂ©ponse « Non trouvĂ© ». + * Pour des erreurs gĂ©nĂ©riques du client, vous pouvez simplement utiliser `400`. +* `500 - 599` sont pour les erreurs cĂŽtĂ© serveur. Vous ne les utilisez presque jamais directement. Lorsqu'un problĂšme survient quelque part dans le code de votre application ou sur le serveur, il renverra automatiquement l'un de ces codes d'Ă©tat. + +/// tip | Astuce + +Pour en savoir plus sur chaque code d'Ă©tat et Ă  quoi il correspond, consultez la MDN documentation about HTTP status codes. + +/// + +## Raccourci pour se souvenir des noms { #shortcut-to-remember-the-names } + +Reprenons l'exemple prĂ©cĂ©dent : + +{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *} + +`201` est le code d'Ă©tat pour « Créé ». + +Mais vous n'avez pas Ă  mĂ©moriser la signification de chacun de ces codes. + +Vous pouvez utiliser les variables pratiques de `fastapi.status`. + +{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *} + +Elles ne sont qu'une commoditĂ©, elles contiennent le mĂȘme nombre, mais de cette façon vous pouvez utiliser l'autocomplĂ©tion de l'Ă©diteur pour les trouver : + + + +/// note | DĂ©tails techniques + +Vous pourriez aussi utiliser `from starlette import status`. + +FastAPI fournit le mĂȘme `starlette.status` que `fastapi.status`, uniquement pour votre commoditĂ© de dĂ©veloppeur. Mais cela vient directement de Starlette. + +/// + +## Modifier la valeur par dĂ©faut { #changing-the-default } + +Plus tard, dans le [Guide utilisateur avancĂ©](../advanced/response-change-status-code.md){.internal-link target=_blank}, vous verrez comment renvoyer un code d'Ă©tat diffĂ©rent de celui par dĂ©faut que vous dĂ©clarez ici. diff --git a/docs/fr/docs/tutorial/schema-extra-example.md b/docs/fr/docs/tutorial/schema-extra-example.md new file mode 100644 index 000000000..d4403c779 --- /dev/null +++ b/docs/fr/docs/tutorial/schema-extra-example.md @@ -0,0 +1,202 @@ +# DĂ©clarer des exemples de donnĂ©es de requĂȘte { #declare-request-example-data } + +Vous pouvez dĂ©clarer des exemples des donnĂ©es que votre application peut recevoir. + +Voici plusieurs façons de le faire. + +## Ajouter des donnĂ©es JSON Schema supplĂ©mentaires dans les modĂšles Pydantic { #extra-json-schema-data-in-pydantic-models } + +Vous pouvez dĂ©clarer `examples` pour un modĂšle Pydantic qui seront ajoutĂ©s au JSON Schema gĂ©nĂ©rĂ©. + +{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *} + +Ces informations supplĂ©mentaires seront ajoutĂ©es telles quelles au **JSON Schema** de sortie pour ce modĂšle, et elles seront utilisĂ©es dans la documentation de l'API. + +Vous pouvez utiliser l'attribut `model_config` qui accepte un `dict` comme dĂ©crit dans Documentation de Pydantic : Configuration. + +Vous pouvez dĂ©finir `"json_schema_extra"` avec un `dict` contenant toutes les donnĂ©es supplĂ©mentaires que vous souhaitez voir apparaĂźtre dans le JSON Schema gĂ©nĂ©rĂ©, y compris `examples`. + +/// tip | Astuce + +Vous pouvez utiliser la mĂȘme technique pour Ă©tendre le JSON Schema et ajouter vos propres informations supplĂ©mentaires personnalisĂ©es. + +Par exemple, vous pourriez l'utiliser pour ajouter des mĂ©tadonnĂ©es pour une interface utilisateur frontend, etc. + +/// + +/// info + +OpenAPI 3.1.0 (utilisĂ© depuis FastAPI 0.99.0) a ajoutĂ© la prise en charge de `examples`, qui fait partie du standard **JSON Schema**. + +Avant cela, seule la clĂ© `example` avec un exemple unique Ă©tait prise en charge. Elle l'est toujours par OpenAPI 3.1.0, mais elle est dĂ©prĂ©ciĂ©e et ne fait pas partie du standard JSON Schema. Vous ĂȘtes donc encouragĂ© Ă  migrer de `example` vers `examples`. đŸ€“ + +Vous pouvez en lire davantage Ă  la fin de cette page. + +/// + +## Arguments supplĂ©mentaires de `Field` { #field-additional-arguments } + +Lorsque vous utilisez `Field()` avec des modĂšles Pydantic, vous pouvez Ă©galement dĂ©clarer des `examples` supplĂ©mentaires : + +{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *} + +## `examples` dans JSON Schema - OpenAPI { #examples-in-json-schema-openapi } + +En utilisant l'un des Ă©lĂ©ments suivants : + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +vous pouvez Ă©galement dĂ©clarer un groupe de `examples` avec des informations supplĂ©mentaires qui seront ajoutĂ©es Ă  leurs **JSON Schemas** Ă  l'intĂ©rieur d'**OpenAPI**. + +### `Body` avec `examples` { #body-with-examples } + +Ici, nous passons `examples` contenant un exemple des donnĂ©es attendues dans `Body()` : + +{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *} + +### Exemple dans l'interface des documents { #example-in-the-docs-ui } + +Avec l'une des mĂ©thodes ci-dessus, cela ressemblerait Ă  ceci dans le `/docs` : + + + +### `Body` avec plusieurs `examples` { #body-with-multiple-examples } + +Vous pouvez bien sĂ»r aussi passer plusieurs `examples` : + +{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *} + +Lorsque vous faites cela, les exemples feront partie du **JSON Schema** interne pour ces donnĂ©es de corps. + +NĂ©anmoins, au moment de la rĂ©daction, Swagger UI, l'outil chargĂ© d'afficher l'interface des documents, ne prend pas en charge l'affichage de plusieurs exemples pour les donnĂ©es dans **JSON Schema**. Mais lisez ci-dessous pour un contournement. + +### `examples` spĂ©cifiques Ă  OpenAPI { #openapi-specific-examples } + +Avant que **JSON Schema** ne prenne en charge `examples`, OpenAPI prenait dĂ©jĂ  en charge un autre champ Ă©galement appelĂ© `examples`. + +Ce `examples` **spĂ©cifique Ă  OpenAPI** se trouve dans une autre section de la spĂ©cification OpenAPI. Il se trouve dans les **dĂ©tails de chaque *chemin d'accĂšs***, et non Ă  l'intĂ©rieur de chaque JSON Schema. + +Et Swagger UI prend en charge ce champ particulier `examples` depuis un certain temps. Vous pouvez donc l'utiliser pour **afficher** diffĂ©rents **exemples dans l'interface des documents**. + +La forme de ce champ `examples` spĂ©cifique Ă  OpenAPI est un `dict` avec **plusieurs exemples** (au lieu d'une `list`), chacun avec des informations supplĂ©mentaires qui seront Ă©galement ajoutĂ©es Ă  **OpenAPI**. + +Cela ne va pas Ă  l'intĂ©rieur de chaque JSON Schema contenu dans OpenAPI, cela se place Ă  l'extĂ©rieur, directement dans le *chemin d'accĂšs*. + +### Utiliser le paramĂštre `openapi_examples` { #using-the-openapi-examples-parameter } + +Vous pouvez dĂ©clarer le `examples` spĂ©cifique Ă  OpenAPI dans FastAPI avec le paramĂštre `openapi_examples` pour : + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +Les clĂ©s du `dict` identifient chaque exemple, et chaque valeur est un autre `dict`. + +Chaque `dict` d'exemple spĂ©cifique dans `examples` peut contenir : + +* `summary` : une courte description de l'exemple. +* `description` : une description longue qui peut contenir du texte Markdown. +* `value` : c'est l'exemple rĂ©el affichĂ©, par ex. un `dict`. +* `externalValue` : alternative Ă  `value`, une URL pointant vers l'exemple. Cependant, cela pourrait ne pas ĂȘtre pris en charge par autant d'outils que `value`. + +Vous pouvez l'utiliser ainsi : + +{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *} + +### Exemples OpenAPI dans l'interface des documents { #openapi-examples-in-the-docs-ui } + +Avec `openapi_examples` ajoutĂ© Ă  `Body()`, le `/docs` ressemblerait Ă  : + + + +## DĂ©tails techniques { #technical-details } + +/// tip | Astuce + +Si vous utilisez dĂ©jĂ  **FastAPI** en version **0.99.0 ou supĂ©rieure**, vous pouvez probablement **passer** ces dĂ©tails. + +Ils sont plus pertinents pour les versions plus anciennes, avant que OpenAPI 3.1.0 ne soit disponible. + +Vous pouvez considĂ©rer ceci comme une courte leçon d'histoire d'OpenAPI et de JSON Schema. đŸ€“ + +/// + +/// warning | Alertes + +Ce sont des dĂ©tails trĂšs techniques au sujet des standards **JSON Schema** et **OpenAPI**. + +Si les idĂ©es ci-dessus fonctionnent dĂ©jĂ  pour vous, cela pourrait suffire, et vous n'avez probablement pas besoin de ces dĂ©tails, n'hĂ©sitez pas Ă  les ignorer. + +/// + +Avant OpenAPI 3.1.0, OpenAPI utilisait une version plus ancienne et modifiĂ©e de **JSON Schema**. + +JSON Schema n'avait pas `examples`, donc OpenAPI a ajoutĂ© son propre champ `example` Ă  sa version modifiĂ©e. + +OpenAPI a Ă©galement ajoutĂ© les champs `example` et `examples` Ă  d'autres parties de la spĂ©cification : + +* `Parameter Object` (dans la spĂ©cification) qui Ă©tait utilisĂ© par les Ă©lĂ©ments FastAPI : + * `Path()` + * `Query()` + * `Header()` + * `Cookie()` +* `Request Body Object`, dans le champ `content`, sur le `Media Type Object` (dans la spĂ©cification) qui Ă©tait utilisĂ© par les Ă©lĂ©ments FastAPI : + * `Body()` + * `File()` + * `Form()` + +/// info + +Ce paramĂštre `examples` ancien et spĂ©cifique Ă  OpenAPI est dĂ©sormais `openapi_examples` depuis FastAPI `0.103.0`. + +/// + +### Le champ `examples` de JSON Schema { #json-schemas-examples-field } + +Ensuite, JSON Schema a ajoutĂ© un champ `examples` dans une nouvelle version de la spĂ©cification. + +Puis le nouveau OpenAPI 3.1.0 s'est basĂ© sur la derniĂšre version (JSON Schema 2020-12) qui incluait ce nouveau champ `examples`. + +Et dĂ©sormais, ce nouveau champ `examples` a prioritĂ© sur l'ancien champ unique (et personnalisĂ©) `example`, qui est maintenant dĂ©prĂ©ciĂ©. + +Ce nouveau champ `examples` dans JSON Schema est **juste une `list`** d'exemples, et non pas un dict avec des mĂ©tadonnĂ©es supplĂ©mentaires comme dans les autres endroits d'OpenAPI (dĂ©crits ci-dessus). + +/// info + +MĂȘme aprĂšs la sortie d'OpenAPI 3.1.0 avec cette nouvelle intĂ©gration plus simple avec JSON Schema, pendant un temps, Swagger UI, l'outil qui fournit la documentation automatique, ne prenait pas en charge OpenAPI 3.1.0 (il le fait depuis la version 5.0.0 🎉). + +À cause de cela, les versions de FastAPI antĂ©rieures Ă  0.99.0 utilisaient encore des versions d'OpenAPI infĂ©rieures Ă  3.1.0. + +/// + +### `examples` avec Pydantic et FastAPI { #pydantic-and-fastapi-examples } + +Lorsque vous ajoutez `examples` dans un modĂšle Pydantic, en utilisant `schema_extra` ou `Field(examples=["something"])`, cet exemple est ajoutĂ© au **JSON Schema** de ce modĂšle Pydantic. + +Et ce **JSON Schema** du modĂšle Pydantic est inclus dans l'**OpenAPI** de votre API, puis il est utilisĂ© dans l'interface de la documentation. + +Dans les versions de FastAPI antĂ©rieures Ă  0.99.0 (0.99.0 et supĂ©rieures utilisent le nouveau OpenAPI 3.1.0), lorsque vous utilisiez `example` ou `examples` avec l'une des autres utilitaires (`Query()`, `Body()`, etc.), ces exemples n'Ă©taient pas ajoutĂ©s au JSON Schema qui dĂ©crit ces donnĂ©es (pas mĂȘme Ă  la version de JSON Schema propre Ă  OpenAPI), ils Ă©taient ajoutĂ©s directement Ă  la dĂ©claration du *chemin d'accĂšs* dans OpenAPI (en dehors des parties d'OpenAPI qui utilisent JSON Schema). + +Mais maintenant que FastAPI 0.99.0 et supĂ©rieures utilisent OpenAPI 3.1.0, qui utilise JSON Schema 2020-12, et Swagger UI 5.0.0 et supĂ©rieures, tout est plus cohĂ©rent et les exemples sont inclus dans JSON Schema. + +### Swagger UI et `examples` spĂ©cifiques Ă  OpenAPI { #swagger-ui-and-openapi-specific-examples } + +Comme Swagger UI ne prenait pas en charge plusieurs exemples JSON Schema (au 2023-08-26), les utilisateurs n'avaient pas de moyen d'afficher plusieurs exemples dans les documents. + +Pour rĂ©soudre cela, FastAPI `0.103.0` a **ajoutĂ© la prise en charge** de la dĂ©claration du mĂȘme ancien champ `examples` **spĂ©cifique Ă  OpenAPI** avec le nouveau paramĂštre `openapi_examples`. đŸ€“ + +### RĂ©sumĂ© { #summary } + +Je disais que je n'aimais pas trop l'histoire ... et me voilĂ  maintenant Ă  donner des leçons d'« tech history ». 😅 + +En bref, **mettez Ă  niveau vers FastAPI 0.99.0 ou supĂ©rieur**, et les choses sont bien plus **simples, cohĂ©rentes et intuitives**, et vous n'avez pas besoin de connaĂźtre tous ces dĂ©tails historiques. 😎 diff --git a/docs/fr/docs/tutorial/security/first-steps.md b/docs/fr/docs/tutorial/security/first-steps.md new file mode 100644 index 000000000..8c4eb50d7 --- /dev/null +++ b/docs/fr/docs/tutorial/security/first-steps.md @@ -0,0 +1,203 @@ +# SĂ©curitĂ© - Premiers pas { #security-first-steps } + +Imaginons que vous ayez votre API de **backend** sur un certain domaine. + +Et vous avez un **frontend** sur un autre domaine ou dans un chemin diffĂ©rent du mĂȘme domaine (ou dans une application mobile). + +Et vous voulez que le **frontend** puisse s'authentifier auprĂšs du **backend**, en utilisant un **username** et un **password**. + +Nous pouvons utiliser **OAuth2** pour construire cela avec **FastAPI**. + +Mais Ă©pargnons-vous le temps de lire toute la spĂ©cification complĂšte juste pour trouver les petites informations dont vous avez besoin. + +Utilisons les outils fournis par **FastAPI** pour gĂ©rer la sĂ©curitĂ©. + +## Voir Ă  quoi cela ressemble { #how-it-looks } + +Commençons par utiliser le code et voir comment cela fonctionne, puis nous reviendrons pour comprendre ce qui se passe. + +## CrĂ©er `main.py` { #create-main-py } + +Copiez l'exemple dans un fichier `main.py` : + +{* ../../docs_src/security/tutorial001_an_py310.py *} + +## ExĂ©cuter { #run-it } + +/// info + +Le package `python-multipart` est installĂ© automatiquement avec **FastAPI** lorsque vous exĂ©cutez la commande `pip install "fastapi[standard]"`. + +Cependant, si vous utilisez la commande `pip install fastapi`, le package `python-multipart` n'est pas inclus par dĂ©faut. + +Pour l'installer manuellement, vous devez vous assurer de crĂ©er un [environnement virtuel](../../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis de l'installer avec : + +```console +$ pip install python-multipart +``` + +Cela est dĂ» au fait que **OAuth2** utilise des « form data » pour envoyer le `username` et le `password`. + +/// + +ExĂ©cutez l'exemple avec : + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +## VĂ©rifier { #check-it } + +Allez Ă  la documentation interactive Ă  l'adresse : http://127.0.0.1:8000/docs. + +Vous verrez quelque chose comme ceci : + + + +/// check | Bouton « Authorize » ! + +Vous avez dĂ©jĂ  un tout nouveau bouton « Authorize ». + +Et votre *chemin d'accĂšs* a un petit cadenas dans le coin supĂ©rieur droit sur lequel vous pouvez cliquer. + +/// + +Et si vous cliquez dessus, vous obtenez un petit formulaire d'autorisation pour saisir un `username` et un `password` (et d'autres champs optionnels) : + + + +/// note | Remarque + +Peu importe ce que vous saisissez dans le formulaire, cela ne fonctionnera pas encore. Mais nous y viendrons. + +/// + +Ce n'est bien sĂ»r pas le frontend pour les utilisateurs finaux, mais c'est un excellent outil automatique pour documenter de maniĂšre interactive toute votre API. + +Il peut ĂȘtre utilisĂ© par l'Ă©quipe frontend (qui peut aussi ĂȘtre vous-mĂȘme). + +Il peut ĂȘtre utilisĂ© par des applications et des systĂšmes tiers. + +Et il peut aussi ĂȘtre utilisĂ© par vous-mĂȘme, pour dĂ©boguer, vĂ©rifier et tester la mĂȘme application. + +## Le flux `password` { #the-password-flow } + +Revenons un peu en arriĂšre et comprenons de quoi il s'agit. + +Le « flux » `password` est l'une des maniĂšres (« flows ») dĂ©finies dans OAuth2 pour gĂ©rer la sĂ©curitĂ© et l'authentification. + +OAuth2 a Ă©tĂ© conçu pour que le backend ou l'API puisse ĂȘtre indĂ©pendant du serveur qui authentifie l'utilisateur. + +Mais dans ce cas, la mĂȘme application **FastAPI** gĂ©rera l'API et l'authentification. + +Voyons cela selon ce point de vue simplifié : + +- L'utilisateur saisit le `username` et le `password` dans le frontend, puis appuie sur EntrĂ©e. +- Le frontend (exĂ©cutĂ© dans le navigateur de l'utilisateur) envoie ce `username` et ce `password` vers une URL spĂ©cifique de notre API (dĂ©clarĂ©e avec `tokenUrl="token"`). +- L'API vĂ©rifie ce `username` et ce `password`, et rĂ©pond avec un « token » (nous n'avons encore rien implĂ©mentĂ© de tout cela). + - Un « token » n'est qu'une chaĂźne contenant des informations que nous pouvons utiliser plus tard pour vĂ©rifier cet utilisateur. + - Normalement, un token est configurĂ© pour expirer aprĂšs un certain temps. + - Ainsi, l'utilisateur devra se reconnecter Ă  un moment donnĂ©. + - Et si le token est volĂ©, le risque est moindre. Ce n'est pas une clĂ© permanente qui fonctionnerait indĂ©finiment (dans la plupart des cas). +- Le frontend stocke ce token temporairement quelque part. +- L'utilisateur clique dans le frontend pour aller vers une autre section de l'application web frontend. +- Le frontend doit rĂ©cupĂ©rer d'autres donnĂ©es depuis l'API. + - Mais cela nĂ©cessite une authentification pour cet endpoint spĂ©cifique. + - Donc, pour s'authentifier auprĂšs de notre API, il envoie un en-tĂȘte `Authorization` avec une valeur `Bearer ` suivie du token. + - Si le token contient `foobar`, le contenu de l'en-tĂȘte `Authorization` serait : `Bearer foobar`. + +## Le `OAuth2PasswordBearer` de **FastAPI** { #fastapis-oauth2passwordbearer } + +**FastAPI** fournit plusieurs outils, Ă  diffĂ©rents niveaux d'abstraction, pour implĂ©menter ces fonctionnalitĂ©s de sĂ©curitĂ©. + +Dans cet exemple, nous allons utiliser **OAuth2**, avec le flux **Password**, en utilisant un token **Bearer**. Nous le faisons avec la classe `OAuth2PasswordBearer`. + +/// info + +Un token « bearer » n'est pas la seule option. + +Mais c'est la meilleure pour notre cas d'utilisation. + +Et cela pourrait ĂȘtre la meilleure pour la plupart des cas, sauf si vous ĂȘtes expert en OAuth2 et savez exactement pourquoi une autre option convient mieux Ă  vos besoins. + +Dans ce cas, **FastAPI** vous fournit aussi les outils pour la construire. + +/// + +Lorsque nous crĂ©ons une instance de la classe `OAuth2PasswordBearer`, nous passons le paramĂštre `tokenUrl`. Ce paramĂštre contient l'URL que le client (le frontend s'exĂ©cutant dans le navigateur de l'utilisateur) utilisera pour envoyer le `username` et le `password` afin d'obtenir un token. + +{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *} + +/// tip | Astuce + +Ici `tokenUrl="token"` fait rĂ©fĂ©rence Ă  une URL relative `token` que nous n'avons pas encore créée. Comme c'est une URL relative, elle est Ă©quivalente Ă  `./token`. + +Parce que nous utilisons une URL relative, si votre API se trouvait Ă  `https://example.com/`, alors elle ferait rĂ©fĂ©rence Ă  `https://example.com/token`. Mais si votre API se trouvait Ă  `https://example.com/api/v1/`, alors elle ferait rĂ©fĂ©rence Ă  `https://example.com/api/v1/token`. + +Utiliser une URL relative est important pour vous assurer que votre application continue de fonctionner mĂȘme dans un cas d'usage avancĂ© comme [DerriĂšre un proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank}. + +/// + +Ce paramĂštre ne crĂ©e pas cet endpoint / *chemin d'accĂšs*, mais dĂ©clare que l'URL `/token` sera celle que le client doit utiliser pour obtenir le token. Cette information est utilisĂ©e dans OpenAPI, puis dans les systĂšmes de documentation API interactifs. + +Nous crĂ©erons bientĂŽt aussi le vĂ©ritable chemin d'accĂšs. + +/// info + +Si vous ĂȘtes un « Pythonista » trĂšs strict, vous pourriez ne pas apprĂ©cier le style du nom de paramĂštre `tokenUrl` au lieu de `token_url`. + +C'est parce qu'il utilise le mĂȘme nom que dans la spĂ©cification OpenAPI. Ainsi, si vous devez approfondir l'un de ces schĂ©mas de sĂ©curitĂ©, vous pouvez simplement copier-coller pour trouver plus d'informations Ă  ce sujet. + +/// + +La variable `oauth2_scheme` est une instance de `OAuth2PasswordBearer`, mais c'est aussi un « callable ». + +Elle pourrait ĂȘtre appelĂ©e ainsi : + +```Python +oauth2_scheme(some, parameters) +``` + +Ainsi, elle peut ĂȘtre utilisĂ©e avec `Depends`. + +### Utiliser { #use-it } + +Vous pouvez maintenant passer ce `oauth2_scheme` en dĂ©pendance avec `Depends`. + +{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *} + +Cette dĂ©pendance fournira une `str` qui est affectĂ©e au paramĂštre `token` de la fonction de *chemin d'accĂšs*. + +**FastAPI** saura qu'il peut utiliser cette dĂ©pendance pour dĂ©finir un « schĂ©ma de sĂ©curitĂ© » dans le schĂ©ma OpenAPI (et la documentation API automatique). + +/// info | DĂ©tails techniques + +**FastAPI** saura qu'il peut utiliser la classe `OAuth2PasswordBearer` (dĂ©clarĂ©e dans une dĂ©pendance) pour dĂ©finir le schĂ©ma de sĂ©curitĂ© dans OpenAPI parce qu'elle hĂ©rite de `fastapi.security.oauth2.OAuth2`, qui hĂ©rite Ă  son tour de `fastapi.security.base.SecurityBase`. + +Tous les utilitaires de sĂ©curitĂ© qui s'intĂšgrent Ă  OpenAPI (et Ă  la documentation API automatique) hĂ©ritent de `SecurityBase`, c'est ainsi que **FastAPI** sait comment les intĂ©grer dans OpenAPI. + +/// + +## Ce que cela fait { #what-it-does } + +Il va chercher dans la requĂȘte cet en-tĂȘte `Authorization`, vĂ©rifier si la valeur est `Bearer ` plus un token, et renverra le token en tant que `str`. + +S'il ne voit pas d'en-tĂȘte `Authorization`, ou si la valeur n'a pas de token `Bearer `, il rĂ©pondra directement avec une erreur de code d'Ă©tat 401 (`UNAUTHORIZED`). + +Vous n'avez mĂȘme pas Ă  vĂ©rifier si le token existe pour renvoyer une erreur. Vous pouvez ĂȘtre sĂ»r que si votre fonction est exĂ©cutĂ©e, elle aura une `str` dans ce token. + +Vous pouvez dĂ©jĂ  l'essayer dans la documentation interactive : + + + +Nous ne vĂ©rifions pas encore la validitĂ© du token, mais c'est dĂ©jĂ  un dĂ©but. + +## RĂ©capitulatif { #recap } + +Ainsi, en seulement 3 ou 4 lignes supplĂ©mentaires, vous disposez dĂ©jĂ  d'une forme primitive de sĂ©curitĂ©. diff --git a/docs/fr/docs/tutorial/security/get-current-user.md b/docs/fr/docs/tutorial/security/get-current-user.md new file mode 100644 index 000000000..5f73efea9 --- /dev/null +++ b/docs/fr/docs/tutorial/security/get-current-user.md @@ -0,0 +1,105 @@ +# Obtenir l'utilisateur actuel { #get-current-user } + +Dans le chapitre prĂ©cĂ©dent, le systĂšme de sĂ©curitĂ© (basĂ© sur le systĂšme d'injection de dĂ©pendances) fournissait Ă  la *fonction de chemin d'accĂšs* un `token` en tant que `str` : + +{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *} + +Mais ce n'est pas encore trĂšs utile. + +Faisons en sorte qu'il nous fournisse l'utilisateur actuel. + +## CrĂ©er un modĂšle d'utilisateur { #create-a-user-model } + +Commençons par crĂ©er un modĂšle d'utilisateur Pydantic. + +De la mĂȘme maniĂšre que nous utilisons Pydantic pour dĂ©clarer des corps de requĂȘte, nous pouvons l'utiliser ailleurs : + +{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *} + +## CrĂ©er une dĂ©pendance `get_current_user` { #create-a-get-current-user-dependency } + +CrĂ©ons une dĂ©pendance `get_current_user`. + +Rappelez-vous que les dĂ©pendances peuvent avoir des sous-dĂ©pendances ? + +`get_current_user` aura une dĂ©pendance avec le mĂȘme `oauth2_scheme` que nous avons créé prĂ©cĂ©demment. + +Comme nous le faisions auparavant directement dans le *chemin d'accĂšs*, notre nouvelle dĂ©pendance `get_current_user` recevra un `token` en tant que `str` de la sous-dĂ©pendance `oauth2_scheme` : + +{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *} + +## RĂ©cupĂ©rer l'utilisateur { #get-the-user } + +`get_current_user` utilisera une fonction utilitaire (factice) que nous avons créée, qui prend un token en `str` et retourne notre modĂšle Pydantic `User` : + +{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *} + +## Injecter l'utilisateur actuel { #inject-the-current-user } + +Nous pouvons donc utiliser le mĂȘme `Depends` avec notre `get_current_user` dans le *chemin d'accĂšs* : + +{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *} + +Remarquez que nous dĂ©clarons le type de `current_user` comme le modĂšle Pydantic `User`. + +Cela nous aidera dans la fonction avec toute l'autocomplĂ©tion et les vĂ©rifications de type. + +/// tip | Astuce + +Vous vous souvenez peut-ĂȘtre que les corps de requĂȘte sont Ă©galement dĂ©clarĂ©s avec des modĂšles Pydantic. + +Ici, **FastAPI** ne s'y trompera pas car vous utilisez `Depends`. + +/// + +/// check | VĂ©rifications + +La maniĂšre dont ce systĂšme de dĂ©pendances est conçu nous permet d'avoir diffĂ©rentes dĂ©pendances (diffĂ©rents « dependables ») qui retournent toutes un modĂšle `User`. + +Nous ne sommes pas limitĂ©s Ă  une seule dĂ©pendance pouvant retourner ce type de donnĂ©es. + +/// + +## Autres modĂšles { #other-models } + +Vous pouvez maintenant obtenir l'utilisateur actuel directement dans les *fonctions de chemin d'accĂšs* et gĂ©rer les mĂ©canismes de sĂ©curitĂ© au niveau de l'**Injection de dĂ©pendances**, en utilisant `Depends`. + +Et vous pouvez utiliser n'importe quel modĂšle ou donnĂ©es pour les exigences de sĂ©curitĂ© (dans ce cas, un modĂšle Pydantic `User`). + +Mais vous n'ĂȘtes pas limitĂ© Ă  un modĂšle, une classe ou un type de donnĂ©es spĂ©cifique. + +Voulez-vous avoir un `id` et `email` et ne pas avoir de `username` dans votre modĂšle ? Bien sĂ»r. Vous pouvez utiliser ces mĂȘmes outils. + +Voulez-vous simplement avoir un `str` ? Ou juste un `dict` ? Ou directement une instance d'un modĂšle de classe de base de donnĂ©es ? Tout fonctionne de la mĂȘme maniĂšre. + +Vous n'avez en fait pas d'utilisateurs qui se connectent Ă  votre application, mais des robots, bots ou d'autres systĂšmes, qui n'ont qu'un jeton d'accĂšs ? LĂ  encore, tout fonctionne de la mĂȘme façon. + +Utilisez simplement tout type de modĂšle, toute sorte de classe, tout type de base de donnĂ©es dont vous avez besoin pour votre application. **FastAPI** vous couvre avec le systĂšme d'injection de dĂ©pendances. + +## Taille du code { #code-size } + +Cet exemple peut sembler verbeux. Gardez Ă  l'esprit que nous mĂ©langeons sĂ©curitĂ©, modĂšles de donnĂ©es, fonctions utilitaires et *chemins d'accĂšs* dans le mĂȘme fichier. + +Mais voici le point clĂ©. + +La partie sĂ©curitĂ© et injection de dĂ©pendances est Ă©crite une seule fois. + +Et vous pouvez la rendre aussi complexe que vous le souhaitez. Et malgrĂ© tout, ne l'Ă©crire qu'une seule fois, en un seul endroit. Avec toute la flexibilitĂ©. + +Mais vous pouvez avoir des milliers d'endpoints (*chemins d'accĂšs*) utilisant le mĂȘme systĂšme de sĂ©curitĂ©. + +Et tous (ou seulement une partie d'entre eux, si vous le souhaitez) peuvent profiter de la rĂ©utilisation de ces dĂ©pendances ou de toute autre dĂ©pendance que vous crĂ©ez. + +Et tous ces milliers de *chemins d'accĂšs* peuvent tenir en seulement 3 lignes : + +{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *} + +## RĂ©capitulatif { #recap } + +Vous pouvez dĂ©sormais obtenir l'utilisateur actuel directement dans votre *fonction de chemin d'accĂšs*. + +Nous avons dĂ©jĂ  fait la moitiĂ© du chemin. + +Il nous suffit d'ajouter un *chemin d'accĂšs* pour que l'utilisateur/client envoie effectivement le `username` et le `password`. + +C'est pour la suite. diff --git a/docs/fr/docs/tutorial/security/index.md b/docs/fr/docs/tutorial/security/index.md new file mode 100644 index 000000000..6de75aed6 --- /dev/null +++ b/docs/fr/docs/tutorial/security/index.md @@ -0,0 +1,106 @@ +# SĂ©curitĂ© { #security } + +Il existe de nombreuses façons de gĂ©rer la sĂ©curitĂ©, l'authentification et l'autorisation. + +Et c'est normalement un sujet complexe et « difficile ». + +Dans de nombreux frameworks et systĂšmes, le simple fait de gĂ©rer la sĂ©curitĂ© et l'authentification demande beaucoup d'efforts et de code (dans de nombreux cas, cela peut reprĂ©senter 50 % ou plus de tout le code Ă©crit). + +**FastAPI** fournit plusieurs outils pour vous aider Ă  gĂ©rer la **SĂ©curitĂ©** facilement, rapidement, de maniĂšre standard, sans avoir Ă  Ă©tudier et apprendre toutes les spĂ©cifications de sĂ©curitĂ©. + +Mais d'abord, voyons quelques notions. + +## PressĂ© ? { #in-a-hurry } + +Si ces termes ne vous intĂ©ressent pas et que vous avez simplement besoin d'ajouter une sĂ©curitĂ© avec une authentification basĂ©e sur un nom d'utilisateur et un mot de passe immĂ©diatement, passez aux chapitres suivants. + +## OAuth2 { #oauth2 } + +OAuth2 est une spĂ©cification qui dĂ©finit plusieurs façons de gĂ©rer l'authentification et l'autorisation. + +C'est une spĂ©cification assez vaste qui couvre plusieurs cas d'utilisation complexes. + +Elle inclut des moyens de s'authentifier en utilisant un « tiers ». + +C'est ce que tous les systĂšmes avec « connexion avec Facebook, Google, X (Twitter), GitHub » utilisent en arriĂšre-plan. + +### OAuth 1 { #oauth-1 } + +Il y a eu un OAuth 1, trĂšs diffĂ©rent d'OAuth2, et plus complexe, car il incluait des spĂ©cifications directes sur la maniĂšre de chiffrer la communication. + +Il n'est plus trĂšs populaire ni utilisĂ© de nos jours. + +OAuth2 ne spĂ©cifie pas comment chiffrer la communication ; il suppose que votre application est servie en HTTPS. + +/// tip | Astuce + +Dans la section sur le dĂ©ploiement, vous verrez comment configurer HTTPS gratuitement, en utilisant Traefik et Let's Encrypt. + +/// + +## OpenID Connect { #openid-connect } + +OpenID Connect est une autre spĂ©cification, basĂ©e sur **OAuth2**. + +Elle Ă©tend simplement OAuth2 en prĂ©cisant certains points relativement ambigus dans OAuth2, afin d'essayer de la rendre plus interopĂ©rable. + +Par exemple, la connexion Google utilise OpenID Connect (qui, en arriĂšre-plan, utilise OAuth2). + +Mais la connexion Facebook ne prend pas en charge OpenID Connect. Elle a sa propre variante d'OAuth2. + +### OpenID (pas « OpenID Connect ») { #openid-not-openid-connect } + +Il y avait aussi une spĂ©cification « OpenID ». Elle essayait de rĂ©soudre la mĂȘme chose qu'**OpenID Connect**, mais n'Ă©tait pas basĂ©e sur OAuth2. + +C'Ă©tait donc un systĂšme totalement distinct. + +Il n'est plus trĂšs populaire ni utilisĂ© de nos jours. + +## OpenAPI { #openapi } + +OpenAPI (prĂ©cĂ©demment connu sous le nom de Swagger) est la spĂ©cification ouverte pour construire des API (dĂ©sormais partie de la Linux Foundation). + +**FastAPI** est basĂ© sur **OpenAPI**. + +C'est ce qui rend possibles plusieurs interfaces de documentation interactive automatiques, la gĂ©nĂ©ration de code, etc. + +OpenAPI propose une maniĂšre de dĂ©finir plusieurs « schĂ©mas » de sĂ©curitĂ©. + +En les utilisant, vous pouvez tirer parti de tous ces outils basĂ©s sur des standards, y compris ces systĂšmes de documentation interactive. + +OpenAPI dĂ©finit les schĂ©mas de sĂ©curitĂ© suivants : + +* `apiKey` : une clĂ© spĂ©cifique Ă  l'application qui peut provenir : + * D'un paramĂštre de requĂȘte. + * D'un en-tĂȘte. + * D'un cookie. +* `http` : des systĂšmes d'authentification HTTP standards, notamment : + * `bearer` : un en-tĂȘte `Authorization` avec une valeur `Bearer ` plus un jeton. HĂ©ritĂ© d'OAuth2. + * Authentification HTTP Basic. + * HTTP Digest, etc. +* `oauth2` : toutes les mĂ©thodes OAuth2 pour gĂ©rer la sĂ©curitĂ© (appelĂ©es « flows »). + * Plusieurs de ces flows conviennent pour construire un fournisseur d'authentification OAuth 2.0 (comme Google, Facebook, X (Twitter), GitHub, etc.) : + * `implicit` + * `clientCredentials` + * `authorizationCode` + * Mais il existe un « flow » spĂ©cifique qui peut parfaitement ĂȘtre utilisĂ© pour gĂ©rer l'authentification directement dans la mĂȘme application : + * `password` : certains des prochains chapitres couvriront des exemples Ă  ce sujet. +* `openIdConnect` : propose un moyen de dĂ©finir comment dĂ©couvrir automatiquement les donnĂ©es d'authentification OAuth2. + * Cette dĂ©couverte automatique est ce qui est dĂ©fini dans la spĂ©cification OpenID Connect. + + +/// tip | Astuce + +IntĂ©grer d'autres fournisseurs d'authentification/autorisation comme Google, Facebook, X (Twitter), GitHub, etc. est Ă©galement possible et relativement facile. + +Le problĂšme le plus complexe est de construire un fournisseur d'authentification/autorisation comme ceux-lĂ , mais **FastAPI** vous donne les outils pour le faire facilement, tout en effectuant le gros du travail pour vous. + +/// + +## Outils **FastAPI** { #fastapi-utilities } + +FastAPI propose plusieurs outils pour chacun de ces schĂ©mas de sĂ©curitĂ© dans le module fastapi.security qui simplifient l'utilisation de ces mĂ©canismes de sĂ©curitĂ©. + +Dans les prochains chapitres, vous verrez comment ajouter de la sĂ©curitĂ© Ă  votre API en utilisant ces outils fournis par **FastAPI**. + +Et vous verrez aussi comment cela s'intĂšgre automatiquement au systĂšme de documentation interactive. diff --git a/docs/fr/docs/tutorial/security/oauth2-jwt.md b/docs/fr/docs/tutorial/security/oauth2-jwt.md new file mode 100644 index 000000000..d35530fc9 --- /dev/null +++ b/docs/fr/docs/tutorial/security/oauth2-jwt.md @@ -0,0 +1,277 @@ +# OAuth2 avec mot de passe (et hachage), Bearer avec des jetons JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens } + +Maintenant que nous avons tout le flux de sĂ©curitĂ©, rendons rĂ©ellement l'application sĂ©curisĂ©e, en utilisant des jetons JWT et un hachage de mot de passe sĂ©curisĂ©. + +Ce code est utilisable dans votre application, enregistrez les hachages de mots de passe dans votre base de donnĂ©es, etc. + +Nous allons repartir d'oĂč nous nous sommes arrĂȘtĂ©s dans le chapitre prĂ©cĂ©dent et l'enrichir. + +## À propos de JWT { #about-jwt } + +JWT signifie « JSON Web Tokens ». + +C'est une norme pour coder un objet JSON dans une longue chaĂźne compacte sans espaces. Cela ressemble Ă  ceci : + +``` +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +``` + +Il n'est pas chiffrĂ© ; ainsi, n'importe qui peut rĂ©cupĂ©rer les informations Ă  partir de son contenu. + +Mais il est signĂ©. Ainsi, quand vous recevez un jeton que vous avez Ă©mis, vous pouvez vĂ©rifier que vous l'avez bien Ă©mis. + +De cette façon, vous pouvez crĂ©er un jeton avec une expiration d'une semaine, par exemple. Et quand l'utilisateur revient le lendemain avec ce jeton, vous savez qu'il est toujours connectĂ© Ă  votre systĂšme. + +AprĂšs une semaine, le jeton aura expirĂ© et l'utilisateur ne sera pas autorisĂ© et devra se reconnecter pour obtenir un nouveau jeton. Et si l'utilisateur (ou un tiers) essayait de modifier le jeton pour changer l'expiration, vous pourriez le dĂ©tecter, car les signatures ne correspondraient pas. + +Si vous voulez expĂ©rimenter avec des jetons JWT et voir comment ils fonctionnent, consultez https://jwt.io. + +## Installer `PyJWT` { #install-pyjwt } + +Nous devons installer `PyJWT` pour gĂ©nĂ©rer et vĂ©rifier les jetons JWT en Python. + +Assurez-vous de crĂ©er un [environnement virtuel](../../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis d'installer `pyjwt` : + +
+ +```console +$ pip install pyjwt + +---> 100% +``` + +
+ +/// info + +Si vous prĂ©voyez d'utiliser des algorithmes de signature numĂ©rique comme RSA ou ECDSA, vous devez installer la dĂ©pendance de bibliothĂšque de cryptographie `pyjwt[crypto]`. + +Vous pouvez en lire davantage dans la documentation d'installation de PyJWT. + +/// + +## Hachage de mot de passe { #password-hashing } + +« Hachage » signifie convertir un contenu (un mot de passe dans ce cas) en une sĂ©quence d'octets (juste une chaĂźne) qui ressemble Ă  du charabia. + +Chaque fois que vous fournissez exactement le mĂȘme contenu (exactement le mĂȘme mot de passe), vous obtenez exactement le mĂȘme charabia. + +Mais vous ne pouvez pas convertir le charabia en sens inverse vers le mot de passe. + +### Pourquoi utiliser le hachage de mot de passe { #why-use-password-hashing } + +Si votre base de donnĂ©es est volĂ©e, le voleur n'aura pas les mots de passe en clair de vos utilisateurs, seulement les hachages. + +Ainsi, le voleur ne pourra pas essayer d'utiliser ce mot de passe dans un autre systĂšme (comme beaucoup d'utilisateurs utilisent le mĂȘme mot de passe partout, ce serait dangereux). + +## Installer `pwdlib` { #install-pwdlib } + +pwdlib est un excellent package Python pour gĂ©rer les hachages de mots de passe. + +Il prend en charge de nombreux algorithmes de hachage sĂ©curisĂ©s et des utilitaires pour travailler avec eux. + +L'algorithme recommandĂ© est « Argon2 ». + +Assurez-vous de crĂ©er un [environnement virtuel](../../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis d'installer pwdlib avec Argon2 : + +
+ +```console +$ pip install "pwdlib[argon2]" + +---> 100% +``` + +
+ +/// tip | Astuce + +Avec `pwdlib`, vous pouvez mĂȘme le configurer pour pouvoir lire des mots de passe créés par **Django**, un plug-in de sĂ©curitĂ© **Flask** ou bien d'autres. + +Ainsi, vous seriez par exemple en mesure de partager les mĂȘmes donnĂ©es d'une application Django dans une base de donnĂ©es avec une application FastAPI. Ou de migrer progressivement une application Django en utilisant la mĂȘme base de donnĂ©es. + +Et vos utilisateurs pourraient se connecter depuis votre application Django ou depuis votre application **FastAPI**, en mĂȘme temps. + +/// + +## Hacher et vĂ©rifier les mots de passe { #hash-and-verify-the-passwords } + +Importez les outils nĂ©cessaires depuis `pwdlib`. + +CrĂ©ez une instance PasswordHash avec les rĂ©glages recommandĂ©s ; elle sera utilisĂ©e pour hacher et vĂ©rifier les mots de passe. + +/// tip | Astuce + +pwdlib prend Ă©galement en charge l'algorithme de hachage bcrypt, mais n'inclut pas les algorithmes hĂ©ritĂ©s. Pour travailler avec des hachages obsolĂštes, il est recommandĂ© d'utiliser la bibliothĂšque passlib. + +Par exemple, vous pourriez l'utiliser pour lire et vĂ©rifier des mots de passe gĂ©nĂ©rĂ©s par un autre systĂšme (comme Django), mais hacher tous les nouveaux mots de passe avec un autre algorithme comme Argon2 ou Bcrypt. + +Et rester compatible avec tous en mĂȘme temps. + +/// + +CrĂ©ez une fonction utilitaire pour hacher un mot de passe fourni par l'utilisateur. + +Et une autre pour vĂ©rifier si un mot de passe reçu correspond au hachage stockĂ©. + +Et une autre pour authentifier et renvoyer un utilisateur. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *} + +Lorsque `authenticate_user` est appelĂ©e avec un nom d'utilisateur qui n'existe pas dans la base de donnĂ©es, nous exĂ©cutons tout de mĂȘme `verify_password` contre un hachage factice. + +Cela garantit que le point de terminaison met approximativement le mĂȘme temps Ă  rĂ©pondre que le nom d'utilisateur soit valide ou non, empĂȘchant des **attaques temporelles** qui pourraient ĂȘtre utilisĂ©es pour Ă©numĂ©rer les noms d'utilisateur existants. + +/// note | Remarque + +Si vous consultez la nouvelle (fausse) base de donnĂ©es `fake_users_db`, vous verrez Ă  quoi ressemble maintenant le mot de passe hachĂ© : `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. + +/// + +## GĂ©rer les jetons JWT { #handle-jwt-tokens } + +Importez les modules installĂ©s. + +CrĂ©ez une clĂ© secrĂšte alĂ©atoire qui sera utilisĂ©e pour signer les jetons JWT. + +Pour gĂ©nĂ©rer une clĂ© secrĂšte alĂ©atoire sĂ©curisĂ©e, utilisez la commande : + +
+ +```console +$ openssl rand -hex 32 + +09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7 +``` + +
+ +Et copiez la sortie dans la variable `SECRET_KEY` (n'utilisez pas celle de l'exemple). + +CrĂ©ez une variable `ALGORITHM` avec l'algorithme utilisĂ© pour signer le jeton JWT, et dĂ©finissez-la Ă  `"HS256"`. + +CrĂ©ez une variable pour l'expiration du jeton. + +DĂ©finissez un modĂšle Pydantic qui sera utilisĂ© dans le point de terminaison du jeton pour la rĂ©ponse. + +CrĂ©ez une fonction utilitaire pour gĂ©nĂ©rer un nouveau jeton d'accĂšs. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *} + +## Mettre Ă  jour les dĂ©pendances { #update-the-dependencies } + +Mettez Ă  jour `get_current_user` pour recevoir le mĂȘme jeton qu'auparavant, mais cette fois en utilisant des jetons JWT. + +DĂ©codez le jeton reçu, vĂ©rifiez-le, et renvoyez l'utilisateur courant. + +Si le jeton est invalide, renvoyez immĂ©diatement une erreur HTTP. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *} + +## Mettre Ă  jour le *chemin d'accĂšs* `/token` { #update-the-token-path-operation } + +CrĂ©ez un `timedelta` avec la durĂ©e d'expiration du jeton. + +CrĂ©ez un vĂ©ritable jeton d'accĂšs JWT et renvoyez-le. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *} + +### DĂ©tails techniques au sujet du « subject » JWT `sub` { #technical-details-about-the-jwt-subject-sub } + +La spĂ©cification JWT indique qu'il existe une clĂ© `sub`, contenant le sujet du jeton. + +Son utilisation est facultative, mais c'est lĂ  que vous placeriez l'identifiant de l'utilisateur ; nous l'utilisons donc ici. + +Les JWT peuvent ĂȘtre utilisĂ©s pour d'autres choses que l'identification d'un utilisateur et l'autorisation d'effectuer des opĂ©rations directement sur votre API. + +Par exemple, vous pourriez identifier une « voiture » ou un « article de blog ». + +Vous pourriez ensuite ajouter des permissions sur cette entitĂ©, comme « conduire » (pour la voiture) ou « modifier » (pour le blog). + +Vous pourriez alors donner ce jeton JWT Ă  un utilisateur (ou un bot), et il pourrait l'utiliser pour effectuer ces actions (conduire la voiture, ou modifier l'article de blog) sans mĂȘme avoir besoin d'avoir un compte, uniquement avec le jeton JWT que votre API a gĂ©nĂ©rĂ© pour cela. + +En utilisant ces idĂ©es, les JWT peuvent servir Ă  des scĂ©narios bien plus sophistiquĂ©s. + +Dans ces cas, plusieurs de ces entitĂ©s peuvent avoir le mĂȘme identifiant, disons `foo` (un utilisateur `foo`, une voiture `foo`, et un article de blog `foo`). + +Donc, pour Ă©viter les collisions d'identifiants, lors de la crĂ©ation du jeton JWT pour l'utilisateur, vous pouvez prĂ©fixer la valeur de la clĂ© `sub`, par exemple avec `username:`. Ainsi, dans cet exemple, la valeur de `sub` aurait pu ĂȘtre : `username:johndoe`. + +L'important Ă  garder Ă  l'esprit est que la clĂ© `sub` doit contenir un identifiant unique dans toute l'application, et ce doit ĂȘtre une chaĂźne de caractĂšres. + +## VĂ©rifier { #check-it } + +Lancez le serveur et allez Ă  la documentation : http://127.0.0.1:8000/docs. + +Vous verrez l'interface utilisateur suivante : + + + +Autorisez l'application de la mĂȘme maniĂšre qu'auparavant. + +En utilisant les identifiants : + +Nom d'utilisateur : `johndoe` +Mot de passe : `secret` + +/// check | VĂ©rifications + +Remarquez qu'Ă  aucun endroit du code le mot de passe en clair « secret » n'apparaĂźt, nous n'avons que la version hachĂ©e. + +/// + + + +Appelez le point de terminaison `/users/me/`, vous obtiendrez la rĂ©ponse suivante : + +```JSON +{ + "username": "johndoe", + "email": "johndoe@example.com", + "full_name": "John Doe", + "disabled": false +} +``` + + + +Si vous ouvrez les outils de dĂ©veloppement, vous pouvez voir que les donnĂ©es envoyĂ©es n'incluent que le jeton ; le mot de passe n'est envoyĂ© que dans la premiĂšre requĂȘte pour authentifier l'utilisateur et obtenir ce jeton d'accĂšs, mais plus ensuite : + + + +/// note | Remarque + +Remarquez l'en-tĂȘte `Authorization`, avec une valeur qui commence par `Bearer `. + +/// + +## Utilisation avancĂ©e avec `scopes` { #advanced-usage-with-scopes } + +OAuth2 comporte la notion de « scopes ». + +Vous pouvez les utiliser pour ajouter un ensemble spĂ©cifique d'autorisations Ă  un jeton JWT. + +Vous pouvez ensuite donner ce jeton directement Ă  un utilisateur ou Ă  un tiers, pour interagir avec votre API avec un ensemble de restrictions. + +Vous pouvez apprendre Ă  les utiliser et comment ils sont intĂ©grĂ©s Ă  **FastAPI** plus tard dans le **Guide de l'utilisateur avancĂ©**. + +## RĂ©capitulatif { #recap } + +Avec ce que vous avez vu jusqu'Ă  prĂ©sent, vous pouvez configurer une application **FastAPI** sĂ©curisĂ©e en utilisant des standards comme OAuth2 et JWT. + +Dans presque n'importe quel framework, la gestion de la sĂ©curitĂ© devient assez rapidement un sujet plutĂŽt complexe. + +De nombreux packages qui la simplifient beaucoup doivent faire de nombreux compromis avec le modĂšle de donnĂ©es, la base de donnĂ©es et les fonctionnalitĂ©s disponibles. Et certains de ces packages qui simplifient trop les choses comportent en fait des failles de sĂ©curitĂ© sous-jacentes. + +--- + +**FastAPI** ne fait aucun compromis avec une base de donnĂ©es, un modĂšle de donnĂ©es ni un outil. + +Il vous donne toute la flexibilitĂ© pour choisir ceux qui conviennent le mieux Ă  votre projet. + +Et vous pouvez utiliser directement de nombreux packages bien maintenus et largement utilisĂ©s comme `pwdlib` et `PyJWT`, car **FastAPI** n'exige aucun mĂ©canisme complexe pour intĂ©grer des packages externes. + +Mais il vous fournit les outils pour simplifier le processus autant que possible sans compromettre la flexibilitĂ©, la robustesse ou la sĂ©curitĂ©. + +Et vous pouvez utiliser et implĂ©menter des protocoles sĂ©curisĂ©s et standard, comme OAuth2, de maniĂšre relativement simple. + +Vous pouvez en apprendre davantage dans le **Guide de l'utilisateur avancĂ©** sur la façon d'utiliser les « scopes » OAuth2, pour un systĂšme d'autorisations plus fin, en suivant ces mĂȘmes standards. OAuth2 avec scopes est le mĂ©canisme utilisĂ© par de nombreux grands fournisseurs d'authentification, comme Facebook, Google, GitHub, Microsoft, X (Twitter), etc., pour autoriser des applications tierces Ă  interagir avec leurs API au nom de leurs utilisateurs. diff --git a/docs/fr/docs/tutorial/security/simple-oauth2.md b/docs/fr/docs/tutorial/security/simple-oauth2.md new file mode 100644 index 000000000..662444753 --- /dev/null +++ b/docs/fr/docs/tutorial/security/simple-oauth2.md @@ -0,0 +1,289 @@ +# OAuth2 simple avec Password et Bearer { #simple-oauth2-with-password-and-bearer } + +Construisons maintenant Ă  partir du chapitre prĂ©cĂ©dent et ajoutons les Ă©lĂ©ments manquants pour avoir un flux de sĂ©curitĂ© complet. + +## Obtenir `username` et `password` { #get-the-username-and-password } + +Nous allons utiliser les utilitaires de sĂ©curitĂ© de **FastAPI** pour obtenir `username` et `password`. + +OAuth2 spĂ©cifie que lorsqu'on utilise le « password flow » (ce que nous utilisons), le client/utilisateur doit envoyer des champs `username` et `password` en tant que donnĂ©es de formulaire. + +Et la spĂ©cification indique que les champs doivent porter exactement ces noms. Ainsi, `user-name` ou `email` ne fonctionneraient pas. + +Mais ne vous inquiĂ©tez pas, vous pouvez l'afficher comme vous le souhaitez Ă  vos utilisateurs finaux dans le frontend. + +Et vos modĂšles de base de donnĂ©es peuvent utiliser les noms que vous voulez. + +Mais pour le chemin d'accĂšs de connexion, nous devons utiliser ces noms pour ĂȘtre compatibles avec la spĂ©cification (et pouvoir, par exemple, utiliser le systĂšme de documentation API intĂ©grĂ©). + +La spĂ©cification prĂ©cise Ă©galement que `username` et `password` doivent ĂȘtre envoyĂ©s en donnĂ©es de formulaire (donc pas de JSON ici). + +### `scope` { #scope } + +La spĂ©cification indique aussi que le client peut envoyer un autre champ de formulaire « scope ». + +Le nom du champ de formulaire est `scope` (au singulier), mais il s'agit en fait d'une longue chaĂźne contenant des « scopes » sĂ©parĂ©s par des espaces. + +Chaque « scope » n'est qu'une chaĂźne (sans espaces). + +Ils sont normalement utilisĂ©s pour dĂ©clarer des permissions de sĂ©curitĂ© spĂ©cifiques, par exemple : + +* `users:read` ou `users:write` sont des exemples courants. +* `instagram_basic` est utilisĂ© par Facebook / Instagram. +* `https://www.googleapis.com/auth/drive` est utilisĂ© par Google. + +/// info + +En OAuth2, un « scope » est simplement une chaĂźne qui dĂ©clare une permission spĂ©cifique requise. + +Peu importe s'il contient d'autres caractĂšres comme `:` ou si c'est une URL. + +Ces dĂ©tails dĂ©pendent de l'implĂ©mentation. + +Pour OAuth2, ce ne sont que des chaĂźnes. + +/// + +## Écrire le code pour obtenir `username` et `password` { #code-to-get-the-username-and-password } + +Utilisons maintenant les utilitaires fournis par **FastAPI** pour gĂ©rer cela. + +### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform } + +Tout d'abord, importez `OAuth2PasswordRequestForm`, et utilisez-la en tant que dĂ©pendance avec `Depends` dans le chemin d'accĂšs pour `/token` : + +{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *} + +`OAuth2PasswordRequestForm` est une dĂ©pendance de classe qui dĂ©clare un corps de formulaire avec : + +* Le `username`. +* Le `password`. +* Un champ optionnel `scope` sous forme d'une grande chaĂźne, composĂ©e de chaĂźnes sĂ©parĂ©es par des espaces. +* Un `grant_type` optionnel. + +/// tip | Astuce + +La spĂ©cification OAuth2 exige en rĂ©alitĂ© un champ `grant_type` avec la valeur fixe `password`, mais `OAuth2PasswordRequestForm` ne l'impose pas. + +Si vous avez besoin de l'imposer, utilisez `OAuth2PasswordRequestFormStrict` au lieu de `OAuth2PasswordRequestForm`. + +/// + +* Un `client_id` optionnel (nous n'en avons pas besoin pour notre exemple). +* Un `client_secret` optionnel (nous n'en avons pas besoin pour notre exemple). + +/// info + +La classe `OAuth2PasswordRequestForm` n'est pas une classe spĂ©ciale pour **FastAPI** comme l'est `OAuth2PasswordBearer`. + +`OAuth2PasswordBearer` indique Ă  **FastAPI** qu'il s'agit d'un schĂ©ma de sĂ©curitĂ©. Il est donc ajoutĂ© de cette façon Ă  OpenAPI. + +Mais `OAuth2PasswordRequestForm` est simplement une dĂ©pendance de classe que vous auriez pu Ă©crire vous‑mĂȘme, ou vous auriez pu dĂ©clarer des paramĂštres `Form` directement. + +Mais comme c'est un cas d'usage courant, elle est fournie directement par **FastAPI**, simplement pour vous faciliter la vie. + +/// + +### Utiliser les donnĂ©es du formulaire { #use-the-form-data } + +/// tip | Astuce + +L'instance de la classe de dĂ©pendance `OAuth2PasswordRequestForm` n'aura pas d'attribut `scope` contenant la longue chaĂźne sĂ©parĂ©e par des espaces ; elle aura plutĂŽt un attribut `scopes` avec la liste rĂ©elle des chaĂźnes pour chaque scope envoyĂ©. + +Nous n'utilisons pas `scopes` dans cet exemple, mais la fonctionnalitĂ© est disponible si vous en avez besoin. + +/// + +RĂ©cupĂ©rez maintenant les donnĂ©es utilisateur depuis la (fausse) base de donnĂ©es, en utilisant le `username` du champ de formulaire. + +S'il n'existe pas d'utilisateur, nous renvoyons une erreur indiquant « Incorrect username or password ». + +Pour l'erreur, nous utilisons l'exception `HTTPException` : + +{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *} + +### VĂ©rifier le mot de passe { #check-the-password } + +À ce stade, nous avons les donnĂ©es utilisateur depuis notre base, mais nous n'avons pas encore vĂ©rifiĂ© le mot de passe. + +Mettons d'abord ces donnĂ©es dans le modĂšle Pydantic `UserInDB`. + +Vous ne devez jamais enregistrer des mots de passe en clair ; nous allons donc utiliser le systĂšme (factice) de hachage de mot de passe. + +Si les mots de passe ne correspondent pas, nous renvoyons la mĂȘme erreur. + +#### Hachage de mot de passe { #password-hashing } + +Le « hachage » signifie : convertir un contenu (un mot de passe, dans ce cas) en une sĂ©quence d'octets (juste une chaĂźne) qui ressemble Ă  du charabia. + +Chaque fois que vous fournissez exactement le mĂȘme contenu (exactement le mĂȘme mot de passe), vous obtenez exactement le mĂȘme charabia. + +Mais vous ne pouvez pas convertir ce charabia pour retrouver le mot de passe. + +##### Pourquoi utiliser le hachage de mot de passe { #why-use-password-hashing } + +Si votre base de donnĂ©es est volĂ©e, le voleur n'aura pas les mots de passe en clair de vos utilisateurs, seulement les hachages. + +Ainsi, il ne pourra pas essayer d'utiliser ces mĂȘmes mots de passe dans un autre systĂšme (comme beaucoup d'utilisateurs utilisent le mĂȘme mot de passe partout, ce serait dangereux). + +{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *} + +#### À propos de `**user_dict` { #about-user-dict } + +`UserInDB(**user_dict)` signifie : + +Passez les clĂ©s et valeurs de `user_dict` directement comme arguments clé‑valeur, Ă©quivalent Ă  : + +```Python +UserInDB( + username = user_dict["username"], + email = user_dict["email"], + full_name = user_dict["full_name"], + disabled = user_dict["disabled"], + hashed_password = user_dict["hashed_password"], +) +``` + +/// info + +Pour une explication plus complĂšte de `**user_dict`, consultez [la documentation pour **ModĂšles supplĂ©mentaires**](../extra-models.md#about-user-in-dict){.internal-link target=_blank}. + +/// + +## Renvoyer le jeton { #return-the-token } + +La rĂ©ponse de l'endpoint `token` doit ĂȘtre un objet JSON. + +Il doit contenir un `token_type`. Dans notre cas, comme nous utilisons des jetons « Bearer », le type de jeton doit ĂȘtre « bearer ». + +Et il doit contenir un `access_token`, avec une chaĂźne contenant notre jeton d'accĂšs. + +Pour cet exemple simple, nous allons faire quelque chose de complĂštement non sĂ©curisĂ© et renvoyer le mĂȘme `username` comme jeton. + +/// tip | Astuce + +Dans le prochain chapitre, vous verrez une vĂ©ritable implĂ©mentation sĂ©curisĂ©e, avec du hachage de mot de passe et des jetons JWT. + +Mais pour l'instant, concentrons‑nous sur les dĂ©tails spĂ©cifiques dont nous avons besoin. + +/// + +{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *} + +/// tip | Astuce + +D'aprĂšs la spĂ©cification, vous devez renvoyer un JSON avec un `access_token` et un `token_type`, comme dans cet exemple. + +C'est quelque chose que vous devez faire vous‑mĂȘme dans votre code, et vous devez vous assurer d'utiliser ces clĂ©s JSON. + +C'est presque la seule chose que vous devez vous rappeler de faire correctement vous‑mĂȘme pour ĂȘtre conforme aux spĂ©cifications. + +Pour le reste, **FastAPI** s'en charge pour vous. + +/// + +## Mettre Ă  jour les dĂ©pendances { #update-the-dependencies } + +Nous allons maintenant mettre Ă  jour nos dĂ©pendances. + +Nous voulons obtenir `current_user` uniquement si cet utilisateur est actif. + +Nous crĂ©ons donc une dĂ©pendance supplĂ©mentaire `get_current_active_user` qui utilise Ă  son tour `get_current_user` comme dĂ©pendance. + +Ces deux dĂ©pendances renverront simplement une erreur HTTP si l'utilisateur n'existe pas, ou s'il est inactif. + +Ainsi, dans notre endpoint, nous n'obtiendrons un utilisateur que si l'utilisateur existe, a Ă©tĂ© correctement authentifiĂ© et est actif : + +{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *} + +/// info + +L'en‑tĂȘte supplĂ©mentaire `WWW-Authenticate` avec la valeur `Bearer` que nous renvoyons ici fait Ă©galement partie de la spĂ©cification. + +Il est prĂ©vu qu'un code d'Ă©tat HTTP (d'erreur) 401 « UNAUTHORIZED » renvoie Ă©galement un en‑tĂȘte `WWW-Authenticate`. + +Dans le cas des jetons bearer (notre cas), la valeur de cet en‑tĂȘte doit ĂȘtre `Bearer`. + +Vous pouvez en rĂ©alitĂ© omettre cet en‑tĂȘte supplĂ©mentaire et cela fonctionnerait quand mĂȘme. + +Mais il est fourni ici pour ĂȘtre conforme aux spĂ©cifications. + +De plus, il peut exister des outils qui l'attendent et l'utilisent (maintenant ou Ă  l'avenir) et cela pourrait vous ĂȘtre utile, Ă  vous ou Ă  vos utilisateurs, maintenant ou Ă  l'avenir. + +C'est l'avantage des standards ... + +/// + +## Voir en action { #see-it-in-action } + +Ouvrez la documentation interactive : http://127.0.0.1:8000/docs. + +### S'authentifier { #authenticate } + +Cliquez sur le bouton « Authorize ». + +Utilisez les identifiants : + +Utilisateur : `johndoe` + +Mot de passe : `secret` + + + +AprĂšs vous ĂȘtre authentifiĂ© dans le systĂšme, vous verrez ceci : + + + +### Obtenir vos propres donnĂ©es utilisateur { #get-your-own-user-data } + +Utilisez maintenant l'opĂ©ration `GET` avec le chemin `/users/me`. + +Vous obtiendrez les donnĂ©es de votre utilisateur, par exemple : + +```JSON +{ + "username": "johndoe", + "email": "johndoe@example.com", + "full_name": "John Doe", + "disabled": false, + "hashed_password": "fakehashedsecret" +} +``` + + + +Si vous cliquez sur l'icĂŽne de cadenas et vous vous dĂ©connectez, puis rĂ©essayez la mĂȘme opĂ©ration, vous obtiendrez une erreur HTTP 401 : + +```JSON +{ + "detail": "Not authenticated" +} +``` + +### Utilisateur inactif { #inactive-user } + +Essayez maintenant avec un utilisateur inactif, authentifiez‑vous avec : + +Utilisateur : `alice` + +Mot de passe : `secret2` + +Et essayez d'utiliser l'opĂ©ration `GET` avec le chemin `/users/me`. + +Vous obtiendrez une erreur « Inactive user », par exemple : + +```JSON +{ + "detail": "Inactive user" +} +``` + +## RĂ©capitulatif { #recap } + +Vous avez maintenant les outils pour implĂ©menter un systĂšme de sĂ©curitĂ© complet basĂ© sur `username` et `password` pour votre API. + +En utilisant ces outils, vous pouvez rendre le systĂšme de sĂ©curitĂ© compatible avec n'importe quelle base de donnĂ©es et avec n'importe quel modĂšle d'utilisateur ou de donnĂ©es. + +Le seul dĂ©tail manquant est qu'il n'est pas encore rĂ©ellement « sĂ©curisĂ© ». + +Dans le prochain chapitre, vous verrez comment utiliser une bibliothĂšque de hachage de mot de passe sĂ©curisĂ©e et des jetons JWT. diff --git a/docs/fr/docs/tutorial/sql-databases.md b/docs/fr/docs/tutorial/sql-databases.md new file mode 100644 index 000000000..75f9ae14f --- /dev/null +++ b/docs/fr/docs/tutorial/sql-databases.md @@ -0,0 +1,357 @@ +# Bases de donnĂ©es SQL (relationnelles) { #sql-relational-databases } + +**FastAPI** ne vous oblige pas Ă  utiliser une base de donnĂ©es SQL (relationnelle). Mais vous pouvez utiliser **n'importe quelle base de donnĂ©es** que vous voulez. + +Ici, nous allons voir un exemple utilisant SQLModel. + +**SQLModel** est construit au-dessus de SQLAlchemy et de Pydantic. Il a Ă©tĂ© créé par le mĂȘme auteur que **FastAPI** pour ĂȘtre l'accord parfait pour les applications FastAPI qui ont besoin d'utiliser des **bases de donnĂ©es SQL**. + +/// tip | Astuce + +Vous pouvez utiliser toute autre bibliothĂšque SQL ou NoSQL que vous voulez (dans certains cas appelĂ©es « ORMs »), FastAPI ne vous impose rien. 😎 + +/// + +Comme SQLModel est basĂ© sur SQLAlchemy, vous pouvez facilement utiliser **toute base prise en charge** par SQLAlchemy (ce qui les rend Ă©galement prises en charge par SQLModel), comme : + +* PostgreSQL +* MySQL +* SQLite +* Oracle +* Microsoft SQL Server, etc. + +Dans cet exemple, nous utiliserons **SQLite**, car il utilise un seul fichier et Python a un support intĂ©grĂ©. Ainsi, vous pouvez copier cet exemple et l'exĂ©cuter tel quel. + +Plus tard, pour votre application de production, vous voudrez peut-ĂȘtre utiliser un serveur de base de donnĂ©es comme **PostgreSQL**. + +/// tip | Astuce + +Il existe un gĂ©nĂ©rateur de projet officiel avec **FastAPI** et **PostgreSQL**, incluant un frontend et plus d'outils : https://github.com/fastapi/full-stack-fastapi-template + +/// + +Il s'agit d'un tutoriel trĂšs simple et court ; si vous souhaitez apprendre sur les bases de donnĂ©es en gĂ©nĂ©ral, sur SQL, ou des fonctionnalitĂ©s plus avancĂ©es, allez voir la documentation SQLModel. + +## Installer `SQLModel` { #install-sqlmodel } + +D'abord, assurez-vous de crĂ©er votre [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis d'installer `sqlmodel` : + +
+ +```console +$ pip install sqlmodel +---> 100% +``` + +
+ +## CrĂ©er l'application avec un modĂšle unique { #create-the-app-with-a-single-model } + +Nous allons d'abord crĂ©er la premiĂšre version la plus simple de l'application avec un seul modĂšle **SQLModel**. + +Ensuite, nous l'amĂ©liorerons en augmentant la sĂ©curitĂ© et la polyvalence avec **plusieurs modĂšles** ci-dessous. đŸ€“ + +### CrĂ©er les modĂšles { #create-models } + +Importez `SQLModel` et crĂ©ez un modĂšle de base de donnĂ©es : + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *} + +La classe `Hero` est trĂšs similaire Ă  un modĂšle Pydantic (en fait, en dessous, c'est rĂ©ellement un modĂšle Pydantic). + +Il y a quelques diffĂ©rences : + +* `table=True` indique Ă  SQLModel qu'il s'agit d'un *modĂšle de table*, il doit reprĂ©senter une **table** dans la base SQL, ce n'est pas seulement un *modĂšle de donnĂ©es* (comme le serait n'importe quelle autre classe Pydantic classique). + +* `Field(primary_key=True)` indique Ă  SQLModel que `id` est la **clĂ© primaire** dans la base SQL (vous pouvez en savoir plus sur les clĂ©s primaires SQL dans la documentation SQLModel). + + Remarque : nous utilisons `int | None` pour le champ clĂ© primaire afin qu'en Python nous puissions *crĂ©er un objet sans `id`* (`id=None`), en supposant que la base *le gĂ©nĂšre Ă  l'enregistrement*. SQLModel comprend que la base fournira l'`id` et *dĂ©finit la colonne comme un `INTEGER` non nul* dans le schĂ©ma de base. Voir la documentation SQLModel sur les clĂ©s primaires pour plus de dĂ©tails. + +* `Field(index=True)` indique Ă  SQLModel qu'il doit crĂ©er un **index SQL** pour cette colonne, ce qui permettra des recherches plus rapides dans la base lors de la lecture de donnĂ©es filtrĂ©es par cette colonne. + + SQLModel saura que quelque chose dĂ©clarĂ© comme `str` sera une colonne SQL de type `TEXT` (ou `VARCHAR`, selon la base). + +### CrĂ©er un engine { #create-an-engine } + +Un `engine` SQLModel (en dessous c'est en fait un `engine` SQLAlchemy) est ce qui **dĂ©tient les connexions** Ă  la base de donnĂ©es. + +Vous devez avoir **un seul objet `engine`** pour tout votre code afin de se connecter Ă  la mĂȘme base. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *} + +L'utilisation de `check_same_thread=False` permet Ă  FastAPI d'utiliser la mĂȘme base SQLite dans diffĂ©rents threads. C'est nĂ©cessaire car **une seule requĂȘte** peut utiliser **plus d'un thread** (par exemple dans des dĂ©pendances). + +Ne vous inquiĂ©tez pas, avec la structure du code, nous nous assurerons d'utiliser **une seule *session* SQLModel par requĂȘte** plus loin, c'est en fait ce que `check_same_thread` essaie d'assurer. + +### CrĂ©er les tables { #create-the-tables } + +Nous ajoutons ensuite une fonction qui utilise `SQLModel.metadata.create_all(engine)` pour **crĂ©er les tables** pour tous les *modĂšles de table*. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *} + +### CrĂ©er une dĂ©pendance de session { #create-a-session-dependency } + +Une **`Session`** est ce qui stocke les **objets en mĂ©moire** et suit les modifications nĂ©cessaires des donnĂ©es, puis **utilise l'`engine`** pour communiquer avec la base. + +Nous allons crĂ©er une **dĂ©pendance** FastAPI avec `yield` qui fournira une nouvelle `Session` pour chaque requĂȘte. C'est ce qui garantit que nous utilisons une seule session par requĂȘte. đŸ€“ + +Puis nous crĂ©ons une dĂ©pendance `Annotated` `SessionDep` pour simplifier le reste du code qui utilisera cette dĂ©pendance. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *} + +### CrĂ©er les tables de base au dĂ©marrage { #create-database-tables-on-startup } + +Nous allons crĂ©er les tables de base de donnĂ©es au dĂ©marrage de l'application. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *} + +Ici, nous crĂ©ons les tables lors d'un Ă©vĂ©nement de dĂ©marrage de l'application. + +En production, vous utiliseriez probablement un script de migration qui s'exĂ©cute avant de dĂ©marrer votre application. đŸ€“ + +/// tip | Astuce + +SQLModel aura des utilitaires de migration enveloppant Alembic, mais pour l'instant, vous pouvez utiliser Alembic directement. + +/// + +### CrĂ©er un hĂ©ros { #create-a-hero } + +Comme chaque modĂšle SQLModel est aussi un modĂšle Pydantic, vous pouvez l'utiliser dans les mĂȘmes **annotations de type** que vous utiliseriez pour des modĂšles Pydantic. + +Par exemple, si vous dĂ©clarez un paramĂštre de type `Hero`, il sera lu depuis le **corps JSON**. + +De la mĂȘme maniĂšre, vous pouvez le dĂ©clarer comme **type de retour** de la fonction, et alors la forme des donnĂ©es apparaĂźtra dans l'UI automatique de documentation de l'API. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *} + +Ici, nous utilisons la dĂ©pendance `SessionDep` (une `Session`) pour ajouter le nouveau `Hero` Ă  l'instance de `Session`, valider les changements dans la base, rafraĂźchir les donnĂ©es dans `hero`, puis le retourner. + +### Lire les hĂ©ros { #read-heroes } + +Nous pouvons **lire** des `Hero` depuis la base en utilisant un `select()`. Nous pouvons inclure une `limit` et un `offset` pour paginer les rĂ©sultats. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *} + +### Lire un hĂ©ros { #read-one-hero } + +Nous pouvons **lire** un seul `Hero`. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *} + +### Supprimer un hĂ©ros { #delete-a-hero } + +Nous pouvons aussi **supprimer** un `Hero`. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *} + +### ExĂ©cuter l'application { #run-the-app } + +Vous pouvez exĂ©cuter l'application : + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Ensuite, allez sur l'UI `/docs`, vous verrez que **FastAPI** utilise ces **modÚles** pour **documenter** l'API, et les utilisera aussi pour **sérialiser** et **valider** les données. + +
+ +
+ +## Mettre Ă  jour l'application avec plusieurs modĂšles { #update-the-app-with-multiple-models } + +Maintenant, **refactorisons** un peu cette application pour augmenter la **sĂ©curitĂ©** et la **polyvalence**. + +Si vous vĂ©rifiez l'application prĂ©cĂ©dente, dans l'UI vous pouvez voir que, jusqu'Ă  prĂ©sent, elle laisse le client dĂ©cider de l'`id` du `Hero` Ă  crĂ©er. đŸ˜± + +Nous ne devrions pas laisser cela se produire, ils pourraient Ă©craser un `id` que nous avons dĂ©jĂ  attribuĂ© dans la base. DĂ©cider de l'`id` doit ĂȘtre fait par le **backend** ou la **base**, **pas par le client**. + +De plus, nous crĂ©ons un `secret_name` pour le hĂ©ros, mais jusqu'ici, nous le renvoyons partout, ce n'est pas trĂšs « secret » ... 😅 + +Nous allons corriger ces choses en ajoutant quelques **modĂšles supplĂ©mentaires**. C'est lĂ  que SQLModel brille. ✹ + +### CrĂ©er plusieurs modĂšles { #create-multiple-models } + +Dans **SQLModel**, toute classe de modĂšle qui a `table=True` est un **modĂšle de table**. + +Et toute classe de modĂšle qui n'a pas `table=True` est un **modĂšle de donnĂ©es**, ceux-ci sont en rĂ©alitĂ© juste des modĂšles Pydantic (avec deux petites fonctionnalitĂ©s en plus). đŸ€“ + +Avec SQLModel, nous pouvons utiliser **l'hĂ©ritage** pour **Ă©viter de dupliquer** tous les champs dans tous les cas. + +#### `HeroBase` - la classe de base { #herobase-the-base-class } + +Commençons avec un modĂšle `HeroBase` qui a tous les **champs partagĂ©s** par tous les modĂšles : + +* `name` +* `age` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *} + +#### `Hero` - le *modĂšle de table* { #hero-the-table-model } + +CrĂ©ons ensuite `Hero`, le *modĂšle de table* proprement dit, avec les **champs supplĂ©mentaires** qui ne sont pas toujours dans les autres modĂšles : + +* `id` +* `secret_name` + +Comme `Hero` hĂ©rite de `HeroBase`, il **a aussi** les **champs** dĂ©clarĂ©s dans `HeroBase`, donc tous les champs de `Hero` sont : + +* `id` +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *} + +#### `HeroPublic` - le *modĂšle de donnĂ©es* public { #heropublic-the-public-data-model } + +Ensuite, nous crĂ©ons un modĂšle `HeroPublic`, c'est celui qui sera **retournĂ©** aux clients de l'API. + +Il a les mĂȘmes champs que `HeroBase`, il n'inclura donc pas `secret_name`. + +Enfin, l'identitĂ© de nos hĂ©ros est protĂ©gĂ©e ! đŸ„· + +Il redĂ©clare aussi `id: int`. Ce faisant, nous faisons un **contrat** avec les clients de l'API, afin qu'ils puissent toujours s'attendre Ă  ce que `id` soit prĂ©sent et soit un `int` (il ne sera jamais `None`). + +/// tip | Astuce + +Avoir le modĂšle de retour qui garantit qu'une valeur est toujours disponible et toujours `int` (pas `None`) est trĂšs utile pour les clients de l'API, ils peuvent Ă©crire un code beaucoup plus simple avec cette certitude. + +De plus, les **clients gĂ©nĂ©rĂ©s automatiquement** auront des interfaces plus simples, afin que les dĂ©veloppeurs qui communiquent avec votre API puissent travailler bien plus facilement avec votre API. 😎 + +/// + +Tous les champs de `HeroPublic` sont les mĂȘmes que dans `HeroBase`, avec `id` dĂ©clarĂ© comme `int` (pas `None`) : + +* `id` +* `name` +* `age` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *} + +#### `HeroCreate` - le *modĂšle de donnĂ©es* pour crĂ©er un hĂ©ros { #herocreate-the-data-model-to-create-a-hero } + +Nous crĂ©ons maintenant un modĂšle `HeroCreate`, c'est celui qui **validera** les donnĂ©es provenant des clients. + +Il a les mĂȘmes champs que `HeroBase`, et il a aussi `secret_name`. + +Maintenant, lorsque les clients **crĂ©ent un nouveau hĂ©ros**, ils enverront `secret_name`, il sera stockĂ© dans la base, mais ces noms secrets ne seront pas renvoyĂ©s dans l'API aux clients. + +/// tip | Astuce + +C'est ainsi que vous gĂ©reriez les **mots de passe**. Les recevoir, mais ne pas les renvoyer dans l'API. + +Vous **hacherez** aussi les valeurs des mots de passe avant de les stocker, **ne les stockez jamais en texte en clair**. + +/// + +Les champs de `HeroCreate` sont : + +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *} + +#### `HeroUpdate` - le *modĂšle de donnĂ©es* pour mettre Ă  jour un hĂ©ros { #heroupdate-the-data-model-to-update-a-hero } + +Nous n'avions pas de moyen de **mettre Ă  jour un hĂ©ros** dans la version prĂ©cĂ©dente de l'application, mais maintenant avec **plusieurs modĂšles**, nous pouvons le faire. 🎉 + +Le *modĂšle de donnĂ©es* `HeroUpdate` est un peu spĂ©cial, il a **tous les mĂȘmes champs** qui seraient nĂ©cessaires pour crĂ©er un nouveau hĂ©ros, mais tous les champs sont **optionnels** (ils ont tous une valeur par dĂ©faut). Ainsi, lorsque vous mettez Ă  jour un hĂ©ros, vous pouvez n'envoyer que les champs que vous souhaitez mettre Ă  jour. + +Comme tous les **champs changent rĂ©ellement** (le type inclut dĂ©sormais `None` et ils ont maintenant une valeur par dĂ©faut de `None`), nous devons les **redĂ©clarer**. + +Nous n'avons pas vraiment besoin d'hĂ©riter de `HeroBase` puisque nous redĂ©clarons tous les champs. Je le laisse hĂ©riter juste pour la cohĂ©rence, mais ce n'est pas nĂ©cessaire. C'est plutĂŽt une question de goĂ»t personnel. đŸ€· + +Les champs de `HeroUpdate` sont : + +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *} + +### CrĂ©er avec `HeroCreate` et retourner un `HeroPublic` { #create-with-herocreate-and-return-a-heropublic } + +Maintenant que nous avons **plusieurs modĂšles**, nous pouvons mettre Ă  jour les parties de l'application qui les utilisent. + +Nous recevons dans la requĂȘte un *modĂšle de donnĂ©es* `HeroCreate`, et Ă  partir de celui-ci, nous crĂ©ons un *modĂšle de table* `Hero`. + +Ce nouveau *modĂšle de table* `Hero` aura les champs envoyĂ©s par le client, et aura aussi un `id` gĂ©nĂ©rĂ© par la base. + +Nous retournons ensuite le mĂȘme *modĂšle de table* `Hero` tel quel depuis la fonction. Mais comme nous dĂ©clarons le `response_model` avec le *modĂšle de donnĂ©es* `HeroPublic`, **FastAPI** utilisera `HeroPublic` pour valider et sĂ©rialiser les donnĂ©es. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *} + +/// tip | Astuce + +Nous utilisons maintenant `response_model=HeroPublic` au lieu de l'**annotation de type de retour** `-> HeroPublic` car la valeur que nous renvoyons n'est en rĂ©alitĂ© *pas* un `HeroPublic`. + +Si nous avions dĂ©clarĂ© `-> HeroPublic`, votre Ă©diteur et votre linter se plaindraient (Ă  juste titre) que vous retournez un `Hero` au lieu d'un `HeroPublic`. + +En le dĂ©clarant dans `response_model`, nous disons Ă  **FastAPI** de faire son travail, sans interfĂ©rer avec les annotations de type et l'aide de votre Ă©diteur et d'autres outils. + +/// + +### Lire des hĂ©ros avec `HeroPublic` { #read-heroes-with-heropublic } + +Nous pouvons faire la mĂȘme chose qu'avant pour **lire** des `Hero`, Ă  nouveau, nous utilisons `response_model=list[HeroPublic]` pour garantir que les donnĂ©es sont correctement validĂ©es et sĂ©rialisĂ©es. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *} + +### Lire un hĂ©ros avec `HeroPublic` { #read-one-hero-with-heropublic } + +Nous pouvons **lire** un hĂ©ros unique : + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *} + +### Mettre Ă  jour un hĂ©ros avec `HeroUpdate` { #update-a-hero-with-heroupdate } + +Nous pouvons **mettre Ă  jour un hĂ©ros**. Pour cela, nous utilisons une opĂ©ration HTTP `PATCH`. + +Et dans le code, nous obtenons un `dict` avec toutes les donnĂ©es envoyĂ©es par le client, **uniquement les donnĂ©es envoyĂ©es par le client**, en excluant toute valeur qui serait lĂ  simplement parce que c'est la valeur par dĂ©faut. Pour ce faire, nous utilisons `exclude_unset=True`. C'est l'astuce principale. đŸȘ„ + +Nous utilisons ensuite `hero_db.sqlmodel_update(hero_data)` pour mettre Ă  jour `hero_db` avec les donnĂ©es de `hero_data`. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *} + +### Supprimer un hĂ©ros (bis) { #delete-a-hero-again } + +**Supprimer** un hĂ©ros reste pratiquement identique. + +Nous n'allons pas cĂ©der Ă  l'envie de tout refactoriser pour celui-ci. 😅 + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *} + +### ExĂ©cuter l'application Ă  nouveau { #run-the-app-again } + +Vous pouvez exĂ©cuter l'application Ă  nouveau : + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Si vous allez sur l'UI `/docs` de l'API, vous verrez qu'elle est maintenant à jour, et qu'elle n'attendra plus de recevoir l'`id` du client lors de la création d'un héros, etc. + +
+ +
+ +## RĂ©capitulatif { #recap } + +Vous pouvez utiliser **SQLModel** pour interagir avec une base SQL et simplifier le code avec des *modĂšles de donnĂ©es* et des *modĂšles de table*. + +Vous pouvez en apprendre beaucoup plus dans la documentation **SQLModel**, il y a un mini tutoriel plus long sur l'utilisation de SQLModel avec **FastAPI**. 🚀 diff --git a/docs/fr/docs/tutorial/static-files.md b/docs/fr/docs/tutorial/static-files.md new file mode 100644 index 000000000..3928fed9b --- /dev/null +++ b/docs/fr/docs/tutorial/static-files.md @@ -0,0 +1,40 @@ +# Fichiers statiques { #static-files } + +Vous pouvez servir des fichiers statiques automatiquement Ă  partir d'un rĂ©pertoire en utilisant `StaticFiles`. + +## Utiliser `StaticFiles` { #use-staticfiles } + +- Importer `StaticFiles`. +- « Mount » une instance `StaticFiles()` sur un chemin spĂ©cifique. + +{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *} + +/// note | DĂ©tails techniques + +Vous pouvez Ă©galement utiliser `from starlette.staticfiles import StaticFiles`. + +**FastAPI** fournit le mĂȘme `starlette.staticfiles` sous le nom `fastapi.staticfiles` uniquement pour votre commoditĂ©, en tant que dĂ©veloppeur. Mais cela provient en rĂ©alitĂ© directement de Starlette. + +/// + +### Qu'est-ce que « Mounting » { #what-is-mounting } + +« Mounting » signifie ajouter une application complĂšte « indĂ©pendante » sur un chemin spĂ©cifique, qui se chargera ensuite de gĂ©rer tous les sous-chemins. + +Cela diffĂšre de l'utilisation d'un `APIRouter`, car une application montĂ©e est complĂštement indĂ©pendante. L'OpenAPI et les documents de votre application principale n'incluront rien provenant de l'application montĂ©e, etc. + +Vous pouvez en lire davantage Ă  ce sujet dans le [Guide utilisateur avancĂ©](../advanced/index.md){.internal-link target=_blank}. + +## DĂ©tails { #details } + +Le premier `"/static"` fait rĂ©fĂ©rence au sous-chemin sur lequel cette « sous-application » sera « montĂ©e ». Ainsi, tout chemin qui commence par `"/static"` sera gĂ©rĂ© par elle. + +Le `directory="static"` fait rĂ©fĂ©rence au nom du rĂ©pertoire qui contient vos fichiers statiques. + +Le `name="static"` lui donne un nom utilisable en interne par **FastAPI**. + +Tous ces paramĂštres peuvent ĂȘtre diffĂ©rents de « `static` », adaptez-les aux besoins et aux dĂ©tails spĂ©cifiques de votre propre application. + +## Plus d'informations { #more-info } + +Pour plus de dĂ©tails et d'options, consultez la documentation de Starlette sur les fichiers statiques. diff --git a/docs/fr/docs/tutorial/testing.md b/docs/fr/docs/tutorial/testing.md new file mode 100644 index 000000000..8a609b644 --- /dev/null +++ b/docs/fr/docs/tutorial/testing.md @@ -0,0 +1,193 @@ +# Tester { #testing } + +GrĂące Ă  Starlette, tester des applications **FastAPI** est simple et agrĂ©able. + +C’est basĂ© sur HTTPX, dont la conception s’inspire de Requests, ce qui le rend trĂšs familier et intuitif. + +Avec cela, vous pouvez utiliser pytest directement avec **FastAPI**. + +## Utiliser `TestClient` { #using-testclient } + +/// info + +Pour utiliser `TestClient`, installez d’abord `httpx`. + +Vous devez crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l’activer, puis y installer le paquet, par exemple : + +```console +$ pip install httpx +``` + +/// + +Importez `TestClient`. + +CrĂ©ez un `TestClient` en lui passant votre application **FastAPI**. + +CrĂ©ez des fonctions dont le nom commence par `test_` (c’est la convention standard de `pytest`). + +Utilisez l’objet `TestClient` de la mĂȘme maniĂšre que vous utilisez `httpx`. + +Écrivez de simples instructions `assert` avec les expressions Python standard que vous devez vĂ©rifier (lĂ  encore, standard `pytest`). + +{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *} + +/// tip | Astuce + +Remarquez que les fonctions de test sont des `def` normales, pas des `async def`. + +Et les appels au client sont aussi des appels normaux, sans utiliser `await`. + +Cela vous permet d’utiliser `pytest` directement sans complications. + +/// + +/// note | DĂ©tails techniques + +Vous pouvez aussi utiliser `from starlette.testclient import TestClient`. + +**FastAPI** fournit le mĂȘme `starlette.testclient` sous le nom `fastapi.testclient` uniquement pour votre commoditĂ©, en tant que dĂ©veloppeur. Mais cela vient directement de Starlette. + +/// + +/// tip | Astuce + +Si vous souhaitez appeler des fonctions `async` dans vos tests en dehors de l’envoi de requĂȘtes Ă  votre application FastAPI (par exemple des fonctions de base de donnĂ©es asynchrones), consultez les [Tests asynchrones](../advanced/async-tests.md){.internal-link target=_blank} dans le tutoriel avancĂ©. + +/// + +## SĂ©parer les tests { #separating-tests } + +Dans une application rĂ©elle, vous auriez probablement vos tests dans un fichier diffĂ©rent. + +Et votre application **FastAPI** pourrait aussi ĂȘtre composĂ©e de plusieurs fichiers/modules, etc. + +### Fichier d’application **FastAPI** { #fastapi-app-file } + +Supposons que vous ayez une structure de fichiers comme dĂ©crit dans [Applications plus grandes](bigger-applications.md){.internal-link target=_blank} : + +``` +. +├── app +│   ├── __init__.py +│   └── main.py +``` + +Dans le fichier `main.py`, vous avez votre application **FastAPI** : + + +{* ../../docs_src/app_testing/app_a_py310/main.py *} + +### Fichier de test { #testing-file } + +Vous pourriez alors avoir un fichier `test_main.py` avec vos tests. Il pourrait vivre dans le mĂȘme package Python (le mĂȘme rĂ©pertoire avec un fichier `__init__.py`) : + +``` hl_lines="5" +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +Comme ce fichier se trouve dans le mĂȘme package, vous pouvez utiliser des imports relatifs pour importer l’objet `app` depuis le module `main` (`main.py`) : + +{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *} + + +
 et avoir le code des tests comme prĂ©cĂ©demment. + +## Tester : exemple Ă©tendu { #testing-extended-example } + +Étendons maintenant cet exemple et ajoutons plus de dĂ©tails pour voir comment tester diffĂ©rentes parties. + +### Fichier d’application **FastAPI** Ă©tendu { #extended-fastapi-app-file } + +Continuons avec la mĂȘme structure de fichiers qu’auparavant : + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +Supposons que dĂ©sormais le fichier `main.py` avec votre application **FastAPI** contienne d’autres **chemins d’accĂšs**. + +Il a une opĂ©ration `GET` qui pourrait renvoyer une erreur. + +Il a une opĂ©ration `POST` qui pourrait renvoyer plusieurs erreurs. + +Les deux chemins d’accĂšs requiĂšrent un en-tĂȘte `X-Token`. + +{* ../../docs_src/app_testing/app_b_an_py310/main.py *} + +### Fichier de test Ă©tendu { #extended-testing-file } + +Vous pourriez ensuite mettre Ă  jour `test_main.py` avec les tests Ă©tendus : + +{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *} + + +Chaque fois que vous avez besoin que le client transmette des informations dans la requĂȘte et que vous ne savez pas comment faire, vous pouvez chercher (Google) comment le faire avec `httpx`, ou mĂȘme comment le faire avec `requests`, puisque la conception de HTTPX est basĂ©e sur celle de Requests. + +Ensuite, vous faites simplement la mĂȘme chose dans vos tests. + +Par exemple : + +* Pour passer un paramĂštre de chemin ou un paramĂštre de requĂȘte, ajoutez-le directement Ă  l’URL. +* Pour passer un corps JSON, passez un objet Python (par exemple un `dict`) au paramĂštre `json`. +* Si vous devez envoyer des *Form Data* au lieu de JSON, utilisez le paramĂštre `data` Ă  la place. +* Pour passer des en-tĂȘtes, utilisez un `dict` dans le paramĂštre `headers`. +* Pour les cookies, un `dict` dans le paramĂštre `cookies`. + +Pour plus d’informations sur la maniĂšre de transmettre des donnĂ©es au backend (en utilisant `httpx` ou le `TestClient`), consultez la documentation HTTPX. + +/// info + +Notez que le `TestClient` reçoit des donnĂ©es qui peuvent ĂȘtre converties en JSON, pas des modĂšles Pydantic. + +Si vous avez un modĂšle Pydantic dans votre test et que vous souhaitez envoyer ses donnĂ©es Ă  l’application pendant les tests, vous pouvez utiliser le `jsonable_encoder` dĂ©crit dans [Encodeur compatible JSON](encoder.md){.internal-link target=_blank}. + +/// + +## ExĂ©cuter { #run-it } + +AprĂšs cela, vous avez simplement besoin d’installer `pytest`. + +Vous devez crĂ©er un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l’activer, puis y installer le paquet, par exemple : + +
+ +```console +$ pip install pytest + +---> 100% +``` + +
+ +Il détectera automatiquement les fichiers et les tests, les exécutera et vous communiquera les résultats. + +Exécutez les tests avec : + +
+ +```console +$ pytest + +================ test session starts ================ +platform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 +rootdir: /home/user/code/superawesome-cli/app +plugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1 +collected 6 items + +---> 100% + +test_main.py ...... [100%] + +================= 1 passed in 0.03s ================= +``` + +
diff --git a/docs/fr/docs/virtual-environments.md b/docs/fr/docs/virtual-environments.md new file mode 100644 index 000000000..86b5faadc --- /dev/null +++ b/docs/fr/docs/virtual-environments.md @@ -0,0 +1,864 @@ +# Environnements virtuels { #virtual-environments } + +Lorsque vous travaillez sur des projets Python, vous devriez probablement utiliser un environnement virtuel (ou un mĂ©canisme similaire) pour isoler les packages que vous installez pour chaque projet. + +/// info + +Si vous connaissez dĂ©jĂ  les environnements virtuels, comment les crĂ©er et les utiliser, vous pouvez passer cette section. đŸ€“ + +/// + +/// tip | Astuce + +Un environnement virtuel est diffĂ©rent d’une variable d’environnement. + +Une variable d’environnement est une variable du systĂšme qui peut ĂȘtre utilisĂ©e par des programmes. + +Un environnement virtuel est un rĂ©pertoire contenant certains fichiers. + +/// + +/// info + +Cette page vous apprendra Ă  utiliser les environnements virtuels et Ă  comprendre leur fonctionnement. + +Si vous ĂȘtes prĂȘt Ă  adopter un outil qui gĂšre tout pour vous (y compris l’installation de Python), essayez uv. + +/// + +## CrĂ©er un projet { #create-a-project } + +Commencez par crĂ©er un rĂ©pertoire pour votre projet. + +Ce que je fais gĂ©nĂ©ralement, c’est crĂ©er un rĂ©pertoire nommĂ© `code` dans mon rĂ©pertoire personnel/utilisateur. + +Et Ă  l’intĂ©rieur, je crĂ©e un rĂ©pertoire par projet. + +
+ +```console +// Aller au répertoire personnel +$ cd +// Créer un répertoire pour tous vos projets de code +$ mkdir code +// Entrer dans ce répertoire code +$ cd code +// Créer un répertoire pour ce projet +$ mkdir awesome-project +// Entrer dans ce répertoire de projet +$ cd awesome-project +``` + +
+ +## CrĂ©er un environnement virtuel { #create-a-virtual-environment } + +Lorsque vous commencez Ă  travailler sur un projet Python pour la premiĂšre fois, crĂ©ez un environnement virtuel dans votre projet. + +/// tip | Astuce + +Vous n’avez besoin de faire cela qu’une seule fois par projet, pas Ă  chaque fois que vous travaillez. + +/// + +//// tab | `venv` + +Pour crĂ©er un environnement virtuel, vous pouvez utiliser le module `venv` fourni avec Python. + +
+ +```console +$ python -m venv .venv +``` + +
+ +/// details | Que signifie cette commande + +* `python` : utiliser le programme nommĂ© `python` +* `-m` : appeler un module comme un script, nous prĂ©ciserons ensuite quel module +* `venv` : utiliser le module nommĂ© `venv` qui est normalement installĂ© avec Python +* `.venv` : crĂ©er l’environnement virtuel dans le nouveau rĂ©pertoire `.venv` + +/// + +//// + +//// tab | `uv` + +Si vous avez installĂ© `uv`, vous pouvez l’utiliser pour crĂ©er un environnement virtuel. + +
+ +```console +$ uv venv +``` + +
+ +/// tip | Astuce + +Par dĂ©faut, `uv` crĂ©era un environnement virtuel dans un rĂ©pertoire appelĂ© `.venv`. + +Mais vous pouvez le personnaliser en passant un argument supplĂ©mentaire avec le nom du rĂ©pertoire. + +/// + +//// + +Cette commande crĂ©e un nouvel environnement virtuel dans un rĂ©pertoire appelĂ© `.venv`. + +/// details | `.venv` ou autre nom + +Vous pourriez crĂ©er l’environnement virtuel dans un autre rĂ©pertoire, mais il est d’usage de l’appeler `.venv`. + +/// + +## Activer l’environnement virtuel { #activate-the-virtual-environment } + +Activez le nouvel environnement virtuel afin que toute commande Python que vous exĂ©cutez ou tout package que vous installez l’utilise. + +/// tip | Astuce + +Faites cela Ă  chaque fois que vous dĂ©marrez une nouvelle session de terminal pour travailler sur le projet. + +/// + +//// tab | Linux, macOS + +
+ +```console +$ source .venv/bin/activate +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ .venv\Scripts\Activate.ps1 +``` + +
+ +//// + +//// tab | Windows Bash + +Ou si vous utilisez Bash pour Windows (par exemple Git Bash) : + +
+ +```console +$ source .venv/Scripts/activate +``` + +
+ +//// + +/// tip | Astuce + +Chaque fois que vous installez un nouveau package dans cet environnement, activez de nouveau l’environnement. + +Vous vous assurez ainsi que si vous utilisez un programme de terminal (CLI) installĂ© par ce package, vous utilisez celui de votre environnement virtuel et non un autre qui pourrait ĂȘtre installĂ© globalement, probablement avec une version diffĂ©rente de celle dont vous avez besoin. + +/// + +## VĂ©rifier que l’environnement virtuel est actif { #check-the-virtual-environment-is-active } + +VĂ©rifiez que l’environnement virtuel est actif (la commande prĂ©cĂ©dente a fonctionnĂ©). + +/// tip | Astuce + +C’est facultatif, mais c’est une bonne maniĂšre de vĂ©rifier que tout fonctionne comme prĂ©vu et que vous utilisez l’environnement virtuel voulu. + +/// + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +$ which python + +/home/user/code/awesome-project/.venv/bin/python +``` + +
+ +S’il affiche le binaire `python` Ă  `.venv/bin/python`, dans votre projet (dans cet exemple `awesome-project`), alors cela a fonctionnĂ©. 🎉 + +//// + +//// tab | Windows PowerShell + +
+ +```console +$ Get-Command python + +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +
+ +S’il affiche le binaire `python` Ă  `.venv\Scripts\python`, dans votre projet (dans cet exemple `awesome-project`), alors cela a fonctionnĂ©. 🎉 + +//// + +## Mettre Ă  niveau `pip` { #upgrade-pip } + +/// tip | Astuce + +Si vous utilisez `uv`, vous l’utiliserez pour installer des Ă©lĂ©ments Ă  la place de `pip`, vous n’avez donc pas besoin de mettre `pip` Ă  niveau. 😎 + +/// + +Si vous utilisez `pip` pour installer des packages (il est fourni par dĂ©faut avec Python), vous devez le mettre Ă  niveau vers la derniĂšre version. + +Beaucoup d’erreurs exotiques lors de l’installation d’un package se rĂ©solvent simplement en mettant d’abord `pip` Ă  niveau. + +/// tip | Astuce + +Vous feriez normalement cela une seule fois, juste aprĂšs avoir créé l’environnement virtuel. + +/// + +Vous devez vous assurer que l’environnement virtuel est actif (avec la commande ci-dessus), puis exĂ©cuter : + +
+ +```console +$ python -m pip install --upgrade pip + +---> 100% +``` + +
+ +/// tip | Astuce + +Parfois, vous pourriez obtenir une erreur **`No module named pip`** en essayant de mettre Ă  niveau pip. + +Si cela arrive, installez et mettez Ă  niveau pip avec la commande ci-dessous : + +
+ +```console +$ python -m ensurepip --upgrade + +---> 100% +``` + +
+ +Cette commande installera pip s’il n’est pas dĂ©jĂ  installĂ© et garantit aussi que la version de pip installĂ©e est au moins aussi rĂ©cente que celle disponible dans `ensurepip`. + +/// + +## Ajouter `.gitignore` { #add-gitignore } + +Si vous utilisez Git (vous devriez), ajoutez un fichier `.gitignore` pour exclure tout ce qui se trouve dans votre `.venv` de Git. + +/// tip | Astuce + +Si vous avez utilisĂ© `uv` pour crĂ©er l’environnement virtuel, il l’a dĂ©jĂ  fait pour vous, vous pouvez passer cette Ă©tape. 😎 + +/// + +/// tip | Astuce + +Faites cela une seule fois, juste aprĂšs avoir créé l’environnement virtuel. + +/// + +
+ +```console +$ echo "*" > .venv/.gitignore +``` + +
+ +/// details | Que signifie cette commande + +* `echo "*"` : va « afficher » le texte `*` dans le terminal (la partie suivante change un peu cela) +* `>` : tout ce qui est affichĂ© dans le terminal par la commande Ă  gauche de `>` ne doit pas ĂȘtre affichĂ© mais Ă©crit dans le fichier Ă  droite de `>` +* `.gitignore` : le nom du fichier dans lequel le texte doit ĂȘtre Ă©crit + +Et `*` signifie pour Git « tout ». Ainsi, il ignorera tout dans le rĂ©pertoire `.venv`. + +Cette commande crĂ©era un fichier `.gitignore` avec le contenu : + +```gitignore +* +``` + +/// + +## Installer des packages { #install-packages } + +AprĂšs avoir activĂ© l’environnement, vous pouvez y installer des packages. + +/// tip | Astuce + +Faites cela une seule fois lorsque vous installez ou mettez Ă  niveau les packages nĂ©cessaires Ă  votre projet. + +Si vous devez mettre Ă  niveau une version ou ajouter un nouveau package, vous le referez. + +/// + +### Installer des packages directement { #install-packages-directly } + +Si vous ĂȘtes pressĂ© et ne souhaitez pas utiliser un fichier pour dĂ©clarer les dĂ©pendances de votre projet, vous pouvez les installer directement. + +/// tip | Astuce + +C’est une trĂšs bonne idĂ©e de placer les packages et leurs versions nĂ©cessaires Ă  votre programme dans un fichier (par exemple `requirements.txt` ou `pyproject.toml`). + +/// + +//// tab | `pip` + +
+ +```console +$ pip install "fastapi[standard]" + +---> 100% +``` + +
+ +//// + +//// tab | `uv` + +Si vous avez `uv` : + +
+ +```console +$ uv pip install "fastapi[standard]" +---> 100% +``` + +
+ +//// + +### Installer depuis `requirements.txt` { #install-from-requirements-txt } + +Si vous avez un `requirements.txt`, vous pouvez maintenant l’utiliser pour installer ses packages. + +//// tab | `pip` + +
+ +```console +$ pip install -r requirements.txt +---> 100% +``` + +
+ +//// + +//// tab | `uv` + +Si vous avez `uv` : + +
+ +```console +$ uv pip install -r requirements.txt +---> 100% +``` + +
+ +//// + +/// details | `requirements.txt` + +Un `requirements.txt` avec quelques packages pourrait ressembler Ă  : + +```requirements.txt +fastapi[standard]==0.113.0 +pydantic==2.8.0 +``` + +/// + +## ExĂ©cuter votre programme { #run-your-program } + +AprĂšs avoir activĂ© l’environnement virtuel, vous pouvez exĂ©cuter votre programme, et il utilisera le Python de votre environnement virtuel avec les packages que vous y avez installĂ©s. + +
+ +```console +$ python main.py + +Hello World +``` + +
+ +## Configurer votre Ă©diteur { #configure-your-editor } + +Vous utiliserez probablement un Ă©diteur, assurez-vous de le configurer pour utiliser le mĂȘme environnement virtuel que vous avez créé (il le dĂ©tectera probablement automatiquement) afin d’avoir l’autocomplĂ©tion et les erreurs inline. + +Par exemple : + +* VS Code +* PyCharm + +/// tip | Astuce + +Vous devez normalement faire cela une seule fois, lorsque vous crĂ©ez l’environnement virtuel. + +/// + +## DĂ©sactiver l’environnement virtuel { #deactivate-the-virtual-environment } + +Une fois que vous avez fini de travailler sur votre projet, vous pouvez dĂ©sactiver l’environnement virtuel. + +
+ +```console +$ deactivate +``` + +
+ +Ainsi, lorsque vous exĂ©cutez `python`, il n’essaiera pas de l’exĂ©cuter depuis cet environnement virtuel avec les packages qui y sont installĂ©s. + +## PrĂȘt Ă  travailler { #ready-to-work } + +Vous ĂȘtes maintenant prĂȘt Ă  commencer Ă  travailler sur votre projet. + + + +/// tip | Astuce + +Voulez-vous comprendre tout ce qui prĂ©cĂšde ? + +Continuez la lecture. đŸ‘‡đŸ€“ + +/// + +## Pourquoi des environnements virtuels { #why-virtual-environments } + +Pour travailler avec FastAPI, vous devez installer Python. + +Ensuite, vous devrez installer FastAPI et tout autre package que vous souhaitez utiliser. + +Pour installer des packages, vous utiliseriez normalement la commande `pip` fournie avec Python (ou des alternatives similaires). + +NĂ©anmoins, si vous utilisez simplement `pip` directement, les packages seraient installĂ©s dans votre environnement Python global (l’installation globale de Python). + +### Le problĂšme { #the-problem } + +Alors, quel est le problĂšme d’installer des packages dans l’environnement Python global ? + +À un moment donnĂ©, vous finirez probablement par Ă©crire de nombreux programmes diffĂ©rents qui dĂ©pendent de packages diffĂ©rents. Et certains de ces projets sur lesquels vous travaillez dĂ©pendront de versions diffĂ©rentes du mĂȘme package. đŸ˜± + +Par exemple, vous pourriez crĂ©er un projet appelĂ© `philosophers-stone`, ce programme dĂ©pend d’un autre package appelĂ© **`harry`, en version `1`**. Vous devez donc installer `harry`. + +```mermaid +flowchart LR + stone(philosophers-stone) -->|requires| harry-1[harry v1] +``` + +Puis, plus tard, vous crĂ©ez un autre projet appelĂ© `prisoner-of-azkaban`, et ce projet dĂ©pend aussi de `harry`, mais il a besoin de **`harry` en version `3`**. + +```mermaid +flowchart LR + azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3] +``` + +Mais maintenant, le problĂšme est que, si vous installez les packages globalement (dans l’environnement global) au lieu de dans un environnement virtuel local, vous devrez choisir quelle version de `harry` installer. + +Si vous voulez exĂ©cuter `philosophers-stone`, vous devrez d’abord installer `harry` en version `1`, par exemple avec : + +
+ +```console +$ pip install "harry==1" +``` + +
+ +Et vous vous retrouverez avec `harry` en version `1` installé dans votre environnement Python global. + +```mermaid +flowchart LR + subgraph global[global env] + harry-1[harry v1] + end + subgraph stone-project[philosophers-stone project] + stone(philosophers-stone) -->|requires| harry-1 + end +``` + +Mais si vous voulez ensuite exécuter `prisoner-of-azkaban`, vous devrez désinstaller `harry` version `1` et installer `harry` version `3` (ou bien installer la version `3` désinstallerait automatiquement la version `1`). + +
+ +```console +$ pip install "harry==3" +``` + +
+ +Et vous vous retrouverez alors avec `harry` version `3` installĂ© dans votre environnement Python global. + +Et si vous essayez d’exĂ©cuter Ă  nouveau `philosophers-stone`, il y a une chance que cela ne fonctionne pas car il a besoin de `harry` version `1`. + +```mermaid +flowchart LR + subgraph global[global env] + harry-1[harry v1] + style harry-1 fill:#ccc,stroke-dasharray: 5 5 + harry-3[harry v3] + end + subgraph stone-project[philosophers-stone project] + stone(philosophers-stone) -.-x|⛔| harry-1 + end + subgraph azkaban-project[prisoner-of-azkaban project] + azkaban(prisoner-of-azkaban) --> |requires| harry-3 + end +``` + +/// tip | Astuce + +Il est trĂšs courant que les packages Python fassent de leur mieux pour Ă©viter les changements cassants dans les nouvelles versions, mais il vaut mieux jouer la sĂ©curitĂ© et installer de nouvelles versions intentionnellement et lorsque vous pouvez exĂ©cuter les tests pour vĂ©rifier que tout fonctionne correctement. + +/// + +Maintenant, imaginez cela avec beaucoup d’autres packages dont tous vos projets dĂ©pendent. C’est trĂšs difficile Ă  gĂ©rer. Et vous finiriez probablement par exĂ©cuter certains projets avec des versions incompatibles des packages, sans savoir pourquoi quelque chose ne fonctionne pas. + +De plus, selon votre systĂšme d’exploitation (par exemple Linux, Windows, macOS), il se peut qu’il soit livrĂ© avec Python dĂ©jĂ  installĂ©. Et dans ce cas, il avait probablement des packages prĂ©installĂ©s avec des versions spĂ©cifiques nĂ©cessaires Ă  votre systĂšme. Si vous installez des packages dans l’environnement Python global, vous pourriez finir par casser certains des programmes fournis avec votre systĂšme d’exploitation. + +## OĂč les packages sont-ils installĂ©s { #where-are-packages-installed } + +Lorsque vous installez Python, il crĂ©e des rĂ©pertoires avec des fichiers sur votre ordinateur. + +Certains de ces rĂ©pertoires sont chargĂ©s de contenir tous les packages que vous installez. + +Lorsque vous exĂ©cutez : + +
+ +```console +// Ne l’exĂ©cutez pas maintenant, c’est juste un exemple đŸ€“ +$ pip install "fastapi[standard]" +---> 100% +``` + +
+ +Cela tĂ©lĂ©chargera un fichier compressĂ© avec le code de FastAPI, normalement depuis PyPI. + +Il tĂ©lĂ©chargera Ă©galement des fichiers pour d’autres packages dont FastAPI dĂ©pend. + +Ensuite, il extraira tous ces fichiers et les placera dans un rĂ©pertoire de votre ordinateur. + +Par dĂ©faut, il placera ces fichiers tĂ©lĂ©chargĂ©s et extraits dans le rĂ©pertoire fourni avec votre installation de Python, c’est l’environnement global. + +## Qu’est-ce qu’un environnement virtuel { #what-are-virtual-environments } + +La solution aux problĂšmes posĂ©s par le fait d’avoir tous les packages dans l’environnement global est d’utiliser un environnement virtuel pour chaque projet sur lequel vous travaillez. + +Un environnement virtuel est un rĂ©pertoire, trĂšs similaire Ă  celui global, oĂč vous pouvez installer les packages pour un projet. + +De cette maniĂšre, chaque projet aura son propre environnement virtuel (rĂ©pertoire `.venv`) avec ses propres packages. + +```mermaid +flowchart TB + subgraph stone-project[philosophers-stone project] + stone(philosophers-stone) --->|requires| harry-1 + subgraph venv1[.venv] + harry-1[harry v1] + end + end + subgraph azkaban-project[prisoner-of-azkaban project] + azkaban(prisoner-of-azkaban) --->|requires| harry-3 + subgraph venv2[.venv] + harry-3[harry v3] + end + end + stone-project ~~~ azkaban-project +``` + +## Que signifie activer un environnement virtuel { #what-does-activating-a-virtual-environment-mean } + +Lorsque vous activez un environnement virtuel, par exemple avec : + +//// tab | Linux, macOS + +
+ +```console +$ source .venv/bin/activate +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ .venv\Scripts\Activate.ps1 +``` + +
+ +//// + +//// tab | Windows Bash + +Ou si vous utilisez Bash pour Windows (par exemple Git Bash) : + +
+ +```console +$ source .venv/Scripts/activate +``` + +
+ +//// + +Cette commande crĂ©era ou modifiera certaines [variables d’environnement](environment-variables.md){.internal-link target=_blank} qui seront disponibles pour les prochaines commandes. + +L’une de ces variables est la variable `PATH`. + +/// tip | Astuce + +Vous pouvez en savoir plus sur la variable d’environnement `PATH` dans la section [Variables d’environnement](environment-variables.md#path-environment-variable){.internal-link target=_blank}. + +/// + +Activer un environnement virtuel ajoute son chemin `.venv/bin` (sur Linux et macOS) ou `.venv\Scripts` (sur Windows) Ă  la variable d’environnement `PATH`. + +Disons qu’avant d’activer l’environnement, la variable `PATH` ressemblait Ă  ceci : + +//// tab | Linux, macOS + +```plaintext +/usr/bin:/bin:/usr/sbin:/sbin +``` + +Cela signifie que le systĂšme chercherait des programmes dans : + +* `/usr/bin` +* `/bin` +* `/usr/sbin` +* `/sbin` + +//// + +//// tab | Windows + +```plaintext +C:\Windows\System32 +``` + +Cela signifie que le systĂšme chercherait des programmes dans : + +* `C:\Windows\System32` + +//// + +AprĂšs avoir activĂ© l’environnement virtuel, la variable `PATH` ressemblerait Ă  quelque chose comme ceci : + +//// tab | Linux, macOS + +```plaintext +/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin +``` + +Cela signifie que le systĂšme commencera maintenant par chercher des programmes dans : + +```plaintext +/home/user/code/awesome-project/.venv/bin +``` + +avant de chercher dans les autres rĂ©pertoires. + +Ainsi, lorsque vous tapez `python` dans le terminal, le systĂšme trouvera le programme Python dans + +```plaintext +/home/user/code/awesome-project/.venv/bin/python +``` + +et utilisera celui-ci. + +//// + +//// tab | Windows + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32 +``` + +Cela signifie que le systĂšme commencera maintenant par chercher des programmes dans : + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts +``` + +avant de chercher dans les autres rĂ©pertoires. + +Ainsi, lorsque vous tapez `python` dans le terminal, le systĂšme trouvera le programme Python dans + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +et utilisera celui-ci. + +//// + +Un dĂ©tail important est qu’il placera le chemin de l’environnement virtuel au dĂ©but de la variable `PATH`. Le systĂšme le trouvera avant de trouver tout autre Python disponible. Ainsi, lorsque vous exĂ©cutez `python`, il utilisera le Python de l’environnement virtuel au lieu de tout autre `python` (par exemple, un `python` d’un environnement global). + +Activer un environnement virtuel change aussi deux ou trois autres choses, mais c’est l’un des points les plus importants. + +## VĂ©rifier un environnement virtuel { #checking-a-virtual-environment } + +Lorsque vous vĂ©rifiez si un environnement virtuel est actif, par exemple avec : + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +$ which python + +/home/user/code/awesome-project/.venv/bin/python +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ Get-Command python + +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +
+ +//// + +Cela signifie que le programme `python` qui sera utilisĂ© est celui dans l’environnement virtuel. + +Vous utilisez `which` sous Linux et macOS et `Get-Command` sous Windows PowerShell. + +La façon dont cette commande fonctionne est qu’elle va vĂ©rifier la variable d’environnement `PATH`, en parcourant chaque chemin dans l’ordre, Ă  la recherche du programme nommĂ© `python`. Une fois trouvĂ©, elle vous affichera le chemin vers ce programme. + +La partie la plus importante est que lorsque vous appelez `python`, c’est exactement « `python` » qui sera exĂ©cutĂ©. + +Ainsi, vous pouvez confirmer si vous ĂȘtes dans le bon environnement virtuel. + +/// tip | Astuce + +Il est facile d’activer un environnement virtuel, d’obtenir un Python, puis d’aller vers un autre projet. + +Et le second projet ne fonctionnerait pas parce que vous utilisez le Python incorrect, provenant d’un environnement virtuel d’un autre projet. + +Il est utile de pouvoir vĂ©rifier quel `python` est utilisĂ©. đŸ€“ + +/// + +## Pourquoi dĂ©sactiver un environnement virtuel { #why-deactivate-a-virtual-environment } + +Par exemple, vous pourriez travailler sur un projet `philosophers-stone`, activer cet environnement virtuel, installer des packages et travailler avec cet environnement. + +Puis vous souhaitez travailler sur un autre projet `prisoner-of-azkaban`. + +Vous allez vers ce projet : + +
+ +```console +$ cd ~/code/prisoner-of-azkaban +``` + +
+ +Si vous ne dĂ©sactivez pas l’environnement virtuel de `philosophers-stone`, lorsque vous exĂ©cutez `python` dans le terminal, il essaiera d’utiliser le Python de `philosophers-stone`. + +
+ +```console +$ cd ~/code/prisoner-of-azkaban + +$ python main.py + +// Erreur lors de l'import de sirius, il n'est pas installĂ© đŸ˜± +Traceback (most recent call last): + File "main.py", line 1, in + import sirius +``` + +
+ +Mais si vous dĂ©sactivez l’environnement virtuel et activez le nouveau pour `prisoner-of-askaban`, alors lorsque vous exĂ©cuterez `python`, il utilisera le Python de l’environnement virtuel de `prisoner-of-azkaban`. + +
+ +```console +$ cd ~/code/prisoner-of-azkaban + +// Vous n’avez pas besoin d’ĂȘtre dans l’ancien rĂ©pertoire pour dĂ©sactiver, vous pouvez le faire oĂč que vous soyez, mĂȘme aprĂšs ĂȘtre allĂ© dans l’autre projet 😎 +$ deactivate + +// Activer l’environnement virtuel dans prisoner-of-azkaban/.venv 🚀 +$ source .venv/bin/activate + +// Maintenant, lorsque vous exĂ©cutez python, il trouvera le package sirius installĂ© dans cet environnement virtuel ✹ +$ python main.py + +I solemnly swear đŸș +``` + +
+ +## Alternatives { #alternatives } + +Ceci est un guide simple pour vous lancer et vous montrer comment tout fonctionne en dessous. + +Il existe de nombreuses alternatives pour gĂ©rer les environnements virtuels, les dĂ©pendances de packages (requirements), les projets. + +Lorsque vous ĂȘtes prĂȘt et souhaitez utiliser un outil pour gĂ©rer l’ensemble du projet, les dĂ©pendances, les environnements virtuels, etc., je vous suggĂšre d’essayer uv. + +`uv` peut faire beaucoup de choses, il peut : + +* Installer Python pour vous, y compris diffĂ©rentes versions +* GĂ©rer l’environnement virtuel pour vos projets +* Installer des packages +* GĂ©rer les dĂ©pendances de packages et leurs versions pour votre projet +* Vous assurer d’avoir un ensemble exact de packages et de versions Ă  installer, y compris leurs dĂ©pendances, afin que vous puissiez ĂȘtre certain d’exĂ©cuter votre projet en production exactement comme sur votre ordinateur pendant le dĂ©veloppement, cela s’appelle le locking +* Et bien d’autres choses + +## Conclusion { #conclusion } + +Si vous avez lu et compris tout cela, vous en savez maintenant bien plus sur les environnements virtuels que beaucoup de dĂ©veloppeurs. đŸ€“ + +ConnaĂźtre ces dĂ©tails vous sera trĂšs probablement utile Ă  l’avenir lorsque vous dĂ©boguerez quelque chose qui semble complexe, mais vous saurez comment tout fonctionne en dessous. 😎