diff --git a/docs/en/docs/advanced/advanced-dependencies.md b/docs/en/docs/advanced/advanced-dependencies.md index 37f5c78f2d..0d03507b7e 100644 --- a/docs/en/docs/advanced/advanced-dependencies.md +++ b/docs/en/docs/advanced/advanced-dependencies.md @@ -120,7 +120,7 @@ The exit code, the automatic closing of the `Session` in: {* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *} -...would be run after the the response finishes sending the slow data: +...would be run after the response finishes sending the slow data: {* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *} diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md index 5e6d821b31..af7944e75c 100644 --- a/docs/en/docs/contributing.md +++ b/docs/en/docs/contributing.md @@ -179,19 +179,23 @@ as Uvicorn by default will use the port `8000`, the documentation on port `8008` Help with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀 -Here are the steps to help with translations. - -#### Translation PRs - Translation pull requests are made by LLMs guided with prompts designed by the FastAPI team together with the community of native speakers for each supported language. -These translations are normally still reviewed by native speakers, and here's where you can help! +#### LLM Prompt per Language -* Check the currently existing pull requests for your language. You can filter the pull requests by the ones with the label for your language. For example, for Spanish, the label is `lang-es`. +Each language has a directory: https://github.com/fastapi/fastapi/tree/master/docs, in it you can see a file `llm-prompt.md` with the prompt specific for that language. -* When reviewing a pull request, it's better not to suggest changes in the same pull request, because it is LLM generated, and it won't be possible to make sure that small individual changes are replicated in other similar sections, or that they are preserved when translating the same content again. +For example, for Spanish, the prompt is at: `docs/es/llm-prompt.md`. -* Instead of adding suggestions to the translation PR, make the suggestions to the LLM prompt file for that language, in a new PR. For example, for Spanish, the LLM prompt file is at: `docs/es/llm-prompt.md`. +If you see mistakes in your language, you can make suggestions to the prompt in that file for your language, and request the specific pages you would like to re-generate after the changes. + +#### Reviewing Translation PRs + +You can also check the currently existing pull requests for your language. You can filter the pull requests by the ones with the label for your language. For example, for Spanish, the label is `lang-es`. + +When reviewing a pull request, it's better not to suggest changes in the same pull request, because it is LLM generated, and it won't be possible to make sure that small individual changes are replicated in other similar sections, or that they are preserved when translating the same content again. + +Instead of adding suggestions to the translation PR, make the suggestions to the LLM prompt file for that language, in a new PR. For example, for Spanish, the LLM prompt file is at: `docs/es/llm-prompt.md`. /// tip @@ -201,9 +205,9 @@ Check the docs about GitHub Discussion to coordinate translations for your language. You can subscribe to it, and when there's a new pull request to review, an automatic comment will be added to the discussion. +Check if there's a GitHub Discussion to coordinate translations for your language. You can subscribe to it, and when there's a new pull request to review, an automatic comment will be added to the discussion. -* To check the 2-letter code for the language you want to translate, you can use the table List of ISO 639-1 codes. +To check the 2-letter code for the language you want to translate, you can use the table List of ISO 639-1 codes. #### Request a New Language diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 983e19fdb8..9304032108 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,8 +7,16 @@ hide: ## Latest Changes +### Docs + +* 📝 Fix duplicate word in `advanced-dependencies.md`. PR [#14815](https://github.com/fastapi/fastapi/pull/14815) by [@Rayyan-Oumlil](https://github.com/Rayyan-Oumlil). + ### Translations +* 🌐 Update translations for tr (add-missing). PR [#14790](https://github.com/fastapi/fastapi/pull/14790) by [@tiangolo](https://github.com/tiangolo). +* 🌐 Update translations for fr (update-outdated). PR [#14826](https://github.com/fastapi/fastapi/pull/14826) by [@tiangolo](https://github.com/tiangolo). +* 🌐 Update translations for zh-hant (update-outdated). PR [#14825](https://github.com/fastapi/fastapi/pull/14825) by [@tiangolo](https://github.com/tiangolo). +* 🌐 Update translations for uk (update-outdated). PR [#14822](https://github.com/fastapi/fastapi/pull/14822) by [@tiangolo](https://github.com/tiangolo). * 🔨 Update docs and translations scripts, enable Turkish. PR [#14824](https://github.com/fastapi/fastapi/pull/14824) by [@tiangolo](https://github.com/tiangolo). ## 0.128.1 diff --git a/docs/fr/docs/advanced/additional-responses.md b/docs/fr/docs/advanced/additional-responses.md index 38527aad3c..dabcded52e 100644 --- a/docs/fr/docs/advanced/additional-responses.md +++ b/docs/fr/docs/advanced/additional-responses.md @@ -1,6 +1,6 @@ -# Réponses supplémentaires dans OpenAPI +# Réponses supplémentaires dans OpenAPI { #additional-responses-in-openapi } -/// warning | Attention +/// warning | Alertes Ceci concerne un sujet plutôt avancé. @@ -14,9 +14,9 @@ Ces réponses supplémentaires seront incluses dans le schéma OpenAPI, elles ap Mais pour ces réponses supplémentaires, vous devez vous assurer de renvoyer directement une `Response` comme `JSONResponse`, avec votre code HTTP et votre contenu. -## Réponse supplémentaire avec `model` +## Réponse supplémentaire avec `model` { #additional-response-with-model } -Vous pouvez ajouter à votre décorateur de *paramètre de chemin* un paramètre `responses`. +Vous pouvez passer à vos décorateurs de *chemin d'accès* un paramètre `responses`. Il prend comme valeur un `dict` dont les clés sont des codes HTTP pour chaque réponse, comme `200`, et la valeur de ces clés sont d'autres `dict` avec des informations pour chacun d'eux. @@ -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.py hl[18,22] *} +{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} /// note | Remarque @@ -49,7 +49,7 @@ Le bon endroit est : /// -Les réponses générées au format OpenAPI pour cette *opération de chemin* seront : +Les réponses générées au format OpenAPI pour ce *chemin d'accès* seront : ```JSON hl_lines="3-12" { @@ -169,13 +169,13 @@ Les schémas sont référencés à un autre endroit du modèle OpenAPI : } ``` -## Types de médias supplémentaires pour la réponse principale +## Types de médias supplémentaires pour la réponse principale { #additional-media-types-for-the-main-response } Vous pouvez utiliser ce même paramètre `responses` pour ajouter différents types de médias pour la même réponse principale. -Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *opération de chemin* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG : +Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *chemin d'accès* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG : -{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *} +{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *} /// note | Remarque @@ -191,7 +191,7 @@ Mais si vous avez spécifié une classe de réponse personnalisée avec `None` c /// -## Combinaison d'informations +## Combiner les informations { #combining-information } Vous pouvez également combiner des informations de réponse provenant de plusieurs endroits, y compris les paramètres `response_model`, `status_code` et `responses`. @@ -203,17 +203,17 @@ 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.py hl[20:31] *} +{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} Tout sera combiné et inclus dans votre OpenAPI, et affiché dans la documentation de l'API : -## Combinez les réponses prédéfinies et les réponses personnalisées +## Combinez les réponses prédéfinies et les réponses personnalisées { #combine-predefined-responses-and-custom-ones } -Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *paramètre de chemin*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *opération de chemin*. +Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *chemins d'accès*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *chemin d'accès*. -Dans ces cas, vous pouvez utiliser la technique Python "d'affection par décomposition" (appelé _unpacking_ en anglais) d'un `dict` avec `**dict_to_unpack` : +Dans ces cas, vous pouvez utiliser la technique Python « unpacking » d'un `dict` avec `**dict_to_unpack` : ```Python old_dict = { @@ -233,15 +233,15 @@ Ici, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la n } ``` -Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *paramètres de chemin* et les combiner avec des réponses personnalisées supplémentaires. +Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *chemins d'accès* et les combiner avec des réponses personnalisées supplémentaires. Par exemple: -{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *} +{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *} -## Plus d'informations sur les réponses OpenAPI +## Plus d'informations sur les réponses OpenAPI { #more-information-about-openapi-responses } Pour voir exactement ce que vous pouvez inclure dans les réponses, vous pouvez consulter ces sections dans la spécification OpenAPI : -* Objet Responses de OpenAPI , il inclut le `Response Object`. -* Objet Response de OpenAPI , vous pouvez inclure n'importe quoi directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et schémas JSON) et `links`. +* Objet Responses de OpenAPI, il inclut le `Response Object`. +* Objet Response de OpenAPI, vous pouvez inclure n'importe quoi directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et schémas JSON) et `links`. diff --git a/docs/fr/docs/advanced/additional-status-codes.md b/docs/fr/docs/advanced/additional-status-codes.md index dde6b9a63f..b2befffa8d 100644 --- a/docs/fr/docs/advanced/additional-status-codes.md +++ b/docs/fr/docs/advanced/additional-status-codes.md @@ -1,28 +1,28 @@ -# Codes HTTP supplémentaires +# Codes HTTP supplémentaires { #additional-status-codes } Par défaut, **FastAPI** renverra les réponses à l'aide d'une structure de données `JSONResponse`, en plaçant la réponse de votre *chemin d'accès* à l'intérieur de cette `JSONResponse`. Il utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *chemin d'accès*. -## Codes HTTP supplémentaires +## Codes HTTP supplémentaires { #additional-status-codes_1 } Si vous souhaitez renvoyer des codes HTTP supplémentaires en plus du code principal, vous pouvez le faire en renvoyant directement une `Response`, comme une `JSONResponse`, et en définissant directement le code HTTP supplémentaire. -Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 "OK" en cas de succès. +Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 « OK » en cas de succès. -Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 "Créé". +Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 « Créé ». Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous souhaitez : -{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *} +{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *} -/// warning | Attention +/// warning | Alertes Lorsque vous renvoyez une `Response` directement, comme dans l'exemple ci-dessus, elle sera renvoyée directement. Elle ne sera pas sérialisée avec un modèle. -Assurez-vous qu'il contient les données souhaitées et que les valeurs soient dans un format JSON valides (si vous utilisez une `JSONResponse`). +Assurez-vous qu'il contient les données souhaitées et que les valeurs sont dans un format JSON valide (si vous utilisez une `JSONResponse`). /// @@ -30,12 +30,12 @@ Assurez-vous qu'il contient les données souhaitées et que les valeurs soient d Vous pouvez également utiliser `from starlette.responses import JSONResponse`. -Pour plus de commodités, **FastAPI** fournit les objets `starlette.responses` sous forme d'un alias accessible par `fastapi.responses`. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en est de même avec l'objet `statut`. +Pour plus de commodités, **FastAPI** fournit les objets `starlette.responses` sous forme d'un alias accessible par `fastapi.responses`. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en est de même avec `status`. /// -## Documents OpenAPI et API +## Documents OpenAPI et API { #openapi-and-api-docs } Si vous renvoyez directement des codes HTTP et des réponses supplémentaires, ils ne seront pas inclus dans le schéma OpenAPI (la documentation de l'API), car FastAPI n'a aucun moyen de savoir à l'avance ce que vous allez renvoyer. -Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}. +Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/fr/docs/advanced/index.md b/docs/fr/docs/advanced/index.md index d9d8ad8e60..a2f9d3b1bb 100644 --- a/docs/fr/docs/advanced/index.md +++ b/docs/fr/docs/advanced/index.md @@ -1,27 +1,21 @@ -# Guide de l'utilisateur avancé +# Guide de l'utilisateur avancé { #advanced-user-guide } -## Caractéristiques supplémentaires +## Caractéristiques supplémentaires { #additional-features } Le [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank} devrait suffire à vous faire découvrir toutes les fonctionnalités principales de **FastAPI**. Dans les sections suivantes, vous verrez des options, configurations et fonctionnalités supplémentaires. -/// note | Remarque +/// tip | Astuce -Les sections de ce chapitre ne sont **pas nécessairement "avancées"**. +Les sections suivantes ne sont **pas nécessairement « avancées »**. -Et il est possible que pour votre cas d'utilisation, la solution se trouve dans l'un d'entre eux. +Et il est possible que, pour votre cas d'utilisation, la solution se trouve dans l'une d'entre elles. /// -## Lisez d'abord le didacticiel +## Lire d'abord le tutoriel { #read-the-tutorial-first } Vous pouvez utiliser la plupart des fonctionnalités de **FastAPI** grâce aux connaissances du [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank}. Et les sections suivantes supposent que vous l'avez lu et que vous en connaissez les idées principales. - -## Cours TestDriven.io - -Si vous souhaitez suivre un cours pour débutants avancés pour compléter cette section de la documentation, vous pouvez consulter : Développement piloté par les tests avec FastAPI et Docker par **TestDriven.io**. - -10 % de tous les bénéfices de ce cours sont reversés au développement de **FastAPI**. 🎉 😄 diff --git a/docs/fr/docs/advanced/path-operation-advanced-configuration.md b/docs/fr/docs/advanced/path-operation-advanced-configuration.md index 7daf0fc65f..fc88f33633 100644 --- a/docs/fr/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/fr/docs/advanced/path-operation-advanced-configuration.md @@ -1,106 +1,108 @@ -# Configuration avancée des paramètres de chemin +# Configuration avancée des chemins d'accès { #path-operation-advanced-configuration } -## ID d'opération OpenAPI +## ID d’opération OpenAPI { #openapi-operationid } -/// warning | Attention +/// warning | Alertes -Si vous n'êtes pas un "expert" en OpenAPI, vous n'en avez probablement pas besoin. +Si vous n’êtes pas un « expert » d’OpenAPI, vous n’en avez probablement pas besoin. /// -Dans OpenAPI, les chemins sont des ressources, tels que /users/ ou /items/, exposées par votre API, et les opérations sont les méthodes HTTP utilisées pour manipuler ces chemins, telles que GET, POST ou DELETE. Les operationId sont des chaînes uniques facultatives utilisées pour identifier une opération d'un chemin. Vous pouvez définir l'OpenAPI `operationId` à utiliser dans votre *opération de chemin* avec le paramètre `operation_id`. +Vous pouvez définir l’OpenAPI `operationId` à utiliser dans votre chemin d’accès avec le paramètre `operation_id`. -Vous devez vous assurer qu'il est unique pour chaque opération. +Vous devez vous assurer qu’il est unique pour chaque opération. -{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *} -### Utilisation du nom *path operation function* comme operationId +### Utiliser le nom de la fonction de chemin d’accès comme operationId { #using-the-path-operation-function-name-as-the-operationid } -Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer chaque `operation_id` de l'*opération de chemin* en utilisant leur `APIRoute.name`. +Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer l’`operation_id` de chaque chemin d’accès en utilisant leur `APIRoute.name`. -Vous devriez le faire après avoir ajouté toutes vos *paramètres de chemin*. +Vous devez le faire après avoir ajouté tous vos chemins d’accès. -{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2,12:21,24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} /// tip | Astuce -Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant. +Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant cela. /// -/// warning | Attention +/// warning | Alertes -Pour faire cela, vous devez vous assurer que chacun de vos *chemin* ait un nom unique. +Si vous faites cela, vous devez vous assurer que chacune de vos fonctions de chemin d’accès a un nom unique. -Même s'ils se trouvent dans des modules différents (fichiers Python). +Même si elles se trouvent dans des modules différents (fichiers Python). /// -## Exclusion d'OpenAPI +## Exclusion d’OpenAPI { #exclude-from-openapi } -Pour exclure un *chemin* du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et assignez-lui la valeur `False` : +Pour exclure un chemin d’accès du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et définissez-le à `False` : -{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} -## Description avancée de docstring +## Description avancée depuis la docstring { #advanced-description-from-docstring } -Vous pouvez limiter le texte utilisé de la docstring d'une *fonction de chemin* qui sera affiché sur OpenAPI. +Vous pouvez limiter les lignes utilisées de la docstring d’une fonction de chemin d’accès pour OpenAPI. -L'ajout d'un `\f` (un caractère d'échappement "form feed") va permettre à **FastAPI** de tronquer la sortie utilisée pour OpenAPI à ce stade. +L’ajout d’un `\f` (un caractère « saut de page » échappé) amène **FastAPI** à tronquer la sortie utilisée pour OpenAPI à cet endroit. -Il n'apparaîtra pas dans la documentation, mais d'autres outils (tel que Sphinx) pourront utiliser le reste. +Cela n’apparaîtra pas dans la documentation, mais d’autres outils (comme Sphinx) pourront utiliser le reste. -{* ../../docs_src/path_operation_advanced_configuration/tutorial004.py hl[19:29] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *} -## Réponses supplémentaires +## Réponses supplémentaires { #additional-responses } -Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour une *opération de chemin*. +Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour un chemin d’accès. -Cela définit les métadonnées sur la réponse principale d'une *opération de chemin*. +Cela définit les métadonnées sur la réponse principale d’un chemin d’accès. Vous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc. -Il y a un chapitre entier ici dans la documentation à ce sujet, vous pouvez le lire sur [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}. +Il y a un chapitre entier dans la documentation à ce sujet, vous pouvez le lire dans [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}. -## OpenAPI supplémentaire +## OpenAPI supplémentaire { #openapi-extra } -Lorsque vous déclarez un *chemin* dans votre application, **FastAPI** génère automatiquement les métadonnées concernant ce *chemin* à inclure dans le schéma OpenAPI. +Lorsque vous déclarez un chemin d’accès dans votre application, **FastAPI** génère automatiquement les métadonnées pertinentes à propos de ce chemin d’accès à inclure dans le schéma OpenAPI. /// note | Détails techniques -La spécification OpenAPI appelle ces métadonnées des Objets d'opération. +Dans la spécification OpenAPI, cela s’appelle l’objet Operation. /// -Il contient toutes les informations sur le *chemin* et est utilisé pour générer automatiquement la documentation. +Il contient toutes les informations sur le chemin d’accès et est utilisé pour générer la documentation automatique. Il inclut les `tags`, `parameters`, `requestBody`, `responses`, etc. -Ce schéma OpenAPI spécifique aux *operations* est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l'étendre. +Ce schéma OpenAPI spécifique à un chemin d’accès est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l’étendre. /// tip | Astuce -Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d'utiliser les [réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}. +Ceci est un point d’extension de bas niveau. + +Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d’utiliser [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}. /// -Vous pouvez étendre le schéma OpenAPI pour une *opération de chemin* en utilisant le paramètre `openapi_extra`. +Vous pouvez étendre le schéma OpenAPI pour un chemin d’accès en utilisant le paramètre `openapi_extra`. -### Extensions OpenAPI +### Extensions OpenAPI { #openapi-extensions } -Cet `openapi_extra` peut être utile, par exemple, pour déclarer [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) : +Cet `openapi_extra` peut être utile, par exemple, pour déclarer des [Extensions OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) : -{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *} -Si vous ouvrez la documentation automatique de l'API, votre extension apparaîtra au bas du *chemin* spécifique. +Si vous ouvrez la documentation automatique de l’API, votre extension apparaîtra en bas du chemin d’accès spécifique. -Et dans le fichier openapi généré (`/openapi.json`), vous verrez également votre extension dans le cadre du *chemin* spécifique : +Et si vous consultez l’OpenAPI résultant (à `/openapi.json` dans votre API), vous verrez également votre extension comme partie du chemin d’accès spécifique : ```JSON hl_lines="22" { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": { "title": "FastAPI", "version": "0.1.0" @@ -127,44 +129,44 @@ Et dans le fichier openapi généré (`/openapi.json`), vous verrez également v } ``` -### Personnalisation du Schéma OpenAPI pour un chemin +### Personnaliser le schéma OpenAPI d’un chemin d’accès { #custom-openapi-path-operation-schema } -Le dictionnaire contenu dans la variable `openapi_extra` sera fusionné avec le schéma OpenAPI généré automatiquement pour l'*opération de chemin*. +Le dictionnaire dans `openapi_extra` sera fusionné en profondeur avec le schéma OpenAPI généré automatiquement pour le chemin d’accès. Ainsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement. -Par exemple, vous pouvez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de validation proposée par Pydantic, mais vous pouvez toujours définir la requête dans le schéma OpenAPI. +Par exemple, vous pourriez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de FastAPI avec Pydantic, mais vous pourriez tout de même vouloir définir la requête dans le schéma OpenAPI. -Vous pouvez le faire avec `openapi_extra` : +Vous pourriez le faire avec `openapi_extra` : -{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[20:37,39:40] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *} -Dans cet exemple, nous n'avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n'est même pas parsé en tant que JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargé de l'analyser d'une manière ou d'une autre. +Dans cet exemple, nous 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. -### Type de contenu OpenAPI personnalisé +### Type de contenu OpenAPI personnalisé { #custom-openapi-content-type } -En utilisant cette même astuce, vous pouvez utiliser un modèle Pydantic pour définir le schéma JSON qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le *chemin* concerné. +En utilisant cette même astuce, vous pourriez utiliser un modèle Pydantic pour définir le JSON Schema qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le chemin d’accès. -Et vous pouvez le faire même si le type de données dans la requête n'est pas au format JSON. +Et vous pourriez le faire même si le type de données dans la requête n’est pas du JSON. -Dans cet exemple, nous n'utilisons pas les fonctionnalités de FastAPI pour extraire le schéma JSON des modèles Pydantic ni la validation automatique pour JSON. En fait, nous déclarons le type de contenu de la requête en tant que YAML, et non JSON : +Par exemple, dans cette application nous 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.py hl[17:22,24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *} -Néanmoins, bien que nous n'utilisions pas la fonctionnalité par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le schéma JSON pour les données que nous souhaitons recevoir en YAML. +Néanmoins, bien que nous 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. -Ensuite, nous utilisons directement la requête et extrayons son contenu en tant qu'octets. Cela signifie que FastAPI n'essaiera même pas d'analyser le payload de la requête en tant que JSON. +Ensuite, nous utilisons directement la requête et extrayons le corps en tant que `bytes`. Cela signifie que FastAPI n’essaiera même pas d’analyser le payload de la requête en JSON. -Et nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML : +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.py hl[26:33] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *} /// tip | Astuce Ici, nous réutilisons le même modèle Pydantic. -Mais nous aurions pu tout aussi bien pu le valider d'une autre manière. +Mais de la même manière, nous aurions pu le valider autrement. /// diff --git a/docs/fr/docs/advanced/response-directly.md b/docs/fr/docs/advanced/response-directly.md index 4ff883c770..f35c39c06f 100644 --- a/docs/fr/docs/advanced/response-directly.md +++ b/docs/fr/docs/advanced/response-directly.md @@ -1,20 +1,20 @@ -# Renvoyer directement une réponse +# Renvoyer directement une réponse { #return-a-response-directly } -Lorsque vous créez une *opération de chemins* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc. +Lorsque vous créez un *chemin d'accès* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc. -Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}. +Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [Encodeur compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}. Ensuite, en arrière-plan, il mettra ces données JSON-compatible (par exemple un `dict`) à l'intérieur d'un `JSONResponse` qui sera utilisé pour envoyer la réponse au client. -Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *opérations de chemin*. +Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *chemins d'accès*. Cela peut être utile, par exemple, pour retourner des en-têtes personnalisés ou des cookies. -## Renvoyer une `Response` +## Renvoyer une `Response` { #return-a-response } En fait, vous pouvez retourner n'importe quelle `Response` ou n'importe quelle sous-classe de celle-ci. -/// note | Remarque +/// tip | Astuce `JSONResponse` est elle-même une sous-classe de `Response`. @@ -24,27 +24,27 @@ 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. -Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données. +Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données, etc. -## Utiliser le `jsonable_encoder` dans une `Response` +## Utiliser le `jsonable_encoder` dans une `Response` { #using-the-jsonable-encoder-in-a-response } -Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt à être utilisé (sérialisable). +Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt pour cela. Par exemple, vous ne pouvez pas mettre un modèle Pydantic dans une `JSONResponse` sans d'abord le convertir en un `dict` avec tous les types de données (comme `datetime`, `UUID`, etc.) convertis en types compatibles avec JSON. -Pour ces cas, vous pouvez spécifier un appel à `jsonable_encoder` pour convertir vos données avant de les passer à une réponse : +Pour ces cas, vous pouvez utiliser le `jsonable_encoder` pour convertir vos données avant de les passer à une réponse : -{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *} +{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *} /// note | Détails techniques Vous pouvez aussi utiliser `from starlette.responses import JSONResponse`. -**FastAPI** fournit le même objet `starlette.responses` que `fastapi.responses` juste par commodité pour le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette. +**FastAPI** fournit le même `starlette.responses` que `fastapi.responses` juste par commodité pour vous, le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette. /// -## Renvoyer une `Response` personnalisée +## Renvoyer une `Response` personnalisée { #returning-a-custom-response } L'exemple ci-dessus montre toutes les parties dont vous avez besoin, mais il n'est pas encore très utile, car vous auriez pu retourner l'`item` directement, et **FastAPI** l'aurait mis dans une `JSONResponse` pour vous, en le convertissant en `dict`, etc. Tout cela par défaut. @@ -54,9 +54,9 @@ Disons que vous voulez retourner une réponse étant l'un des frameworks Python les plus rapides disponibles, seulement inférieur à Starlette et Uvicorn (tous deux utilisés au cœur de FastAPI). (*) +Les benchmarks indépendants de TechEmpower montrent que les applications **FastAPI** s’exécutant avec Uvicorn sont parmi les frameworks Python les plus rapides disponibles, seulement en dessous de Starlette et Uvicorn eux‑mêmes (tous deux utilisés en interne par FastAPI). -Mais en prêtant attention aux tests de performance et aux comparaisons, il faut tenir compte de ce qu'il suit. +Mais en prêtant attention aux tests de performance et aux comparaisons, vous devez tenir compte de ce qui suit. -## Tests de performance et rapidité +## Tests de performance et rapidité { #benchmarks-and-speed } Lorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents. En particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils). -Plus le problème résolu par un outil est simple, mieux seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils. +Plus le problème résolu par un outil est simple, meilleures seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils. La hiérarchie est la suivante : * **Uvicorn** : un serveur ASGI - * **Starlette** : (utilise Uvicorn) un micro-framework web - * **FastAPI**: (utilise Starlette) un micro-framework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc. + * **Starlette** : (utilise Uvicorn) un microframework web + * **FastAPI**: (utilise Starlette) un microframework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc. * **Uvicorn** : - * A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis-à-part le serveur en lui-même. - * On n'écrit pas une application avec uniquement Uvicorn. Cela signifie que le code devrait inclure plus ou moins, au minimum, tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale apportera les mêmes complications que si on avait utilisé un framework et que l'on avait minimisé la quantité de code et de bugs. - * Si on compare Uvicorn, il faut le comparer à d'autre applications de serveurs comme Daphne, Hypercorn, uWSGI, etc. + * A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis à part le serveur en lui‑même. + * On n'écrit pas une application directement avec Uvicorn. Cela signifie que le code devrait inclure, au minimum, plus ou moins tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale aura la même surcharge que si on avait utilisé un framework, tout en minimisant la quantité de code et les bugs. + * Si on compare Uvicorn, il faut le comparer à d'autres serveurs d'applications comme Daphne, Hypercorn, uWSGI, etc. * **Starlette** : - * A les seconde meilleures performances après Uvicorn. Starlette utilise en réalité Uvicorn. De ce fait, il ne peut qu’être plus "lent" qu'Uvicorn car il requiert l'exécution de plus de code. - * Cependant il nous apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc. - * Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou micorframework) comme Sanic, Flask, Django, etc. + * A les secondes meilleures performances après Uvicorn. En réalité, Starlette utilise Uvicorn. De ce fait, il ne peut qu’être plus « lent » qu'Uvicorn car il requiert l'exécution de plus de code. + * Cependant, il apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc. + * Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou microframeworks) comme Sanic, Flask, Django, etc. * **FastAPI** : - * Comme Starlette, FastAPI utilise Uvicorn et ne peut donc pas être plus rapide que ce dernier. - * FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités qui sont nécessaires presque systématiquement lors de la création d'une API, comme la validation des données, la sérialisation. En utilisant FastAPI, on obtient une documentation automatiquement (qui ne requiert aucune manipulation pour être mise en place). - * Si on n'utilisait pas FastAPI mais directement Starlette (ou un outil équivalent comme Sanic, Flask, Responder, etc) il faudrait implémenter la validation des données et la sérialisation par nous-même. Le résultat serait donc le même dans les deux cas mais du travail supplémentaire serait à réaliser avec Starlette, surtout en considérant que la validation des données et la sérialisation représentent la plus grande quantité de code à écrire dans une application. - * De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient les mêmes performances (si ce n'est de meilleurs performances) que l'on aurait pu avoir sans ce framework (en ayant à implémenter de nombreuses fonctionnalités importantes par nous-mêmes). - * Si on compare FastAPI, il faut le comparer à d'autres frameworks web (ou ensemble d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc. + * Comme Starlette utilise Uvicorn et ne peut donc pas être plus rapide que lui, **FastAPI** utilise Starlette et ne peut donc pas être plus rapide que lui. + * FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités dont vous avez presque toujours besoin lors de la création d'une API, comme la validation des données et la sérialisation. En l'utilisant, vous obtenez une documentation automatique « gratuitement » (la documentation automatique n'ajoute même pas de surcharge à l’exécution, elle est générée au démarrage). + * Si on n'utilisait pas FastAPI mais directement Starlette (ou un autre outil comme Sanic, Flask, Responder, etc.), il faudrait implémenter toute la validation des données et la sérialisation soi‑même. L'application finale aurait donc la même surcharge que si elle avait été construite avec FastAPI. Et dans de nombreux cas, cette validation des données et cette sérialisation représentent la plus grande quantité de code écrite dans les applications. + * De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient probablement les mêmes performances (voire de meilleures performances) que l'on aurait pu avoir sans ce framework (car il aurait fallu tout implémenter dans votre code). + * Si on compare FastAPI, il faut le comparer à d'autres frameworks d’application web (ou ensembles d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc. Des frameworks avec validation des données, sérialisation et documentation automatiques intégrées. diff --git a/docs/fr/docs/deployment/docker.md b/docs/fr/docs/deployment/docker.md index 05b597a2df..ec30f96079 100644 --- a/docs/fr/docs/deployment/docker.md +++ b/docs/fr/docs/deployment/docker.md @@ -1,75 +1,150 @@ -# Déployer avec Docker +# FastAPI dans des conteneurs - Docker { #fastapi-in-containers-docker } -Dans cette section, vous verrez des instructions et des liens vers des guides pour savoir comment : +Lors du déploiement d'applications FastAPI, une approche courante consiste à construire une **image de conteneur Linux**. C'est généralement fait avec **Docker**. Vous pouvez ensuite déployer cette image de conteneur de plusieurs façons possibles. -* Faire de votre application **FastAPI** une image/conteneur Docker avec une performance maximale. En environ **5 min**. -* (Optionnellement) comprendre ce que vous, en tant que développeur, devez savoir sur HTTPS. -* Configurer un cluster en mode Docker Swarm avec HTTPS automatique, même sur un simple serveur à 5 dollars US/mois. En environ **20 min**. -* Générer et déployer une application **FastAPI** complète, en utilisant votre cluster Docker Swarm, avec HTTPS, etc. En environ **10 min**. - -Vous pouvez utiliser **Docker** pour le déploiement. Il présente plusieurs avantages comme la sécurité, la réplicabilité, la simplicité de développement, etc. - -Si vous utilisez Docker, vous pouvez utiliser l'image Docker officielle : - -## tiangolo/uvicorn-gunicorn-fastapi - -Cette image est dotée d'un mécanisme d'"auto-tuning", de sorte qu'il vous suffit d'ajouter votre code pour obtenir automatiquement des performances très élevées. Et sans faire de sacrifices. - -Mais vous pouvez toujours changer et mettre à jour toutes les configurations avec des variables d'environnement ou des fichiers de configuration. +L'utilisation de conteneurs Linux présente plusieurs avantages, notamment la **sécurité**, la **réplicabilité**, la **simplicité**, entre autres. /// tip | Astuce -Pour voir toutes les configurations et options, rendez-vous sur la page de l'image Docker : tiangolo/uvicorn-gunicorn-fastapi. +Vous êtes pressé et vous connaissez déjà tout ça ? Allez directement au [`Dockerfile` ci-dessous 👇](#build-a-docker-image-for-fastapi). /// -## Créer un `Dockerfile` - -* Allez dans le répertoire de votre projet. -* Créez un `Dockerfile` avec : +
+Aperçu du Dockerfile 👀 ```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 +FROM python:3.9 -COPY ./app /app +WORKDIR /code + +COPY ./requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +COPY ./app /code/app + +CMD ["fastapi", "run", "app/main.py", "--port", "80"] + +# Si vous exécutez derrière un proxy comme Nginx ou Traefik, ajoutez --proxy-headers +# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"] ``` -### Applications plus larges +
-Si vous avez suivi la section sur la création d' [Applications avec plusieurs fichiers](../tutorial/bigger-applications.md){.internal-link target=_blank}, votre `Dockerfile` pourrait ressembler à ceci : +## Qu'est-ce qu'un conteneur { #what-is-a-container } -```Dockerfile -FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7 +Les conteneurs (principalement les conteneurs Linux) sont un moyen très **léger** d'empaqueter des applications, y compris toutes leurs dépendances et les fichiers nécessaires, tout en les isolant des autres conteneurs (autres applications ou composants) dans le même système. -COPY ./app /app/app +Les conteneurs Linux s'exécutent en utilisant le même noyau Linux que l'hôte (machine, machine virtuelle, serveur cloud, etc.). Cela signifie simplement qu'ils sont très légers (comparés à des machines virtuelles complètes émulant un système d'exploitation entier). + +Ainsi, les conteneurs consomment **peu de ressources**, une quantité comparable à l'exécution directe des processus (alors qu'une machine virtuelle consommerait beaucoup plus). + +Les conteneurs ont également leurs propres processus d'exécution **isolés** (généralement un seul processus), leur système de fichiers et leur réseau, ce qui simplifie le déploiement, la sécurité, le développement, etc. + +## Qu'est-ce qu'une image de conteneur { #what-is-a-container-image } + +Un **conteneur** s'exécute à partir d'une **image de conteneur**. + +Une image de conteneur est une version **statique** de tous les fichiers, des variables d'environnement et de la commande/le programme par défaut devant être présents dans un conteneur. Ici, **statique** signifie que l'**image** du conteneur ne s'exécute pas, elle n'est pas en cours d'exécution, ce ne sont que les fichiers et métadonnées empaquetés. + +Par opposition à une « **image de conteneur** » qui correspond aux contenus statiques stockés, un « **conteneur** » fait normalement référence à l'instance en cours d'exécution, la chose qui est **exécutée**. + +Lorsque le **conteneur** est démarré et en cours d'exécution (démarré à partir d'une **image de conteneur**), il peut créer ou modifier des fichiers, des variables d'environnement, etc. Ces changements n'existeront que dans ce conteneur, mais ne persisteront pas dans l'image de conteneur sous-jacente (ils ne seront pas enregistrés sur le disque). + +Une image de conteneur est comparable au **programme** et à ses contenus, par exemple `python` et un fichier `main.py`. + +Et le **conteneur** lui-même (par opposition à l'**image de conteneur**) est l'instance en cours d'exécution réelle de l'image, comparable à un **processus**. En fait, un conteneur ne fonctionne que lorsqu'il a un **processus en cours d'exécution** (et normalement, il s'agit d'un seul processus). Le conteneur s'arrête lorsqu'aucun processus n'y est en cours d'exécution. + +## Images de conteneur { #container-images } + +Docker a été l'un des principaux outils pour créer et gérer des **images de conteneur** et des **conteneurs**. + +Et il existe un Docker Hub public avec des **images de conteneur officielles** pré-construites pour de nombreux outils, environnements, bases de données et applications. + +Par exemple, il existe une image Python officielle. + +Et il existe beaucoup d'autres images pour différentes choses comme des bases de données, par exemple : + +* PostgreSQL +* MySQL +* MongoDB +* Redis, etc. + +En utilisant une image de conteneur pré-construite, il est très facile de **combiner** et d'utiliser différents outils. Par exemple, pour essayer une nouvelle base de données. Dans la plupart des cas, vous pouvez utiliser les **images officielles** et simplement les configurer avec des variables d'environnement. + +Ainsi, dans de nombreux cas, vous pouvez apprendre les conteneurs et Docker et réutiliser ces connaissances avec de nombreux outils et composants différents. + +Vous exécuteriez donc **plusieurs conteneurs** avec des éléments différents, comme une base de données, une application Python, un serveur web avec une application frontend React, et les connecter entre eux via leur réseau interne. + +Tous les systèmes de gestion de conteneurs (comme Docker ou Kubernetes) disposent de ces fonctionnalités réseau intégrées. + +## Conteneurs et processus { #containers-and-processes } + +Une **image de conteneur** inclut normalement dans ses métadonnées le programme/la commande par défaut à exécuter lorsque le **conteneur** est démarré et les paramètres à transmettre à ce programme. Très similaire à ce que vous utiliseriez en ligne de commande. + +Lorsqu'un **conteneur** est démarré, il exécutera cette commande/ce programme (bien que vous puissiez la/le remplacer et faire exécuter une autre commande/un autre programme). + +Un conteneur fonctionne tant que le **processus principal** (commande ou programme) est en cours d'exécution. + +Un conteneur a normalement un **seul processus**, mais il est aussi possible de démarrer des sous-processus à partir du processus principal, et ainsi vous aurez **plusieurs processus** dans le même conteneur. + +Mais il n'est pas possible d'avoir un conteneur en cours d'exécution sans **au moins un processus en cours**. Si le processus principal s'arrête, le conteneur s'arrête. + +## Construire une image Docker pour FastAPI { #build-a-docker-image-for-fastapi } + +Très bien, construisons quelque chose maintenant ! 🚀 + +Je vais vous montrer comment construire une **image Docker** pour FastAPI **à partir de zéro**, basée sur l'image **officielle Python**. + +C'est ce que vous voudrez faire dans **la plupart des cas**, par exemple : + +* Utiliser **Kubernetes** ou des outils similaires +* Exécuter sur un **Raspberry Pi** +* Utiliser un service cloud qui exécuterait une image de conteneur pour vous, etc. + +### Dépendances des paquets { #package-requirements } + +Vous aurez normalement les **dépendances des paquets** de votre application dans un fichier. + +Cela dépendra principalement de l'outil que vous utilisez pour **installer** ces dépendances. + +La manière la plus courante consiste à avoir un fichier `requirements.txt` avec les noms des paquets et leurs versions, un par ligne. + +Vous utiliserez bien sûr les mêmes idées que vous avez lues dans [À propos des versions de FastAPI](versions.md){.internal-link target=_blank} pour définir les plages de versions. + +Par exemple, votre `requirements.txt` pourrait ressembler à : + +``` +fastapi[standard]>=0.113.0,<0.114.0 +pydantic>=2.7.0,<3.0.0 ``` -### Raspberry Pi et autres architectures +Et vous installerez normalement ces dépendances de paquets avec `pip`, par exemple : -Si vous utilisez Docker sur un Raspberry Pi (qui a un processeur ARM) ou toute autre architecture, vous pouvez créer un `Dockerfile` à partir de zéro, basé sur une image de base Python (qui est multi-architecture) et utiliser Uvicorn seul. +
-Dans ce cas, votre `Dockerfile` pourrait ressembler à ceci : - -```Dockerfile -FROM python:3.7 - -RUN pip install fastapi uvicorn - -EXPOSE 80 - -COPY ./app /app - -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] +```console +$ pip install -r requirements.txt +---> 100% +Successfully installed fastapi pydantic ``` -## Créer le code **FastAPI**. +
-* Créer un répertoire `app` et y entrer. -* Créez un fichier `main.py` avec : +/// info + +Il existe d'autres formats et outils pour définir et installer des dépendances de paquets. + +/// + +### Créer le code **FastAPI** { #create-the-fastapi-code } + +* Créez un répertoire `app` et entrez dedans. +* Créez un fichier vide `__init__.py`. +* Créez un fichier `main.py` avec : ```Python -from typing import Optional - from fastapi import FastAPI app = FastAPI() @@ -81,22 +156,168 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Optional[str] = None): +def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} ``` -* Vous devriez maintenant avoir une structure de répertoire telle que : +### Dockerfile { #dockerfile } + +Maintenant, dans le même répertoire de projet, créez un fichier `Dockerfile` avec : + +```{ .dockerfile .annotate } +# (1)! +FROM python:3.9 + +# (2)! +WORKDIR /code + +# (3)! +COPY ./requirements.txt /code/requirements.txt + +# (4)! +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# (5)! +COPY ./app /code/app + +# (6)! +CMD ["fastapi", "run", "app/main.py", "--port", "80"] +``` + +1. Démarrer à partir de l'image de base Python officielle. + +2. Définir le répertoire de travail courant sur `/code`. + + C'est là que nous placerons le fichier `requirements.txt` et le répertoire `app`. + +3. Copier le fichier des dépendances vers le répertoire `/code`. + + Copier **uniquement** le fichier des dépendances en premier, pas le reste du code. + + Comme ce fichier **ne change pas souvent**, Docker le détectera et utilisera le **cache** pour cette étape, ce qui activera le cache pour l'étape suivante aussi. + +4. Installer les dépendances listées dans le fichier des dépendances. + + L'option `--no-cache-dir` indique à `pip` de ne pas enregistrer localement les paquets téléchargés, car cela ne sert que si `pip` devait être relancé pour installer les mêmes paquets, mais ce n'est pas le cas lorsque l'on travaille avec des conteneurs. + + /// note | Remarque + + Le `--no-cache-dir` concerne uniquement `pip`, cela n'a rien à voir avec Docker ou les conteneurs. + + /// + + L'option `--upgrade` indique à `pip` de mettre à niveau les paquets s'ils sont déjà installés. + + Comme l'étape précédente de copie du fichier peut être détectée par le **cache Docker**, cette étape **utilisera également le cache Docker** lorsqu'il est disponible. + + L'utilisation du cache à cette étape vous **fera gagner** beaucoup de **temps** lors de la reconstruction de l'image encore et encore pendant le développement, au lieu de **télécharger et installer** toutes les dépendances **à chaque fois**. + +5. Copier le répertoire `./app` dans le répertoire `/code`. + + Comme cela contient tout le code qui est ce qui **change le plus fréquemment**, le **cache** Docker ne sera pas facilement utilisé pour cette étape ou pour les **étapes suivantes**. + + Il est donc important de placer cela **vers la fin** du `Dockerfile`, pour optimiser les temps de construction de l'image de conteneur. + +6. Définir la **commande** pour utiliser `fastapi run`, qui utilise Uvicorn sous le capot. + + `CMD` prend une liste de chaînes, chacune de ces chaînes correspond à ce que vous taperiez en ligne de commande séparé par des espaces. + + Cette commande sera exécutée à partir du **répertoire de travail courant**, le même répertoire `/code` que vous avez défini plus haut avec `WORKDIR /code`. + +/// tip | Astuce + +Passez en revue ce que fait chaque ligne en cliquant sur chaque bulle numérotée dans le code. 👆 + +/// + +/// warning | Alertes + +Vous devez vous assurer d'utiliser **toujours** la **forme exec** de l'instruction `CMD`, comme expliqué ci-dessous. + +/// + +#### Utiliser `CMD` - Forme Exec { #use-cmd-exec-form } + +L'instruction Docker `CMD` peut être écrite sous deux formes : + +✅ Forme **Exec** : + +```Dockerfile +# ✅ À faire +CMD ["fastapi", "run", "app/main.py", "--port", "80"] +``` + +⛔️ Forme **Shell** : + +```Dockerfile +# ⛔️ À ne pas faire +CMD fastapi run app/main.py --port 80 +``` + +Assurez-vous d'utiliser toujours la forme **exec** pour garantir que FastAPI peut s'arrêter proprement et que les [événements de cycle de vie](../advanced/events.md){.internal-link target=_blank} sont déclenchés. + +Vous pouvez en lire davantage dans la documentation Docker sur les formes shell et exec. + +Cela peut être très visible lors de l'utilisation de `docker compose`. Voir cette section de la FAQ Docker Compose pour plus de détails techniques : Pourquoi mes services mettent-ils 10 secondes à se recréer ou à s'arrêter ?. + +#### Structure du répertoire { #directory-structure } + +Vous devriez maintenant avoir une structure de répertoire comme : ``` . ├── app +│   ├── __init__.py │ └── main.py -└── Dockerfile +├── Dockerfile +└── requirements.txt ``` -## Construire l'image Docker +#### Derrière un proxy de terminaison TLS { #behind-a-tls-termination-proxy } -* Allez dans le répertoire du projet (dans lequel se trouve votre `Dockerfile`, contenant votre répertoire `app`). +Si vous exécutez votre conteneur derrière un proxy de terminaison TLS (load balancer) comme Nginx ou Traefik, ajoutez l'option `--proxy-headers`, cela indiquera à Uvicorn (via la CLI FastAPI) de faire confiance aux en-têtes envoyés par ce proxy lui indiquant que l'application s'exécute derrière HTTPS, etc. + +```Dockerfile +CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"] +``` + +#### Cache Docker { #docker-cache } + +Il y a une astuce importante dans ce `Dockerfile`, nous copions d'abord **le fichier des dépendances seul**, pas le reste du code. Laissez-moi vous expliquer pourquoi. + +```Dockerfile +COPY ./requirements.txt /code/requirements.txt +``` + +Docker et d'autres outils **construisent** ces images de conteneur **de manière incrémentale**, en ajoutant **une couche au-dessus de l'autre**, en commençant par le haut du `Dockerfile` et en ajoutant tous les fichiers créés par chacune des instructions du `Dockerfile`. + +Docker et des outils similaires utilisent également un **cache interne** lors de la construction de l'image : si un fichier n'a pas changé depuis la dernière construction de l'image de conteneur, alors il va **réutiliser la même couche** créée la dernière fois, au lieu de recopier le fichier et créer une nouvelle couche à partir de zéro. + +Éviter simplement la copie des fichiers n'améliore pas nécessairement les choses de manière significative, mais comme il a utilisé le cache pour cette étape, il peut **utiliser le cache pour l'étape suivante**. Par exemple, il peut utiliser le cache pour l'instruction qui installe les dépendances avec : + +```Dockerfile +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt +``` + +Le fichier des dépendances **ne changera pas fréquemment**. Ainsi, en copiant uniquement ce fichier, Docker pourra **utiliser le cache** pour cette étape. + +Et ensuite, Docker pourra **utiliser le cache pour l'étape suivante** qui télécharge et installe ces dépendances. Et c'est là que nous **gagnons beaucoup de temps**. ✨ ... et évitons l'ennui en attendant. 😪😆 + +Télécharger et installer les dépendances de paquets **peut prendre des minutes**, mais utiliser le **cache** ne **prendra que quelques secondes** au plus. + +Et comme vous reconstruirez l'image de conteneur encore et encore pendant le développement pour vérifier que vos modifications de code fonctionnent, cela vous fera gagner beaucoup de temps cumulé. + +Ensuite, vers la fin du `Dockerfile`, nous copions tout le code. Comme c'est ce qui **change le plus fréquemment**, nous le plaçons vers la fin, car presque toujours, tout ce qui suit cette étape ne pourra pas utiliser le cache. + +```Dockerfile +COPY ./app /code/app +``` + +### Construire l'image Docker { #build-the-docker-image } + +Maintenant que tous les fichiers sont en place, construisons l'image de conteneur. + +* Allez dans le répertoire du projet (là où se trouve votre `Dockerfile`, contenant votre répertoire `app`). * Construisez votre image FastAPI :
@@ -109,9 +330,17 @@ $ docker build -t myimage .
-## Démarrer le conteneur Docker +/// tip | Astuce -* Exécutez un conteneur basé sur votre image : +Remarquez le `.` à la fin, équivalent à `./`, il indique à Docker le répertoire à utiliser pour construire l'image de conteneur. + +Dans ce cas, c'est le même répertoire courant (`.`). + +/// + +### Démarrer le conteneur Docker { #start-the-docker-container } + +* Exécutez un conteneur basé sur votre image :
@@ -121,65 +350,269 @@ $ docker run -d --name mycontainer -p 80:80 myimage
-Vous disposez maintenant d'un serveur FastAPI optimisé dans un conteneur Docker. Configuré automatiquement pour votre -serveur actuel (et le nombre de cœurs du CPU). +## Vérifier { #check-it } -## Vérifier +Vous devriez pouvoir le vérifier via l'URL de votre conteneur Docker, par exemple : http://192.168.99.100/items/5?q=somequery ou http://127.0.0.1/items/5?q=somequery (ou équivalent, en utilisant votre hôte Docker). -Vous devriez pouvoir accéder à votre application via l'URL de votre conteneur Docker, par exemple : http://192.168.99.100/items/5?q=somequery ou http://127.0.0.1/items/5?q=somequery (ou équivalent, en utilisant votre hôte Docker). - -Vous verrez quelque chose comme : +Vous verrez quelque chose comme : ```JSON {"item_id": 5, "q": "somequery"} ``` -## Documentation interactive de l'API +## Documentation interactive de l'API { #interactive-api-docs } -Vous pouvez maintenant visiter http://192.168.99.100/docs ou http://127.0.0.1/docs (ou équivalent, en utilisant votre hôte Docker). +Vous pouvez maintenant aller sur http://192.168.99.100/docs ou http://127.0.0.1/docs (ou équivalent, en utilisant votre hôte Docker). -Vous verrez la documentation interactive automatique de l'API (fournie par Swagger UI) : +Vous verrez la documentation interactive automatique de l'API (fournie par Swagger UI) : ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -## Documentation de l'API alternative +## Documentation alternative de l'API { #alternative-api-docs } -Et vous pouvez également aller sur http://192.168.99.100/redoc ou http://127.0.0.1/redoc (ou équivalent, en utilisant votre hôte Docker). +Et vous pouvez aussi aller sur http://192.168.99.100/redoc ou http://127.0.0.1/redoc (ou équivalent, en utilisant votre hôte Docker). -Vous verrez la documentation automatique alternative (fournie par ReDoc) : +Vous verrez la documentation automatique alternative (fournie par ReDoc) : ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## Traefik +## Construire une image Docker avec un FastAPI mono-fichier { #build-a-docker-image-with-a-single-file-fastapi } -Traefik est un reverse proxy/load balancer -haute performance. Il peut faire office de "Proxy de terminaison TLS" (entre autres fonctionnalités). +Si votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./app`, votre structure de fichiers pourrait ressembler à ceci : -Il est intégré à Let's Encrypt. Ainsi, il peut gérer toutes les parties HTTPS, y compris l'acquisition et le renouvellement des certificats. +``` +. +├── Dockerfile +├── main.py +└── requirements.txt +``` -Il est également intégré à Docker. Ainsi, vous pouvez déclarer vos domaines dans les configurations de chaque application et faire en sorte qu'elles lisent ces configurations, génèrent les certificats HTTPS et servent via HTTPS à votre application automatiquement, sans nécessiter aucune modification de leurs configurations. +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 + +WORKDIR /code + +COPY ./requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# (1)! +COPY ./main.py /code/ + +# (2)! +CMD ["fastapi", "run", "main.py", "--port", "80"] +``` + +1. Copier le fichier `main.py` directement dans le répertoire `/code` (sans répertoire `./app`). + +2. Utiliser `fastapi run` pour servir votre application dans le fichier unique `main.py`. + +Lorsque vous passez le fichier à `fastapi run`, il détectera automatiquement qu'il s'agit d'un fichier unique et non d'un package et saura comment l'importer et servir votre application FastAPI. 😎 + +## Concepts de déploiement { #deployment-concepts } + +Parlons à nouveau de certains des mêmes [Concepts de déploiement](concepts.md){.internal-link target=_blank} en termes de conteneurs. + +Les conteneurs sont principalement un outil pour simplifier le processus de **construction et de déploiement** d'une application, mais ils n'imposent pas une approche particulière pour gérer ces **concepts de déploiement**, et il existe plusieurs stratégies possibles. + +La **bonne nouvelle**, c'est qu'avec chaque stratégie différente, il existe un moyen de couvrir tous les concepts de déploiement. 🎉 + +Passons en revue ces **concepts de déploiement** en termes de conteneurs : + +* HTTPS +* Exécution au démarrage +* Redémarrages +* Réplication (le nombre de processus en cours d'exécution) +* Mémoire +* Étapes préalables au démarrage + +## HTTPS { #https } + +Si l'on se concentre uniquement sur l'**image de conteneur** pour une application FastAPI (et plus tard sur le **conteneur** en cours d'exécution), HTTPS serait normalement géré **à l'extérieur** par un autre outil. + +Cela pourrait être un autre conteneur, par exemple avec Traefik, gérant **HTTPS** et l'acquisition **automatique** des **certificats**. + +/// tip | Astuce + +Traefik s'intègre avec Docker, Kubernetes, et d'autres, donc il est très facile de configurer HTTPS pour vos conteneurs avec lui. + +/// + +Alternativement, HTTPS pourrait être géré par un fournisseur cloud comme l'un de leurs services (tout en exécutant l'application dans un conteneur). + +## Exécution au démarrage et redémarrages { #running-on-startup-and-restarts } + +Il y a normalement un autre outil chargé de **démarrer et exécuter** votre conteneur. + +Cela pourrait être **Docker** directement, **Docker Compose**, **Kubernetes**, un **service cloud**, etc. + +Dans la plupart (ou toutes) des situations, il existe une option simple pour activer l'exécution du conteneur au démarrage et activer les redémarrages en cas d'échec. Par exemple, dans Docker, c'est l'option de ligne de commande `--restart`. + +Sans utiliser de conteneurs, faire en sorte que les applications s'exécutent au démarrage et avec redémarrages peut être fastidieux et difficile. Mais en **travaillant avec des conteneurs**, dans la plupart des cas, cette fonctionnalité est incluse par défaut. ✨ + +## Réplication - Nombre de processus { #replication-number-of-processes } + +Si vous avez un 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**. + +Dans ces cas, vous voudrez probablement construire une **image Docker à partir de zéro** comme [expliqué ci-dessus](#dockerfile), en installant vos dépendances et en exécutant **un seul processus Uvicorn** au lieu d'utiliser plusieurs workers Uvicorn. + +### Équilibreur de charge { #load-balancer } + +Lors de l'utilisation de conteneurs, vous aurez normalement un composant **à l'écoute sur le port principal**. Cela pourrait être un autre conteneur qui est également un **proxy de terminaison TLS** pour gérer **HTTPS** ou un outil similaire. + +Comme ce composant prend la **charge** des requêtes et la distribue entre les workers de façon (espérons-le) **équilibrée**, on l'appelle également communément un **équilibreur de charge**. + +/// tip | Astuce + +Le même composant de **proxy de terminaison TLS** utilisé pour HTTPS sera probablement aussi un **équilibreur de charge**. + +/// + +Et en travaillant avec des conteneurs, le même système que vous utilisez pour les démarrer et les gérer dispose déjà d'outils internes pour transmettre la **communication réseau** (par ex. les requêtes HTTP) depuis cet **équilibreur de charge** (qui peut aussi être un **proxy de terminaison TLS**) vers le ou les conteneurs avec votre application. + +### Un équilibreur de charge - Plusieurs conteneurs worker { #one-load-balancer-multiple-worker-containers } + +Lorsque vous travaillez avec **Kubernetes** ou des systèmes de gestion de conteneurs distribués similaires, l'utilisation de leurs mécanismes réseau internes permet au **seul équilibreur de charge** à l'écoute sur le **port** principal de transmettre la communication (les requêtes) vers potentiellement **plusieurs conteneurs** exécutant votre application. + +Chacun de ces conteneurs exécutant votre application aura normalement **un seul processus** (par ex. un processus Uvicorn exécutant votre application FastAPI). Ils seront tous des **conteneurs identiques**, exécutant la même chose, mais chacun avec son propre processus, sa mémoire, etc. De cette façon, vous profiterez de la **parallélisation** sur **différents cœurs** du CPU, voire sur **différentes machines**. + +Et le système de conteneurs distribués avec l'**équilibreur de charge** **distribuera les requêtes** à chacun des conteneurs exécutant votre application **à tour de rôle**. Ainsi, chaque requête pourrait être traitée par l'un des multiples **conteneurs répliqués** exécutant votre application. + +Et normalement cet **équilibreur de charge** pourra gérer des requêtes qui vont vers *d'autres* applications dans votre cluster (par ex. vers un autre domaine, ou sous un autre préfixe de chemin d'URL), et transmettra cette communication aux bons conteneurs pour *cette autre* application s'exécutant dans votre cluster. + +### Un processus par conteneur { #one-process-per-container } + +Dans ce type de scénario, vous voudrez probablement avoir **un seul processus (Uvicorn) par conteneur**, puisque vous gérez déjà la réplication au niveau du cluster. + +Donc, dans ce cas, vous **ne voudrez pas** avoir plusieurs workers dans le conteneur, par exemple avec l'option de ligne de commande `--workers`. Vous voudrez avoir **un seul processus Uvicorn** par conteneur (mais probablement plusieurs conteneurs). + +Avoir un autre gestionnaire de processus à l'intérieur du conteneur (comme ce serait le cas avec plusieurs workers) n'ajouterait que de la **complexité inutile** que vous gérez très probablement déjà avec votre système de cluster. + +### Conteneurs avec plusieurs processus et cas particuliers { #containers-with-multiple-processes-and-special-cases } + +Bien sûr, il existe des **cas particuliers** où vous pourriez vouloir avoir **un conteneur** avec plusieurs **processus worker Uvicorn** à l'intérieur. + +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 + +WORKDIR /code + +COPY ./requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +COPY ./app /code/app + +# (1)! +CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"] +``` + +1. Ici, nous utilisons l'option de ligne de commande `--workers` pour définir le nombre de workers à 4. + +Voici quelques exemples où cela pourrait avoir du sens : + +#### Une application simple { #a-simple-app } + +Vous pourriez vouloir un gestionnaire de processus dans le conteneur si votre application est **suffisamment simple** pour s'exécuter sur un **seul serveur**, pas un cluster. + +#### Docker Compose { #docker-compose } + +Vous pourriez déployer sur un **seul serveur** (pas un cluster) avec **Docker Compose**, donc vous n'auriez pas un moyen simple de gérer la réplication des conteneurs (avec Docker Compose) tout en préservant le réseau partagé et l'**équilibrage de charge**. + +Vous pourriez alors vouloir avoir **un seul conteneur** avec un **gestionnaire de processus** qui démarre **plusieurs processus worker** à l'intérieur. --- -Avec ces informations et ces outils, passez à la section suivante pour tout combiner. +L'idée principale est que **rien** de tout cela ne sont des **règles gravées dans la pierre** que vous devez suivre aveuglément. Vous pouvez utiliser ces idées pour **évaluer votre propre cas d'usage** et décider de la meilleure approche pour votre système, en vérifiant comment gérer les concepts suivants : -## Cluster en mode Docker Swarm avec Traefik et HTTPS +* Sécurité - HTTPS +* Exécution au démarrage +* Redémarrages +* Réplication (le nombre de processus en cours d'exécution) +* Mémoire +* Étapes préalables au démarrage -Vous pouvez avoir un cluster en mode Docker Swarm configuré en quelques minutes (environ 20 min) avec un processus Traefik principal gérant HTTPS (y compris l'acquisition et le renouvellement des certificats). +## Mémoire { #memory } -En utilisant le mode Docker Swarm, vous pouvez commencer par un "cluster" d'une seule machine (il peut même s'agir -d'un serveur à 5 USD/mois) et ensuite vous pouvez vous développer autant que vous le souhaitez en ajoutant d'autres serveurs. +Si vous exécutez **un seul processus par conteneur**, vous aurez une quantité de mémoire consommée plus ou moins bien définie, stable et limitée par chacun de ces conteneurs (plus d'un s'ils sont répliqués). -Pour configurer un cluster en mode Docker Swarm avec Traefik et la gestion de HTTPS, suivez ce guide : +Vous pouvez alors définir ces mêmes limites et exigences de mémoire dans vos configurations pour votre système de gestion de conteneurs (par exemple dans **Kubernetes**). De cette façon, il pourra **répliquer les conteneurs** sur les **machines disponibles** en tenant compte de la quantité de mémoire dont ils ont besoin et de la quantité disponible sur les machines du cluster. -### Docker Swarm Mode et Traefik pour un cluster HTTPS +Si votre application est **simple**, cela ne sera probablement **pas un problème**, et vous n'aurez peut-être pas besoin de spécifier des limites de mémoire strictes. Mais si vous **utilisez beaucoup de mémoire** (par exemple avec des modèles de **machine learning**), vous devez vérifier combien de mémoire vous consommez et ajuster le **nombre de conteneurs** qui s'exécutent sur **chaque machine** (et peut-être ajouter plus de machines à votre cluster). -### Déployer une application FastAPI +Si vous exécutez **plusieurs processus par conteneur**, vous devez vous assurer que le nombre de processus démarrés ne **consomme pas plus de mémoire** que ce qui est disponible. -La façon la plus simple de tout mettre en place, serait d'utiliser les [**Générateurs de projet FastAPI**](../project-generation.md){.internal-link target=_blank}. +## Étapes préalables au démarrage et conteneurs { #previous-steps-before-starting-and-containers } -Le génerateur de projet adéquat est conçu pour être intégré à ce cluster Docker Swarm avec Traefik et HTTPS décrit ci-dessus. +Si vous utilisez des conteneurs (par ex. Docker, Kubernetes), alors il existe deux approches principales que vous pouvez utiliser. -Vous pouvez générer un projet en 2 min environ. +### Plusieurs conteneurs { #multiple-containers } -Le projet généré a des instructions pour le déployer et le faire prend 2 min de plus. +Si vous avez **plusieurs conteneurs**, probablement chacun exécutant un **seul processus** (par exemple, dans un cluster **Kubernetes**), alors vous voudrez probablement avoir un **conteneur séparé** effectuant le travail des **étapes préalables** dans un seul conteneur, exécutant un seul processus, **avant** d'exécuter les conteneurs worker répliqués. + +/// info + +Si vous utilisez Kubernetes, ce sera probablement un Init Container. + +/// + +Si, dans votre cas d'usage, il n'y a pas de problème à exécuter ces étapes préalables **plusieurs fois en parallèle** (par exemple si vous n'exécutez pas de migrations de base de données, mais vérifiez simplement si la base de données est prête), alors vous pourriez aussi simplement les mettre dans chaque conteneur juste avant de démarrer le processus principal. + +### Un seul conteneur { #single-container } + +Si vous avez une configuration simple, avec **un seul conteneur** qui démarre ensuite plusieurs **processus worker** (ou un seul processus aussi), vous pouvez alors exécuter ces étapes préalables dans le même conteneur, juste avant de démarrer le processus avec l'application. + +### Image Docker de base { #base-docker-image } + +Il existait une image Docker officielle FastAPI : tiangolo/uvicorn-gunicorn-fastapi. Mais elle est désormais dépréciée. ⛔️ + +Vous ne devriez probablement **pas** utiliser cette image Docker de base (ni aucune autre similaire). + +Si vous utilisez **Kubernetes** (ou autres) et que vous définissez déjà la **réplication** au niveau du cluster, avec plusieurs **conteneurs**. Dans ces cas, il est préférable de **construire une image à partir de zéro** comme décrit ci-dessus : [Construire une image Docker pour FastAPI](#build-a-docker-image-for-fastapi). + +Et si vous devez avoir plusieurs workers, vous pouvez simplement utiliser l'option de ligne de commande `--workers`. + +/// note | Détails techniques + +L'image Docker a été créée à une époque où Uvicorn ne supportait pas la gestion et le redémarrage des workers morts, il fallait donc utiliser Gunicorn avec Uvicorn, ce qui ajoutait pas mal de complexité, uniquement pour que Gunicorn gère et redémarre les processus worker Uvicorn. + +Mais maintenant qu'Uvicorn (et la commande `fastapi`) supporte l'usage de `--workers`, il n'y a plus de raison d'utiliser une image Docker de base au lieu de construire la vôtre (c'est à peu près la même quantité de code 😅). + +/// + +## Déployer l'image de conteneur { #deploy-the-container-image } + +Après avoir une image de conteneur (Docker), il existe plusieurs façons de la déployer. + +Par exemple : + +* Avec **Docker Compose** sur un seul serveur +* Avec un cluster **Kubernetes** +* Avec un cluster Docker Swarm Mode +* Avec un autre outil comme Nomad +* Avec un service cloud qui prend votre image de conteneur et la déploie + +## Image Docker avec `uv` { #docker-image-with-uv } + +Si vous utilisez uv pour installer et gérer votre projet, vous pouvez suivre leur guide Docker pour uv. + +## Récapitulatif { #recap } + +Avec les systèmes de conteneurs (par ex. avec **Docker** et **Kubernetes**), il devient assez simple de gérer tous les **concepts de déploiement** : + +* HTTPS +* Exécution au démarrage +* Redémarrages +* Réplication (le nombre de processus en cours d'exécution) +* Mémoire +* Étapes préalables au démarrage + +Dans la plupart des cas, vous ne voudrez probablement pas utiliser d'image de base, et au contraire **construire une image de conteneur à partir de zéro** basée sur l'image Docker Python officielle. + +En prenant soin de l'**ordre** des instructions dans le `Dockerfile` et du **cache Docker**, vous pouvez **minimiser les temps de construction**, maximiser votre productivité (et éviter l'ennui). 😎 diff --git a/docs/fr/docs/deployment/https.md b/docs/fr/docs/deployment/https.md index 3f7068ff03..74d38cdb9f 100644 --- a/docs/fr/docs/deployment/https.md +++ b/docs/fr/docs/deployment/https.md @@ -1,56 +1,231 @@ -# À propos de HTTPS +# À propos de HTTPS { #about-https } -Il est facile de penser que HTTPS peut simplement être "activé" ou non. +Il est facile de supposer que HTTPS est quelque chose qui est simplement « activé » ou non. Mais c'est beaucoup plus complexe que cela. -/// tip +/// tip | Astuce -Si vous êtes pressé ou si cela ne vous intéresse pas, passez aux sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques. +Si vous êtes pressé ou si cela ne vous intéresse pas, continuez avec les sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques. /// -Pour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez https://howhttps.works/. +Pour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez https://howhttps.works/. Maintenant, du point de vue d'un développeur, voici plusieurs choses à avoir en tête en pensant au HTTPS : -* Pour le HTTPS, le serveur a besoin de "certificats" générés par une tierce partie. - * Ces certificats sont en fait acquis auprès de la tierce partie, et non "générés". -* Les certificats ont une durée de vie. - * Ils expirent. - * Puis ils doivent être renouvelés et acquis à nouveau auprès de la tierce partie. -* Le cryptage de la connexion se fait au niveau du protocole TCP. - * C'est une couche en dessous de HTTP. - * Donc, le certificat et le traitement du cryptage sont faits avant HTTP. -* TCP ne connaît pas les "domaines", seulement les adresses IP. - * L'information sur le domaine spécifique demandé se trouve dans les données HTTP. -* Les certificats HTTPS "certifient" un certain domaine, mais le protocole et le cryptage se font au niveau TCP, avant de savoir quel domaine est traité. -* Par défaut, cela signifie que vous ne pouvez avoir qu'un seul certificat HTTPS par adresse IP. - * Quelle que soit la taille de votre serveur ou la taille de chacune des applications qu'il contient. - * Il existe cependant une solution à ce problème. -* Il existe une extension du protocole TLS (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée SNI (indication du nom du serveur). - * Cette extension SNI permet à un seul serveur (avec une seule adresse IP) d'avoir plusieurs certificats HTTPS et de servir plusieurs domaines/applications HTTPS. - * Pour que cela fonctionne, un seul composant (programme) fonctionnant sur le serveur, écoutant sur l'adresse IP publique, doit avoir tous les certificats HTTPS du serveur. -* Après avoir obtenu une connexion sécurisée, le protocole de communication est toujours HTTP. - * Le contenu est crypté, même s'il est envoyé avec le protocole HTTP. +* Pour le HTTPS, **le serveur** doit **disposer de « certificats »** générés par une **tierce partie**. + * Ces certificats sont en réalité **acquis** auprès de la tierce partie, et non « générés ». +* Les certificats ont une **durée de vie**. + * Ils **expirent**. + * Puis ils doivent être **renouvelés**, **acquis à nouveau** auprès de la tierce partie. +* Le cryptage de la connexion se fait au **niveau TCP**. + * C'est une couche **en dessous de HTTP**. + * Donc, la gestion du **certificat et du cryptage** est effectuée **avant HTTP**. +* **TCP ne connaît pas les « domaines »**. Il ne connaît que les adresses IP. + * L'information sur le **domaine spécifique** demandé se trouve dans les **données HTTP**. +* Les **certificats HTTPS** « certifient » un **certain domaine**, mais le protocole et le cryptage se font au niveau TCP, **avant de savoir** quel domaine est traité. +* **Par défaut**, cela signifie que vous ne pouvez avoir qu'**un seul certificat HTTPS par adresse IP**. + * Quelle que soit la taille de votre serveur ou la petitesse de chacune des applications qu'il contient. + * Il existe cependant une **solution** à ce problème. +* Il existe une **extension** du protocole **TLS** (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée **SNI**. + * Cette extension SNI permet à un seul serveur (avec une **seule adresse IP**) d'avoir **plusieurs certificats HTTPS** et de servir **plusieurs domaines/applications HTTPS**. + * Pour que cela fonctionne, un **seul** composant (programme) fonctionnant sur le serveur, écoutant sur l'**adresse IP publique**, doit avoir **tous les certificats HTTPS** du serveur. +* **Après** l'établissement d'une connexion sécurisée, le protocole de communication est **toujours HTTP**. + * Le contenu est **crypté**, même s'il est envoyé avec le **protocole HTTP**. -Il est courant d'avoir un seul programme/serveur HTTP fonctionnant sur le serveur (la machine, l'hôte, etc.) et -gérant toutes les parties HTTPS : envoyer les requêtes HTTP décryptées à l'application HTTP réelle fonctionnant sur -le même serveur (dans ce cas, l'application **FastAPI**), prendre la réponse HTTP de l'application, la crypter en utilisant le certificat approprié et la renvoyer au client en utilisant HTTPS. Ce serveur est souvent appelé un Proxy de terminaison TLS. +Il est courant d'avoir **un seul programme/serveur HTTP** fonctionnant sur le serveur (la machine, l'hôte, etc.) et **gérant toutes les parties HTTPS** : recevoir les **requêtes HTTPS chiffrées**, envoyer les **requêtes HTTP déchiffrées** à l'application HTTP réelle fonctionnant sur le même serveur (l'application **FastAPI**, dans ce cas), prendre la **réponse HTTP** de l'application, la **chiffrer** en utilisant le **certificat HTTPS** approprié et la renvoyer au client en utilisant **HTTPS**. Ce serveur est souvent appelé un **Proxy de terminaison TLS**. -## Let's Encrypt +Parmi les options que vous pourriez utiliser comme Proxy de terminaison TLS : -Avant Let's Encrypt, ces certificats HTTPS étaient vendus par des tiers de confiance. +* Traefik (qui peut également gérer les renouvellements de certificats) +* Caddy (qui peut également gérer les renouvellements de certificats) +* Nginx +* HAProxy -Le processus d'acquisition d'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasses et les certificats étaient assez chers. +## Let's Encrypt { #lets-encrypt } -Mais ensuite, Let's Encrypt a été créé. +Avant Let's Encrypt, ces **certificats HTTPS** étaient vendus par des tiers de confiance. -Il s'agit d'un projet de la Fondation Linux. Il fournit des certificats HTTPS gratuitement. De manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la sécurité est en fait meilleure en raison de leur durée de vie réduite. +Le processus d'acquisition de l'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasses et les certificats étaient assez chers. + +Mais ensuite, **Let's Encrypt** a été créé. + +Il s'agit d'un projet de la Fondation Linux. Il fournit **des certificats HTTPS gratuitement**, de manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la **sécurité est en fait meilleure** en raison de leur durée de vie réduite. Les domaines sont vérifiés de manière sécurisée et les certificats sont générés automatiquement. Cela permet également d'automatiser le renouvellement de ces certificats. -L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un HTTPS sécurisé, gratuitement et pour toujours. +L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un **HTTPS sécurisé, gratuitement et pour toujours**. + +## HTTPS pour les développeurs { #https-for-developers } + +Voici un exemple de ce à quoi pourrait ressembler une API HTTPS, étape par étape, en portant principalement attention aux idées importantes pour les développeurs. + +### Nom de domaine { #domain-name } + +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. + +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**. + +Vous feriez probablement cela une seule fois, la première fois, lors de la mise en place de l'ensemble. + +/// tip | Astuce + +Cette partie relative au nom de domaine intervient bien avant HTTPS, mais comme tout dépend du domaine et de l'adresse IP, il vaut la peine de la mentionner ici. + +/// + +### DNS { #dns } + +Concentrons-nous maintenant sur toutes les parties réellement liées à HTTPS. + +D'abord, le navigateur vérifierait auprès des **serveurs DNS** quelle est l'**IP du domaine**, dans ce cas, `someapp.example.com`. + +Les serveurs DNS indiqueraient au navigateur d'utiliser une **adresse IP** spécifique. Ce serait l'adresse IP publique utilisée par votre serveur, celle que vous avez configurée dans les serveurs DNS. + + + +### Début de la négociation TLS (Handshake) { #tls-handshake-start } + +Le navigateur communiquerait ensuite avec cette adresse IP sur le **port 443** (le port HTTPS). + +La première partie de la communication consiste simplement à établir la connexion entre le client et le serveur et à décider des clés cryptographiques qu'ils utiliseront, etc. + + + +Cette interaction entre le client et le serveur pour établir la connexion TLS s'appelle la **négociation TLS (TLS handshake)**. + +### TLS avec l'extension SNI { #tls-with-sni-extension } + +**Un seul processus** sur le serveur peut écouter sur un **port** spécifique d'une **adresse IP** spécifique. Il pourrait y avoir d'autres processus écoutant sur d'autres ports de la même adresse IP, mais un seul pour chaque combinaison d'adresse IP et de port. + +TLS (HTTPS) utilise par défaut le port spécifique `443`. C'est donc le port dont nous aurions besoin. + +Comme un seul processus peut écouter sur ce port, le processus qui le ferait serait le **Proxy de terminaison TLS**. + +Le Proxy de terminaison TLS aurait accès à un ou plusieurs **certificats TLS** (certificats HTTPS). + +En utilisant l'**extension SNI** mentionnée plus haut, le Proxy de terminaison TLS vérifierait lequel des certificats TLS (HTTPS) disponibles il devrait utiliser pour cette connexion, en choisissant celui qui correspond au domaine attendu par le client. + +Dans ce cas, il utiliserait le certificat pour `someapp.example.com`. + + + +Le client **fait déjà confiance** à l'entité qui a généré ce certificat TLS (dans ce cas Let's Encrypt, mais nous y reviendrons plus tard), il peut donc **vérifier** que le certificat est valide. + +Ensuite, en utilisant le certificat, le client et le Proxy de terminaison TLS **décident comment chiffrer** le reste de la **communication TCP**. Cela termine la partie **négociation TLS**. + +Après cela, le client et le serveur disposent d'une **connexion TCP chiffrée**, c'est ce que fournit TLS. Ils peuvent alors utiliser cette connexion pour démarrer la **communication HTTP** proprement dite. + +Et c'est ce qu'est **HTTPS** : c'est simplement du **HTTP** à l'intérieur d'une **connexion TLS sécurisée** au lieu d'une connexion TCP pure (non chiffrée). + +/// tip | Astuce + +Remarquez que le cryptage de la communication se produit au **niveau TCP**, pas au niveau HTTP. + +/// + +### Requête HTTPS { #https-request } + +Maintenant que le client et le serveur (spécifiquement le navigateur et le Proxy de terminaison TLS) ont une **connexion TCP chiffrée**, ils peuvent démarrer la **communication HTTP**. + +Ainsi, le client envoie une **requête HTTPS**. Ce n'est qu'une requête HTTP à travers une connexion TLS chiffrée. + + + +### Déchiffrer la requête { #decrypt-the-request } + +Le Proxy de terminaison TLS utiliserait le chiffrement convenu pour **déchiffrer la requête**, et transmettrait la **requête HTTP en clair (déchiffrée)** au processus exécutant l'application (par exemple un processus avec Uvicorn exécutant l'application FastAPI). + + + +### Réponse HTTP { #http-response } + +L'application traiterait la requête et enverrait une **réponse HTTP en clair (non chiffrée)** au Proxy de terminaison TLS. + + + +### Réponse HTTPS { #https-response } + +Le Proxy de terminaison TLS **chiffrerait ensuite la réponse** en utilisant la cryptographie convenue auparavant (qui a commencé avec le certificat pour `someapp.example.com`), et la renverrait au navigateur. + +Ensuite, le navigateur vérifierait que la réponse est valide et chiffrée avec la bonne clé cryptographique, etc. Il **déchiffrerait la réponse** et la traiterait. + + + +Le client (navigateur) saura que la réponse provient du bon serveur parce qu'elle utilise la cryptographie convenue auparavant à l'aide du **certificat HTTPS**. + +### Applications multiples { #multiple-applications } + +Sur le même serveur (ou les mêmes serveurs), il pourrait y avoir **plusieurs applications**, par exemple d'autres programmes d'API ou une base de données. + +Un seul processus peut gérer l'adresse IP et le port spécifiques (le Proxy de terminaison TLS dans notre exemple), mais les autres applications/processus peuvent également s'exécuter sur le ou les serveurs, tant qu'ils n'essaient pas d'utiliser la même **combinaison d'adresse IP publique et de port**. + + + +De cette façon, le Proxy de terminaison TLS pourrait gérer HTTPS et les certificats pour **plusieurs domaines**, pour plusieurs applications, puis transmettre les requêtes à la bonne application dans chaque cas. + +### Renouvellement des certificats { #certificate-renewal } + +À un moment donné dans le futur, chaque certificat **expirerait** (environ 3 mois après son acquisition). + +Ensuite, il y aurait un autre programme (dans certains cas c'est un autre programme, dans d'autres cas cela pourrait être le même Proxy de terminaison TLS) qui communiquerait avec Let's Encrypt et renouvellerait le ou les certificats. + + + +Les **certificats TLS** sont **associés à un nom de domaine**, pas à une adresse IP. + +Ainsi, pour renouveler les certificats, le programme de renouvellement doit **prouver** à l'autorité (Let's Encrypt) qu'il **« possède » et contrôle ce domaine**. + +Pour ce faire, et pour s'adapter aux différents besoins des applications, il existe plusieurs façons de procéder. Parmi les plus courantes : + +* **Modifier certains enregistrements DNS**. + * Pour cela, le programme de renouvellement doit prendre en charge les API du fournisseur DNS ; ainsi, selon le fournisseur DNS que vous utilisez, cela peut être ou non une option. +* **S'exécuter comme un serveur** (au moins pendant le processus d'acquisition du certificat) sur l'adresse IP publique associée au domaine. + * Comme nous l'avons dit plus haut, un seul processus peut écouter sur une adresse IP et un port spécifiques. + * C'est l'une des raisons pour lesquelles il est très utile que le même Proxy de terminaison TLS prenne également en charge le processus de renouvellement des certificats. + * Sinon, vous pourriez avoir à arrêter le Proxy de terminaison TLS momentanément, démarrer le programme de renouvellement pour acquérir les certificats, puis les configurer avec le Proxy de terminaison TLS, et ensuite redémarrer le Proxy de terminaison TLS. Ce n'est pas idéal, car votre/vos application(s) ne seront pas disponibles pendant le temps où le Proxy de terminaison TLS est arrêté. + +Tout ce processus de renouvellement, tout en continuant à servir l'application, est l'une des principales raisons pour lesquelles vous voudriez avoir un **système séparé pour gérer HTTPS** avec un Proxy de terminaison TLS, au lieu d'utiliser directement les certificats TLS avec le serveur d'application (par exemple Uvicorn). + +## En-têtes Proxy Forwarded { #proxy-forwarded-headers } + +Lorsque vous utilisez un proxy pour gérer HTTPS, votre **serveur d'application** (par exemple Uvicorn via FastAPI CLI) ne connaît rien du processus HTTPS, il communique en HTTP en clair avec le **Proxy de terminaison TLS**. + +Ce **proxy** définirait normalement certains en-têtes HTTP à la volée avant de transmettre la requête au **serveur d'application**, pour informer le serveur d'application que la requête est **transmise** par le proxy. + +/// note | Détails techniques + +Les en-têtes du proxy sont : + +* X-Forwarded-For +* X-Forwarded-Proto +* X-Forwarded-Host + +/// + +Néanmoins, comme le **serveur d'application** ne sait pas qu'il se trouve derrière un **proxy** de confiance, par défaut, il ne ferait pas confiance à ces en-têtes. + +Mais vous pouvez configurer le **serveur d'application** pour qu'il fasse confiance aux en-têtes transmis (*forwarded*) envoyés par le **proxy**. Si vous utilisez FastAPI CLI, vous pouvez utiliser l'*option CLI* `--forwarded-allow-ips` pour lui indiquer à partir de quelles IP il doit faire confiance à ces en-têtes transmis. + +Par exemple, si le **serveur d'application** ne reçoit des communications que du **proxy** de confiance, vous pouvez définir `--forwarded-allow-ips="*"` pour lui faire faire confiance à toutes les IP entrantes, puisqu'il ne recevra des requêtes que depuis l'IP utilisée par le **proxy**. + +De cette façon, l'application sera en mesure de savoir quelle est sa propre URL publique, si elle utilise HTTPS, le domaine, etc. + +Cela serait utile, par exemple, pour gérer correctement les redirections. + +/// tip | Astuce + +Vous pouvez en savoir plus dans la documentation [Derrière un proxy - Activer les en-têtes transmis par le proxy](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} + +/// + +## Récapitulatif { #recap } + +Disposer de **HTTPS** est très important, et assez **critique** dans la plupart des cas. La majeure partie de l'effort que vous, en tant que développeur, devez fournir autour de HTTPS consiste simplement à **comprendre ces concepts** et leur fonctionnement. + +Mais une fois que vous connaissez les informations de base sur **HTTPS pour les développeurs**, vous pouvez facilement combiner et configurer différents outils pour vous aider à tout gérer simplement. + +Dans certains des prochains chapitres, je vous montrerai plusieurs exemples concrets de configuration de **HTTPS** pour des applications **FastAPI**. 🔒 diff --git a/docs/fr/docs/deployment/index.md b/docs/fr/docs/deployment/index.md index e2014afe95..3b08e9af76 100644 --- a/docs/fr/docs/deployment/index.md +++ b/docs/fr/docs/deployment/index.md @@ -1,8 +1,8 @@ -# Déploiement +# Déploiement { #deployment } Le déploiement d'une application **FastAPI** est relativement simple. -## Que signifie le déploiement +## Que signifie le déploiement { #what-does-deployment-mean } **Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les utilisateurs**. @@ -14,7 +14,7 @@ l'application efficacement et sans interruption ni problème. Ceci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser et de le réparer, d'arrêter et de redémarrer le serveur de développement, _etc._ -## Stratégies de déploiement +## Stratégies de déploiement { #deployment-strategies } Il existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous utilisez. @@ -22,6 +22,8 @@ utilisez. Vous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service cloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles. +Par exemple, nous, l'équipe derrière FastAPI, avons créé **FastAPI Cloud**, pour rendre le déploiement d'applications FastAPI dans le cloud aussi fluide que possible, avec la même expérience développeur que lorsque vous travaillez avec FastAPI. + Je vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement d'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web). diff --git a/docs/fr/docs/deployment/versions.md b/docs/fr/docs/deployment/versions.md index 9d84274e27..81794428fb 100644 --- a/docs/fr/docs/deployment/versions.md +++ b/docs/fr/docs/deployment/versions.md @@ -1,101 +1,93 @@ -# À propos des versions de FastAPI +# À propos des versions de FastAPI { #about-fastapi-versions } -**FastAPI** est déjà utilisé en production dans de nombreuses applications et systèmes. Et la couverture de test est maintenue à 100 %. Mais son développement est toujours aussi rapide. +**FastAPI** est déjà utilisé en production dans de nombreuses applications et de nombreux systèmes. Et la couverture de tests est maintenue à 100 %. Mais son développement avance toujours rapidement. -De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code est -amélioré continuellement. +De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code s'améliore continuellement. -C'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version peut potentiellement -recevoir des changements non rétrocompatibles. Cela suit les conventions de versionnage sémantique. +C'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version pourrait potentiellement comporter des changements non rétrocompatibles. Cela suit les conventions de versionnage sémantique. Vous pouvez créer des applications de production avec **FastAPI** dès maintenant (et vous le faites probablement depuis un certain temps), vous devez juste vous assurer que vous utilisez une version qui fonctionne correctement avec le reste de votre code. -## Épinglez votre version de `fastapi` +## Épingler votre version de `fastapi` { #pin-your-fastapi-version } -Tout d'abord il faut "épingler" la version de **FastAPI** que vous utilisez à la dernière version dont vous savez -qu'elle fonctionne correctement pour votre application. +La première chose que vous devez faire est « épingler » la version de **FastAPI** que vous utilisez à la dernière version spécifique dont vous savez qu’elle fonctionne correctement pour votre application. -Par exemple, disons que vous utilisez la version `0.45.0` dans votre application. +Par exemple, disons que vous utilisez la version `0.112.0` dans votre application. -Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec : +Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec : ```txt -fastapi==0.45.0 +fastapi[standard]==0.112.0 ``` -ce qui signifierait que vous utiliseriez exactement la version `0.45.0`. +ce qui signifierait que vous utiliseriez exactement la version `0.112.0`. -Ou vous pourriez aussi l'épingler avec : +Ou vous pourriez aussi l'épingler avec : ```txt -fastapi>=0.45.0,<0.46.0 +fastapi[standard]>=0.112.0,<0.113.0 ``` -cela signifierait que vous utiliseriez les versions `0.45.0` ou supérieures, mais inférieures à `0.46.0`, par exemple, une version `0.45.2` serait toujours acceptée. +cela signifierait que vous utiliseriez les versions `0.112.0` ou supérieures, mais inférieures à `0.113.0`, par exemple, une version `0.112.2` serait toujours acceptée. -Si vous utilisez un autre outil pour gérer vos installations, comme Poetry, Pipenv, ou autres, ils ont tous un moyen que vous pouvez utiliser pour définir des versions spécifiques pour vos paquets. +Si vous utilisez un autre outil pour gérer vos installations, comme `uv`, Poetry, Pipenv, ou autres, ils ont tous un moyen que vous pouvez utiliser pour définir des versions spécifiques pour vos paquets. -## Versions disponibles +## Versions disponibles { #available-versions } Vous pouvez consulter les versions disponibles (par exemple, pour vérifier quelle est la dernière version en date) dans les [Notes de version](../release-notes.md){.internal-link target=_blank}. -## À propos des versions +## À propos des versions { #about-versions } -Suivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter -des changements non rétrocompatibles. +Suivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter des changements non rétrocompatibles. -FastAPI suit également la convention que tout changement de version "PATCH" est pour des corrections de bogues et -des changements rétrocompatibles. +FastAPI suit également la convention selon laquelle tout changement de version « PATCH » concerne des corrections de bogues et des changements rétrocompatibles. /// tip | Astuce -Le "PATCH" est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`. +Le « PATCH » est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`. /// -Donc, vous devriez être capable d'épingler une version comme suit : +Donc, vous devriez être en mesure d'épingler une version comme suit : ```txt fastapi>=0.45.0,<0.46.0 ``` -Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions "MINOR". +Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions « MINOR ». /// tip | Astuce -Le "MINOR" est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`. +Le « MINOR » est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`. /// -## Mise à jour des versions FastAPI +## Mettre à niveau les versions de FastAPI { #upgrading-the-fastapi-versions } -Vous devriez tester votre application. +Vous devez ajouter des tests pour votre application. -Avec **FastAPI** c'est très facile (merci à Starlette), consultez la documentation : [Testing](../tutorial/testing.md){.internal-link target=_blank} +Avec **FastAPI** c'est très facile (merci à Starlette), consultez les documents : [Tests](../tutorial/testing.md){.internal-link target=_blank} -Après avoir effectué des tests, vous pouvez mettre à jour la version **FastAPI** vers une version plus récente, et vous assurer que tout votre code fonctionne correctement en exécutant vos tests. +Après avoir des tests, vous pouvez mettre à niveau la version de **FastAPI** vers une version plus récente et vous assurer que tout votre code fonctionne correctement en exécutant vos tests. -Si tout fonctionne, ou après avoir fait les changements nécessaires, et que tous vos tests passent, vous pouvez -épingler votre version de `fastapi` à cette nouvelle version récente. +Si tout fonctionne, ou après avoir effectué les changements nécessaires, et que tous vos tests passent, vous pouvez alors épingler votre `fastapi` à cette nouvelle version récente. -## À propos de Starlette +## À propos de Starlette { #about-starlette } -Vous ne devriez pas épingler la version de `starlette`. +Vous ne devez pas épingler la version de `starlette`. Différentes versions de **FastAPI** utiliseront une version spécifique plus récente de Starlette. Ainsi, vous pouvez simplement laisser **FastAPI** utiliser la bonne version de Starlette. -## À propos de Pydantic +## À propos de Pydantic { #about-pydantic } -Pydantic inclut des tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus -de `1.0.0`) sont toujours compatibles avec **FastAPI**. +Pydantic inclut les tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus de `1.0.0`) sont toujours compatibles avec FastAPI. -Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous et inférieure à `2.0.0`. +Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous. -Par exemple : +Par exemple : ```txt -pydantic>=1.2.0,<2.0.0 +pydantic>=2.7.0,<3.0.0 ``` diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 99ea8dda12..2aeaa1c692 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -1,11 +1,11 @@ -# FastAPI +# FastAPI { #fastapi }

- FastAPI + FastAPI

Framework FastAPI, haute performance, facile à apprendre, rapide à coder, prêt pour la production @@ -27,7 +27,7 @@ --- -**Documentation** : https://fastapi.tiangolo.com +**Documentation** : https://fastapi.tiangolo.com/fr **Code Source** : https://github.com/fastapi/fastapi @@ -37,128 +37,130 @@ FastAPI est un framework web moderne et rapide (haute performance) pour la créa Les principales fonctionnalités sont : -* **Rapidité** : De 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 IDE. Complétion complète. Moins de temps passé à déboguer. -* **Facile** : Conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire la documentation. -* **Concis** : Diminue la duplication de code. De nombreuses fonctionnalités liées à la déclaration de chaque paramètre. Moins de bugs. -* **Robuste** : Obtenez un code prêt pour la production. Avec une documentation interactive automatique. -* **Basé sur des normes** : Basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : OpenAPI (précédemment connu sous le nom de Swagger) et JSON Schema. +* **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. +* **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. +* **Basé sur des normes** : basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : OpenAPI (précédemment connu sous le nom de Swagger) et JSON Schema. * estimation basée sur des tests d'une équipe de développement interne, construisant des applications de production. -## Sponsors +## Sponsors { #sponsors } -{% if sponsors %} +### Sponsor clé de voûte { #keystone-sponsor } + +{% for sponsor in sponsors.keystone -%} + +{% endfor -%} + +### Sponsors Or et Argent { #gold-and-silver-sponsors } + {% for sponsor in sponsors.gold -%} {% endfor -%} {%- for sponsor in sponsors.silver -%} {% endfor %} -{% endif %} -Other sponsors +Autres sponsors -## Opinions +## Opinions { #opinions } -"_[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux seront intégrés dans le coeur de **Windows** et dans certains produits **Office**._" +« _[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux sont intégrés au cœur de **Windows** et à certains produits **Office**._ »

Kabir Khan - Microsoft (ref)
--- -"_Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_" +« _Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_ » -
Piero Molino, Yaroslav Dudin et Sai Sumanth Miryala - Uber (ref)
+
Piero Molino, Yaroslav Dudin, et Sai Sumanth Miryala - Uber (ref)
--- -"_**Netflix** a le plaisir d'annoncer la sortie en open-source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_" +« _**Netflix** est heureux d'annoncer la publication en open source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_ »
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
--- -"_Je suis très enthousiaste à propos de **FastAPI**. C'est un bonheur !_" +« _Je suis plus qu'enthousiaste à propos de **FastAPI**. C'est tellement fun !_ » -
Brian Okken - Auteur du podcast Python Bytes (ref)
+
Brian Okken - Animateur du podcast Python Bytes (ref)
--- -"_Honnêtement, ce que vous avez construit a l'air super solide et élégant. A bien des égards, c'est comme ça que je voulais que **Hug** soit - c'est vraiment inspirant de voir quelqu'un construire ça._" +« _Honnêtement, ce que vous avez construit a l'air super solide et soigné. À bien des égards, c'est ce que je voulais que **Hug** soit — c'est vraiment inspirant de voir quelqu'un construire ça._ » -
Timothy Crosley - Créateur de Hug (ref)
+
Timothy Crosley - Créateur de Hug (ref)
--- -"_Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et à apprendre [...]_" +« _Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et facile à apprendre [...]_ » -"_Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_" +« _Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_ »
Ines Montani - Matthew Honnibal - Fondateurs de Explosion AI - Créateurs de spaCy (ref) - (ref)
--- -"_Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **bien conçu**, **simple à utiliser** et **très évolutif**. Il est devenu un **composant clé** dans notre stratégie de développement API first et il est à l'origine de nombreux automatismes et services tels que notre ingénieur virtuel TAC._" +« _Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **magnifiquement conçu**, **simple à utiliser** et **hautement scalable**. Il est devenu un **composant clé** de notre stratégie de développement API-first et alimente de nombreuses automatisations et services tels que notre ingénieur TAC virtuel._ »
Deon Pillsbury - Cisco (ref)
--- -## **Typer**, le FastAPI des CLI +## Mini documentaire FastAPI { #fastapi-mini-documentary } + +Un mini documentaire FastAPI est sorti fin 2025, vous pouvez le regarder en ligne : + +FastAPI Mini Documentary + +## **Typer**, le FastAPI des CLIs { #typer-the-fastapi-of-clis } -Si vous souhaitez construire une application CLI utilisable dans un terminal au lieu d'une API web, regardez **Typer**. +Si vous construisez une application CLI à utiliser dans un terminal au lieu d'une API web, regardez **Typer**. -**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des CLI**. ⌨️ 🚀 +**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des CLIs**. ⌨️ 🚀 -## Prérequis +## Prérequis { #requirements } FastAPI repose sur les épaules de géants : * Starlette pour les parties web. * Pydantic pour les parties données. -## Installation +## Installation { #installation } + +Créez et activez un environnement virtuel puis installez FastAPI :
```console -$ pip install fastapi +$ pip install "fastapi[standard]" ---> 100% ```
-Vous aurez également besoin d'un serveur ASGI pour la production tel que Uvicorn ou Hypercorn. +**Remarque** : Vous devez vous assurer de mettre « fastapi[standard] » entre guillemets pour garantir que cela fonctionne dans tous les terminaux. -
+## Exemple { #example } -```console -$ pip install "uvicorn[standard]" +### Créer { #create-it } ----> 100% -``` - -
- -## Exemple - -### Créez - -* Créez un fichier `main.py` avec : +Créez un fichier `main.py` avec : ```Python -from typing import Union - from fastapi import FastAPI app = FastAPI() @@ -170,18 +172,16 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): +def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} ```
-Ou utilisez async def ... +Ou utilisez async def... Si votre code utilise `async` / `await`, utilisez `async def` : -```Python hl_lines="9 14" -from typing import Union - +```Python hl_lines="7 12" from fastapi import FastAPI app = FastAPI() @@ -193,28 +193,41 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): +async def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} ``` -**Note** +**Remarque** : -Si vous n'êtes pas familier avec cette notion, consultez la section _"Vous êtes pressés ?"_ à propos de `async` et `await` dans la documentation. +Si vous ne savez pas, consultez la section « Vous êtes pressés ? » à propos de `async` et `await` dans la documentation.
-### Lancez +### Lancer { #run-it } Lancez le serveur avec :
```console -$ uvicorn main:app --reload +$ fastapi dev main.py + ╭────────── FastAPI CLI - Development mode ───────────╮ + │ │ + │ Serving at: http://127.0.0.1:8000 │ + │ │ + │ API docs: http://127.0.0.1:8000/docs │ + │ │ + │ Running in development mode, for production use: │ + │ │ + │ fastapi run │ + │ │ + ╰─────────────────────────────────────────────────────╯ + +INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] +INFO: Started reloader process [2248755] using WatchFiles +INFO: Started server process [2248757] INFO: Waiting for application startup. INFO: Application startup complete. ``` @@ -222,34 +235,34 @@ INFO: Application startup complete.
-À propos de la commande uvicorn main:app --reload ... +À propos de la commande fastapi dev main.py... -La commande `uvicorn main:app` fait référence à : +La commande `fastapi dev` lit votre fichier `main.py`, détecte l'application **FastAPI** qu'il contient et lance un serveur avec Uvicorn. -* `main` : le fichier `main.py` (le "module" Python). -* `app` : l'objet créé à l'intérieur de `main.py` avec la ligne `app = FastAPI()`. -* `--reload` : fait redémarrer le serveur après des changements de code. À n'utiliser que pour le développement. +Par défaut, `fastapi dev` démarre avec le rechargement automatique activé pour le développement local. + +Vous pouvez en savoir plus dans la documentation de la CLI FastAPI.
-### Vérifiez +### Vérifier { #check-it } Ouvrez votre navigateur à l'adresse http://127.0.0.1:8000/items/5?q=somequery. -Vous obtenez alors cette réponse JSON : +Vous verrez la réponse JSON : ```JSON {"item_id": 5, "q": "somequery"} ``` -Vous venez de créer une API qui : +Vous avez déjà créé une API qui : -* Reçoit les requêtes HTTP pour les _chemins_ `/` et `/items/{item_id}`. -* Les deux _chemins_ acceptent des opérations `GET` (également connu sous le nom de _méthodes_ HTTP). -* Le _chemin_ `/items/{item_id}` a un _paramètre_ `item_id` qui doit être un `int`. -* Le _chemin_ `/items/{item_id}` a un _paramètre de requête_ optionnel `q` de type `str`. +* Reçoit des requêtes HTTP sur les _chemins_ `/` et `/items/{item_id}`. +* Les deux _chemins_ acceptent des opérations `GET` (également connues sous le nom de _méthodes_ HTTP). +* Le _chemin_ `/items/{item_id}` a un _paramètre de chemin_ `item_id` qui doit être un `int`. +* Le _chemin_ `/items/{item_id}` a un _paramètre de requête_ optionnel `q` de type `str`. -### Documentation API interactive +### Documentation API interactive { #interactive-api-docs } Maintenant, rendez-vous sur http://127.0.0.1:8000/docs. @@ -257,23 +270,21 @@ Vous verrez la documentation interactive automatique de l'API (fournie par http://127.0.0.1:8000/redoc. -Vous verrez la documentation interactive automatique de l'API (fournie par ReDoc) : +Vous verrez la documentation alternative automatique (fournie par ReDoc) : ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## Exemple plus poussé +## Mettre à niveau l'exemple { #example-upgrade } -Maintenant, modifiez le fichier `main.py` pour recevoir le corps d'une requête `PUT`. +Modifiez maintenant le fichier `main.py` pour recevoir un corps depuis une requête `PUT`. -Déclarez ce corps en utilisant les types Python standards, grâce à Pydantic. - -```Python hl_lines="4 9-12 25-27" -from typing import Union +Déclarez le corps en utilisant les types Python standard, grâce à Pydantic. +```Python hl_lines="2 7-10 23-25" from fastapi import FastAPI from pydantic import BaseModel @@ -283,7 +294,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Union[bool, None] = None + is_offer: bool | None = None @app.get("/") @@ -292,7 +303,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): +def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} @@ -301,35 +312,35 @@ def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id} ``` -Le serveur se recharge normalement automatiquement (car vous avez pensé à `--reload` dans la commande `uvicorn` ci-dessus). +Le serveur `fastapi dev` devrait se recharger automatiquement. -### Plus loin avec la documentation API interactive +### Mettre à niveau la documentation API interactive { #interactive-api-docs-upgrade } Maintenant, rendez-vous sur http://127.0.0.1:8000/docs. -* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps de la requête : +* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps : ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) -* Cliquez sur le bouton "Try it out", il vous permet de renseigner les paramètres et d'interagir directement avec l'API : +* Cliquez sur le bouton « Try it out », il vous permet de renseigner les paramètres et d'interagir directement avec l'API : ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) -* Cliquez ensuite sur le bouton "Execute", l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran : +* Cliquez ensuite sur le bouton « Execute », l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran : ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) -### Plus loin avec la documentation API alternative +### Mettre à niveau la documentation API alternative { #alternative-api-docs-upgrade } Et maintenant, rendez-vous sur http://127.0.0.1:8000/redoc. -* La documentation alternative reflétera également le nouveau paramètre de requête et le nouveau corps : +* La documentation alternative reflètera également le nouveau paramètre de requête et le nouveau corps : ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### En résumé +### En résumé { #recap } -En résumé, vous déclarez **une fois** les types de paramètres, le corps de la requête, etc. en tant que paramètres de fonction. +En résumé, vous déclarez **une fois** les types de paramètres, le corps, etc. en tant que paramètres de fonction. Vous faites cela avec les types Python standard modernes. @@ -337,7 +348,7 @@ Vous n'avez pas à apprendre une nouvelle syntaxe, les méthodes ou les classes Juste du **Python** standard. -Par exemple, pour un `int`: +Par exemple, pour un `int` : ```Python item_id: int @@ -351,54 +362,54 @@ item: Item ... et avec cette déclaration unique, vous obtenez : -* Une assistance dans votre IDE, notamment : - * la complétion. +* Une assistance dans l'éditeur, notamment : + * l'autocomplétion. * la vérification des types. * La validation des données : * des erreurs automatiques et claires lorsque les données ne sont pas valides. - * une validation même pour les objets JSON profondément imbriqués. -* Une conversion des données d'entrée : venant du réseau et allant vers les données et types de Python, permettant de lire : - * le JSON. - * les paramètres du chemin. - * les paramètres de la requête. - * les cookies. - * les en-têtes. - * les formulaires. - * les fichiers. -* La conversion des données de sortie : conversion des données et types Python en données réseau (au format JSON), permettant de convertir : - * les types Python (`str`, `int`, `float`, `bool`, `list`, etc). - * les objets `datetime`. - * les objets `UUID`. - * les modèles de base de données. - * ... et beaucoup plus. -* La documentation API interactive automatique, avec 2 interfaces utilisateur au choix : + * 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 : + * JSON. + * Paramètres de chemin. + * Paramètres de requête. + * Cookies. + * 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 types Python (`str`, `int`, `float`, `bool`, `list`, etc). + * Objets `datetime`. + * Objets `UUID`. + * Modèles de base de données. + * ... et bien plus. +* Documentation API interactive automatique, avec 2 interfaces utilisateur au choix : * Swagger UI. * ReDoc. --- -Pour revenir à l'exemple de code précédent, **FastAPI** permet de : +Pour revenir à l'exemple de code précédent, **FastAPI** va : -* Valider que `item_id` existe dans le chemin des requêtes `GET` et `PUT`. +* Valider la présence d'un `item_id` dans le chemin pour les requêtes `GET` et `PUT`. * Valider que `item_id` est de type `int` pour les requêtes `GET` et `PUT`. - * Si ce n'est pas le cas, le client voit une erreur utile et claire. -* Vérifier qu'il existe un paramètre de requête facultatif nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`. - * Puisque le paramètre `q` est déclaré avec `= None`, il est facultatif. - * Sans le `None`, il serait nécessaire (comme l'est le corps de la requête dans le cas du `PUT`). -* Pour les requêtes `PUT` vers `/items/{item_id}`, de lire le corps en JSON : - * Vérifier qu'il a un attribut obligatoire `name` qui devrait être un `str`. - * Vérifier qu'il a un attribut obligatoire `prix` qui doit être un `float`. - * Vérifier qu'il a un attribut facultatif `is_offer`, qui devrait être un `bool`, s'il est présent. - * Tout cela fonctionnerait également pour les objets JSON profondément imbriqués. -* Convertir de et vers JSON automatiquement. -* Documenter tout avec OpenAPI, qui peut être utilisé par : - * Les systèmes de documentation interactifs. - * Les systèmes de génération automatique de code client, pour de nombreuses langues. + * Si ce n'est pas le cas, le client verra une erreur utile et claire. +* Vérifier s'il existe un paramètre de requête optionnel nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`. + * Comme le paramètre `q` est déclaré avec `= None`, il est optionnel. + * Sans le `None`, il serait requis (comme l'est le corps dans le cas de `PUT`). +* Pour les requêtes `PUT` vers `/items/{item_id}`, lire le corps au format JSON : + * Vérifier qu'il a un attribut obligatoire `name` qui doit être un `str`. + * Vérifier qu'il a un attribut obligatoire `price` qui doit être un `float`. + * Vérifier qu'il a un attribut optionnel `is_offer`, qui doit être un `bool`, s'il est présent. + * Tout cela fonctionne également pour les objets JSON profondément imbriqués. +* Convertir automatiquement depuis et vers JSON. +* Tout documenter avec OpenAPI, qui peut être utilisé par : + * des systèmes de documentation interactive. + * des systèmes de génération automatique de clients, pour de nombreux langages. * Fournir directement 2 interfaces web de documentation interactive. --- -Nous n'avons fait qu'effleurer la surface, mais vous avez déjà une idée de la façon dont tout cela fonctionne. +Nous n'avons fait qu'effleurer la surface, mais vous avez déjà une idée de la façon dont tout fonctionne. Essayez de changer la ligne contenant : @@ -412,61 +423,137 @@ Essayez de changer la ligne contenant : ... "item_name": item.name ... ``` -... vers : +... à : ```Python ... "item_price": item.price ... ``` -... et voyez comment votre éditeur complétera automatiquement les attributs et connaîtra leurs types : +... et voyez comment votre éditeur complète automatiquement les attributs et connaît leurs types : -![compatibilité IDE](https://fastapi.tiangolo.com/img/vscode-completion.png) +![compatibilité éditeur](https://fastapi.tiangolo.com/img/vscode-completion.png) Pour un exemple plus complet comprenant plus de fonctionnalités, voir le Tutoriel - Guide utilisateur. -**Spoiler alert** : le tutoriel - guide utilisateur inclut : +**Alerte spoiler** : le tutoriel - guide utilisateur inclut : -* Déclaration de **paramètres** provenant d'autres endroits différents comme : **en-têtes.**, **cookies**, **champs de formulaire** et **fichiers**. -* L'utilisation de **contraintes de validation** comme `maximum_length` ou `regex`. -* Un **système d'injection de dépendance ** très puissant et facile à utiliser . -* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec les **jetons JWT** et l'authentification **HTTP Basic**. -* Des techniques plus avancées (mais tout aussi faciles) pour déclarer les **modèles JSON profondément imbriqués** (grâce à Pydantic). -* Intégration de **GraphQL** avec Strawberry et d'autres bibliothèques. -* D'obtenir de nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme : +* Déclaration de **paramètres** provenant d'autres emplacements comme : **en-têtes**, **cookies**, **champs de formulaire** et **fichiers**. +* Comment définir des **contraintes de validation** comme `maximum_length` ou `regex`. +* Un système **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. +* De nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme : * **WebSockets** - * de tester le code très facilement avec `requests` et `pytest` - * **CORS** + * des tests extrêmement faciles basés sur HTTPX et `pytest` + * **CORS** * **Cookie Sessions** * ... et plus encore. -## Performance +### Déployer votre application (optionnel) { #deploy-your-app-optional } -Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont parmi les frameworks existants en Python les plus rapides , juste derrière Starlette et Uvicorn (utilisés en interne par FastAPI). (*) +Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur FastAPI Cloud, allez vous inscrire sur la liste d'attente si ce n'est pas déjà fait. 🚀 + +Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d'attente 😉), vous pouvez déployer votre application avec une seule commande. + +Avant de déployer, assurez-vous d'être connecté : + +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
+ +Puis déployez votre application : + +
+ +```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 construit par le même auteur et la même équipe derrière **FastAPI**. + +Il simplifie le processus de **construction**, de **déploiement** et **d'accès** à une API avec un effort minimal. + +Il apporte la même **expérience développeur** de la création d'applications avec FastAPI au **déploiement** dans le cloud. 🎉 + +FastAPI Cloud est le principal sponsor et 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 y déployer des applications FastAPI. 🤓 + +## Performance { #performance } + +Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont parmi les frameworks Python les plus rapides, juste derrière Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI). (*) Pour en savoir plus, consultez la section Benchmarks. -## Dépendances facultatives +## Dépendances { #dependencies } -Utilisées par Pydantic: +FastAPI dépend de Pydantic et Starlette. -* email-validator - pour la validation des adresses email. +### Dépendances `standard` { #standard-dependencies } + +Lorsque vous installez FastAPI avec `pip install "fastapi[standard]"`, il inclut le groupe `standard` de dépendances optionnelles : + +Utilisées par Pydantic : + +* email-validator - pour la validation des adresses e-mail. Utilisées par Starlette : -* requests - Obligatoire si vous souhaitez utiliser `TestClient`. +* 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 supporter le "décodage" de formulaire avec `request.form()`. -* itsdangerous - Obligatoire pour la prise en charge de `SessionMiddleware`. -* pyyaml - Obligatoire pour le support `SchemaGenerator` de Starlette (vous n'en avez probablement pas besoin avec FastAPI). +* python-multipart - Obligatoire si vous souhaitez prendre en charge l’« parsing » de formulaires avec `request.form()`. -Utilisées par FastAPI / Starlette : +Utilisées par FastAPI : -* uvicorn - Pour le serveur qui charge et sert votre application. -* orjson - Obligatoire si vous voulez utiliser `ORJSONResponse`. +* uvicorn - pour le serveur qui charge et sert votre application. Cela inclut `uvicorn[standard]`, qui comprend certaines dépendances (par ex. `uvloop`) nécessaires pour une haute performance. +* `fastapi-cli[standard]` - pour fournir la commande `fastapi`. + * Cela inclut `fastapi-cloud-cli`, qui vous permet de déployer votre application FastAPI sur FastAPI Cloud. + +### Sans les dépendances `standard` { #without-standard-dependencies } + +Si vous ne souhaitez pas inclure les dépendances optionnelles `standard`, vous pouvez installer avec `pip install fastapi` au lieu de `pip install "fastapi[standard]"`. + +### Sans `fastapi-cloud-cli` { #without-fastapi-cloud-cli } + +Si vous souhaitez installer FastAPI avec les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. + +### Dépendances optionnelles supplémentaires { #additional-optional-dependencies } + +Il existe des dépendances supplémentaires que vous pourriez vouloir installer. + +Dépendances optionnelles supplémentaires pour Pydantic : + +* pydantic-settings - pour la gestion des paramètres. +* pydantic-extra-types - pour des types supplémentaires à utiliser avec Pydantic. + +Dépendances optionnelles supplémentaires pour FastAPI : + +* orjson - Obligatoire si vous souhaitez utiliser `ORJSONResponse`. * ujson - Obligatoire si vous souhaitez utiliser `UJSONResponse`. -Vous pouvez tout installer avec `pip install fastapi[all]`. - -## Licence +## Licence { #license } Ce projet est soumis aux termes de la licence MIT. diff --git a/docs/fr/docs/learn/index.md b/docs/fr/docs/learn/index.md index 46fc095dce..5526877038 100644 --- a/docs/fr/docs/learn/index.md +++ b/docs/fr/docs/learn/index.md @@ -1,5 +1,5 @@ -# Apprendre +# Apprendre { #learn } Voici les sections introductives et les tutoriels pour apprendre **FastAPI**. -Vous pouvez considérer ceci comme un **manuel**, un **cours**, la **méthode officielle** et recommandée pour appréhender FastAPI. 😎 +Vous pouvez considérer ceci comme un **livre**, un **cours**, la **méthode officielle** et recommandée pour apprendre FastAPI. 😎 diff --git a/docs/fr/docs/project-generation.md b/docs/fr/docs/project-generation.md index 4c04dc167d..f062ffecf5 100644 --- a/docs/fr/docs/project-generation.md +++ b/docs/fr/docs/project-generation.md @@ -1,84 +1,28 @@ -# Génération de projets - Modèle +# Modèle Full Stack FastAPI { #full-stack-fastapi-template } -Vous pouvez utiliser un générateur de projet pour commencer, qui réalisera pour vous la mise en place de bases côté architecture globale, sécurité, base de données et premières routes d'API. +Les modèles, bien qu'ils soient généralement livrés avec une configuration spécifique, sont conçus pour être flexibles et personnalisables. Cela vous permet de les modifier et de les adapter aux exigences de votre projet, ce qui en fait un excellent point de départ. 🏁 -Un générateur de projet fera toujours une mise en place très subjective que vous devriez modifier et adapter suivant vos besoins, mais cela reste un bon point de départ pour vos projets. +Vous pouvez utiliser ce modèle pour démarrer, car il inclut une grande partie de la configuration initiale, la sécurité, la base de données et quelques endpoints d'API déjà prêts pour vous. -## Full Stack FastAPI PostgreSQL +Dépôt GitHub : Modèle Full Stack FastAPI -GitHub : https://github.com/tiangolo/full-stack-fastapi-postgresql +## Modèle Full Stack FastAPI - Pile technologique et fonctionnalités { #full-stack-fastapi-template-technology-stack-and-features } -### Full Stack FastAPI PostgreSQL - Fonctionnalités - -* Intégration **Docker** complète (basée sur Docker). -* Déploiement Docker en mode Swarm -* Intégration **Docker Compose** et optimisation pour développement local. -* Serveur web Python **prêt au déploiement** utilisant Uvicorn et Gunicorn. -* Backend Python **FastAPI** : - * **Rapide** : Très hautes performances, comparables à **NodeJS** ou **Go** (grâce à Starlette et Pydantic). - * **Intuitif** : Excellent support des éditeurs. Complétion partout. Moins de temps passé à déboguer. - * **Facile** : Fait pour être facile à utiliser et apprendre. Moins de temps passé à lire de la documentation. - * **Concis** : Minimise la duplication de code. Plusieurs fonctionnalités à chaque déclaration de paramètre. - * **Robuste** : Obtenez du code prêt pour être utilisé en production. Avec de la documentation automatique interactive. - * **Basé sur des normes** : Basé sur (et totalement compatible avec) les normes ouvertes pour les APIs : OpenAPI et JSON Schema. - * **Et bien d'autres fonctionnalités** comme la validation automatique, la sérialisation, l'authentification avec OAuth2 JWT tokens, etc. -* Hashage de **mots de passe sécurisé** par défaut. -* Authentification par **jetons JWT**. -* Modèles **SQLAlchemy** (indépendants des extensions Flask, afin qu'ils puissent être utilisés directement avec des *workers* Celery). -* Modèle de démarrages basiques pour les utilisateurs (à modifier et supprimer au besoin). -* Migrations **Alembic**. -* **CORS** (partage des ressources entre origines multiples, ou *Cross Origin Resource Sharing*). -* *Worker* **Celery** pouvant importer et utiliser les modèles et le code du reste du backend. -* Tests du backend REST basés sur **Pytest**, intégrés dans Docker, pour que vous puissiez tester toutes les interactions de l'API indépendamment de la base de données. Étant exécutés dans Docker, les tests peuvent utiliser un nouvel entrepôt de données créé de zéro à chaque fois (vous pouvez donc utiliser ElasticSearch, MongoDB, CouchDB, etc. et juste tester que l'API fonctionne). -* Intégration Python facile avec **Jupyter Kernels** pour le développement à distance ou intra-Docker avec des extensions comme Atom Hydrogen ou Visual Studio Code Jupyter. -* Frontend **Vue** : - * Généré avec Vue CLI. - * Gestion de l'**Authentification JWT**. - * Page de connexion. - * Après la connexion, page de tableau de bord principal. - * Tableau de bord principal avec création et modification d'utilisateurs. - * Modification de ses propres caractéristiques utilisateur. - * **Vuex**. - * **Vue-router**. - * **Vuetify** pour de magnifiques composants *material design*. - * **TypeScript**. - * Serveur Docker basé sur **Nginx** (configuré pour être facilement manipulé avec Vue-router). - * Utilisation de *Docker multi-stage building*, pour ne pas avoir besoin de sauvegarder ou *commit* du code compilé. - * Tests frontend exécutés à la compilation (pouvant être désactivés). - * Fait aussi modulable que possible, pour pouvoir fonctionner comme tel, tout en pouvant être utilisé qu'en partie grâce à Vue CLI. -* **PGAdmin** pour les bases de données PostgreSQL, facilement modifiable pour utiliser PHPMYAdmin ou MySQL. -* **Flower** pour la surveillance de tâches Celery. -* Équilibrage de charge entre le frontend et le backend avec **Traefik**, afin de pouvoir avoir les deux sur le même domaine, séparés par chemins, mais servis par différents conteneurs. -* Intégration Traefik, comprenant la génération automatique de certificat **HTTPS** Let's Encrypt. -* GitLab **CI** (intégration continue), comprenant des tests pour le frontend et le backend. - -## Full Stack FastAPI Couchbase - -GitHub : https://github.com/tiangolo/full-stack-fastapi-couchbase - -⚠️ **ATTENTION** ⚠️ - -Si vous démarrez un nouveau projet de zéro, allez voir les alternatives au début de cette page. - -Par exemple, le générateur de projet Full Stack FastAPI PostgreSQL peut être une meilleure alternative, étant activement maintenu et utilisé et comprenant toutes les nouvelles fonctionnalités et améliorations. - -Vous êtes toujours libre d'utiliser le générateur basé sur Couchbase si vous le voulez, cela devrait probablement fonctionner correctement, et si vous avez déjà un projet généré en utilisant ce dernier, cela devrait fonctionner aussi (et vous l'avez déjà probablement mis à jour suivant vos besoins). - -Vous pouvez en apprendre plus dans la documentation du dépôt GithHub. - -## Full Stack FastAPI MongoDB - -...viendra surement plus tard, suivant le temps que j'ai. 😅 🎉 - -## Modèles d'apprentissage automatique avec spaCy et FastAPI - -GitHub : https://github.com/microsoft/cookiecutter-spacy-fastapi - -## Modèles d'apprentissage automatique avec spaCy et FastAPI - Fonctionnalités - -* Intégration d'un modèle NER **spaCy**. -* Formatage de requête pour **Azure Cognitive Search**. -* Serveur Python web **prêt à utiliser en production** utilisant Uvicorn et Gunicorn. -* Déploiement CI/CD Kubernetes pour **Azure DevOps** (AKS). -* **Multilangues**. Choisissez facilement l'une des langues intégrées à spaCy durant la mise en place du projet. -* **Facilement généralisable** à d'autres bibliothèques similaires (Pytorch, Tensorflow), et non juste spaCy. +- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/fr) pour l'API backend Python. + - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) pour les interactions avec la base de données SQL en Python (ORM). + - 🔍 [Pydantic](https://docs.pydantic.dev), utilisé par FastAPI, pour la validation des données et la gestion des paramètres. + - 💾 [PostgreSQL](https://www.postgresql.org) comme base de données SQL. +- 🚀 [React](https://react.dev) pour le frontend. + - 💃 Utilisation de TypeScript, des hooks, de Vite et d'autres éléments d'un stack frontend moderne. + - 🎨 [Tailwind CSS](https://tailwindcss.com) et [shadcn/ui](https://ui.shadcn.com) pour les composants frontend. + - 🤖 Un client frontend généré automatiquement. + - 🧪 [Playwright](https://playwright.dev) pour les tests de bout en bout. + - 🦇 Prise en charge du mode sombre. +- 🐋 [Docker Compose](https://www.docker.com) pour le développement et la production. +- 🔒 Hachage sécurisé des mots de passe par défaut. +- 🔑 Authentification JWT (JSON Web Token). +- 📫 Récupération de mot de passe par e-mail. +- ✅ Tests avec [Pytest](https://pytest.org). +- 📞 [Traefik](https://traefik.io) comme proxy inverse / répartiteur de charge. +- 🚢 Instructions de déploiement avec Docker Compose, y compris la configuration d'un proxy Traefik frontal pour gérer les certificats HTTPS automatiques. +- 🏭 CI (intégration continue) et CD (déploiement continu) basés sur GitHub Actions. diff --git a/docs/fr/docs/python-types.md b/docs/fr/docs/python-types.md index 99ca908277..f393b0f5c1 100644 --- a/docs/fr/docs/python-types.md +++ b/docs/fr/docs/python-types.md @@ -1,70 +1,68 @@ -# Introduction aux Types Python +# Introduction aux types Python { #python-types-intro } -Python supporte des annotations de type (ou *type hints*) optionnelles. +Python prend en charge des « type hints » (aussi appelées « annotations de type ») facultatives. -Ces annotations de type constituent une syntaxe spéciale qui permet de déclarer le type d'une variable. +Ces « type hints » ou annotations sont une syntaxe spéciale qui permet de déclarer le type d'une variable. -En déclarant les types de vos variables, cela permet aux différents outils comme les éditeurs de texte d'offrir un meilleur support. +En déclarant les types de vos variables, les éditeurs et outils peuvent vous offrir un meilleur support. -Ce chapitre n'est qu'un **tutoriel rapide / rappel** sur les annotations de type Python. -Seulement le minimum nécessaire pour les utiliser avec **FastAPI** sera couvert... ce qui est en réalité très peu. +Ceci est un **tutoriel rapide / rappel** à propos des annotations de type Python. Il couvre uniquement le minimum nécessaire pour les utiliser avec **FastAPI** ... ce qui est en réalité très peu. -**FastAPI** est totalement basé sur ces annotations de type, qui lui donnent de nombreux avantages. +**FastAPI** est totalement basé sur ces annotations de type, elles lui donnent de nombreux avantages et bénéfices. -Mais même si vous n'utilisez pas ou n'utiliserez jamais **FastAPI**, vous pourriez bénéficier d'apprendre quelques choses sur ces dernières. +Mais même si vous n'utilisez jamais **FastAPI**, vous auriez intérêt à en apprendre un peu à leur sujet. -/// note +/// note | Remarque -Si vous êtes un expert Python, et que vous savez déjà **tout** sur les annotations de type, passez au chapitre suivant. +Si vous êtes un expert Python, et que vous savez déjà tout sur les annotations de type, passez au chapitre suivant. /// -## Motivations +## Motivation { #motivation } -Prenons un exemple simple : +Commençons par un exemple simple : -{*../../docs_src/python_types/tutorial001.py*} +{* ../../docs_src/python_types/tutorial001_py39.py *} -Exécuter ce programe affiche : +Exécuter ce programme affiche : ``` John Doe ``` -La fonction : +La fonction fait ce qui suit : * Prend un `first_name` et un `last_name`. -* Convertit la première lettre de chaque paramètre en majuscules grâce à `title()`. -* Concatène les résultats avec un espace entre les deux. +* Convertit la première lettre de chacun en majuscule avec `title()`. +* Concatène ces deux valeurs avec un espace au milieu. -{*../../docs_src/python_types/tutorial001.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} -### Limitations +### Modifier le code { #edit-it } C'est un programme très simple. Mais maintenant imaginez que vous l'écriviez de zéro. -À un certain point vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts. +À un certain moment, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts ... -Mais vous aviez besoin de "cette méthode qui convertit la première lettre en majuscule". +Mais ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ». -Était-ce `upper` ? `uppercase` ? `first_uppercase` ? `capitalize` ? +Était-ce `upper` ? Était-ce `uppercase` ? `first_uppercase` ? `capitalize` ? -Vous essayez donc d'utiliser le vieil ami du programmeur, l'auto-complétion de l'éditeur. +Vous essayez alors avec l'ami de toujours des programmeurs, l'autocomplétion de l'éditeur. -Vous écrivez le premier paramètre, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'auto-complétion. +Vous tapez le premier paramètre de la fonction, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'autocomplétion. -Mais malheureusement, rien d'utile n'en résulte : +Mais, malheureusement, vous n'obtenez rien d'utile : -### Ajouter des types +### Ajouter des types { #add-types } Modifions une seule ligne de la version précédente. -Nous allons changer seulement cet extrait, les paramètres de la fonction, de : - +Nous allons changer exactement ce fragment, les paramètres de la fonction, de : ```Python first_name, last_name @@ -78,222 +76,389 @@ Nous allons changer seulement cet extrait, les paramètres de la fonction, de : C'est tout. -Ce sont des annotations de types : +Ce sont les « annotations de type » : -{*../../docs_src/python_types/tutorial002.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} -À ne pas confondre avec la déclaration de valeurs par défaut comme ici : +Ce n'est pas la même chose que de déclarer des valeurs par défaut, ce qui serait : ```Python first_name="john", last_name="doe" ``` -C'est une chose différente. +C'est différent. -On utilise un deux-points (`:`), et pas un égal (`=`). +Nous utilisons des deux-points (`:`), pas des signes égal (`=`). -Et ajouter des annotations de types ne crée normalement pas de différence avec le comportement qui aurait eu lieu si elles n'étaient pas là. +Et ajouter des annotations de type ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans elles. -Maintenant, imaginez que vous êtes en train de créer cette fonction, mais avec des annotations de type cette fois. +Mais maintenant, imaginez que vous êtes à nouveau en train de créer cette fonction, mais avec des annotations de type. -Au même moment que durant l'exemple précédent, vous essayez de déclencher l'auto-complétion et vous voyez : +Au même moment, vous essayez de déclencher l'autocomplétion avec `Ctrl+Espace` et vous voyez : -Vous pouvez donc dérouler les options jusqu'à trouver la méthode à laquelle vous pensiez. +Avec cela, vous pouvez faire défiler en voyant les options, jusqu'à trouver celle qui « vous dit quelque chose » : -## Plus de motivations +## Plus de motivation { #more-motivation } -Cette fonction possède déjà des annotations de type : +Regardez cette fonction, elle a déjà des annotations de type : -{*../../docs_src/python_types/tutorial003.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} -Comme l'éditeur connaît le type des variables, vous n'avez pas seulement l'auto-complétion, mais aussi de la détection d'erreurs : +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 : -Maintenant que vous avez connaissance du problème, convertissez `age` en chaîne de caractères grâce à `str(age)` : +Vous savez maintenant qu'il faut corriger, convertir `age` en chaîne avec `str(age)` : -{*../../docs_src/python_types/tutorial004.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} -## Déclarer des types +## Déclarer des types { #declaring-types } -Vous venez de voir là où les types sont généralement déclarés : dans les paramètres de fonctions. +Vous venez de voir l'endroit principal pour déclarer des annotations de type : dans les paramètres des fonctions. -C'est aussi ici que vous les utiliseriez avec **FastAPI**. +C'est aussi l'endroit principal où vous les utiliserez avec **FastAPI**. -### Types simples +### Types simples { #simple-types } -Vous pouvez déclarer tous les types de Python, pas seulement `str`. +Vous pouvez déclarer tous les types standards de Python, pas seulement `str`. -Comme par exemple : +Vous pouvez utiliser, par exemple : * `int` * `float` * `bool` * `bytes` -{*../../docs_src/python_types/tutorial005.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} -### Types génériques avec des paramètres de types +### Types génériques avec paramètres de type { #generic-types-with-type-parameters } -Il existe certaines structures de données qui contiennent d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent elles aussi avoir leurs propres types. +Il existe 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 déclarer ces types et les types internes, on utilise le module standard de Python `typing`. +Ces types qui ont des types internes sont appelés types « génériques ». Et il est possible de les déclarer, même avec leurs types internes. -Il existe spécialement pour supporter ces annotations de types. +Pour déclarer ces types et les types internes, vous pouvez utiliser le module standard Python `typing`. Il existe spécifiquement pour prendre en charge ces annotations de type. -#### `List` +#### Versions plus récentes de Python { #newer-versions-of-python } -Par exemple, définissons une variable comme `list` de `str`. +La syntaxe utilisant `typing` est compatible avec toutes les versions, de Python 3.6 aux plus récentes, y compris Python 3.9, Python 3.10, etc. -Importez `List` (avec un `L` majuscule) depuis `typing`. +Au fur et à mesure que Python évolue, les versions plus récentes 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. -{*../../docs_src/python_types/tutorial006.py hl[1] *} +Si vous pouvez choisir une version plus récente de Python pour votre projet, vous pourrez profiter de cette simplicité supplémentaire. -Déclarez la variable, en utilisant la syntaxe des deux-points (`:`). +Dans toute la documentation, il y a des exemples compatibles avec chaque version de Python (lorsqu'il y a une différence). -Et comme type, mettez `List`. +Par exemple « Python 3.6+ » signifie que c'est compatible avec Python 3.6 ou supérieur (y compris 3.7, 3.8, 3.9, 3.10, etc.). Et « Python 3.9+ » signifie que c'est compatible avec Python 3.9 ou supérieur (y compris 3.10, etc). -Les listes étant un type contenant des types internes, mettez ces derniers entre crochets (`[`, `]`) : +Si vous pouvez utiliser les dernières versions de Python, utilisez les exemples pour la dernière version, ils auront la meilleure et la plus simple syntaxe, par exemple, « Python 3.10+ ». -{*../../docs_src/python_types/tutorial006.py hl[4] *} +#### Liste { #list } -/// tip | Astuce +Par exemple, définissons une variable comme une `list` de `str`. -Ces types internes entre crochets sont appelés des "paramètres de type". +Déclarez la variable, en utilisant la même syntaxe avec deux-points (`:`). -Ici, `str` est un paramètre de type passé à `List`. +Comme type, mettez `list`. + +Comme la liste est un type qui contient des types internes, mettez-les entre crochets : + +{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} + +/// info + +Ces types internes entre crochets sont appelés « paramètres de type ». + +Dans ce cas, `str` est le paramètre de type passé à `list`. /// -Ce qui signifie : "la variable `items` est une `list`, et chacun de ses éléments a pour type `str`. +Cela signifie : « la variable `items` est une `list`, et chacun des éléments de cette liste est un `str` ». -En faisant cela, votre éditeur pourra vous aider, même pendant que vous traitez des éléments de la liste. +En faisant cela, votre éditeur peut vous fournir de l'aide même pendant le traitement des éléments de la liste : Sans types, c'est presque impossible à réaliser. -Vous remarquerez que la variable `item` n'est qu'un des éléments de la list `items`. +Remarquez que la variable `item` est l'un des éléments de la liste `items`. -Et pourtant, l'éditeur sait qu'elle est de type `str` et pourra donc vous aider à l'utiliser. +Et pourtant, l'éditeur sait que c'est un `str` et fournit le support approprié. -#### `Tuple` et `Set` +#### Tuple et Set { #tuple-and-set } -C'est le même fonctionnement pour déclarer un `tuple` ou un `set` : +Vous feriez la même chose pour déclarer des `tuple` et des `set` : -{*../../docs_src/python_types/tutorial007.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} -Dans cet exemple : +Cela signifie : -* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un deuxième `int`, et un `str`. +* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un autre `int`, et un `str`. * La variable `items_s` est un `set`, et chacun de ses éléments est de type `bytes`. -#### `Dict` +#### Dict { #dict } -Pour définir un `dict`, il faut lui passer 2 paramètres, séparés par une virgule (`,`). +Pour définir un `dict`, vous passez 2 paramètres de type, séparés par des virgules. -Le premier paramètre de type est pour les clés et le second pour les valeurs du dictionnaire (`dict`). +Le premier paramètre de type est pour les clés du `dict`. -{*../../docs_src/python_types/tutorial008.py hl[1,4] *} +Le second paramètre de type est pour les valeurs du `dict` : -Dans cet exemple : +{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} -* La variable `prices` est de type `dict` : - * Les clés de ce dictionnaire sont de type `str`. - * Les valeurs de ce dictionnaire sont de type `float`. +Cela signifie : -#### `Optional` +* La variable `prices` est un `dict` : + * Les clés de ce `dict` sont de type `str` (disons, le nom de chaque article). + * Les valeurs de ce `dict` sont de type `float` (disons, le prix de chaque article). -Vous pouvez aussi utiliser `Optional` pour déclarer qu'une variable a un type, comme `str` mais qu'il est "optionnel" signifiant qu'il pourrait aussi être `None`. +#### Union { #union } -{*../../docs_src/python_types/tutorial009.py hl[1,4] *} +Vous pouvez déclarer qu'une variable peut être de plusieurs types, par exemple, un `int` ou un `str`. -Utiliser `Optional[str]` plutôt que `str` permettra à l'éditeur de vous aider à détecter les erreurs où vous supposeriez qu'une valeur est toujours de type `str`, alors qu'elle pourrait aussi être `None`. +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. -#### Types génériques +Dans Python 3.10, il existe aussi une nouvelle syntaxe où vous pouvez mettre les types possibles séparés par une barre verticale (`|`). -Les types qui peuvent contenir des paramètres de types entre crochets, comme : +//// tab | Python 3.10+ -* `List` -* `Tuple` -* `Set` -* `Dict` +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial008b_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial008b_py39.py!} +``` + +//// + +Dans les deux cas, cela signifie que `item` 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" +{!> ../../docs_src/python_types/tutorial009_py310.py!} +``` + +//// + +//// 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. +* ... et d'autres. -sont appelés des **types génériques** ou **Generics**. +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. -### Classes en tant que types +//// + +//// 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. + +//// + +### Classes en tant que types { #classes-as-types } Vous pouvez aussi déclarer une classe comme type d'une variable. -Disons que vous avez une classe `Person`, avec une variable `name` : - -{*../../docs_src/python_types/tutorial010.py hl[1:3] *} +Disons que vous avez une classe `Person`, avec un nom : +{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} Vous pouvez ensuite déclarer une variable de type `Person` : -{*../../docs_src/python_types/tutorial010.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} -Et vous aurez accès, encore une fois, au support complet offert par l'éditeur : +Et là encore, vous obtenez tout le support de l'éditeur : -## Les modèles Pydantic +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` ». + +## Modèles Pydantic { #pydantic-models } Pydantic est une bibliothèque Python pour effectuer de la validation de données. -Vous déclarez la forme de la donnée avec des classes et des attributs. +Vous déclarez la « forme » de la donnée sous forme de classes avec des attributs. -Chaque attribut possède un type. +Et chaque attribut a un type. -Puis vous créez une instance de cette classe avec certaines valeurs et **Pydantic** validera les valeurs, les convertira dans le type adéquat (si c'est nécessaire et possible) et vous donnera un objet avec toute la donnée. +Ensuite, vous créez une instance de cette classe avec certaines valeurs et elle validera les valeurs, les convertira dans le type approprié (le cas échéant) et vous donnera un objet avec toutes les données. -Ainsi, votre éditeur vous offrira un support adapté pour l'objet résultant. +Et vous obtenez tout le support de l'éditeur avec cet objet résultant. -Extrait de la documentation officielle de **Pydantic** : +Un exemple tiré de la documentation officielle de Pydantic : -{*../../docs_src/python_types/tutorial011.py*} +{* ../../docs_src/python_types/tutorial011_py310.py *} /// info -Pour en savoir plus à propos de Pydantic, allez jeter un coup d'oeil à sa documentation. +Pour en savoir plus à propos de Pydantic, consultez sa documentation. /// -**FastAPI** est basé entièrement sur **Pydantic**. +**FastAPI** est entièrement basé sur Pydantic. -Vous verrez bien plus d'exemples de son utilisation dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}. +Vous verrez beaucoup plus de tout cela en pratique dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}. -## Les annotations de type dans **FastAPI** +/// tip | Astuce -**FastAPI** utilise ces annotations pour faire différentes choses. +Pydantic a un comportement spécial lorsque vous utilisez `Optional` ou `Union[Something, None]` sans valeur par défaut, vous pouvez en lire davantage dans la documentation de Pydantic à propos des champs Optionals requis. -Avec **FastAPI**, vous déclarez des paramètres grâce aux annotations de types et vous obtenez : +/// -* **du support de l'éditeur** -* **de la vérification de types** +## Annotations de type avec métadonnées { #type-hints-with-metadata-annotations } -...et **FastAPI** utilise ces mêmes déclarations pour : +Python dispose également d'une fonctionnalité qui permet de mettre des **métadonnées supplémentaires** dans ces annotations de type en utilisant `Annotated`. -* **Définir les prérequis** : depuis les paramètres de chemins des requêtes, les entêtes, les corps, les dépendances, etc. -* **Convertir des données** : depuis la requête vers les types requis. -* **Valider des données** : venant de chaque requête : - * Générant automatiquement des **erreurs** renvoyées au client quand la donnée est invalide. +Depuis Python 3.9, `Annotated` fait partie de la bibliothèque standard, vous pouvez donc l'importer depuis `typing`. + +{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} + +Python lui-même ne fait rien avec ce `Annotated`. Et pour les éditeurs et 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. + +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. + +/// 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. ✨ + +Et aussi que votre code sera très compatible avec de nombreux autres outils et bibliothèques Python. 🚀 + +/// + +## Annotations de type dans **FastAPI** { #type-hints-in-fastapi } + +**FastAPI** tire parti de ces annotations de type pour faire plusieurs choses. + +Avec **FastAPI**, vous déclarez des paramètres avec des annotations de type et vous obtenez : + +* **Du support de l'éditeur**. +* **Des vérifications de types**. + +... et **FastAPI** utilise les mêmes déclarations pour : + +* **Définir des prérequis** : à partir des paramètres de chemin de la requête, des paramètres de requête, des en-têtes, des corps, des dépendances, etc. +* **Convertir des données** : de la requête vers le type requis. +* **Valider des données** : provenant de chaque requête : + * En générant des **erreurs automatiques** renvoyées au client lorsque la donnée est invalide. * **Documenter** l'API avec OpenAPI : - * ce qui ensuite utilisé par les interfaces utilisateur automatiques de documentation interactive. + * ce qui est ensuite utilisé par les interfaces utilisateur de documentation interactive automatiques. -Tout cela peut paraître bien abstrait, mais ne vous inquiétez pas, vous verrez tout ça en pratique dans [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}. +Tout cela peut sembler abstrait. Ne vous inquiétez pas. Vous verrez tout cela en action dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}. -Ce qu'il faut retenir c'est qu'en utilisant les types standard de Python, à un seul endroit (plutôt que d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous. +L'important est qu'en utilisant les types standards de Python, 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 -Si vous avez déjà lu le tutoriel et êtes revenus ici pour voir plus sur les types, une bonne ressource est la "cheat sheet" de `mypy`. +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/tutorial/background-tasks.md b/docs/fr/docs/tutorial/background-tasks.md index 6efd16e07d..ed7494669f 100644 --- a/docs/fr/docs/tutorial/background-tasks.md +++ b/docs/fr/docs/tutorial/background-tasks.md @@ -1,4 +1,4 @@ -# Tâches d'arrière-plan +# Tâches d'arrière-plan { #background-tasks } Vous pouvez définir des tâches d'arrière-plan qui seront exécutées après avoir retourné une réponse. @@ -7,20 +7,19 @@ Ceci est utile pour les opérations qui doivent avoir lieu après une requête, Cela comprend, par exemple : * Les notifications par email envoyées après l'exécution d'une action : - * Étant donné que se connecter à un serveur et envoyer un email a tendance à être «lent» (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan. + * Étant donné que se connecter à un serveur et envoyer un email a tendance à être « lent » (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan. * Traiter des données : - * Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse «Accepted» (HTTP 202) puis faire le traitement en arrière-plan. + * Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse « Accepted » (HTTP 202) puis faire le traitement en arrière-plan. +## Utiliser `BackgroundTasks` { #using-backgroundtasks } -## Utiliser `BackgroundTasks` +Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin d'accès* avec `BackgroundTasks` comme type déclaré. -Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin* avec `BackgroundTasks` comme type déclaré. - -{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} **FastAPI** créera l'objet de type `BackgroundTasks` pour vous et le passera comme paramètre. -## Créer une fonction de tâche +## Créer une fonction de tâche { #create-a-task-function } Une fonction à exécuter comme tâche d'arrière-plan est juste une fonction standard qui peut recevoir des paramètres. @@ -30,14 +29,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.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} -## Ajouter une tâche d'arrière-plan +## Ajouter une tâche d'arrière-plan { #add-the-background-task } -Dans votre *fonction de chemin*, passez votre fonction de tâche à l'objet de type `BackgroundTasks` (`background_tasks` ici) grâce à la méthode `.add_task()` : +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.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} `.add_task()` reçoit comme arguments : @@ -45,40 +43,40 @@ Dans votre *fonction de chemin*, passez votre fonction de tâche à l'objet de t * Les arguments positionnels à passer à la fonction de tâche dans l'ordre (`email`). * Les arguments nommés à passer à la fonction de tâche (`message="some notification"`). -## Injection de dépendances +## Injection de dépendances { #dependency-injection } -Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances. Vous pouvez déclarer un paramètre de type `BackgroundTasks` à différents niveaux : dans une *fonction de chemin*, dans une dépendance, dans une sous-dépendance... +Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances. Vous pouvez déclarer un paramètre de type `BackgroundTasks` à différents niveaux : dans une *fonction de chemin d'accès*, dans une dépendance (dependable), dans une sous-dépendance, etc. -**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que tous les paramètres de type `BackgroundTasks` soient fusionnés et que les tâches soient exécutées en arrière-plan : +**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que toutes les tâches d'arrière-plan soient fusionnées et que les tâches soient ensuite exécutées en arrière-plan : -{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *} +{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *} Dans cet exemple, les messages seront écrits dans le fichier `log.txt` après que la réponse soit envoyée. -S'il y avait une `query` (paramètre nommé `q`) dans la requête, alors elle sera écrite dans `log.txt` via une tâche d'arrière-plan. +S'il y avait un paramètre de requête dans la requête, alors il sera écrit dans le journal via une tâche d'arrière-plan. -Et ensuite une autre tâche d'arrière-plan (générée dans les paramètres de la *la fonction de chemin*) écrira un message dans `log.txt` comprenant le paramètre de chemin `email`. +Et ensuite une autre tâche d'arrière-plan (générée dans la *fonction de chemin d'accès*) écrira un message comprenant le paramètre de chemin `email`. -## Détails techniques +## Détails techniques { #technical-details } La classe `BackgroundTasks` provient directement de `starlette.background`. Elle est importée/incluse directement dans **FastAPI** pour que vous puissiez l'importer depuis `fastapi` et éviter d'importer accidentellement `BackgroundTask` (sans `s` à la fin) depuis `starlette.background`. -En utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin* et de laisser **FastAPI** gérer le reste pour vous, comme en utilisant l'objet `Request` directement. +En utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin d'accès* et de laisser **FastAPI** gérer le reste pour vous, comme en utilisant l'objet `Request` directement. Il est tout de même possible d'utiliser `BackgroundTask` seul dans **FastAPI**, mais dans ce cas il faut créer l'objet dans le code et renvoyer une `Response` Starlette l'incluant. -Plus de détails sont disponibles dans la documentation officielle de Starlette sur les tâches d'arrière-plan (via leurs classes `BackgroundTasks`et `BackgroundTask`). +Plus de détails sont disponibles dans la documentation officielle de Starlette sur les tâches d'arrière-plan. -## Avertissement +## Avertissement { #caveat } Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que Celery. -Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et potentiellement, sur plusieurs serveurs. +Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et surtout, sur plusieurs serveurs. Mais si vous avez besoin d'accéder aux variables et objets de la même application **FastAPI**, ou si vous avez besoin d'effectuer de petites tâches d'arrière-plan (comme envoyer des notifications par email), vous pouvez simplement vous contenter d'utiliser `BackgroundTasks`. -## Résumé +## Résumé { #recap } -Importez et utilisez `BackgroundTasks` grâce aux paramètres de *fonction de chemin* et les dépendances pour ajouter des tâches d'arrière-plan. +Importez et utilisez `BackgroundTasks` grâce aux paramètres de *fonction de chemin d'accès* et les dépendances pour ajouter des tâches d'arrière-plan. diff --git a/docs/fr/docs/tutorial/body-multiple-params.md b/docs/fr/docs/tutorial/body-multiple-params.md index 0541acc74e..9aed24e989 100644 --- a/docs/fr/docs/tutorial/body-multiple-params.md +++ b/docs/fr/docs/tutorial/body-multiple-params.md @@ -1,24 +1,24 @@ -# Body - Paramètres multiples +# Body - Paramètres multiples { #body-multiple-parameters } -Maintenant que nous avons vu comment manipuler `Path` et `Query`, voyons comment faire pour le corps d'une requête, communément désigné par le terme anglais "body". +Maintenant que nous avons vu comment utiliser `Path` et `Query`, voyons des usages plus avancés des déclarations de paramètres du corps de la requête. -## Mélanger les paramètres `Path`, `Query` et body +## Mélanger les paramètres `Path`, `Query` et body { #mix-path-query-and-body-parameters } -Tout d'abord, sachez que vous pouvez mélanger les déclarations des paramètres `Path`, `Query` et body, **FastAPI** saura quoi faire. +Tout d'abord, sachez que vous pouvez mélanger librement les déclarations des paramètres `Path`, `Query` et du body, **FastAPI** saura quoi faire. -Vous pouvez également déclarer des paramètres body comme étant optionnels, en leur assignant une valeur par défaut à `None` : +Et vous pouvez également déclarer des paramètres du body comme étant optionnels, en leur assignant une valeur par défaut à `None` : {* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *} -/// note +/// note | Remarque -Notez que, dans ce cas, le paramètre `item` provenant du `Body` est optionnel (sa valeur par défaut est `None`). +Notez que, dans ce cas, l'élément `item` récupéré depuis le body est optionnel. Comme sa valeur par défaut est `None`. /// -## Paramètres multiples du body +## Paramètres multiples du body { #multiple-body-parameters } -Dans l'exemple précédent, les opérations de routage attendaient un body JSON avec les attributs d'un `Item`, par exemple : +Dans l'exemple précédent, les chemins d'accès attendraient un body JSON avec les attributs d'un `Item`, par exemple : ```JSON { @@ -29,13 +29,13 @@ Dans l'exemple précédent, les opérations de routage attendaient un body JSON } ``` -Mais vous pouvez également déclarer plusieurs paramètres provenant de body, par exemple `item` et `user` simultanément : +Mais vous pouvez également déclarer plusieurs paramètres provenant du body, par exemple `item` et `user` : {* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *} -Dans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre dans le body (chacun correspondant à un modèle Pydantic). +Dans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre du body dans la fonction (il y a deux paramètres qui sont des modèles Pydantic). -Il utilisera alors les noms des paramètres comme clés, et s'attendra à recevoir quelque chose de semblable à : +Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le body, et s'attendra à recevoir un body semblable à : ```JSON { @@ -52,25 +52,25 @@ Il utilisera alors les noms des paramètres comme clés, et s'attendra à recevo } ``` -/// note +/// note | Remarque -"Notez que, bien que nous ayons déclaré le paramètre `item` de la même manière que précédemment, il est maintenant associé à la clé `item` dans le corps de la requête."`. +Notez que, bien que `item` ait été déclaré de la même manière qu'auparavant, il est désormais attendu à l'intérieur du body sous la clé `item`. /// -**FastAPI** effectue la conversion de la requête de façon transparente, de sorte que les objets `item` et `user` se trouvent correctement définis. +**FastAPI** effectuera la conversion automatique depuis la requête, de sorte que le paramètre `item` reçoive son contenu spécifique, et de même pour `user`. -Il effectue également la validation des données (même imbriquées les unes dans les autres), et permet de les documenter correctement (schéma OpenAPI et documentation auto-générée). +Il effectuera la validation des données composées, et les documentera ainsi pour le schéma OpenAPI et la documentation automatique. -## Valeurs scalaires dans le body +## Valeurs singulières dans le body { #singular-values-in-body } -De la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres query et path, **FastAPI** fournit un équivalent `Body`. +De la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres de requête et de chemin, **FastAPI** fournit un équivalent `Body`. -Par exemple, en étendant le modèle précédent, vous pouvez vouloir ajouter un paramètre `importance` dans le même body, en plus des paramètres `item` et `user`. +Par exemple, en étendant le modèle précédent, vous pourriez décider d'avoir une autre clé `importance` dans le même body, en plus de `item` et `user`. -Si vous le déclarez tel quel, comme c'est une valeur [scalaire](https://docs.github.com/fr/graphql/reference/scalars), **FastAPI** supposera qu'il s'agit d'un paramètre de requête (`Query`). +Si vous le déclarez tel quel, comme c'est une valeur singulière, **FastAPI** supposera qu'il s'agit d'un paramètre de requête. -Mais vous pouvez indiquer à **FastAPI** de la traiter comme une variable de body en utilisant `Body` : +Mais vous pouvez indiquer à **FastAPI** de la traiter comme une autre clé du body en utilisant `Body` : {* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *} @@ -92,51 +92,51 @@ Dans ce cas, **FastAPI** s'attendra à un body semblable à : } ``` -Encore une fois, cela convertira les types de données, les validera, permettra de générer la documentation, etc... +Encore une fois, il convertira les types de données, validera, documentera, etc. -## Paramètres multiples body et query +## Paramètres multiples du body et paramètres de requête { #multiple-body-params-and-query } -Bien entendu, vous pouvez déclarer autant de paramètres que vous le souhaitez, en plus des paramètres body déjà déclarés. +Bien entendu, vous pouvez également déclarer des paramètres de requête supplémentaires quand vous en avez besoin, en plus de tout paramètre du body. -Par défaut, les valeurs [scalaires](https://docs.github.com/fr/graphql/reference/scalars) sont interprétées comme des paramètres query, donc inutile d'ajouter explicitement `Query`. Vous pouvez juste écrire : - -```Python -q: Union[str, None] = None -``` - -Ou bien, en Python 3.10 et supérieur : +Comme, par défaut, les valeurs singulières sont interprétées comme des paramètres de requête, vous n'avez pas besoin d'ajouter explicitement `Query`, vous pouvez simplement écrire : ```Python 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[27] *} +{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *} /// info -`Body` possède les mêmes paramètres de validation additionnels et de gestion des métadonnées que `Query` et `Path`, ainsi que d'autres que nous verrons plus tard. +`Body` possède également les mêmes paramètres supplémentaires de validation et de métadonnées que `Query`, `Path` et d'autres que vous verrez plus tard. /// -## Inclure un paramètre imbriqué dans le body +## Intégrer un seul paramètre du body { #embed-a-single-body-parameter } -Disons que vous avez seulement un paramètre `item` dans le body, correspondant à un modèle Pydantic `Item`. +Supposons que vous n'ayez qu'un seul paramètre `item` dans le body, provenant d'un modèle Pydantic `Item`. -Par défaut, **FastAPI** attendra sa déclaration directement dans le body. +Par défaut, **FastAPI** attendra alors son contenu directement. -Cependant, si vous souhaitez qu'il interprête correctement un JSON avec une clé `item` associée au contenu du modèle, comme cela serait le cas si vous déclariez des paramètres body additionnels, vous pouvez utiliser le paramètre spécial `embed` de `Body` : +Mais si vous voulez qu'il attende un JSON avec une clé `item` contenant le contenu du modèle, comme lorsqu'on déclare des paramètres supplémentaires du body, vous pouvez utiliser le paramètre spécial `embed` de `Body` : ```Python item: Item = Body(embed=True) ``` -Voici un exemple complet : +comme dans : {* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *} -Dans ce cas **FastAPI** attendra un body semblable à : +Dans ce cas **FastAPI** s'attendra à un body semblable à : ```JSON hl_lines="2" { @@ -160,12 +160,12 @@ au lieu de : } ``` -## Pour résumer +## Récapitulatif { #recap } -Vous pouvez ajouter plusieurs paramètres body dans votre fonction de routage, même si une requête ne peut avoir qu'un seul body. +Vous pouvez ajouter plusieurs paramètres du body à votre fonction de chemin d'accès, même si une requête ne peut avoir qu'un seul body. -Cependant, **FastAPI** se chargera de faire opérer sa magie, afin de toujours fournir à votre fonction des données correctes, les validera et documentera le schéma associé. +Mais **FastAPI** s'en chargera, vous fournira les bonnes données dans votre fonction, et validera et documentera le schéma correct dans le chemin d'accès. -Vous pouvez également déclarer des valeurs [scalaires](https://docs.github.com/fr/graphql/reference/scalars) à recevoir dans le body. +Vous pouvez également déclarer des valeurs singulières à recevoir dans le body. -Et vous pouvez indiquer à **FastAPI** d'inclure le body dans une autre variable, même lorsqu'un seul paramètre est déclaré. +Et vous pouvez indiquer à **FastAPI** d'intégrer le body sous une clé même lorsqu'un seul paramètre est déclaré. diff --git a/docs/fr/docs/tutorial/body.md b/docs/fr/docs/tutorial/body.md index 760b6d80ae..ca115fabc7 100644 --- a/docs/fr/docs/tutorial/body.md +++ b/docs/fr/docs/tutorial/body.md @@ -1,10 +1,10 @@ -# Corps de la requête +# Corps de la requête { #request-body } Quand vous avez besoin d'envoyer de la donnée depuis un client (comme un navigateur) vers votre API, vous l'envoyez en tant que **corps de requête**. Le corps d'une **requête** est de la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée envoyée par votre API au client. -Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un corps de **requête**. +Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un **corps de requête** : parfois il demande seulement un chemin, peut-être avec quelques paramètres de requête, mais n'envoie pas de corps. Pour déclarer un corps de **requête**, on utilise les modèles de Pydantic en profitant de tous leurs avantages et fonctionnalités. @@ -18,23 +18,23 @@ Ceci étant découragé, la documentation interactive générée par Swagger UI /// -## Importez le `BaseModel` de Pydantic +## Importer le `BaseModel` de Pydantic { #import-pydantics-basemodel } Commencez par importer la classe `BaseModel` du module `pydantic` : -{* ../../docs_src/body/tutorial001.py hl[4] *} +{* ../../docs_src/body/tutorial001_py310.py hl[2] *} -## Créez votre modèle de données +## Créer votre modèle de données { #create-your-data-model } Déclarez ensuite votre modèle de données en tant que classe qui hérite de `BaseModel`. Utilisez les types Python standard pour tous les attributs : -{* ../../docs_src/body/tutorial001.py hl[7:11] *} +{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *} -Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, cet attribut doit être renseigné dans le corps de la requête. Pour rendre ce champ optionnel simplement, utilisez `None` comme valeur par défaut. +Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, cet attribut doit être renseigné dans le corps de la requête. Utilisez `None` pour le rendre simplement optionnel. -Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) tel que : +Par exemple, le modèle ci-dessus déclare un JSON « `object` » (ou `dict` Python) tel que : ```JSON { @@ -45,7 +45,7 @@ Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) te } ``` -...`description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), cet "objet" JSON serait aussi valide : +... `description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), ce JSON « `object` » serait aussi valide : ```JSON { @@ -54,28 +54,28 @@ Par exemple, le modèle ci-dessus déclare un "objet" JSON (ou `dict` Python) te } ``` -## Déclarez-le comme paramètre +## Le déclarer comme paramètre { #declare-it-as-a-parameter } Pour l'ajouter à votre *opération de chemin*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête : -{* ../../docs_src/body/tutorial001.py hl[18] *} +{* ../../docs_src/body/tutorial001_py310.py hl[16] *} -...et déclarez que son type est le modèle que vous avez créé : `Item`. +... et déclarez que son type est le modèle que vous avez créé : `Item`. -## Résultats +## Résultats { #results } En utilisant uniquement les déclarations de type Python, **FastAPI** réussit à : * Lire le contenu de la requête en tant que JSON. * Convertir les types correspondants (si nécessaire). * Valider la donnée. - * Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où était la donnée incorrecte. + * Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où et quelle était la donnée incorrecte. * Passer la donnée reçue dans le paramètre `item`. - * Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (auto-complétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs. -* Générer des définitions JSON Schema pour votre modèle, qui peuvent être utilisées où vous en avez besoin dans votre projet ensuite. -* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront donc utilisés par les documentations automatiquement générées. + * Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (autocomplétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs. +* Générer des définitions JSON Schema pour votre modèle ; vous pouvez également les utiliser partout ailleurs si cela a du sens pour votre projet. +* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront utilisés par les documentations automatiques UIs. -## Documentation automatique +## Documentation automatique { #automatic-docs } Les schémas JSON de vos modèles seront intégrés au schéma OpenAPI global de votre application, et seront donc affichés dans la documentation interactive de l'API : @@ -85,63 +85,63 @@ Et seront aussi utilisés dans chaque *opération de chemin* de la documentation -## Support de l'éditeur +## Support de l'éditeur { #editor-support } -Dans votre éditeur, vous aurez des annotations de types et de l'auto-complétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez utilisé un classique `dict` plutôt qu'un modèle Pydantic) : +Dans votre éditeur, vous aurez des annotations de type et de l'autocomplétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez reçu un `dict` plutôt qu'un modèle Pydantic) : -Et vous obtenez aussi de la vérification d'erreur pour les opérations incorrectes de types : +Et vous obtenez aussi des vérifications d'erreurs pour les opérations de types incorrectes : Ce n'est pas un hasard, ce framework entier a été bâti avec ce design comme objectif. -Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour s'assurer que cela fonctionnerait avec tous les éditeurs. +Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour vous assurer que cela fonctionnerait avec tous les éditeurs. Des changements sur Pydantic ont même été faits pour supporter cela. -Les captures d'écrans précédentes ont été prises sur Visual Studio Code. +Les captures d'écran précédentes ont été prises sur Visual Studio Code. -Mais vous auriez le même support de l'éditeur avec PyCharm et la majorité des autres éditeurs de code Python. +Mais vous auriez le même support de l'éditeur avec PyCharm et la majorité des autres éditeurs de code Python : /// tip | Astuce -Si vous utilisez PyCharm comme éditeur, vous pouvez utiliser le Plugin Pydantic PyCharm Plugin. +Si vous utilisez PyCharm comme éditeur, vous pouvez utiliser le plug-in Pydantic PyCharm Plugin. Ce qui améliore le support pour les modèles Pydantic avec : -* de l'auto-complétion +* de l'autocomplétion * des vérifications de type -* du "refactoring" (ou remaniement de code) +* du « refactoring » (ou remaniement de code) * de la recherche -* de l'inspection +* des inspections /// -## Utilisez le modèle +## Utiliser le modèle { #use-the-model } Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement : -{* ../../docs_src/body/tutorial002.py hl[21] *} +{* ../../docs_src/body/tutorial002_py310.py *} -## Corps de la requête + paramètres de chemin +## Corps de la requête + paramètres de chemin { #request-body-path-parameters } Vous pouvez déclarer des paramètres de chemin et un corps de requête pour la même *opération de chemin*. **FastAPI** est capable de reconnaître que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de fonctions déclarés comme modèles Pydantic devraient être **récupérés depuis le corps de la requête**. -{* ../../docs_src/body/tutorial003.py hl[17:18] *} +{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *} -## Corps de la requête + paramètres de chemin et de requête +## 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*. **FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit. -{* ../../docs_src/body/tutorial004.py hl[18] *} +{* ../../docs_src/body/tutorial004_py310.py hl[16] *} Les paramètres de la fonction seront reconnus comme tel : @@ -149,14 +149,16 @@ Les paramètres de la fonction seront reconnus comme tel : * Si le paramètre est d'un **type singulier** (comme `int`, `float`, `str`, `bool`, etc.), il sera interprété comme un paramètre de **requête**. * Si le paramètre est déclaré comme ayant pour type un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête. -/// note +/// note | Remarque -**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `=None`. +**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`. -Le type `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI**, mais sera utile à votre éditeur pour améliorer le support offert par ce dernier et détecter plus facilement des erreurs de type. +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`. + +Mais ajouter ces annotations de type permettra à votre éditeur de vous offrir un meilleur support et de détecter des erreurs. /// -## Sans Pydantic +## Sans Pydantic { #without-pydantic } -Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Corps**. Pour cela, allez voir la partie de la documentation sur [Corps de la requête - Paramètres multiples](body-multiple-params.md){.internal-link target=_blank}. +Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Body**. Pour cela, allez voir la documentation sur [Corps de la requête - Paramètres multiples : Valeurs singulières dans le corps](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}. diff --git a/docs/fr/docs/tutorial/debugging.md b/docs/fr/docs/tutorial/debugging.md index ab00fbdeb2..a88fa2b23f 100644 --- a/docs/fr/docs/tutorial/debugging.md +++ b/docs/fr/docs/tutorial/debugging.md @@ -1,14 +1,14 @@ -# Débogage +# Débogage { #debugging } Vous pouvez connecter le débogueur dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm. -## Faites appel à `uvicorn` +## Appeler `uvicorn` { #call-uvicorn } Dans votre application FastAPI, importez et exécutez directement `uvicorn` : -{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} -### À propos de `__name__ == "__main__"` +### À propos de `__name__ == "__main__"` { #about-name-main } Le but principal de `__name__ == "__main__"` est d'avoir du code qui est exécuté lorsque votre fichier est appelé avec : @@ -26,7 +26,7 @@ mais qui n'est pas appelé lorsqu'un autre fichier l'importe, comme dans : from myapp import app ``` -#### Pour davantage de détails +#### Pour davantage de détails { #more-details } Imaginons que votre fichier s'appelle `myapp.py`. @@ -78,7 +78,7 @@ Pour plus d'informations, consultez débogueur +## Exécuter votre code avec votre débogueur { #run-your-code-with-your-debugger } Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le débogueur. @@ -86,10 +86,10 @@ Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous Par exemple, dans Visual Studio Code, vous pouvez : -- Cliquer sur l'onglet "Debug" de la barre d'activités de Visual Studio Code. -- "Add configuration...". -- Sélectionnez "Python". -- Lancez le débogueur avec l'option "`Python: Current File (Integrated Terminal)`". +- Allez dans le panneau « Debug ». +- « Add configuration... ». +- Sélectionnez « Python ». +- Lancez le débogueur avec l'option « Python: Current File (Integrated Terminal) ». Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc. @@ -101,8 +101,8 @@ Voici à quoi cela pourrait ressembler : Si vous utilisez Pycharm, vous pouvez : -- Ouvrir le menu "Run". -- Sélectionnez l'option "Debug...". +- Ouvrez le menu « Run ». +- Sélectionnez l'option « Debug... ». - Un menu contextuel s'affiche alors. - Sélectionnez le fichier à déboguer (dans ce cas, `main.py`). diff --git a/docs/fr/docs/tutorial/first-steps.md b/docs/fr/docs/tutorial/first-steps.md index 96ea56e622..b2693b3e5a 100644 --- a/docs/fr/docs/tutorial/first-steps.md +++ b/docs/fr/docs/tutorial/first-steps.md @@ -1,107 +1,122 @@ -# Démarrage +# Démarrage { #first-steps } -Le fichier **FastAPI** le plus simple possible pourrait ressembler à cela : +Le fichier **FastAPI** le plus simple possible pourrait ressembler à ceci : -{* ../../docs_src/first_steps/tutorial001.py *} +{* ../../docs_src/first_steps/tutorial001_py39.py *} -Copiez ce code dans un fichier nommé `main.py`. +Copiez cela dans un fichier `main.py`. -Démarrez le serveur : +Démarrez le serveur en direct :
```console -$ uvicorn main:app --reload +$ fastapi dev main.py -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. + 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. ```
-/// note - -La commande `uvicorn main:app` fait référence à : - -* `main` : le fichier `main.py` (le module Python). -* `app` : l'objet créé dans `main.py` via la ligne `app = FastAPI()`. -* `--reload` : l'option disant à uvicorn de redémarrer le serveur à chaque changement du code. À ne pas utiliser en production ! - -/// - -Vous devriez voir dans la console, une ligne semblable à la suivante : +Dans la sortie, il y a une ligne semblable à : ```hl_lines="4" INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) ``` -Cette ligne montre l'URL par laquelle l'app est actuellement accessible, sur votre machine locale. +Cette ligne montre l’URL où votre application est servie, sur votre machine locale. -### Allez voir le résultat +### Vérifiez { #check-it } -Ouvrez votre navigateur à l'adresse
http://127.0.0.1:8000. +Ouvrez votre navigateur à l’adresse http://127.0.0.1:8000. -Vous obtiendrez cette réponse JSON : +Vous verrez la réponse JSON suivante : ```JSON {"message": "Hello World"} ``` -### Documentation interactive de l'API +### Documentation interactive de l’API { #interactive-api-docs } -Rendez-vous sur http://127.0.0.1:8000/docs. +Allez maintenant sur http://127.0.0.1:8000/docs. -Vous verrez la documentation interactive de l'API générée automatiquement (via Swagger UI) : +Vous verrez la documentation interactive de l’API générée automatiquement (fournie par Swagger UI) : ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -### Documentation alternative +### Documentation alternative de l’API { #alternative-api-docs } -Ensuite, rendez-vous sur http://127.0.0.1:8000/redoc. +Et maintenant, allez sur http://127.0.0.1:8000/redoc. -Vous y verrez la documentation alternative (via ReDoc) : +Vous verrez la documentation automatique alternative (fournie par ReDoc) : ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -### OpenAPI +### OpenAPI { #openapi } -**FastAPI** génère un "schéma" contenant toute votre API dans le standard de définition d'API **OpenAPI**. +**FastAPI** génère un « schéma » contenant toute votre API en utilisant le standard **OpenAPI** pour définir des API. -#### "Schéma" +#### « Schéma » { #schema } -Un "schéma" est une définition ou une description de quelque chose. Pas le code qui l'implémente, uniquement une description abstraite. +Un « schéma » est une définition ou une description de quelque chose. Pas le code qui l’implémente, mais uniquement une description abstraite. -#### "Schéma" d'API +#### « Schéma » d’API { #api-schema } Ici, OpenAPI est une spécification qui dicte comment définir le schéma de votre API. -Le schéma inclut les chemins de votre API, les paramètres potentiels de chaque chemin, etc. +Cette définition de schéma inclut les chemins de votre API, les paramètres possibles qu’ils prennent, etc. -#### "Schéma" de données +#### « Schéma » de données { #data-schema } -Le terme "schéma" peut aussi faire référence à la forme de la donnée, comme un contenu JSON. +Le terme « schéma » peut également faire référence à la forme d’une donnée, comme un contenu JSON. -Dans ce cas, cela signifierait les attributs JSON, ainsi que les types de ces attributs, etc. +Dans ce cas, cela désignerait les attributs JSON, ainsi que leurs types, etc. -#### OpenAPI et JSON Schema +#### OpenAPI et JSON Schema { #openapi-and-json-schema } -**OpenAPI** définit un schéma d'API pour votre API. Il inclut des définitions (ou "schémas") de la donnée envoyée et reçue par votre API en utilisant **JSON Schema**, le standard des schémas de données JSON. +OpenAPI définit un schéma d’API pour votre API. Et ce schéma inclut des définitions (ou « schémas ») des données envoyées et reçues par votre API en utilisant **JSON Schema**, le standard pour les schémas de données JSON. -#### Allez voir `openapi.json` +#### Voir le `openapi.json` { #check-the-openapi-json } -Si vous êtes curieux d'à quoi ressemble le schéma brut **OpenAPI**, **FastAPI** génère automatiquement un (schéma) JSON avec les descriptions de toute votre API. +Si vous êtes curieux de voir à quoi ressemble le schéma OpenAPI brut, FastAPI génère automatiquement un JSON (schéma) avec les descriptions de toute votre API. -Vous pouvez le voir directement à cette adresse : http://127.0.0.1:8000/openapi.json. - -Le schéma devrait ressembler à ceci : +Vous pouvez le voir directement à l’adresse : http://127.0.0.1:8000/openapi.json. +Il affichera un JSON commençant par quelque chose comme : ```JSON { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": { "title": "FastAPI", "version": "0.1.0" @@ -120,79 +135,87 @@ Le schéma devrait ressembler à ceci : ... ``` -#### À quoi sert OpenAPI +#### À quoi sert OpenAPI { #what-is-openapi-for } -Le schéma **OpenAPI** est ce qui alimente les deux systèmes de documentation interactive. +Le schéma OpenAPI est ce qui alimente les deux systèmes de documentation interactive inclus. -Et il existe des dizaines d'alternatives, toutes basées sur **OpenAPI**. Vous pourriez facilement ajouter n'importe laquelle de ces alternatives à votre application **FastAPI**. +Et il existe des dizaines d’alternatives, toutes basées sur OpenAPI. Vous pourriez facilement ajouter n’importe laquelle de ces alternatives à votre application construite avec **FastAPI**. -Vous pourriez aussi l'utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Comme par exemple, des applications frontend, mobiles ou IOT. +Vous pourriez également l’utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Par exemple, des applications frontend, mobiles ou IoT. -## Récapitulatif, étape par étape +### Déployer votre application (optionnel) { #deploy-your-app-optional } -### Étape 1 : import `FastAPI` +Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur FastAPI Cloud, allez rejoindre la liste d’attente si ce n’est pas déjà fait. 🚀 -{* ../../docs_src/first_steps/tutorial001.py hl[1] *} +Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉), vous pouvez déployer votre application avec une seule commande. -`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires au lancement de votre API. +Avant de déployer, vous devez vous assurer que vous êtes connecté : + +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
+ +Puis déployez votre application : + +
+ +```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. ✨ + +## Récapitulatif, étape par étape { #recap-step-by-step } + +### Étape 1 : importer `FastAPI` { #step-1-import-fastapi } + +{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *} + +`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires à votre API. /// note | Détails techniques -`FastAPI` est une classe héritant directement de `Starlette`. +`FastAPI` est une classe qui hérite directement de `Starlette`. -Vous pouvez donc aussi utiliser toutes les fonctionnalités de Starlette depuis `FastAPI`. +Vous pouvez donc aussi utiliser toutes les fonctionnalités de Starlette avec `FastAPI`. /// -### Étape 2 : créer une "instance" `FastAPI` +### Étape 2 : créer une « instance » `FastAPI` { #step-2-create-a-fastapi-instance } -{* ../../docs_src/first_steps/tutorial001.py hl[3] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *} -Ici la variable `app` sera une "instance" de la classe `FastAPI`. +Ici, la variable `app` sera une « instance » de la classe `FastAPI`. -Ce sera le point principal d'interaction pour créer toute votre API. +Ce sera le point principal d’interaction pour créer toute votre API. -Cette `app` est la même que celle à laquelle fait référence `uvicorn` dans la commande : +### Étape 3 : créer un « chemin d’accès » { #step-3-create-a-path-operation } -
+#### Chemin { #path } -```console -$ uvicorn main:app --reload +« Chemin » fait ici référence à la dernière partie de l’URL à partir du premier `/`. -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -
- -Si vous créez votre app avec : - -{* ../../docs_src/first_steps/tutorial002.py hl[3] *} - -Et la mettez dans un fichier `main.py`, alors vous appelleriez `uvicorn` avec : - -
- -```console -$ uvicorn main:my_awesome_api --reload - -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -``` - -
- -### Étape 3: créer une *opération de chemin* - -#### Chemin - -Chemin, ou "path" fait référence ici à la dernière partie de l'URL démarrant au premier `/`. - -Donc, dans un URL tel que : +Donc, dans une URL telle que : ``` https://example.com/items/foo ``` -...le "path" serait : +... le chemin serait : ``` /items/foo @@ -200,66 +223,67 @@ https://example.com/items/foo /// info -Un chemin, ou "path" est aussi souvent appelé route ou "endpoint". +Un « chemin » est aussi couramment appelé « endpoint » ou « route ». /// -#### Opération +Lors de la création d’une API, le « chemin » est la manière principale de séparer les « préoccupations » et les « ressources ». -"Opération" fait référence à une des "méthodes" HTTP. +#### Opération { #operation } -Une de : +« Opération » fait ici référence à l’une des « méthodes » HTTP. + +L’une de : * `POST` * `GET` * `PUT` * `DELETE` -...ou une des plus exotiques : +... et les plus exotiques : * `OPTIONS` * `HEAD` * `PATCH` * `TRACE` -Dans le protocol HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plus) de ces "méthodes". +Dans le protocole HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plusieurs) de ces « méthodes ». --- -En construisant des APIs, vous utilisez généralement ces méthodes HTTP spécifiques pour effectuer une action précise. +En construisant des APIs, vous utilisez normalement ces méthodes HTTP spécifiques pour effectuer une action précise. -Généralement vous utilisez : +En général, vous utilisez : -* `POST` : pour créer de la donnée. -* `GET` : pour lire de la donnée. -* `PUT` : pour mettre à jour de la donnée. -* `DELETE` : pour supprimer de la donnée. +* `POST` : pour créer des données. +* `GET` : pour lire des données. +* `PUT` : pour mettre à jour des données. +* `DELETE` : pour supprimer des données. -Donc, dans **OpenAPI**, chaque méthode HTTP est appelée une "opération". +Donc, dans OpenAPI, chacune des méthodes HTTP est appelée une « opération ». -Nous allons donc aussi appeler ces dernières des "**opérations**". +Nous allons donc aussi les appeler « opérations ». +#### Définir un « décorateur de chemin d’accès » { #define-a-path-operation-decorator } -#### Définir un *décorateur d'opération de chemin* +{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *} -{* ../../docs_src/first_steps/tutorial001.py hl[6] *} - -Le `@app.get("/")` dit à **FastAPI** que la fonction en dessous est chargée de gérer les requêtes qui vont sur : +Le `@app.get("/")` indique à **FastAPI** que la fonction juste en dessous est chargée de gérer les requêtes qui vont vers : * le chemin `/` -* en utilisant une opération get +* en utilisant une get opération /// info | `@décorateur` Info -Cette syntaxe `@something` en Python est appelée un "décorateur". +Cette syntaxe `@something` en Python est appelée un « décorateur ». -Vous la mettez au dessus d'une fonction. Comme un joli chapeau décoratif (j'imagine que ce terme vient de là 🤷🏻‍♂). +Vous la mettez au-dessus d’une fonction. Comme un joli chapeau décoratif (j’imagine que c’est de là que vient le terme 🤷🏻‍♂). -Un "décorateur" prend la fonction en dessous et en fait quelque chose. +Un « décorateur » prend la fonction en dessous et fait quelque chose avec. -Dans notre cas, ce décorateur dit à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec l'**opération** `get`. +Dans notre cas, ce décorateur indique à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec une **opération** `get`. -C'est le "**décorateur d'opération de chemin**". +C’est le « décorateur de chemin d’accès ». /// @@ -269,7 +293,7 @@ Vous pouvez aussi utiliser les autres opérations : * `@app.put()` * `@app.delete()` -Tout comme celles les plus exotiques : +Ainsi que les plus exotiques : * `@app.options()` * `@app.head()` @@ -278,58 +302,79 @@ Tout comme celles les plus exotiques : /// tip | Astuce -Vous êtes libres d'utiliser chaque opération (méthode HTTP) comme vous le désirez. +Vous êtes libre d’utiliser chaque opération (méthode HTTP) comme vous le souhaitez. -**FastAPI** n'impose pas de sens spécifique à chacune d'elle. +**FastAPI** n’impose aucune signification spécifique. -Les informations qui sont présentées ici forment une directive générale, pas des obligations. +Les informations ici sont présentées comme des lignes directrices, pas comme une obligation. -Par exemple, quand l'on utilise **GraphQL**, toutes les actions sont effectuées en utilisant uniquement des opérations `POST`. +Par exemple, lorsque vous utilisez GraphQL, vous effectuez normalement toutes les actions en utilisant uniquement des opérations `POST`. /// -### Étape 4 : définir la **fonction de chemin**. +### Étape 4 : définir la **fonction de chemin d’accès** { #step-4-define-the-path-operation-function } -Voici notre "**fonction de chemin**" (ou fonction d'opération de chemin) : +Voici notre « fonction de chemin d’accès » : * **chemin** : `/`. * **opération** : `get`. -* **fonction** : la fonction sous le "décorateur" (sous `@app.get("/")`). +* **fonction** : la fonction sous le « décorateur » (sous `@app.get("/")`). -{* ../../docs_src/first_steps/tutorial001.py hl[7] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *} -C'est une fonction Python. +C’est une fonction Python. -Elle sera appelée par **FastAPI** quand une requête sur l'URL `/` sera reçue via une opération `GET`. +Elle sera appelée par **FastAPI** chaque fois qu’il recevra une requête vers l’URL « / » en utilisant une opération `GET`. -Ici, c'est une fonction asynchrone (définie avec `async def`). +Dans ce cas, c’est une fonction `async`. --- -Vous pourriez aussi la définir comme une fonction classique plutôt qu'avec `async def` : +Vous pouvez aussi la définir comme une fonction normale au lieu de `async def` : -{* ../../docs_src/first_steps/tutorial003.py hl[7] *} +{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *} /// note -Si vous ne connaissez pas la différence, allez voir la section [Concurrence : *"Vous êtes pressés ?"*](../async.md#vous-etes-presses){.internal-link target=_blank}. +Si vous ne connaissez pas la différence, consultez [Asynchrone : « Pressé ? »](../async.md#in-a-hurry){.internal-link target=_blank}. /// -### Étape 5 : retourner le contenu +### Étape 5 : retourner le contenu { #step-5-return-the-content } -{* ../../docs_src/first_steps/tutorial001.py hl[8] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *} -Vous pouvez retourner un dictionnaire (`dict`), une liste (`list`), des valeurs seules comme des chaines de caractères (`str`) et des entiers (`int`), etc. +Vous pouvez retourner un `dict`, une `list`, des valeurs uniques comme `str`, `int`, etc. -Vous pouvez aussi retourner des models **Pydantic** (qui seront détaillés plus tard). +Vous pouvez également retourner des modèles Pydantic (vous en verrez plus à ce sujet plus tard). -Il y a de nombreux autres objets et modèles qui seront automatiquement convertis en JSON. Essayez d'utiliser vos favoris, il est fort probable qu'ils soient déjà supportés. +Il existe de nombreux autres objets et modèles qui seront automatiquement convertis en JSON (y compris des ORM, etc.). Essayez d’utiliser vos favoris, il est fort probable qu’ils soient déjà pris en charge. -## Récapitulatif +### Étape 6 : le déployer { #step-6-deploy-it } + +Déployez votre application sur **FastAPI Cloud** avec une seule commande : `fastapi deploy`. 🎉 + +#### À propos de FastAPI Cloud { #about-fastapi-cloud } + +**FastAPI Cloud** est construit par le même auteur et l’équipe derrière **FastAPI**. + +Il simplifie le processus de **construction**, de **déploiement** et d’**accès** à une API avec un minimum d’effort. + +Il apporte la même **expérience développeur** de création d’applications avec FastAPI au **déploiement** dans le cloud. 🎉 + +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 chez n’importe quel fournisseur cloud de votre choix. + +Suivez les guides de votre fournisseur cloud pour y déployer des applications FastAPI. 🤓 + +## Récapitulatif { #recap } * Importez `FastAPI`. -* Créez une instance d'`app`. -* Ajoutez une **décorateur d'opération de chemin** (tel que `@app.get("/")`). -* Ajoutez une **fonction de chemin** (telle que `def root(): ...` comme ci-dessus). -* Lancez le serveur de développement (avec `uvicorn main:app --reload`). +* Créez une instance `app`. +* Écrivez un **décorateur de chemin d’accès** avec des décorateurs comme `@app.get("/")`. +* Définissez une **fonction de chemin d’accès** ; par exemple, `def root(): ...`. +* Exécutez le serveur de développement avec la commande `fastapi dev`. +* Déployez éventuellement votre application avec `fastapi deploy`. diff --git a/docs/fr/docs/tutorial/index.md b/docs/fr/docs/tutorial/index.md index 83cc5f9e88..0251b9b4b2 100644 --- a/docs/fr/docs/tutorial/index.md +++ b/docs/fr/docs/tutorial/index.md @@ -1,29 +1,53 @@ -# Tutoriel - Guide utilisateur - Introduction +# Tutoriel - Guide utilisateur { #tutorial-user-guide } Ce tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape. -Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour résoudre vos besoins spécifiques en matière d'API. +Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour répondre à vos besoins spécifiques d'API. -Il est également conçu pour fonctionner comme une référence future. +Il est également conçu pour servir de référence ultérieure, afin que vous puissiez revenir voir exactement ce dont vous avez besoin. -Vous pouvez donc revenir et voir exactement ce dont vous avez besoin. - -## Exécuter le code +## Exécuter le code { #run-the-code } Tous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés). -Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et commencez `uvicorn` avec : +Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et démarrez `fastapi dev` avec :
```console -$ uvicorn main:app --reload +$ fastapi dev main.py -INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] -INFO: Waiting for application startup. -INFO: Application startup complete. + 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. ```
@@ -34,45 +58,33 @@ L'utiliser dans votre éditeur est ce qui vous montre vraiment les avantages de --- -## Installer FastAPI +## Installer FastAPI { #install-fastapi } La première étape consiste à installer FastAPI. -Pour le tutoriel, vous voudrez peut-être l'installer avec toutes les dépendances et fonctionnalités optionnelles : +Assurez-vous de créer un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, de l'activer, puis **d'installer FastAPI** :
```console -$ pip install fastapi[all] +$ pip install "fastapi[standard]" ---> 100% ```
-... qui comprend également `uvicorn`, que vous pouvez utiliser comme serveur pour exécuter votre code. +/// note | Remarque -/// note +Lorsque vous installez avec `pip install "fastapi[standard]"` cela inclut des dépendances standard optionnelles par défaut, y compris `fastapi-cloud-cli`, qui vous permet de déployer sur FastAPI Cloud. -Vous pouvez également l'installer pièce par pièce. +Si vous ne souhaitez pas avoir ces dépendances optionnelles, vous pouvez à la place installer `pip install fastapi`. -C'est ce que vous feriez probablement une fois que vous voudrez déployer votre application en production : - -``` -pip install fastapi -``` - -Installez également `uvicorn` pour qu'il fonctionne comme serveur : - -``` -pip install uvicorn -``` - -Et la même chose pour chacune des dépendances facultatives que vous voulez utiliser. +Si vous souhaitez installer les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. /// -## Guide utilisateur avancé +## Guide d'utilisation avancé { #advanced-user-guide } Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**. diff --git a/docs/fr/docs/tutorial/path-params-numeric-validations.md b/docs/fr/docs/tutorial/path-params-numeric-validations.md index 3f3280e640..c80710777f 100644 --- a/docs/fr/docs/tutorial/path-params-numeric-validations.md +++ b/docs/fr/docs/tutorial/path-params-numeric-validations.md @@ -1,8 +1,8 @@ -# Paramètres de chemin et validations numériques +# Paramètres de chemin et validations numériques { #path-parameters-and-numeric-validations } De la même façon que vous pouvez déclarer plus de validations et de métadonnées pour les paramètres de requête avec `Query`, vous pouvez déclarer le même type de validations et de métadonnées pour les paramètres de chemin avec `Path`. -## Importer Path +## Importer `Path` { #import-path } Tout d'abord, importez `Path` de `fastapi`, et importez `Annotated` : @@ -14,11 +14,11 @@ FastAPI a ajouté le support pour `Annotated` (et a commencé à le recommander) Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d'utiliser `Annotated`. -Assurez-vous de [Mettre à jour la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 à minima avant d'utiliser `Annotated`. +Assurez-vous de [Mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 à minima avant d'utiliser `Annotated`. /// -## Déclarer des métadonnées +## Déclarer des métadonnées { #declare-metadata } Vous pouvez déclarer les mêmes paramètres que pour `Query`. @@ -26,15 +26,15 @@ Par exemple, pour déclarer une valeur de métadonnée `title` pour le paramètr {* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *} -/// note +/// note | Remarque Un paramètre de chemin est toujours requis car il doit faire partie du chemin. Même si vous l'avez déclaré avec `None` ou défini une valeur par défaut, cela ne changerait rien, il serait toujours requis. /// -## Ordonnez les paramètres comme vous le souhaitez +## Ordonner les paramètres comme vous le souhaitez { #order-the-parameters-as-you-need } -/// tip +/// tip | Astuce Ce n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`. @@ -46,7 +46,7 @@ Et vous n'avez pas besoin de déclarer autre chose pour ce paramètre, donc vous Mais vous avez toujours besoin d'utiliser `Path` pour le paramètre de chemin `item_id`. Et vous ne voulez pas utiliser `Annotated` pour une raison quelconque. -Python se plaindra si vous mettez une valeur avec une "défaut" avant une valeur qui n'a pas de "défaut". +Python se plaindra si vous mettez une valeur avec une « valeur par défaut » avant une valeur qui n'a pas de « valeur par défaut ». Mais vous pouvez les réorganiser, et avoir la valeur sans défaut (le paramètre de requête `q`) en premier. @@ -54,15 +54,15 @@ 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.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} Mais gardez à l'esprit que si vous utilisez `Annotated`, vous n'aurez pas ce problème, cela n'aura pas d'importance car vous n'utilisez pas les valeurs par défaut des paramètres de fonction pour `Query()` ou `Path()`. -{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *} -## Ordonnez les paramètres comme vous le souhaitez (astuces) +## Ordonner les paramètres comme vous le souhaitez, astuces { #order-the-parameters-as-you-need-tricks } -/// tip +/// tip | Astuce Ce n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`. @@ -77,38 +77,29 @@ Si vous voulez : * les avoir dans un ordre différent * ne pas utiliser `Annotated` -...Python a une petite syntaxe spéciale pour cela. +... Python a une petite syntaxe spéciale pour cela. Passez `*`, comme premier paramètre de la fonction. Python ne fera rien avec ce `*`, mais il saura que tous les paramètres suivants doivent être appelés comme arguments "mots-clés" (paires clé-valeur), également connus sous le nom de kwargs. Même s'ils n'ont pas de valeur par défaut. -{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} -# Avec `Annotated` +### Mieux avec `Annotated` { #better-with-annotated } Gardez à l'esprit que si vous utilisez `Annotated`, comme vous n'utilisez pas les valeurs par défaut des paramètres de fonction, vous n'aurez pas ce problème, et vous n'aurez probablement pas besoin d'utiliser `*`. {* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *} -## Validations numériques : supérieur ou égal +## Validations numériques : supérieur ou égal { #number-validations-greater-than-or-equal } Avec `Query` et `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des contraintes numériques. -Ici, avec `ge=1`, `item_id` devra être un nombre entier "`g`reater than or `e`qual" à `1`. +Ici, avec `ge=1`, `item_id` devra être un nombre entier « `g`reater than or `e`qual » à `1`. {* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *} -## Validations numériques : supérieur ou égal et inférieur ou égal - -La même chose s'applique pour : - -* `gt` : `g`reater `t`han -* `le` : `l`ess than or `e`qual - -{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *} - -## Validations numériques : supérieur et inférieur ou égal +## Validations numériques : supérieur et inférieur ou égal { #number-validations-greater-than-and-less-than-or-equal } La même chose s'applique pour : @@ -117,7 +108,7 @@ La même chose s'applique pour : {* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *} -## Validations numériques : flottants, supérieur et inférieur +## Validations numériques : flottants, supérieur et inférieur { #number-validations-floats-greater-than-and-less-than } Les validations numériques fonctionnent également pour les valeurs `float`. @@ -129,7 +120,7 @@ Et la même chose pour lt. {* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *} -## Pour résumer +## Pour résumer { #recap } Avec `Query`, `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des métadonnées et des validations de chaînes de la même manière qu'avec les [Paramètres de requête et validations de chaînes](query-params-str-validations.md){.internal-link target=_blank}. diff --git a/docs/fr/docs/tutorial/path-params.md b/docs/fr/docs/tutorial/path-params.md index 71c96b18ee..3b2955a95d 100644 --- a/docs/fr/docs/tutorial/path-params.md +++ b/docs/fr/docs/tutorial/path-params.md @@ -1,205 +1,196 @@ -# Paramètres de chemin +# Paramètres de chemin { #path-parameters } -Vous pouvez déclarer des "paramètres" ou "variables" de chemin avec la même syntaxe que celle utilisée par le -formatage de chaîne Python : +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.py hl[6:7] *} +La valeur du paramètre de chemin `item_id` sera transmise à votre fonction dans l'argument `item_id`. -La valeur du paramètre `item_id` sera transmise à la fonction dans l'argument `item_id`. - -Donc, si vous exécutez cet exemple et allez sur http://127.0.0.1:8000/items/foo, -vous verrez comme réponse : +Donc, si vous exécutez cet exemple et allez sur http://127.0.0.1:8000/items/foo, vous verrez comme réponse : ```JSON {"item_id":"foo"} ``` -## Paramètres de chemin typés +## Paramètres de chemin typés { #path-parameters-with-types } -Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python : +Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python standard : - -{* ../../docs_src/path_params/tutorial002.py hl[7] *} +{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *} Ici, `item_id` est déclaré comme `int`. -/// check | vérifier +/// check | Vérifications -Ceci vous permettra d'obtenir des fonctionnalités de l'éditeur dans votre fonction, telles -que des vérifications d'erreur, de l'auto-complétion, etc. +Cela vous apporte la prise en charge par l'éditeur dans votre fonction, avec vérifications d'erreurs, autocomplétion, etc. /// -## Conversion de données +## Conversion de données { #data-conversion } -Si vous exécutez cet exemple et allez sur http://127.0.0.1:8000/items/3, vous aurez comme réponse : +Si vous exécutez cet exemple et ouvrez votre navigateur sur http://127.0.0.1:8000/items/3, vous verrez comme réponse : ```JSON {"item_id":3} ``` -/// check | vérifier +/// check | Vérifications -Comme vous l'avez remarqué, la valeur reçue par la fonction (et renvoyée ensuite) est `3`, -en tant qu'entier (`int`) Python, pas la chaîne de caractères (`string`) `"3"`. +Remarquez que la valeur reçue par votre fonction (et renvoyée) est `3`, en tant qu'entier (`int`) Python, pas la chaîne de caractères « 3 ». -Grâce aux déclarations de types, **FastAPI** fournit du -"parsing" automatique. +Ainsi, avec cette déclaration de type, **FastAPI** vous fournit automatiquement le « parsing » de la requête. /// -## Validation de données +## Validation de données { #data-validation } -Si vous allez sur http://127.0.0.1:8000/items/foo, vous aurez une belle erreur HTTP : +Mais si vous allez dans le navigateur sur http://127.0.0.1:8000/items/foo, vous verrez une belle erreur HTTP : ```JSON { - "detail": [ - { - "loc": [ - "path", - "item_id" - ], - "msg": "value is not a valid integer", - "type": "type_error.integer" - } - ] + "detail": [ + { + "type": "int_parsing", + "loc": [ + "path", + "item_id" + ], + "msg": "Input should be a valid integer, unable to parse string as an integer", + "input": "foo" + } + ] } ``` -car le paramètre de chemin `item_id` possède comme valeur `"foo"`, qui ne peut pas être convertie en entier (`int`). +car le paramètre de chemin `item_id` a pour valeur « foo », qui n'est pas un `int`. -La même erreur se produira si vous passez un nombre flottant (`float`) et non un entier, comme ici -http://127.0.0.1:8000/items/4.2. +La même erreur apparaîtrait si vous fournissiez un `float` au lieu d'un `int`, comme ici : http://127.0.0.1:8000/items/4.2 +/// check | Vérifications -/// check | vérifier +Ainsi, avec la même déclaration de type Python, **FastAPI** vous fournit la validation de données. -Donc, avec ces mêmes déclarations de type Python, **FastAPI** vous fournit de la validation de données. +Remarquez que l'erreur indique clairement l'endroit exact où la validation n'a pas réussi. -Notez que l'erreur mentionne le point exact où la validation n'a pas réussi. - -Ce qui est incroyablement utile au moment de développer et débugger du code qui interagit avec votre API. +C'est incroyablement utile lors du développement et du débogage du code qui interagit avec votre API. /// -## Documentation +## Documentation { #documentation } -Et quand vous vous rendez sur http://127.0.0.1:8000/docs, vous verrez la -documentation générée automatiquement et interactive : +Et lorsque vous ouvrez votre navigateur sur http://127.0.0.1:8000/docs, vous verrez une documentation d'API automatique et interactive comme : -/// info +/// check | Vérifications -À nouveau, en utilisant uniquement les déclarations de type Python, **FastAPI** vous fournit automatiquement une documentation interactive (via Swagger UI). +À nouveau, simplement avec cette même déclaration de type Python, **FastAPI** vous fournit une documentation interactive automatique (intégrant Swagger UI). -On voit bien dans la documentation que `item_id` est déclaré comme entier. +Remarquez que le paramètre de chemin est déclaré comme entier. /// -## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative. +## Les avantages d'une norme, documentation alternative { #standards-based-benefits-alternative-documentation } -Le schéma généré suivant la norme OpenAPI, -il existe de nombreux outils compatibles. +Et comme le schéma généré suit la norme OpenAPI, il existe de nombreux outils compatibles. -Grâce à cela, **FastAPI** lui-même fournit une documentation alternative (utilisant ReDoc), qui peut être lue -sur http://127.0.0.1:8000/redoc : +Grâce à cela, **FastAPI** fournit lui-même une documentation d'API alternative (utilisant ReDoc), accessible sur http://127.0.0.1:8000/redoc : -De la même façon, il existe bien d'autres outils compatibles, y compris des outils de génération de code -pour de nombreux langages. +De la même façon, il existe de nombreux outils compatibles, y compris des outils de génération de code pour de nombreux langages. -## Pydantic +## Pydantic { #pydantic } -Toute la validation de données est effectué en arrière-plan avec Pydantic, -dont vous bénéficierez de tous les avantages. Vous savez donc que vous êtes entre de bonnes mains. +Toute la validation de données est effectuée sous le capot par Pydantic, vous en bénéficiez donc pleinement. Vous savez ainsi que vous êtes entre de bonnes mains. -## L'ordre importe +Vous pouvez utiliser les mêmes déclarations de type avec `str`, `float`, `bool` et de nombreux autres types de données complexes. -Quand vous créez des *fonctions de chemins*, vous pouvez vous retrouver dans une situation où vous avez un chemin fixe. +Plusieurs d'entre eux sont explorés dans les prochains chapitres du tutoriel. -Tel que `/users/me`, disons pour récupérer les données sur l'utilisateur actuel. +## L'ordre importe { #order-matters } -Et vous avez un second chemin : `/users/{user_id}` pour récupérer de la donnée sur un utilisateur spécifique grâce à son identifiant d'utilisateur +Quand vous créez des *chemins d'accès*, vous pouvez vous retrouver dans une situation avec un chemin fixe. -Les *fonctions de chemin* étant évaluées dans l'ordre, il faut s'assurer que la fonction correspondant à `/users/me` est déclarée avant celle de `/users/{user_id}` : +Par exemple `/users/me`, disons pour récupérer les données de l'utilisateur actuel. -{* ../../docs_src/path_params/tutorial003.py hl[6,11] *} +Et vous pouvez aussi avoir un chemin `/users/{user_id}` pour récupérer des données sur un utilisateur spécifique grâce à un identifiant d'utilisateur. -Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, la fonction "croyant" qu'elle a reçu un paramètre `user_id` avec pour valeur `"me"`. +Comme les *chemins d'accès* sont évalués dans l'ordre, vous devez vous assurer que le chemin `/users/me` est déclaré avant celui de `/users/{user_id}` : -## Valeurs prédéfinies +{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *} -Si vous avez une *fonction de chemin* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles des paramètres soient prédéfinies, vous pouvez utiliser les `Enum` de Python. +Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, « pensant » qu'il reçoit un paramètre `user_id` avec la valeur « me ». -### Création d'un `Enum` +De même, vous ne pouvez pas redéfinir un chemin d'accès : -Importez `Enum` et créez une sous-classe qui hérite de `str` et `Enum`. +{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *} -En héritant de `str` la documentation sera capable de savoir que les valeurs doivent être de type `string` et pourra donc afficher cette `Enum` correctement. +Le premier sera toujours utilisé puisque le chemin correspond en premier. -Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs autorisées pour cette énumération. +## Valeurs prédéfinies { #predefined-values } -{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *} +Si vous avez un *chemin d'accès* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles de ce *paramètre de chemin* soient prédéfinies, vous pouvez utiliser une `Enum` Python standard. -/// info +### Créer une classe `Enum` { #create-an-enum-class } -Les énumérations (ou enums) sont disponibles en Python depuis la version 3.4. +Importez `Enum` et créez une sous-classe qui hérite de `str` et de `Enum`. -/// +En héritant de `str`, la documentation de l'API saura que les valeurs doivent être de type `string` et pourra donc s'afficher correctement. + +Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs valides disponibles : + +{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *} /// tip | Astuce -Pour ceux qui se demandent, "AlexNet", "ResNet", et "LeNet" sont juste des noms de modèles de Machine Learning. +Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des noms de modèles de Machine Learning. /// -### Déclarer un paramètre de chemin +### Déclarer un paramètre de chemin { #declare-a-path-parameter } -Créez ensuite un *paramètre de chemin* avec une annotation de type désignant l'énumération créée précédemment (`ModelName`) : +Créez ensuite un *paramètre de chemin* avec une annotation de type utilisant la classe d'énumération que vous avez créée (`ModelName`) : -{* ../../docs_src/path_params/tutorial005.py hl[16] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *} -### Documentation +### Consulter la documentation { #check-the-docs } -Les valeurs disponibles pour le *paramètre de chemin* sont bien prédéfinies, la documentation les affiche correctement : +Comme les valeurs disponibles pour le *paramètre de chemin* sont prédéfinies, la documentation interactive peut les afficher clairement : -### Manipuler les *énumérations* Python +### Travailler avec les *énumérations* Python { #working-with-python-enumerations } -La valeur du *paramètre de chemin* sera un des "membres" de l'énumération. +La valeur du *paramètre de chemin* sera un *membre d'énumération*. -#### Comparer les *membres d'énumération* +#### Comparer des *membres d'énumération* { #compare-enumeration-members } -Vous pouvez comparer ce paramètre avec les membres de votre énumération `ModelName` : +Vous pouvez le comparer avec le *membre d'énumération* dans votre enum `ModelName` : -{* ../../docs_src/path_params/tutorial005.py hl[17] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *} -#### Récupérer la *valeur de l'énumération* +#### Obtenir la *valeur de l'énumération* { #get-the-enumeration-value } -Vous pouvez obtenir la valeur réel d'un membre (une chaîne de caractères ici), avec `model_name.value`, ou en général, `votre_membre_d'enum.value` : +Vous pouvez obtenir la valeur réelle (une `str` dans ce cas) avec `model_name.value`, ou en général, `votre_membre_d_enum.value` : -{* ../../docs_src/path_params/tutorial005.py hl[20] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *} /// tip | Astuce -Vous pouvez aussi accéder la valeur `"lenet"` avec `ModelName.lenet.value`. +Vous pouvez aussi accéder à la valeur « lenet » avec `ModelName.lenet.value`. /// -#### Retourner des *membres d'énumération* +#### Retourner des *membres d'énumération* { #return-enumeration-members } -Vous pouvez retourner des *membres d'énumération* dans vos *fonctions de chemin*, même imbriquée dans un JSON (e.g. un `dict`). +Vous pouvez retourner des *membres d'énumération* depuis votre *chemin d'accès*, même imbriqués dans un corps JSON (par ex. un `dict`). -Ils seront convertis vers leurs valeurs correspondantes (chaînes de caractères ici) avant d'être transmis au client : +Ils seront convertis vers leurs valeurs correspondantes (des chaînes de caractères ici) avant d'être renvoyés au client : -{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *} -Le client recevra une réponse JSON comme celle-ci : +Dans votre client, vous recevrez une réponse JSON comme : ```JSON { @@ -208,53 +199,53 @@ Le client recevra une réponse JSON comme celle-ci : } ``` -## Paramètres de chemin contenant des chemins +## Paramètres de chemin contenant des chemins { #path-parameters-containing-paths } -Disons que vous avez une *fonction de chemin* liée au chemin `/files/{file_path}`. +Disons que vous avez un *chemin d'accès* avec un chemin `/files/{file_path}`. -Mais que `file_path` lui-même doit contenir un *chemin*, comme `home/johndoe/myfile.txt` par exemple. +Mais vous avez besoin que `file_path` lui-même contienne un *chemin*, comme `home/johndoe/myfile.txt`. -Donc, l'URL pour ce fichier pourrait être : `/files/home/johndoe/myfile.txt`. +Ainsi, l'URL pour ce fichier serait : `/files/home/johndoe/myfile.txt`. -### Support d'OpenAPI +### Support d'OpenAPI { #openapi-support } -OpenAPI ne supporte pas de manière de déclarer un paramètre de chemin contenant un *chemin*, cela pouvant causer des scénarios difficiles à tester et définir. +OpenAPI ne prend pas en charge une manière de déclarer un *paramètre de chemin* contenant un *chemin* à l'intérieur, car cela peut conduire à des scénarios difficiles à tester et à définir. -Néanmoins, cela reste faisable dans **FastAPI**, via les outils internes de Starlette. +Néanmoins, vous pouvez toujours le faire dans **FastAPI**, en utilisant l'un des outils internes de Starlette. -Et la documentation fonctionne quand même, bien qu'aucune section ne soit ajoutée pour dire que la paramètre devrait contenir un *chemin*. +Et la documentation fonctionnera quand même, même si aucune indication supplémentaire ne sera ajoutée pour dire que le paramètre doit contenir un chemin. -### Convertisseur de *chemin* +### Convertisseur de chemin { #path-convertor } -En utilisant une option de Starlette directement, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme : +En utilisant une option directement depuis Starlette, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme : ``` /files/{file_path:path} ``` -Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique à Starlette que le paramètre devrait correspondre à un *chemin*. +Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique que le paramètre doit correspondre à n'importe quel *chemin*. -Vous pouvez donc l'utilisez comme tel : +Vous pouvez donc l'utiliser ainsi : -{* ../../docs_src/path_params/tutorial004.py hl[6] *} +{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *} /// tip | Astuce -Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash au début (`/`). +Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash initial (`/`). Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double slash (`//`) entre `files` et `home`. /// -## Récapitulatif +## Récapitulatif { #recap } -Avec **FastAPI**, en utilisant les déclarations de type rapides, intuitives et standards de Python, vous bénéficiez de : +Avec **FastAPI**, en utilisant des déclarations de type Python courtes, intuitives et standard, vous obtenez : -* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc. -* "Parsing" de données. -* Validation de données. -* Annotations d'API et documentation automatique. +* Support de l'éditeur : vérifications d'erreurs, autocomplétion, etc. +* Données « parsing » +* Validation de données +* Annotations d'API et documentation automatique -Et vous n'avez besoin de le déclarer qu'une fois. +Et vous n'avez besoin de les déclarer qu'une seule fois. -C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres *frameworks* (outre les performances pures). +C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres frameworks (outre les performances pures). diff --git a/docs/fr/docs/tutorial/query-params-str-validations.md b/docs/fr/docs/tutorial/query-params-str-validations.md index c54c0c7171..544d10328e 100644 --- a/docs/fr/docs/tutorial/query-params-str-validations.md +++ b/docs/fr/docs/tutorial/query-params-str-validations.md @@ -1,166 +1,273 @@ -# Paramètres de requête et validations de chaînes de caractères +# Paramètres de requête et validations de chaînes de caractères { #query-parameters-and-string-validations } -**FastAPI** vous permet de déclarer des informations et des validateurs additionnels pour vos paramètres de requêtes. +**FastAPI** vous permet de déclarer des informations et des validations supplémentaires pour vos paramètres. -Commençons avec cette application pour exemple : +Prenons cette application comme exemple : -{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *} -Le paramètre de requête `q` a pour type `Union[str, None]` (ou `str | None` en Python 3.10), signifiant qu'il est de type `str` mais pourrait aussi être égal à `None`, et bien sûr, la valeur par défaut est `None`, donc **FastAPI** saura qu'il n'est pas requis. +Le paramètre de requête `q` est de type `str | None`, cela signifie qu’il est de type `str` mais peut aussi être `None`, et en effet, la valeur par défaut est `None`, donc FastAPI saura qu’il n’est pas requis. -/// note +/// note | Remarque -**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`. +FastAPI saura que la valeur de `q` n’est pas requise grâce à la valeur par défaut `= None`. -Le `Union` dans `Union[str, None]` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs. +Avoir `str | None` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs. /// -## Validation additionnelle +## Validation additionnelle { #additional-validation } -Nous allons imposer que bien que `q` soit un paramètre optionnel, dès qu'il est fourni, **sa longueur n'excède pas 50 caractères**. +Nous allons imposer que, même si `q` est optionnel, dès qu’il est fourni, **sa longueur n’excède pas 50 caractères**. -## Importer `Query` +### Importer `Query` et `Annotated` { #import-query-and-annotated } -Pour cela, importez d'abord `Query` depuis `fastapi` : +Pour ce faire, importez d’abord : -{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *} +- `Query` depuis `fastapi` +- `Annotated` depuis `typing` -## Utiliser `Query` comme valeur par défaut +{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *} -Construisez ensuite la valeur par défaut de votre paramètre avec `Query`, en choisissant 50 comme `max_length` : +/// info -{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *} +FastAPI a ajouté la prise en charge de `Annotated` (et a commencé à le recommander) dans la version 0.95.0. -Comme nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous pouvons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, il sert le même objectif qui est de définir cette valeur par défaut. +Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d’utiliser `Annotated`. -Donc : +Assurez-vous de [mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} vers au moins 0.95.1 avant d’utiliser `Annotated`. + +/// + +## Utiliser `Annotated` dans le type pour le paramètre `q` { #use-annotated-in-the-type-for-the-q-parameter } + +Vous vous souvenez que je vous ai dit plus tôt que `Annotated` peut être utilisé pour ajouter des métadonnées à vos paramètres dans l’[Introduction aux types Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} ? + +C’est le moment de l’utiliser avec FastAPI. 🚀 + +Nous avions cette annotation de type : + +//// tab | Python 3.10+ ```Python -q: Union[str, None] = Query(default=None) +q: str | None = None ``` -... rend le paramètre optionnel, et est donc équivalent à : +//// + +//// tab | Python 3.9+ ```Python q: Union[str, None] = None ``` -Mais déclare explicitement `q` comme étant un paramètre de requête. +//// -/// info +Ce que nous allons faire, c’est l’englober avec `Annotated`, de sorte que cela devienne : -Gardez à l'esprit que la partie la plus importante pour rendre un paramètre optionnel est : +//// tab | Python 3.10+ ```Python -= None +q: Annotated[str | None] = None ``` -ou : +//// + +//// tab | Python 3.9+ ```Python -= Query(None) +q: Annotated[Union[str, None]] = None ``` -et utilisera ce `None` pour détecter que ce paramètre de requête **n'est pas requis**. +//// -Le `Union[str, None]` est uniquement là pour permettre à votre éditeur un meilleur support. +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. 🎉 + +## Ajouter `Query` à `Annotated` dans le paramètre `q` { #add-query-to-annotated-in-the-q-parameter } + +Maintenant que nous avons cet `Annotated` dans lequel nous pouvons mettre plus d’informations (dans ce cas une validation supplémentaire), ajoutez `Query` à l’intérieur de `Annotated`, et définissez le paramètre `max_length` à `50` : + +{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *} + +Remarquez que la valeur par défaut est toujours `None`, donc le paramètre est toujours optionnel. + +Mais maintenant, avec `Query(max_length=50)` à l’intérieur de `Annotated`, nous indiquons à FastAPI que nous voulons **une validation supplémentaire** pour cette valeur, nous voulons qu’elle ait au maximum 50 caractères. 😎 + +/// tip | Astuce + +Ici nous utilisons `Query()` parce qu’il s’agit d’un **paramètre de requête**. Plus tard nous verrons d’autres comme `Path()`, `Body()`, `Header()` et `Cookie()`, qui acceptent également les mêmes arguments que `Query()`. /// -Ensuite, nous pouvons passer d'autres paramètres à `Query`. Dans cet exemple, le paramètre `max_length` qui s'applique aux chaînes de caractères : +FastAPI va maintenant : -```Python -q: Union[str, None] = Query(default=None, max_length=50) -``` +- **Valider** les données en s’assurant que la longueur maximale est de 50 caractères +- Afficher une **erreur claire** au client quand les données ne sont pas valides +- **Documenter** le paramètre dans la *chemin d'accès* du schéma OpenAPI (il apparaîtra donc dans l’**interface de documentation automatique**) -Cela va valider les données, montrer une erreur claire si ces dernières ne sont pas valides, et documenter le paramètre dans le schéma `OpenAPI` de cette *path operation*. +## Alternative (ancienne) : `Query` comme valeur par défaut { #alternative-old-query-as-the-default-value } -## Rajouter plus de validation +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. -Vous pouvez aussi rajouter un second paramètre `min_length` : +/// tip | Astuce -{* ../../docs_src/query_params_str_validations/tutorial003.py hl[9] *} - -## Ajouter des validations par expressions régulières - -On peut définir une expression régulière à laquelle le paramètre doit correspondre : - -{* ../../docs_src/query_params_str_validations/tutorial004.py hl[10] *} - -Cette expression régulière vérifie que la valeur passée comme paramètre : - -* `^` : commence avec les caractères qui suivent, avec aucun caractère avant ceux-là. -* `fixedquery` : a pour valeur exacte `fixedquery`. -* `$` : se termine directement ensuite, n'a pas d'autres caractères après `fixedquery`. - -Si vous vous sentez perdu avec le concept d'**expression régulière**, pas d'inquiétudes. Il s'agit d'une notion difficile pour beaucoup, et l'on peut déjà réussir à faire beaucoup sans jamais avoir à les manipuler. - -Mais si vous décidez d'apprendre à les utiliser, sachez qu'ensuite vous pouvez les utiliser directement dans **FastAPI**. - -## Valeurs par défaut - -De la même façon que vous pouvez passer `None` comme premier argument pour l'utiliser comme valeur par défaut, vous pouvez passer d'autres valeurs. - -Disons que vous déclarez le paramètre `q` comme ayant une longueur minimale de `3`, et une valeur par défaut étant `"fixedquery"` : - -{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *} - -/// note | Rappel - -Avoir une valeur par défaut rend le paramètre optionnel. +Pour du nouveau code et dès que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a de multiples avantages (expliqués ci-dessous) et aucun inconvénient. 🍰 /// -## Rendre ce paramètre requis +Voici comment vous utiliseriez `Query()` comme valeur par défaut du paramètre de votre fonction, en définissant le paramètre `max_length` à 50 : -Quand on ne déclare ni validation, ni métadonnée, on peut rendre le paramètre `q` requis en ne lui déclarant juste aucune valeur par défaut : +{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *} + +Comme, dans ce cas (sans utiliser `Annotated`), nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous devons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, cela sert le même objectif de définir cette valeur par défaut (au moins pour FastAPI). + +Donc : + +```Python +q: str | None = Query(default=None) +``` + +... rend le paramètre optionnel, avec une valeur par défaut de `None`, comme : + +```Python +q: str | None = None +``` + +Mais la version avec `Query` le déclare explicitement comme étant un paramètre de requête. + +Ensuite, nous pouvons passer plus de paramètres à `Query`. Dans ce cas, le paramètre `max_length` qui s’applique aux chaînes de caractères : + +```Python +q: str | None = Query(default=None, max_length=50) +``` + +Cela validera les données, affichera une erreur claire lorsque les données ne sont pas valides et documentera le paramètre dans la *chemin d'accès* du schéma OpenAPI. + +### `Query` comme valeur par défaut ou dans `Annotated` { #query-as-the-default-value-or-in-annotated } + +Gardez à l’esprit qu’en utilisant `Query` à l’intérieur de `Annotated`, vous ne pouvez pas utiliser le paramètre `default` de `Query`. + +Utilisez à la place la valeur par défaut réelle du paramètre de fonction. Sinon, ce serait incohérent. + +Par exemple, ceci n’est pas autorisé : + +```Python +q: Annotated[str, Query(default="rick")] = "morty" +``` + +... parce qu’il n’est pas clair si la valeur par défaut doit être « rick » ou « morty ». + +Donc, vous utiliseriez (de préférence) : + +```Python +q: Annotated[str, Query()] = "rick" +``` + +... ou dans des bases de code plus anciennes, vous trouverez : + +```Python +q: str = Query(default="rick") +``` + +### Avantages de `Annotated` { #advantages-of-annotated } + +**L’utilisation de `Annotated` est recommandée** plutôt que la valeur par défaut dans les paramètres de fonction, c’est **mieux** pour plusieurs raisons. 🤓 + +La valeur **par défaut** du **paramètre de fonction** est la **vraie valeur par défaut**, c’est plus intuitif en Python en général. 😌 + +Vous pouvez **appeler** cette même fonction dans **d’autres endroits** sans FastAPI, et elle **fonctionnera comme prévu**. S’il y a un paramètre **requis** (sans valeur par défaut), votre **éditeur** vous le signalera avec une erreur, **Python** se plaindra aussi si vous l’exécutez sans passer le paramètre requis. + +Quand vous n’utilisez pas `Annotated` et utilisez à la place l’**ancienne** méthode avec la **valeur par défaut**, si vous appelez cette fonction sans FastAPI dans **d’autres endroits**, vous devez **penser** à passer les arguments à la fonction pour qu’elle fonctionne correctement, sinon les valeurs seront différentes de ce que vous attendez (par ex. `QueryInfo` ou quelque chose de similaire au lieu d’une `str`). Et votre éditeur ne se plaindra pas, et Python ne se plaindra pas en exécutant cette fonction, seulement quand les opérations internes échoueront. + +Comme `Annotated` peut avoir plus d’une annotation de métadonnées, vous pouvez maintenant même utiliser la même fonction avec d’autres outils, comme Typer. 🚀 + +## Ajouter plus de validations { #add-more-validations } + +Vous pouvez également ajouter un paramètre `min_length` : + +{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *} + +## Ajouter des expressions régulières { #add-regular-expressions } + +Vous pouvez définir un `pattern` d’expression régulière auquel le paramètre doit correspondre : + +{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *} + +Ce pattern d’expression régulière spécifique vérifie que la valeur reçue pour le paramètre : + +- `^` : commence avec les caractères qui suivent, n’a pas de caractères avant. +- `fixedquery` : a exactement la valeur `fixedquery`. +- `$` : se termine là, n’a pas d’autres caractères après `fixedquery`. + +Si vous vous sentez perdu avec toutes ces idées d’**« expression régulière »**, pas d’inquiétude. C’est un sujet difficile pour beaucoup. Vous pouvez déjà faire beaucoup de choses sans avoir besoin d’expressions régulières. + +Désormais, vous savez que, lorsque vous en aurez besoin, vous pourrez les utiliser dans **FastAPI**. + +## Valeurs par défaut { #default-values } + +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] *} + +/// note | Remarque + +Avoir une valeur par défaut de n’importe quel type, y compris `None`, rend le paramètre optionnel (non requis). + +/// + +## Paramètres requis { #required-parameters } + +Quand nous n’avons pas besoin de déclarer plus de validations ou de métadonnées, nous pouvons rendre le paramètre de requête `q` requis en n’indiquant simplement pas de valeur par défaut, comme : ```Python q: str ``` -à la place de : +au lieu de : ```Python -q: Union[str, None] = None +q: str | None = None ``` -Mais maintenant, on déclare `q` avec `Query`, comme ceci : +Mais maintenant nous le déclarons avec `Query`, par exemple ainsi : ```Python -q: Union[str, None] = Query(default=None, min_length=3) +q: Annotated[str | None, Query(min_length=3)] = None ``` -Donc pour déclarer une valeur comme requise tout en utilisant `Query`, il faut utiliser `...` comme premier argument : +Donc, lorsque vous 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.py hl[7] *} +{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *} -/// info +### Requis, peut valoir `None` { #required-can-be-none } -Si vous n'avez jamais vu ce `...` auparavant : c'est une des constantes natives de Python appelée "Ellipsis". +Vous pouvez déclarer qu’un paramètre accepte `None`, mais qu’il est tout de même requis. Cela obligerait les clients à envoyer une valeur, même si la valeur est `None`. -/// +Pour ce faire, vous pouvez déclarer que `None` est un type valide tout en ne déclarant pas de valeur par défaut : -Cela indiquera à **FastAPI** que la présence de ce paramètre est obligatoire. +{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *} -## Liste de paramètres / valeurs multiples via Query +## Liste de paramètres de requête / valeurs multiples { #query-parameter-list-multiple-values } -Quand on définit un paramètre de requête explicitement avec `Query` on peut aussi déclarer qu'il reçoit une liste de valeur, ou des "valeurs multiples". +Quand vous définissez un paramètre de requête explicitement avec `Query`, vous pouvez aussi déclarer qu’il reçoit une liste de valeurs, autrement dit, qu’il reçoit des valeurs multiples. -Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans une URL, on écrit : +Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans l’URL, vous pouvez écrire : -{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *} -Ce qui fait qu'avec une URL comme : +Ensuite, avec une URL comme : ``` http://localhost:8000/items/?q=foo&q=bar ``` -vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python au sein de votre fonction de **path operation**, dans le paramètre de fonction `q`. +vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python à l’intérieur de votre fonction de *chemin d'accès*, dans le *paramètre de fonction* `q`. -Donc la réponse de cette URL serait : +Donc, la réponse pour cette URL serait : ```JSON { @@ -173,19 +280,19 @@ Donc la réponse de cette URL serait : /// tip | Astuce -Pour déclarer un paramètre de requête de type `list`, comme dans l'exemple ci-dessus, il faut explicitement utiliser `Query`, sinon cela sera interprété comme faisant partie du corps de la requête. +Pour déclarer un paramètre de requête avec un type `list`, comme dans l’exemple ci-dessus, vous devez explicitement utiliser `Query`, sinon il serait interprété comme faisant partie du corps de la requête. /// -La documentation sera donc mise à jour automatiquement pour autoriser plusieurs valeurs : +L’interface de documentation interactive de l’API sera mise à jour en conséquence, pour autoriser plusieurs valeurs : -### Combiner liste de paramètres et valeurs par défaut +### Liste de paramètres de requête / valeurs multiples avec valeurs par défaut { #query-parameter-list-multiple-values-with-defaults } -Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie : +Vous pouvez également définir une `list` de valeurs par défaut si aucune n’est fournie : -{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *} Si vous allez à : @@ -193,9 +300,7 @@ Si vous allez à : http://localhost:8000/items/ ``` -la valeur par défaut de `q` sera : `["foo", "bar"]` - -et la réponse sera : +la valeur par défaut de `q` sera : `["foo", "bar"]` et votre réponse sera : ```JSON { @@ -206,93 +311,163 @@ et la réponse sera : } ``` -#### Utiliser `list` +#### Utiliser simplement `list` { #using-just-list } -Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` : +Vous pouvez aussi utiliser `list` directement au lieu de `list[str]` : -{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *} +{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *} -/// note +/// note | Remarque -Dans ce cas-là, **FastAPI** ne vérifiera pas le contenu de la liste. +Gardez à l’esprit que dans ce cas, FastAPI ne vérifiera pas le contenu de la liste. -Par exemple, `List[int]` vérifiera (et documentera) que la liste est bien entièrement composée d'entiers. Alors qu'un simple `list` ne ferait pas cette vérification. +Par exemple, `list[int]` vérifierait (et documenterait) que le contenu de la liste est composé d’entiers. Mais un simple `list` ne le ferait pas. /// -## Déclarer des métadonnées supplémentaires +## Déclarer plus de métadonnées { #declare-more-metadata } -On peut aussi ajouter plus d'informations sur le paramètre. +Vous pouvez ajouter plus d’informations à propos du paramètre. -Ces informations seront incluses dans le schéma `OpenAPI` généré et utilisées par la documentation interactive ou les outils externes utilisés. +Ces informations seront incluses dans l’OpenAPI généré et utilisées par les interfaces de documentation et les outils externes. -/// note +/// note | Remarque -Gardez en tête que les outils externes utilisés ne supportent pas forcément tous parfaitement OpenAPI. +Gardez à l’esprit que différents outils peuvent avoir des niveaux de prise en charge d’OpenAPI différents. -Il se peut donc que certains d'entre eux n'utilisent pas toutes les métadonnées que vous avez déclarées pour le moment, bien que dans la plupart des cas, les fonctionnalités manquantes ont prévu d'être implémentées. +Certains d’entre eux pourraient ne pas encore afficher toutes les informations supplémentaires déclarées, bien que, dans la plupart des cas, la fonctionnalité manquante soit déjà prévue au développement. /// Vous pouvez ajouter un `title` : -{* ../../docs_src/query_params_str_validations/tutorial007.py hl[10] *} +{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *} Et une `description` : -{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *} +{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *} -## Alias de paramètres +## Paramètres avec alias { #alias-parameters } -Imaginez que vous vouliez que votre paramètre se nomme `item-query`. +Imaginez que vous vouliez que le paramètre soit `item-query`. -Comme dans la requête : +Comme dans : ``` http://127.0.0.1:8000/items/?item-query=foobaritems ``` -Mais `item-query` n'est pas un nom de variable valide en Python. +Mais `item-query` n’est pas un nom de variable Python valide. -Le nom le plus proche serait `item_query`. +Le plus proche serait `item_query`. -Mais vous avez vraiment envie que ce soit exactement `item-query`... +Mais vous avez quand même besoin que ce soit exactement `item-query` ... -Pour cela vous pouvez déclarer un `alias`, et cet alias est ce qui sera utilisé pour trouver la valeur du paramètre : +Vous pouvez alors déclarer un `alias`, et cet alias sera utilisé pour trouver la valeur du paramètre : -{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *} +{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *} -## Déprécier des paramètres +## Déprécier des paramètres { #deprecating-parameters } -Disons que vous ne vouliez plus utiliser ce paramètre désormais. +Disons que vous n’aimez plus ce paramètre. -Il faut qu'il continue à exister pendant un certain temps car vos clients l'utilisent, mais vous voulez que la documentation mentionne clairement que ce paramètre est 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é. -On utilise alors l'argument `deprecated=True` de `Query` : +Passez alors le paramètre `deprecated=True` à `Query` : -{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *} +{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *} -La documentation le présentera comme il suit : +Les documents l’afficheront ainsi : -## Pour résumer +## Exclure des paramètres d’OpenAPI { #exclude-parameters-from-openapi } -Il est possible d'ajouter des validateurs et métadonnées pour vos paramètres. +Pour exclure un paramètre de requête du schéma OpenAPI généré (et donc, des systèmes de documentation automatiques), définissez le paramètre `include_in_schema` de `Query` à `False` : -Validateurs et métadonnées génériques: +{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *} -* `alias` -* `title` -* `description` -* `deprecated` +## Validation personnalisée { #custom-validation } -Validateurs spécifiques aux chaînes de caractères : +Il peut y avoir des cas où vous devez faire une **validation personnalisée** qui ne peut pas être réalisée avec les paramètres montrés ci-dessus. -* `min_length` -* `max_length` -* `regex` +Dans ces cas, vous pouvez utiliser une **fonction de validation personnalisée** qui est appliquée après la validation normale (par ex. après avoir validé que la valeur est une `str`). -Parmi ces exemples, vous avez pu voir comment déclarer des validateurs pour les chaînes de caractères. +Vous pouvez y parvenir en utilisant `AfterValidator` de Pydantic à l’intérieur de `Annotated`. -Dans les prochains chapitres, vous verrez comment déclarer des validateurs pour d'autres types, comme les nombres. +/// tip | Astuce + +Pydantic a aussi `BeforeValidator` et d’autres. 🤓 + +/// + +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] *} + +/// info + +C’est disponible avec Pydantic version 2 ou supérieure. 😎 + +/// + +/// tip | Astuce + +Si vous devez faire un type de validation qui nécessite de communiquer avec un **composant externe**, comme une base de données ou une autre API, vous devez plutôt utiliser les **Dépendances de FastAPI**, vous en apprendrez davantage plus tard. + +Ces validateurs personnalisés sont destinés aux éléments qui peuvent être vérifiés **uniquement** avec les **mêmes données** fournies dans la requête. + +/// + +### Comprendre ce code { #understand-that-code } + +Le point important est simplement d’utiliser **`AfterValidator` avec une fonction à l’intérieur de `Annotated`**. N’hésitez pas à passer cette partie. 🤸 + +--- + +Mais si vous êtes curieux de cet exemple de code spécifique et que vous êtes toujours partant, voici quelques détails supplémentaires. + +#### Chaîne avec `value.startswith()` { #string-with-value-startswith } + +Avez-vous remarqué ? Une chaîne utilisant `value.startswith()` peut prendre un tuple, et elle vérifiera chaque valeur du tuple : + +{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *} + +#### 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. + +Nous convertissons cet objet itérable en une `list` propre avec `list(data.items())`. + +Ensuite, avec `random.choice()` nous pouvons obtenir une **valeur aléatoire** depuis la liste, nous obtenons donc un tuple `(id, name)`. Ce sera quelque chose comme `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`. + +Puis nous **affectons ces deux valeurs** du tuple aux variables `id` et `name`. + +Ainsi, si l’utilisateur n’a pas fourni d’ID d’item, il recevra quand même une suggestion aléatoire. + +... nous faisons tout cela en **une seule ligne simple**. 🤯 Vous n’adorez pas Python ? 🐍 + +{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *} + +## Récapitulatif { #recap } + +Vous pouvez déclarer des validations et des métadonnées supplémentaires pour vos paramètres. + +Validations et métadonnées génériques : + +- `alias` +- `title` +- `description` +- `deprecated` + +Validations spécifiques aux chaînes : + +- `min_length` +- `max_length` +- `pattern` + +Validations personnalisées avec `AfterValidator`. + +Dans ces exemples, vous avez vu comment déclarer des validations pour des valeurs `str`. + +Voyez les prochains chapitres pour apprendre à déclarer des validations pour d’autres types, comme les nombres. diff --git a/docs/fr/docs/tutorial/query-params.md b/docs/fr/docs/tutorial/query-params.md index b87c26c782..1a4880ced3 100644 --- a/docs/fr/docs/tutorial/query-params.md +++ b/docs/fr/docs/tutorial/query-params.md @@ -1,10 +1,10 @@ -# Paramètres de requête +# Paramètres de requête { #query-parameters } -Quand vous déclarez des paramètres dans votre fonction de chemin qui ne font pas partie des paramètres indiqués dans le chemin associé, ces paramètres sont automatiquement considérés comme des paramètres de "requête". +Quand vous déclarez d'autres paramètres de fonction qui ne font pas partie des paramètres de chemin, ils sont automatiquement interprétés comme des paramètres de « query ». -{* ../../docs_src/query_params/tutorial001.py hl[9] *} +{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *} -La partie appelée requête (ou **query**) dans une URL est l'ensemble des paires clés-valeurs placées après le `?` , séparées par des `&`. +La query est l'ensemble des paires clé-valeur placées après le `?` dans une URL, séparées par des caractères `&`. Par exemple, dans l'URL : @@ -12,27 +12,27 @@ Par exemple, dans l'URL : http://127.0.0.1:8000/items/?skip=0&limit=10 ``` -...les paramètres de requête sont : +... les paramètres de requête sont : -* `skip` : avec une valeur de`0` +* `skip` : avec une valeur de `0` * `limit` : avec une valeur de `10` -Faisant partie de l'URL, ces valeurs sont des chaînes de caractères (`str`). +Comme ils font partie de l'URL, ce sont « naturellement » des chaînes de caractères. -Mais quand on les déclare avec des types Python (dans l'exemple précédent, en tant qu'`int`), elles sont converties dans les types renseignés. +Mais lorsque vous les déclarez avec des types Python (dans l'exemple ci-dessus, en tant que `int`), ils sont convertis vers ce type et validés par rapport à celui-ci. -Toutes les fonctionnalités qui s'appliquent aux paramètres de chemin s'appliquent aussi aux paramètres de requête : +Tous les mêmes processus qui s'appliquaient aux paramètres de chemin s'appliquent aussi aux paramètres de requête : -* Support de l'éditeur : vérification d'erreurs, auto-complétion, etc. -* "Parsing" de données. -* Validation de données. -* Annotations d'API et documentation automatique. +* Prise en charge de l'éditeur (évidemment) +* « parsing » des données +* Validation des données +* Documentation automatique -## Valeurs par défaut +## Valeurs par défaut { #defaults } -Les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut. +Comme les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut. -Dans l'exemple ci-dessus, ils ont des valeurs par défaut qui sont `skip=0` et `limit=10`. +Dans l'exemple ci-dessus, ils ont des valeurs par défaut `skip=0` et `limit=10`. Donc, accéder à l'URL : @@ -40,52 +40,44 @@ Donc, accéder à l'URL : http://127.0.0.1:8000/items/ ``` -serait équivalent à accéder à l'URL : +serait équivalent à accéder à : ``` http://127.0.0.1:8000/items/?skip=0&limit=10 ``` -Mais si vous accédez à, par exemple : +Mais si vous accédez, par exemple, à : ``` http://127.0.0.1:8000/items/?skip=20 ``` -Les valeurs des paramètres de votre fonction seront : +Les valeurs des paramètres dans votre fonction seront : -* `skip=20` : car c'est la valeur déclarée dans l'URL. -* `limit=10` : car `limit` n'a pas été déclaré dans l'URL, et que la valeur par défaut était `10`. +* `skip=20` : car vous l'avez défini dans l'URL +* `limit=10` : car c'était la valeur par défaut -## Paramètres optionnels +## Paramètres optionnels { #optional-parameters } -De la même façon, vous pouvez définir des paramètres de requête comme optionnels, en leur donnant comme valeur par défaut `None` : +De la même façon, vous pouvez déclarer des paramètres de requête optionnels, en définissant leur valeur par défaut à `None` : -{* ../../docs_src/query_params/tutorial002.py hl[9] *} +{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *} -Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut. +Dans ce cas, le paramètre de fonction `q` sera optionnel et vaudra `None` par défaut. -/// check | Remarque +/// check | Vérifications -On peut voir que **FastAPI** est capable de détecter que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` n'en est pas un, c'est donc un paramètre de requête. +Notez également que FastAPI est suffisamment intelligent pour remarquer que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` ne l'est pas, c'est donc un paramètre de requête. /// -/// note +## Conversion des types des paramètres de requête { #query-parameter-type-conversion } -**FastAPI** saura que `q` est optionnel grâce au `=None`. +Vous pouvez aussi déclarer des types `bool`, ils seront convertis : -Le `Optional` dans `Optional[str]` n'est pas utilisé par **FastAPI** (**FastAPI** n'en utilisera que la partie `str`), mais il servira tout de même à votre éditeur de texte pour détecter des erreurs dans votre code. +{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *} -/// - -## Conversion des types des paramètres de requête - -Vous pouvez aussi déclarer des paramètres de requête comme booléens (`bool`), **FastAPI** les convertira : - -{* ../../docs_src/query_params/tutorial003.py hl[9] *} - -Avec ce code, en allant sur : +Dans ce cas, si vous allez sur : ``` http://127.0.0.1:8000/items/foo?short=1 @@ -115,60 +107,61 @@ ou http://127.0.0.1:8000/items/foo?short=yes ``` -ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction considérera le paramètre `short` comme ayant une valeur booléenne à `True`. Sinon la valeur sera à `False`. +ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction verra le paramètre `short` avec une valeur `bool` à `True`. Sinon la valeur sera à `False`. -## Multiples paramètres de chemin et de requête +## Multiples paramètres de chemin et de requête { #multiple-path-and-query-parameters } -Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer. +Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête en même temps, FastAPI sait lequel est lequel. Et vous n'avez pas besoin de les déclarer dans un ordre spécifique. -Ils seront détectés par leurs noms : +Ils seront détectés par leur nom : -{* ../../docs_src/query_params/tutorial004.py hl[8,10] *} +{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *} -## Paramètres de requête requis +## Paramètres de requête requis { #required-query-parameters } -Quand vous déclarez une valeur par défaut pour un paramètre qui n'est pas un paramètre de chemin (actuellement, nous n'avons vu que les paramètres de requête), alors ce paramètre n'est pas requis. +Quand vous déclarez une valeur par défaut pour des paramètres qui ne sont pas des paramètres de chemin (pour l'instant, nous n'avons vu que les paramètres de requête), alors ils ne sont pas requis. -Si vous ne voulez pas leur donner de valeur par défaut mais juste les rendre optionnels, utilisez `None` comme valeur par défaut. +Si vous ne voulez pas leur donner de valeur spécifique mais simplement les rendre optionnels, définissez la valeur par défaut à `None`. -Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez juste ne pas y affecter de valeur par défaut : +Mais 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.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} -Ici le paramètre `needy` est un paramètre requis (ou obligatoire) de type `str`. +Ici, le paramètre de requête `needy` est un paramètre de requête requis de type `str`. -Si vous ouvrez une URL comme : +Si vous ouvrez dans votre navigateur une URL comme : ``` http://127.0.0.1:8000/items/foo-item ``` -...sans ajouter le paramètre requis `needy`, vous aurez une erreur : +... sans ajouter le paramètre requis `needy`, vous verrez une erreur comme : ```JSON { - "detail": [ - { - "loc": [ - "query", - "needy" - ], - "msg": "field required", - "type": "value_error.missing" - } - ] + "detail": [ + { + "type": "missing", + "loc": [ + "query", + "needy" + ], + "msg": "Field required", + "input": null + } + ] } ``` -La présence de `needy` étant nécessaire, vous auriez besoin de l'insérer dans l'URL : +Comme `needy` est un paramètre requis, vous devez le définir dans l'URL : ``` http://127.0.0.1:8000/items/foo-item?needy=sooooneedy ``` -...ce qui fonctionnerait : +... cela fonctionnerait : ```JSON { @@ -177,18 +170,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy } ``` -Et bien sur, vous pouvez définir certains paramètres comme requis, certains avec des valeurs par défaut et certains entièrement optionnels : +Et bien sûr, vous pouvez définir certains paramètres comme requis, certains avec une valeur par défaut et certains entièrement optionnels : -{* ../../docs_src/query_params/tutorial006.py hl[10] *} +{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *} -Ici, on a donc 3 paramètres de requête : +Dans ce cas, il y a 3 paramètres de requête : -* `needy`, requis et de type `str`. -* `skip`, un `int` avec comme valeur par défaut `0`. +* `needy`, un `str` requis. +* `skip`, un `int` avec une valeur par défaut de `0`. * `limit`, un `int` optionnel. /// tip | Astuce -Vous pouvez utiliser les `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#valeurs-predefinies){.internal-link target=_blank}. +Vous pourriez aussi utiliser des `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#predefined-values){.internal-link target=_blank}. /// diff --git a/docs/tr/docs/_llm-test.md b/docs/tr/docs/_llm-test.md new file mode 100644 index 0000000000..0ca218e6e9 --- /dev/null +++ b/docs/tr/docs/_llm-test.md @@ -0,0 +1,503 @@ +# LLM test dosyası { #llm-test-file } + +Bu doküman, dokümantasyonu çeviren LLM'nin `scripts/translate.py` içindeki `general_prompt`'u ve `docs/{language code}/llm-prompt.md` içindeki dile özel prompt'u anlayıp anlamadığını test eder. Dile özel prompt, `general_prompt`'a eklenir. + +Buraya eklenen testler, dile özel prompt'ları tasarlayan herkes tarafından görülecektir. + +Şu şekilde kullanın: + +* Dile özel bir prompt bulundurun: `docs/{language code}/llm-prompt.md`. +* Bu dokümanın hedeflediğiniz dile sıfırdan yeni bir çevirisini yapın (örneğin `translate.py` içindeki `translate-page` komutu). Bu, çeviriyi `docs/{language code}/docs/_llm-test.md` altında oluşturur. +* Çeviride her şeyin yolunda olup olmadığını kontrol edin. +* Gerekirse dile özel prompt'u, genel prompt'u veya İngilizce dokümanı iyileştirin. +* Ardından çeviride kalan sorunları elle düzeltin; böylece iyi bir çeviri elde edin. +* İyi çeviri yerindeyken yeniden çeviri yapın. İdeal sonuç, LLM'nin artık çeviride hiçbir değişiklik yapmamasıdır. Bu da genel prompt'un ve dile özel prompt'un olabilecek en iyi hâle geldiği anlamına gelir (bazen rastgele gibi görünen birkaç değişiklik yapabilir; çünkü LLM'ler deterministik algoritmalar değildir). + +Testler: + +## Code snippets { #code-snippets } + +//// tab | Test + +Bu bir code snippet: `foo`. Bu da başka bir code snippet: `bar`. Bir tane daha: `baz quux`. + +//// + +//// tab | Bilgi + +Code snippet'lerin içeriği olduğu gibi bırakılmalıdır. + +`script/translate.py` içindeki genel prompt'ta `### Content of code snippets` bölümüne bakın. + +//// + +## Alıntılar { #quotes } + +//// tab | Test + +Dün bir arkadaşım şunu yazdı: "If you spell incorrectly correctly, you have spelled it incorrectly". Ben de şunu yanıtladım: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'". + +/// note | Not + +LLM muhtemelen bunu yanlış çevirecektir. Yeniden çeviri yapıldığında düzeltilmiş çeviriyi koruyup korumadığı önemlidir. + +/// + +//// + +//// tab | Bilgi + +Prompt tasarlayan kişi, düz tırnakları tipografik tırnaklara dönüştürüp dönüştürmemeyi seçebilir. Olduğu gibi bırakmak da uygundur. + +Örneğin `docs/de/llm-prompt.md` içindeki `### Quotes` bölümüne bakın. + +//// + +## Code snippet'lerde alıntılar { #quotes-in-code-snippets } + +//// tab | Test + +`pip install "foo[bar]"` + +Code snippet'lerde string literal örnekleri: `"this"`, `'that'`. + +Code snippet'lerde string literal için zor bir örnek: `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 | Bilgi + +... Ancak code snippet'lerin içindeki tırnaklar olduğu gibi kalmalıdır. + +//// + +## Code block'lar { #code-blocks } + +//// tab | Test + +Bir Bash code örneği... + +```bash +# Evrene bir selam yazdır +echo "Hello universe" +``` + +...ve bir console code örneği... + +```console +$ fastapi run main.py + FastAPI Starting server + Searching for package file structure +``` + +...ve bir başka console code örneği... + +```console +// "Code" adında bir dizin oluştur +$ mkdir code +// O dizine geç +$ cd code +``` + +...ve bir Python code örneği... + +```Python +wont_work() # This won't work 😱 +works(foo="bar") # This works 🎉 +``` + +...ve hepsi bu. + +//// + +//// tab | Bilgi + +Code block'ların içindeki code değiştirilmemelidir; tek istisna yorumlardır (comments). + +`script/translate.py` içindeki genel prompt'ta `### Content of code blocks` bölümüne bakın. + +//// + +## Sekmeler ve renkli kutular { #tabs-and-colored-boxes } + +//// tab | Test + +/// info | Bilgi +Some text +/// + +/// note | Not +Some text +/// + +/// note | Teknik Detaylar +Some text +/// + +/// check | Ek bilgi +Some text +/// + +/// tip | İpucu +Some text +/// + +/// warning | Uyarı +Some text +/// + +/// danger | Tehlike +Some text +/// + +//// + +//// tab | Bilgi + +Sekmelerin ve `Info`/`Note`/`Warning`/vb. blokların başlığı, dikey çizgiden (`|`) sonra çeviri olarak eklenmelidir. + +`script/translate.py` içindeki genel prompt'ta `### Special blocks` ve `### Tab blocks` bölümlerine bakın. + +//// + +## Web ve internal link'ler { #web-and-internal-links } + +//// tab | Test + +Link metni çevrilmelidir, link adresi değişmeden kalmalıdır: + +* [Yukarıdaki başlığa link](#code-snippets) +* [Internal link](index.md#installation){.internal-link target=_blank} +* External link +* Link to a style +* Link to a script +* Link to an image + +Link metni çevrilmelidir, link adresi çeviriye işaret etmelidir: + +* FastAPI link + +//// + +//// tab | Bilgi + +Link'ler çevrilmelidir, ancak adresleri değişmeden kalmalıdır. Bir istisna, FastAPI dokümantasyonunun sayfalarına verilen mutlak link'lerdir. Bu durumda link, çeviriye işaret etmelidir. + +`script/translate.py` içindeki genel prompt'ta `### Links` bölümüne bakın. + +//// + +## HTML "abbr" öğeleri { #html-abbr-elements } + +//// tab | Test + +Burada HTML "abbr" öğeleriyle sarılmış bazı şeyler var (bazıları uydurma): + +### abbr tam bir ifade verir { #the-abbr-gives-a-full-phrase } + +* GTD +* lt +* XWT +* PSGI + +### abbr bir açıklama verir { #the-abbr-gives-an-explanation } + +* cluster +* Deep Learning + +### abbr tam bir ifade ve bir açıklama verir { #the-abbr-gives-a-full-phrase-and-an-explanation } + +* MDN +* I/O. + +//// + +//// tab | Bilgi + +"abbr" öğelerinin "title" attribute'ları belirli talimatlara göre çevrilir. + +Çeviriler, LLM'nin kaldırmaması gereken kendi "abbr" öğelerini ekleyebilir. Örneğin İngilizce kelimeleri açıklamak için. + +`script/translate.py` içindeki genel prompt'ta `### HTML abbr elements` bölümüne bakın. + +//// + +## Başlıklar { #headings } + +//// tab | Test + +### Bir web uygulaması geliştirin - bir öğretici { #develop-a-webapp-a-tutorial } + +Merhaba. + +### Type hint'ler ve -annotation'lar { #type-hints-and-annotations } + +Tekrar merhaba. + +### Super- ve subclass'lar { #super-and-subclasses } + +Tekrar merhaba. + +//// + +//// tab | Bilgi + +Başlıklarla ilgili tek katı kural, LLM'nin süslü parantezler içindeki hash kısmını değiştirmemesidir; böylece link'ler bozulmaz. + +`script/translate.py` içindeki genel prompt'ta `### Headings` bölümüne bakın. + +Dile özel bazı talimatlar için örneğin `docs/de/llm-prompt.md` içindeki `### Headings` bölümüne bakın. + +//// + +## Dokümanlarda kullanılan terimler { #terms-used-in-the-docs } + +//// tab | Test + +* siz +* sizin + +* örn. +* vb. + +* `foo` bir `int` olarak +* `bar` bir `str` olarak +* `baz` bir `list` olarak + +* Tutorial - Kullanıcı kılavuzu +* İleri Düzey Kullanıcı Kılavuzu +* SQLModel dokümanları +* API dokümanları +* otomatik dokümanlar + +* Veri Bilimi +* Deep Learning +* Machine Learning +* Dependency Injection +* HTTP Basic authentication +* HTTP Digest +* ISO formatı +* JSON Schema standardı +* JSON schema +* schema tanımı +* Password Flow +* Mobil + +* deprecated +* designed +* invalid +* on the fly +* standard +* default +* case-sensitive +* case-insensitive + +* uygulamayı serve etmek +* sayfayı serve etmek + +* app +* application + +* request +* response +* error response + +* path operation +* path operation decorator +* path operation function + +* body +* request body +* response body +* JSON body +* form body +* file body +* function body + +* parameter +* body parameter +* path parameter +* query parameter +* cookie parameter +* header parameter +* form parameter +* function parameter + +* event +* startup event +* server'ın startup'ı +* shutdown event +* lifespan event + +* handler +* event handler +* exception handler +* handle etmek + +* model +* Pydantic model +* data model +* database model +* form model +* model object + +* class +* base class +* parent class +* subclass +* child class +* sibling class +* class method + +* header +* headers +* authorization header +* `Authorization` header +* forwarded header + +* dependency injection system +* dependency +* dependable +* dependant + +* I/O bound +* CPU bound +* concurrency +* parallelism +* multiprocessing + +* env var +* environment variable +* `PATH` +* `PATH` variable + +* authentication +* authentication provider +* authorization +* authorization form +* authorization provider +* kullanıcı authenticate olur +* sistem kullanıcıyı authenticate eder + +* CLI +* command line interface + +* server +* client + +* cloud provider +* cloud service + +* geliştirme +* geliştirme aşamaları + +* dict +* dictionary +* enumeration +* enum +* enum member + +* encoder +* decoder +* encode etmek +* decode etmek + +* exception +* raise etmek + +* expression +* statement + +* frontend +* backend + +* GitHub discussion +* GitHub issue + +* performance +* performance optimization + +* return type +* return value + +* security +* security scheme + +* task +* background task +* task function + +* template +* template engine + +* type annotation +* type hint + +* server worker +* Uvicorn worker +* Gunicorn Worker +* worker process +* worker class +* workload + +* deployment +* deploy etmek + +* SDK +* software development kit + +* `APIRouter` +* `requirements.txt` +* Bearer Token +* breaking change +* bug +* button +* callable +* code +* commit +* context manager +* coroutine +* database session +* disk +* domain +* engine +* fake X +* HTTP GET method +* item +* library +* lifespan +* lock +* middleware +* mobile application +* module +* mounting +* network +* origin +* override +* payload +* processor +* property +* proxy +* pull request +* query +* RAM +* remote machine +* status code +* string +* tag +* web framework +* wildcard +* return etmek +* validate etmek + +//// + +//// tab | Bilgi + +Bu, dokümanlarda görülen (çoğunlukla) teknik terimlerin eksiksiz ve normatif olmayan bir listesidir. Prompt tasarlayan kişi için, LLM'nin hangi terimlerde desteğe ihtiyaç duyduğunu anlamada yardımcı olabilir. Örneğin iyi bir çeviriyi sürekli daha zayıf bir çeviriye geri alıyorsa. Ya da sizin dilinizde bir terimi çekimlemekte (conjugating/declinating) zorlanıyorsa. + +Örneğin `docs/de/llm-prompt.md` içindeki `### List of English terms and their preferred German translations` bölümüne bakın. + +//// diff --git a/docs/tr/docs/advanced/additional-responses.md b/docs/tr/docs/advanced/additional-responses.md new file mode 100644 index 0000000000..c8e372775c --- /dev/null +++ b/docs/tr/docs/advanced/additional-responses.md @@ -0,0 +1,247 @@ +# OpenAPI'de Ek Response'lar { #additional-responses-in-openapi } + +/// warning | Uyarı + +Bu konu oldukça ileri seviye bir konudur. + +**FastAPI**'ye yeni başlıyorsanız buna ihtiyaç duymayabilirsiniz. + +/// + +Ek status code'lar, media type'lar, açıklamalar vb. ile ek response'lar tanımlayabilirsiniz. + +Bu ek response'lar OpenAPI şemasına dahil edilir; dolayısıyla API dokümanlarında da görünürler. + +Ancak bu ek response'lar için, status code'unuzu ve içeriğinizi vererek `JSONResponse` gibi bir `Response`'u doğrudan döndürdüğünüzden emin olmanız gerekir. + +## `model` ile Ek Response { #additional-response-with-model } + +*Path operation decorator*'larınıza `responses` adlı bir parametre geçebilirsiniz. + +Bu parametre bir `dict` alır: anahtarlar her response için status code'lardır (`200` gibi), değerler ise her birine ait bilgileri içeren başka `dict`'lerdir. + +Bu response `dict`'lerinin her birinde, `response_model`'e benzer şekilde bir Pydantic model içeren `model` anahtarı olabilir. + +**FastAPI** bu modeli alır, JSON Schema'sını üretir ve OpenAPI'de doğru yere ekler. + +Örneğin, `404` status code'u ve `Message` Pydantic model'i ile başka bir response tanımlamak için şunu yazabilirsiniz: + +{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} + +/// note | Not + +`JSONResponse`'u doğrudan döndürmeniz gerektiğini unutmayın. + +/// + +/// info | Bilgi + +`model` anahtarı OpenAPI'nin bir parçası değildir. + +**FastAPI** buradaki Pydantic model'i alır, JSON Schema'yı üretir ve doğru yere yerleştirir. + +Doğru yer şurasıdır: + +* Değeri başka bir JSON nesnesi (`dict`) olan `content` anahtarının içinde: + * Media type anahtarı (örn. `application/json`) bulunur; bunun değeri başka bir JSON nesnesidir ve onun içinde: + * Değeri model'den gelen JSON Schema olan `schema` anahtarı vardır; doğru yer burasıdır. + * **FastAPI** bunu doğrudan gömmek yerine OpenAPI'deki başka bir yerde bulunan global JSON Schema'lara bir referans ekler. Böylece diğer uygulamalar ve client'lar bu JSON Schema'ları doğrudan kullanabilir, daha iyi code generation araçları sağlayabilir, vb. + +/// + +Bu *path operation* için OpenAPI'de üretilen response'lar şöyle olur: + +```JSON hl_lines="3-12" +{ + "responses": { + "404": { + "description": "Additional Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Message" + } + } + } + }, + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Item" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } +} +``` + +Schema'lar OpenAPI şemasının içinde başka bir yere referanslanır: + +```JSON hl_lines="4-16" +{ + "components": { + "schemas": { + "Message": { + "title": "Message", + "required": [ + "message" + ], + "type": "object", + "properties": { + "message": { + "title": "Message", + "type": "string" + } + } + }, + "Item": { + "title": "Item", + "required": [ + "id", + "value" + ], + "type": "object", + "properties": { + "id": { + "title": "Id", + "type": "string" + }, + "value": { + "title": "Value", + "type": "string" + } + } + }, + "ValidationError": { + "title": "ValidationError", + "required": [ + "loc", + "msg", + "type" + ], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "type": "string" + } + }, + "msg": { + "title": "Message", + "type": "string" + }, + "type": { + "title": "Error Type", + "type": "string" + } + } + }, + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": { + "$ref": "#/components/schemas/ValidationError" + } + } + } + } + } + } +} +``` + +## Ana Response İçin Ek Media Type'lar { #additional-media-types-for-the-main-response } + +Aynı `responses` parametresini, aynı ana response için farklı media type'lar eklemek amacıyla da kullanabilirsiniz. + +Örneğin, `image/png` için ek bir media type ekleyerek, *path operation*'ınızın bir JSON nesnesi (media type `application/json`) ya da bir PNG görseli döndürebildiğini belirtebilirsiniz: + +{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *} + +/// note | Not + +Görseli `FileResponse` kullanarak doğrudan döndürmeniz gerektiğine dikkat edin. + +/// + +/// info | Bilgi + +`responses` parametrenizde açıkça farklı bir media type belirtmediğiniz sürece FastAPI, response'un ana response class'ı ile aynı media type'a sahip olduğunu varsayar (varsayılan `application/json`). + +Ancak media type'ı `None` olan özel bir response class belirttiyseniz, FastAPI ilişkili bir model'i olan tüm ek response'lar için `application/json` kullanır. + +/// + +## Bilgileri Birleştirme { #combining-information } + +`response_model`, `status_code` ve `responses` parametreleri dahil olmak üzere, response bilgilerini birden fazla yerden birleştirebilirsiniz. + +Varsayılan `200` status code'unu (ya da gerekiyorsa özel bir tane) kullanarak bir `response_model` tanımlayabilir, ardından aynı response için ek bilgileri `responses` içinde, doğrudan OpenAPI şemasına ekleyebilirsiniz. + +**FastAPI**, `responses` içindeki ek bilgileri korur ve model'inizin JSON Schema'sı ile birleştirir. + +Örneğin, Pydantic model kullanan ve özel bir `description` içeren `404` status code'lu bir response tanımlayabilirsiniz. + +Ayrıca `response_model`'inizi kullanan, ancak özel bir `example` içeren `200` status code'lu bir response da tanımlayabilirsiniz: + +{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} + +Bunların hepsi OpenAPI'nize birleştirilerek dahil edilir ve API dokümanlarında gösterilir: + + + +## Ön Tanımlı Response'ları Özel Olanlarla Birleştirme { #combine-predefined-responses-and-custom-ones } + +Birçok *path operation* için geçerli olacak bazı ön tanımlı response'larınız olabilir; ancak bunları her *path operation*'ın ihtiyaç duyduğu özel response'larla birleştirmek isteyebilirsiniz. + +Bu durumlarda, Python'daki bir `dict`'i `**dict_to_unpack` ile "unpacking" tekniğini kullanabilirsiniz: + +```Python +old_dict = { + "old key": "old value", + "second old key": "second old value", +} +new_dict = {**old_dict, "new key": "new value"} +``` + +Burada `new_dict`, `old_dict` içindeki tüm key-value çiftlerini ve buna ek olarak yeni key-value çiftini içerir: + +```Python +{ + "old key": "old value", + "second old key": "second old value", + "new key": "new value", +} +``` + +Bu tekniği, *path operation*'larınızda bazı ön tanımlı response'ları yeniden kullanmak ve bunları ek özel response'larla birleştirmek için kullanabilirsiniz. + +Örneğin: + +{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *} + +## OpenAPI Response'ları Hakkında Daha Fazla Bilgi { #more-information-about-openapi-responses } + +Response'ların içine tam olarak neleri dahil edebileceğinizi görmek için OpenAPI spesifikasyonundaki şu bölümlere bakabilirsiniz: + +* OpenAPI Responses Object, `Response Object`'i içerir. +* OpenAPI Response Object, buradaki her şeyi `responses` parametreniz içinde, her bir response'un içine doğrudan ekleyebilirsiniz. Buna `description`, `headers`, `content` (bunun içinde farklı media type'lar ve JSON Schema'lar tanımlarsınız) ve `links` dahildir. diff --git a/docs/tr/docs/advanced/additional-status-codes.md b/docs/tr/docs/advanced/additional-status-codes.md new file mode 100644 index 0000000000..710a6459f3 --- /dev/null +++ b/docs/tr/docs/advanced/additional-status-codes.md @@ -0,0 +1,41 @@ +# Ek Status Code'ları { #additional-status-codes } + +Varsayılan olarak **FastAPI**, response'ları bir `JSONResponse` kullanarak döndürür; *path operation*'ınızdan döndürdüğünüz içeriği bu `JSONResponse`'un içine yerleştirir. + +Varsayılan status code'u veya *path operation* içinde sizin belirlediğiniz status code'u kullanır. + +## Ek status code'ları { #additional-status-codes_1 } + +Ana status code'a ek olarak başka status code'lar da döndürmek istiyorsanız, `JSONResponse` gibi bir `Response`'u doğrudan döndürerek bunu yapabilirsiniz ve ek status code'u doğrudan orada ayarlarsınız. + +Örneğin, item'ları güncellemeye izin veren bir *path operation*'ınız olduğunu düşünelim; başarılı olduğunda 200 "OK" HTTP status code'unu döndürüyor olsun. + +Ancak yeni item'ları da kabul etmesini istiyorsunuz. Ve item daha önce yoksa, onu oluşturup 201 "Created" HTTP status code'unu döndürsün. + +Bunu yapmak için `JSONResponse` import edin ve içeriğinizi doğrudan onunla döndürün; istediğiniz `status_code`'u da ayarlayın: + +{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *} + +/// warning | Uyarı + +Yukarıdaki örnekte olduğu gibi bir `Response`'u doğrudan döndürdüğünüzde, response aynen olduğu gibi döndürülür. + +Bir model ile serialize edilmez, vb. + +İçinde olmasını istediğiniz veriyi taşıdığından emin olun ve değerlerin geçerli JSON olduğundan emin olun (eğer `JSONResponse` kullanıyorsanız). + +/// + +/// note | Teknik Detaylar + +`from starlette.responses import JSONResponse` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` altında da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. `status` için de aynı durum geçerlidir. + +/// + +## OpenAPI ve API docs { #openapi-and-api-docs } + +Ek status code'ları ve response'ları doğrudan döndürürseniz, FastAPI sizin ne döndüreceğinizi önceden bilemeyeceği için bunlar OpenAPI şemasına (API docs) dahil edilmez. + +Ancak bunu kodunuzda şu şekilde dokümante edebilirsiniz: [Ek Response'lar](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/tr/docs/advanced/advanced-dependencies.md b/docs/tr/docs/advanced/advanced-dependencies.md new file mode 100644 index 0000000000..48c0b62111 --- /dev/null +++ b/docs/tr/docs/advanced/advanced-dependencies.md @@ -0,0 +1,163 @@ +# Gelişmiş Dependency'ler { #advanced-dependencies } + +## Parametreli dependency'ler { #parameterized-dependencies } + +Şimdiye kadar gördüğümüz tüm dependency'ler sabit bir function ya da class idi. + +Ancak, birçok farklı function veya class tanımlamak zorunda kalmadan, dependency üzerinde bazı parametreler ayarlamak isteyebileceğiniz durumlar olabilir. + +Örneğin, query parametresi `q`'nun belirli bir sabit içeriği barındırıp barındırmadığını kontrol eden bir dependency istediğimizi düşünelim. + +Ama bu sabit içeriği parametreleştirebilmek istiyoruz. + +## "Callable" bir instance { #a-callable-instance } + +Python'da bir class'ın instance'ını "callable" yapmanın bir yolu vardır. + +Class'ın kendisini değil (zaten callable'dır), o class'ın bir instance'ını. + +Bunu yapmak için `__call__` adında bir method tanımlarız: + +{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *} + +Bu durumda, ek parametreleri ve alt-dependency'leri kontrol etmek için **FastAPI**'nin kullanacağı şey bu `__call__` olacaktır; ayrıca daha sonra *path operation function* içindeki parametreye bir değer geçmek için çağrılacak olan da budur. + +## Instance'ı parametreleştirme { #parameterize-the-instance } + +Ve şimdi, dependency'yi "parametreleştirmek" için kullanacağımız instance parametrelerini tanımlamak üzere `__init__` kullanabiliriz: + +{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *} + +Bu durumda **FastAPI**, `__init__` ile asla uğraşmaz veya onu önemsemez; onu doğrudan kendi kodumuzda kullanırız. + +## Bir instance oluşturma { #create-an-instance } + +Bu class'tan bir instance'ı şöyle oluşturabiliriz: + +{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *} + +Böylece dependency'mizi "parametreleştirmiş" oluruz; artık içinde `"bar"` vardır ve bu değer `checker.fixed_content` attribute'u olarak durur. + +## Instance'ı dependency olarak kullanma { #use-the-instance-as-a-dependency } + +Sonra `Depends(FixedContentQueryChecker)` yerine `Depends(checker)` içinde bu `checker`'ı kullanabiliriz. Çünkü dependency, class'ın kendisi değil, `checker` instance'ıdır. + +Ve dependency çözülürken **FastAPI** bu `checker`'ı şöyle çağırır: + +```Python +checker(q="somequery") +``` + +...ve bunun döndürdüğü her şeyi, *path operation function* içinde `fixed_content_included` parametresine dependency değeri olarak geçirir: + +{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *} + +/// tip | İpucu + +Bunların tamamı biraz yapay görünebilir. Ayrıca bunun nasıl faydalı olduğu da henüz çok net olmayabilir. + +Bu örnekler bilerek basit tutuldu; ama mekanizmanın nasıl çalıştığını gösteriyor. + +Security bölümlerinde, aynı şekilde implement edilmiş yardımcı function'lar bulunuyor. + +Buradaki her şeyi anladıysanız, security için kullanılan bu yardımcı araçların arka planda nasıl çalıştığını da zaten biliyorsunuz demektir. + +/// + +## `yield`, `HTTPException`, `except` ve Background Tasks ile Dependency'ler { #dependencies-with-yield-httpexception-except-and-background-tasks } + +/// warning | Uyarı + +Büyük ihtimalle bu teknik detaylara ihtiyacınız yok. + +Bu detaylar, özellikle 0.121.0'dan eski bir FastAPI uygulamanız varsa ve `yield` kullanan dependency'lerle ilgili sorunlar yaşıyorsanız faydalıdır. + +/// + +`yield` kullanan dependency'ler; farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için zaman içinde evrildi. Aşağıda nelerin değiştiğinin bir özeti var. + +### `yield` ve `scope` ile dependency'ler { #dependencies-with-yield-and-scope } + +0.121.0 sürümünde FastAPI, `yield` kullanan dependency'ler için `Depends(scope="function")` desteğini ekledi. + +`Depends(scope="function")` kullanıldığında, `yield` sonrasındaki çıkış kodu, *path operation function* biter bitmez, response client'a geri gönderilmeden önce çalıştırılır. + +`Depends(scope="request")` (varsayılan) kullanıldığında ise `yield` sonrasındaki çıkış kodu, response gönderildikten sonra çalıştırılır. + +Daha fazlasını [Dependencies with `yield` - Early exit and `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) dokümantasyonunda okuyabilirsiniz. + +### `yield` ve `StreamingResponse` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-streamingresponse-technical-details } + +FastAPI 0.118.0 öncesinde, `yield` kullanan bir dependency kullanırsanız, *path operation function* döndükten sonra ama response gönderilmeden hemen önce `yield` sonrasındaki çıkış kodu çalıştırılırdı. + +Amaç, response'un ağ üzerinden taşınmasını beklerken gereğinden uzun süre resource tutmaktan kaçınmaktı. + +Bu değişiklik aynı zamanda şunu da ifade ediyordu: `StreamingResponse` döndürürseniz, `yield` kullanan dependency'nin çıkış kodu zaten çalışmış olurdu. + +Örneğin, `yield` kullanan bir dependency içinde bir veritabanı session'ınız varsa, `StreamingResponse` veri stream ederken bu session'ı kullanamazdı; çünkü `yield` sonrasındaki çıkış kodunda session zaten kapatılmış olurdu. + +Bu davranış 0.118.0'da geri alındı ve `yield` sonrasındaki çıkış kodunun, response gönderildikten sonra çalıştırılması sağlandı. + +/// info | Bilgi + +Aşağıda göreceğiniz gibi, bu davranış 0.106.0 sürümünden önceki davranışa oldukça benzer; ancak köşe durumlar için çeşitli iyileştirmeler ve bug fix'ler içerir. + +/// + +#### Erken Çıkış Kodu için Kullanım Senaryoları { #use-cases-with-early-exit-code } + +Bazı özel koşullardaki kullanım senaryoları, response gönderilmeden önce `yield` kullanan dependency'lerin çıkış kodunun çalıştırıldığı eski davranıştan fayda görebilir. + +Örneğin, `yield` kullanan bir dependency içinde yalnızca bir kullanıcıyı doğrulamak için veritabanı session'ı kullanan bir kodunuz olduğunu düşünün; ama bu session *path operation function* içinde bir daha hiç kullanılmıyor, yalnızca dependency içinde kullanılıyor **ve** response'un gönderilmesi uzun sürüyor. Mesela veriyi yavaş gönderen bir `StreamingResponse` var, ama herhangi bir nedenle veritabanını kullanmıyor. + +Bu durumda veritabanı session'ı, response tamamen gönderilene kadar elde tutulur. Ancak session kullanılmıyorsa, bunu elde tutmak gerekli değildir. + +Şöyle görünebilir: + +{* ../../docs_src/dependencies/tutorial013_an_py310.py *} + +`Session`'ın otomatik kapatılması olan çıkış kodu şurada: + +{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *} + +...yavaş veri gönderen response'un gönderimi bittikten sonra çalıştırılır: + +{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *} + +Ama `generate_stream()` veritabanı session'ını kullanmadığı için, response gönderilirken session'ı açık tutmak aslında gerekli değildir. + +SQLModel (veya SQLAlchemy) kullanarak bu spesifik senaryoya sahipseniz, session'a artık ihtiyacınız kalmadıktan sonra session'ı açıkça kapatabilirsiniz: + +{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *} + +Böylece session veritabanı bağlantısını serbest bırakır ve diğer request'ler bunu kullanabilir. + +`yield` kullanan bir dependency'den erken çıkış gerektiren farklı bir kullanım senaryonuz varsa, lütfen kullanım senaryonuzla birlikte ve `yield` kullanan dependency'ler için erken kapatmadan neden fayda göreceğinizi açıklayarak bir GitHub Discussion Question oluşturun. + +`yield` kullanan dependency'lerde erken kapatma için ikna edici kullanım senaryoları varsa, erken kapatmayı seçmeli (opt-in) hale getiren yeni bir yöntem eklemeyi düşünebilirim. + +### `yield` ve `except` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-except-technical-details } + +FastAPI 0.110.0 öncesinde, `yield` kullanan bir dependency kullanır, sonra o dependency içinde `except` ile bir exception yakalar ve exception'ı tekrar raise etmezseniz; exception otomatik olarak herhangi bir exception handler'a veya internal server error handler'a raise/forward edilirdi. + +Bu davranış 0.110.0 sürümünde değiştirildi. Amaç, handler olmayan (internal server errors) forward edilmiş exception'ların yönetilmemesinden kaynaklanan bellek tüketimini düzeltmek ve bunu normal Python kodunun davranışıyla tutarlı hale getirmekti. + +### Background Tasks ve `yield` ile dependency'ler, Teknik Detaylar { #background-tasks-and-dependencies-with-yield-technical-details } + +FastAPI 0.106.0 öncesinde, `yield` sonrasında exception raise etmek mümkün değildi; çünkü `yield` kullanan dependency'lerdeki çıkış kodu response gönderildikten *sonra* çalıştırılıyordu. Bu nedenle [Exception Handlers](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} zaten çalışmış olurdu. + +Bu tasarımın ana sebeplerinden biri, background task'lerin içinde dependency'lerin "yield ettiği" aynı objeleri kullanmaya izin vermekti; çünkü çıkış kodu, background task'ler bittikten sonra çalıştırılıyordu. + +Bu davranış FastAPI 0.106.0'da, response'un ağ üzerinde taşınmasını beklerken resource tutmamak amacıyla değiştirildi. + +/// tip | İpucu + +Ek olarak, bir background task normalde ayrı ele alınması gereken bağımsız bir mantık setidir ve kendi resource'larına sahip olmalıdır (ör. kendi veritabanı bağlantısı). + +Bu şekilde muhtemelen daha temiz bir kod elde edersiniz. + +/// + +Bu davranışa güvenerek kod yazdıysanız, artık background task'ler için resource'ları background task'in içinde oluşturmalı ve içeride yalnızca `yield` kullanan dependency'lerin resource'larına bağlı olmayan verileri kullanmalısınız. + +Örneğin, aynı veritabanı session'ını kullanmak yerine background task içinde yeni bir veritabanı session'ı oluşturur ve veritabanındaki objeleri bu yeni session ile alırsınız. Ardından, background task function'ına veritabanından gelen objeyi parametre olarak geçirmek yerine, o objenin ID'sini geçirir ve objeyi background task function'ı içinde yeniden elde edersiniz. diff --git a/docs/tr/docs/advanced/async-tests.md b/docs/tr/docs/advanced/async-tests.md new file mode 100644 index 0000000000..82349bbec4 --- /dev/null +++ b/docs/tr/docs/advanced/async-tests.md @@ -0,0 +1,99 @@ +# Async Testler { #async-tests } + +Sağlanan `TestClient` ile **FastAPI** uygulamalarınızı nasıl test edeceğinizi zaten gördünüz. Şimdiye kadar yalnızca senkron testler yazdık, yani `async` fonksiyonlar kullanmadan. + +Testlerinizde asenkron fonksiyonlar kullanabilmek faydalı olabilir; örneğin veritabanınızı asenkron olarak sorguluyorsanız. Diyelim ki FastAPI uygulamanıza request gönderilmesini test etmek ve ardından async bir veritabanı kütüphanesi kullanırken backend'in doğru veriyi veritabanına başarıyla yazdığını doğrulamak istiyorsunuz. + +Bunu nasıl çalıştırabileceğimize bir bakalım. + +## pytest.mark.anyio { #pytest-mark-anyio } + +Testlerimizde asenkron fonksiyonlar çağırmak istiyorsak, test fonksiyonlarımızın da asenkron olması gerekir. AnyIO bunun için güzel bir plugin sağlar; böylece bazı test fonksiyonlarının asenkron olarak çağrılacağını belirtebiliriz. + +## HTTPX { #httpx } + +**FastAPI** uygulamanız `async def` yerine normal `def` fonksiyonları kullanıyor olsa bile, altta yatan yapı hâlâ bir `async` uygulamadır. + +`TestClient`, standart pytest kullanarak normal `def` test fonksiyonlarınızın içinden asenkron FastAPI uygulamasını çağırmak için içeride bazı “sihirli” işlemler yapar. Ancak bu sihir, onu asenkron fonksiyonların içinde kullandığımızda artık çalışmaz. Testlerimizi asenkron çalıştırdığımızda, test fonksiyonlarımızın içinde `TestClient` kullanamayız. + +`TestClient`, HTTPX tabanlıdır ve neyse ki API'yi test etmek için HTTPX'i doğrudan kullanabiliriz. + +## Örnek { #example } + +Basit bir örnek için, [Bigger Applications](../tutorial/bigger-applications.md){.internal-link target=_blank} ve [Testing](../tutorial/testing.md){.internal-link target=_blank} bölümlerinde anlatılana benzer bir dosya yapısı düşünelim: + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +`main.py` dosyası şöyle olur: + +{* ../../docs_src/async_tests/app_a_py39/main.py *} + +`test_main.py` dosyasında `main.py` için testler yer alır, artık şöyle görünebilir: + +{* ../../docs_src/async_tests/app_a_py39/test_main.py *} + +## Çalıştırma { #run-it } + +Testlerinizi her zamanki gibi şu şekilde çalıştırabilirsiniz: + +
+ +```console +$ pytest + +---> 100% +``` + +
+ +## Detaylı Anlatım { #in-detail } + +`@pytest.mark.anyio` marker'ı, pytest'e bu test fonksiyonunun asenkron olarak çağrılması gerektiğini söyler: + +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *} + +/// tip | İpucu + +Test fonksiyonu artık `TestClient` kullanırken eskiden olduğu gibi sadece `def` değil, `async def`. + +/// + +Ardından app ile bir `AsyncClient` oluşturup `await` kullanarak ona async request'ler gönderebiliriz. + +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *} + +Bu, şu kullanıma denktir: + +```Python +response = client.get('/') +``` + +...ki daha önce request'leri `TestClient` ile bu şekilde gönderiyorduk. + +/// tip | İpucu + +Yeni `AsyncClient` ile async/await kullandığımızı unutmayın; request asenkron çalışır. + +/// + +/// warning | Uyarı + +Uygulamanız lifespan event'lerine dayanıyorsa, `AsyncClient` bu event'leri tetiklemez. Tetiklendiklerinden emin olmak için florimondmanca/asgi-lifespan paketindeki `LifespanManager`'ı kullanın. + +/// + +## Diğer Asenkron Fonksiyon Çağrıları { #other-asynchronous-function-calls } + +Test fonksiyonu artık asenkron olduğundan, testlerinizde FastAPI uygulamanıza request göndermenin yanında başka `async` fonksiyonları da (çağırıp `await` ederek) kodunuzun başka yerlerinde yaptığınız gibi aynı şekilde kullanabilirsiniz. + +/// tip | İpucu + +Testlerinize asenkron fonksiyon çağrıları entegre ederken `RuntimeError: Task attached to a different loop` hatasıyla karşılaşırsanız (ör. MongoDB'nin MotorClient kullanımı), event loop gerektiren nesneleri yalnızca async fonksiyonların içinde oluşturmanız gerektiğini unutmayın; örneğin bir `@app.on_event("startup")` callback'i içinde. + +/// diff --git a/docs/tr/docs/advanced/behind-a-proxy.md b/docs/tr/docs/advanced/behind-a-proxy.md new file mode 100644 index 0000000000..e70b16960f --- /dev/null +++ b/docs/tr/docs/advanced/behind-a-proxy.md @@ -0,0 +1,466 @@ +# Proxy Arkasında Çalıştırma { #behind-a-proxy } + +Birçok durumda, FastAPI uygulamanızın önünde Traefik veya Nginx gibi bir **proxy** kullanırsınız. + +Bu proxy'ler HTTPS sertifikalarını ve diğer bazı işleri üstlenebilir. + +## Proxy Forwarded Header'ları { #proxy-forwarded-headers } + +Uygulamanızın önündeki bir **proxy**, request'leri **server**'ınıza göndermeden önce genelde bazı header'ları dinamik olarak ayarlar. Böylece server, request'in proxy tarafından **forward** edildiğini; domain dahil orijinal (public) URL'yi, HTTPS kullanıldığını vb. bilgileri anlayabilir. + +**Server** programı (örneğin **FastAPI CLI** üzerinden **Uvicorn**) bu header'ları yorumlayabilir ve ardından bu bilgiyi uygulamanıza aktarabilir. + +Ancak güvenlik nedeniyle, server güvenilir bir proxy arkasında olduğunu bilmediği için bu header'ları yorumlamaz. + +/// note | Teknik Detaylar + +Proxy header'ları şunlardır: + +* X-Forwarded-For +* X-Forwarded-Proto +* X-Forwarded-Host + +/// + +### Proxy Forwarded Header'larını Etkinleştirme { #enable-proxy-forwarded-headers } + +FastAPI CLI'yi `--forwarded-allow-ips` *CLI Option*'ı ile başlatıp, bu forwarded header'ları okumada güvenilecek IP adreslerini verebilirsiniz. + +Bunu `--forwarded-allow-ips="*"` olarak ayarlarsanız, gelen tüm IP'lere güvenir. + +**Server**'ınız güvenilir bir **proxy** arkasındaysa ve onunla sadece proxy konuşuyorsa, bu ayar server'ın o **proxy**'nin IP'si her neyse onu kabul etmesini sağlar. + +
+ +```console +$ fastapi run --forwarded-allow-ips="*" + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### HTTPS ile Redirect'ler { #redirects-with-https } + +Örneğin `/items/` adında bir *path operation* tanımladığınızı düşünelim: + +{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *} + +Client `/items`'a gitmeye çalışırsa, varsayılan olarak `/items/`'a redirect edilir. + +Ancak *CLI Option* `--forwarded-allow-ips` ayarlanmadan önce, `http://localhost:8000/items/`'a redirect edebilir. + +Oysa uygulamanız `https://mysuperapp.com` üzerinde host ediliyor olabilir ve redirect'in `https://mysuperapp.com/items/` olması gerekir. + +Artık `--proxy-headers` ayarını yaparak FastAPI'nin doğru adrese redirect edebilmesini sağlarsınız. 😎 + +``` +https://mysuperapp.com/items/ +``` + +/// tip | İpucu + +HTTPS hakkında daha fazla bilgi için [HTTPS Hakkında](../deployment/https.md){.internal-link target=_blank} rehberine bakın. + +/// + +### Proxy Forwarded Header'ları Nasıl Çalışır { #how-proxy-forwarded-headers-work } + +**Proxy**'nin, client ile **application server** arasında forwarded header'ları nasıl eklediğini gösteren görsel bir temsil: + +```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 +``` + +**Proxy**, orijinal client request'ini araya girerek (intercept) alır ve request'i **application server**'a iletmeden önce özel *forwarded* header'ları (`X-Forwarded-*`) ekler. + +Bu header'lar, aksi halde kaybolacak olan orijinal request bilgilerini korur: + +* **X-Forwarded-For**: Orijinal client'ın IP adresi +* **X-Forwarded-Proto**: Orijinal protokol (`https`) +* **X-Forwarded-Host**: Orijinal host (`mysuperapp.com`) + +**FastAPI CLI** `--forwarded-allow-ips` ile yapılandırıldığında bu header'lara güvenir ve örneğin redirect'lerde doğru URL'leri üretmek için bunları kullanır. + +## Path Prefix'i Kırpılan (Stripped) Bir Proxy { #proxy-with-a-stripped-path-prefix } + +Uygulamanıza bir path prefix ekleyen bir proxy'niz olabilir. + +Bu durumlarda uygulamanızı yapılandırmak için `root_path` kullanabilirsiniz. + +`root_path`, FastAPI'nin (Starlette üzerinden) üzerine kurulduğu ASGI spesifikasyonunun sağladığı bir mekanizmadır. + +`root_path` bu özel senaryoları yönetmek için kullanılır. + +Ayrıca sub-application mount ederken de içeride kullanılır. + +Path prefix'i kırpılan bir proxy kullanmak, şu anlama gelir: Kodunuzda `/app` altında bir path tanımlarsınız; ancak üstte bir katman (proxy) ekleyip **FastAPI** uygulamanızı `/api/v1` gibi bir path'in altına koyarsınız. + +Bu durumda, orijinal `/app` path'i aslında `/api/v1/app` altında servis edilir. + +Kodunuzun tamamı sadece `/app` varmış gibi yazılmış olsa bile. + +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *} + +Proxy, request'i app server'a (muhtemelen FastAPI CLI üzerinden Uvicorn) iletmeden önce **path prefix**'i anlık olarak **"kırpar"** (strip). Böylece uygulamanız hâlâ `/app` altında servis ediliyormuş gibi davranır ve tüm kodunuzu `/api/v1` prefix'ini içerecek şekilde güncellemeniz gerekmez. + +Buraya kadar her şey normal çalışır. + +Ancak entegre doküman arayüzünü (frontend) açtığınızda, OpenAPI şemasını `/api/v1/openapi.json` yerine `/openapi.json` üzerinden almayı bekler. + +Dolayısıyla tarayıcıda çalışan frontend `/openapi.json`'a erişmeye çalışır ve OpenAPI şemasını alamaz. + +Çünkü uygulamamız proxy arkasında `/api/v1` path prefix'i ile çalışmaktadır; frontend'in OpenAPI şemasını `/api/v1/openapi.json` üzerinden çekmesi gerekir. + +```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 | İpucu + +`0.0.0.0` IP'si, genelde programın ilgili makine/server üzerindeki tüm kullanılabilir IP'lerde dinlediği anlamına gelir. + +/// + +Docs UI'nin, bu API `server`'ının (proxy arkasında) `/api/v1` altında bulunduğunu belirtmek için OpenAPI şemasına da ihtiyacı olur. Örneğin: + +```JSON hl_lines="4-8" +{ + "openapi": "3.1.0", + // More stuff here + "servers": [ + { + "url": "/api/v1" + } + ], + "paths": { + // More stuff here + } +} +``` + +Bu örnekte "Proxy", **Traefik** gibi bir şey olabilir. Server da FastAPI uygulamanızı çalıştıran (Uvicorn'lu) FastAPI CLI olabilir. + +### `root_path` Sağlama { #providing-the-root-path } + +Bunu yapmak için `--root-path` komut satırı seçeneğini şöyle kullanabilirsiniz: + +
+ +```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) +``` + +
+ +Hypercorn kullanıyorsanız, onda da `--root-path` seçeneği vardır. + +/// note | Teknik Detaylar + +ASGI spesifikasyonu bu kullanım senaryosu için bir `root_path` tanımlar. + +`--root-path` komut satırı seçeneği de bu `root_path`'i sağlar. + +/// + +### Mevcut `root_path`'i Kontrol Etme { #checking-the-current-root-path } + +Uygulamanızın her request için kullandığı mevcut `root_path` değerini alabilirsiniz; bu değer ASGI spesifikasyonunun bir parçası olan `scope` dict'inin içindedir. + +Burada sadece göstermek için bunu mesaja dahil ediyoruz. + +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *} + +Ardından Uvicorn'u şu şekilde başlatırsanız: + +
+ +```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) +``` + +
+ +Response şöyle bir şey olur: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +### FastAPI Uygulamasında `root_path` Ayarlama { #setting-the-root-path-in-the-fastapi-app } + +Alternatif olarak, `--root-path` gibi bir komut satırı seçeneği (veya muadili) sağlayamıyorsanız, FastAPI uygulamanızı oluştururken `root_path` parametresini ayarlayabilirsiniz: + +{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *} + +`FastAPI`'ye `root_path` vermek, Uvicorn veya Hypercorn'a `--root-path` komut satırı seçeneğini vermekle eşdeğerdir. + +### `root_path` Hakkında { #about-root-path } + +Şunu unutmayın: Server (Uvicorn) bu `root_path`'i, uygulamaya iletmek dışında başka bir amaçla kullanmaz. + +Ancak tarayıcınızla http://127.0.0.1:8000/app adresine giderseniz normal response'u görürsünüz: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +Yani `http://127.0.0.1:8000/api/v1/app` üzerinden erişilmeyi beklemez. + +Uvicorn, proxy'nin Uvicorn'a `http://127.0.0.1:8000/app` üzerinden erişmesini bekler; bunun üstüne ekstra `/api/v1` prefix'ini eklemek proxy'nin sorumluluğudur. + +## Stripped Path Prefix Kullanan Proxy'ler Hakkında { #about-proxies-with-a-stripped-path-prefix } + +Stripped path prefix kullanan bir proxy, yapılandırma yöntemlerinden yalnızca biridir. + +Birçok durumda varsayılan davranış, proxy'nin stripped path prefix kullanmaması olacaktır. + +Böyle bir durumda (stripped path prefix olmadan), proxy `https://myawesomeapp.com` gibi bir yerde dinler; tarayıcı `https://myawesomeapp.com/api/v1/app`'e giderse ve sizin server'ınız (ör. Uvicorn) `http://127.0.0.1:8000` üzerinde dinliyorsa, proxy (stripped path prefix olmadan) Uvicorn'a aynı path ile erişir: `http://127.0.0.1:8000/api/v1/app`. + +## Traefik ile Local Olarak Test Etme { #testing-locally-with-traefik } + +Traefik kullanarak, stripped path prefix'li deneyi local'de kolayca çalıştırabilirsiniz. + +Traefik'i indirin; tek bir binary'dir, sıkıştırılmış dosyayı çıkarıp doğrudan terminalden çalıştırabilirsiniz. + +Ardından `traefik.toml` adında bir dosya oluşturup şunu yazın: + +```TOML hl_lines="3" +[entryPoints] + [entryPoints.http] + address = ":9999" + +[providers] + [providers.file] + filename = "routes.toml" +``` + +Bu, Traefik'e 9999 portunda dinlemesini ve `routes.toml` adlı başka bir dosyayı kullanmasını söyler. + +/// tip | İpucu + +Standart HTTP portu 80 yerine 9999 portunu kullanıyoruz; böylece admin (`sudo`) yetkileriyle çalıştırmanız gerekmez. + +/// + +Şimdi diğer dosyayı, `routes.toml`'u oluşturun: + +```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" +``` + +Bu dosya, Traefik'i `/api/v1` path prefix'ini kullanacak şekilde yapılandırır. + +Ardından Traefik, request'leri `http://127.0.0.1:8000` üzerinde çalışan Uvicorn'unuza yönlendirir. + +Şimdi Traefik'i başlatın: + +
+ +```console +$ ./traefik --configFile=traefik.toml + +INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml +``` + +
+ +Ve şimdi uygulamanızı `--root-path` seçeneğiyle başlatın: + +
+ +```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) +``` + +
+ +### Response'ları Kontrol Edin { #check-the-responses } + +Şimdi Uvicorn'un portundaki URL'ye giderseniz: http://127.0.0.1:8000/app, normal response'u görürsünüz: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +/// tip | İpucu + +`http://127.0.0.1:8000/app` üzerinden erişiyor olsanız bile, `root_path` değerinin `--root-path` seçeneğinden alınıp `/api/v1` olarak gösterildiğine dikkat edin. + +/// + +Şimdi de Traefik'in portundaki URL'yi, path prefix ile birlikte açın: http://127.0.0.1:9999/api/v1/app. + +Aynı response'u alırız: + +```JSON +{ + "message": "Hello World", + "root_path": "/api/v1" +} +``` + +ama bu sefer proxy'nin sağladığı prefix path olan `/api/v1` ile gelen URL'de. + +Elbette buradaki fikir, herkesin uygulamaya proxy üzerinden erişmesidir; dolayısıyla `/api/v1` path prefix'li sürüm "doğru" olandır. + +Uvicorn'un doğrudan sunduğu, path prefix olmayan sürüm (`http://127.0.0.1:8000/app`) ise sadece _proxy_'nin (Traefik) erişmesi için kullanılmalıdır. + +Bu da Proxy'nin (Traefik) path prefix'i nasıl kullandığını ve server'ın (Uvicorn) `--root-path` seçeneğinden gelen `root_path`'i nasıl kullandığını gösterir. + +### Docs UI'yi Kontrol Edin { #check-the-docs-ui } + +Şimdi işin eğlenceli kısmı. ✨ + +Uygulamaya erişmenin "resmi" yolu, tanımladığımız path prefix ile proxy üzerinden erişmektir. Bu yüzden beklendiği gibi, Uvicorn'un doğrudan servis ettiği docs UI'yi URL'de path prefix olmadan açarsanız çalışmaz; çünkü proxy üzerinden erişileceğini varsayar. + +Şuradan kontrol edebilirsiniz: http://127.0.0.1:8000/docs: + + + +Ancak docs UI'yi proxy üzerinden, `9999` portuyla, `/api/v1/docs` altında "resmi" URL'den açarsak doğru çalışır! 🎉 + +Şuradan kontrol edebilirsiniz: http://127.0.0.1:9999/api/v1/docs: + + + +Tam istediğimiz gibi. ✔️ + +Bunun nedeni, FastAPI'nin OpenAPI içinde varsayılan `server`'ı, `root_path` tarafından verilen URL ile oluşturmak için bu `root_path`'i kullanmasıdır. + +## Ek `server`'lar { #additional-servers } + +/// warning | Uyarı + +Bu daha ileri seviye bir kullanım senaryosudur. İsterseniz atlayabilirsiniz. + +/// + +Varsayılan olarak **FastAPI**, OpenAPI şemasında `root_path` için bir `server` oluşturur. + +Ancak başka alternatif `servers` da sağlayabilirsiniz; örneğin *aynı* docs UI'nin hem staging hem de production ortamıyla etkileşime girmesini istiyorsanız. + +Özel bir `servers` listesi verirseniz ve bir `root_path` varsa (çünkü API'niz proxy arkasındadır), **FastAPI** bu `root_path` ile bir "server"ı listenin başına ekler. + +Örneğin: + +{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *} + +Şöyle bir OpenAPI şeması üretir: + +```JSON hl_lines="5-7" +{ + "openapi": "3.1.0", + // More stuff here + "servers": [ + { + "url": "/api/v1" + }, + { + "url": "https://stag.example.com", + "description": "Staging environment" + }, + { + "url": "https://prod.example.com", + "description": "Production environment" + } + ], + "paths": { + // More stuff here + } +} +``` + +/// tip | İpucu + +`url` değeri `/api/v1` olan, `root_path`'ten alınmış otomatik üretilen server'a dikkat edin. + +/// + +Docs UI'de, http://127.0.0.1:9999/api/v1/docs adresinde şöyle görünür: + + + +/// tip | İpucu + +Docs UI, seçtiğiniz server ile etkileşime girer. + +/// + +/// note | Teknik Detaylar + +OpenAPI spesifikasyonunda `servers` özelliği opsiyoneldir. + +`servers` parametresini belirtmezseniz ve `root_path` `/` ile aynıysa, üretilen OpenAPI şemasında `servers` özelliği varsayılan olarak tamamen çıkarılır; bu da `url` değeri `/` olan tek bir server ile eşdeğerdir. + +/// + +### `root_path`'ten Otomatik `server` Eklenmesini Kapatma { #disable-automatic-server-from-root-path } + +**FastAPI**'nin `root_path` kullanarak otomatik bir server eklemesini istemiyorsanız, `root_path_in_servers=False` parametresini kullanabilirsiniz: + +{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *} + +Böylece OpenAPI şemasına dahil etmez. + +## Bir Sub-Application Mount Etme { #mounting-a-sub-application } + +Bir sub-application'ı ( [Sub Applications - Mounts](sub-applications.md){.internal-link target=_blank} bölümünde anlatıldığı gibi) mount etmeniz gerekiyorsa ve aynı zamanda `root_path` ile bir proxy kullanıyorsanız, bunu beklendiği gibi normal şekilde yapabilirsiniz. + +FastAPI içeride `root_path`'i akıllıca kullanır; dolayısıyla doğrudan çalışır. ✨ diff --git a/docs/tr/docs/advanced/custom-response.md b/docs/tr/docs/advanced/custom-response.md new file mode 100644 index 0000000000..c5148f4287 --- /dev/null +++ b/docs/tr/docs/advanced/custom-response.md @@ -0,0 +1,312 @@ +# Özel Response - HTML, Stream, File ve Diğerleri { #custom-response-html-stream-file-others } + +Varsayılan olarak **FastAPI**, response'ları `JSONResponse` kullanarak döndürür. + +Bunu, [Doğrudan bir Response döndür](response-directly.md){.internal-link target=_blank} bölümünde gördüğünüz gibi doğrudan bir `Response` döndürerek geçersiz kılabilirsiniz. + +Ancak doğrudan bir `Response` döndürürseniz (veya `JSONResponse` gibi herhangi bir alt sınıfını), veri otomatik olarak dönüştürülmez (bir `response_model` tanımlamış olsanız bile) ve dokümantasyon da otomatik üretilmez (örneğin, üretilen OpenAPI’nin parçası olarak HTTP header `Content-Type` içindeki ilgili "media type" dahil edilmez). + +Bununla birlikte, *path operation decorator* içinde `response_class` parametresini kullanarak hangi `Response`’un (örn. herhangi bir `Response` alt sınıfı) kullanılacağını da ilan edebilirsiniz. + +*path operation function*’ınızdan döndürdüğünüz içerik, o `Response`’un içine yerleştirilir. + +Ve eğer bu `Response` ( `JSONResponse` ve `UJSONResponse`’ta olduğu gibi) bir JSON media type’a (`application/json`) sahipse, döndürdüğünüz veri; *path operation decorator* içinde tanımladığınız herhangi bir Pydantic `response_model` ile otomatik olarak dönüştürülür (ve filtrelenir). + +/// note | Not + +Media type’ı olmayan bir response class kullanırsanız, FastAPI response’unuzun content içermediğini varsayar; bu yüzden ürettiği OpenAPI dokümanında response formatını dokümante etmez. + +/// + +## `ORJSONResponse` Kullan { #use-orjsonresponse } + +Örneğin performansı sıkıştırmaya çalışıyorsanız, `orjson` kurup kullanabilir ve response’u `ORJSONResponse` olarak ayarlayabilirsiniz. + +Kullanmak istediğiniz `Response` class’ını (alt sınıfını) import edin ve *path operation decorator* içinde tanımlayın. + +Büyük response'larda, doğrudan bir `Response` döndürmek bir dictionary döndürmekten çok daha hızlıdır. + +Çünkü varsayılan olarak FastAPI, içindeki her item’ı inceleyip JSON olarak serialize edilebilir olduğundan emin olur; tutorial’da anlatılan aynı [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} mekanizmasını kullanır. Bu da örneğin veritabanı modelleri gibi **keyfi objeleri** döndürebilmenizi sağlar. + +Ancak döndürdüğünüz içeriğin **JSON ile serialize edilebilir** olduğundan eminseniz, onu doğrudan response class’ına verebilir ve FastAPI’nin response class’ına vermeden önce dönüş içeriğinizi `jsonable_encoder` içinden geçirirken oluşturacağı ek yükten kaçınabilirsiniz. + +{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *} + +/// info | Bilgi + +`response_class` parametresi, response’un "media type"’ını tanımlamak için de kullanılır. + +Bu durumda HTTP header `Content-Type`, `application/json` olarak ayarlanır. + +Ve OpenAPI’de de bu şekilde dokümante edilir. + +/// + +/// tip | İpucu + +`ORJSONResponse` yalnızca FastAPI’de vardır, Starlette’te yoktur. + +/// + +## HTML Response { #html-response } + +**FastAPI**’den doğrudan HTML içeren bir response döndürmek için `HTMLResponse` kullanın. + +* `HTMLResponse` import edin. +* *path operation decorator*’ınızın `response_class` parametresi olarak `HTMLResponse` verin. + +{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *} + +/// info | Bilgi + +`response_class` parametresi, response’un "media type"’ını tanımlamak için de kullanılır. + +Bu durumda HTTP header `Content-Type`, `text/html` olarak ayarlanır. + +Ve OpenAPI’de de bu şekilde dokümante edilir. + +/// + +### Bir `Response` Döndür { #return-a-response } + +[Doğrudan bir Response döndür](response-directly.md){.internal-link target=_blank} bölümünde görüldüğü gibi, *path operation* içinde doğrudan bir response döndürerek response’u override edebilirsiniz. + +Yukarıdaki örneğin aynısı, bu sefer bir `HTMLResponse` döndürerek, şöyle görünebilir: + +{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *} + +/// warning | Uyarı + +*path operation function*’ınızın doğrudan döndürdüğü bir `Response`, OpenAPI’de dokümante edilmez (örneğin `Content-Type` dokümante edilmez) ve otomatik interaktif dokümanlarda görünmez. + +/// + +/// info | Bilgi + +Elbette gerçek `Content-Type` header’ı, status code vb. değerler, döndürdüğünüz `Response` objesinden gelir. + +/// + +### OpenAPI’de Dokümante Et ve `Response`’u Override Et { #document-in-openapi-and-override-response } + +Response’u fonksiyonun içinden override etmek ama aynı zamanda OpenAPI’de "media type"’ı dokümante etmek istiyorsanız, `response_class` parametresini kullanıp ayrıca bir `Response` objesi döndürebilirsiniz. + +Bu durumda `response_class` sadece OpenAPI *path operation*’ını dokümante etmek için kullanılır; sizin `Response`’unuz ise olduğu gibi kullanılır. + +#### Doğrudan bir `HTMLResponse` Döndür { #return-an-htmlresponse-directly } + +Örneğin şöyle bir şey olabilir: + +{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *} + +Bu örnekte `generate_html_response()` fonksiyonu, HTML’i bir `str` olarak döndürmek yerine zaten bir `Response` üretip döndürmektedir. + +`generate_html_response()` çağrısının sonucunu döndürerek, varsayılan **FastAPI** davranışını override edecek bir `Response` döndürmüş olursunuz. + +Ama `response_class` içinde `HTMLResponse` da verdiğiniz için **FastAPI**, bunu OpenAPI’de ve interaktif dokümanlarda `text/html` ile HTML olarak nasıl dokümante edeceğini bilir: + + + +## Mevcut Response'lar { #available-responses } + +Mevcut response'lardan bazıları aşağıdadır. + +Unutmayın: `Response` ile başka herhangi bir şeyi döndürebilir, hatta özel bir alt sınıf da oluşturabilirsiniz. + +/// note | Teknik Detaylar + +`from starlette.responses import HTMLResponse` da kullanabilirsiniz. + +**FastAPI**, geliştirici için kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` olarak da sağlar. Ancak mevcut response'ların çoğu doğrudan Starlette’ten gelir. + +/// + +### `Response` { #response } + +Ana `Response` class’ıdır; diğer tüm response'lar bundan türetilir. + +Bunu doğrudan döndürebilirsiniz. + +Şu parametreleri kabul eder: + +* `content` - Bir `str` veya `bytes`. +* `status_code` - Bir `int` HTTP status code. +* `headers` - String’lerden oluşan bir `dict`. +* `media_type` - Media type’ı veren bir `str`. Örn. `"text/html"`. + +FastAPI (aslında Starlette) otomatik olarak bir Content-Length header’ı ekler. Ayrıca `media_type`’a göre bir Content-Type header’ı ekler ve text türleri için sona bir charset ekler. + +{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} + +### `HTMLResponse` { #htmlresponse } + +Yukarıda okuduğunuz gibi, bir miktar text veya bytes alır ve HTML response döndürür. + +### `PlainTextResponse` { #plaintextresponse } + +Bir miktar text veya bytes alır ve düz metin response döndürür. + +{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *} + +### `JSONResponse` { #jsonresponse } + +Bir miktar veri alır ve `application/json` olarak encode edilmiş bir response döndürür. + +Yukarıda okuduğunuz gibi, **FastAPI**’de varsayılan response budur. + +### `ORJSONResponse` { #orjsonresponse } + +Yukarıda okuduğunuz gibi `orjson` kullanan hızlı bir alternatif JSON response. + +/// info | Bilgi + +Bunun için `orjson` kurulmalıdır; örneğin `pip install orjson`. + +/// + +### `UJSONResponse` { #ujsonresponse } + +`ujson` kullanan alternatif bir JSON response. + +/// info | Bilgi + +Bunun için `ujson` kurulmalıdır; örneğin `pip install ujson`. + +/// + +/// warning | Uyarı + +`ujson`, bazı edge-case’leri ele alma konusunda Python’un built-in implementasyonu kadar dikkatli değildir. + +/// + +{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *} + +/// tip | İpucu + +`ORJSONResponse` daha hızlı bir alternatif olabilir. + +/// + +### `RedirectResponse` { #redirectresponse } + +HTTP redirect döndürür. Varsayılan olarak 307 status code (Temporary Redirect) kullanır. + +`RedirectResponse`’u doğrudan döndürebilirsiniz: + +{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *} + +--- + +Veya `response_class` parametresi içinde kullanabilirsiniz: + +{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *} + +Bunu yaparsanız, *path operation* function’ınızdan doğrudan URL döndürebilirsiniz. + +Bu durumda kullanılan `status_code`, `RedirectResponse` için varsayılan olan `307` olur. + +--- + +Ayrıca `status_code` parametresini `response_class` parametresiyle birlikte kullanabilirsiniz: + +{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *} + +### `StreamingResponse` { #streamingresponse } + +Bir async generator veya normal generator/iterator alır ve response body’yi stream eder. + +{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *} + +#### `StreamingResponse`’u file-like objelerle kullanma { #using-streamingresponse-with-file-like-objects } + +Bir file-like objeniz varsa (örn. `open()`’ın döndürdüğü obje), o file-like obje üzerinde iterate eden bir generator function oluşturabilirsiniz. + +Böylece önce hepsini memory’ye okumak zorunda kalmazsınız; bu generator function’ı `StreamingResponse`’a verip döndürebilirsiniz. + +Buna cloud storage ile etkileşime giren, video işleyen ve benzeri birçok kütüphane dahildir. + +{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *} + +1. Bu generator function’dır. İçinde `yield` ifadeleri olduğu için "generator function" denir. +2. Bir `with` bloğu kullanarak, generator function bittiğinde file-like objenin kapandığından emin oluruz. Yani response göndermeyi bitirdikten sonra kapanır. +3. Bu `yield from`, fonksiyona `file_like` isimli şeyi iterate etmesini söyler. Ardından iterate edilen her parça için, o parçayı bu generator function’dan (`iterfile`) geliyormuş gibi yield eder. + + Yani, içerdeki "üretme" (generating) işini başka bir şeye devreden bir generator function’dır. + + Bunu bu şekilde yaptığımızda `with` bloğu içinde tutabilir ve böylece iş bitince file-like objenin kapanmasını garanti edebiliriz. + +/// tip | İpucu + +Burada `async` ve `await` desteklemeyen standart `open()` kullandığımız için path operation’ı normal `def` ile tanımlarız. + +/// + +### `FileResponse` { #fileresponse } + +Asenkron olarak bir dosyayı response olarak stream eder. + +Diğer response türlerine göre instantiate ederken farklı argümanlar alır: + +* `path` - Stream edilecek dosyanın dosya path'i. +* `headers` - Eklenecek özel header’lar; dictionary olarak. +* `media_type` - Media type’ı veren string. Ayarlanmazsa, dosya adı veya path kullanılarak media type tahmin edilir. +* `filename` - Ayarlanırsa response içindeki `Content-Disposition`’a dahil edilir. + +File response'ları uygun `Content-Length`, `Last-Modified` ve `ETag` header’larını içerir. + +{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *} + +`response_class` parametresini de kullanabilirsiniz: + +{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *} + +Bu durumda *path operation* function’ınızdan doğrudan dosya path'ini döndürebilirsiniz. + +## Özel response class { #custom-response-class } + +`Response`’dan türeterek kendi özel response class’ınızı oluşturabilir ve kullanabilirsiniz. + +Örneğin, dahil gelen `ORJSONResponse` class’ında kullanılmayan bazı özel ayarlarla `orjson` kullanmak istediğinizi varsayalım. + +Diyelim ki girintili ve biçimlendirilmiş JSON döndürmek istiyorsunuz; bunun için `orjson.OPT_INDENT_2` seçeneğini kullanmak istiyorsunuz. + +Bir `CustomORJSONResponse` oluşturabilirsiniz. Burada yapmanız gereken temel şey, content’i `bytes` olarak döndüren bir `Response.render(content)` metodu yazmaktır: + +{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *} + +Artık şunu döndürmek yerine: + +```json +{"message": "Hello World"} +``` + +...bu response şunu döndürür: + +```json +{ + "message": "Hello World" +} +``` + +Elbette JSON’u formatlamaktan çok daha iyi şekillerde bundan faydalanabilirsiniz. 😉 + +## Varsayılan response class { #default-response-class } + +Bir **FastAPI** class instance’ı veya bir `APIRouter` oluştururken, varsayılan olarak hangi response class’ının kullanılacağını belirtebilirsiniz. + +Bunu tanımlayan parametre `default_response_class`’tır. + +Aşağıdaki örnekte **FastAPI**, tüm *path operations* için varsayılan olarak `JSONResponse` yerine `ORJSONResponse` kullanır. + +{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *} + +/// tip | İpucu + +Daha önce olduğu gibi, *path operations* içinde `response_class`’ı yine override edebilirsiniz. + +/// + +## Ek dokümantasyon { #additional-documentation } + +OpenAPI’de media type’ı ve daha birçok detayı `responses` kullanarak da tanımlayabilirsiniz: [OpenAPI’de Ek Response'lar](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/tr/docs/advanced/dataclasses.md b/docs/tr/docs/advanced/dataclasses.md new file mode 100644 index 0000000000..2639760070 --- /dev/null +++ b/docs/tr/docs/advanced/dataclasses.md @@ -0,0 +1,95 @@ +# Dataclass Kullanımı { #using-dataclasses } + +FastAPI, **Pydantic** üzerine inşa edilmiştir ve request/response tanımlamak için Pydantic model'lerini nasıl kullanacağınızı gösteriyordum. + +Ancak FastAPI, `dataclasses` kullanmayı da aynı şekilde destekler: + +{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *} + +Bu destek hâlâ **Pydantic** sayesinde vardır; çünkü Pydantic, `dataclasses` için dahili destek sunar. + +Yani yukarıdaki kod Pydantic'i doğrudan kullanmasa bile, FastAPI bu standart dataclass'ları Pydantic'in kendi dataclass biçimine dönüştürmek için Pydantic'i kullanmaktadır. + +Ve elbette aynı özellikleri destekler: + +* veri doğrulama (data validation) +* veri serileştirme (data serialization) +* veri dokümantasyonu (data documentation), vb. + +Bu, Pydantic model'lerinde olduğu gibi çalışır. Aslında arka planda da aynı şekilde, Pydantic kullanılarak yapılır. + +/// info | Bilgi + +Dataclass'ların, Pydantic model'lerinin yapabildiği her şeyi yapamadığını unutmayın. + +Bu yüzden yine de Pydantic model'lerini kullanmanız gerekebilir. + +Ancak elinizde zaten bir sürü dataclass varsa, bunları FastAPI ile bir web API'yi beslemek için kullanmak güzel bir numaradır. 🤓 + +/// + +## `response_model` İçinde Dataclass'lar { #dataclasses-in-response-model } + +`response_model` parametresinde `dataclasses` da kullanabilirsiniz: + +{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *} + +Dataclass otomatik olarak bir Pydantic dataclass'ına dönüştürülür. + +Bu sayede şeması API docs kullanıcı arayüzünde görünür: + + + +## İç İçe Veri Yapılarında Dataclass'lar { #dataclasses-in-nested-data-structures } + +İç içe veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları da birleştirebilirsiniz. + +Bazı durumlarda yine de Pydantic'in `dataclasses` sürümünü kullanmanız gerekebilir. Örneğin, otomatik oluşturulan API dokümantasyonunda hata alıyorsanız. + +Bu durumda standart `dataclasses` yerine, drop-in replacement olan `pydantic.dataclasses` kullanabilirsiniz: + +{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *} + +1. `field` hâlâ standart `dataclasses` içinden import edilir. + +2. `pydantic.dataclasses`, `dataclasses` için bir drop-in replacement'tır. + +3. `Author` dataclass'ı, `Item` dataclass'larından oluşan bir liste içerir. + +4. `Author` dataclass'ı, `response_model` parametresi olarak kullanılır. + +5. Request body olarak dataclass'larla birlikte diğer standart type annotation'ları da kullanabilirsiniz. + + Bu örnekte, `Item` dataclass'larından oluşan bir listedir. + +6. Burada `items` içeren bir dictionary döndürüyoruz; `items` bir dataclass listesi. + + FastAPI, veriyi JSON'a serializing etmeyi yine başarır. + +7. Burada `response_model`, `Author` dataclass'larından oluşan bir listenin type annotation'ını kullanıyor. + + Yine `dataclasses` ile standart type annotation'ları birleştirebilirsiniz. + +8. Bu *path operation function*, `async def` yerine normal `def` kullanıyor. + + Her zaman olduğu gibi, FastAPI'de ihtiyaca göre `def` ve `async def`’i birlikte kullanabilirsiniz. + + Hangisini ne zaman kullanmanız gerektiğine dair hızlı bir hatırlatma isterseniz, [`async` ve `await`](../async.md#in-a-hurry){.internal-link target=_blank} dokümanındaki _"In a hurry?"_ bölümüne bakın. + +9. Bu *path operation function* dataclass döndürmüyor (isterse döndürebilir), onun yerine dahili verilerle bir dictionary listesi döndürüyor. + + FastAPI, response'u dönüştürmek için (dataclass'ları içeren) `response_model` parametresini kullanacaktır. + +Karmaşık veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları pek çok farklı kombinasyonda birleştirebilirsiniz. + +Daha spesifik ayrıntılar için yukarıdaki kod içi annotation ipuçlarına bakın. + +## Daha Fazla Öğrenin { #learn-more } + +`dataclasses`'ı diğer Pydantic model'leriyle de birleştirebilir, onlardan kalıtım alabilir, kendi model'lerinize dahil edebilirsiniz, vb. + +Daha fazlası için Pydantic'in dataclasses dokümantasyonuna bakın. + +## Sürüm { #version } + +Bu özellik FastAPI `0.67.0` sürümünden beri mevcuttur. 🔖 diff --git a/docs/tr/docs/advanced/events.md b/docs/tr/docs/advanced/events.md new file mode 100644 index 0000000000..257b952f95 --- /dev/null +++ b/docs/tr/docs/advanced/events.md @@ -0,0 +1,165 @@ +# Lifespan Olayları { #lifespan-events } + +Uygulama **başlamadan** önce çalıştırılması gereken mantığı (kodu) tanımlayabilirsiniz. Bu, bu kodun **bir kez**, uygulama **request almaya başlamadan önce** çalıştırılacağı anlamına gelir. + +Benzer şekilde, uygulama **kapanırken** çalıştırılması gereken mantığı (kodu) da tanımlayabilirsiniz. Bu durumda bu kod, muhtemelen **çok sayıda request** işlendi **sonra**, **bir kez** çalıştırılır. + +Bu kod, uygulama request almaya **başlamadan** önce ve request’leri işlemeyi **bitirdikten** hemen sonra çalıştığı için, uygulamanın tüm **lifespan**’ını (birazdan "lifespan" kelimesi önemli olacak 😉) kapsar. + +Bu yaklaşım, tüm uygulama boyunca kullanacağınız ve request’ler arasında **paylaşılan** **resource**’ları kurmak ve/veya sonrasında bunları **temizlemek** için çok faydalıdır. Örneğin bir veritabanı connection pool’u ya da paylaşılan bir machine learning modelini yüklemek gibi. + +## Kullanım Senaryosu { #use-case } + +Önce bir **kullanım senaryosu** örneğiyle başlayalım, sonra bunu bununla nasıl çözeceğimize bakalım. + +Request’leri işlemek için kullanmak istediğiniz bazı **machine learning modelleriniz** olduğunu hayal edelim. 🤖 + +Aynı modeller request’ler arasında paylaşılır; yani request başına bir model, kullanıcı başına bir model vb. gibi değil. + +Modeli yüklemenin, diskten çok fazla **data** okunması gerektiği için **oldukça uzun sürebildiğini** düşünelim. Dolayısıyla bunu her request için yapmak istemezsiniz. + +Modeli modülün/dosyanın en üst seviyesinde yükleyebilirdiniz; ancak bu, basit bir otomatik test çalıştırdığınızda bile **modelin yükleneceği** anlamına gelir. Böyle olunca test, kodun bağımsız bir kısmını çalıştırabilmek için önce modelin yüklenmesini beklemek zorunda kalır ve **yavaş** olur. + +Burada çözeceğimiz şey bu: modeli request’ler işlenmeden önce yükleyelim, ama kod yüklenirken değil; yalnızca uygulama request almaya başlamadan hemen önce. + +## Lifespan { #lifespan } + +Bu *startup* ve *shutdown* mantığını, `FastAPI` uygulamasının `lifespan` parametresi ve bir "context manager" kullanarak tanımlayabilirsiniz (bunun ne olduğunu birazdan göstereceğim). + +Önce bir örnekle başlayıp sonra ayrıntılarına bakalım. + +Aşağıdaki gibi `yield` kullanan async bir `lifespan()` fonksiyonu oluşturuyoruz: + +{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *} + +Burada, `yield` öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionary’e koyarak, modeli yükleme gibi maliyetli bir *startup* işlemini simüle ediyoruz. Bu kod, *startup* sırasında, uygulama **request almaya başlamadan önce** çalıştırılır. + +Ardından `yield`’den hemen sonra modeli bellekten kaldırıyoruz (unload). Bu kod, uygulama **request’leri işlemeyi bitirdikten sonra**, *shutdown*’dan hemen önce çalıştırılır. Örneğin memory veya GPU gibi resource’ları serbest bırakabilir. + +/// tip | İpucu + +`shutdown`, uygulamayı **durdurduğunuzda** gerçekleşir. + +Belki yeni bir sürüm başlatmanız gerekiyordur, ya da çalıştırmaktan sıkılmışsınızdır. 🤷 + +/// + +### Lifespan fonksiyonu { #lifespan-function } + +Dikkat edilmesi gereken ilk şey, `yield` içeren async bir fonksiyon tanımlıyor olmamız. Bu, `yield` kullanan Dependencies’e oldukça benzer. + +{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *} + +Fonksiyonun `yield`’den önceki kısmı, uygulama başlamadan **önce** çalışır. + +`yield`’den sonraki kısım ise, uygulama işini bitirdikten **sonra** çalışır. + +### Async Context Manager { #async-context-manager } + +Bakarsanız, fonksiyon `@asynccontextmanager` ile dekore edilmiş. + +Bu da fonksiyonu "**async context manager**" denen şeye dönüştürür. + +{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} + +Python’da **context manager**, `with` ifadesi içinde kullanabildiğiniz bir yapıdır. Örneğin `open()` bir context manager olarak kullanılabilir: + +```Python +with open("file.txt") as file: + file.read() +``` + +Python’ın güncel sürümlerinde bir de **async context manager** vardır. Bunu `async with` ile kullanırsınız: + +```Python +async with lifespan(app): + await do_stuff() +``` + +Yukarıdaki gibi bir context manager veya async context manager oluşturduğunuzda, yaptığı şey şudur: `with` bloğuna girmeden önce `yield`’den önceki kodu çalıştırır, `with` bloğundan çıktıktan sonra da `yield`’den sonraki kodu çalıştırır. + +Yukarıdaki kod örneğimizde bunu doğrudan kullanmıyoruz; bunun yerine FastAPI’ye veriyoruz ki o kullansın. + +`FastAPI` uygulamasının `lifespan` parametresi bir **async context manager** alır; dolayısıyla oluşturduğumuz yeni `lifespan` async context manager’ını buraya geçebiliriz. + +{* ../../docs_src/events/tutorial003_py39.py hl[22] *} + +## Alternatif Events (kullanımdan kaldırıldı) { #alternative-events-deprecated } + +/// warning | Uyarı + +*startup* ve *shutdown* işlemlerini yönetmenin önerilen yolu, yukarıda anlatıldığı gibi `FastAPI` uygulamasının `lifespan` parametresini kullanmaktır. Bir `lifespan` parametresi sağlarsanız, `startup` ve `shutdown` event handler’ları artık çağrılmaz. Ya tamamen `lifespan` ya da tamamen events; ikisi birden değil. + +Muhtemelen bu bölümü atlayabilirsiniz. + +/// + +*startup* ve *shutdown* sırasında çalıştırılacak bu mantığı tanımlamanın alternatif bir yolu daha vardır. + +Uygulama başlamadan önce veya uygulama kapanırken çalıştırılması gereken event handler’ları (fonksiyonları) tanımlayabilirsiniz. + +Bu fonksiyonlar `async def` ile veya normal `def` ile tanımlanabilir. + +### `startup` eventi { #startup-event } + +Uygulama başlamadan önce çalıştırılacak bir fonksiyon eklemek için, `"startup"` event’i ile tanımlayın: + +{* ../../docs_src/events/tutorial001_py39.py hl[8] *} + +Bu durumda `startup` event handler fonksiyonu, "database" öğesini (sadece bir `dict`) bazı değerlerle başlatır. + +Birden fazla event handler fonksiyonu ekleyebilirsiniz. + +Ve tüm `startup` event handler’ları tamamlanmadan uygulamanız request almaya başlamaz. + +### `shutdown` eventi { #shutdown-event } + +Uygulama kapanırken çalıştırılacak bir fonksiyon eklemek için, `"shutdown"` event’i ile tanımlayın: + +{* ../../docs_src/events/tutorial002_py39.py hl[6] *} + +Burada `shutdown` event handler fonksiyonu, `log.txt` dosyasına `"Application shutdown"` satırını yazar. + +/// info | Bilgi + +`open()` fonksiyonunda `mode="a"` "append" anlamına gelir; yani satır, önceki içeriği silmeden dosyada ne varsa onun sonuna eklenir. + +/// + +/// tip | İpucu + +Dikkat edin, bu örnekte bir dosyayla etkileşen standart Python `open()` fonksiyonunu kullanıyoruz. + +Dolayısıyla disk’e yazılmasını beklemeyi gerektiren I/O (input/output) söz konusu. + +Ancak `open()` `async` ve `await` kullanmaz. + +Bu yüzden event handler fonksiyonunu `async def` yerine standart `def` ile tanımlarız. + +/// + +### `startup` ve `shutdown` birlikte { #startup-and-shutdown-together } + +*startup* ve *shutdown* mantığınızın birbiriyle bağlantılı olma ihtimali yüksektir; bir şeyi başlatıp sonra bitirmek, bir resource edinip sonra serbest bırakmak vb. isteyebilirsiniz. + +Bunu, ortak mantık veya değişken paylaşmayan ayrı fonksiyonlarda yapmak daha zordur; çünkü değerleri global değişkenlerde tutmanız veya benzer numaralar yapmanız gerekir. + +Bu nedenle artık bunun yerine, yukarıda açıklandığı gibi `lifespan` kullanmanız önerilmektedir. + +## Teknik Detaylar { #technical-details } + +Meraklı nerd’ler için küçük bir teknik detay. 🤓 + +Altta, ASGI teknik spesifikasyonunda bu, Lifespan Protocol’ün bir parçasıdır ve `startup` ile `shutdown` adında event’ler tanımlar. + +/// info | Bilgi + +Starlette `lifespan` handler’ları hakkında daha fazlasını Starlette's Lifespan docs içinde okuyabilirsiniz. + +Ayrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan state’i nasıl yöneteceğinizi de kapsar. + +/// + +## Alt Uygulamalar { #sub-applications } + +🚨 Unutmayın: Bu lifespan event’leri (`startup` ve `shutdown`) yalnızca ana uygulama için çalıştırılır; [Alt Uygulamalar - Mounts](sub-applications.md){.internal-link target=_blank} için çalıştırılmaz. diff --git a/docs/tr/docs/advanced/generate-clients.md b/docs/tr/docs/advanced/generate-clients.md new file mode 100644 index 0000000000..af278f2fef --- /dev/null +++ b/docs/tr/docs/advanced/generate-clients.md @@ -0,0 +1,208 @@ +# SDK Üretme { #generating-sdks } + +**FastAPI**, **OpenAPI** spesifikasyonunu temel aldığı için API'leri birçok aracın anlayabildiği standart bir formatta tanımlanabilir. + +Bu sayede güncel **dokümantasyon**, birden fazla dilde istemci kütüphaneleri (**SDKs**) ve kodunuzla senkron kalan **test** veya **otomasyon iş akışları** üretmek kolaylaşır. + +Bu rehberde, FastAPI backend'iniz için bir **TypeScript SDK** üretmeyi öğreneceksiniz. + +## Açık Kaynak SDK Üreteçleri { #open-source-sdk-generators } + +Esnek bir seçenek olan OpenAPI Generator, **birçok programlama dilini** destekler ve OpenAPI spesifikasyonunuzdan SDK üretebilir. + +**TypeScript client**'lar için Hey API, TypeScript ekosistemi için özel olarak tasarlanmış, optimize bir deneyim sunan bir çözümdür. + +Daha fazla SDK üretecini OpenAPI.Tools üzerinde keşfedebilirsiniz. + +/// tip | İpucu + +FastAPI otomatik olarak **OpenAPI 3.1** spesifikasyonları üretir; bu yüzden kullanacağınız aracın bu sürümü desteklemesi gerekir. + +/// + +## FastAPI Sponsorlarından SDK Üreteçleri { #sdk-generators-from-fastapi-sponsors } + +Bu bölüm, FastAPI'yi sponsorlayan şirketlerin sunduğu **yatırım destekli** ve **şirket destekli** çözümleri öne çıkarır. Bu ürünler, yüksek kaliteli üretilen SDK'ların üzerine **ek özellikler** ve **entegrasyonlar** sağlar. + +✨ [**FastAPI'ye sponsor olarak**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ bu şirketler, framework'ün ve **ekosisteminin** sağlıklı ve **sürdürülebilir** kalmasına yardımcı olur. + +Sponsor olmaları aynı zamanda FastAPI **topluluğuna** (size) güçlü bir bağlılığı da gösterir; yalnızca **iyi bir hizmet** sunmayı değil, aynı zamanda **güçlü ve gelişen bir framework** olan FastAPI'yi desteklemeyi de önemsediklerini gösterir. 🙇 + +Örneğin şunları deneyebilirsiniz: + +* Speakeasy +* Stainless +* liblab + +Bu çözümlerin bazıları açık kaynak olabilir veya ücretsiz katman sunabilir; yani finansal bir taahhüt olmadan deneyebilirsiniz. Başka ticari SDK üreteçleri de vardır ve internette bulunabilir. 🤓 + +## TypeScript SDK Oluşturma { #create-a-typescript-sdk } + +Basit bir FastAPI uygulamasıyla başlayalım: + +{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *} + +*Path operation*'ların, request payload ve response payload için kullandıkları modelleri `Item` ve `ResponseMessage` modelleriyle tanımladıklarına dikkat edin. + +### API Dokümanları { #api-docs } + +`/docs` adresine giderseniz, request'lerde gönderilecek ve response'larda alınacak veriler için **schema**'ları içerdiğini görürsünüz: + + + +Bu schema'ları görebilirsiniz, çünkü uygulamada modellerle birlikte tanımlandılar. + +Bu bilgi uygulamanın **OpenAPI schema**'sında bulunur ve sonrasında API dokümanlarında gösterilir. + +OpenAPI'ye dahil edilen, modellerden gelen bu bilginin aynısı **client code üretmek** için kullanılabilir. + +### Hey API { #hey-api } + +Modelleri olan bir FastAPI uygulamamız olduğunda, Hey API ile bir TypeScript client üretebiliriz. Bunu yapmanın en hızlı yolu npx kullanmaktır. + +```sh +npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client +``` + +Bu komut `./src/client` içine bir TypeScript SDK üretecektir. + +Web sitelerinde `@hey-api/openapi-ts` kurulumunu öğrenebilir ve üretilen çıktıyı inceleyebilirsiniz. + +### SDK'yı Kullanma { #using-the-sdk } + +Artık client code'u import edip kullanabilirsiniz. Şuna benzer görünebilir; method'lar için otomatik tamamlama aldığınıza dikkat edin: + + + +Ayrıca gönderilecek payload için de otomatik tamamlama alırsınız: + + + +/// tip | İpucu + +`name` ve `price` için otomatik tamamlamaya dikkat edin; bunlar FastAPI uygulamasında, `Item` modelinde tanımlanmıştı. + +/// + +Gönderdiğiniz veriler için satır içi hatalar (inline errors) da alırsınız: + + + +Response objesi de otomatik tamamlama sunacaktır: + + + +## Tag'lerle FastAPI Uygulaması { #fastapi-app-with-tags } + +Birçok durumda FastAPI uygulamanız daha büyük olacaktır ve farklı *path operation* gruplarını ayırmak için muhtemelen tag'leri kullanacaksınız. + +Örneğin **items** için bir bölüm, **users** için başka bir bölüm olabilir ve bunları tag'lerle ayırabilirsiniz: + +{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *} + +### Tag'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-tags } + +Tag'leri kullanan bir FastAPI uygulaması için client ürettiğinizde, genelde client code da tag'lere göre ayrılır. + +Bu sayede client code tarafında her şey doğru şekilde sıralanır ve gruplandırılır: + + + +Bu örnekte şunlar var: + +* `ItemsService` +* `UsersService` + +### Client Method İsimleri { #client-method-names } + +Şu an üretilen `createItemItemsPost` gibi method isimleri çok temiz görünmüyor: + +```TypeScript +ItemsService.createItemItemsPost({name: "Plumbus", price: 5}) +``` + +...çünkü client üreteci, her *path operation* için OpenAPI'nin dahili **operation ID** değerini kullanır. + +OpenAPI, her operation ID'nin tüm *path operation*'lar arasında benzersiz olmasını ister. Bu yüzden FastAPI; operation ID'yi benzersiz tutabilmek için **function adı**, **path** ve **HTTP method/operation** bilgilerini birleştirerek üretir. + +Ancak bunu bir sonraki adımda nasıl iyileştirebileceğinizi göstereceğim. 🤓 + +## Özel Operation ID'ler ve Daha İyi Method İsimleri { #custom-operation-ids-and-better-method-names } + +Bu operation ID'lerin **üretilme** şeklini **değiştirerek**, client'larda daha basit **method isimleri** elde edebilirsiniz. + +Bu durumda, her operation ID'nin **benzersiz** olduğundan başka bir şekilde emin olmanız gerekir. + +Örneğin, her *path operation*'ın bir tag'i olmasını sağlayabilir ve operation ID'yi **tag** ve *path operation* **adı**na (function adı) göre üretebilirsiniz. + +### Benzersiz ID Üreten Özel Fonksiyon { #custom-generate-unique-id-function } + +FastAPI, her *path operation* için bir **unique ID** kullanır. Bu ID, **operation ID** için ve ayrıca request/response'lar için gerekebilecek özel model isimleri için de kullanılır. + +Bu fonksiyonu özelleştirebilirsiniz. Bir `APIRoute` alır ve string döndürür. + +Örneğin burada ilk tag'i (muhtemelen tek tag'iniz olur) ve *path operation* adını (function adı) kullanıyor. + +Sonrasında bu özel fonksiyonu `generate_unique_id_function` parametresiyle **FastAPI**'ye geçebilirsiniz: + +{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *} + +### Özel Operation ID'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-custom-operation-ids } + +Artık client'ı tekrar üretirseniz, geliştirilmiş method isimlerini göreceksiniz: + + + +Gördüğünüz gibi method isimleri artık önce tag'i, sonra function adını içeriyor; URL path'i ve HTTP operation bilgisini artık taşımıyor. + +### Client Üretecine Vermeden Önce OpenAPI Spesifikasyonunu Ön İşlemek { #preprocess-the-openapi-specification-for-the-client-generator } + +Üretilen kodda hâlâ bazı **tekrarlanan bilgiler** var. + +Bu method'un **items** ile ilişkili olduğunu zaten biliyoruz; çünkü bu kelime `ItemsService` içinde var (tag'den geliyor). Ama method adında da tag adı önek olarak duruyor. 😕 + +OpenAPI genelinde muhtemelen bunu korumak isteriz; çünkü operation ID'lerin **benzersiz** olmasını sağlar. + +Ancak üretilen client için, client'ları üretmeden hemen önce OpenAPI operation ID'lerini **değiştirip**, method isimlerini daha hoş ve **temiz** hale getirebiliriz. + +OpenAPI JSON'u `openapi.json` diye bir dosyaya indirip, şu tarz bir script ile **öndeki tag'i kaldırabiliriz**: + +{* ../../docs_src/generate_clients/tutorial004_py39.py *} + +//// tab | Node.js + +```Javascript +{!> ../../docs_src/generate_clients/tutorial004.js!} +``` + +//// + +Bununla operation ID'ler `items-get_items` gibi değerlerden sadece `get_items` olacak şekilde yeniden adlandırılır; böylece client üreteci daha basit method isimleri üretebilir. + +### Ön İşlenmiş OpenAPI ile TypeScript Client Üretme { #generate-a-typescript-client-with-the-preprocessed-openapi } + +Sonuç artık bir `openapi.json` dosyasında olduğuna göre, input konumunu güncellemeniz gerekir: + +```sh +npx @hey-api/openapi-ts -i ./openapi.json -o src/client +``` + +Yeni client'ı ürettikten sonra, tüm **otomatik tamamlama**, **satır içi hatalar**, vb. ile birlikte **temiz method isimleri** elde edersiniz: + + + +## Faydalar { #benefits } + +Otomatik üretilen client'ları kullanınca şu alanlarda **otomatik tamamlama** elde edersiniz: + +* Method'lar. +* Body'deki request payload'ları, query parametreleri, vb. +* Response payload'ları. + +Ayrıca her şey için **satır içi hatalar** (inline errors) da olur. + +Backend kodunu her güncellediğinizde ve frontend'i **yeniden ürettiğinizde**, yeni *path operation*'lar method olarak eklenir, eskileri kaldırılır ve diğer değişiklikler de üretilen koda yansır. 🤓 + +Bu, bir şey değiştiğinde client code'a otomatik olarak **yansıyacağı** anlamına gelir. Ayrıca client'ı **build** ettiğinizde, kullanılan verilerde bir **uyuşmazlık** (mismatch) varsa hata alırsınız. + +Böylece üretimde son kullanıcılara hata yansımasını beklemek ve sonra sorunun nerede olduğunu debug etmeye çalışmak yerine, geliştirme sürecinin çok erken aşamalarında **birçok hatayı tespit edersiniz**. ✨ diff --git a/docs/tr/docs/advanced/middleware.md b/docs/tr/docs/advanced/middleware.md new file mode 100644 index 0000000000..a22644a090 --- /dev/null +++ b/docs/tr/docs/advanced/middleware.md @@ -0,0 +1,97 @@ +# İleri Seviye Middleware { #advanced-middleware } + +Ana tutorial'da uygulamanıza [Özel Middleware](../tutorial/middleware.md){.internal-link target=_blank} eklemeyi gördünüz. + +Ardından [`CORSMiddleware` ile CORS'u yönetmeyi](../tutorial/cors.md){.internal-link target=_blank} de okudunuz. + +Bu bölümde diğer middleware'leri nasıl kullanacağımıza bakacağız. + +## ASGI middleware'leri ekleme { #adding-asgi-middlewares } + +**FastAPI**, Starlette üzerine kurulu olduğu ve ASGI spesifikasyonunu uyguladığı için, herhangi bir ASGI middleware'ini kullanabilirsiniz. + +Bir middleware'in çalışması için özellikle FastAPI ya da Starlette için yazılmış olması gerekmez; ASGI spec'ine uyduğu sürece yeterlidir. + +Genel olarak ASGI middleware'leri, ilk argüman olarak bir ASGI app almayı bekleyen class'lar olur. + +Dolayısıyla üçüncü taraf ASGI middleware'lerinin dokümantasyonunda muhtemelen şöyle bir şey yapmanızı söylerler: + +```Python +from unicorn import UnicornMiddleware + +app = SomeASGIApp() + +new_app = UnicornMiddleware(app, some_config="rainbow") +``` + +Ancak FastAPI (aslında Starlette) bunu yapmanın daha basit bir yolunu sunar; böylece dahili middleware'ler server hatalarını doğru şekilde ele alır ve özel exception handler'lar düzgün çalışır. + +Bunun için `app.add_middleware()` kullanırsınız (CORS örneğindeki gibi). + +```Python +from fastapi import FastAPI +from unicorn import UnicornMiddleware + +app = FastAPI() + +app.add_middleware(UnicornMiddleware, some_config="rainbow") +``` + +`app.add_middleware()` ilk argüman olarak bir middleware class'ı alır ve middleware'e aktarılacak ek argümanları da kabul eder. + +## Entegre middleware'ler { #integrated-middlewares } + +**FastAPI**, yaygın kullanım senaryoları için birkaç middleware içerir; şimdi bunları nasıl kullanacağımıza bakacağız. + +/// note | Teknik Detaylar + +Bir sonraki örneklerde `from starlette.middleware.something import SomethingMiddleware` kullanmanız da mümkündür. + +**FastAPI**, size (geliştirici olarak) kolaylık olsun diye `fastapi.middleware` içinde bazı middleware'leri sağlar. Ancak mevcut middleware'lerin çoğu doğrudan Starlette'ten gelir. + +/// + +## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware } + +Gelen tüm request'lerin `https` veya `wss` olmasını zorunlu kılar. + +`http` veya `ws` olarak gelen herhangi bir request, bunun yerine güvenli şemaya redirect edilir. + +{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *} + +## `TrustedHostMiddleware` { #trustedhostmiddleware } + +HTTP Host Header saldırılarına karşı korunmak için, gelen tüm request'lerde `Host` header'ının doğru ayarlanmış olmasını zorunlu kılar. + +{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *} + +Aşağıdaki argümanlar desteklenir: + +* `allowed_hosts` - Hostname olarak izin verilmesi gereken domain adlarının listesi. `*.example.com` gibi wildcard domain'ler subdomain eşleştirmesi için desteklenir. Herhangi bir hostname'e izin vermek için `allowed_hosts=["*"]` kullanın veya middleware'i hiç eklemeyin. +* `www_redirect` - True olarak ayarlanırsa, izin verilen host'ların www olmayan sürümlerine gelen request'ler www sürümlerine redirect edilir. Varsayılanı `True`'dur. + +Gelen bir request doğru şekilde doğrulanmazsa `400` response gönderilir. + +## `GZipMiddleware` { #gzipmiddleware } + +`Accept-Encoding` header'ında `"gzip"` içeren herhangi bir request için GZip response'larını yönetir. + +Middleware hem standart hem de streaming response'ları ele alır. + +{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *} + +Aşağıdaki argümanlar desteklenir: + +* `minimum_size` - Bayt cinsinden bu minimum boyuttan küçük response'lara GZip uygulama. Varsayılanı `500`'dür. +* `compresslevel` - GZip sıkıştırması sırasında kullanılır. 1 ile 9 arasında bir tamsayıdır. Varsayılanı `9`'dur. Daha düşük değer daha hızlı sıkıştırma ama daha büyük dosya boyutları üretir; daha yüksek değer daha yavaş sıkıştırma ama daha küçük dosya boyutları üretir. + +## Diğer middleware'ler { #other-middlewares } + +Başka birçok ASGI middleware'i vardır. + +Örneğin: + +* Uvicorn'un `ProxyHeadersMiddleware`'i +* MessagePack + +Diğer mevcut middleware'leri görmek için Starlette'in Middleware dokümanlarına ve ASGI Awesome List listesine bakın. diff --git a/docs/tr/docs/advanced/openapi-callbacks.md b/docs/tr/docs/advanced/openapi-callbacks.md new file mode 100644 index 0000000000..61135b7e01 --- /dev/null +++ b/docs/tr/docs/advanced/openapi-callbacks.md @@ -0,0 +1,186 @@ +# OpenAPI Callback'leri { #openapi-callbacks } + +Başka biri tarafından (muhtemelen API'nizi *kullanacak* olan aynı geliştirici tarafından) oluşturulmuş bir *external API*'ye request tetikleyebilen bir *path operation* ile bir API oluşturabilirsiniz. + +API uygulamanızın *external API*'yi çağırdığı sırada gerçekleşen sürece "callback" denir. Çünkü dış geliştiricinin yazdığı yazılım API'nize bir request gönderir ve ardından API'niz *geri çağrı* yaparak (*call back*), bir *external API*'ye request gönderir (muhtemelen aynı geliştiricinin oluşturduğu). + +Bu durumda, o external API'nin nasıl görünmesi *gerektiğini* dokümante etmek isteyebilirsiniz. Hangi *path operation*'a sahip olmalı, hangi body'yi beklemeli, hangi response'u döndürmeli, vb. + +## Callback'leri olan bir uygulama { #an-app-with-callbacks } + +Bunların hepsine bir örnekle bakalım. + +Fatura oluşturmayı sağlayan bir uygulama geliştirdiğinizi düşünün. + +Bu faturaların `id`, `title` (opsiyonel), `customer` ve `total` alanları olacak. + +API'nizin kullanıcısı (external bir geliştirici) API'nizde bir POST request ile fatura oluşturacak. + +Sonra API'niz (varsayalım ki): + +* Faturayı external geliştiricinin bir müşterisine gönderir. +* Parayı tahsil eder. +* API kullanıcısına (external geliştiriciye) tekrar bir bildirim gönderir. + * Bu, external geliştiricinin sağladığı bir *external API*'ye (*sizin API'nizden*) bir POST request gönderilerek yapılır (işte bu "callback"tir). + +## Normal **FastAPI** uygulaması { #the-normal-fastapi-app } + +Önce callback eklemeden önce normal API uygulamasının nasıl görüneceğine bakalım. + +Bir `Invoice` body alacak bir *path operation*'ı ve callback için URL'yi taşıyacak `callback_url` adlı bir query parametresi olacak. + +Bu kısım oldukça standart; kodun çoğu muhtemelen size zaten tanıdık gelecektir: + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *} + +/// tip | İpucu + +`callback_url` query parametresi, Pydantic'in Url tipini kullanır. + +/// + +Tek yeni şey, *path operation decorator*'ına argüman olarak verilen `callbacks=invoices_callback_router.routes`. Bunun ne olduğuna şimdi bakacağız. + +## Callback'i dokümante etmek { #documenting-the-callback } + +Callback'in gerçek kodu, büyük ölçüde sizin API uygulamanıza bağlıdır. + +Ve bir uygulamadan diğerine oldukça değişebilir. + +Sadece bir-iki satır kod bile olabilir, örneğin: + +```Python +callback_url = "https://example.com/api/v1/invoices/events/" +httpx.post(callback_url, json={"description": "Invoice paid", "paid": True}) +``` + +Ancak callback'in belki de en önemli kısmı, API'nizin kullanıcısının (external geliştiricinin) *external API*'yi doğru şekilde uyguladığından emin olmaktır; çünkü *sizin API'niz* callback'in request body'sinde belirli veriler gönderecektir, vb. + +Dolayısıyla sıradaki adım olarak, *sizin API'nizden* callback almak için o *external API*'nin nasıl görünmesi gerektiğini dokümante eden kodu ekleyeceğiz. + +Bu dokümantasyon, API'nizde `/docs` altındaki Swagger UI'da görünecek ve external geliştiricilere *external API*'yi nasıl inşa edeceklerini gösterecek. + +Bu örnek callback'in kendisini implemente etmiyor (o zaten tek satır kod olabilir), sadece dokümantasyon kısmını ekliyor. + +/// tip | İpucu + +Gerçek callback, sadece bir HTTP request'tir. + +Callback'i kendiniz implemente ederken HTTPX veya Requests gibi bir şey kullanabilirsiniz. + +/// + +## Callback dokümantasyon kodunu yazın { #write-the-callback-documentation-code } + +Bu kod uygulamanızda çalıştırılmayacak; sadece o *external API*'nin nasıl görünmesi gerektiğini *dokümante etmek* için gerekiyor. + +Ancak **FastAPI** ile bir API için otomatik dokümantasyonu kolayca nasıl üreteceğinizi zaten biliyorsunuz. + +O halde aynı bilgiyi kullanarak, *external API*'nin nasıl görünmesi gerektiğini dokümante edeceğiz... external API'nin implemente etmesi gereken *path operation*'ları oluşturarak (API'nizin çağıracağı olanlar). + +/// tip | İpucu + +Bir callback'i dokümante eden kodu yazarken, kendinizi *external geliştirici* olarak hayal etmek faydalı olabilir. Ve şu anda *sizin API'nizi* değil, *external API*'yi implemente ettiğinizi düşünün. + +Bu bakış açısını (external geliştiricinin bakış açısını) geçici olarak benimsemek; parametreleri nereye koyacağınızı, body için Pydantic modelini, response için modelini vb. external API tarafında nasıl tasarlayacağınızı daha net hale getirebilir. + +/// + +### Bir callback `APIRouter` oluşturun { #create-a-callback-apirouter } + +Önce bir veya daha fazla callback içerecek yeni bir `APIRouter` oluşturun. + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *} + +### Callback *path operation*'ını oluşturun { #create-the-callback-path-operation } + +Callback *path operation*'ını oluşturmak için, yukarıda oluşturduğunuz aynı `APIRouter`'ı kullanın. + +Normal bir FastAPI *path operation*'ı gibi görünmelidir: + +* Muhtemelen alması gereken body'nin bir deklarasyonu olmalı, örn. `body: InvoiceEvent`. +* Ayrıca döndürmesi gereken response'un deklarasyonu da olabilir, örn. `response_model=InvoiceEventReceived`. + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *} + +Normal bir *path operation*'dan 2 temel farkı vardır: + +* Gerçek bir koda ihtiyaç duymaz; çünkü uygulamanız bu kodu asla çağırmayacak. Bu yalnızca *external API*'yi dokümante etmek için kullanılır. Yani fonksiyon sadece `pass` içerebilir. +* *path*, bir OpenAPI 3 expression (aşağıda daha fazlası) içerebilir; böylece parametreler ve *sizin API'nize* gönderilen orijinal request'in bazı parçalarıyla değişkenler kullanılabilir. + +### Callback path ifadesi { #the-callback-path-expression } + +Callback *path*'i, *sizin API'nize* gönderilen orijinal request'in bazı parçalarını içerebilen bir OpenAPI 3 expression barındırabilir. + +Bu örnekte, bu bir `str`: + +```Python +"{$callback_url}/invoices/{$request.body.id}" +``` + +Yani API'nizin kullanıcısı (external geliştirici) *sizin API'nize* şu adrese bir request gönderirse: + +``` +https://yourapi.com/invoices/?callback_url=https://www.external.org/events +``` + +ve JSON body şu şekilde olursa: + +```JSON +{ + "id": "2expen51ve", + "customer": "Mr. Richie Rich", + "total": "9999" +} +``` + +o zaman *sizin API'niz* faturayı işleyecek ve daha sonra bir noktada `callback_url`'ye (yani *external API*'ye) bir callback request gönderecek: + +``` +https://www.external.org/events/invoices/2expen51ve +``` + +ve JSON body yaklaşık şöyle bir şey içerecek: + +```JSON +{ + "description": "Payment celebration", + "paid": true +} +``` + +ve o *external API*'den şu gibi bir JSON body içeren response bekleyecek: + +```JSON +{ + "ok": true +} +``` + +/// tip | İpucu + +Callback URL'sinin, `callback_url` içindeki query parametresi olarak alınan URL'yi (`https://www.external.org/events`) ve ayrıca JSON body'nin içindeki fatura `id`'sini (`2expen51ve`) birlikte kullandığına dikkat edin. + +/// + +### Callback router'ını ekleyin { #add-the-callback-router } + +Bu noktada, yukarıda oluşturduğunuz callback router'ında gerekli callback *path operation*'ları (external geliştiricinin *external API*'de implemente etmesi gerekenler) hazır. + +Şimdi *sizin API'nizin path operation decorator*'ında `callbacks` parametresini kullanarak, callback router'ının `.routes` attribute'unu (bu aslında route/*path operation*'lardan oluşan bir `list`) geçin: + +{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *} + +/// tip | İpucu + +`callback=` içine router'ın kendisini (`invoices_callback_router`) değil, `invoices_callback_router.routes` şeklinde `.routes` attribute'unu verdiğinize dikkat edin. + +/// + +### Dokümanları kontrol edin { #check-the-docs } + +Artık uygulamanızı başlatıp http://127.0.0.1:8000/docs adresine gidebilirsiniz. + +*Path operation*'ınız için, *external API*'nin nasıl görünmesi gerektiğini gösteren bir "Callbacks" bölümünü içeren dokümanları göreceksiniz: + + diff --git a/docs/tr/docs/advanced/openapi-webhooks.md b/docs/tr/docs/advanced/openapi-webhooks.md new file mode 100644 index 0000000000..dd9e9bbe73 --- /dev/null +++ b/docs/tr/docs/advanced/openapi-webhooks.md @@ -0,0 +1,55 @@ +# OpenAPI Webhook'lar { #openapi-webhooks } + +Bazı durumlarda, API'nizi kullanan **kullanıcılara** uygulamanızın *onların* uygulamasını (request göndererek) bazı verilerle çağırabileceğini; genellikle bir tür **event** hakkında **bildirim** yapmak için kullanacağını söylemek istersiniz. + +Bu da şunu ifade eder: Kullanıcılarınızın API'nize request göndermesi şeklindeki normal akış yerine, request'i **sizin API'niz** (veya uygulamanız) **onların sistemine** (onların API'sine, onların uygulamasına) **gönderebilir**. + +Buna genellikle **webhook** denir. + +## Webhook adımları { #webhooks-steps } + +Süreç genellikle şöyledir: Kodunuzda göndereceğiniz mesajın ne olduğunu, yani request'in **body**'sini **siz tanımlarsınız**. + +Ayrıca uygulamanızın bu request'leri veya event'leri hangi **anlarda** göndereceğini de bir şekilde tanımlarsınız. + +Ve **kullanıcılarınız** da bir şekilde (örneğin bir web dashboard üzerinden) uygulamanızın bu request'leri göndermesi gereken **URL**'yi tanımlar. + +Webhook'lar için URL'lerin nasıl kaydedileceğine dair tüm **mantık** ve bu request'leri gerçekten gönderen kod tamamen size bağlıdır. Bunu **kendi kodunuzda** istediğiniz gibi yazarsınız. + +## **FastAPI** ve OpenAPI ile webhook'ları dokümante etmek { #documenting-webhooks-with-fastapi-and-openapi } + +**FastAPI** ile OpenAPI kullanarak bu webhook'ların adlarını, uygulamanızın gönderebileceği HTTP operation türlerini (örn. `POST`, `PUT`, vb.) ve uygulamanızın göndereceği request **body**'lerini tanımlayabilirsiniz. + +Bu, kullanıcılarınızın **webhook** request'lerinizi alacak şekilde **API'lerini implement etmesini** çok daha kolaylaştırabilir; hatta kendi API kodlarının bir kısmını otomatik üretebilirler. + +/// info | Bilgi + +Webhook'lar OpenAPI 3.1.0 ve üzeri sürümlerde mevcuttur; FastAPI `0.99.0` ve üzeri tarafından desteklenir. + +/// + +## Webhook'ları olan bir uygulama { #an-app-with-webhooks } + +Bir **FastAPI** uygulaması oluşturduğunuzda, *webhook*'ları tanımlamak için kullanabileceğiniz bir `webhooks` attribute'u vardır; *path operation* tanımlar gibi, örneğin `@app.webhooks.post()` ile. + +{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *} + +Tanımladığınız webhook'lar **OpenAPI** şemasında ve otomatik **docs UI**'da yer alır. + +/// info | Bilgi + +`app.webhooks` nesnesi aslında sadece bir `APIRouter`'dır; uygulamanızı birden fazla dosya ile yapılandırırken kullanacağınız türün aynısıdır. + +/// + +Dikkat edin: Webhook'larda aslında bir *path* (ör. `/items/`) deklare etmiyorsunuz; oraya verdiğiniz metin sadece webhook'un bir **identifier**'ıdır (event'in adı). Örneğin `@app.webhooks.post("new-subscription")` içinde webhook adı `new-subscription`'dır. + +Bunun nedeni, webhook request'ini almak istedikleri gerçek **URL path**'i **kullanıcılarınızın** başka bir şekilde (örn. bir web dashboard üzerinden) tanımlamasının beklenmesidir. + +### Dokümanları kontrol edin { #check-the-docs } + +Şimdi uygulamanızı başlatıp http://127.0.0.1:8000/docs adresine gidin. + +Dokümanlarınızda normal *path operation*'ları ve artık bazı **webhook**'ları da göreceksiniz: + + diff --git a/docs/tr/docs/advanced/path-operation-advanced-configuration.md b/docs/tr/docs/advanced/path-operation-advanced-configuration.md new file mode 100644 index 0000000000..e326842d67 --- /dev/null +++ b/docs/tr/docs/advanced/path-operation-advanced-configuration.md @@ -0,0 +1,172 @@ +# Path Operation İleri Düzey Yapılandırma { #path-operation-advanced-configuration } + +## OpenAPI operationId { #openapi-operationid } + +/// warning | Uyarı + +OpenAPI konusunda "uzman" değilseniz, muhtemelen buna ihtiyacınız yok. + +/// + +*path operation*’ınızda kullanılacak OpenAPI `operationId` değerini `operation_id` parametresiyle ayarlayabilirsiniz. + +Bunun her operation için benzersiz olduğundan emin olmanız gerekir. + +{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *} + +### operationId olarak *path operation function* adını kullanma { #using-the-path-operation-function-name-as-the-operationid } + +API’lerinizin function adlarını `operationId` olarak kullanmak istiyorsanız, hepsini dolaşıp her *path operation*’ın `operation_id` değerini `APIRoute.name` ile override edebilirsiniz. + +Bunu, tüm *path operation*’ları ekledikten sonra yapmalısınız. + +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} + +/// tip | İpucu + +`app.openapi()` fonksiyonunu manuel olarak çağırıyorsanız, bunu yapmadan önce `operationId`’leri güncellemelisiniz. + +/// + +/// warning | Uyarı + +Bunu yaparsanız, her bir *path operation function*’ın adının benzersiz olduğundan emin olmanız gerekir. + +Farklı modüllerde (Python dosyalarında) olsalar bile. + +/// + +## OpenAPI’den Hariç Tutma { #exclude-from-openapi } + +Bir *path operation*’ı üretilen OpenAPI şemasından (dolayısıyla otomatik dokümantasyon sistemlerinden) hariç tutmak için `include_in_schema` parametresini kullanın ve `False` yapın: + +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} + +## Docstring’den İleri Düzey Açıklama { #advanced-description-from-docstring } + +OpenAPI için, bir *path operation function*’ın docstring’inden kullanılacak satırları sınırlandırabilirsiniz. + +Bir `\f` (escape edilmiş "form feed" karakteri) eklerseniz, **FastAPI** OpenAPI için kullanılan çıktıyı bu noktada **keser**. + +Dokümantasyonda görünmez, ancak diğer araçlar (Sphinx gibi) geri kalan kısmı kullanabilir. + +{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *} + +## Ek Responses { #additional-responses } + +Muhtemelen bir *path operation* için `response_model` ve `status_code` tanımlamayı görmüşsünüzdür. + +Bu, bir *path operation*’ın ana response’u ile ilgili metadata’yı tanımlar. + +Ek response’ları; modelleri, status code’ları vb. ile birlikte ayrıca da tanımlayabilirsiniz. + +Dokümantasyonda bununla ilgili ayrı bir bölüm var; [OpenAPI’de Ek Responses](additional-responses.md){.internal-link target=_blank} sayfasından okuyabilirsiniz. + +## OpenAPI Extra { #openapi-extra } + +Uygulamanızda bir *path operation* tanımladığınızda, **FastAPI** OpenAPI şemasına dahil edilmek üzere o *path operation* ile ilgili metadata’yı otomatik olarak üretir. + +/// note | Teknik Detaylar + +OpenAPI spesifikasyonunda buna Operation Object denir. + +/// + +Bu, *path operation* hakkında tüm bilgileri içerir ve otomatik dokümantasyonu üretmek için kullanılır. + +`tags`, `parameters`, `requestBody`, `responses` vb. alanları içerir. + +Bu *path operation*’a özel OpenAPI şeması normalde **FastAPI** tarafından otomatik üretilir; ancak siz bunu genişletebilirsiniz. + +/// tip | İpucu + +Bu, düşük seviyeli bir genişletme noktasıdır. + +Yalnızca ek response’lar tanımlamanız gerekiyorsa, bunu yapmanın daha pratik yolu [OpenAPI’de Ek Responses](additional-responses.md){.internal-link target=_blank} kullanmaktır. + +/// + +Bir *path operation* için OpenAPI şemasını `openapi_extra` parametresiyle genişletebilirsiniz. + +### OpenAPI Extensions { #openapi-extensions } + +Örneğin bu `openapi_extra`, [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) tanımlamak için faydalı olabilir: + +{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *} + +Otomatik API dokümanlarını açtığınızda, extension’ınız ilgili *path operation*’ın en altında görünür. + + + +Ayrıca ortaya çıkan OpenAPI’yi (API’nizde `/openapi.json`) görüntülerseniz, extension’ınızı ilgili *path operation*’ın bir parçası olarak orada da görürsünüz: + +```JSON hl_lines="22" +{ + "openapi": "3.1.0", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + } + }, + "x-aperture-labs-portal": "blue" + } + } + } +} +``` + +### Özel OpenAPI *path operation* şeması { #custom-openapi-path-operation-schema } + +`openapi_extra` içindeki dictionary, *path operation* için otomatik üretilen OpenAPI şemasıyla derinlemesine (deep) birleştirilir. + +Böylece otomatik üretilen şemaya ek veri ekleyebilirsiniz. + +Örneğin, Pydantic ile FastAPI’nin otomatik özelliklerini kullanmadan request’i kendi kodunuzla okuyup doğrulamaya karar verebilirsiniz; ancak yine de OpenAPI şemasında request’i tanımlamak isteyebilirsiniz. + +Bunu `openapi_extra` ile yapabilirsiniz: + +{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *} + +Bu örnekte herhangi bir Pydantic model tanımlamadık. Hatta request body JSON olarak parsed bile edilmiyor; doğrudan `bytes` olarak okunuyor ve `magic_data_reader()` fonksiyonu bunu bir şekilde parse etmekten sorumlu oluyor. + +Buna rağmen, request body için beklenen şemayı tanımlayabiliriz. + +### Özel OpenAPI content type { #custom-openapi-content-type } + +Aynı yöntemi kullanarak, Pydantic model ile JSON Schema’yı tanımlayıp bunu *path operation* için özel OpenAPI şeması bölümüne dahil edebilirsiniz. + +Ve bunu, request içindeki veri tipi JSON olmasa bile yapabilirsiniz. + +Örneğin bu uygulamada, FastAPI’nin Pydantic modellerinden JSON Schema çıkarmaya yönelik entegre işlevselliğini ve JSON için otomatik doğrulamayı kullanmıyoruz. Hatta request content type’ını JSON değil, YAML olarak tanımlıyoruz: + +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *} + +Buna rağmen, varsayılan entegre işlevselliği kullanmasak da, YAML olarak almak istediğimiz veri için JSON Schema’yı manuel üretmek üzere bir Pydantic model kullanmaya devam ediyoruz. + +Ardından request’i doğrudan kullanıp body’yi `bytes` olarak çıkarıyoruz. Bu da FastAPI’nin request payload’ını JSON olarak parse etmeye çalışmayacağı anlamına gelir. + +Sonrasında kodumuzda bu YAML içeriğini doğrudan parse ediyor, ardından YAML içeriğini doğrulamak için yine aynı Pydantic modeli kullanıyoruz: + +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *} + +/// tip | İpucu + +Burada aynı Pydantic modeli tekrar kullanıyoruz. + +Aynı şekilde, başka bir yöntemle de doğrulama yapabilirdik. + +/// diff --git a/docs/tr/docs/advanced/response-change-status-code.md b/docs/tr/docs/advanced/response-change-status-code.md new file mode 100644 index 0000000000..239c0dddd4 --- /dev/null +++ b/docs/tr/docs/advanced/response-change-status-code.md @@ -0,0 +1,31 @@ +# Response - Status Code Değiştirme { #response-change-status-code } + +Muhtemelen daha önce varsayılan bir [Response Status Code](../tutorial/response-status-code.md){.internal-link target=_blank} ayarlayabileceğinizi okumuşsunuzdur. + +Ancak bazı durumlarda, varsayılandan farklı bir status code döndürmeniz gerekir. + +## Kullanım senaryosu { #use-case } + +Örneğin, varsayılan olarak "OK" `200` HTTP status code'u döndürmek istediğinizi düşünün. + +Ama veri mevcut değilse onu oluşturmak ve "CREATED" `201` HTTP status code'u döndürmek istiyorsunuz. + +Aynı zamanda, döndürdüğünüz veriyi bir `response_model` ile filtreleyip dönüştürebilmeyi de sürdürmek istiyorsunuz. + +Bu tür durumlarda bir `Response` parametresi kullanabilirsiniz. + +## Bir `Response` parametresi kullanın { #use-a-response-parameter } + +*Path operation function* içinde `Response` tipinde bir parametre tanımlayabilirsiniz (cookie ve header'lar için yapabildiğiniz gibi). + +Ardından bu *geçici (temporal)* `Response` nesnesi üzerinde `status_code` değerini ayarlayabilirsiniz. + +{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} + +Sonrasında, normalde yaptığınız gibi ihtiyacınız olan herhangi bir nesneyi döndürebilirsiniz (`dict`, bir veritabanı modeli, vb.). + +Ve eğer bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır. + +**FastAPI**, status code'u (ayrıca cookie ve header'ları) bu *geçici (temporal)* response'tan alır ve `response_model` ile filtrelenmiş, sizin döndürdüğünüz değeri içeren nihai response'a yerleştirir. + +Ayrıca `Response` parametresini dependency'lerde de tanımlayıp status code'u orada ayarlayabilirsiniz. Ancak unutmayın, en son ayarlanan değer geçerli olur. diff --git a/docs/tr/docs/advanced/response-cookies.md b/docs/tr/docs/advanced/response-cookies.md new file mode 100644 index 0000000000..d00bfc4cd0 --- /dev/null +++ b/docs/tr/docs/advanced/response-cookies.md @@ -0,0 +1,51 @@ +# Response Cookie'leri { #response-cookies } + +## Bir `Response` parametresi kullanın { #use-a-response-parameter } + +*Path operation function* içinde `Response` tipinde bir parametre tanımlayabilirsiniz. + +Ardından bu *geçici* response nesnesi üzerinde cookie'leri set edebilirsiniz. + +{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} + +Sonrasında normalde yaptığınız gibi ihtiyaç duyduğunuz herhangi bir nesneyi döndürebilirsiniz (bir `dict`, bir veritabanı modeli vb.). + +Ayrıca bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır. + +**FastAPI**, bu *geçici* response'u cookie'leri (ayrıca header'ları ve status code'u) çıkarmak için kullanır ve bunları, döndürdüğünüz değeri içeren nihai response'a ekler. Döndürdüğünüz değer, varsa `response_model` ile filtrelenmiş olur. + +`Response` parametresini dependency'lerde de tanımlayıp, onların içinde cookie (ve header) set edebilirsiniz. + +## Doğrudan bir `Response` döndürün { #return-a-response-directly } + +Kodunuzda doğrudan bir `Response` döndürürken de cookie oluşturabilirsiniz. + +Bunu yapmak için, [Doğrudan Response Döndürme](response-directly.md){.internal-link target=_blank} bölümünde anlatıldığı gibi bir response oluşturabilirsiniz. + +Sonra bunun içinde Cookie'leri set edin ve response'u döndürün: + +{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} + +/// tip | İpucu + +`Response` parametresini kullanmak yerine doğrudan bir response döndürürseniz, FastAPI onu olduğu gibi (doğrudan) döndürür. + +Bu yüzden, verinizin doğru tipte olduğundan emin olmanız gerekir. Örneğin `JSONResponse` döndürüyorsanız, verinin JSON ile uyumlu olması gerekir. + +Ayrıca `response_model` tarafından filtrelenmesi gereken bir veriyi göndermediğinizden de emin olun. + +/// + +### Daha fazla bilgi { #more-info } + +/// note | Teknik Detaylar + +`from starlette.responses import Response` veya `from starlette.responses import JSONResponse` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olması için `fastapi.responses` içinde `starlette.responses` ile aynı response sınıflarını sunar. Ancak mevcut response'ların büyük kısmı doğrudan Starlette'ten gelir. + +Ve `Response`, header ve cookie set etmek için sık kullanıldığından, **FastAPI** bunu `fastapi.Response` olarak da sağlar. + +/// + +Mevcut tüm parametreleri ve seçenekleri görmek için Starlette dokümantasyonuna bakın. diff --git a/docs/tr/docs/advanced/response-directly.md b/docs/tr/docs/advanced/response-directly.md new file mode 100644 index 0000000000..332f1224fc --- /dev/null +++ b/docs/tr/docs/advanced/response-directly.md @@ -0,0 +1,65 @@ +# Doğrudan Bir Response Döndürme { #return-a-response-directly } + +**FastAPI** ile bir *path operation* oluşturduğunuzda, normalde ondan herhangi bir veri döndürebilirsiniz: bir `dict`, bir `list`, bir Pydantic model, bir veritabanı modeli vb. + +Varsayılan olarak **FastAPI**, döndürdüğünüz bu değeri [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank} bölümünde anlatılan `jsonable_encoder` ile otomatik olarak JSON'a çevirir. + +Ardından perde arkasında, JSON-uyumlu bu veriyi (ör. bir `dict`) client'a response göndermek için kullanılacak bir `JSONResponse` içine yerleştirir. + +Ancak *path operation*'larınızdan doğrudan bir `JSONResponse` döndürebilirsiniz. + +Bu, örneğin özel header'lar veya cookie'ler döndürmek istediğinizde faydalı olabilir. + +## Bir `Response` Döndürme { #return-a-response } + +Aslında herhangi bir `Response` veya onun herhangi bir alt sınıfını döndürebilirsiniz. + +/// tip | İpucu + +`JSONResponse` zaten `Response`'un bir alt sınıfıdır. + +/// + +Bir `Response` döndürdüğünüzde, **FastAPI** bunu olduğu gibi doğrudan iletir. + +Pydantic model'leriyle herhangi bir veri dönüşümü yapmaz, içeriği başka bir tipe çevirmez vb. + +Bu size ciddi bir esneklik sağlar. Herhangi bir veri türü döndürebilir, herhangi bir veri deklarasyonunu veya validasyonunu override edebilirsiniz. + +## Bir `Response` İçinde `jsonable_encoder` Kullanma { #using-the-jsonable-encoder-in-a-response } + +**FastAPI**, sizin döndürdüğünüz `Response` üzerinde hiçbir değişiklik yapmadığı için, içeriğinin gönderilmeye hazır olduğundan emin olmanız gerekir. + +Örneğin, bir Pydantic model'i, önce JSON-uyumlu tiplere çevrilmeden (`datetime`, `UUID` vb.) doğrudan bir `JSONResponse` içine koyamazsınız. Önce tüm veri tipleri JSON-uyumlu hale gelecek şekilde `dict`'e çevrilmesi gerekir. + +Bu gibi durumlarda, response'a vermeden önce verinizi dönüştürmek için `jsonable_encoder` kullanabilirsiniz: + +{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *} + +/// note | Teknik Detaylar + +`from starlette.responses import JSONResponse` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olması için `starlette.responses` içeriğini `fastapi.responses` üzerinden de sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'tan gelir. + +/// + +## Özel Bir `Response` Döndürme { #returning-a-custom-response } + +Yukarıdaki örnek ihtiyaç duyduğunuz tüm parçaları gösteriyor, ancak henüz çok kullanışlı değil. Çünkü `item`'ı zaten doğrudan döndürebilirdiniz ve **FastAPI** varsayılan olarak onu sizin için bir `JSONResponse` içine koyup `dict`'e çevirirdi vb. + +Şimdi bunu kullanarak nasıl özel bir response döndürebileceğinize bakalım. + +Diyelim ki XML response döndürmek istiyorsunuz. + +XML içeriğinizi bir string içine koyabilir, onu bir `Response` içine yerleştirip döndürebilirsiniz: + +{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} + +## Notlar { #notes } + +Bir `Response`'u doğrudan döndürdüğünüzde, verisi otomatik olarak validate edilmez, dönüştürülmez (serialize edilmez) veya dokümante edilmez. + +Ancak yine de [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank} bölümünde anlatıldığı şekilde dokümante edebilirsiniz. + +İlerleyen bölümlerde, otomatik veri dönüşümü, dokümantasyon vb. özellikleri korurken bu özel `Response`'ları nasıl kullanıp declare edebileceğinizi göreceksiniz. diff --git a/docs/tr/docs/advanced/response-headers.md b/docs/tr/docs/advanced/response-headers.md new file mode 100644 index 0000000000..85b0799d3f --- /dev/null +++ b/docs/tr/docs/advanced/response-headers.md @@ -0,0 +1,41 @@ +# Response Header'ları { #response-headers } + +## Bir `Response` parametresi kullanın { #use-a-response-parameter } + +*Path operation function* içinde (cookie'lerde yapabildiğiniz gibi) tipi `Response` olan bir parametre tanımlayabilirsiniz. + +Sonra da bu *geçici* response nesnesi üzerinde header'ları ayarlayabilirsiniz. + +{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *} + +Ardından normalde yaptığınız gibi ihtiyacınız olan herhangi bir nesneyi döndürebilirsiniz (bir `dict`, bir veritabanı modeli vb.). + +Eğer bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır. + +**FastAPI**, header'ları (aynı şekilde cookie'leri ve status code'u) bu *geçici* response'dan alır ve döndürdüğünüz değeri (varsa bir `response_model` ile filtrelenmiş hâliyle) içeren nihai response'a ekler. + +`Response` parametresini dependency'lerde de tanımlayıp, onların içinde header (ve cookie) ayarlayabilirsiniz. + +## Doğrudan bir `Response` döndürün { #return-a-response-directly } + +Doğrudan bir `Response` döndürdüğünüzde de header ekleyebilirsiniz. + +[Bir Response'u Doğrudan Döndürün](response-directly.md){.internal-link target=_blank} bölümünde anlatıldığı gibi bir response oluşturun ve header'ları ek bir parametre olarak geçin: + +{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *} + +/// note | Teknik Detaylar + +`from starlette.responses import Response` veya `from starlette.responses import JSONResponse` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. + +Ayrıca `Response` header ve cookie ayarlamak için sık kullanıldığından, **FastAPI** bunu `fastapi.Response` altında da sağlar. + +/// + +## Özel Header'lar { #custom-headers } + +Özel/proprietary header'ların `X-` prefix'i kullanılarak eklenebileceğini unutmayın. + +Ancak tarayıcıdaki bir client'ın görebilmesini istediğiniz özel header'larınız varsa, bunları CORS ayarlarınıza eklemeniz gerekir ([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank} bölümünde daha fazla bilgi), bunun için Starlette'in CORS dokümanında açıklanan `expose_headers` parametresini kullanın. diff --git a/docs/tr/docs/advanced/security/http-basic-auth.md b/docs/tr/docs/advanced/security/http-basic-auth.md new file mode 100644 index 0000000000..b194c763e8 --- /dev/null +++ b/docs/tr/docs/advanced/security/http-basic-auth.md @@ -0,0 +1,107 @@ +# HTTP Basic Auth { #http-basic-auth } + +En basit senaryolarda HTTP Basic Auth kullanabilirsiniz. + +HTTP Basic Auth’ta uygulama, içinde kullanıcı adı ve şifre bulunan bir header bekler. + +Eğer bunu almazsa HTTP 401 "Unauthorized" hatası döndürür. + +Ayrıca değeri `Basic` olan ve isteğe bağlı `realm` parametresi içerebilen `WWW-Authenticate` header’ını da döndürür. + +Bu da tarayıcıya, kullanıcı adı ve şifre için entegre giriş penceresini göstermesini söyler. + +Ardından kullanıcı adı ve şifreyi yazdığınızda tarayıcı bunları otomatik olarak header içinde gönderir. + +## Basit HTTP Basic Auth { #simple-http-basic-auth } + +* `HTTPBasic` ve `HTTPBasicCredentials` import edin. +* `HTTPBasic` kullanarak bir "`security` scheme" oluşturun. +* *path operation*’ınızda bir dependency ile bu `security`’yi kullanın. +* Bu, `HTTPBasicCredentials` tipinde bir nesne döndürür: + * İçinde gönderilen `username` ve `password` bulunur. + +{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *} + +URL’yi ilk kez açmaya çalıştığınızda (veya dokümanlardaki "Execute" butonuna tıkladığınızda) tarayıcı sizden kullanıcı adınızı ve şifrenizi ister: + + + +## Kullanıcı adını kontrol edin { #check-the-username } + +Daha kapsamlı bir örneğe bakalım. + +Kullanıcı adı ve şifrenin doğru olup olmadığını kontrol etmek için bir dependency kullanın. + +Bunun için kullanıcı adı ve şifreyi kontrol ederken Python standart modülü olan `secrets`’i kullanın. + +`secrets.compare_digest()`; `bytes` ya da yalnızca ASCII karakterleri (İngilizce’deki karakterler) içeren bir `str` almalıdır. Bu da `Sebastián` içindeki `á` gibi karakterlerle çalışmayacağı anlamına gelir. + +Bunu yönetmek için önce `username` ve `password` değerlerini UTF-8 ile encode ederek `bytes`’a dönüştürürüz. + +Sonra `secrets.compare_digest()` kullanarak `credentials.username`’in `"stanleyjobson"` ve `credentials.password`’ün `"swordfish"` olduğundan emin olabiliriz. + +{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *} + +Bu, kabaca şuna benzer olurdu: + +```Python +if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"): + # Return some error + ... +``` + +Ancak `secrets.compare_digest()` kullanarak, "timing attacks" denilen bir saldırı türüne karşı güvenli olursunuz. + +### Timing Attacks { #timing-attacks } + +Peki "timing attack" nedir? + +Bazı saldırganların kullanıcı adı ve şifreyi tahmin etmeye çalıştığını düşünelim. + +Ve `johndoe` kullanıcı adı ve `love123` şifresi ile bir request gönderiyorlar. + +Uygulamanızdaki Python kodu o zaman kabaca şuna denk olur: + +```Python +if "johndoe" == "stanleyjobson" and "love123" == "swordfish": + ... +``` + +Ancak Python, `johndoe` içindeki ilk `j` ile `stanleyjobson` içindeki ilk `s`’i karşılaştırdığı anda `False` döndürür; çünkü iki string’in aynı olmadığını zaten anlar ve "kalan harfleri karşılaştırmak için daha fazla hesaplama yapmaya gerek yok" diye düşünür. Uygulamanız da "Incorrect username or password" der. + +Sonra saldırganlar bu sefer `stanleyjobsox` kullanıcı adı ve `love123` şifresi ile dener. + +Uygulama kodunuz da şuna benzer bir şey yapar: + +```Python +if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish": + ... +``` + +Bu kez Python, iki string’in aynı olmadığını fark etmeden önce hem `stanleyjobsox` hem de `stanleyjobson` içinde `stanleyjobso` kısmının tamamını karşılaştırmak zorunda kalır. Bu nedenle "Incorrect username or password" yanıtını vermesi birkaç mikro saniye daha uzun sürer. + +#### Yanıt süresi saldırganlara yardımcı olur { #the-time-to-answer-helps-the-attackers } + +Bu noktada saldırganlar, server’ın "Incorrect username or password" response’unu göndermesinin birkaç mikro saniye daha uzun sürdüğünü fark ederek _bir şeyleri_ doğru yaptıklarını anlar; yani başlangıçtaki bazı harfler doğrudur. + +Sonra tekrar denerken, bunun `johndoe`’dan ziyade `stanleyjobsox`’a daha yakın bir şey olması gerektiğini bilerek devam edebilirler. + +#### "Profesyonel" bir saldırı { #a-professional-attack } + +Elbette saldırganlar bunu elle tek tek denemez; bunu yapan bir program yazarlar. Muhtemelen saniyede binlerce ya da milyonlarca test yaparlar ve her seferinde yalnızca bir doğru harf daha elde ederler. + +Böylece birkaç dakika ya da birkaç saat içinde doğru kullanıcı adı ve şifreyi, yanıt süresini kullanarak ve uygulamamızın "yardımıyla" tahmin etmiş olurlar. + +#### `secrets.compare_digest()` ile düzeltin { #fix-it-with-secrets-compare-digest } + +Ancak bizim kodumuzda `secrets.compare_digest()` kullanıyoruz. + +Kısacası, `stanleyjobsox` ile `stanleyjobson`’u karşılaştırmak için geçen süre, `johndoe` ile `stanleyjobson`’u karşılaştırmak için geçen süreyle aynı olur. Şifre için de aynı şekilde. + +Bu sayede uygulama kodunuzda `secrets.compare_digest()` kullanarak bu güvenlik saldırıları ailesine karşı güvenli olursunuz. + +### Hatayı döndürün { #return-the-error } + +Credential’ların hatalı olduğunu tespit ettikten sonra, 401 status code ile (credential verilmediğinde dönenle aynı) bir `HTTPException` döndürün ve tarayıcının giriş penceresini yeniden göstermesi için `WWW-Authenticate` header’ını ekleyin: + +{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *} diff --git a/docs/tr/docs/advanced/security/oauth2-scopes.md b/docs/tr/docs/advanced/security/oauth2-scopes.md new file mode 100644 index 0000000000..ecba7851b0 --- /dev/null +++ b/docs/tr/docs/advanced/security/oauth2-scopes.md @@ -0,0 +1,274 @@ +# OAuth2 scope'ları { #oauth2-scopes } + +OAuth2 scope'larını **FastAPI** ile doğrudan kullanabilirsiniz; sorunsuz çalışacak şekilde entegre edilmiştir. + +Bu sayede OAuth2 standardını takip eden, daha ince taneli bir izin sistemini OpenAPI uygulamanıza (ve API dokümanlarınıza) entegre edebilirsiniz. + +Scope'lu OAuth2; Facebook, Google, GitHub, Microsoft, X (Twitter) vb. birçok büyük kimlik doğrulama sağlayıcısının kullandığı mekanizmadır. Kullanıcı ve uygulamalara belirli izinler vermek için bunu kullanırlar. + +Facebook, Google, GitHub, Microsoft, X (Twitter) ile "giriş yaptığınızda", o uygulama scope'lu OAuth2 kullanıyor demektir. + +Bu bölümde, **FastAPI** uygulamanızda aynı scope'lu OAuth2 ile authentication ve authorization'ı nasıl yöneteceğinizi göreceksiniz. + +/// warning | Uyarı + +Bu bölüm az çok ileri seviye sayılır. Yeni başlıyorsanız atlayabilirsiniz. + +OAuth2 scope'larına mutlaka ihtiyacınız yok; authentication ve authorization'ı istediğiniz şekilde ele alabilirsiniz. + +Ancak scope'lu OAuth2, API'nize (OpenAPI ile) ve API dokümanlarınıza güzel biçimde entegre edilebilir. + +Buna rağmen, bu scope'ları (veya başka herhangi bir security/authorization gereksinimini) kodunuzda ihtiyaç duyduğunuz şekilde yine siz zorunlu kılarsınız. + +Birçok durumda scope'lu OAuth2 gereğinden fazla (overkill) olabilir. + +Ama ihtiyacınız olduğunu biliyorsanız ya da merak ediyorsanız okumaya devam edin. + +/// + +## OAuth2 scope'ları ve OpenAPI { #oauth2-scopes-and-openapi } + +OAuth2 spesifikasyonu, "scope"ları boşluklarla ayrılmış string'lerden oluşan bir liste olarak tanımlar. + +Bu string'lerin her birinin içeriği herhangi bir formatta olabilir, ancak boşluk içermemelidir. + +Bu scope'lar "izinleri" temsil eder. + +OpenAPI'de (ör. API dokümanlarında) "security scheme" tanımlayabilirsiniz. + +Bu security scheme'lerden biri OAuth2 kullanıyorsa, scope'ları da tanımlayıp kullanabilirsiniz. + +Her bir "scope" sadece bir string'dir (boşluksuz). + +Genellikle belirli güvenlik izinlerini tanımlamak için kullanılır, örneğin: + +* `users:read` veya `users:write` sık görülen örneklerdir. +* `instagram_basic` Facebook / Instagram tarafından kullanılır. +* `https://www.googleapis.com/auth/drive` Google tarafından kullanılır. + +/// info | Bilgi + +OAuth2'de "scope", gereken belirli bir izni bildiren bir string'den ibarettir. + +`:` gibi başka karakterler içermesi ya da bir URL olması önemli değildir. + +Bu detaylar implementasyon'a bağlıdır. + +OAuth2 için bunlar sadece string'dir. + +/// + +## Genel görünüm { #global-view } + +Önce, ana **Tutorial - User Guide** içindeki [Password (ve hashing) ile OAuth2, JWT token'lı Bearer](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank} örneklerinden, OAuth2 scope'larına geçince hangi kısımların değiştiğine hızlıca bakalım: + +{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *} + +Şimdi bu değişiklikleri adım adım inceleyelim. + +## OAuth2 Security scheme { #oauth2-security-scheme } + +İlk değişiklik, artık OAuth2 security scheme'ini iki adet kullanılabilir scope ile tanımlamamız: `me` ve `items`. + +`scopes` parametresi; her scope'un key, açıklamasının ise value olduğu bir `dict` alır: + +{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *} + +Bu scope'ları tanımladığımız için, login/authorize yaptığınızda API dokümanlarında görünecekler. + +Ve hangi scope'lara erişim vermek istediğinizi seçebileceksiniz: `me` ve `items`. + +Bu, Facebook/Google/GitHub vb. ile giriş yaparken izin verdiğinizde kullanılan mekanizmanın aynısıdır: + + + +## Scope'lu JWT token { #jwt-token-with-scopes } + +Şimdi token *path operation*'ını, istenen scope'ları döndürecek şekilde değiştirin. + +Hâlâ aynı `OAuth2PasswordRequestForm` kullanılıyor. Bu form, request'te aldığı her scope için `str`'lerden oluşan bir `list` içeren `scopes` özelliğine sahiptir. + +Ve scope'ları JWT token'ın bir parçası olarak döndürüyoruz. + +/// danger | Uyarı + +Basitlik için burada, gelen scope'ları doğrudan token'a ekliyoruz. + +Ama uygulamanızda güvenlik açısından, yalnızca kullanıcının gerçekten sahip olabileceği scope'ları (veya sizin önceden tanımladıklarınızı) eklediğinizden emin olmalısınız. + +/// + +{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *} + +## *Path operation*'larda ve dependency'lerde scope tanımlama { #declare-scopes-in-path-operations-and-dependencies } + +Artık `/users/me/items/` için olan *path operation*'ın `items` scope'unu gerektirdiğini tanımlıyoruz. + +Bunun için `fastapi` içinden `Security` import edip kullanıyoruz. + +Dependency'leri (`Depends` gibi) tanımlamak için `Security` kullanabilirsiniz; fakat `Security`, ayrıca string'lerden oluşan bir scope listesi alan `scopes` parametresini de alır. + +Bu durumda `Security`'ye dependency fonksiyonu olarak `get_current_active_user` veriyoruz (`Depends` ile yaptığımız gibi). + +Ama ayrıca bir `list` olarak scope'ları da veriyoruz; burada tek bir scope var: `items` (daha fazla da olabilir). + +Ve `get_current_active_user` dependency fonksiyonu, sadece `Depends` ile değil `Security` ile de alt-dependency'ler tanımlayabilir. Kendi alt-dependency fonksiyonunu (`get_current_user`) ve daha fazla scope gereksinimini tanımlar. + +Bu örnekte `me` scope'unu gerektiriyor (birden fazla scope da isteyebilirdi). + +/// note | Not + +Farklı yerlerde farklı scope'lar eklemek zorunda değilsiniz. + +Burada, **FastAPI**'nin farklı seviyelerde tanımlanan scope'ları nasıl ele aldığını göstermek için böyle yapıyoruz. + +/// + +{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *} + +/// info | Teknik Detaylar + +`Security` aslında `Depends`'in bir alt sınıfıdır ve sadece birazdan göreceğimiz bir ek parametreye sahiptir. + +Ancak `Depends` yerine `Security` kullanınca **FastAPI**, security scope'larının tanımlanabileceğini bilir, bunları içeride kullanır ve API'yi OpenAPI ile dokümante eder. + +Fakat `fastapi` içinden `Query`, `Path`, `Depends`, `Security` vb. import ettiğiniz şeyler, aslında özel sınıflar döndüren fonksiyonlardır. + +/// + +## `SecurityScopes` kullanımı { #use-securityscopes } + +Şimdi `get_current_user` dependency'sini güncelleyelim. + +Bu fonksiyon, yukarıdaki dependency'ler tarafından kullanılıyor. + +Burada, daha önce oluşturduğumuz aynı OAuth2 scheme'i dependency olarak tanımlıyoruz: `oauth2_scheme`. + +Bu dependency fonksiyonunun kendi içinde bir scope gereksinimi olmadığı için, `oauth2_scheme` ile `Depends` kullanabiliriz; security scope'larını belirtmemiz gerekmiyorsa `Security` kullanmak zorunda değiliz. + +Ayrıca `fastapi.security` içinden import edilen, `SecurityScopes` tipinde özel bir parametre tanımlıyoruz. + +Bu `SecurityScopes` sınıfı, `Request`'e benzer (`Request`, request nesnesini doğrudan almak için kullanılmıştı). + +{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *} + +## `scopes`'ları kullanma { #use-the-scopes } + +`security_scopes` parametresi `SecurityScopes` tipinde olacaktır. + +Bu nesnenin `scopes` adlı bir özelliği vardır; bu liste, kendisinin ve bunu alt-dependency olarak kullanan tüm dependency'lerin gerektirdiği tüm scope'ları içerir. Yani tüm "dependant"lar... kafa karıştırıcı gelebilir; aşağıda tekrar açıklanıyor. + +`security_scopes` nesnesi (`SecurityScopes` sınıfından) ayrıca, bu scope'ları boşluklarla ayrılmış tek bir string olarak veren `scope_str` attribute'una sahiptir (bunu kullanacağız). + +Sonrasında birkaç farklı noktada tekrar kullanabileceğimiz (`raise` edebileceğimiz) bir `HTTPException` oluşturuyoruz. + +Bu exception içinde, gerekiyorsa, gerekli scope'ları boşlukla ayrılmış bir string olarak (`scope_str` ile) ekliyoruz. Bu scope'ları içeren string'i `WWW-Authenticate` header'ına koyuyoruz (spesifikasyonun bir parçası). + +{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *} + +## `username` ve veri şeklinin doğrulanması { #verify-the-username-and-data-shape } + +Bir `username` aldığımızı doğruluyoruz ve scope'ları çıkarıyoruz. + +Ardından bu veriyi Pydantic model'i ile doğruluyoruz (`ValidationError` exception'ını yakalayarak). JWT token'ı okurken veya Pydantic ile veriyi doğrularken bir hata olursa, daha önce oluşturduğumuz `HTTPException`'ı fırlatıyoruz. + +Bunun için Pydantic model'i `TokenData`'yı, `scopes` adlı yeni bir özellik ekleyerek güncelliyoruz. + +Veriyi Pydantic ile doğrulayarak örneğin scope'ların tam olarak `str`'lerden oluşan bir `list` olduğunu ve `username`'in bir `str` olduğunu garanti edebiliriz. + +Aksi halde, örneğin bir `dict` veya başka bir şey gelebilir; bu da daha sonra uygulamanın bir yerinde kırılmaya yol açıp güvenlik riski oluşturabilir. + +Ayrıca bu `username` ile bir kullanıcı olduğunu doğruluyoruz; yoksa yine aynı exception'ı fırlatıyoruz. + +{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *} + +## `scopes`'ların doğrulanması { #verify-the-scopes } + +Şimdi bu dependency'nin ve tüm dependant'ların ( *path operation*'lar dahil) gerektirdiği tüm scope'ların, alınan token'da sağlanan scope'lar içinde olup olmadığını doğruluyoruz; değilse `HTTPException` fırlatıyoruz. + +Bunun için, tüm bu scope'ları `str` olarak içeren bir `list` olan `security_scopes.scopes` kullanılır. + +{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *} + +## Dependency ağacı ve scope'lar { #dependency-tree-and-scopes } + +Bu dependency ağacını ve scope'ları tekrar gözden geçirelim. + +`get_current_active_user` dependency'si, alt-dependency olarak `get_current_user`'ı kullandığı için, `get_current_active_user` üzerinde tanımlanan `"me"` scope'u, `get_current_user`'a geçirilen `security_scopes.scopes` içindeki gerekli scope listesine dahil edilir. + +*Path operation*'ın kendisi de `"items"` scope'unu tanımlar; bu da `get_current_user`'a geçirilen `security_scopes.scopes` listesinde yer alır. + +Dependency'lerin ve scope'ların hiyerarşisi şöyle görünür: + +* *Path operation* `read_own_items` şunlara sahiptir: + * Dependency ile gerekli scope'lar `["items"]`: + * `get_current_active_user`: + * `get_current_active_user` dependency fonksiyonu şunlara sahiptir: + * Dependency ile gerekli scope'lar `["me"]`: + * `get_current_user`: + * `get_current_user` dependency fonksiyonu şunlara sahiptir: + * Kendisinin gerektirdiği scope yok. + * `oauth2_scheme` kullanan bir dependency. + * `SecurityScopes` tipinde bir `security_scopes` parametresi: + * Bu `security_scopes` parametresinin `scopes` adlı bir özelliği vardır ve yukarıda tanımlanan tüm scope'ları içeren bir `list` taşır, yani: + * *Path operation* `read_own_items` için `security_scopes.scopes` `["me", "items"]` içerir. + * *Path operation* `read_users_me` için `security_scopes.scopes` `["me"]` içerir; çünkü bu scope `get_current_active_user` dependency'sinde tanımlanmıştır. + * *Path operation* `read_system_status` için `security_scopes.scopes` `[]` (boş) olur; çünkü herhangi bir `Security` ile `scopes` tanımlamamıştır ve dependency'si olan `get_current_user` da `scopes` tanımlamaz. + +/// tip | İpucu + +Buradaki önemli ve "sihirli" nokta şu: `get_current_user`, her *path operation* için kontrol etmesi gereken farklı bir `scopes` listesi alır. + +Bu, belirli bir *path operation* için dependency ağacındaki her *path operation* ve her dependency üzerinde tanımlanan `scopes`'lara bağlıdır. + +/// + +## `SecurityScopes` hakkında daha fazla detay { #more-details-about-securityscopes } + +`SecurityScopes`'u herhangi bir noktada ve birden fazla yerde kullanabilirsiniz; mutlaka "kök" dependency'de olmak zorunda değildir. + +Her zaman, **o spesifik** *path operation* ve **o spesifik** dependency ağacı için, mevcut `Security` dependency'lerinde ve tüm dependant'larda tanımlanan security scope'larını içerir. + +`SecurityScopes`, dependant'ların tanımladığı tüm scope'ları barındırdığı için, gereken scope'ların token'da olup olmadığını merkezi bir dependency fonksiyonunda doğrulayıp, farklı *path operation*'larda farklı scope gereksinimleri tanımlayabilirsiniz. + +Bu kontroller her *path operation* için bağımsız yapılır. + +## Deneyin { #check-it } + +API dokümanlarını açarsanız, authenticate olup hangi scope'ları authorize etmek istediğinizi seçebilirsiniz. + + + +Hiç scope seçmezseniz "authenticated" olursunuz; ancak `/users/me/` veya `/users/me/items/`'e erişmeye çalıştığınızda, yeterli izniniz olmadığını söyleyen bir hata alırsınız. Yine de `/status/`'a erişebilirsiniz. + +`me` scope'unu seçip `items` scope'unu seçmezseniz `/users/me/`'a erişebilirsiniz ama `/users/me/items/`'e erişemezsiniz. + +Bu, bir üçüncü taraf uygulamanın, bir kullanıcı tarafından sağlanan token ile bu *path operation*'lardan birine erişmeye çalıştığında; kullanıcının uygulamaya kaç izin verdiğine bağlı olarak yaşayacağı durumdur. + +## Üçüncü taraf entegrasyonları hakkında { #about-third-party-integrations } + +Bu örnekte OAuth2 "password" flow'unu kullanıyoruz. + +Bu, kendi uygulamamıza giriş yaptığımız durumlar için uygundur; muhtemelen kendi frontend'imiz vardır. + +Çünkü `username` ve `password` alacağını bildiğimiz frontend'i biz kontrol ediyoruz, dolayısıyla güvenebiliriz. + +Ancak başkalarının bağlanacağı bir OAuth2 uygulaması geliştiriyorsanız (yani Facebook, Google, GitHub vb. gibi bir authentication provider muadili geliştiriyorsanız) diğer flow'lardan birini kullanmalısınız. + +En yaygını implicit flow'dur. + +En güvenlisi code flow'dur; ancak daha fazla adım gerektirdiği için implementasyonu daha karmaşıktır. Daha karmaşık olduğundan, birçok sağlayıcı implicit flow'yu önermeye yönelir. + +/// note | Not + +Her authentication provider'ın flow'ları markasının bir parçası yapmak için farklı şekilde adlandırması yaygındır. + +Ama sonuçta aynı OAuth2 standardını implement ediyorlar. + +/// + +**FastAPI**, bu OAuth2 authentication flow'larının tamamı için `fastapi.security.oauth2` içinde yardımcı araçlar sunar. + +## Decorator `dependencies` içinde `Security` { #security-in-decorator-dependencies } + +Decorator'ın `dependencies` parametresinde bir `list` `Depends` tanımlayabildiğiniz gibi ( [Path operation decorator'larında Dependencies](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} bölümünde açıklandığı üzere), burada `scopes` ile birlikte `Security` de kullanabilirsiniz. diff --git a/docs/tr/docs/advanced/settings.md b/docs/tr/docs/advanced/settings.md new file mode 100644 index 0000000000..e3bcaac610 --- /dev/null +++ b/docs/tr/docs/advanced/settings.md @@ -0,0 +1,302 @@ +# Ayarlar ve Ortam Değişkenleri { #settings-and-environment-variables } + +Birçok durumda uygulamanızın bazı harici ayarlara veya konfigürasyonlara ihtiyacı olabilir; örneğin secret key'ler, veritabanı kimlik bilgileri, e-posta servisleri için kimlik bilgileri vb. + +Bu ayarların çoğu değişkendir (değişebilir); örneğin veritabanı URL'leri. Ayrıca birçoğu hassas olabilir; örneğin secret'lar. + +Bu nedenle bunları, uygulama tarafından okunan environment variable'lar ile sağlamak yaygındır. + +/// tip | İpucu + +Environment variable'ları anlamak için [Environment Variables](../environment-variables.md){.internal-link target=_blank} dokümanını okuyabilirsiniz. + +/// + +## Tipler ve doğrulama { #types-and-validation } + +Bu environment variable'lar yalnızca metin (string) taşıyabilir; çünkü Python'ın dışındadırlar ve diğer programlarla ve sistemin geri kalanıyla uyumlu olmaları gerekir (hatta Linux, Windows, macOS gibi farklı işletim sistemleriyle de). + +Bu da, Python içinde bir environment variable'dan okunan herhangi bir değerin `str` olacağı anlamına gelir; farklı bir tipe dönüştürme veya herhangi bir doğrulama işlemi kod içinde yapılmalıdır. + +## Pydantic `Settings` { #pydantic-settings } + +Neyse ki Pydantic, environment variable'lardan gelen bu ayarları yönetmek için Pydantic: Settings management ile çok iyi bir yardımcı araç sunar. + +### `pydantic-settings`'i kurun { #install-pydantic-settings } + +Önce, [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, aktive ettiğinizden emin olun ve ardından `pydantic-settings` paketini kurun: + +
+ +```console +$ pip install pydantic-settings +---> 100% +``` + +
+ +Ayrıca `all` extras'ını şu şekilde kurduğunuzda da dahil gelir: + +
+ +```console +$ pip install "fastapi[all]" +---> 100% +``` + +
+ +### `Settings` nesnesini oluşturun { #create-the-settings-object } + +Pydantic'ten `BaseSettings` import edin ve bir alt sınıf (sub-class) oluşturun; tıpkı bir Pydantic model'inde olduğu gibi. + +Pydantic model'lerinde olduğu gibi, type annotation'larla (ve gerekirse default değerlerle) class attribute'ları tanımlarsınız. + +Pydantic model'lerinde kullandığınız aynı doğrulama özelliklerini ve araçlarını burada da kullanabilirsiniz; örneğin farklı veri tipleri ve `Field()` ile ek doğrulamalar. + +{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *} + +/// tip | İpucu + +Hızlıca kopyalayıp yapıştırmak istiyorsanız bu örneği kullanmayın; aşağıdaki son örneği kullanın. + +/// + +Ardından, bu `Settings` sınıfının bir instance'ını oluşturduğunuzda (bu örnekte `settings` nesnesi), Pydantic environment variable'ları büyük/küçük harfe duyarsız şekilde okur; yani büyük harfli `APP_NAME` değişkeni, yine de `app_name` attribute'u için okunur. + +Sonrasında veriyi dönüştürür ve doğrular. Böylece `settings` nesnesini kullandığınızda, tanımladığınız tiplerde verilere sahip olursunuz (örn. `items_per_user` bir `int` olur). + +### `settings`'i kullanın { #use-the-settings } + +Daha sonra uygulamanızda yeni `settings` nesnesini kullanabilirsiniz: + +{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *} + +### Server'ı çalıştırın { #run-the-server } + +Sonraki adımda server'ı çalıştırırken konfigürasyonları environment variable olarak geçersiniz; örneğin `ADMIN_EMAIL` ve `APP_NAME` şu şekilde ayarlanabilir: + +
+ +```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 | İpucu + +Tek bir komut için birden fazla env var ayarlamak istiyorsanız aralarına boşluk koyun ve hepsini komuttan önce yazın. + +/// + +Böylece `admin_email` ayarı `"deadpool@example.com"` olur. + +`app_name` `"ChimichangApp"` olur. + +`items_per_user` ise default değeri olan `50` olarak kalır. + +## Ayarları başka bir module'de tutma { #settings-in-another-module } + +[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank} bölümünde gördüğünüz gibi, bu ayarları başka bir module dosyasına koyabilirsiniz. + +Örneğin `config.py` adında bir dosyanız şu şekilde olabilir: + +{* ../../docs_src/settings/app01_py39/config.py *} + +Ve ardından bunu `main.py` dosyasında kullanabilirsiniz: + +{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *} + +/// tip | İpucu + +[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank} bölümünde gördüğünüz gibi, ayrıca bir `__init__.py` dosyasına da ihtiyacınız olacak. + +/// + +## Dependency içinde ayarlar { #settings-in-a-dependency } + +Bazı durumlarda, her yerde kullanılan global bir `settings` nesnesi yerine ayarları bir dependency üzerinden sağlamak faydalı olabilir. + +Bu özellikle test sırasında çok işe yarar; çünkü bir dependency'yi kendi özel ayarlarınızla override etmek çok kolaydır. + +### Config dosyası { #the-config-file } + +Bir önceki örnekten devam edersek, `config.py` dosyanız şöyle görünebilir: + +{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *} + +Dikkat edin, artık default bir instance `settings = Settings()` oluşturmuyoruz. + +### Ana uygulama dosyası { #the-main-app-file } + +Şimdi, yeni bir `config.Settings()` döndüren bir dependency oluşturuyoruz. + +{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *} + +/// tip | İpucu + +`@lru_cache` konusunu birazdan ele alacağız. + +Şimdilik `get_settings()`'in normal bir fonksiyon olduğunu varsayabilirsiniz. + +/// + +Sonra bunu dependency olarak *path operation function*'dan talep edebilir ve ihtiyaç duyduğumuz her yerde kullanabiliriz. + +{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *} + +### Ayarlar ve test { #settings-and-testing } + +Ardından, `get_settings` için bir dependency override oluşturarak test sırasında farklı bir settings nesnesi sağlamak çok kolay olur: + +{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *} + +Dependency override içinde, yeni `Settings` nesnesini oluştururken `admin_email` için yeni bir değer ayarlarız ve sonra bu yeni nesneyi döndürürüz. + +Sonrasında bunun kullanıldığını test edebiliriz. + +## `.env` dosyası okuma { #reading-a-env-file } + +Çok sayıda ayarınız varsa ve bunlar farklı ortamlarda sık sık değişiyorsa, bunları bir dosyaya koyup, sanki environment variable'mış gibi o dosyadan okumak faydalı olabilir. + +Bu yaklaşım oldukça yaygındır ve bir adı vardır: Bu environment variable'lar genellikle `.env` adlı bir dosyaya konur ve bu dosyaya "dotenv" denir. + +/// tip | İpucu + +Nokta (`.`) ile başlayan dosyalar, Linux ve macOS gibi Unix-benzeri sistemlerde gizli dosyadır. + +Ancak dotenv dosyasının mutlaka bu dosya adına sahip olması gerekmez. + +/// + +Pydantic, harici bir kütüphane kullanarak bu tür dosyalardan okuma desteğine sahiptir. Daha fazlası için: Pydantic Settings: Dotenv (.env) support. + +/// tip | İpucu + +Bunun çalışması için `pip install python-dotenv` yapmanız gerekir. + +/// + +### `.env` dosyası { #the-env-file } + +Şöyle bir `.env` dosyanız olabilir: + +```bash +ADMIN_EMAIL="deadpool@example.com" +APP_NAME="ChimichangApp" +``` + +### Ayarları `.env`'den okuyun { #read-settings-from-env } + +Ardından `config.py` dosyanızı şöyle güncelleyin: + +{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *} + +/// tip | İpucu + +`model_config` attribute'u yalnızca Pydantic konfigürasyonu içindir. Daha fazlası için Pydantic: Concepts: Configuration. + +/// + +Burada, Pydantic `Settings` sınıfınızın içinde `env_file` konfigürasyonunu tanımlar ve değer olarak kullanmak istediğimiz dotenv dosyasının dosya adını veririz. + +### `lru_cache` ile `Settings`'i yalnızca bir kez oluşturma { #creating-the-settings-only-once-with-lru-cache } + +Diskten dosya okumak normalde maliyetli (yavaş) bir işlemdir; bu yüzden muhtemelen bunu yalnızca bir kez yapıp aynı settings nesnesini tekrar kullanmak istersiniz. Her request için yeniden okumak istemezsiniz. + +Ancak her seferinde şunu yaptığımızda: + +```Python +Settings() +``` + +yeni bir `Settings` nesnesi oluşturulur ve oluşturulurken `.env` dosyasını yeniden okur. + +Dependency fonksiyonu sadece şöyle olsaydı: + +```Python +def get_settings(): + return Settings() +``` + +bu nesneyi her request için oluştururduk ve `.env` dosyasını her request'te okurduk. ⚠️ + +Fakat en üstte `@lru_cache` decorator'ünü kullandığımız için `Settings` nesnesi yalnızca bir kez, ilk çağrıldığı anda oluşturulur. ✔️ + +{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *} + +Sonraki request'lerde dependency'ler içinden `get_settings()` çağrıldığında, `get_settings()`'in iç kodu tekrar çalıştırılıp yeni bir `Settings` nesnesi yaratılmak yerine, ilk çağrıda döndürülen aynı nesne tekrar tekrar döndürülür. + +#### `lru_cache` Teknik Detayları { #lru-cache-technical-details } + +`@lru_cache`, decorator olarak uygulandığı fonksiyonu, her seferinde tekrar hesaplamak yerine ilk seferde döndürdüğü değeri döndürecek şekilde değiştirir; yani fonksiyon kodunu her çağrıda yeniden çalıştırmaz. + +Bu nedenle altındaki fonksiyon, argüman kombinasyonlarının her biri için bir kez çalıştırılır. Sonra bu argüman kombinasyonlarının her biri için döndürülmüş değerler, fonksiyon aynı argüman kombinasyonuyla çağrıldıkça tekrar tekrar kullanılır. + +Örneğin, şöyle bir fonksiyonunuz varsa: + +```Python +@lru_cache +def say_hi(name: str, salutation: str = "Ms."): + return f"Hello {salutation} {name}" +``` + +programınız şu şekilde çalışabilir: + +```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 +``` + +Bizim `get_settings()` dependency'miz özelinde ise fonksiyon hiç argüman almaz; dolayısıyla her zaman aynı değeri döndürür. + +Bu şekilde, neredeyse global bir değişken gibi davranır. Ancak bir dependency fonksiyonu kullandığı için testte kolayca override edebiliriz. + +`@lru_cache`, Python standart kütüphanesinin bir parçası olan `functools` içindedir. Daha fazla bilgi için: Python docs for `@lru_cache`. + +## Özet { #recap } + +Uygulamanızın ayarlarını veya konfigürasyonlarını yönetmek için, Pydantic model'lerinin tüm gücüyle birlikte Pydantic Settings'i kullanabilirsiniz. + +* Dependency kullanarak test etmeyi basitleştirebilirsiniz. +* Bununla `.env` dosyalarını kullanabilirsiniz. +* `@lru_cache` kullanmak, dotenv dosyasını her request için tekrar tekrar okumayı engellerken, test sırasında override etmenize de izin verir. diff --git a/docs/tr/docs/advanced/sub-applications.md b/docs/tr/docs/advanced/sub-applications.md new file mode 100644 index 0000000000..4773ba2004 --- /dev/null +++ b/docs/tr/docs/advanced/sub-applications.md @@ -0,0 +1,67 @@ +# Alt Uygulamalar - Mount İşlemi { #sub-applications-mounts } + +Kendi bağımsız OpenAPI şemaları ve kendi dokümantasyon arayüzleri olan iki bağımsız FastAPI uygulamasına ihtiyacınız varsa, bir ana uygulama oluşturup bir (veya daha fazla) alt uygulamayı "mount" edebilirsiniz. + +## Bir **FastAPI** uygulamasını mount etmek { #mounting-a-fastapi-application } + +"Mount" etmek, belirli bir path altında tamamen "bağımsız" bir uygulamayı eklemek anlamına gelir. Ardından o path’in altındaki her şeyi, alt uygulamada tanımlanan _path operation_’lar ile o alt uygulama yönetir. + +### Üst seviye uygulama { #top-level-application } + +Önce ana, üst seviye **FastAPI** uygulamasını ve onun *path operation*’larını oluşturun: + +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *} + +### Alt uygulama { #sub-application } + +Sonra alt uygulamanızı ve onun *path operation*’larını oluşturun. + +Bu alt uygulama da standart bir FastAPI uygulamasıdır; ancak "mount" edilecek olan budur: + +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *} + +### Alt uygulamayı mount edin { #mount-the-sub-application } + +Üst seviye uygulamanızda (`app`), alt uygulama `subapi`’yi mount edin. + +Bu örnekte `/subapi` path’ine mount edilecektir: + +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *} + +### Otomatik API dokümanlarını kontrol edin { #check-the-automatic-api-docs } + +Şimdi dosyanızla birlikte `fastapi` komutunu çalıştırın: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Ardından http://127.0.0.1:8000/docs adresinden dokümanları açın. + +Ana uygulama için otomatik API dokümanlarını göreceksiniz; yalnızca onun kendi _path operation_’larını içerir: + + + +Sonra alt uygulamanın dokümanlarını http://127.0.0.1:8000/subapi/docs adresinden açın. + +Alt uygulama için otomatik API dokümanlarını göreceksiniz; yalnızca onun kendi _path operation_’larını içerir ve hepsi doğru alt-path öneki `/subapi` altında yer alır: + + + +İki arayüzden herhangi biriyle etkileşime girmeyi denerseniz doğru şekilde çalıştıklarını görürsünüz; çünkü tarayıcı her bir uygulama ya da alt uygulama ile ayrı ayrı iletişim kurabilir. + +### Teknik Detaylar: `root_path` { #technical-details-root-path } + +Yukarıda anlatıldığı gibi bir alt uygulamayı mount ettiğinizde FastAPI, ASGI spesifikasyonundaki `root_path` adlı bir mekanizmayı kullanarak alt uygulamaya mount path’ini iletmeyi otomatik olarak yönetir. + +Bu sayede alt uygulama, dokümantasyon arayüzü için o path önekini kullanması gerektiğini bilir. + +Ayrıca alt uygulamanın kendi mount edilmiş alt uygulamaları da olabilir; FastAPI tüm bu `root_path`’leri otomatik olarak yönettiği için her şey doğru şekilde çalışır. + +`root_path` hakkında daha fazlasını ve bunu açıkça nasıl kullanacağınızı [Behind a Proxy](behind-a-proxy.md){.internal-link target=_blank} bölümünde öğreneceksiniz. diff --git a/docs/tr/docs/advanced/templates.md b/docs/tr/docs/advanced/templates.md new file mode 100644 index 0000000000..b91e0a2a84 --- /dev/null +++ b/docs/tr/docs/advanced/templates.md @@ -0,0 +1,126 @@ +# Şablonlar { #templates } + +**FastAPI** ile istediğiniz herhangi bir template engine'i kullanabilirsiniz. + +Yaygın bir tercih, Flask ve diğer araçların da kullandığı Jinja2'dir. + +Bunu kolayca yapılandırmak için, doğrudan **FastAPI** uygulamanızda kullanabileceğiniz yardımcı araçlar vardır (Starlette tarafından sağlanır). + +## Bağımlılıkları Yükleme { #install-dependencies } + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, etkinleştirdiğinizden ve `jinja2`'yi yüklediğinizden emin olun: + +
+ +```console +$ pip install jinja2 + +---> 100% +``` + +
+ +## `Jinja2Templates` Kullanımı { #using-jinja2templates } + +* `Jinja2Templates`'ı içe aktarın. +* Daha sonra tekrar kullanabileceğiniz bir `templates` nesnesi oluşturun. +* Template döndürecek *path operation* içinde bir `Request` parametresi tanımlayın. +* Oluşturduğunuz `templates` nesnesini kullanarak bir `TemplateResponse` render edip döndürün; template'in adını, request nesnesini ve Jinja2 template'i içinde kullanılacak anahtar-değer çiftlerini içeren bir "context" sözlüğünü (dict) iletin. + +{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *} + +/// note | Not + +FastAPI 0.108.0 ve Starlette 0.29.0 öncesinde, ilk parametre `name` idi. + +Ayrıca, daha önceki sürümlerde `request` nesnesi, Jinja2 için context içindeki anahtar-değer çiftlerinin bir parçası olarak geçirilirdi. + +/// + +/// tip | İpucu + +`response_class=HTMLResponse` olarak tanımlarsanız doküman arayüzü (docs UI) response'un HTML olacağını anlayabilir. + +/// + +/// note | Teknik Detaylar + +`from starlette.templating import Jinja2Templates` da kullanabilirsiniz. + +**FastAPI**, geliştirici için kolaylık olması adına `starlette.templating` içeriğini `fastapi.templating` olarak da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. `Request` ve `StaticFiles` için de aynı durum geçerlidir. + +/// + +## Template Yazma { #writing-templates } + +Ardından örneğin `templates/item.html` konumunda bir template yazabilirsiniz: + +```jinja hl_lines="7" +{!../../docs_src/templates/templates/item.html!} +``` + +### Template Context Değerleri { #template-context-values } + +Şu HTML içeriğinde: + +{% raw %} + +```jinja +Item ID: {{ id }} +``` + +{% endraw %} + +...gösterilecek olan `id`, sizin "context" olarak ilettiğiniz `dict` içinden alınır: + +```Python +{"id": id} +``` + +Örneğin ID değeri `42` ise, şu şekilde render edilir: + +```html +Item ID: 42 +``` + +### Template `url_for` Argümanları { #template-url-for-arguments } + +Template içinde `url_for()` da kullanabilirsiniz; argüman olarak, *path operation function*'ınızın kullandığı argümanların aynısını alır. + +Dolayısıyla şu bölüm: + +{% raw %} + +```jinja + +``` + +{% endraw %} + +...*path operation function* olan `read_item(id=id)` tarafından handle edilecek URL'nin aynısına bir link üretir. + +Örneğin ID değeri `42` ise, şu şekilde render edilir: + +```html + +``` + +## Template'ler ve statik dosyalar { #templates-and-static-files } + +Template içinde `url_for()` kullanabilir ve örneğin `name="static"` ile mount ettiğiniz `StaticFiles` ile birlikte kullanabilirsiniz. + +```jinja hl_lines="4" +{!../../docs_src/templates/templates/item.html!} +``` + +Bu örnekte, şu şekilde `static/styles.css` konumundaki bir CSS dosyasına link verir: + +```CSS hl_lines="4" +{!../../docs_src/templates/static/styles.css!} +``` + +Ve `StaticFiles` kullandığınız için, bu CSS dosyası **FastAPI** uygulamanız tarafından `/static/styles.css` URL'sinde otomatik olarak servis edilir. + +## Daha fazla detay { #more-details } + +Template'leri nasıl test edeceğiniz dahil daha fazla detay için Starlette'in template dokümantasyonuna bakın. diff --git a/docs/tr/docs/advanced/testing-dependencies.md b/docs/tr/docs/advanced/testing-dependencies.md new file mode 100644 index 0000000000..3cad637762 --- /dev/null +++ b/docs/tr/docs/advanced/testing-dependencies.md @@ -0,0 +1,53 @@ +# Override Kullanarak Dependency'leri Test Etme { #testing-dependencies-with-overrides } + +## Test Sırasında Dependency Override Etme { #overriding-dependencies-during-testing } + +Test yazarken bazı durumlarda bir dependency'yi override etmek isteyebilirsiniz. + +Orijinal dependency'nin (ve varsa tüm alt dependency'lerinin) çalışmasını istemezsiniz. + +Bunun yerine, yalnızca testler sırasında (hatta belki sadece belirli bazı testlerde) kullanılacak farklı bir dependency sağlarsınız; böylece orijinal dependency'nin ürettiği değerin kullanıldığı yerde, test için üretilen değeri kullanabilirsiniz. + +### Kullanım Senaryoları: Harici Servis { #use-cases-external-service } + +Örneğin, çağırmanız gereken harici bir authentication provider'ınız olabilir. + +Ona bir token gönderirsiniz ve o da authenticated bir user döndürür. + +Bu provider request başına ücret alıyor olabilir ve onu çağırmak, testlerde sabit bir mock user kullanmaya kıyasla daha fazla zaman alabilir. + +Muhtemelen harici provider'ı bir kez test etmek istersiniz; ancak çalışan her testte onu çağırmanız şart değildir. + +Bu durumda, o provider'ı çağıran dependency'yi override edebilir ve yalnızca testleriniz için mock user döndüren özel bir dependency kullanabilirsiniz. + +### `app.dependency_overrides` Attribute'ünü Kullanın { #use-the-app-dependency-overrides-attribute } + +Bu tür durumlar için **FastAPI** uygulamanızda `app.dependency_overrides` adında bir attribute bulunur; bu basit bir `dict`'tir. + +Test için bir dependency'yi override etmek istediğinizde, key olarak orijinal dependency'yi (bir function), value olarak da override edecek dependency'nizi (başka bir function) verirsiniz. + +Böylece **FastAPI**, orijinal dependency yerine bu override'ı çağırır. + +{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *} + +/// tip | İpucu + +**FastAPI** uygulamanızın herhangi bir yerinde kullanılan bir dependency için override tanımlayabilirsiniz. + +Orijinal dependency bir *path operation function* içinde, bir *path operation decorator* içinde (return value kullanmadığınız durumlarda), bir `.include_router()` çağrısında, vb. kullanılıyor olabilir. + +FastAPI yine de onu override edebilir. + +/// + +Sonrasında override'larınızı (yani kaldırıp sıfırlamayı) `app.dependency_overrides` değerini boş bir `dict` yaparak gerçekleştirebilirsiniz: + +```Python +app.dependency_overrides = {} +``` + +/// tip | İpucu + +Bir dependency'yi yalnızca bazı testler sırasında override etmek istiyorsanız, override'ı testin başında (test function'ının içinde) ayarlayıp testin sonunda (yine test function'ının sonunda) sıfırlayabilirsiniz. + +/// diff --git a/docs/tr/docs/advanced/testing-events.md b/docs/tr/docs/advanced/testing-events.md new file mode 100644 index 0000000000..f12aef9888 --- /dev/null +++ b/docs/tr/docs/advanced/testing-events.md @@ -0,0 +1,12 @@ +# Event'leri Test Etme: lifespan ve startup - shutdown { #testing-events-lifespan-and-startup-shutdown } + +Test'lerinizde `lifespan`'ın çalışması gerektiğinde, `TestClient`'ı bir `with` ifadesiyle kullanabilirsiniz: + +{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *} + + +Bu konuda daha fazla ayrıntıyı resmi Starlette dokümantasyon sitesindeki ["Running lifespan in tests in the official Starlette documentation site."](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) bölümünde okuyabilirsiniz. + +Kullanımdan kaldırılmış `startup` ve `shutdown` event'leri için ise `TestClient`'ı aşağıdaki gibi kullanabilirsiniz: + +{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *} diff --git a/docs/tr/docs/advanced/using-request-directly.md b/docs/tr/docs/advanced/using-request-directly.md new file mode 100644 index 0000000000..3efdafb032 --- /dev/null +++ b/docs/tr/docs/advanced/using-request-directly.md @@ -0,0 +1,56 @@ +# Request'i Doğrudan Kullanmak { #using-the-request-directly } + +Şu ana kadar, ihtiyacınız olan request parçalarını tipleriyle birlikte tanımlıyordunuz. + +Verileri şuradan alarak: + +* path'ten parameter olarak. +* Header'lardan. +* Cookie'lerden. +* vb. + +Bunu yaptığınızda **FastAPI**, bu verileri doğrular (validate eder), dönüştürür ve API'niz için dokümantasyonu otomatik olarak üretir. + +Ancak bazı durumlarda `Request` nesnesine doğrudan erişmeniz gerekebilir. + +## `Request` nesnesi hakkında detaylar { #details-about-the-request-object } + +**FastAPI** aslında altta **Starlette** çalıştırır ve üstüne çeşitli araçlardan oluşan bir katman ekler. Bu yüzden gerektiğinde Starlette'in `Request` nesnesini doğrudan kullanabilirsiniz. + +Bu ayrıca şu anlama gelir: `Request` nesnesinden veriyi doğrudan alırsanız (örneğin body'yi okursanız) FastAPI bu veriyi doğrulamaz, dönüştürmez veya dokümante etmez (otomatik API arayüzü için OpenAPI ile). + +Buna rağmen normal şekilde tanımladığınız diğer herhangi bir parameter (örneğin Pydantic model ile body) yine doğrulanır, dönüştürülür, annotate edilir, vb. + +Ama bazı özel durumlarda `Request` nesnesini almak faydalıdır. + +## `Request` nesnesini doğrudan kullanın { #use-the-request-object-directly } + +*Path operation function* içinde client'ın IP adresini/host'unu almak istediğinizi düşünelim. + +Bunun için request'e doğrudan erişmeniz gerekir. + +{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *} + +Tipi `Request` olan bir *path operation function* parameter'ı tanımladığınızda **FastAPI**, o parameter'a `Request` nesnesini geçmesi gerektiğini anlar. + +/// tip | İpucu + +Bu örnekte, request parameter'ının yanında bir path parameter'ı da tanımladığımıza dikkat edin. + +Dolayısıyla path parameter'ı çıkarılır, doğrulanır, belirtilen tipe dönüştürülür ve OpenAPI ile annotate edilir. + +Aynı şekilde, diğer parameter'ları normal biçimde tanımlamaya devam edip buna ek olarak `Request` de alabilirsiniz. + +/// + +## `Request` dokümantasyonu { #request-documentation } + +Resmi Starlette dokümantasyon sitesinde `Request` nesnesiyle ilgili daha fazla detayı okuyabilirsiniz. + +/// note | Teknik Detaylar + +`from starlette.requests import Request` de kullanabilirsiniz. + +**FastAPI** bunu size (geliştiriciye) kolaylık olsun diye doğrudan sunar. Ancak kendisi doğrudan Starlette'ten gelir. + +/// diff --git a/docs/tr/docs/advanced/websockets.md b/docs/tr/docs/advanced/websockets.md new file mode 100644 index 0000000000..775d7cc25f --- /dev/null +++ b/docs/tr/docs/advanced/websockets.md @@ -0,0 +1,186 @@ +# WebSockets { #websockets } + +**FastAPI** ile WebSockets kullanabilirsiniz. + +## `websockets` Kurulumu { #install-websockets } + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktive ettiğinizden ve `websockets`'i ("WebSocket" protokolünü kullanmayı kolaylaştıran bir Python kütüphanesi) kurduğunuzdan emin olun: + +
+ +```console +$ pip install websockets + +---> 100% +``` + +
+ +## WebSockets client { #websockets-client } + +### Production'da { #in-production } + +Production sisteminizde muhtemelen React, Vue.js veya Angular gibi modern bir framework ile oluşturulmuş bir frontend vardır. + +WebSockets kullanarak backend'inizle iletişim kurmak için de büyük ihtimalle frontend'inizin sağladığı yardımcı araçları kullanırsınız. + +Ya da native kod ile doğrudan WebSocket backend'inizle iletişim kuran native bir mobil uygulamanız olabilir. + +Veya WebSocket endpoint'i ile iletişim kurmak için başka herhangi bir yönteminizi de kullanıyor olabilirsiniz. + +--- + +Ancak bu örnek için, tamamı uzun bir string içinde olacak şekilde biraz JavaScript içeren çok basit bir HTML dokümanı kullanacağız. + +Elbette bu optimal değil ve production için kullanmazsınız. + +Production'da yukarıdaki seçeneklerden birini kullanırsınız. + +Ama WebSockets'in server tarafına odaklanmak ve çalışan bir örnek görmek için en basit yol bu: + +{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *} + +## Bir `websocket` Oluşturun { #create-a-websocket } + +**FastAPI** uygulamanızda bir `websocket` oluşturun: + +{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *} + +/// note | Teknik Detaylar + +`from starlette.websockets import WebSocket` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak işinizi kolaylaştırmak için aynı `WebSocket`'i doğrudan sağlar. Ancak aslında doğrudan Starlette'ten gelir. + +/// + +## Mesajları `await` Edin ve Mesaj Gönderin { #await-for-messages-and-send-messages } + +WebSocket route'unuzda mesajları `await` edebilir ve mesaj gönderebilirsiniz. + +{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *} + +Binary, text ve JSON verisi alıp gönderebilirsiniz. + +## Deneyin { #try-it } + +Dosyanızın adı `main.py` ise uygulamanızı şu şekilde çalıştırın: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Tarayıcınızda http://127.0.0.1:8000 adresini açın. + +Şuna benzer basit bir sayfa göreceksiniz: + + + +Input kutusuna mesaj yazıp gönderebilirsiniz: + + + +Ve WebSockets kullanan **FastAPI** uygulamanız yanıt döndürecektir: + + + +Birçok mesaj gönderebilir (ve alabilirsiniz): + + + +Ve hepsinde aynı WebSocket bağlantısı kullanılacaktır. + +## `Depends` ve Diğerlerini Kullanma { #using-depends-and-others } + +WebSocket endpoint'lerinde `fastapi` içinden import edip şunları kullanabilirsiniz: + +* `Depends` +* `Security` +* `Cookie` +* `Header` +* `Path` +* `Query` + +Diğer FastAPI endpoint'leri/*path operations* ile aynı şekilde çalışırlar: + +{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *} + +/// info | Bilgi + +Bu bir WebSocket olduğu için `HTTPException` raise etmek pek anlamlı değildir; bunun yerine `WebSocketException` raise ederiz. + +Spesifikasyonda tanımlanan geçerli kodlar arasından bir kapatma kodu kullanabilirsiniz. + +/// + +### Dependency'lerle WebSockets'i Deneyin { #try-the-websockets-with-dependencies } + +Dosyanızın adı `main.py` ise uygulamanızı şu şekilde çalıştırın: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Tarayıcınızda http://127.0.0.1:8000 adresini açın. + +Burada şunları ayarlayabilirsiniz: + +* path'te kullanılan "Item ID". +* query parametresi olarak kullanılan "Token". + +/// tip | İpucu + +query'deki `token` değerinin bir dependency tarafından ele alınacağına dikkat edin. + +/// + +Bununla WebSocket'e bağlanabilir, ardından mesaj gönderip alabilirsiniz: + + + +## Bağlantı Kopmalarını ve Birden Fazla Client'ı Yönetme { #handling-disconnections-and-multiple-clients } + +Bir WebSocket bağlantısı kapandığında, `await websocket.receive_text()` bir `WebSocketDisconnect` exception'ı raise eder; ardından bunu bu örnekteki gibi yakalayıp (catch) yönetebilirsiniz. + +{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *} + +Denemek için: + +* Uygulamayı birden fazla tarayıcı sekmesiyle açın. +* Bu sekmelerden mesaj yazın. +* Sonra sekmelerden birini kapatın. + +Bu, `WebSocketDisconnect` exception'ını raise eder ve diğer tüm client'lar şuna benzer bir mesaj alır: + +``` +Client #1596980209979 left the chat +``` + +/// tip | İpucu + +Yukarıdaki uygulama, birden fazla WebSocket bağlantısına mesajları nasıl yönetip broadcast edeceğinizi göstermek için minimal ve basit bir örnektir. + +Ancak her şey memory'de, tek bir list içinde yönetildiği için yalnızca process çalıştığı sürece ve yalnızca tek bir process ile çalışacaktır. + +FastAPI ile kolay entegre olan ama Redis, PostgreSQL vb. tarafından desteklenen daha sağlam bir şeye ihtiyacınız varsa encode/broadcaster'a göz atın. + +/// + +## Daha Fazla Bilgi { #more-info } + +Seçenekler hakkında daha fazlasını öğrenmek için Starlette dokümantasyonunda şunlara bakın: + +* `WebSocket` class'ı. +* Class tabanlı WebSocket yönetimi. diff --git a/docs/tr/docs/deployment/concepts.md b/docs/tr/docs/deployment/concepts.md new file mode 100644 index 0000000000..d0f5681469 --- /dev/null +++ b/docs/tr/docs/deployment/concepts.md @@ -0,0 +1,321 @@ +# Deployment Kavramları { #deployments-concepts } + +Bir **FastAPI** uygulamasını (hatta genel olarak herhangi bir web API'yi) deploy ederken, muhtemelen önemseyeceğiniz bazı kavramlar vardır. Bu kavramları kullanarak, **uygulamanızı deploy etmek** için **en uygun** yöntemi bulabilirsiniz. + +Önemli kavramlardan bazıları şunlardır: + +* Güvenlik - HTTPS +* Startup'ta çalıştırma +* Yeniden başlatmalar +* Replikasyon (çalışan process sayısı) +* Bellek +* Başlatmadan önceki adımlar + +Bunların **deployment**'ları nasıl etkilediğine bakalım. + +Nihai hedef, **API client**'larınıza **güvenli** bir şekilde hizmet verebilmek, **kesintileri** önlemek ve **hesaplama kaynaklarını** (ör. uzak server'lar/sanal makineler) olabildiğince verimli kullanmaktır. + +Burada bu **kavramlar** hakkında biraz daha bilgi vereceğim. Böylece, çok farklı ortamlarda—hatta bugün var olmayan **gelecekteki** ortamlarda bile—API'nizi nasıl deploy edeceğinize karar verirken ihtiyaç duyacağınız **sezgiyi** kazanmış olursunuz. + +Bu kavramları dikkate alarak, **kendi API**'leriniz için en iyi deployment yaklaşımını **değerlendirebilir ve tasarlayabilirsiniz**. + +Sonraki bölümlerde, FastAPI uygulamalarını deploy etmek için daha **somut tarifler** (recipes) paylaşacağım. + +Ama şimdilik, bu önemli **kavramsal fikirleri** inceleyelim. Bu kavramlar diğer tüm web API türleri için de geçerlidir. + +## Güvenlik - HTTPS { #security-https } + +[HTTPS hakkındaki önceki bölümde](https.md){.internal-link target=_blank} HTTPS'in API'niz için nasıl şifreleme sağladığını öğrenmiştik. + +Ayrıca HTTPS'in genellikle uygulama server'ınızın **dışında** yer alan bir bileşen tarafından sağlandığını, yani bir **TLS Termination Proxy** ile yapıldığını da görmüştük. + +Ve **HTTPS sertifikalarını yenilemekten** sorumlu bir şey olmalıdır; bu aynı bileşen olabileceği gibi farklı bir bileşen de olabilir. + +### HTTPS için Örnek Araçlar { #example-tools-for-https } + +TLS Termination Proxy olarak kullanabileceğiniz bazı araçlar: + +* Traefik + * Sertifika yenilemelerini otomatik yönetir +* Caddy + * Sertifika yenilemelerini otomatik yönetir +* Nginx + * Sertifika yenilemeleri için Certbot gibi harici bir bileşenle +* HAProxy + * Sertifika yenilemeleri için Certbot gibi harici bir bileşenle +* Nginx gibi bir Ingress Controller ile Kubernetes + * Sertifika yenilemeleri için cert-manager gibi harici bir bileşenle +* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi (aşağıyı okuyun) + +Bir diğer seçenek de, HTTPS kurulumunu da dahil olmak üzere işin daha büyük kısmını yapan bir **cloud service** kullanmaktır. Bunun bazı kısıtları olabilir veya daha pahalı olabilir vb. Ancak bu durumda TLS Termination Proxy'yi kendiniz kurmak zorunda kalmazsınız. + +Sonraki bölümlerde bazı somut örnekler göstereceğim. + +--- + +Sonraki kavramlar, gerçek API'nizi çalıştıran programla (ör. Uvicorn) ilgilidir. + +## Program ve Process { #program-and-process } + +Çalışan "**process**" hakkında çok konuşacağız. Bu yüzden ne anlama geldiğini ve "**program**" kelimesinden farkının ne olduğunu netleştirmek faydalı. + +### Program Nedir { #what-is-a-program } + +**Program** kelimesi günlük kullanımda birçok şeyi anlatmak için kullanılır: + +* Yazdığınız **code**, yani **Python dosyaları**. +* İşletim sistemi tarafından **çalıştırılabilen** **dosya**, örn: `python`, `python.exe` veya `uvicorn`. +* İşletim sistemi üzerinde **çalışır durumdayken** CPU kullanan ve bellekte veri tutan belirli bir program. Buna **process** de denir. + +### Process Nedir { #what-is-a-process } + +**Process** kelimesi genellikle daha spesifik kullanılır; yalnızca işletim sistemi üzerinde çalışan şeye (yukarıdaki son madde gibi) işaret eder: + +* İşletim sistemi üzerinde **çalışır durumda** olan belirli bir program. + * Bu; dosyayı ya da code'u değil, işletim sistemi tarafından **çalıştırılan** ve yönetilen şeyi ifade eder. +* Herhangi bir program, herhangi bir code, **yalnızca çalıştırılırken** bir şey yapabilir. Yani bir **process çalışıyorken**. +* Process siz tarafından veya işletim sistemi tarafından **sonlandırılabilir** (ya da "killed" edilebilir). O anda çalışması/çalıştırılması durur ve artık **hiçbir şey yapamaz**. +* Bilgisayarınızda çalışan her uygulamanın arkasında bir process vardır; çalışan her program, her pencere vb. Bilgisayar açıkken normalde **aynı anda** birçok process çalışır. +* Aynı anda **aynı programın birden fazla process**'i çalışabilir. + +İşletim sisteminizdeki "task manager" veya "system monitor" (ya da benzeri araçlar) ile bu process'lerin birçoğunu çalışır halde görebilirsiniz. + +Örneğin muhtemelen aynı browser programını (Firefox, Chrome, Edge vb.) çalıştıran birden fazla process göreceksiniz. Genelde her tab için bir process, üstüne bazı ek process'ler çalıştırırlar. + + + +--- + +Artık **process** ve **program** arasındaki farkı bildiğimize göre, deployment konusuna devam edelim. + +## Startup'ta Çalıştırma { #running-on-startup } + +Çoğu durumda bir web API oluşturduğunuzda, client'larınızın her zaman erişebilmesi için API'nizin kesintisiz şekilde **sürekli çalışıyor** olmasını istersiniz. Elbette sadece belirli durumlarda çalışmasını istemenizin özel bir sebebi olabilir; ancak çoğunlukla onu sürekli açık ve **kullanılabilir** halde tutarsınız. + +### Uzak Bir Server'da { #in-a-remote-server } + +Uzak bir server (cloud server, sanal makine vb.) kurduğunuzda, yapabileceğiniz en basit şey; local geliştirme sırasında yaptığınız gibi, manuel olarak `fastapi run` (Uvicorn'u kullanır) veya benzeri bir komutla çalıştırmaktır. + +Bu yöntem çalışır ve **geliştirme sırasında** faydalıdır. + +Ancak server'a olan bağlantınız koparsa, **çalışan process** muhtemelen ölür. + +Ve server yeniden başlatılırsa (örneğin update'lerden sonra ya da cloud provider'ın migration'larından sonra) bunu muhtemelen **fark etmezsiniz**. Dolayısıyla process'i manuel yeniden başlatmanız gerektiğini de bilmezsiniz. Sonuçta API'niz ölü kalır. + +### Startup'ta Otomatik Çalıştırma { #run-automatically-on-startup } + +Genellikle server programının (ör. Uvicorn) server açılışında otomatik başlamasını ve herhangi bir **insan müdahalesi** gerektirmeden API'nizi çalıştıran bir process'in sürekli ayakta olmasını istersiniz (ör. FastAPI uygulamanızı çalıştıran Uvicorn). + +### Ayrı Bir Program { #separate-program } + +Bunu sağlamak için genellikle startup'ta uygulamanızın çalıştığından emin olacak **ayrı bir program** kullanırsınız. Pek çok durumda bu program, örneğin bir veritabanı gibi diğer bileşenlerin/uygulamaların da çalıştığından emin olur. + +### Startup'ta Çalıştırmak için Örnek Araçlar { #example-tools-to-run-at-startup } + +Bu işi yapabilen araçlara örnekler: + +* Docker +* Kubernetes +* Docker Compose +* Docker in Swarm Mode +* Systemd +* Supervisor +* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi +* Diğerleri... + +Sonraki bölümlerde daha somut örnekler vereceğim. + +## Yeniden Başlatmalar { #restarts } + +Uygulamanızın startup'ta çalıştığından emin olmaya benzer şekilde, hatalardan sonra **yeniden başlatıldığından** da emin olmak istersiniz. + +### Hata Yaparız { #we-make-mistakes } + +Biz insanlar sürekli **hata** yaparız. Yazılımın neredeyse *her zaman* farklı yerlerinde gizli **bug**'lar vardır. + +Ve biz geliştiriciler bu bug'ları buldukça ve yeni özellikler ekledikçe code'u iyileştiririz (muhtemelen yeni bug'lar da ekleyerek). + +### Küçük Hatalar Otomatik Yönetilir { #small-errors-automatically-handled } + +FastAPI ile web API geliştirirken, code'umuzda bir hata olursa FastAPI genellikle bunu hatayı tetikleyen tek request ile sınırlar. + +Client o request için **500 Internal Server Error** alır; ancak uygulama tamamen çöküp durmak yerine sonraki request'ler için çalışmaya devam eder. + +### Daha Büyük Hatalar - Çökmeler { #bigger-errors-crashes } + +Yine de bazı durumlarda, yazdığımız bir code **tüm uygulamayı çökertip** Uvicorn ve Python'ın crash olmasına neden olabilir. + +Böyle bir durumda, tek bir noktadaki hata yüzünden uygulamanın ölü kalmasını istemezsiniz; bozuk olmayan *path operations* en azından çalışmaya devam etsin istersiniz. + +### Crash Sonrası Yeniden Başlatma { #restart-after-crash } + +Ancak çalışan **process**'i çökerten gerçekten kötü hatalarda, process'i **yeniden başlatmaktan** sorumlu harici bir bileşen istersiniz; en azından birkaç kez... + +/// tip | İpucu + +...Yine de uygulama **hemen crash oluyorsa**, onu sonsuza kadar yeniden başlatmaya çalışmanın pek anlamı yoktur. Böyle durumları büyük ihtimalle geliştirme sırasında ya da en geç deploy'dan hemen sonra fark edersiniz. + +O yüzden ana senaryoya odaklanalım: Gelecekte bazı özel durumlarda tamamen çökebilir ve yine de yeniden başlatmak mantıklıdır. + +/// + +Uygulamanızı yeniden başlatmakla görevli bileşenin **harici bir bileşen** olmasını istersiniz. Çünkü o noktada Uvicorn ve Python ile birlikte aynı uygulama zaten crash olmuştur; aynı app'in içindeki aynı code'un bunu düzeltmek için yapabileceği bir şey kalmaz. + +### Otomatik Yeniden Başlatma için Örnek Araçlar { #example-tools-to-restart-automatically } + +Çoğu durumda, **startup'ta programı çalıştırmak** için kullanılan aracın aynısı otomatik **restart**'ları yönetmek için de kullanılır. + +Örneğin bu şunlarla yönetilebilir: + +* Docker +* Kubernetes +* Docker Compose +* Docker in Swarm Mode +* Systemd +* Supervisor +* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi +* Diğerleri... + +## Replikasyon - Process'ler ve Bellek { #replication-processes-and-memory } + +FastAPI uygulamasında, Uvicorn'u çalıştıran `fastapi` komutu gibi bir server programı kullanırken, uygulamayı **tek bir process** içinde bir kez çalıştırmak bile aynı anda birden fazla client'a hizmet verebilir. + +Ancak birçok durumda, aynı anda birden fazla worker process çalıştırmak istersiniz. + +### Birden Fazla Process - Worker'lar { #multiple-processes-workers } + +Tek bir process'in karşılayabileceğinden daha fazla client'ınız varsa (örneğin sanal makine çok büyük değilse) ve server CPU'sunda **birden fazla core** varsa, aynı uygulamayla **birden fazla process** çalıştırıp tüm request'leri bunlara dağıtabilirsiniz. + +Aynı API programının **birden fazla process**'ini çalıştırdığınızda, bunlara genellikle **worker** denir. + +### Worker Process'ler ve Port'lar { #worker-processes-and-ports } + +[HTTPS hakkındaki dokümanda](https.md){.internal-link target=_blank} bir server'da aynı port ve IP adresi kombinasyonunu yalnızca tek bir process'in dinleyebileceğini hatırlıyor musunuz? + +Bu hâlâ geçerli. + +Dolayısıyla **aynı anda birden fazla process** çalıştırabilmek için, **port** üzerinde dinleyen **tek bir process** olmalı ve bu process iletişimi bir şekilde worker process'lere aktarmalıdır. + +### Process Başına Bellek { #memory-per-process } + +Program belleğe bir şeyler yüklediğinde—örneğin bir değişkende bir machine learning modelini veya büyük bir dosyanın içeriğini tutmak gibi—bunların hepsi server'ın **belleğini (RAM)** tüketir. + +Ve birden fazla process normalde **belleği paylaşmaz**. Yani her çalışan process'in kendi verileri, değişkenleri ve belleği vardır. Code'unuz çok bellek tüketiyorsa, **her process** buna denk bir miktar bellek tüketir. + +### Server Belleği { #server-memory } + +Örneğin code'unuz **1 GB** boyutunda bir Machine Learning modelini yüklüyorsa, API'niz tek process ile çalışırken en az 1 GB RAM tüketir. **4 process** (4 worker) başlatırsanız her biri 1 GB RAM tüketir. Yani toplamda API'niz **4 GB RAM** tüketir. + +Uzak server'ınız veya sanal makineniz yalnızca 3 GB RAM'e sahipse, 4 GB'tan fazla RAM yüklemeye çalışmak sorun çıkarır. + +### Birden Fazla Process - Bir Örnek { #multiple-processes-an-example } + +Bu örnekte, iki adet **Worker Process** başlatıp kontrol eden bir **Manager Process** vardır. + +Bu Manager Process büyük ihtimalle IP üzerindeki **port**'u dinleyen süreçtir ve tüm iletişimi worker process'lere aktarır. + +Worker process'ler uygulamanızı çalıştıran process'lerdir; bir **request** alıp bir **response** döndürmek için asıl hesaplamaları yaparlar ve sizin RAM'de değişkenlere koyduğunuz her şeyi yüklerler. + + + +Elbette aynı makinede, uygulamanız dışında da muhtemelen **başka process**'ler çalışır. + +İlginç bir detay: Her process'in kullandığı **CPU** yüzdesi zaman içinde çok **değişken** olabilir; ancak **bellek (RAM)** genellikle az çok **stabil** kalır. + +Eğer API'niz her seferinde benzer miktarda hesaplama yapıyorsa ve çok sayıda client'ınız varsa, **CPU kullanımı** da muhtemelen *stabil olur* (hızlı hızlı sürekli yükselip alçalmak yerine). + +### Replikasyon Araçları ve Stratejileri Örnekleri { #examples-of-replication-tools-and-strategies } + +Bunu başarmak için farklı yaklaşımlar olabilir. Sonraki bölümlerde, örneğin Docker ve container'lar konuşurken, belirli stratejileri daha detaylı anlatacağım. + +Dikkate almanız gereken ana kısıt şudur: **public IP** üzerindeki **port**'u yöneten **tek** bir bileşen olmalı. Sonrasında bu bileşenin, replikasyonla çoğaltılmış **process/worker**'lara iletişimi **aktarmanın** bir yoluna sahip olması gerekir. + +Olası kombinasyonlar ve stratejiler: + +* `--workers` ile **Uvicorn** + * Bir Uvicorn **process manager** **IP** ve **port** üzerinde dinler ve **birden fazla Uvicorn worker process** başlatır. +* **Kubernetes** ve diğer dağıtık **container sistemleri** + * **Kubernetes** katmanında bir şey **IP** ve **port** üzerinde dinler. Replikasyon, her birinde **tek bir Uvicorn process** çalışan **birden fazla container** ile yapılır. +* Bunu sizin yerinize yapan **cloud service**'ler + * Cloud service muhtemelen **replikasyonu sizin yerinize yönetir**. Size çalıştırılacak **bir process** veya kullanılacak bir **container image** tanımlama imkânı verebilir; her durumda büyük ihtimalle **tek bir Uvicorn process** olur ve bunu çoğaltmaktan cloud service sorumlu olur. + +/// tip | İpucu + +**Container**, Docker veya Kubernetes ile ilgili bazı maddeler şimdilik çok anlamlı gelmiyorsa dert etmeyin. + +Container image'ları, Docker, Kubernetes vb. konuları ilerideki bir bölümde daha detaylı anlatacağım: [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank}. + +/// + +## Başlatmadan Önceki Adımlar { #previous-steps-before-starting } + +Uygulamanızı **başlatmadan önce** bazı adımlar yapmak isteyeceğiniz birçok durum vardır. + +Örneğin **database migrations** çalıştırmak isteyebilirsiniz. + +Ancak çoğu durumda, bu adımları yalnızca **bir kez** çalıştırmak istersiniz. + +Bu yüzden, uygulamayı başlatmadan önce bu **ön adımları** çalıştıracak **tek bir process** olmasını istersiniz. + +Ve daha sonra uygulamanın kendisi için **birden fazla process** (birden fazla worker) başlatsanız bile, bu ön adımları çalıştıranın *yine* tek process olduğundan emin olmalısınız. Bu adımlar **birden fazla process** tarafından çalıştırılsaydı, işi **paralel** şekilde tekrarlarlardı. Adımlar database migration gibi hassas bir şeyse, birbirleriyle çakışıp çatışma çıkarabilirler. + +Elbette bazı durumlarda ön adımları birden fazla kez çalıştırmak sorun değildir; bu durumda yönetmesi çok daha kolay olur. + +/// tip | İpucu + +Ayrıca, kurulumunuza bağlı olarak bazı durumlarda uygulamanızı başlatmadan önce **hiç ön adıma ihtiyaç duymayabilirsiniz**. + +Bu durumda bunların hiçbirini düşünmeniz gerekmez. + +/// + +### Ön Adımlar için Strateji Örnekleri { #examples-of-previous-steps-strategies } + +Bu konu, **sisteminizi nasıl deploy ettiğinize** çok bağlıdır ve muhtemelen programları nasıl başlattığınız, restart'ları nasıl yönettiğiniz vb. ile bağlantılıdır. + +Bazı olası fikirler: + +* Kubernetes'te, app container'ınızdan önce çalışan bir "Init Container" +* Ön adımları çalıştırıp sonra uygulamanızı başlatan bir bash script + * Yine de o bash script'i başlatmak/restart etmek, hataları tespit etmek vb. için bir mekanizmaya ihtiyacınız olur. + +/// tip | İpucu + +Bunu container'larla nasıl yapabileceğinize dair daha somut örnekleri ilerideki bir bölümde anlatacağım: [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank}. + +/// + +## Kaynak Kullanımı { #resource-utilization } + +Server(lar)ınız bir **kaynaktır**. Programlarınızla CPU'lardaki hesaplama zamanını ve mevcut RAM belleğini tüketebilir veya **kullanabilirsiniz**. + +Sistem kaynaklarının ne kadarını tüketmek/kullanmak istersiniz? "Az" demek kolaydır; ancak pratikte hedef genellikle **çökmeden mümkün olduğunca fazla** kullanmaktır. + +3 server için para ödüyor ama onların RAM ve CPU'sunun yalnızca küçük bir kısmını kullanıyorsanız, muhtemelen **para israf ediyorsunuz** ve muhtemelen **elektrik tüketimini** de gereksiz yere artırıyorsunuz vb. + +Bu durumda 2 server ile devam edip onların kaynaklarını (CPU, bellek, disk, ağ bant genişliği vb.) daha yüksek oranlarda kullanmak daha iyi olabilir. + +Öte yandan, 2 server'ınız var ve CPU ile RAM'in **%100**'ünü kullanıyorsanız, bir noktada bir process daha fazla bellek ister; server diski "bellek" gibi kullanmak zorunda kalır (binlerce kat daha yavaş olabilir) ya da hatta **crash** edebilir. Ya da bir process bir hesaplama yapmak ister ve CPU tekrar boşalana kadar beklemek zorunda kalır. + +Bu senaryoda **bir server daha** eklemek ve bazı process'leri orada çalıştırmak daha iyi olur; böylece hepsinin **yeterli RAM'i ve CPU zamanı** olur. + +Ayrıca, herhangi bir sebeple API'nizde bir kullanım **spike**'ı olma ihtimali de vardır. Belki viral olur, belki başka servisler veya bot'lar kullanmaya başlar. Bu durumlarda güvende olmak için ekstra kaynak isteyebilirsiniz. + +Hedef olarak **keyfi bir sayı** belirleyebilirsiniz; örneğin kaynak kullanımını **%50 ile %90 arasında** tutmak gibi. Önemli olan, bunların muhtemelen ölçmek isteyeceğiniz ve deployment'larınızı ayarlamak için kullanacağınız ana metrikler olmasıdır. + +Server'ınızda CPU ve RAM kullanımını veya her process'in ne kadar kullandığını görmek için `htop` gibi basit araçları kullanabilirsiniz. Ya da server'lar arasında dağıtık çalışan daha karmaşık monitoring araçları kullanabilirsiniz. + +## Özet { #recap } + +Uygulamanızı nasıl deploy edeceğinize karar verirken aklınızda tutmanız gereken ana kavramların bazılarını okudunuz: + +* Güvenlik - HTTPS +* Startup'ta çalıştırma +* Yeniden başlatmalar +* Replikasyon (çalışan process sayısı) +* Bellek +* Başlatmadan önceki adımlar + +Bu fikirleri ve nasıl uygulayacağınızı anlamak, deployment'larınızı yapılandırırken ve ince ayar yaparken ihtiyaç duyacağınız sezgiyi kazanmanızı sağlamalıdır. + +Sonraki bölümlerde, izleyebileceğiniz stratejilere dair daha somut örnekler paylaşacağım. diff --git a/docs/tr/docs/deployment/docker.md b/docs/tr/docs/deployment/docker.md new file mode 100644 index 0000000000..b48d2ddf58 --- /dev/null +++ b/docs/tr/docs/deployment/docker.md @@ -0,0 +1,620 @@ +# Container'larda FastAPI - Docker { #fastapi-in-containers-docker } + +FastAPI uygulamalarını deploy ederken yaygın bir yaklaşım, bir **Linux container image** oluşturmaktır. Bu genellikle **Docker** kullanılarak yapılır. Ardından bu container image'ı birkaç farklı yöntemden biriyle deploy edebilirsiniz. + +Linux container'ları kullanmanın **güvenlik**, **tekrarlanabilirlik**, **basitlik** gibi birçok avantajı vardır. + +/// tip | İpucu + +Aceleniz var ve bunları zaten biliyor musunuz? Aşağıdaki [`Dockerfile`'a atlayın 👇](#build-a-docker-image-for-fastapi). + +/// + +
+Dockerfile Önizleme 👀 + +```Dockerfile +FROM python:3.9 + +WORKDIR /code + +COPY ./requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +COPY ./app /code/app + +CMD ["fastapi", "run", "app/main.py", "--port", "80"] + +# If running behind a proxy like Nginx or Traefik add --proxy-headers +# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"] +``` + +
+ +## Container Nedir { #what-is-a-container } + +Container'lar (özellikle Linux container'ları), bir uygulamayı tüm bağımlılıkları ve gerekli dosyalarıyla birlikte paketlemenin, aynı sistemdeki diğer container'lardan (diğer uygulama ya da bileşenlerden) izole tutarken yapılan, çok **hafif** bir yoludur. + +Linux container'ları, host'un (makine, sanal makine, cloud server vb.) aynı Linux kernel'ini kullanarak çalışır. Bu da, tüm bir işletim sistemini emüle eden tam sanal makinelere kıyasla çok daha hafif oldukları anlamına gelir. + +Bu sayede container'lar **az kaynak** tüketir; süreçleri doğrudan çalıştırmaya benzer bir seviyede (bir sanal makine çok daha fazla tüketirdi). + +Container'ların ayrıca kendi **izole** çalışan process'leri (çoğunlukla tek bir process), dosya sistemi ve ağı vardır. Bu da deployment, güvenlik, geliştirme vb. süreçleri kolaylaştırır. + +## Container Image Nedir { #what-is-a-container-image } + +Bir **container**, bir **container image**'dan çalıştırılır. + +Container image; bir container içinde bulunması gereken tüm dosyaların, environment variable'ların ve varsayılan komut/programın **statik** bir sürümüdür. Buradaki **statik**, container **image**'ının çalışmadığı, execute edilmediği; sadece paketlenmiş dosyalar ve metadata olduğu anlamına gelir. + +Depolanmış statik içerik olan "**container image**"ın aksine, "**container**" normalde çalışan instance'ı, yani **execute edilen** şeyi ifade eder. + +**Container** başlatılıp çalıştığında (bir **container image**'dan başlatılır), dosyalar oluşturabilir/değiştirebilir, environment variable'ları değiştirebilir vb. Bu değişiklikler sadece o container içinde kalır; alttaki container image'da kalıcı olmaz (diske kaydedilmez). + +Bir container image, **program** dosyası ve içeriklerine benzetilebilir; örn. `python` ve `main.py` gibi bir dosya. + +Ve **container**'ın kendisi (container image'a karşıt olarak) image'ın gerçek çalışan instance'ıdır; bir **process**'e benzer. Hatta bir container, yalnızca içinde **çalışan bir process** varken çalışır (ve genelde tek process olur). İçinde çalışan process kalmayınca container durur. + +## Container Image'lar { #container-images } + +Docker, **container image** ve **container** oluşturup yönetmek için kullanılan başlıca araçlardan biri olmuştur. + +Ayrıca birçok araç, ortam, veritabanı ve uygulama için önceden hazırlanmış **resmi container image**'ların bulunduğu herkese açık bir Docker Hub vardır. + +Örneğin, resmi bir Python Image bulunur. + +Ve veritabanları gibi farklı şeyler için de birçok image vardır; örneğin: + +* PostgreSQL +* MySQL +* MongoDB +* Redis, vb. + +Hazır bir container image kullanarak farklı araçları **birleştirmek** ve birlikte kullanmak çok kolaydır. Örneğin yeni bir veritabanını denemek için. Çoğu durumda **resmi image**'ları kullanıp sadece environment variable'lar ile yapılandırmanız yeterlidir. + +Bu şekilde, çoğu zaman container'lar ve Docker hakkında öğrendiklerinizi farklı araç ve bileşenlerde tekrar kullanabilirsiniz. + +Dolayısıyla; veritabanı, Python uygulaması, React frontend uygulaması olan bir web server gibi farklı şeyler için **birden fazla container** çalıştırır ve bunları internal network üzerinden birbirine bağlarsınız. + +Docker veya Kubernetes gibi tüm container yönetim sistemlerinde bu ağ özellikleri entegre olarak bulunur. + +## Container'lar ve Process'ler { #containers-and-processes } + +Bir **container image** normalde metadata içinde, **container** başlatıldığında çalıştırılacak varsayılan program/komutu ve o programa geçirilecek parametreleri içerir. Bu, komut satırında yazacağınız şeye çok benzer. + +Bir **container** başlatıldığında bu komutu/programı çalıştırır (ancak isterseniz bunu override edip başka bir komut/program çalıştırabilirsiniz). + +Bir container, **ana process** (komut/program) çalıştığı sürece çalışır. + +Container'larda normalde **tek bir process** olur. Ancak ana process içinden subprocess'ler başlatmak da mümkündür; böylece aynı container içinde **birden fazla process** olur. + +Ama **en az bir çalışan process olmadan** çalışan bir container olamaz. Ana process durursa container da durur. + +## FastAPI için Docker Image Oluşturalım { #build-a-docker-image-for-fastapi } + +Tamam, şimdi bir şeyler inşa edelim! 🚀 + +Resmi **Python** image'ını temel alarak, FastAPI için **sıfırdan** bir **Docker image** nasıl oluşturulur göstereceğim. + +Bu, örneğin şu durumlarda **çoğu zaman** yapmak isteyeceğiniz şeydir: + +* **Kubernetes** veya benzeri araçlar kullanırken +* **Raspberry Pi** üzerinde çalıştırırken +* Container image'ınızı sizin için çalıştıran bir cloud servisi kullanırken, vb. + +### Paket Gereksinimleri { #package-requirements } + +Uygulamanızın **paket gereksinimleri** genelde bir dosyada yer alır. + +Bu, gereksinimleri **yüklemek** için kullandığınız araca göre değişir. + +En yaygın yöntem, paket adları ve versiyonlarının satır satır yazıldığı bir `requirements.txt` dosyasına sahip olmaktır. + +Versiyon aralıklarını belirlemek için elbette [FastAPI sürümleri hakkında](versions.md){.internal-link target=_blank} bölümünde okuduğunuz fikirleri kullanırsınız. + +Örneğin `requirements.txt` şöyle görünebilir: + +``` +fastapi[standard]>=0.113.0,<0.114.0 +pydantic>=2.7.0,<3.0.0 +``` + +Ve bu bağımlılıkları normalde `pip` ile yüklersiniz, örneğin: + +
+ +```console +$ pip install -r requirements.txt +---> 100% +Successfully installed fastapi pydantic +``` + +
+ +/// info | Bilgi + +Paket bağımlılıklarını tanımlamak ve yüklemek için başka formatlar ve araçlar da vardır. + +/// + +### **FastAPI** Kodunu Oluşturun { #create-the-fastapi-code } + +* Bir `app` dizini oluşturun ve içine girin. +* Boş bir `__init__.py` dosyası oluşturun. +* Aşağıdakilerle bir `main.py` dosyası oluşturun: + +```Python +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +### Dockerfile { #dockerfile } + +Şimdi aynı proje dizininde `Dockerfile` adlı bir dosya oluşturun ve içine şunları yazın: + +```{ .dockerfile .annotate } +# (1)! +FROM python:3.9 + +# (2)! +WORKDIR /code + +# (3)! +COPY ./requirements.txt /code/requirements.txt + +# (4)! +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# (5)! +COPY ./app /code/app + +# (6)! +CMD ["fastapi", "run", "app/main.py", "--port", "80"] +``` + +1. Resmi Python base image'ından başlayın. + +2. Geçerli çalışma dizinini `/code` olarak ayarlayın. + + `requirements.txt` dosyasını ve `app` dizinini buraya koyacağız. + +3. Gereksinimleri içeren dosyayı `/code` dizinine kopyalayın. + + Önce kodun tamamını değil, **sadece** gereksinim dosyasını kopyalayın. + + Bu dosya **çok sık değişmediği** için Docker bunu tespit eder ve bu adımda **cache** kullanır; böylece bir sonraki adım için de cache devreye girer. + +4. Gereksinim dosyasındaki paket bağımlılıklarını yükleyin. + + `--no-cache-dir` seçeneği, indirilen paketlerin yerel olarak kaydedilmemesini `pip`'e söyler. Bu kayıt, `pip` aynı paketleri tekrar yüklemek için yeniden çalıştırılacaksa işe yarar; ancak container'larla çalışırken genelde bu durum geçerli değildir. + + /// note | Not + + `--no-cache-dir` yalnızca `pip` ile ilgilidir; Docker veya container'larla ilgili değildir. + + /// + + `--upgrade` seçeneği, paketler zaten yüklüyse `pip`'e onları yükseltmesini söyler. + + Bir önceki adım (dosyayı kopyalama) **Docker cache** tarafından tespit edilebildiği için, bu adım da uygun olduğunda **Docker cache'i kullanır**. + + Bu adımda cache kullanmak, geliştirme sırasında image'ı tekrar tekrar build ederken size çok **zaman** kazandırır; her seferinde bağımlılıkları **indirip yüklemek** zorunda kalmazsınız. + +5. `./app` dizinini `/code` dizininin içine kopyalayın. + + Burada en sık değişen şey olan kodun tamamı bulunduğundan, bu adım (ve genelde bundan sonraki adımlar) için Docker **cache**'i kolay kolay kullanılamaz. + + Bu yüzden, container image build sürelerini optimize etmek için bunu `Dockerfile`'ın **sonlarına yakın** koymak önemlidir. + +6. Altta Uvicorn kullanan `fastapi run` komutunu **command** olarak ayarlayın. + + `CMD` bir string listesi alır; bu string'lerin her biri komut satırında boşlukla ayrılmış şekilde yazacağınız parçaları temsil eder. + + Bu komut, yukarıda `WORKDIR /code` ile ayarladığınız `/code` dizininden çalıştırılır. + +/// tip | İpucu + +Kod içindeki her numara balonuna tıklayarak her satırın ne yaptığını gözden geçirin. 👆 + +/// + +/// warning | Uyarı + +Aşağıda açıklandığı gibi `CMD` talimatının **her zaman** **exec form**'unu kullandığınızdan emin olun. + +/// + +#### `CMD` Kullanımı - Exec Form { #use-cmd-exec-form } + +`CMD` Docker talimatı iki formda yazılabilir: + +✅ **Exec** form: + +```Dockerfile +# ✅ Do this +CMD ["fastapi", "run", "app/main.py", "--port", "80"] +``` + +⛔️ **Shell** form: + +```Dockerfile +# ⛔️ Don't do this +CMD fastapi run app/main.py --port 80 +``` + +FastAPI'nin düzgün şekilde kapanabilmesi ve [lifespan event](../advanced/events.md){.internal-link target=_blank}'lerinin tetiklenmesi için her zaman **exec** formunu kullanın. + +Detaylar için shell ve exec form için Docker dokümanlarına bakabilirsiniz. + +Bu durum `docker compose` kullanırken oldukça belirgin olabilir. Daha teknik detaylar için şu Docker Compose FAQ bölümüne bakın: Why do my services take 10 seconds to recreate or stop?. + +#### Dizin Yapısı { #directory-structure } + +Artık dizin yapınız şöyle olmalı: + +``` +. +├── app +│   ├── __init__.py +│ └── main.py +├── Dockerfile +└── requirements.txt +``` + +#### TLS Termination Proxy Arkasında { #behind-a-tls-termination-proxy } + +Container'ınızı Nginx veya Traefik gibi bir TLS Termination Proxy (load balancer) arkasında çalıştırıyorsanız `--proxy-headers` seçeneğini ekleyin. Bu, Uvicorn'a (FastAPI CLI üzerinden) uygulamanın HTTPS arkasında çalıştığını söyleyen proxy header'larına güvenmesini söyler. + +```Dockerfile +CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"] +``` + +#### Docker Cache { #docker-cache } + +Bu `Dockerfile` içinde önemli bir numara var: önce kodun geri kalanını değil, **sadece bağımlılık dosyasını** kopyalıyoruz. Nedenini anlatayım. + +```Dockerfile +COPY ./requirements.txt /code/requirements.txt +``` + +Docker ve benzeri araçlar bu container image'larını **artımlı (incremental)** olarak **build** eder; `Dockerfile`'ın en üstünden başlayıp her talimatın oluşturduğu dosyaları ekleyerek **katman katman (layer)** ilerler. + +Docker ve benzeri araçlar image build ederken ayrıca bir **internal cache** kullanır. Son build'den beri bir dosya değişmediyse, dosyayı tekrar kopyalayıp sıfırdan yeni bir layer oluşturmak yerine, daha önce oluşturulan **aynı layer**'ı yeniden kullanır. + +Sadece dosya kopyalamayı azaltmak her zaman büyük fark yaratmaz. Ancak o adımda cache kullanıldığı için, **bir sonraki adımda da cache kullanılabilir**. Örneğin bağımlılıkları yükleyen şu talimat için: + +```Dockerfile +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt +``` + +Paket gereksinimleri dosyası **sık sık değişmez**. Bu yüzden sadece bu dosyayı kopyalayınca, Docker bu adımda **cache** kullanabilir. + +Sonra Docker, bağımlılıkları indirip yükleyen **bir sonraki adımda** da cache kullanabilir. Asıl **çok zaman kazandığımız** yer de burasıdır. ✨ ...ve beklerken sıkılmayı engeller. 😪😆 + +Bağımlılıkları indirip yüklemek **dakikalar sürebilir**, fakat **cache** kullanmak en fazla **saniyeler** alır. + +Geliştirme sırasında kod değişikliklerinizin çalıştığını kontrol etmek için container image'ı tekrar tekrar build edeceğinizden, bu ciddi birikimli zaman kazancı sağlar. + +Sonra `Dockerfile`'ın sonlarına doğru tüm kodu kopyalarız. En sık değişen kısım bu olduğu için sona koyarız; çünkü neredeyse her zaman bu adımdan sonra gelen adımlar cache kullanamaz. + +```Dockerfile +COPY ./app /code/app +``` + +### Docker Image'ını Build Edin { #build-the-docker-image } + +Tüm dosyalar hazır olduğuna göre container image'ı build edelim. + +* Proje dizinine gidin (`Dockerfile`'ınızın olduğu ve `app` dizininizi içeren dizin). +* FastAPI image'ınızı build edin: + +
+ +```console +$ docker build -t myimage . + +---> 100% +``` + +
+ +/// tip | İpucu + +Sondaki `.` ifadesine dikkat edin; `./` ile aynı anlama gelir ve Docker'a container image build etmek için hangi dizini kullanacağını söyler. + +Bu örnekte, mevcut dizindir (`.`). + +/// + +### Docker Container'ını Başlatın { #start-the-docker-container } + +* Image'ınızdan bir container çalıştırın: + +
+ +```console +$ docker run -d --name mycontainer -p 80:80 myimage +``` + +
+ +## Kontrol Edin { #check-it } + +Docker container'ınızın URL'inden kontrol edebilmelisiniz. Örneğin: http://192.168.99.100/items/5?q=somequery veya http://127.0.0.1/items/5?q=somequery (ya da Docker host'unuzu kullanarak eşdeğeri). + +Şuna benzer bir şey görürsünüz: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +## Etkileşimli API Dokümanları { #interactive-api-docs } + +Şimdi http://192.168.99.100/docs veya http://127.0.0.1/docs adresine gidebilirsiniz (ya da Docker host'unuzla eşdeğeri). + +Otomatik etkileşimli API dokümantasyonunu görürsünüz ( Swagger UI tarafından sağlanır): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +## Alternatif API Dokümanları { #alternative-api-docs } + +Ayrıca http://192.168.99.100/redoc veya http://127.0.0.1/redoc adresine de gidebilirsiniz (ya da Docker host'unuzla eşdeğeri). + +Alternatif otomatik dokümantasyonu görürsünüz (ReDoc tarafından sağlanır): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## Tek Dosyalık FastAPI ile Docker Image Oluşturma { #build-a-docker-image-with-a-single-file-fastapi } + +FastAPI uygulamanız tek bir dosyaysa; örneğin `./app` dizini olmadan sadece `main.py` varsa, dosya yapınız şöyle olabilir: + +``` +. +├── Dockerfile +├── main.py +└── requirements.txt +``` + +Bu durumda `Dockerfile` içinde dosyayı kopyaladığınız path'leri buna göre değiştirmeniz yeterlidir: + +```{ .dockerfile .annotate hl_lines="10 13" } +FROM python:3.9 + +WORKDIR /code + +COPY ./requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +# (1)! +COPY ./main.py /code/ + +# (2)! +CMD ["fastapi", "run", "main.py", "--port", "80"] +``` + +1. `main.py` dosyasını doğrudan `/code` dizinine kopyalayın (herhangi bir `./app` dizini olmadan). + +2. Tek dosya olan `main.py` içindeki uygulamanızı sunmak için `fastapi run` kullanın. + +Dosyayı `fastapi run`'a verdiğinizde, bunun bir package'ın parçası değil tek bir dosya olduğunu otomatik olarak algılar; nasıl import edip FastAPI uygulamanızı nasıl serve edeceğini bilir. 😎 + +## Deployment Kavramları { #deployment-concepts } + +Aynı [Deployment Kavramları](concepts.md){.internal-link target=_blank}nı bu kez container'lar açısından tekrar konuşalım. + +Container'lar, bir uygulamayı **build etme ve deploy etme** sürecini basitleştiren bir araçtır. Ancak bu **deployment kavramları**nı ele almak için belirli bir yaklaşımı zorunlu kılmazlar; birkaç farklı strateji mümkündür. + +**İyi haber** şu: Hangi stratejiyi seçerseniz seçin, deployment kavramlarının tamamını kapsayacak bir yol vardır. 🎉 + +Bu **deployment kavramları**nı container'lar açısından gözden geçirelim: + +* HTTPS +* Startup'ta çalıştırma +* Restart'lar +* Replication (çalışan process sayısı) +* Memory +* Başlatmadan önceki adımlar + +## HTTPS { #https } + +Bir FastAPI uygulamasının sadece **container image**'ına (ve sonra çalışan **container**'a) odaklanırsak, HTTPS genellikle **haricen** başka bir araçla ele alınır. + +Örneğin Traefik kullanan başka bir container olabilir; **HTTPS** ve **sertifika**ların **otomatik** alınmasını o yönetebilir. + +/// tip | İpucu + +Traefik; Docker, Kubernetes ve diğerleriyle entegre çalışır. Bu sayede container'larınız için HTTPS'i kurup yapılandırmak oldukça kolaydır. + +/// + +Alternatif olarak HTTPS, bir cloud provider'ın sunduğu servislerden biri tarafından da yönetilebilir (uygulama yine container içinde çalışırken). + +## Startup'ta Çalıştırma ve Restart'lar { #running-on-startup-and-restarts } + +Container'ınızı **başlatıp çalıştırmaktan** sorumlu genellikle başka bir araç olur. + +Bu; doğrudan **Docker**, **Docker Compose**, **Kubernetes**, bir **cloud service** vb. olabilir. + +Çoğu (veya tüm) durumda, container'ı startup'ta çalıştırmayı ve hata durumlarında restart'ları etkinleştirmeyi sağlayan basit bir seçenek vardır. Örneğin Docker'da bu, `--restart` komut satırı seçeneğidir. + +Container kullanmadan, uygulamaları startup'ta çalıştırmak ve restart mekanizması eklemek zahmetli ve zor olabilir. Ancak **container'larla çalışırken** çoğu zaman bu işlevler varsayılan olarak hazır gelir. ✨ + +## Replication - Process Sayısı { #replication-number-of-processes } + +Kubernetes, Docker Swarm Mode, Nomad veya benzeri, birden fazla makinede dağıtık container'ları yöneten karmaşık bir sistemle kurulmuş bir cluster'ınız varsa, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **cluster seviyesinde** ele almak istersiniz. + +Kubernetes gibi dağıtık container yönetim sistemleri, gelen request'ler için **load balancing** desteği sunarken aynı zamanda **container replication**'ını yönetmek için entegre mekanizmalara sahiptir. Hepsi **cluster seviyesinde**. + +Bu tür durumlarda, yukarıda [anlatıldığı gibi](#dockerfile) bağımlılıkları yükleyip **sıfırdan bir Docker image** build etmek ve birden fazla Uvicorn worker kullanmak yerine **tek bir Uvicorn process** çalıştırmak istersiniz. + +### Load Balancer { #load-balancer } + +Container'lar kullanırken, genellikle ana port'ta dinleyen bir bileşen olur. Bu, **HTTPS**'i ele almak için bir **TLS Termination Proxy** olan başka bir container da olabilir ya da benzeri bir araç olabilir. + +Bu bileşen request'lerin **yükünü** alıp worker'lar arasında (umarım) **dengeli** şekilde dağıttığı için yaygın olarak **Load Balancer** diye de adlandırılır. + +/// tip | İpucu + +HTTPS için kullanılan aynı **TLS Termination Proxy** bileşeni muhtemelen bir **Load Balancer** olarak da çalışır. + +/// + +Container'larla çalışırken, onları başlatıp yönettiğiniz sistem; bu **load balancer**'dan (aynı zamanda **TLS Termination Proxy** de olabilir) uygulamanızın bulunduğu container(lar)a **network communication**'ı (ör. HTTP request'leri) iletmek için zaten dahili araçlar sunar. + +### Tek Load Balancer - Çoklu Worker Container { #one-load-balancer-multiple-worker-containers } + +**Kubernetes** veya benzeri dağıtık container yönetim sistemleriyle çalışırken, dahili ağ mekanizmaları sayesinde ana **port**'u dinleyen tek bir **load balancer**, uygulamanızı çalıştıran muhtemelen **birden fazla container**'a request'leri iletebilir. + +Uygulamanızı çalıştıran bu container'ların her birinde normalde **tek bir process** olur (ör. FastAPI uygulamanızı çalıştıran bir Uvicorn process). Hepsi aynı şeyi çalıştıran **özdeş container**'lardır; ancak her birinin kendi process'i, memory'si vb. vardır. Böylece CPU'nun **farklı core**'larında, hatta **farklı makinelerde** paralelleştirmeden yararlanırsınız. + +Load balancer'lı dağıtık sistem, request'leri uygulamanızın bulunduğu container'ların her birine sırayla **dağıtır**. Böylece her request, uygulamanızın birden fazla **replicated container**'ından biri tarafından işlenebilir. + +Ve bu **load balancer** normalde cluster'ınızdaki *diğer* uygulamalara giden request'leri de (ör. farklı bir domain ya da farklı bir URL path prefix altında) yönetebilir ve iletişimi o *diğer* uygulamanın doğru container'larına iletir. + +### Container Başına Tek Process { #one-process-per-container } + +Bu senaryoda, replication'ı zaten cluster seviyesinde yaptığınız için, muhtemelen **container başına tek bir (Uvicorn) process** istersiniz. + +Dolayısıyla bu durumda container içinde `--workers` gibi bir komut satırı seçeneğiyle çoklu worker istemezsiniz. Container başına sadece **tek bir Uvicorn process** istersiniz (ama muhtemelen birden fazla container). + +Container içine ekstra bir process manager koymak (çoklu worker gibi) çoğu zaman zaten cluster sisteminizle çözdüğünüz şeye ek **gereksiz karmaşıklık** katar. + +### Birden Fazla Process'li Container'lar ve Özel Durumlar { #containers-with-multiple-processes-and-special-cases } + +Elbette bazı **özel durumlarda** bir container içinde birden fazla **Uvicorn worker process** çalıştırmak isteyebilirsiniz. + +Bu durumlarda çalıştırmak istediğiniz worker sayısını `--workers` komut satırı seçeneğiyle ayarlayabilirsiniz: + +```{ .dockerfile .annotate } +FROM python:3.9 + +WORKDIR /code + +COPY ./requirements.txt /code/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt + +COPY ./app /code/app + +# (1)! +CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"] +``` + +1. Burada worker sayısını 4 yapmak için `--workers` komut satırı seçeneğini kullanıyoruz. + +Bunun mantıklı olabileceği birkaç örnek: + +#### Basit Bir Uygulama { #a-simple-app } + +Uygulamanız tek bir server üzerinde (cluster değil) çalışacak kadar **basitse**, container içinde bir process manager isteyebilirsiniz. + +#### Docker Compose { #docker-compose } + +**Docker Compose** ile **tek bir server**'a (cluster değil) deploy ediyor olabilirsiniz. Bu durumda, paylaşılan ağı ve **load balancing**'i koruyarak container replication'ını (Docker Compose ile) yönetmenin kolay bir yolu olmayabilir. + +Bu durumda, tek bir container içinde **bir process manager** ile **birden fazla worker process** başlatmak isteyebilirsiniz. + +--- + +Ana fikir şu: Bunların **hiçbiri** körü körüne uymanız gereken **değişmez kurallar** değildir. Bu fikirleri, kendi kullanım senaryonuzu **değerlendirmek** ve sisteminiz için en iyi yaklaşımı seçmek için kullanabilirsiniz. Şu kavramları nasıl yöneteceğinize bakarak karar verin: + +* Güvenlik - HTTPS +* Startup'ta çalıştırma +* Restart'lar +* Replication (çalışan process sayısı) +* Memory +* Başlatmadan önceki adımlar + +## Memory { #memory } + +**Container başına tek process** çalıştırırsanız, her container'ın tüketeceği memory miktarı aşağı yukarı tanımlı, stabil ve sınırlı olur (replication varsa birden fazla container için). + +Sonra aynı memory limit ve gereksinimlerini container yönetim sisteminizin (ör. **Kubernetes**) konfigürasyonlarında belirleyebilirsiniz. Böylece sistem; ihtiyaç duyulan memory miktarını ve cluster'daki makinelerde mevcut memory'yi dikkate alarak **uygun makinelerde container'ları replicate edebilir**. + +Uygulamanız **basitse**, muhtemelen bu **bir sorun olmaz** ve katı memory limitleri belirlemeniz gerekmeyebilir. Ancak **çok memory kullanıyorsanız** (ör. **machine learning** modelleriyle), ne kadar memory tükettiğinizi kontrol edip **her makinede** çalışacak **container sayısını** ayarlamalısınız (ve gerekirse cluster'a daha fazla makine eklemelisiniz). + +**Container başına birden fazla process** çalıştırırsanız, başlatılan process sayısının mevcut olandan **fazla memory tüketmediğinden** emin olmanız gerekir. + +## Başlatmadan Önceki Adımlar ve Container'lar { #previous-steps-before-starting-and-containers } + +Container kullanıyorsanız (örn. Docker, Kubernetes), temelde iki yaklaşım vardır. + +### Birden Fazla Container { #multiple-containers } + +**Birden fazla container**'ınız varsa ve muhtemelen her biri **tek process** çalıştırıyorsa (ör. bir **Kubernetes** cluster'ında), replication yapılan worker container'lar çalışmadan **önce**, **başlatmadan önceki adımlar**ın işini yapan **ayrı bir container** kullanmak isteyebilirsiniz (tek container, tek process). + +/// info | Bilgi + +Kubernetes kullanıyorsanız, bu muhtemelen bir Init Container olur. + +/// + +Kullanım senaryonuzda bu adımları **paralel olarak birden fazla kez** çalıştırmak sorun değilse (örneğin veritabanı migration çalıştırmıyor, sadece veritabanı hazır mı diye kontrol ediyorsanız), o zaman her container'da ana process başlamadan hemen önce de çalıştırabilirsiniz. + +### Tek Container { #single-container } + +Basit bir kurulumda; **tek bir container** olup onun içinde birden fazla **worker process** (ya da sadece bir process) başlatıyorsanız, bu adımları aynı container içinde, uygulama process'ini başlatmadan hemen önce çalıştırabilirsiniz. + +### Base Docker Image { #base-docker-image } + +Eskiden resmi bir FastAPI Docker image'ı vardı: tiangolo/uvicorn-gunicorn-fastapi. Ancak artık kullanımdan kaldırıldı (deprecated). ⛔️ + +Muhtemelen bu base Docker image'ını (veya benzeri başka bir image'ı) kullanmamalısınız. + +**Kubernetes** (veya diğerleri) kullanıyor ve cluster seviyesinde birden fazla **container** ile **replication** ayarlıyorsanız, bu durumda yukarıda anlatıldığı gibi **sıfırdan bir image build etmek** daha iyi olur: [FastAPI için Docker Image Oluşturalım](#build-a-docker-image-for-fastapi). + +Ve birden fazla worker gerekiyorsa, sadece `--workers` komut satırı seçeneğini kullanabilirsiniz. + +/// note | Teknik Detaylar + +Bu Docker image, Uvicorn dead worker'ları yönetmeyi ve yeniden başlatmayı desteklemediği dönemde oluşturulmuştu. Bu yüzden Uvicorn ile birlikte Gunicorn kullanmak gerekiyordu; sırf Gunicorn, Uvicorn worker process'lerini yönetip yeniden başlatsın diye oldukça fazla karmaşıklık ekleniyordu. + +Ancak artık Uvicorn (ve `fastapi` komutu) `--workers` kullanımını desteklediğine göre, kendi image'ınızı build etmek yerine bir base Docker image kullanmanın bir nedeni kalmadı (kod miktarı da hemen hemen aynı 😅). + +/// + +## Container Image'ı Deploy Etme { #deploy-the-container-image } + +Bir Container (Docker) Image'ınız olduktan sonra bunu deploy etmenin birkaç yolu vardır. + +Örneğin: + +* Tek bir server'da **Docker Compose** ile +* Bir **Kubernetes** cluster'ı ile +* Docker Swarm Mode cluster'ı ile +* Nomad gibi başka bir araçla +* Container image'ınızı alıp deploy eden bir cloud servisiyle + +## `uv` ile Docker Image { #docker-image-with-uv } + +Projenizi yüklemek ve yönetmek için uv kullanıyorsanız, onların uv Docker rehberini takip edebilirsiniz. + +## Özet { #recap } + +Container sistemleri (örn. **Docker** ve **Kubernetes** ile) kullanınca tüm **deployment kavramları**nı ele almak oldukça kolaylaşır: + +* HTTPS +* Startup'ta çalıştırma +* Restart'lar +* Replication (çalışan process sayısı) +* Memory +* Başlatmadan önceki adımlar + +Çoğu durumda bir base image kullanmak istemezsiniz; bunun yerine resmi Python Docker image'ını temel alarak **sıfırdan bir container image** build edersiniz. + +`Dockerfile` içindeki talimatların **sırasına** ve **Docker cache**'ine dikkat ederek **build sürelerini minimize edebilir**, üretkenliğinizi artırabilirsiniz (ve beklerken sıkılmayı önlersiniz). 😎 diff --git a/docs/tr/docs/deployment/fastapicloud.md b/docs/tr/docs/deployment/fastapicloud.md new file mode 100644 index 0000000000..bb861273be --- /dev/null +++ b/docs/tr/docs/deployment/fastapicloud.md @@ -0,0 +1,65 @@ +# FastAPI Cloud { #fastapi-cloud } + +FastAPI uygulamanızı FastAPI Cloud'a **tek bir komutla** deploy edebilirsiniz. Henüz yapmadıysanız gidip bekleme listesine katılın. 🚀 + +## Giriş Yapma { #login } + +Önceden bir **FastAPI Cloud** hesabınız olduğundan emin olun (sizi bekleme listesinden davet ettik 😉). + +Ardından giriş yapın: + +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
+ +## Deploy { #deploy } + +Şimdi uygulamanızı **tek bir komutla** deploy edin: + +
+ +```console +$ fastapi deploy + +Deploying to FastAPI Cloud... + +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
+ +Hepsi bu! Artık uygulamanıza o URL üzerinden erişebilirsiniz. ✨ + +## FastAPI Cloud Hakkında { #about-fastapi-cloud } + +**FastAPI Cloud**, **FastAPI**'nin arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir. + +Bir API'yi minimum eforla **geliştirme**, **deploy etme** ve **erişilebilir kılma** sürecini sadeleştirir. + +FastAPI ile uygulama geliştirirken elde ettiğiniz aynı **developer experience**'ı, onları buluta **deploy etmeye** de taşır. 🎉 + +Ayrıca bir uygulamayı deploy ederken ihtiyaç duyacağınız pek çok şeyi de sizin için halleder; örneğin: + +* HTTPS +* Replication (çoğaltma), request'lere göre autoscaling ile +* vb. + +FastAPI Cloud, *FastAPI and friends* açık kaynak projelerinin birincil sponsoru ve finansman sağlayıcısıdır. ✨ + +## Diğer cloud sağlayıcılarına deploy etme { #deploy-to-other-cloud-providers } + +FastAPI açık kaynaklıdır ve standartlara dayanır. FastAPI uygulamalarını seçtiğiniz herhangi bir cloud sağlayıcısına deploy edebilirsiniz. + +FastAPI uygulamalarını deploy etmek için cloud sağlayıcınızın kendi kılavuzlarını takip edin. 🤓 + +## Kendi server'ınıza deploy etme { #deploy-your-own-server } + +Bu **Deployment** kılavuzunun ilerleyen bölümlerinde tüm detayları da ele alacağız; böylece neler olduğunu, nelerin gerçekleşmesi gerektiğini ve FastAPI uygulamalarını kendi başınıza (kendi server'larınızla da) nasıl deploy edebileceğinizi anlayacaksınız. 🤓 diff --git a/docs/tr/docs/deployment/https.md b/docs/tr/docs/deployment/https.md new file mode 100644 index 0000000000..bb70883aa7 --- /dev/null +++ b/docs/tr/docs/deployment/https.md @@ -0,0 +1,231 @@ +# HTTPS Hakkında { #about-https } + +HTTPS’in sadece "açık" ya da "kapalı" olan bir şey olduğunu düşünmek kolaydır. + +Ancak bundan çok daha karmaşıktır. + +/// tip | İpucu + +Aceleniz varsa veya çok da önemsemiyorsanız, her şeyi farklı tekniklerle adım adım kurmak için sonraki bölümlere geçin. + +/// + +Bir kullanıcı gözüyle **HTTPS’in temellerini öğrenmek** için https://howhttps.works/ adresine bakın. + +Şimdi de **geliştirici perspektifinden**, HTTPS hakkında düşünürken akılda tutulması gereken birkaç nokta: + +* HTTPS için **server**’ın, **üçüncü bir taraf** tarafından verilen **"sertifikalara"** sahip olması gerekir. + * Bu sertifikalar aslında üçüncü tarafça "üretilmez", üçüncü taraftan **temin edilir**. +* Sertifikaların bir **geçerlilik süresi** vardır. + * Süresi **dolar**. + * Sonrasında **yenilenmeleri**, üçüncü taraftan **yeniden temin edilmeleri** gerekir. +* Bağlantının şifrelenmesi **TCP seviyesinde** gerçekleşir. + * Bu, **HTTP’nin bir katman altıdır**. + * Dolayısıyla **sertifika ve şifreleme** işlemleri **HTTP’den önce** yapılır. +* **TCP "domain"leri bilmez**. Yalnızca IP adreslerini bilir. + * İstenen **spesifik domain** bilgisi **HTTP verisinin** içindedir. +* **HTTPS sertifikaları** belirli bir **domain**’i "sertifikalandırır"; ancak protokol ve şifreleme TCP seviyesinde, hangi domain ile çalışıldığı **henüz bilinmeden** gerçekleşir. +* **Varsayılan olarak** bu, IP adresi başına yalnızca **bir HTTPS sertifikası** olabileceği anlamına gelir. + * Server’ınız ne kadar büyük olursa olsun ya da üzerindeki her uygulama ne kadar küçük olursa olsun. + * Ancak bunun bir **çözümü** vardır. +* **TLS** protokolüne (TCP seviyesinde, HTTP’den önce şifrelemeyi yapan) eklenen **SNI** adlı bir **extension** vardır. + * Bu SNI extension’ı, tek bir server’ın (tek bir **IP adresiyle**) **birden fazla HTTPS sertifikası** kullanmasına ve **birden fazla HTTPS domain/uygulama** sunmasına izin verir. + * Bunun çalışması için server üzerinde, **public IP adresini** dinleyen tek bir bileşenin (programın) server’daki **tüm HTTPS sertifikalarına** sahip olması gerekir. +* Güvenli bir bağlantı elde edildikten **sonra**, iletişim protokolü **hâlâ HTTP**’dir. + * İçerikler, **HTTP protokolü** ile gönderiliyor olsa bile **şifrelenmiştir**. + +Yaygın yaklaşım, server’da (makine, host vb.) çalışan **tek bir program/HTTP server** bulundurup **HTTPS ile ilgili tüm kısımları** yönetmektir: **şifreli HTTPS request**’leri almak, aynı server’da çalışan gerçek HTTP uygulamasına (bu örnekte **FastAPI** uygulaması) **şifresi çözülmüş HTTP request**’leri iletmek, uygulamadan gelen **HTTP response**’u almak, uygun **HTTPS sertifikası** ile **şifrelemek** ve **HTTPS** ile client’a geri göndermek. Bu server’a çoğu zaman **TLS Termination Proxy** denir. + +TLS Termination Proxy olarak kullanabileceğiniz seçeneklerden bazıları: + +* Traefik (sertifika yenilemelerini de yönetebilir) +* Caddy (sertifika yenilemelerini de yönetebilir) +* Nginx +* HAProxy + +## Let's Encrypt { #lets-encrypt } + +Let's Encrypt’ten önce bu **HTTPS sertifikaları**, güvenilen üçüncü taraflar tarafından satılırdı. + +Bu sertifikalardan birini temin etme süreci zahmetliydi, epey evrak işi gerektirirdi ve sertifikalar oldukça pahalıydı. + +Sonra **Let's Encrypt** ortaya çıktı. + +Linux Foundation’ın bir projesidir. **HTTPS sertifikalarını ücretsiz** ve otomatik bir şekilde sağlar. Bu sertifikalar tüm standart kriptografik güvenliği kullanır ve kısa ömürlüdür (yaklaşık 3 ay). Bu yüzden, ömürleri kısa olduğu için **güvenlik aslında daha iyidir**. + +Domain’ler güvenli şekilde doğrulanır ve sertifikalar otomatik üretilir. Bu sayede sertifikaların yenilenmesini otomatikleştirmek de mümkün olur. + +Amaç, bu sertifikaların temin edilmesi ve yenilenmesini otomatikleştirerek **ücretsiz, kalıcı olarak güvenli HTTPS** sağlamaktır. + +## Geliştiriciler İçin HTTPS { #https-for-developers } + +Burada, bir HTTPS API’nin adım adım nasıl görünebileceğine dair, özellikle geliştiriciler için önemli fikirlere odaklanan bir örnek var. + +### Domain Adı { #domain-name } + +Muhtemelen her şey, bir **domain adı** **temin etmenizle** başlar. Sonra bunu bir DNS server’ında (muhtemelen aynı cloud provider’ınızda) yapılandırırsınız. + +Muhtemelen bir cloud server (virtual machine) ya da benzeri bir şey alırsınız ve bunun fixed bir **public IP adresi** olur. + +DNS server(lar)ında, bir kaydı ("`A record`") **domain**’inizi server’ınızın **public IP adresine** yönlendirecek şekilde yapılandırırsınız. + +Bunu büyük olasılıkla ilk kurulumda, sadece bir kez yaparsınız. + +/// tip | İpucu + +Bu Domain Adı kısmı HTTPS’ten çok daha önce gelir. Ancak her şey domain ve IP adresine bağlı olduğu için burada bahsetmeye değer. + +/// + +### DNS { #dns } + +Şimdi gerçek HTTPS parçalarına odaklanalım. + +Önce tarayıcı, bu örnekte `someapp.example.com` olan domain için **IP**’nin ne olduğunu **DNS server**’larına sorar. + +DNS server’ları tarayıcıya belirli bir **IP adresini** kullanmasını söyler. Bu, DNS server’larında yapılandırdığınız ve server’ınızın kullandığı public IP adresidir. + + + +### TLS Handshake Başlangıcı { #tls-handshake-start } + +Tarayıcı daha sonra bu IP adresiyle **443 portu** (HTTPS portu) üzerinden iletişim kurar. + +İletişimin ilk kısmı, client ile server arasında bağlantıyı kurmak ve hangi kriptografik anahtarların kullanılacağına karar vermek vb. içindir. + + + +Client ile server arasındaki, TLS bağlantısını kurmaya yönelik bu etkileşime **TLS handshake** denir. + +### SNI Extension’ı ile TLS { #tls-with-sni-extension } + +Server’da, belirli bir **IP adresindeki** belirli bir **portu** dinleyen **yalnızca bir process** olabilir. Aynı IP adresinde başka portları dinleyen başka process’ler olabilir, ancak IP+port kombinasyonu başına yalnızca bir tane olur. + +TLS (HTTPS) varsayılan olarak `443` portunu kullanır. Yani ihtiyaç duyacağımız port budur. + +Bu portu yalnızca bir process dinleyebileceği için, bunu yapacak process **TLS Termination Proxy** olur. + +TLS Termination Proxy, bir ya da daha fazla **TLS sertifikasına** (HTTPS sertifikası) erişebilir. + +Yukarıda bahsettiğimiz **SNI extension**’ını kullanarak TLS Termination Proxy, bu bağlantı için elindeki TLS (HTTPS) sertifikalarından hangisini kullanacağını kontrol eder; client’ın beklediği domain ile eşleşen sertifikayı seçer. + +Bu örnekte `someapp.example.com` sertifikasını kullanır. + + + +Client, bu TLS sertifikasını üreten kuruluşa zaten **güvenir** (bu örnekte Let's Encrypt; birazdan ona da geleceğiz). Bu sayede sertifikanın geçerli olduğunu **doğrulayabilir**. + +Ardından client ve TLS Termination Proxy, sertifikayı kullanarak **TCP iletişiminin geri kalanını nasıl şifreleyeceklerine** karar verir. Böylece **TLS Handshake** kısmı tamamlanır. + +Bundan sonra client ve server arasında **şifreli bir TCP bağlantısı** vardır; TLS’in sağladığı şey budur. Sonra bu bağlantıyı kullanarak gerçek **HTTP iletişimini** başlatabilirler. + +Ve **HTTPS** de tam olarak budur: şifrelenmemiş bir TCP bağlantısı yerine, **güvenli bir TLS bağlantısının içinde** düz **HTTP**’dir. + +/// tip | İpucu + +Şifrelemenin HTTP seviyesinde değil, **TCP seviyesinde** gerçekleştiğine dikkat edin. + +/// + +### HTTPS Request { #https-request } + +Artık client ile server (özellikle tarayıcı ile TLS Termination Proxy) arasında **şifreli bir TCP bağlantısı** olduğuna göre, **HTTP iletişimi** başlayabilir. + +Dolayısıyla client bir **HTTPS request** gönderir. Bu, şifreli bir TLS bağlantısı üzerinden giden bir HTTP request’tir. + + + +### Request’in Şifresini Çözme { #decrypt-the-request } + +TLS Termination Proxy, üzerinde anlaşılan şifrelemeyi kullanarak **request’in şifresini çözer** ve **düz (şifresi çözülmüş) HTTP request**’i uygulamayı çalıştıran process’e iletir (ör. FastAPI uygulamasını çalıştıran Uvicorn process’i). + + + +### HTTP Response { #http-response } + +Uygulama request’i işler ve TLS Termination Proxy’ye **düz (şifrelenmemiş) bir HTTP response** gönderir. + + + +### HTTPS Response { #https-response } + +TLS Termination Proxy daha sonra response’u, daha önce üzerinde anlaşılan kriptografi ile (başlangıcı `someapp.example.com` sertifikasına dayanan) **şifreler** ve tarayıcıya geri gönderir. + +Sonrasında tarayıcı response’un geçerli olduğunu ve doğru kriptografik anahtarla şifrelendiğini doğrular vb. Ardından **response’un şifresini çözer** ve işler. + + + +Client (tarayıcı), response’un doğru server’dan geldiğini bilir; çünkü daha önce **HTTPS sertifikası** ile üzerinde anlaştıkları kriptografiyi kullanmaktadır. + +### Birden Fazla Uygulama { #multiple-applications } + +Aynı server’da (veya server’larda) örneğin başka API programları ya da bir veritabanı gibi **birden fazla uygulama** olabilir. + +Belirli IP ve port kombinasyonunu yalnızca bir process yönetebilir (örneğimizde TLS Termination Proxy). Ancak diğer uygulamalar/process’ler, aynı **public IP + port kombinasyonunu** kullanmaya çalışmadıkları sürece server(lar)da çalışabilir. + + + +Bu şekilde TLS Termination Proxy, birden fazla uygulama için **birden fazla domain**’in HTTPS ve sertifika işlerini yönetebilir ve her durumda request’leri doğru uygulamaya iletebilir. + +### Sertifika Yenileme { #certificate-renewal } + +Gelecekte bir noktada, her sertifikanın süresi **dolar** (temin edildikten yaklaşık 3 ay sonra). + +Ardından başka bir program (bazı durumlarda ayrı bir programdır, bazı durumlarda aynı TLS Termination Proxy olabilir) Let's Encrypt ile konuşup sertifika(ları) yeniler. + + + +**TLS sertifikaları** bir IP adresiyle değil, **domain adıyla ilişkilidir**. + +Bu yüzden sertifikaları yenilemek için, yenileme programı otoriteye (Let's Encrypt) gerçekten o domain’i **"sahiplendiğini" ve kontrol ettiğini** **kanıtlamalıdır**. + +Bunu yapmak ve farklı uygulama ihtiyaçlarını karşılamak için birden fazla yöntem vardır. Yaygın yöntemlerden bazıları: + +* Bazı **DNS kayıtlarını değiştirmek**. + * Bunun için yenileme programının DNS provider API’lerini desteklemesi gerekir. Dolayısıyla kullandığınız DNS provider’a bağlı olarak bu seçenek mümkün de olabilir, olmayabilir de. +* Domain ile ilişkili public IP adresinde **server olarak çalışmak** (en azından sertifika temin sürecinde). + * Yukarıda söylediğimiz gibi, belirli bir IP ve portu yalnızca bir process dinleyebilir. + * Bu, aynı TLS Termination Proxy’nin sertifika yenileme sürecini de yönetmesinin neden çok faydalı olduğunun sebeplerinden biridir. + * Aksi halde TLS Termination Proxy’yi kısa süreliğine durdurmanız, sertifikaları temin etmek için yenileme programını başlatmanız, sonra bunları TLS Termination Proxy ile yapılandırmanız ve ardından TLS Termination Proxy’yi tekrar başlatmanız gerekebilir. Bu ideal değildir; çünkü TLS Termination Proxy kapalıyken uygulama(lar)ınıza erişilemez. + +Uygulamayı servis etmeye devam ederken tüm bu yenileme sürecini yönetebilmek, TLS sertifikalarını doğrudan uygulama server’ıyla (örn. Uvicorn) kullanmak yerine, TLS Termination Proxy ile HTTPS’i yönetecek **ayrı bir sistem** istemenizin başlıca nedenlerinden biridir. + +## Proxy Forwarded Headers { #proxy-forwarded-headers } + +HTTPS’i bir proxy ile yönetirken, **application server**’ınız (örneğin FastAPI CLI üzerinden Uvicorn) HTTPS süreci hakkında hiçbir şey bilmez; **TLS Termination Proxy** ile düz HTTP üzerinden iletişim kurar. + +Bu **proxy** normalde request’i **application server**’a iletmeden önce, request’in proxy tarafından **forward** edildiğini application server’a bildirmek için bazı HTTP header’larını anlık olarak ekler. + +/// note | Teknik Detaylar + +Proxy header’ları şunlardır: + +* X-Forwarded-For +* X-Forwarded-Proto +* X-Forwarded-Host + +/// + +Buna rağmen **application server**, güvenilen bir **proxy** arkasında olduğunu bilmediği için varsayılan olarak bu header’lara güvenmez. + +Ancak **application server**’ı, **proxy**’nin gönderdiği *forwarded* header’larına güvenecek şekilde yapılandırabilirsiniz. FastAPI CLI kullanıyorsanız, hangi IP’lerden gelen *forwarded* header’lara güvenmesi gerektiğini söylemek için *CLI Option* `--forwarded-allow-ips` seçeneğini kullanabilirsiniz. + +Örneğin **application server** yalnızca güvenilen **proxy**’den iletişim alıyorsa, yalnızca **proxy**’nin kullandığı IP’den request alacağı için `--forwarded-allow-ips="*"` ayarlayıp gelen tüm IP’lere güvenmesini sağlayabilirsiniz. + +Bu sayede uygulama kendi public URL’inin ne olduğunu, HTTPS kullanıp kullanmadığını, domain’i vb. bilebilir. + +Bu, örneğin redirect’leri doğru şekilde yönetmek için faydalıdır. + +/// tip | İpucu + +Bununla ilgili daha fazlasını [Behind a Proxy - Enable Proxy Forwarded Headers](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank} dokümantasyonunda öğrenebilirsiniz. + +/// + +## Özet { #recap } + +**HTTPS** kullanmak çok önemlidir ve çoğu durumda oldukça **kritiktir**. Geliştirici olarak HTTPS etrafında harcadığınız çabanın büyük kısmı, aslında **bu kavramları** ve nasıl çalıştıklarını **anlamaktır**. + +Ancak **geliştiriciler için HTTPS**’in temel bilgilerini öğrendikten sonra, her şeyi basitçe yönetmek için farklı araçları kolayca birleştirip yapılandırabilirsiniz. + +Sonraki bölümlerin bazılarında, **FastAPI** uygulamaları için **HTTPS**’i nasıl kuracağınıza dair birkaç somut örnek göstereceğim. 🔒 diff --git a/docs/tr/docs/deployment/manually.md b/docs/tr/docs/deployment/manually.md new file mode 100644 index 0000000000..561ba86772 --- /dev/null +++ b/docs/tr/docs/deployment/manually.md @@ -0,0 +1,157 @@ +# Bir Sunucuyu Manuel Olarak Çalıştırın { #run-a-server-manually } + +## `fastapi run` Komutunu Kullanın { #use-the-fastapi-run-command } + +Kısacası, FastAPI uygulamanızı sunmak için `fastapi run` kullanın: + +
+ +```console +$ fastapi run 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 Started server process [2306215] + INFO Waiting for application startup. + INFO Application startup complete. + INFO Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C + to quit) +``` + +
+ +Bu, çoğu durumda işinizi görür. 😎 + +Örneğin bu komutu, **FastAPI** app'inizi bir container içinde, bir sunucuda vb. başlatmak için kullanabilirsiniz. + +## ASGI Sunucuları { #asgi-servers } + +Şimdi biraz daha detaya inelim. + +FastAPI, Python web framework'leri ve sunucularını inşa etmek için kullanılan ASGI adlı bir standardı kullanır. FastAPI bir ASGI web framework'üdür. + +Uzak bir sunucu makinesinde **FastAPI** uygulamasını (veya herhangi bir ASGI uygulamasını) çalıştırmak için gereken ana şey, **Uvicorn** gibi bir ASGI server programıdır. `fastapi` komutuyla varsayılan olarak gelen de budur. + +Buna alternatif birkaç seçenek daha vardır, örneğin: + +* Uvicorn: yüksek performanslı bir ASGI server. +* Hypercorn: diğer özelliklerin yanında HTTP/2 ve Trio ile uyumlu bir ASGI server. +* Daphne: Django Channels için geliştirilmiş ASGI server. +* Granian: Python uygulamaları için bir Rust HTTP server. +* NGINX Unit: NGINX Unit, hafif ve çok yönlü bir web uygulaması runtime'ıdır. + +## Sunucu Makinesi ve Sunucu Programı { #server-machine-and-server-program } + +İsimlendirme konusunda akılda tutulması gereken küçük bir detay var. 💡 + +"**server**" kelimesi yaygın olarak hem uzak/bulut bilgisayarı (fiziksel veya sanal makine) hem de o makinede çalışan programı (ör. Uvicorn) ifade etmek için kullanılır. + +Dolayısıyla genel olarak "server" dendiğinde, bu iki şeyden birini kast ediyor olabilir. + +Uzak makineden bahsederken genelde **server** denir; ayrıca **machine**, **VM** (virtual machine), **node** ifadeleri de kullanılır. Bunların hepsi, genellikle Linux çalıştıran ve üzerinde programlarınızı çalıştırdığınız bir tür uzak makineyi ifade eder. + +## Sunucu Programını Yükleyin { #install-the-server-program } + +FastAPI'yi kurduğunuzda, production sunucusu olarak Uvicorn da beraberinde gelir ve bunu `fastapi run` komutuyla başlatabilirsiniz. + +Ancak bir ASGI server'ı manuel olarak da kurabilirsiniz. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, etkinleştirdiğinizden emin olun; ardından server uygulamasını kurabilirsiniz. + +Örneğin Uvicorn'u kurmak için: + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +Benzer bir süreç, diğer ASGI server programlarının tamamı için de geçerlidir. + +/// tip | İpucu + +`standard` eklediğinizde Uvicorn, önerilen bazı ek bağımlılıkları kurar ve kullanır. + +Bunlara, `asyncio` için yüksek performanslı bir drop-in replacement olan ve concurrency performansını ciddi şekilde artıran `uvloop` da dahildir. + +FastAPI'yi `pip install "fastapi[standard]"` gibi bir şekilde kurduğunuzda `uvicorn[standard]` da zaten kurulmuş olur. + +/// + +## Sunucu Programını Çalıştırın { #run-the-server-program } + +Bir ASGI server'ı manuel olarak kurduysanız, FastAPI uygulamanızı import edebilmesi için genellikle özel bir formatta bir import string geçirmeniz gerekir: + +
+ +```console +$ uvicorn main:app --host 0.0.0.0 --port 80 + +INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit) +``` + +
+ +/// note | Not + +`uvicorn main:app` komutu şunları ifade eder: + +* `main`: `main.py` dosyası (Python "module"). +* `app`: `main.py` içinde `app = FastAPI()` satırıyla oluşturulan nesne. + +Şununla eşdeğerdir: + +```Python +from main import app +``` + +/// + +Her alternatif ASGI server programı için benzer bir komut bulunur; daha fazlası için ilgili dokümantasyonlarına bakabilirsiniz. + +/// warning | Uyarı + +Uvicorn ve diğer sunucular, geliştirme sırasında faydalı olan `--reload` seçeneğini destekler. + +`--reload` seçeneği çok daha fazla kaynak tüketir, daha kararsızdır vb. + +**Geliştirme** sırasında çok yardımcı olur, ancak **production** ortamında kullanmamalısınız. + +/// + +## Deployment Kavramları { #deployment-concepts } + +Bu örnekler server programını (ör. Uvicorn) çalıştırır; **tek bir process** başlatır, tüm IP'lerde (`0.0.0.0`) ve önceden belirlenmiş bir port'ta (ör. `80`) dinler. + +Temel fikir budur. Ancak muhtemelen şunlar gibi bazı ek konularla da ilgilenmek isteyeceksiniz: + +* Güvenlik - HTTPS +* Açılışta çalıştırma +* Yeniden başlatmalar +* Replikasyon (çalışan process sayısı) +* Bellek +* Başlatmadan önceki adımlar + +Sonraki bölümlerde bu kavramların her birini nasıl düşünmeniz gerektiğini ve bunlarla başa çıkmak için kullanabileceğiniz somut örnekleri/stratejileri anlatacağım. 🚀 diff --git a/docs/tr/docs/deployment/server-workers.md b/docs/tr/docs/deployment/server-workers.md new file mode 100644 index 0000000000..faae4ef920 --- /dev/null +++ b/docs/tr/docs/deployment/server-workers.md @@ -0,0 +1,139 @@ +# Server Workers - Worker'larla Uvicorn { #server-workers-uvicorn-with-workers } + +Önceki bölümlerde bahsettiğimiz deployment kavramlarına tekrar bakalım: + +* Güvenlik - HTTPS +* Başlangıçta çalıştırma +* Yeniden başlatmalar +* **Replikasyon (çalışan process sayısı)** +* Bellek +* Başlatmadan önceki adımlar + +Bu noktaya kadar, dokümantasyondaki tüm tutorial'larla muhtemelen bir **server programı** çalıştırıyordunuz; örneğin Uvicorn'u çalıştıran `fastapi` komutunu kullanarak ve **tek bir process** ile. + +Uygulamaları deploy ederken, **çok çekirdekten (multiple cores)** faydalanmak ve daha fazla request'i karşılayabilmek için büyük olasılıkla **process replikasyonu** (birden fazla process) isteyeceksiniz. + +[Daha önceki Deployment Concepts](concepts.md){.internal-link target=_blank} bölümünde gördüğünüz gibi, kullanabileceğiniz birden fazla strateji var. + +Burada, `fastapi` komutunu kullanarak ya da `uvicorn` komutunu doğrudan çalıştırarak **worker process**'lerle **Uvicorn**'u nasıl kullanacağınızı göstereceğim. + +/// info | Bilgi + +Container kullanıyorsanız (örneğin Docker veya Kubernetes ile), bununla ilgili daha fazlasını bir sonraki bölümde anlatacağım: [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank}. + +Özellikle **Kubernetes** üzerinde çalıştırırken, büyük olasılıkla worker kullanmak **istemeyeceksiniz**; bunun yerine **container başına tek bir Uvicorn process** çalıştırmak daha uygundur. Ancak bunu da o bölümde detaylandıracağım. + +/// + +## Birden Fazla Worker { #multiple-workers } + +Komut satırında `--workers` seçeneğiyle birden fazla worker başlatabilirsiniz: + +//// tab | `fastapi` + +`fastapi` komutunu kullanıyorsanız: + +
+ +```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` + +`uvicorn` komutunu doğrudan kullanmayı tercih ederseniz: + +
+ +```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. +``` + +
+ +//// + +Buradaki tek yeni seçenek `--workers`; bu seçenek Uvicorn'a 4 adet worker process başlatmasını söyler. + +Ayrıca her process'in **PID**'inin gösterildiğini de görebilirsiniz: parent process için `27365` (bu **process manager**), her worker process için de bir PID: `27368`, `27369`, `27370` ve `27367`. + +## Deployment Kavramları { #deployment-concepts } + +Burada, uygulamanın çalışmasını **paralelleştirmek**, CPU'daki **çok çekirdekten** yararlanmak ve **daha fazla request** karşılayabilmek için birden fazla **worker**'ı nasıl kullanacağınızı gördünüz. + +Yukarıdaki deployment kavramları listesinden, worker kullanımı ağırlıklı olarak **replikasyon** kısmına yardımcı olur, ayrıca **yeniden başlatmalar** konusunda da az da olsa katkı sağlar. Ancak diğerlerini yine sizin yönetmeniz gerekir: + +* **Güvenlik - HTTPS** +* **Başlangıçta çalıştırma** +* ***Yeniden başlatmalar*** +* Replikasyon (çalışan process sayısı) +* **Bellek** +* **Başlatmadan önceki adımlar** + +## Container'lar ve Docker { #containers-and-docker } + +Bir sonraki bölümde, [Container'larda FastAPI - Docker](docker.md){.internal-link target=_blank} üzerinden diğer **deployment kavramlarını** ele almak için kullanabileceğiniz bazı stratejileri anlatacağım. + +Tek bir Uvicorn process çalıştıracak şekilde **sıfırdan kendi image'ınızı oluşturmayı** göstereceğim. Bu oldukça basit bir süreçtir ve **Kubernetes** gibi dağıtık bir container yönetim sistemi kullanırken büyük olasılıkla yapmak isteyeceğiniz şey de budur. + +## Özet { #recap } + +**Çok çekirdekli CPU**'lardan faydalanmak ve **birden fazla process'i paralel** çalıştırmak için `fastapi` veya `uvicorn` komutlarıyla `--workers` CLI seçeneğini kullanarak birden fazla worker process çalıştırabilirsiniz. + +Diğer deployment kavramlarını da kendiniz ele alarak **kendi deployment sisteminizi** kuruyorsanız, bu araçları ve fikirleri kullanabilirsiniz. + +Container'larla (örn. Docker ve Kubernetes) **FastAPI**'yi öğrenmek için bir sonraki bölüme göz atın. Bu araçların, diğer **deployment kavramlarını** çözmek için de basit yöntemleri olduğunu göreceksiniz. ✨ diff --git a/docs/tr/docs/deployment/versions.md b/docs/tr/docs/deployment/versions.md new file mode 100644 index 0000000000..c3fb5d9bd9 --- /dev/null +++ b/docs/tr/docs/deployment/versions.md @@ -0,0 +1,93 @@ +# FastAPI Sürümleri Hakkında { #about-fastapi-versions } + +**FastAPI** hâlihazırda birçok uygulama ve sistemde production ortamında kullanılmaktadır. Ayrıca test kapsamı %100 seviyesinde tutulmaktadır. Ancak geliştirme süreci hâlâ hızlı şekilde ilerlemektedir. + +Yeni özellikler sık sık eklenir, bug'lar düzenli olarak düzeltilir ve kod sürekli iyileştirilmektedir. + +Bu yüzden mevcut sürümler hâlâ `0.x.x` şeklindedir; bu da her sürümde breaking change olma ihtimalini yansıtır. Bu yaklaşım Semantic Versioning kurallarını takip eder. + +Şu anda **FastAPI** ile production uygulamaları geliştirebilirsiniz (muhtemelen bir süredir yapıyorsunuz da); sadece kodunuzun geri kalanıyla doğru çalışan bir sürüm kullandığınızdan emin olmanız gerekir. + +## `fastapi` sürümünü sabitleyin { #pin-your-fastapi-version } + +İlk yapmanız gereken, kullandığınız **FastAPI** sürümünü uygulamanızla doğru çalıştığını bildiğiniz belirli bir güncel sürüme "sabitlemek" (pinlemek) olmalı. + +Örneğin, uygulamanızda `0.112.0` sürümünü kullandığınızı varsayalım. + +`requirements.txt` dosyası kullanıyorsanız sürümü şöyle belirtebilirsiniz: + +```txt +fastapi[standard]==0.112.0 +``` + +Bu, tam olarak `0.112.0` sürümünü kullanacağınız anlamına gelir. + +Ya da şu şekilde de sabitleyebilirsiniz: + +```txt +fastapi[standard]>=0.112.0,<0.113.0 +``` + +Bu da `0.112.0` ve üzeri, ama `0.113.0` altındaki sürümleri kullanacağınız anlamına gelir; örneğin `0.112.2` gibi bir sürüm de kabul edilir. + +Kurulumları yönetmek için `uv`, Poetry, Pipenv gibi başka bir araç (veya benzerleri) kullanıyorsanız, bunların hepsinde paketler için belirli sürümler tanımlamanın bir yolu vardır. + +## Mevcut sürümler { #available-versions } + +Mevcut sürümleri (ör. en güncel son sürümün hangisi olduğunu kontrol etmek için) [Release Notes](../release-notes.md){.internal-link target=_blank} sayfasında görebilirsiniz. + +## Sürümler Hakkında { #about-versions } + +Semantic Versioning kurallarına göre, `1.0.0` altındaki herhangi bir sürüm breaking change içerebilir. + +FastAPI ayrıca "PATCH" sürüm değişikliklerinin bug fix'ler ve breaking olmayan değişiklikler için kullanılması kuralını da takip eder. + +/// tip | İpucu + +"PATCH" son sayıdır. Örneğin `0.2.3` içinde PATCH sürümü `3`'tür. + +/// + +Dolayısıyla şu şekilde bir sürüme sabitleyebilmelisiniz: + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +Breaking change'ler ve yeni özellikler "MINOR" sürümlerde eklenir. + +/// tip | İpucu + +"MINOR" ortadaki sayıdır. Örneğin `0.2.3` içinde MINOR sürümü `2`'dir. + +/// + +## FastAPI Sürümlerini Yükseltme { #upgrading-the-fastapi-versions } + +Uygulamanız için test'ler eklemelisiniz. + +**FastAPI** ile bu çok kolaydır (Starlette sayesinde). Dokümantasyona bakın: [Testing](../tutorial/testing.md){.internal-link target=_blank} + +Test'leriniz olduktan sonra **FastAPI** sürümünü daha yeni bir sürüme yükseltebilir ve test'lerinizi çalıştırarak tüm kodunuzun doğru çalıştığından emin olabilirsiniz. + +Her şey çalışıyorsa (ya da gerekli değişiklikleri yaptıktan sonra) ve tüm test'leriniz geçiyorsa, `fastapi` sürümünü o yeni sürüme sabitleyebilirsiniz. + +## Starlette Hakkında { #about-starlette } + +`starlette` sürümünü sabitlememelisiniz. + +**FastAPI**'nin farklı sürümleri, Starlette'in belirli (daha yeni) bir sürümünü kullanır. + +Bu yüzden **FastAPI**'nin doğru Starlette sürümünü kullanmasına izin verebilirsiniz. + +## Pydantic Hakkında { #about-pydantic } + +Pydantic, **FastAPI** için olan test'leri kendi test'lerinin içine dahil eder; bu yüzden Pydantic'in yeni sürümleri (`1.0.0` üzeri) her zaman FastAPI ile uyumludur. + +Pydantic'i sizin için çalışan `1.0.0` üzerindeki herhangi bir sürüme sabitleyebilirsiniz. + +Örneğin: + +```txt +pydantic>=2.7.0,<3.0.0 +``` diff --git a/docs/tr/docs/environment-variables.md b/docs/tr/docs/environment-variables.md new file mode 100644 index 0000000000..e4f769a16e --- /dev/null +++ b/docs/tr/docs/environment-variables.md @@ -0,0 +1,298 @@ +# Ortam Değişkenleri { #environment-variables } + +/// tip | İpucu + +"Ortam değişkenleri"nin ne olduğunu ve nasıl kullanılacağını zaten biliyorsanız, bu bölümü atlayabilirsiniz. + +/// + +Ortam değişkeni (genelde "**env var**" olarak da anılır), Python kodunun **dışında**, **işletim sistemi** seviyesinde bulunan ve Python kodunuz (veya diğer programlar) tarafından okunabilen bir değişkendir. + +Ortam değişkenleri; uygulama **ayarları**nı yönetmek, Python’un **kurulumu**nun bir parçası olarak konfigürasyon yapmak vb. durumlarda işe yarar. + +## Env Var Oluşturma ve Kullanma { #create-and-use-env-vars } + +Python’a ihtiyaç duymadan, **shell (terminal)** içinde ortam değişkenleri **oluşturabilir** ve kullanabilirsiniz: + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +// You could create an env var MY_NAME with +$ export MY_NAME="Wade Wilson" + +// Then you could use it with other programs, like +$ echo "Hello $MY_NAME" + +Hello Wade Wilson +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +// Create an env var MY_NAME +$ $Env:MY_NAME = "Wade Wilson" + +// Use it with other programs, like +$ echo "Hello $Env:MY_NAME" + +Hello Wade Wilson +``` + +
+ +//// + +## Python’da env var Okuma { #read-env-vars-in-python } + +Ortam değişkenlerini Python’un **dışında** (terminalde veya başka bir yöntemle) oluşturup daha sonra **Python’da okuyabilirsiniz**. + +Örneğin `main.py` adında bir dosyanız şöyle olabilir: + +```Python hl_lines="3" +import os + +name = os.getenv("MY_NAME", "World") +print(f"Hello {name} from Python") +``` + +/// tip | İpucu + +`os.getenv()` fonksiyonunun ikinci argümanı, bulunamadığında döndürülecek varsayılan (default) değerdir. + +Verilmezse varsayılan olarak `None` olur; burada varsayılan değer olarak `"World"` verdik. + +/// + +Sonrasında bu Python programını çalıştırabilirsiniz: + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +// Here we don't set the env var yet +$ python main.py + +// As we didn't set the env var, we get the default value + +Hello World from Python + +// But if we create an environment variable first +$ export MY_NAME="Wade Wilson" + +// And then call the program again +$ python main.py + +// Now it can read the environment variable + +Hello Wade Wilson from Python +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +// Here we don't set the env var yet +$ python main.py + +// As we didn't set the env var, we get the default value + +Hello World from Python + +// But if we create an environment variable first +$ $Env:MY_NAME = "Wade Wilson" + +// And then call the program again +$ python main.py + +// Now it can read the environment variable + +Hello Wade Wilson from Python +``` + +
+ +//// + +Ortam değişkenleri kodun dışında ayarlanabildiği, ama kod tarafından okunabildiği ve dosyalarla birlikte saklanmasının (ör. `git`’e commit edilmesinin) gerekmediği için, konfigürasyon veya **ayarlar** için sıkça kullanılır. + +Ayrıca, bir ortam değişkenini yalnızca **belirli bir program çalıştırımı** için oluşturabilirsiniz; bu değişken sadece o program tarafından, sadece o çalıştırma süresince kullanılabilir. + +Bunu yapmak için, program komutunun hemen öncesinde ve aynı satırda tanımlayın: + +
+ +```console +// Create an env var MY_NAME in line for this program call +$ MY_NAME="Wade Wilson" python main.py + +// Now it can read the environment variable + +Hello Wade Wilson from Python + +// The env var no longer exists afterwards +$ python main.py + +Hello World from Python +``` + +
+ +/// tip | İpucu + +Bu konuyla ilgili daha fazlasını The Twelve-Factor App: Config bölümünde okuyabilirsiniz. + +/// + +## Tipler ve Doğrulama { #types-and-validation } + +Bu ortam değişkenleri yalnızca **metin string**’lerini taşıyabilir. Çünkü Python’un dışındadırlar ve diğer programlarla, sistemin geri kalanıyla (hatta Linux, Windows, macOS gibi farklı işletim sistemleriyle) uyumlu olmak zorundadırlar. + +Bu, Python’da bir ortam değişkeninden okunan **her değerin `str` olacağı** anlamına gelir. Farklı bir tipe dönüştürme veya doğrulama işlemleri kod içinde yapılmalıdır. + +Uygulama **ayarları**nı yönetmek için ortam değişkenlerini kullanmayı, [İleri Seviye Kullanıcı Rehberi - Ayarlar ve Ortam Değişkenleri](./advanced/settings.md){.internal-link target=_blank} bölümünde daha detaylı öğreneceksiniz. + +## `PATH` Ortam Değişkeni { #path-environment-variable } + +İşletim sistemlerinin (Linux, macOS, Windows) çalıştırılacak programları bulmak için kullandığı **özel** bir ortam değişkeni vardır: **`PATH`**. + +`PATH` değişkeninin değeri uzun bir string’dir; Linux ve macOS’te dizinler iki nokta üst üste `:` ile, Windows’ta ise noktalı virgül `;` ile ayrılır. + +Örneğin `PATH` ortam değişkeni şöyle görünebilir: + +//// tab | Linux, macOS + +```plaintext +/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin +``` + +Bu, sistemin şu dizinlerde program araması gerektiği anlamına gelir: + +* `/usr/local/bin` +* `/usr/bin` +* `/bin` +* `/usr/sbin` +* `/sbin` + +//// + +//// tab | Windows + +```plaintext +C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32 +``` + +Bu, sistemin şu dizinlerde program araması gerektiği anlamına gelir: + +* `C:\Program Files\Python312\Scripts` +* `C:\Program Files\Python312` +* `C:\Windows\System32` + +//// + +Terminalde bir **komut** yazdığınızda, işletim sistemi `PATH` ortam değişkeninde listelenen **bu dizinlerin her birinde** programı **arar**. + +Örneğin terminalde `python` yazdığınızda, işletim sistemi bu listedeki **ilk dizinde** `python` adlı bir program arar. + +Bulursa **onu kullanır**. Bulamazsa **diğer dizinlerde** aramaya devam eder. + +### Python Kurulumu ve `PATH`’in Güncellenmesi { #installing-python-and-updating-the-path } + +Python’u kurarken, `PATH` ortam değişkenini güncellemek isteyip istemediğiniz sorulabilir. + +//// tab | Linux, macOS + +Diyelim ki Python’u kurdunuz ve `/opt/custompython/bin` dizinine yüklendi. + +`PATH` ortam değişkenini güncellemeyi seçerseniz, kurulum aracı `/opt/custompython/bin` yolunu `PATH` ortam değişkenine ekler. + +Şöyle görünebilir: + +```plaintext +/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin +``` + +Böylece terminalde `python` yazdığınızda, sistem `/opt/custompython/bin` (son dizin) içindeki Python programını bulur ve onu kullanır. + +//// + +//// tab | Windows + +Diyelim ki Python’u kurdunuz ve `C:\opt\custompython\bin` dizinine yüklendi. + +`PATH` ortam değişkenini güncellemeyi seçerseniz, kurulum aracı `C:\opt\custompython\bin` yolunu `PATH` ortam değişkenine ekler. + +```plaintext +C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin +``` + +Böylece terminalde `python` yazdığınızda, sistem `C:\opt\custompython\bin` (son dizin) içindeki Python programını bulur ve onu kullanır. + +//// + +Yani şunu yazarsanız: + +
+ +```console +$ python +``` + +
+ +//// tab | Linux, macOS + +Sistem `python` programını `/opt/custompython/bin` içinde **bulur** ve çalıştırır. + +Bu, kabaca şunu yazmaya denktir: + +
+ +```console +$ /opt/custompython/bin/python +``` + +
+ +//// + +//// tab | Windows + +Sistem `python` programını `C:\opt\custompython\bin\python` içinde **bulur** ve çalıştırır. + +Bu, kabaca şunu yazmaya denktir: + +
+ +```console +$ C:\opt\custompython\bin\python +``` + +
+ +//// + +Bu bilgiler, [Virtual Environments](virtual-environments.md){.internal-link target=_blank} konusunu öğrenirken işinize yarayacak. + +## Sonuç { #conclusion } + +Buraya kadar **ortam değişkenleri**nin ne olduğuna ve Python’da nasıl kullanılacağına dair temel bir fikir edinmiş olmalısınız. + +Ayrıca Wikipedia for Environment Variable sayfasından daha fazlasını da okuyabilirsiniz. + +Çoğu zaman ortam değişkenlerinin hemen nasıl işe yarayacağı ilk bakışta çok net olmayabilir. Ancak geliştirme yaparken birçok farklı senaryoda tekrar tekrar karşınıza çıkarlar; bu yüzden bunları bilmek faydalıdır. + +Örneğin bir sonraki bölümde, [Virtual Environments](virtual-environments.md) konusunda bu bilgilere ihtiyaç duyacaksınız. diff --git a/docs/tr/docs/fastapi-cli.md b/docs/tr/docs/fastapi-cli.md new file mode 100644 index 0000000000..4680d4bb6d --- /dev/null +++ b/docs/tr/docs/fastapi-cli.md @@ -0,0 +1,75 @@ +# FastAPI CLI { #fastapi-cli } + +**FastAPI CLI**, FastAPI uygulamanızı servis etmek, FastAPI projenizi yönetmek ve daha fazlası için kullanabileceğiniz bir komut satırı programıdır. + +FastAPI'yi kurduğunuzda (ör. `pip install "fastapi[standard]"`), beraberinde `fastapi-cli` adlı bir paket de gelir; bu paket terminalde `fastapi` komutunu sağlar. + +FastAPI uygulamanızı geliştirme için çalıştırmak üzere `fastapi dev` komutunu kullanabilirsiniz: + +
+ +```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. +``` + +
+ +`fastapi` adlı bu komut satırı programı, **FastAPI CLI**'dır. + +FastAPI CLI, Python programınızın path'ini (ör. `main.py`) alır; `FastAPI` instance'ını (genellikle `app` olarak adlandırılır) otomatik olarak tespit eder, doğru import sürecini belirler ve ardından uygulamayı servis eder. + +Production için bunun yerine `fastapi run` kullanırsınız. 🚀 + +İçeride **FastAPI CLI**, yüksek performanslı, production'a hazır bir ASGI server olan Uvicorn'u kullanır. 😎 + +## `fastapi dev` { #fastapi-dev } + +`fastapi dev` çalıştırmak, geliştirme modunu başlatır. + +Varsayılan olarak **auto-reload** etkindir; kodunuzda değişiklik yaptığınızda server'ı otomatik olarak yeniden yükler. Bu, kaynak tüketimi yüksek bir özelliktir ve kapalı olduğuna kıyasla daha az stabil olabilir. Sadece geliştirme sırasında kullanmalısınız. Ayrıca yalnızca `127.0.0.1` IP adresini dinler; bu, makinenizin sadece kendisiyle iletişim kurması için kullanılan IP'dir (`localhost`). + +## `fastapi run` { #fastapi-run } + +`fastapi run` çalıştırmak, varsayılan olarak FastAPI'yi production modunda başlatır. + +Varsayılan olarak **auto-reload** kapalıdır. Ayrıca `0.0.0.0` IP adresini dinler; bu, kullanılabilir tüm IP adresleri anlamına gelir. Böylece makineyle iletişim kurabilen herkes tarafından genel erişime açık olur. Bu, normalde production'da çalıştırma şeklidir; örneğin bir container içinde. + +Çoğu durumda (ve genellikle yapmanız gereken şekilde) üst tarafta sizin yerinize HTTPS'i yöneten bir "termination proxy" bulunur. Bu, uygulamanızı nasıl deploy ettiğinize bağlıdır; sağlayıcınız bunu sizin için yapabilir ya da sizin ayrıca kurmanız gerekebilir. + +/// tip | İpucu + +Bununla ilgili daha fazla bilgiyi [deployment dokümantasyonunda](deployment/index.md){.internal-link target=_blank} bulabilirsiniz. + +/// diff --git a/docs/tr/docs/help-fastapi.md b/docs/tr/docs/help-fastapi.md new file mode 100644 index 0000000000..785c0ae0d2 --- /dev/null +++ b/docs/tr/docs/help-fastapi.md @@ -0,0 +1,256 @@ +# FastAPI'ye Yardım Et - Yardım Al { #help-fastapi-get-help } + +**FastAPI**'yi seviyor musunuz? + +FastAPI'ye, diğer kullanıcılara ve yazara yardım etmek ister misiniz? + +Yoksa **FastAPI** ile ilgili yardım mı almak istiyorsunuz? + +Yardım etmenin çok basit yolları var (bazıları sadece bir-iki tıklama gerektirir). + +Yardım almanın da birkaç yolu var. + +## Bültene abone olun { #subscribe-to-the-newsletter } + +Şunlardan haberdar olmak için (seyrek yayımlanan) [**FastAPI and friends** bültenine](newsletter.md){.internal-link target=_blank} abone olabilirsiniz: + +* FastAPI ve friends ile ilgili haberler 🚀 +* Rehberler 📝 +* Özellikler ✨ +* Geriye dönük uyumsuz değişiklikler 🚨 +* İpuçları ve püf noktaları ✅ + +## X (Twitter) üzerinden FastAPI'yi takip edin { #follow-fastapi-on-x-twitter } + +**FastAPI** ile ilgili en güncel haberleri almak için @fastapi hesabını **X (Twitter)** üzerinde takip edin. 🐦 + +## GitHub'da **FastAPI**'ye yıldız verin { #star-fastapi-in-github } + +GitHub'da FastAPI'ye "star" verebilirsiniz (sağ üstteki yıldız butonuna tıklayarak): https://github.com/fastapi/fastapi. ⭐️ + +Yıldız verince, diğer kullanıcılar projeyi daha kolay bulabilir ve başkaları için de faydalı olduğunu görebilir. + +## GitHub repository'sini release'ler için izleyin { #watch-the-github-repository-for-releases } + +GitHub'da FastAPI'yi "watch" edebilirsiniz (sağ üstteki "watch" butonuna tıklayarak): https://github.com/fastapi/fastapi. 👀 + +Orada "Releases only" seçebilirsiniz. + +Böylece **FastAPI**'nin bug fix'ler ve yeni özelliklerle gelen her yeni release'inde (yeni versiyonunda) email ile bildirim alırsınız. + +## Yazarla bağlantı kurun { #connect-with-the-author } + +Yazar olan benimle (Sebastián Ramírez / `tiangolo`) bağlantı kurabilirsiniz. + +Şunları yapabilirsiniz: + +* Beni **GitHub**'da takip edin. + * Size yardımcı olabilecek oluşturduğum diğer Open Source projelere göz atın. + * Yeni bir Open Source proje oluşturduğumda haberdar olmak için beni takip edin. +* Beni **X (Twitter)** üzerinde veya Mastodon'da takip edin. + * FastAPI'yi nasıl kullandığınızı anlatın (bunu duymayı seviyorum). + * Duyuru yaptığımda veya yeni araçlar yayınladığımda haberdar olun. + * Ayrıca (ayrı bir hesap olan) X (Twitter) üzerinde @fastapi hesabını da takip edebilirsiniz. +* Beni **LinkedIn**'de takip edin. + * Duyuru yaptığımda veya yeni araçlar yayınladığımda haberdar olun (gerçi X (Twitter)'ı daha sık kullanıyorum 🤷‍♂). +* **Dev.to** veya **Medium** üzerinde yazdıklarımı okuyun (ya da beni takip edin). + * Diğer fikirleri, yazıları ve oluşturduğum araçlarla ilgili içerikleri okuyun. + * Yeni bir şey yayınladığımda görmek için beni takip edin. + +## **FastAPI** hakkında tweet atın { #tweet-about-fastapi } + +**FastAPI** hakkında tweet atın ve neden sevdiğinizi bana ve diğerlerine söyleyin. 🎉 + +**FastAPI**'nin nasıl kullanıldığını, nelerini sevdiğinizi, hangi projede/şirkette kullandığınızı vb. duymayı seviyorum. + +## FastAPI için oy verin { #vote-for-fastapi } + +* Slant'ta **FastAPI** için oy verin. +* AlternativeTo'da **FastAPI** için oy verin. +* StackShare'de **FastAPI** kullandığınızı belirtin. + +## GitHub'da sorularla başkalarına yardım edin { #help-others-with-questions-in-github } + +Şuralarda insanların sorularına yardımcı olmayı deneyebilirsiniz: + +* GitHub Discussions +* GitHub Issues + +Birçok durumda bu soruların cevabını zaten biliyor olabilirsiniz. 🤓 + +Eğer insanların sorularına çok yardım ederseniz, resmi bir [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank} olabilirsiniz. 🎉 + +Şunu unutmayın: en önemli nokta, nazik olmaya çalışmak. İnsanlar çoğu zaman biriken stresle geliyor ve birçok durumda soruyu en iyi şekilde sormuyor; yine de elinizden geldiğince nazik olmaya çalışın. 🤗 + +Amaç, **FastAPI** topluluğunun nazik ve kapsayıcı olması. Aynı zamanda başkalarına zorbalık ya da saygısız davranışları da kabul etmeyin. Birbirimizi kollamalıyız. + +--- + +Sorularda (discussions veya issues içinde) başkalarına yardım etmek için şunları yapabilirsiniz: + +### Soruyu anlayın { #understand-the-question } + +* Soru soran kişinin **amacının** ve kullanım senaryosunun ne olduğunu anlayabiliyor musunuz, kontrol edin. + +* Sonra sorunun (büyük çoğunluğu soru olur) **net** olup olmadığına bakın. + +* Birçok durumda kullanıcı kafasında hayali bir çözüm kurup onu sorar; ancak **daha iyi** bir çözüm olabilir. Problemi ve kullanım senaryosunu daha iyi anladıysanız daha iyi bir **alternatif çözüm** önerebilirsiniz. + +* Soruyu anlayamıyorsanız daha fazla **detay** isteyin. + +### Problemi yeniden üretin { #reproduce-the-problem } + +Çoğu durumda ve çoğu soruda, kişinin **orijinal kodu** ile ilgili bir şey vardır. + +Birçok kişi sadece kodun bir parçasını kopyalar, ama bu **problemi yeniden üretmek** için yeterli olmaz. + +* Çalıştırıp aynı hatayı/davranışı görebileceğiniz veya kullanım senaryosunu daha iyi anlayabileceğiniz, yerelde **kopyala-yapıştır** yaparak çalıştırılabilen bir minimal, reproducible, example paylaşmalarını isteyebilirsiniz. + +* Çok cömert hissediyorsanız, problemi anlatan açıklamadan yola çıkarak kendiniz de böyle bir **örnek oluşturmayı** deneyebilirsiniz. Ancak bunun çok zaman alabileceğini unutmayın; çoğu zaman önce problemi netleştirmelerini istemek daha iyidir. + +### Çözüm önerin { #suggest-solutions } + +* Soruyu anlayabildikten sonra olası bir **cevap** verebilirsiniz. + +* Çoğu durumda, yapmak istediklerinden ziyade alttaki **asıl problemi veya kullanım senaryosunu** anlamak daha iyidir; çünkü denedikleri yöntemden daha iyi bir çözüm yolu olabilir. + +### Kapatılmasını isteyin { #ask-to-close } + +Eğer yanıt verirlerse, büyük ihtimalle problemi çözmüşsünüzdür, tebrikler, **kahramansınız**! 🦸 + +* Eğer çözüm işe yaradıysa şunları yapmalarını isteyebilirsiniz: + + * GitHub Discussions'ta: ilgili yorumu **answer** olarak işaretlemeleri. + * GitHub Issues'ta: issue'yu **close** etmeleri. + +## GitHub repository'sini izleyin { #watch-the-github-repository } + +GitHub'da FastAPI'yi "watch" edebilirsiniz (sağ üstteki "watch" butonuna tıklayarak): https://github.com/fastapi/fastapi. 👀 + +"Releases only" yerine "Watching" seçerseniz biri yeni bir issue veya soru oluşturduğunda bildirim alırsınız. Ayrıca sadece yeni issue'lar, ya da discussions, ya da PR'lar vb. için bildirim almak istediğinizi belirtebilirsiniz. + +Sonra da bu soruları çözmelerine yardımcı olmayı deneyebilirsiniz. + +## Soru Sorun { #ask-questions } + +GitHub repository'sinde örneğin şunlar için yeni bir soru oluşturabilirsiniz: + +* Bir **soru** sorun veya bir **problem** hakkında danışın. +* Yeni bir **feature** önerin. + +**Not**: Bunu yaparsanız, ben de sizden başkalarına yardım etmenizi isteyeceğim. 😉 + +## Pull Request'leri İnceleyin { #review-pull-requests } + +Başkalarının gönderdiği pull request'leri incelememde bana yardımcı olabilirsiniz. + +Yine, lütfen elinizden geldiğince nazik olmaya çalışın. 🤗 + +--- + +Bir pull request'i incelerken akılda tutmanız gerekenler: + +### Problemi anlayın { #understand-the-problem } + +* Önce, pull request'in çözmeye çalıştığı **problemi anladığınızdan** emin olun. GitHub Discussion veya issue içinde daha uzun bir tartışması olabilir. + +* Pull request'in aslında hiç gerekmiyor olma ihtimali de yüksektir; çünkü problem **farklı bir şekilde** çözülebilir. Bu durumda bunu önerebilir veya bununla ilgili soru sorabilirsiniz. + +### Style konusunda çok dert etmeyin { #dont-worry-about-style } + +* Commit message tarzı gibi şeyleri çok dert etmeyin; ben commit'leri manuel olarak düzenleyerek squash and merge yapacağım. + +* Style kuralları için de endişelenmeyin; bunları kontrol eden otomatik araçlar zaten var. + +Ek bir style veya tutarlılık ihtiyacı olursa, bunu doğrudan isterim ya da gerekli değişikliklerle üstüne commit eklerim. + +### Kodu kontrol edin { #check-the-code } + +* Kodu okuyup kontrol edin; mantıklı mı bakın, **yerelde çalıştırın** ve gerçekten problemi çözüyor mu görün. + +* Ardından bunu yaptığınızı belirten bir **yorum** yazın; böylece gerçekten kontrol ettiğinizi anlarım. + +/// info | Bilgi + +Ne yazık ki sadece birkaç onayı olan PR'lara körü körüne güvenemem. + +Defalarca, 3, 5 veya daha fazla onayı olan PR'lar oldu; muhtemelen açıklaması çekici olduğu için onay aldılar. Ama PR'lara baktığımda aslında bozuk olduklarını, bug içerdiğini veya iddia ettikleri problemi çözmediklerini gördüm. 😅 + +Bu yüzden kodu gerçekten okuyup çalıştırmanız ve bunu yorumlarda bana bildirmeniz çok önemli. 🤓 + +/// + +* PR bir şekilde basitleştirilebiliyorsa bunu isteyebilirsiniz. Ancak çok didik didik etmeye gerek yok; konuya göre birçok öznel bakış açısı olabilir (benim de olacaktır 🙈). Bu yüzden temel noktalara odaklanmak daha iyi. + +### Testler { #tests } + +* PR'da **testler** olduğunu kontrol etmemde bana yardımcı olun. + +* PR'dan önce testlerin **fail** ettiğini kontrol edin. 🚨 + +* PR'dan sonra testlerin **pass** ettiğini kontrol edin. ✅ + +* Birçok PR test içermez; test eklemelerini **hatırlatabilirsiniz** veya hatta kendiniz bazı testler **önerebilirsiniz**. Bu, en çok zaman alan işlerden biridir ve burada çok yardımcı olabilirsiniz. + +* Ayrıca neleri denediğinizi yorumlara yazın; böylece kontrol ettiğinizi anlarım. 🤓 + +## Pull Request Oluşturun { #create-a-pull-request } + +Örneğin şunlar için Pull Request'lerle kaynak koda [katkıda bulunabilirsiniz](contributing.md){.internal-link target=_blank}: + +* Dokümantasyonda bulduğunuz bir yazım hatasını düzeltmek. +* FastAPI hakkında oluşturduğunuz veya bulduğunuz bir makaleyi, videoyu ya da podcast'i bu dosyayı düzenleyerek paylaşmak. + * Link'inizi ilgili bölümün başına eklediğinizden emin olun. +* Dokümantasyonu kendi dilinize [çevirmeye yardımcı olmak](contributing.md#translations){.internal-link target=_blank}. + * Başkalarının yaptığı çevirileri gözden geçirmeye de yardımcı olabilirsiniz. +* Yeni dokümantasyon bölümleri önermek. +* Mevcut bir issue/bug'ı düzeltmek. + * Test eklediğinizden emin olun. +* Yeni bir feature eklemek. + * Test eklediğinizden emin olun. + * İlgiliyse dokümantasyon da eklediğinizden emin olun. + +## FastAPI'nin Bakımına Yardım Edin { #help-maintain-fastapi } + +**FastAPI**'nin bakımını yapmama yardımcı olun! 🤓 + +Yapılacak çok iş var ve bunların çoğunu **SİZ** yapabilirsiniz. + +Şu anda yapabileceğiniz ana işler: + +* [GitHub'da sorularla başkalarına yardım edin](#help-others-with-questions-in-github){.internal-link target=_blank} (yukarıdaki bölüme bakın). +* [Pull Request'leri inceleyin](#review-pull-requests){.internal-link target=_blank} (yukarıdaki bölüme bakın). + +Bu iki iş, **en çok zamanı alan** işlerdir. FastAPI bakımının ana yükü buradadır. + +Burada yardımcı olursanız, **FastAPI'nin bakımını yapmama yardım etmiş** ve daha **hızlı ve daha iyi ilerlemesini** sağlamış olursunuz. 🚀 + +## Sohbete katılın { #join-the-chat } + +FastAPI topluluğundan diğer kişilerle takılmak için 👥 Discord chat server 👥 sohbetine katılın. + +/// tip | İpucu + +Sorular için GitHub Discussions'a sorun; [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank} tarafından yardım alma ihtimaliniz çok daha yüksektir. + +Chat'i sadece genel sohbetler için kullanın. + +/// + +### Sorular için chat'i kullanmayın { #dont-use-the-chat-for-questions } + +Chat sistemleri daha "serbest sohbet"e izin verdiği için, çok genel ve yanıtlaması daha zor sorular sormak kolaylaşır; bu nedenle cevap alamayabilirsiniz. + +GitHub'da ise şablon (template) doğru soruyu yazmanız için sizi yönlendirir; böylece daha kolay iyi bir cevap alabilir, hatta bazen sormadan önce problemi kendiniz çözebilirsiniz. Ayrıca GitHub'da (zaman alsa bile) her şeye mutlaka cevap verdiğimden emin olabilirim. Chat sistemlerinde bunu kişisel olarak yapamam. 😅 + +Chat sistemlerindeki konuşmalar GitHub kadar kolay aranabilir değildir; bu yüzden soru ve cevaplar sohbet içinde kaybolabilir. Ayrıca [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank} olmak için sadece GitHub'daki katkılar sayılır; dolayısıyla büyük olasılıkla GitHub'da daha fazla ilgi görürsünüz. + +Öte yandan chat sistemlerinde binlerce kullanıcı vardır; bu yüzden neredeyse her zaman konuşacak birini bulma ihtimaliniz yüksektir. 😄 + +## Yazara sponsor olun { #sponsor-the-author } + +Eğer **ürününüz/şirketiniz** **FastAPI**'ye bağlıysa veya onunla ilişkiliyse ve FastAPI kullanıcılarına ulaşmak istiyorsanız, GitHub sponsors üzerinden yazara (bana) sponsor olabilirsiniz. Tier'a göre dokümantasyonda bir rozet gibi ek faydalar elde edebilirsiniz. 🎁 + +--- + +Teşekkürler! 🚀 diff --git a/docs/tr/docs/how-to/authentication-error-status-code.md b/docs/tr/docs/how-to/authentication-error-status-code.md new file mode 100644 index 0000000000..579673624b --- /dev/null +++ b/docs/tr/docs/how-to/authentication-error-status-code.md @@ -0,0 +1,17 @@ +# Eski 403 Kimlik Doğrulama Hata Durum Kodlarını Kullanma { #use-old-403-authentication-error-status-codes } + +FastAPI `0.122.0` sürümünden önce, entegre security yardımcı araçları başarısız bir kimlik doğrulama (authentication) sonrasında client'a bir hata döndüğünde HTTP durum kodu olarak `403 Forbidden` kullanıyordu. + +FastAPI `0.122.0` sürümünden itibaren ise daha uygun olan HTTP durum kodu `401 Unauthorized` kullanılmakta ve HTTP spesifikasyonlarına uygun olarak response içinde anlamlı bir `WWW-Authenticate` header'ı döndürülmektedir: RFC 7235, RFC 9110. + +Ancak herhangi bir nedenle client'larınız eski davranışa bağlıysa, security class'larınızda `make_not_authenticated_error` metodunu override ederek eski davranışa geri dönebilirsiniz. + +Örneğin, varsayılan `401 Unauthorized` hatası yerine `403 Forbidden` hatası döndüren bir `HTTPBearer` alt sınıfı oluşturabilirsiniz: + +{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *} + +/// tip | İpucu + +Fonksiyonun exception instance'ını döndürdüğüne dikkat edin; exception'ı raise etmiyor. Raise işlemi internal kodun geri kalan kısmında yapılıyor. + +/// diff --git a/docs/tr/docs/how-to/conditional-openapi.md b/docs/tr/docs/how-to/conditional-openapi.md new file mode 100644 index 0000000000..9562637c47 --- /dev/null +++ b/docs/tr/docs/how-to/conditional-openapi.md @@ -0,0 +1,56 @@ +# Koşullu OpenAPI { #conditional-openapi } + +Gerekirse, ayarlar ve environment variable'ları kullanarak OpenAPI'yi ortama göre koşullu şekilde yapılandırabilir, hatta tamamen devre dışı bırakabilirsiniz. + +## Güvenlik, API'ler ve dokümantasyon hakkında { #about-security-apis-and-docs } + +Production ortamında dokümantasyon arayüzlerini gizlemek, API'nizi korumanın yolu *olmamalıdır*. + +Bu, API'nize ekstra bir güvenlik katmanı eklemez; *path operation*'lar bulundukları yerde yine erişilebilir olacaktır. + +Kodunuzda bir güvenlik açığı varsa, o açık yine var olmaya devam eder. + +Dokümantasyonu gizlemek, API'nizle nasıl etkileşime geçileceğini anlamayı zorlaştırır ve production'da debug etmeyi de daha zor hale getirebilir. Bu yaklaşım, basitçe Security through obscurity olarak değerlendirilebilir. + +API'nizi güvence altına almak istiyorsanız, yapabileceğiniz daha iyi birçok şey var; örneğin: + +* request body'leriniz ve response'larınız için iyi tanımlanmış Pydantic model'larına sahip olduğunuzdan emin olun. +* dependencies kullanarak gerekli izinleri ve rolleri yapılandırın. +* Asla düz metin (plaintext) şifre saklamayın, yalnızca password hash'leri saklayın. +* pwdlib ve JWT token'ları gibi, iyi bilinen kriptografik araçları uygulayın ve kullanın. +* Gerektiğinde OAuth2 scope'ları ile daha ayrıntılı izin kontrolleri ekleyin. +* ...vb. + +Yine de, bazı ortamlarda (örn. production) veya environment variable'lardan gelen konfigürasyonlara bağlı olarak API docs'u gerçekten devre dışı bırakmanız gereken çok spesifik bir use case'iniz olabilir. + +## Ayarlar ve env var'lar ile koşullu OpenAPI { #conditional-openapi-from-settings-and-env-vars } + +Üretilen OpenAPI'yi ve docs UI'larını yapılandırmak için aynı Pydantic settings'i kolayca kullanabilirsiniz. + +Örneğin: + +{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *} + +Burada `openapi_url` ayarını, varsayılanı `"/openapi.json"` olacak şekilde tanımlıyoruz. + +Ardından `FastAPI` app'ini oluştururken bunu kullanıyoruz. + +Sonrasında, environment variable `OPENAPI_URL`'i boş string olarak ayarlayarak OpenAPI'yi (UI docs dahil) devre dışı bırakabilirsiniz; örneğin: + +
+ +```console +$ OPENAPI_URL= uvicorn main:app + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Böylece `/openapi.json`, `/docs` veya `/redoc` URL'lerine giderseniz, aşağıdaki gibi bir `404 Not Found` hatası alırsınız: + +```JSON +{ + "detail": "Not Found" +} +``` diff --git a/docs/tr/docs/how-to/configure-swagger-ui.md b/docs/tr/docs/how-to/configure-swagger-ui.md new file mode 100644 index 0000000000..6c051a1215 --- /dev/null +++ b/docs/tr/docs/how-to/configure-swagger-ui.md @@ -0,0 +1,70 @@ +# Swagger UI'yi Yapılandırın { #configure-swagger-ui } + +Bazı ek Swagger UI parametrelerini yapılandırabilirsiniz. + +Bunları yapılandırmak için, `FastAPI()` uygulama nesnesini oluştururken ya da `get_swagger_ui_html()` fonksiyonuna `swagger_ui_parameters` argümanını verin. + +`swagger_ui_parameters`, Swagger UI'ye doğrudan iletilecek yapılandırmaları içeren bir `dict` alır. + +FastAPI, Swagger UI'nin ihtiyaç duyduğu şekilde JavaScript ile uyumlu olsun diye bu yapılandırmaları **JSON**'a dönüştürür. + +## Syntax Highlighting'i Devre Dışı Bırakın { #disable-syntax-highlighting } + +Örneğin, Swagger UI'de syntax highlighting'i devre dışı bırakabilirsiniz. + +Ayarları değiştirmeden bırakırsanız, syntax highlighting varsayılan olarak etkindir: + + + +Ancak `syntaxHighlight` değerini `False` yaparak devre dışı bırakabilirsiniz: + +{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *} + +...ve ardından Swagger UI artık syntax highlighting'i göstermeyecektir: + + + +## Temayı Değiştirin { #change-the-theme } + +Aynı şekilde, `"syntaxHighlight.theme"` anahtarıyla (ortasında bir nokta olduğuna dikkat edin) syntax highlighting temasını ayarlayabilirsiniz: + +{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *} + +Bu yapılandırma, syntax highlighting renk temasını değiştirir: + + + +## Varsayılan Swagger UI Parametrelerini Değiştirin { #change-default-swagger-ui-parameters } + +FastAPI, çoğu kullanım senaryosu için uygun bazı varsayılan yapılandırma parametreleriyle gelir. + +Şu varsayılan yapılandırmaları içerir: + +{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *} + +`swagger_ui_parameters` argümanında farklı bir değer vererek bunların herhangi birini ezebilirsiniz (override). + +Örneğin `deepLinking`'i devre dışı bırakmak için `swagger_ui_parameters`'a şu ayarları geçebilirsiniz: + +{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *} + +## Diğer Swagger UI Parametreleri { #other-swagger-ui-parameters } + +Kullanabileceğiniz diğer tüm olası yapılandırmaları görmek için, resmi Swagger UI parametreleri dokümantasyonunu okuyun. + +## Yalnızca JavaScript ayarları { #javascript-only-settings } + +Swagger UI ayrıca bazı yapılandırmaların **yalnızca JavaScript** nesneleri olmasına izin verir (örneğin JavaScript fonksiyonları). + +FastAPI, bu yalnızca JavaScript olan `presets` ayarlarını da içerir: + +```JavaScript +presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIBundle.SwaggerUIStandalonePreset +] +``` + +Bunlar string değil, **JavaScript** nesneleridir; dolayısıyla bunları Python kodundan doğrudan geçemezsiniz. + +Böyle yalnızca JavaScript yapılandırmalarına ihtiyacınız varsa, yukarıdaki yöntemlerden birini kullanabilirsiniz: Swagger UI'nin tüm *path operation*'larını override edin ve ihtiyaç duyduğunuz JavaScript'i elle yazın. diff --git a/docs/tr/docs/how-to/custom-docs-ui-assets.md b/docs/tr/docs/how-to/custom-docs-ui-assets.md new file mode 100644 index 0000000000..bdd2d02440 --- /dev/null +++ b/docs/tr/docs/how-to/custom-docs-ui-assets.md @@ -0,0 +1,185 @@ +# Özel Docs UI Statik Varlıkları (Self-Hosting) { #custom-docs-ui-static-assets-self-hosting } + +API dokümanları **Swagger UI** ve **ReDoc** kullanır ve bunların her biri bazı JavaScript ve CSS dosyalarına ihtiyaç duyar. + +Varsayılan olarak bu dosyalar bir CDN üzerinden servis edilir. + +Ancak bunu özelleştirmek mümkündür; belirli bir CDN ayarlayabilir veya dosyaları kendiniz servis edebilirsiniz. + +## JavaScript ve CSS için Özel CDN { #custom-cdn-for-javascript-and-css } + +Diyelim ki farklı bir CDN kullanmak istiyorsunuz; örneğin `https://unpkg.com/` kullanmak istiyorsunuz. + +Bu, örneğin bazı URL'leri kısıtlayan bir ülkede yaşıyorsanız faydalı olabilir. + +### Otomatik dokümanları devre dışı bırakın { #disable-the-automatic-docs } + +İlk adım, otomatik dokümanları devre dışı bırakmaktır; çünkü varsayılan olarak bunlar varsayılan CDN'i kullanır. + +Bunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın: + +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *} + +### Özel dokümanları ekleyin { #include-the-custom-docs } + +Şimdi özel dokümanlar için *path operation*'ları oluşturabilirsiniz. + +Dokümanlar için HTML sayfalarını üretmek üzere FastAPI'nin dahili fonksiyonlarını yeniden kullanabilir ve gerekli argümanları iletebilirsiniz: + +* `openapi_url`: Dokümanların HTML sayfasının API'niz için OpenAPI şemasını alacağı URL. Burada `app.openapi_url` niteliğini kullanabilirsiniz. +* `title`: API'nizin başlığı. +* `oauth2_redirect_url`: varsayılanı kullanmak için burada `app.swagger_ui_oauth2_redirect_url` kullanabilirsiniz. +* `swagger_js_url`: Swagger UI dokümanlarınızın HTML'inin **JavaScript** dosyasını alacağı URL. Bu, özel CDN URL'idir. +* `swagger_css_url`: Swagger UI dokümanlarınızın HTML'inin **CSS** dosyasını alacağı URL. Bu, özel CDN URL'idir. + +ReDoc için de benzer şekilde... + +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *} + +/// tip | İpucu + +`swagger_ui_redirect` için olan *path operation*, OAuth2 kullandığınızda yardımcı olması için vardır. + +API'nizi bir OAuth2 sağlayıcısıyla entegre ederseniz kimlik doğrulaması yapabilir, aldığınız kimlik bilgileriyle API dokümanlarına geri dönebilir ve gerçek OAuth2 kimlik doğrulamasını kullanarak onunla etkileşime geçebilirsiniz. + +Swagger UI bunu arka planda sizin için yönetir, ancak bu "redirect" yardımcısına ihtiyaç duyar. + +/// + +### Test etmek için bir *path operation* oluşturun { #create-a-path-operation-to-test-it } + +Şimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun: + +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *} + +### Test edin { #test-it } + +Artık http://127.0.0.1:8000/docs adresinden dokümanlarınıza gidebilmeli ve sayfayı yenilediğinizde bu varlıkların yeni CDN'den yüklendiğini görebilmelisiniz. + +## Dokümanlar için JavaScript ve CSS'i Self-Hosting ile barındırma { #self-hosting-javascript-and-css-for-docs } + +JavaScript ve CSS'i self-hosting ile barındırmak, örneğin uygulamanızın İnternet erişimi olmadan (offline), açık İnternet olmadan veya bir lokal ağ içinde bile çalışmaya devam etmesi gerekiyorsa faydalı olabilir. + +Burada bu dosyaları aynı FastAPI uygulamasında nasıl kendiniz servis edeceğinizi ve dokümanların bunları kullanacak şekilde nasıl yapılandırılacağını göreceksiniz. + +### Proje dosya yapısı { #project-file-structure } + +Diyelim ki projenizin dosya yapısı şöyle: + +``` +. +├── app +│ ├── __init__.py +│ ├── main.py +``` + +Şimdi bu statik dosyaları saklamak için bir dizin oluşturun. + +Yeni dosya yapınız şöyle olabilir: + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +└── static/ +``` + +### Dosyaları indirin { #download-the-files } + +Dokümanlar için gereken statik dosyaları indirin ve `static/` dizinine koyun. + +Muhtemelen her bir linke sağ tıklayıp "Save link as..." benzeri bir seçenek seçebilirsiniz. + +**Swagger UI** şu dosyaları kullanır: + +* `swagger-ui-bundle.js` +* `swagger-ui.css` + +**ReDoc** ise şu dosyayı kullanır: + +* `redoc.standalone.js` + +Bundan sonra dosya yapınız şöyle görünebilir: + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +└── static + ├── redoc.standalone.js + ├── swagger-ui-bundle.js + └── swagger-ui.css +``` + +### Statik dosyaları servis edin { #serve-the-static-files } + +* `StaticFiles` içe aktarın. +* Belirli bir path'te bir `StaticFiles()` instance'ını "mount" edin. + +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *} + +### Statik dosyaları test edin { #test-the-static-files } + +Uygulamanızı başlatın ve http://127.0.0.1:8000/static/redoc.standalone.js adresine gidin. + +**ReDoc** için çok uzun bir JavaScript dosyası görmelisiniz. + +Şuna benzer bir şekilde başlayabilir: + +```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")): +... +``` + +Bu, uygulamanızdan statik dosyaları servis edebildiğinizi ve dokümanlar için statik dosyaları doğru yere koyduğunuzu doğrular. + +Şimdi uygulamayı, dokümanlar için bu statik dosyaları kullanacak şekilde yapılandırabiliriz. + +### Statik dosyalar için otomatik dokümanları devre dışı bırakın { #disable-the-automatic-docs-for-static-files } + +Özel CDN kullanırken olduğu gibi, ilk adım otomatik dokümanları devre dışı bırakmaktır; çünkü bunlar varsayılan olarak CDN kullanır. + +Bunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın: + +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *} + +### Statik dosyalar için özel dokümanları ekleyin { #include-the-custom-docs-for-static-files } + +Özel CDN'de olduğu gibi, artık özel dokümanlar için *path operation*'ları oluşturabilirsiniz. + +Yine FastAPI'nin dahili fonksiyonlarını kullanarak dokümanlar için HTML sayfalarını oluşturabilir ve gerekli argümanları geçebilirsiniz: + +* `openapi_url`: Dokümanların HTML sayfasının API'niz için OpenAPI şemasını alacağı URL. Burada `app.openapi_url` niteliğini kullanabilirsiniz. +* `title`: API'nizin başlığı. +* `oauth2_redirect_url`: varsayılanı kullanmak için burada `app.swagger_ui_oauth2_redirect_url` kullanabilirsiniz. +* `swagger_js_url`: Swagger UI dokümanlarınızın HTML'inin **JavaScript** dosyasını alacağı URL. **Artık bunu sizin kendi uygulamanız servis ediyor**. +* `swagger_css_url`: Swagger UI dokümanlarınızın HTML'inin **CSS** dosyasını alacağı URL. **Artık bunu sizin kendi uygulamanız servis ediyor**. + +ReDoc için de benzer şekilde... + +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *} + +/// tip | İpucu + +`swagger_ui_redirect` için olan *path operation*, OAuth2 kullandığınızda yardımcı olması için vardır. + +API'nizi bir OAuth2 sağlayıcısıyla entegre ederseniz kimlik doğrulaması yapabilir, aldığınız kimlik bilgileriyle API dokümanlarına geri dönebilir ve gerçek OAuth2 kimlik doğrulamasını kullanarak onunla etkileşime geçebilirsiniz. + +Swagger UI bunu arka planda sizin için yönetir, ancak bu "redirect" yardımcısına ihtiyaç duyar. + +/// + +### Statik dosyaları test etmek için bir *path operation* oluşturun { #create-a-path-operation-to-test-static-files } + +Şimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun: + +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *} + +### Statik Dosyalar UI'ını Test Edin { #test-static-files-ui } + +Artık WiFi bağlantınızı kesip http://127.0.0.1:8000/docs adresindeki dokümanlarınıza gidebilmeli ve sayfayı yenileyebilmelisiniz. + +Ve İnternet olmasa bile API dokümanlarınızı görebilir ve onunla etkileşime geçebilirsiniz. diff --git a/docs/tr/docs/how-to/custom-request-and-route.md b/docs/tr/docs/how-to/custom-request-and-route.md new file mode 100644 index 0000000000..a4419373f7 --- /dev/null +++ b/docs/tr/docs/how-to/custom-request-and-route.md @@ -0,0 +1,109 @@ +# Özel Request ve APIRoute sınıfı { #custom-request-and-apiroute-class } + +Bazı durumlarda, `Request` ve `APIRoute` sınıflarının kullandığı mantığı override etmek isteyebilirsiniz. + +Özellikle bu yaklaşım, bir middleware içindeki mantığa iyi bir alternatif olabilir. + +Örneğin, request body uygulamanız tarafından işlenmeden önce okumak veya üzerinde değişiklik yapmak istiyorsanız. + +/// danger | Uyarı + +Bu "ileri seviye" bir özelliktir. + +**FastAPI**'ye yeni başlıyorsanız bu bölümü atlamak isteyebilirsiniz. + +/// + +## Kullanım senaryoları { #use-cases } + +Bazı kullanım senaryoları: + +* JSON olmayan request body'leri JSON'a dönüştürmek (örn. `msgpack`). +* gzip ile sıkıştırılmış request body'leri açmak (decompress). +* Tüm request body'lerini otomatik olarak loglamak. + +## Özel request body encoding'lerini ele alma { #handling-custom-request-body-encodings } + +Gzip request'lerini açmak için özel bir `Request` alt sınıfını nasıl kullanabileceğimize bakalım. + +Ayrıca, o özel request sınıfını kullanmak için bir `APIRoute` alt sınıfı da oluşturacağız. + +### Özel bir `GzipRequest` sınıfı oluşturun { #create-a-custom-gziprequest-class } + +/// tip | İpucu + +Bu, nasıl çalıştığını göstermek için hazırlanmış basit bir örnektir; Gzip desteğine ihtiyacınız varsa sağlanan [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank} bileşenini kullanabilirsiniz. + +/// + +Önce, uygun bir header mevcut olduğunda body'yi açmak için `Request.body()` metodunu overwrite edecek bir `GzipRequest` sınıfı oluşturuyoruz. + +Header'da `gzip` yoksa body'yi açmayı denemez. + +Böylece aynı route sınıfı, gzip ile sıkıştırılmış veya sıkıştırılmamış request'leri handle edebilir. + +{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *} + +### Özel bir `GzipRoute` sınıfı oluşturun { #create-a-custom-gziproute-class } + +Sonra, `GzipRequest`'i kullanacak `fastapi.routing.APIRoute` için özel bir alt sınıf oluşturuyoruz. + +Bu kez `APIRoute.get_route_handler()` metodunu overwrite edeceğiz. + +Bu metot bir fonksiyon döndürür. Bu fonksiyon da request'i alır ve response döndürür. + +Burada bu fonksiyonu, orijinal request'ten bir `GzipRequest` oluşturmak için kullanıyoruz. + +{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *} + +/// note | Teknik Detaylar + +Bir `Request`'in, request ile ilgili metadata'yı içeren bir Python `dict` olan `request.scope` attribute'u vardır. + +Bir `Request` ayrıca `request.receive` içerir; bu, request'in body'sini "almak" (receive etmek) için kullanılan bir fonksiyondur. + +`scope` `dict`'i ve `receive` fonksiyonu, ASGI spesifikasyonunun parçalarıdır. + +Ve bu iki şey, `scope` ve `receive`, yeni bir `Request` instance'ı oluşturmak için gerekenlerdir. + +`Request` hakkında daha fazla bilgi için Starlette'ın Request dokümantasyonuna bakın. + +/// + +`GzipRequest.get_route_handler` tarafından döndürülen fonksiyonun farklı yaptığı tek şey, `Request`'i bir `GzipRequest`'e dönüştürmektir. + +Bunu yaptığımızda `GzipRequest`, veriyi (gerekliyse) *path operations*'larımıza geçirmeden önce açma (decompress) işini üstlenir. + +Bundan sonra tüm işleme mantığı aynıdır. + +Ancak `GzipRequest.body` içindeki değişikliklerimiz sayesinde, request body gerektiğinde **FastAPI** tarafından yüklendiğinde otomatik olarak decompress edilir. + +## Bir exception handler içinde request body'ye erişme { #accessing-the-request-body-in-an-exception-handler } + +/// tip | İpucu + +Aynı problemi çözmek için, muhtemelen `RequestValidationError` için özel bir handler içinde `body` kullanmak çok daha kolaydır ([Hataları Ele Alma](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}). + +Yine de bu örnek geçerlidir ve dahili bileşenlerle nasıl etkileşime geçileceğini gösterir. + +/// + +Aynı yaklaşımı bir exception handler içinde request body'ye erişmek için de kullanabiliriz. + +Tek yapmamız gereken, request'i bir `try`/`except` bloğu içinde handle etmek: + +{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *} + +Bir exception oluşursa, `Request` instance'ı hâlâ scope içinde olacağı için, hatayı handle ederken request body'yi okuyup kullanabiliriz: + +{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *} + +## Bir router içinde özel `APIRoute` sınıfı { #custom-apiroute-class-in-a-router } + +Bir `APIRouter` için `route_class` parametresini de ayarlayabilirsiniz: + +{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *} + +Bu örnekte, `router` altındaki *path operations*'lar özel `TimedRoute` sınıfını kullanır ve response'u üretmek için geçen süreyi içeren ekstra bir `X-Response-Time` header'ı response'ta bulunur: + +{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *} diff --git a/docs/tr/docs/how-to/extending-openapi.md b/docs/tr/docs/how-to/extending-openapi.md new file mode 100644 index 0000000000..99691946c2 --- /dev/null +++ b/docs/tr/docs/how-to/extending-openapi.md @@ -0,0 +1,80 @@ +# OpenAPI'yi Genişletme { #extending-openapi } + +Oluşturulan OpenAPI şemasını değiştirmeniz gereken bazı durumlar olabilir. + +Bu bölümde bunun nasıl yapılacağını göreceksiniz. + +## Normal süreç { #the-normal-process } + +Normal (varsayılan) süreç şöyledir. + +Bir `FastAPI` uygulamasının (instance) OpenAPI şemasını döndürmesi beklenen bir `.openapi()` metodu vardır. + +Uygulama nesnesi oluşturulurken, `/openapi.json` (ya da `openapi_url` için ne ayarladıysanız o) için bir *path operation* kaydedilir. + +Bu path operation, uygulamanın `.openapi()` metodunun sonucunu içeren bir JSON response döndürür. + +Varsayılan olarak `.openapi()` metodunun yaptığı şey, `.openapi_schema` özelliğinde içerik olup olmadığını kontrol etmek ve varsa onu döndürmektir. + +Eğer yoksa, `fastapi.openapi.utils.get_openapi` konumundaki yardımcı (utility) fonksiyonu kullanarak şemayı üretir. + +Ve `get_openapi()` fonksiyonu şu parametreleri alır: + +* `title`: Dokümanlarda gösterilen OpenAPI başlığı. +* `version`: API'nizin sürümü, örn. `2.5.0`. +* `openapi_version`: Kullanılan OpenAPI specification sürümü. Varsayılan olarak en günceli: `3.1.0`. +* `summary`: API'nin kısa özeti. +* `description`: API'nizin açıklaması; markdown içerebilir ve dokümanlarda gösterilir. +* `routes`: route'ların listesi; bunların her biri kayıtlı *path operations*'lardır. `app.routes` içinden alınırlar. + +/// info | Bilgi + +`summary` parametresi OpenAPI 3.1.0 ve üzeri sürümlerde vardır; FastAPI 0.99.0 ve üzeri tarafından desteklenmektedir. + +/// + +## Varsayılanları ezme { #overriding-the-defaults } + +Yukarıdaki bilgileri kullanarak aynı yardımcı fonksiyonla OpenAPI şemasını üretebilir ve ihtiyacınız olan her parçayı override edebilirsiniz. + +Örneğin, özel bir logo eklemek için ReDoc'un OpenAPI extension'ını ekleyelim. + +### Normal **FastAPI** { #normal-fastapi } + +Önce, tüm **FastAPI** uygulamanızı her zamanki gibi yazın: + +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *} + +### OpenAPI şemasını üretme { #generate-the-openapi-schema } + +Ardından, bir `custom_openapi()` fonksiyonunun içinde aynı yardımcı fonksiyonu kullanarak OpenAPI şemasını üretin: + +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *} + +### OpenAPI şemasını değiştirme { #modify-the-openapi-schema } + +Artık OpenAPI şemasındaki `info` "object"'ine özel bir `x-logo` ekleyerek ReDoc extension'ını ekleyebilirsiniz: + +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *} + +### OpenAPI şemasını cache'leme { #cache-the-openapi-schema } + +Ürettiğiniz şemayı saklamak için `.openapi_schema` özelliğini bir "cache" gibi kullanabilirsiniz. + +Böylece bir kullanıcı API docs'larınızı her açtığında uygulamanız şemayı tekrar tekrar üretmek zorunda kalmaz. + +Şema yalnızca bir kez üretilecektir; sonraki request'ler için de aynı cache'lenmiş şema kullanılacaktır. + +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *} + +### Metodu override etme { #override-the-method } + +Şimdi `.openapi()` metodunu yeni fonksiyonunuzla değiştirebilirsiniz. + +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *} + +### Kontrol edin { #check-it } + +http://127.0.0.1:8000/redoc adresine gittiğinizde, özel logonuzu kullandığınızı göreceksiniz (bu örnekte **FastAPI**'nin logosu): + + diff --git a/docs/tr/docs/how-to/graphql.md b/docs/tr/docs/how-to/graphql.md new file mode 100644 index 0000000000..fbf0188740 --- /dev/null +++ b/docs/tr/docs/how-to/graphql.md @@ -0,0 +1,60 @@ +# GraphQL { #graphql } + +**FastAPI**, **ASGI** standardını temel aldığı için ASGI ile uyumlu herhangi bir **GraphQL** kütüphanesini entegre etmek oldukça kolaydır. + +Aynı uygulama içinde normal FastAPI *path operation*'larını GraphQL ile birlikte kullanabilirsiniz. + +/// tip | İpucu + +**GraphQL** bazı çok özel kullanım senaryolarını çözer. + +Yaygın **web API**'lerle karşılaştırıldığında **avantajları** ve **dezavantajları** vardır. + +Kendi senaryonuz için **faydaların**, **olumsuz yönleri** telafi edip etmediğini mutlaka değerlendirin. 🤓 + +/// + +## GraphQL Kütüphaneleri { #graphql-libraries } + +Aşağıda **ASGI** desteği olan bazı **GraphQL** kütüphaneleri var. Bunları **FastAPI** ile kullanabilirsiniz: + +* Strawberry 🍓 + * FastAPI dokümantasyonu ile +* Ariadne + * FastAPI dokümantasyonu ile +* Tartiflette + * ASGI entegrasyonu sağlamak için Tartiflette ASGI ile +* Graphene + * starlette-graphene3 ile + +## Strawberry ile GraphQL { #graphql-with-strawberry } + +**GraphQL** ile çalışmanız gerekiyorsa ya da bunu istiyorsanız, **Strawberry** önerilen kütüphanedir; çünkü tasarımı **FastAPI**'nin tasarımına en yakındır ve her şey **type annotation**'lar üzerine kuruludur. + +Kullanım senaryonuza göre farklı bir kütüphaneyi tercih edebilirsiniz; ancak bana sorarsanız muhtemelen **Strawberry**'yi denemenizi önerirdim. + +Strawberry'yi FastAPI ile nasıl entegre edebileceğinize dair küçük bir ön izleme: + +{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *} + +Strawberry hakkında daha fazlasını Strawberry dokümantasyonunda öğrenebilirsiniz. + +Ayrıca FastAPI ile Strawberry dokümanlarına da göz atın. + +## Starlette'teki Eski `GraphQLApp` { #older-graphqlapp-from-starlette } + +Starlette'in önceki sürümlerinde Graphene ile entegrasyon için bir `GraphQLApp` sınıfı vardı. + +Bu sınıf Starlette'te kullanımdan kaldırıldı (deprecated). Ancak bunu kullanan bir kodunuz varsa, aynı kullanım senaryosunu kapsayan ve **neredeyse aynı bir interface** sağlayan starlette-graphene3'e kolayca **migrate** edebilirsiniz. + +/// tip | İpucu + +GraphQL'e ihtiyacınız varsa, custom class ve type'lar yerine type annotation'lara dayandığı için yine de Strawberry'yi incelemenizi öneririm. + +/// + +## Daha Fazlasını Öğrenin { #learn-more } + +**GraphQL** hakkında daha fazlasını resmi GraphQL dokümantasyonunda öğrenebilirsiniz. + +Ayrıca yukarıda bahsedilen kütüphanelerin her biri hakkında, kendi bağlantılarından daha fazla bilgi okuyabilirsiniz. diff --git a/docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md new file mode 100644 index 0000000000..275ac5fd17 --- /dev/null +++ b/docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md @@ -0,0 +1,135 @@ +# Pydantic v1'den Pydantic v2'ye Geçiş { #migrate-from-pydantic-v1-to-pydantic-v2 } + +Eski bir FastAPI uygulamanız varsa, Pydantic'in 1. sürümünü kullanıyor olabilirsiniz. + +FastAPI 0.100.0 sürümü, Pydantic v1 veya v2 ile çalışmayı destekliyordu. Hangisi kuruluysa onu kullanıyordu. + +FastAPI 0.119.0 sürümü, v2'ye geçişi kolaylaştırmak için, Pydantic v2’nin içinden Pydantic v1’e (`pydantic.v1` olarak) kısmi destek ekledi. + +FastAPI 0.126.0 sürümü Pydantic v1 desteğini kaldırdı, ancak bir süre daha `pydantic.v1` desteğini sürdürdü. + +/// warning | Uyarı + +Pydantic ekibi, **Python 3.14** ile başlayarak Python'ın en yeni sürümleri için Pydantic v1 desteğini sonlandırdı. + +Buna `pydantic.v1` de dahildir; Python 3.14 ve üzeri sürümlerde artık desteklenmemektedir. + +Python'ın en yeni özelliklerini kullanmak istiyorsanız, Pydantic v2 kullandığınızdan emin olmanız gerekir. + +/// + +Pydantic v1 kullanan eski bir FastAPI uygulamanız varsa, burada onu Pydantic v2'ye nasıl taşıyacağınızı ve kademeli geçişi kolaylaştıran **FastAPI 0.119.0 özelliklerini** göstereceğim. + +## Resmi Kılavuz { #official-guide } + +Pydantic'in v1'den v2'ye resmi bir Migration Guide'ı vardır. + +Ayrıca nelerin değiştiğini, validasyonların artık nasıl daha doğru ve katı olduğunu, olası dikkat edilmesi gereken noktaları (caveat) vb. de içerir. + +Nelerin değiştiğini daha iyi anlamak için okuyabilirsiniz. + +## Testler { #tests } + +Uygulamanız için [testlerinizin](../tutorial/testing.md){.internal-link target=_blank} olduğundan ve bunları continuous integration (CI) üzerinde çalıştırdığınızdan emin olun. + +Bu şekilde yükseltmeyi yapabilir ve her şeyin hâlâ beklendiği gibi çalıştığını doğrulayabilirsiniz. + +## `bump-pydantic` { #bump-pydantic } + +Birçok durumda, özel özelleştirmeler olmadan standart Pydantic modelleri kullanıyorsanız, Pydantic v1'den Pydantic v2'ye geçiş sürecinin büyük kısmını otomatikleştirebilirsiniz. + +Aynı Pydantic ekibinin geliştirdiği `bump-pydantic` aracını kullanabilirsiniz. + +Bu araç, değişmesi gereken kodun büyük bir kısmını otomatik olarak dönüştürmenize yardımcı olur. + +Bundan sonra testleri çalıştırıp her şeyin çalışıp çalışmadığını kontrol edebilirsiniz. Çalışıyorsa işiniz biter. 😎 + +## v2 İçinde Pydantic v1 { #pydantic-v1-in-v2 } + +Pydantic v2, `pydantic.v1` adlı bir alt modül olarak Pydantic v1'in tamamını içerir. Ancak bu yapı, Python 3.13'ün üzerindeki sürümlerde artık desteklenmemektedir. + +Bu da şu anlama gelir: Pydantic v2'nin en güncel sürümünü kurup, bu alt modülden eski Pydantic v1 bileşenlerini import ederek, sanki eski Pydantic v1 kuruluymuş gibi kullanabilirsiniz. + +{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *} + +### v2 İçinde Pydantic v1 için FastAPI Desteği { #fastapi-support-for-pydantic-v1-in-v2 } + +FastAPI 0.119.0'dan itibaren, v2'ye geçişi kolaylaştırmak için Pydantic v2’nin içinden Pydantic v1 kullanımına yönelik kısmi destek de vardır. + +Dolayısıyla Pydantic'i en güncel 2 sürümüne yükseltip import'ları `pydantic.v1` alt modülünü kullanacak şekilde değiştirebilirsiniz; çoğu durumda bu doğrudan çalışır. + +{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *} + +/// warning | Uyarı + +Pydantic ekibi Python 3.14'ten itibaren yeni Python sürümlerinde Pydantic v1'i artık desteklemediği için, `pydantic.v1` kullanımı da Python 3.14 ve üzeri sürümlerde desteklenmez. + +/// + +### Aynı Uygulamada Pydantic v1 ve v2 { #pydantic-v1-and-v2-on-the-same-app } + +Pydantic açısından, alanları (field) Pydantic v1 modelleriyle tanımlanmış bir Pydantic v2 modeli (ya da tersi) kullanmak **desteklenmez**. + +```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 +``` + +...ancak aynı uygulamada Pydantic v1 ve v2 kullanarak **ayrı (separated)** modeller tanımlayabilirsiniz. + +```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 +``` + +Bazı durumlarda, FastAPI uygulamanızda aynı **path operation** içinde hem Pydantic v1 hem de v2 modellerini kullanmak bile mümkündür: + +{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *} + +Yukarıdaki örnekte input modeli bir Pydantic v1 modelidir; output modeli ( `response_model=ItemV2` ile tanımlanan) ise bir Pydantic v2 modelidir. + +### Pydantic v1 Parametreleri { #pydantic-v1-parameters } + +Pydantic v1 modelleriyle `Body`, `Query`, `Form` vb. parametreler için FastAPI'ye özgü bazı araçları kullanmanız gerekiyorsa, Pydantic v2'ye geçişi tamamlayana kadar bunları `fastapi.temp_pydantic_v1_params` içinden import edebilirsiniz: + +{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *} + +### Adım Adım Geçiş { #migrate-in-steps } + +/// tip | İpucu + +Önce `bump-pydantic` ile deneyin; testleriniz geçerse ve bu yol çalışırsa tek komutla işi bitirmiş olursunuz. ✨ + +/// + +`bump-pydantic` sizin senaryonuz için uygun değilse, aynı uygulamada hem Pydantic v1 hem de v2 modellerini birlikte kullanma desteğinden yararlanarak Pydantic v2'ye kademeli şekilde geçebilirsiniz. + +Önce Pydantic'i en güncel 2 sürümüne yükseltip tüm modelleriniz için import'ları `pydantic.v1` kullanacak şekilde değiştirebilirsiniz. + +Ardından modellerinizi Pydantic v1'den v2'ye gruplar hâlinde, adım adım taşımaya başlayabilirsiniz. 🚶 diff --git a/docs/tr/docs/how-to/separate-openapi-schemas.md b/docs/tr/docs/how-to/separate-openapi-schemas.md new file mode 100644 index 0000000000..c26411d292 --- /dev/null +++ b/docs/tr/docs/how-to/separate-openapi-schemas.md @@ -0,0 +1,102 @@ +# Input ve Output için Ayrı OpenAPI Schema'ları (Ya da Değil) { #separate-openapi-schemas-for-input-and-output-or-not } + +**Pydantic v2** yayınlandığından beri, üretilen OpenAPI eskisine göre biraz daha net ve **doğru**. 😎 + +Hatta bazı durumlarda, aynı Pydantic model için OpenAPI içinde input ve output tarafında, **default değerler** olup olmamasına bağlı olarak **iki farklı JSON Schema** bile görebilirsiniz. + +Bunun nasıl çalıştığına ve gerekirse nasıl değiştirebileceğinize bir bakalım. + +## Input ve Output için Pydantic Modelleri { #pydantic-models-for-input-and-output } + +Default değerleri olan bir Pydantic modeliniz olduğunu varsayalım; örneğin şöyle: + +{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *} + +### Input için Model { #model-for-input } + +Bu modeli şöyle input olarak kullanırsanız: + +{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *} + +...`description` alanı **zorunlu olmaz**. Çünkü `None` default değerine sahiptir. + +### Dokümanlarda Input Modeli { #input-model-in-docs } + +Bunu dokümanlarda da doğrulayabilirsiniz; `description` alanında **kırmızı yıldız** yoktur, yani required olarak işaretlenmemiştir: + +
+ +
+ +### Output için Model { #model-for-output } + +Ancak aynı modeli output olarak şöyle kullanırsanız: + +{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *} + +...`description` default değere sahip olduğu için, o alan için **hiçbir şey döndürmeseniz** bile yine de **o default değeri** alır. + +### Output Response Verisi için Model { #model-for-output-response-data } + +Dokümanlarla etkileşip response'u kontrol ederseniz, kod `description` alanlarından birine bir şey eklememiş olsa bile, JSON response default değeri (`null`) içerir: + +
+ +
+ +Bu, alanın **her zaman bir değeri olacağı** anlamına gelir; sadece bazen bu değer `None` olabilir (JSON'da `null`). + +Dolayısıyla API'nizi kullanan client'ların bu değerin var olup olmadığını kontrol etmesine gerek yoktur; **alanın her zaman mevcut olacağını varsayabilirler**, sadece bazı durumlarda default değer olan `None` gelecektir. + +Bunu OpenAPI'de ifade etmenin yolu, bu alanı **required** olarak işaretlemektir; çünkü her zaman yer alacaktır. + +Bu nedenle, bir modelin JSON Schema'sı **input mu output mu** kullanıldığına göre farklı olabilir: + +* **input** için `description` **required olmaz** +* **output** için **required olur** (ve `None` olabilir; JSON açısından `null`) + +### Dokümanlarda Output Modeli { #model-for-output-in-docs } + +Dokümanlarda output modelini de kontrol edebilirsiniz; **hem** `name` **hem de** `description` alanları **kırmızı yıldız** ile **required** olarak işaretlenmiştir: + +
+ +
+ +### Dokümanlarda Input ve Output Modelleri { #model-for-input-and-output-in-docs } + +OpenAPI içindeki tüm kullanılabilir Schema'lara (JSON Schema'lara) bakarsanız, iki tane olduğunu göreceksiniz: biri `Item-Input`, diğeri `Item-Output`. + +`Item-Input` için `description` **required değildir**, kırmızı yıldız yoktur. + +Ama `Item-Output` için `description` **required**'dır, kırmızı yıldız vardır. + +
+ +
+ +**Pydantic v2**'nin bu özelliğiyle API dokümantasyonunuz daha **hassas** olur; ayrıca autogenerated client'lar ve SDK'lar kullanıyorsanız, onlar da daha tutarlı ve daha iyi bir **developer experience** ile daha doğru üretilir. 🎉 + +## Schema'ları Ayırma { #do-not-separate-schemas } + +Bazı durumlarda **input ve output için aynı schema'yı** kullanmak isteyebilirsiniz. + +Bunun muhtemelen en yaygın nedeni, halihazırda autogenerated client kodlarınız/SDK'larınızın olması ve henüz bunların hepsini güncellemek istememenizdir. Büyük ihtimalle bir noktada güncellemek isteyeceksiniz, ama belki şu an değil. + +Bu durumda **FastAPI**'de bu özelliği `separate_input_output_schemas=False` parametresiyle kapatabilirsiniz. + +/// info | Bilgi + +`separate_input_output_schemas` desteği FastAPI `0.102.0` sürümünde eklendi. 🤓 + +/// + +{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *} + +### Dokümanlarda Input ve Output Modelleri için Aynı Schema { #same-schema-for-input-and-output-models-in-docs } + +Artık model için input ve output tarafında tek bir schema olur: sadece `Item`. Ayrıca `description` alanı **required değildir**: + +
+ +
diff --git a/docs/tr/docs/how-to/testing-database.md b/docs/tr/docs/how-to/testing-database.md new file mode 100644 index 0000000000..a2062f6c26 --- /dev/null +++ b/docs/tr/docs/how-to/testing-database.md @@ -0,0 +1,7 @@ +# Bir Veritabanını Test Etmek { #testing-a-database } + +Veritabanları, SQL ve SQLModel hakkında SQLModel dokümantasyonundan öğrenebilirsiniz. 🤓 + +Ayrıca SQLModel'i FastAPI ile kullanmaya dair mini bir tutorial da var. ✨ + +Bu tutorial içinde SQL veritabanlarını test etme hakkında bir bölüm de bulunuyor. 😎 diff --git a/docs/tr/docs/tutorial/background-tasks.md b/docs/tr/docs/tutorial/background-tasks.md new file mode 100644 index 0000000000..4cb67d8224 --- /dev/null +++ b/docs/tr/docs/tutorial/background-tasks.md @@ -0,0 +1,84 @@ +# Arka Plan Görevleri { #background-tasks } + +Response döndürüldükten *sonra* çalıştırılacak arka plan görevleri tanımlayabilirsiniz. + +Bu, request’ten sonra yapılması gereken; ancak client’ın response’u almadan önce tamamlanmasını beklemesine gerek olmayan işlemler için kullanışlıdır. + +Örneğin: + +* Bir işlem gerçekleştirdikten sonra gönderilen email bildirimleri: + * Bir email server’a bağlanmak ve email göndermek genellikle "yavaş" olduğundan (birkaç saniye), response’u hemen döndürüp email bildirimini arka planda gönderebilirsiniz. +* Veri işleme: + * Örneğin, yavaş bir süreçten geçmesi gereken bir dosya aldığınızı düşünün; "Accepted" (HTTP 202) response’u döndürüp dosyayı arka planda işleyebilirsiniz. + +## `BackgroundTasks` Kullanımı { #using-backgroundtasks } + +Önce `BackgroundTasks`’i import edin ve *path operation function*’ınızda `BackgroundTasks` tip bildirimi olan bir parametre tanımlayın: + +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} + +**FastAPI**, sizin için `BackgroundTasks` tipinde bir obje oluşturur ve onu ilgili parametre olarak geçirir. + +## Bir Görev Fonksiyonu Oluşturun { #create-a-task-function } + +Arka plan görevi olarak çalıştırılacak bir fonksiyon oluşturun. + +Bu, parametre alabilen standart bir fonksiyondur. + +`async def` de olabilir, normal `def` de olabilir; **FastAPI** bunu doğru şekilde nasıl ele alacağını bilir. + +Bu örnekte görev fonksiyonu bir dosyaya yazacaktır (email göndermeyi simüle ediyor). + +Ve yazma işlemi `async` ve `await` kullanmadığı için fonksiyonu normal `def` ile tanımlarız: + +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} + +## Arka Plan Görevini Ekleyin { #add-the-background-task } + +*Path operation function*’ınızın içinde, görev fonksiyonunuzu `.add_task()` metodu ile *background tasks* objesine ekleyin: + +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} + +`.add_task()` şu argümanları alır: + +* Arka planda çalıştırılacak bir görev fonksiyonu (`write_notification`). +* Görev fonksiyonuna sırayla geçirilecek argümanlar (`email`). +* Görev fonksiyonuna geçirilecek keyword argümanlar (`message="some notification"`). + +## Dependency Injection { #dependency-injection } + +`BackgroundTasks` kullanımı dependency injection sistemiyle de çalışır; `BackgroundTasks` tipinde bir parametreyi birden fazla seviyede tanımlayabilirsiniz: bir *path operation function* içinde, bir dependency’de (dependable), bir sub-dependency’de, vb. + +**FastAPI** her durumda ne yapılacağını ve aynı objenin nasıl yeniden kullanılacağını bilir; böylece tüm arka plan görevleri birleştirilir ve sonrasında arka planda çalıştırılır: + +{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *} + +Bu örnekte, response gönderildikten *sonra* mesajlar `log.txt` dosyasına yazılacaktır. + +Request’te bir query varsa, log’a bir arka plan göreviyle yazılır. + +Ardından *path operation function* içinde oluşturulan başka bir arka plan görevi, `email` path parametresini kullanarak bir mesaj yazar. + +## Teknik Detaylar { #technical-details } + +`BackgroundTasks` sınıfı doğrudan `starlette.background`’dan gelir. + +`fastapi` üzerinden import edebilmeniz ve yanlışlıkla `starlette.background` içindeki alternatif `BackgroundTask`’i (sonunda `s` olmadan) import etmemeniz için FastAPI’nin içine doğrudan import/eklenmiştir. + +Sadece `BackgroundTasks` (ve `BackgroundTask` değil) kullanarak, bunu bir *path operation function* parametresi olarak kullanmak ve gerisini **FastAPI**’nin sizin için halletmesini sağlamak mümkündür; tıpkı `Request` objesini doğrudan kullanırken olduğu gibi. + +FastAPI’de `BackgroundTask`’i tek başına kullanmak hâlâ mümkündür; ancak bu durumda objeyi kendi kodunuzda oluşturmanız ve onu içeren bir Starlette `Response` döndürmeniz gerekir. + +Daha fazla detayı Starlette’in Background Tasks için resmi dokümantasyonunda görebilirsiniz. + +## Dikkat Edilmesi Gerekenler { #caveat } + +Yoğun arka plan hesaplamaları yapmanız gerekiyorsa ve bunun aynı process tarafından çalıştırılmasına şart yoksa (örneğin memory, değişkenler vb. paylaşmanız gerekmiyorsa), Celery gibi daha büyük araçları kullanmak size fayda sağlayabilir. + +Bunlar genellikle daha karmaşık konfigurasyonlar ve RabbitMQ veya Redis gibi bir mesaj/iş kuyruğu yöneticisi gerektirir; ancak arka plan görevlerini birden fazla process’te ve özellikle birden fazla server’da çalıştırmanıza olanak tanırlar. + +Ancak aynı **FastAPI** app’i içindeki değişkenlere ve objelere erişmeniz gerekiyorsa veya küçük arka plan görevleri (email bildirimi göndermek gibi) yapacaksanız, doğrudan `BackgroundTasks` kullanabilirsiniz. + +## Özet { #recap } + +Arka plan görevleri eklemek için *path operation function*’larda ve dependency’lerde parametre olarak `BackgroundTasks`’i import edip kullanın. diff --git a/docs/tr/docs/tutorial/bigger-applications.md b/docs/tr/docs/tutorial/bigger-applications.md new file mode 100644 index 0000000000..d8a4b8208b --- /dev/null +++ b/docs/tr/docs/tutorial/bigger-applications.md @@ -0,0 +1,504 @@ +# Daha Büyük Uygulamalar - Birden Fazla Dosya { #bigger-applications-multiple-files } + +Bir uygulama veya web API geliştirirken, her şeyi tek bir dosyaya sığdırabilmek nadirdir. + +**FastAPI**, tüm esnekliği korurken uygulamanızı yapılandırmanıza yardımcı olan pratik bir araç sunar. + +/// info | Bilgi + +Flask'ten geliyorsanız, bu yapı Flask'in Blueprints'ine denk gelir. + +/// + +## Örnek Bir Dosya Yapısı { #an-example-file-structure } + +Diyelim ki şöyle bir dosya yapınız var: + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   ├── dependencies.py +│   └── routers +│   │ ├── __init__.py +│   │ ├── items.py +│   │ └── users.py +│   └── internal +│   ├── __init__.py +│   └── admin.py +``` + +/// tip | İpucu + +Birden fazla `__init__.py` dosyası var: her dizinde veya alt dizinde bir tane. + +Bu sayede bir dosyadaki kodu diğerine import edebilirsiniz. + +Örneğin `app/main.py` içinde şöyle bir satırınız olabilir: + +``` +from app.routers import items +``` + +/// + +* `app` dizini her şeyi içerir. Ayrıca boş bir `app/__init__.py` dosyası olduğu için bir "Python package" (bir "Python module" koleksiyonu) olur: `app`. +* İçinde bir `app/main.py` dosyası vardır. Bir Python package'in (içinde `__init__.py` dosyası olan bir dizinin) içinde olduğundan, o package'in bir "module"’üdür: `app.main`. +* Benzer şekilde `app/dependencies.py` dosyası da bir "module"’dür: `app.dependencies`. +* `app/routers/` adında bir alt dizin vardır ve içinde başka bir `__init__.py` dosyası bulunur; dolayısıyla bu bir "Python subpackage"’dir: `app.routers`. +* `app/routers/items.py` dosyası `app/routers/` package’i içinde olduğundan bir submodule’dür: `app.routers.items`. +* `app/routers/users.py` için de aynı şekilde, başka bir submodule’dür: `app.routers.users`. +* `app/internal/` adında bir alt dizin daha vardır ve içinde başka bir `__init__.py` dosyası bulunur; dolayısıyla bu da bir "Python subpackage"’dir: `app.internal`. +* Ve `app/internal/admin.py` dosyası başka bir submodule’dür: `app.internal.admin`. + + + +Aynı dosya yapısı, yorumlarla birlikte: + +```bash +. +├── app # "app" bir Python package'idir +│   ├── __init__.py # bu dosya, "app"i bir "Python package" yapar +│   ├── main.py # "main" module'ü, örn. import app.main +│   ├── dependencies.py # "dependencies" module'ü, örn. import app.dependencies +│   └── routers # "routers" bir "Python subpackage"idir +│   │ ├── __init__.py # "routers"ı bir "Python subpackage" yapar +│   │ ├── items.py # "items" submodule'ü, örn. import app.routers.items +│   │ └── users.py # "users" submodule'ü, örn. import app.routers.users +│   └── internal # "internal" bir "Python subpackage"idir +│   ├── __init__.py # "internal"ı bir "Python subpackage" yapar +│   └── admin.py # "admin" submodule'ü, örn. import app.internal.admin +``` + +## `APIRouter` { #apirouter } + +Diyelim ki sadece kullanıcıları yönetmeye ayrılmış dosyanız `/app/routers/users.py` içindeki submodule olsun. + +Kullanıcılarla ilgili *path operation*’ları, kodun geri kalanından ayrı tutmak istiyorsunuz; böylece düzenli kalır. + +Ancak bu hâlâ aynı **FastAPI** uygulaması/web API’sinin bir parçasıdır (aynı "Python Package" içinde). + +Bu module için *path operation*’ları `APIRouter` kullanarak oluşturabilirsiniz. + +### `APIRouter` Import Edin { #import-apirouter } + +`FastAPI` class’ında yaptığınız gibi import edip bir "instance" oluşturursunuz: + +{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[1,3] title["app/routers/users.py"] *} + +### `APIRouter` ile *Path Operations* { #path-operations-with-apirouter } + +Sonra bunu kullanarak *path operation*’larınızı tanımlarsınız. + +`FastAPI` class’ını nasıl kullanıyorsanız aynı şekilde kullanın: + +{* ../../docs_src/bigger_applications/app_an_py39/routers/users.py hl[6,11,16] title["app/routers/users.py"] *} + +`APIRouter`’ı "mini bir `FastAPI`" class’ı gibi düşünebilirsiniz. + +Aynı seçeneklerin hepsi desteklenir. + +Aynı `parameters`, `responses`, `dependencies`, `tags`, vb. + +/// tip | İpucu + +Bu örnekte değişkenin adı `router`. Ancak istediğiniz gibi adlandırabilirsiniz. + +/// + +Bu `APIRouter`’ı ana `FastAPI` uygulamasına ekleyeceğiz; ama önce dependency’lere ve bir diğer `APIRouter`’a bakalım. + +## Dependencies { #dependencies } + +Uygulamanın birden fazla yerinde kullanılacak bazı dependency’lere ihtiyacımız olacağını görüyoruz. + +Bu yüzden onları ayrı bir `dependencies` module’üne koyuyoruz (`app/dependencies.py`). + +Şimdi, özel bir `X-Token` header'ını okumak için basit bir dependency kullanalım: + +{* ../../docs_src/bigger_applications/app_an_py39/dependencies.py hl[3,6:8] title["app/dependencies.py"] *} + +/// tip | İpucu + +Örneği basit tutmak için uydurma bir header kullanıyoruz. + +Ancak gerçek senaryolarda, entegre [Security yardımcı araçlarını](security/index.md){.internal-link target=_blank} kullanarak daha iyi sonuç alırsınız. + +/// + +## `APIRouter` ile Başka Bir Module { #another-module-with-apirouter } + +Diyelim ki uygulamanızdaki "items" ile ilgili endpoint'ler de `app/routers/items.py` module’ünde olsun. + +Şunlar için *path operation*’larınız var: + +* `/items/` +* `/items/{item_id}` + +Bu, `app/routers/users.py` ile aynı yapıdadır. + +Ancak biraz daha akıllı davranıp kodu sadeleştirmek istiyoruz. + +Bu module’deki tüm *path operation*’ların şu ortak özelliklere sahip olduğunu biliyoruz: + +* Path `prefix`: `/items`. +* `tags`: (tek bir tag: `items`). +* Ek `responses`. +* `dependencies`: hepsinin, oluşturduğumuz `X-Token` dependency’sine ihtiyacı var. + +Dolayısıyla bunları her *path operation*’a tek tek eklemek yerine `APIRouter`’a ekleyebiliriz. + +{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[5:10,16,21] title["app/routers/items.py"] *} + +Her *path operation*’ın path’i aşağıdaki gibi `/` ile başlamak zorunda olduğundan: + +```Python hl_lines="1" +@router.get("/{item_id}") +async def read_item(item_id: str): + ... +``` + +...prefix’in sonunda `/` olmamalıdır. + +Yani bu örnekte prefix `/items` olur. + +Ayrıca, bu router içindeki tüm *path operation*’lara uygulanacak bir `tags` listesi ve ek `responses` da ekleyebiliriz. + +Ve router’daki tüm *path operation*’lara eklenecek, her request için çalıştırılıp çözülecek bir `dependencies` listesi de ekleyebiliriz. + +/// tip | İpucu + +[ *path operation decorator*’larındaki dependency’lerde](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank} olduğu gibi, *path operation function*’ınıza herhangi bir değer aktarılmayacağını unutmayın. + +/// + +Sonuç olarak item path’leri artık: + +* `/items/` +* `/items/{item_id}` + +...tam da istediğimiz gibi olur. + +* Hepsi, içinde tek bir string `"items"` bulunan bir tag listesiyle işaretlenir. + * Bu "tags", özellikle otomatik interaktif dokümantasyon sistemleri (OpenAPI) için çok faydalıdır. +* Hepsi önceden tanımlı `responses`’ları içerir. +* Bu *path operation*’ların hepsinde, öncesinde `dependencies` listesi değerlendirilip çalıştırılır. + * Ayrıca belirli bir *path operation* içinde dependency tanımlarsanız, **onlar da çalıştırılır**. + * Önce router dependency’leri, sonra decorator’daki [`dependencies`](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, sonra da normal parametre dependency’leri çalışır. + * Ayrıca [`scopes` ile `Security` dependency’leri](../advanced/security/oauth2-scopes.md){.internal-link target=_blank} de ekleyebilirsiniz. + +/// tip | İpucu + +`APIRouter` içinde `dependencies` kullanmak, örneğin bir grup *path operation* için kimlik doğrulamayı zorunlu kılmakta kullanılabilir. Dependency’leri tek tek her birine eklemeseniz bile. + +/// + +/// check | Ek bilgi + +`prefix`, `tags`, `responses` ve `dependencies` parametreleri (çoğu başka örnekte olduğu gibi) kod tekrarını önlemenize yardımcı olan, **FastAPI**’nin bir özelliğidir. + +/// + +### Dependency'leri Import Edin { #import-the-dependencies } + +Bu kod `app.routers.items` module’ünde, yani `app/routers/items.py` dosyasında duruyor. + +Dependency function’ını ise `app.dependencies` module’ünden, yani `app/dependencies.py` dosyasından almamız gerekiyor. + +Bu yüzden dependency’ler için `..` ile relative import kullanıyoruz: + +{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[3] title["app/routers/items.py"] *} + +#### Relative Import Nasıl Çalışır { #how-relative-imports-work } + +/// tip | İpucu + +Import’ların nasıl çalıştığını çok iyi biliyorsanız, bir sonraki bölüme geçin. + +/// + +Tek bir nokta `.`, örneğin: + +```Python +from .dependencies import get_token_header +``` + +şu anlama gelir: + +* Bu module’ün (yani `app/routers/items.py` dosyasının) bulunduğu package içinden başla ( `app/routers/` dizini)... +* `dependencies` module’ünü bul (`app/routers/dependencies.py` gibi hayali bir dosya)... +* ve oradan `get_token_header` function’ını import et. + +Ama o dosya yok; bizim dependency’lerimiz `app/dependencies.py` dosyasında. + +Uygulama/dosya yapımızın nasıl göründüğünü hatırlayın: + + + +--- + +İki nokta `..`, örneğin: + +```Python +from ..dependencies import get_token_header +``` + +şu anlama gelir: + +* Bu module’ün bulunduğu package içinden başla (`app/routers/` dizini)... +* üst (parent) package’e çık (`app/` dizini)... +* burada `dependencies` module’ünü bul (`app/dependencies.py` dosyası)... +* ve oradan `get_token_header` function’ını import et. + +Bu doğru şekilde çalışır! 🎉 + +--- + +Aynı şekilde, üç nokta `...` kullansaydık: + +```Python +from ...dependencies import get_token_header +``` + +şu anlama gelirdi: + +* Bu module’ün bulunduğu package içinden başla (`app/routers/` dizini)... +* üst package’e çık (`app/` dizini)... +* sonra bir üstüne daha çık (orada bir üst package yok; `app` en üst seviye 😱)... +* ve orada `dependencies` module’ünü bul (`app/dependencies.py` dosyası)... +* ve oradan `get_token_header` function’ını import et. + +Bu, `app/` dizininin üstünde, kendi `__init__.py` dosyası olan başka bir package’e işaret ederdi. Ama bizde böyle bir şey yok. Dolayısıyla bu örnekte hata verirdi. 🚨 + +Artık nasıl çalıştığını bildiğinize göre, uygulamalarınız ne kadar karmaşık olursa olsun relative import’ları kullanabilirsiniz. 🤓 + +### Özel `tags`, `responses` ve `dependencies` Ekleyin { #add-some-custom-tags-responses-and-dependencies } + +`/items` prefix’ini ya da `tags=["items"]` değerini her *path operation*’a tek tek eklemiyoruz; çünkü bunları `APIRouter`’a ekledik. + +Ama yine de belirli bir *path operation*’a uygulanacak _ek_ `tags` tanımlayabilir, ayrıca o *path operation*’a özel `responses` ekleyebiliriz: + +{* ../../docs_src/bigger_applications/app_an_py39/routers/items.py hl[30:31] title["app/routers/items.py"] *} + +/// tip | İpucu + +Bu son *path operation*’da tag kombinasyonu şöyle olur: `["items", "custom"]`. + +Ayrıca dokümantasyonda iki response da görünür: biri `404`, diğeri `403`. + +/// + +## Ana `FastAPI` { #the-main-fastapi } + +Şimdi `app/main.py` module’üne bakalım. + +Burada `FastAPI` class’ını import edip kullanırsınız. + +Bu dosya, uygulamanızda her şeyi bir araya getiren ana dosya olacak. + +Mantığın büyük kısmı artık kendi module’lerinde yaşayacağı için ana dosya oldukça basit kalır. + +### `FastAPI` Import Edin { #import-fastapi } + +Normal şekilde bir `FastAPI` class’ı oluşturursunuz. + +Hatta her `APIRouter` için olan dependency’lerle birleştirilecek [global dependencies](dependencies/global-dependencies.md){.internal-link target=_blank} bile tanımlayabilirsiniz: + +{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[1,3,7] title["app/main.py"] *} + +### `APIRouter` Import Edin { #import-the-apirouter } + +Şimdi `APIRouter` içeren diğer submodule’leri import ediyoruz: + +{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[4:5] title["app/main.py"] *} + +`app/routers/users.py` ve `app/routers/items.py` dosyaları aynı Python package’i olan `app`’in parçası olan submodule’ler olduğu için, onları "relative import" ile tek bir nokta `.` kullanarak import edebiliriz. + +### Import Nasıl Çalışır { #how-the-importing-works } + +Şu bölüm: + +```Python +from .routers import items, users +``` + +şu anlama gelir: + +* Bu module’ün (yani `app/main.py` dosyasının) bulunduğu package içinden başla (`app/` dizini)... +* `routers` subpackage’ini bul (`app/routers/` dizini)... +* ve buradan `items` submodule’ünü (`app/routers/items.py`) ve `users` submodule’ünü (`app/routers/users.py`) import et... + +`items` module’ünün içinde `router` adında bir değişken vardır (`items.router`). Bu, `app/routers/items.py` dosyasında oluşturduğumuz aynı değişkendir; bir `APIRouter` nesnesidir. + +Sonra aynı işlemi `users` module’ü için de yaparız. + +Ayrıca şöyle de import edebilirdik: + +```Python +from app.routers import items, users +``` + +/// info | Bilgi + +İlk sürüm "relative import"tur: + +```Python +from .routers import items, users +``` + +İkinci sürüm "absolute import"tur: + +```Python +from app.routers import items, users +``` + +Python Packages ve Modules hakkında daha fazlası için, Python'ın Modules ile ilgili resmi dokümantasyonunu okuyun. + +/// + +### İsim Çakışmalarını Önleyin { #avoid-name-collisions } + +`items` submodule’ünü doğrudan import ediyoruz; sadece içindeki `router` değişkenini import etmiyoruz. + +Çünkü `users` submodule’ünde de `router` adlı başka bir değişken var. + +Eğer şöyle sırayla import etseydik: + +```Python +from .routers.items import router +from .routers.users import router +``` + +`users` içindeki `router`, `items` içindeki `router`’ın üstüne yazardı ve ikisini aynı anda kullanamazdık. + +Bu yüzden ikisini de aynı dosyada kullanabilmek için submodule’leri doğrudan import ediyoruz: + +{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[5] title["app/main.py"] *} + +### `users` ve `items` için `APIRouter`’ları Dahil Edin { #include-the-apirouters-for-users-and-items } + +Şimdi `users` ve `items` submodule’lerindeki `router`’ları dahil edelim: + +{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[10:11] title["app/main.py"] *} + +/// info | Bilgi + +`users.router`, `app/routers/users.py` dosyasının içindeki `APIRouter`’ı içerir. + +`items.router` ise `app/routers/items.py` dosyasının içindeki `APIRouter`’ı içerir. + +/// + +`app.include_router()` ile her bir `APIRouter`’ı ana `FastAPI` uygulamasına ekleyebiliriz. + +Böylece o router içindeki tüm route’lar uygulamanın bir parçası olarak dahil edilir. + +/// note | Teknik Detaylar + +Aslında içeride, `APIRouter` içinde tanımlanan her *path operation* için bir *path operation* oluşturur. + +Yani perde arkasında, her şey tek bir uygulamaymış gibi çalışır. + +/// + +/// check | Ek bilgi + +Router’ları dahil ederken performans konusunda endişelenmeniz gerekmez. + +Bu işlem mikrosaniyeler sürer ve sadece startup sırasında olur. + +Dolayısıyla performansı etkilemez. ⚡ + +/// + +### Özel `prefix`, `tags`, `responses` ve `dependencies` ile Bir `APIRouter` Dahil Edin { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies } + +Şimdi, kurumunuzun size `app/internal/admin.py` dosyasını verdiğini düşünelim. + +Bu dosyada, kurumunuzun birden fazla proje arasında paylaştığı bazı admin *path operation*’larını içeren bir `APIRouter` var. + +Bu örnekte çok basit olacak. Ancak kurum içinde başka projelerle paylaşıldığı için, bunu değiştirip `prefix`, `dependencies`, `tags` vs. doğrudan `APIRouter`’a ekleyemediğimizi varsayalım: + +{* ../../docs_src/bigger_applications/app_an_py39/internal/admin.py hl[3] title["app/internal/admin.py"] *} + +Yine de bu `APIRouter`’ı dahil ederken özel bir `prefix` ayarlamak istiyoruz ki tüm *path operation*’ları `/admin` ile başlasın; ayrıca bu projede hâlihazırda kullandığımız `dependencies` ile güvene almak, `tags` ve `responses` eklemek istiyoruz. + +Orijinal `APIRouter`’ı değiştirmeden, bu parametreleri `app.include_router()`’a vererek hepsini tanımlayabiliriz: + +{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[14:17] title["app/main.py"] *} + +Böylece orijinal `APIRouter` değişmeden kalır; yani aynı `app/internal/admin.py` dosyasını kurum içindeki diğer projelerle de paylaşmaya devam edebiliriz. + +Sonuç olarak, uygulamamızda `admin` module’ündeki her bir *path operation* şunlara sahip olur: + +* `/admin` prefix’i. +* `admin` tag’i. +* `get_token_header` dependency’si. +* `418` response’u. 🍵 + +Ancak bu sadece bizim uygulamamızdaki o `APIRouter` için geçerlidir; onu kullanan diğer kodlar için değil. + +Dolayısıyla örneğin diğer projeler aynı `APIRouter`’ı farklı bir authentication yöntemiyle kullanabilir. + +### Bir *Path Operation* Dahil Edin { #include-a-path-operation } + +*Path operation*’ları doğrudan `FastAPI` uygulamasına da ekleyebiliriz. + +Burada bunu yapıyoruz... sadece yapabildiğimizi göstermek için 🤷: + +{* ../../docs_src/bigger_applications/app_an_py39/main.py hl[21:23] title["app/main.py"] *} + +ve `app.include_router()` ile eklenen diğer tüm *path operation*’larla birlikte doğru şekilde çalışır. + +/// info | Çok Teknik Detaylar + +**Not**: Bu oldukça teknik bir detay; büyük ihtimalle **direkt geçebilirsiniz**. + +--- + +`APIRouter`’lar "mount" edilmez; uygulamanın geri kalanından izole değildir. + +Çünkü *path operation*’larını OpenAPI şemasına ve kullanıcı arayüzlerine dahil etmek istiyoruz. + +Onları tamamen izole edip bağımsız şekilde "mount" edemediğimiz için, *path operation*’lar doğrudan eklenmek yerine "klonlanır" (yeniden oluşturulur). + +/// + +## Otomatik API Dokümanını Kontrol Edin { #check-the-automatic-api-docs } + +Şimdi uygulamanızı çalıştırın: + +
+ +```console +$ fastapi dev app/main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Ve dokümanları http://127.0.0.1:8000/docs adresinde açın. + +Tüm submodule’lerdeki path’leri, doğru path’ler (ve prefix’ler) ve doğru tag’lerle birlikte içeren otomatik API dokümanını göreceksiniz: + + + +## Aynı Router'ı Farklı `prefix` ile Birden Fazla Kez Dahil Edin { #include-the-same-router-multiple-times-with-different-prefix } + +`.include_router()` ile aynı router’ı farklı prefix’ler kullanarak birden fazla kez de dahil edebilirsiniz. + +Örneğin aynı API’yi `/api/v1` ve `/api/latest` gibi farklı prefix’ler altında sunmak için faydalı olabilir. + +Bu, muhtemelen ihtiyacınız olmayan ileri seviye bir kullanımdır; ancak gerekirse diye mevcut. + +## Bir `APIRouter`’ı Başka Birine Dahil Edin { #include-an-apirouter-in-another } + +Bir `APIRouter`’ı `FastAPI` uygulamasına dahil ettiğiniz gibi, bir `APIRouter`’ı başka bir `APIRouter`’a da şu şekilde dahil edebilirsiniz: + +```Python +router.include_router(other_router) +``` + +`router`’ı `FastAPI` uygulamasına dahil etmeden önce bunu yaptığınızdan emin olun; böylece `other_router` içindeki *path operation*’lar da dahil edilmiş olur. diff --git a/docs/tr/docs/tutorial/body-fields.md b/docs/tr/docs/tutorial/body-fields.md new file mode 100644 index 0000000000..6a0f3314a1 --- /dev/null +++ b/docs/tr/docs/tutorial/body-fields.md @@ -0,0 +1,60 @@ +# Body - Alanlar { #body-fields } + +`Query`, `Path` ve `Body` ile *path operation function* parametrelerinde ek doğrulama ve metadata tanımlayabildiğiniz gibi, Pydantic modellerinin içinde de Pydantic'in `Field`'ını kullanarak doğrulama ve metadata tanımlayabilirsiniz. + +## `Field`'ı import edin { #import-field } + +Önce import etmeniz gerekir: + +{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *} + +/// warning | Uyarı + +`Field`'ın, diğerlerinin (`Query`, `Path`, `Body` vb.) aksine `fastapi`'den değil doğrudan `pydantic`'den import edildiğine dikkat edin. + +/// + +## Model attribute'larını tanımlayın { #declare-model-attributes } + +Ardından `Field`'ı model attribute'larıyla birlikte kullanabilirsiniz: + +{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *} + +`Field`, `Query`, `Path` ve `Body` ile aynı şekilde çalışır; aynı parametrelerin tamamına sahiptir, vb. + +/// note | Teknik Detaylar + +Aslında, `Query`, `Path` ve birazdan göreceğiniz diğerleri, ortak bir `Param` sınıfının alt sınıflarından nesneler oluşturur; `Param` sınıfı da Pydantic'in `FieldInfo` sınıfının bir alt sınıfıdır. + +Pydantic'in `Field`'ı da `FieldInfo`'nun bir instance'ını döndürür. + +`Body` ayrıca doğrudan `FieldInfo`'nun bir alt sınıfından nesneler döndürür. Daha sonra göreceğiniz başka bazıları da `Body` sınıfının alt sınıflarıdır. + +`fastapi`'den `Query`, `Path` ve diğerlerini import ettiğinizde, bunların aslında özel sınıflar döndüren fonksiyonlar olduğunu unutmayın. + +/// + +/// tip | İpucu + +Type, varsayılan değer ve `Field` ile tanımlanan her model attribute'unun yapısının, *path operation function* parametresiyle aynı olduğuna dikkat edin; sadece `Path`, `Query` ve `Body` yerine `Field` kullanılmıştır. + +/// + +## Ek bilgi ekleyin { #add-extra-information } + +`Field`, `Query`, `Body` vb. içinde ek bilgi tanımlayabilirsiniz. Bu bilgiler oluşturulan JSON Schema'ya dahil edilir. + +Örnek (examples) tanımlamayı öğrenirken, dokümanların ilerleyen kısımlarında ek bilgi ekleme konusunu daha ayrıntılı göreceksiniz. + +/// warning | Uyarı + +`Field`'a geçirilen ekstra key'ler, uygulamanız için üretilen OpenAPI schema'sında da yer alır. +Bu key'ler OpenAPI spesifikasyonunun bir parçası olmak zorunda olmadığından, örneğin [OpenAPI validator](https://validator.swagger.io/) gibi bazı OpenAPI araçları üretilen schema'nızla çalışmayabilir. + +/// + +## Özet { #recap } + +Model attribute'ları için ek doğrulamalar ve metadata tanımlamak üzere Pydantic'in `Field`'ını kullanabilirsiniz. + +Ayrıca, ek keyword argument'ları kullanarak JSON Schema'ya ekstra metadata da iletebilirsiniz. diff --git a/docs/tr/docs/tutorial/body-multiple-params.md b/docs/tr/docs/tutorial/body-multiple-params.md new file mode 100644 index 0000000000..3bac80d6a8 --- /dev/null +++ b/docs/tr/docs/tutorial/body-multiple-params.md @@ -0,0 +1,175 @@ +# Body - Birden Fazla Parametre { #body-multiple-parameters } + +Artık `Path` ve `Query` kullanmayı gördüğümüze göre, request body bildirimlerinin daha ileri kullanım senaryolarına bakalım. + +## `Path`, `Query` ve body parametrelerini karıştırma { #mix-path-query-and-body-parameters } + +Öncelikle, elbette `Path`, `Query` ve request body parametre bildirimlerini serbestçe karıştırabilirsiniz ve **FastAPI** ne yapacağını bilir. + +Ayrıca, varsayılan değeri `None` yaparak body parametrelerini opsiyonel olarak da tanımlayabilirsiniz: + +{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *} + +/// note | Not + +Bu durumda body'den alınacak `item` opsiyoneldir. Çünkü varsayılan değeri `None` olarak ayarlanmıştır. + +/// + +## Birden fazla body parametresi { #multiple-body-parameters } + +Önceki örnekte, *path operation*'lar `Item`'ın özelliklerini içeren bir JSON body beklerdi, örneğin: + +```JSON +{ + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 +} +``` + +Ancak birden fazla body parametresi de tanımlayabilirsiniz; örneğin `item` ve `user`: + +{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *} + + +Bu durumda **FastAPI**, fonksiyonda birden fazla body parametresi olduğunu fark eder (iki parametre de Pydantic modelidir). + +Bunun üzerine, body içinde anahtar (field name) olarak parametre adlarını kullanır ve şu şekilde bir body bekler: + +```JSON +{ + "item": { + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 + }, + "user": { + "username": "dave", + "full_name": "Dave Grohl" + } +} +``` + +/// note | Not + +`item` daha öncekiyle aynı şekilde tanımlanmış olsa bile, artık body içinde `item` anahtarı altında gelmesi beklenir. + +/// + +**FastAPI**, request'ten otomatik dönüşümü yapar; böylece `item` parametresi kendi içeriğini alır, `user` için de aynı şekilde olur. + +Birleşik verinin validasyonunu yapar ve OpenAPI şeması ile otomatik dokümantasyonda da bunu bu şekilde dokümante eder. + +## Body içinde tekil değerler { #singular-values-in-body } + +Query ve path parametreleri için ek veri tanımlamak üzere `Query` ve `Path` olduğu gibi, **FastAPI** bunların karşılığı olarak `Body` de sağlar. + +Örneğin, önceki modeli genişleterek, aynı body içinde `item` ve `user` dışında bir de `importance` anahtarı olmasını isteyebilirsiniz. + +Bunu olduğu gibi tanımlarsanız, tekil bir değer olduğu için **FastAPI** bunun bir query parametresi olduğunu varsayar. + +Ama `Body` kullanarak, **FastAPI**'ye bunu body içinde başka bir anahtar olarak ele almasını söyleyebilirsiniz: + +{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *} + + +Bu durumda **FastAPI** şu şekilde bir body bekler: + +```JSON +{ + "item": { + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 + }, + "user": { + "username": "dave", + "full_name": "Dave Grohl" + }, + "importance": 5 +} +``` + +Yine veri tiplerini dönüştürür, validate eder, dokümante eder, vb. + +## Birden fazla body parametresi ve query { #multiple-body-params-and-query } + +Elbette ihtiyaç duyduğunuzda, body parametrelerine ek olarak query parametreleri de tanımlayabilirsiniz. + +Varsayılan olarak tekil değerler query parametresi olarak yorumlandığı için, ayrıca `Query` eklemeniz gerekmez; şöyle yazmanız yeterlidir: + +```Python +q: Union[str, None] = None +``` + +Ya da Python 3.10 ve üzeri için: + +```Python +q: str | None = None +``` + +Örneğin: + +{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *} + + +/// info | Bilgi + +`Body`, `Query`, `Path` ve daha sonra göreceğiniz diğerleriyle aynı ek validasyon ve metadata parametrelerine de sahiptir. + +/// + +## Tek bir body parametresini gömme { #embed-a-single-body-parameter } + +Diyelim ki Pydantic'teki `Item` modelinden gelen yalnızca tek bir `item` body parametreniz var. + +Varsayılan olarak **FastAPI**, body'nin doğrudan bu modelin içeriği olmasını bekler. + +Ancak, ek body parametreleri tanımladığınızda olduğu gibi, `item` anahtarı olan bir JSON ve onun içinde modelin içeriğini beklemesini istiyorsanız, `Body`'nin özel parametresi olan `embed`'i kullanabilirsiniz: + +```Python +item: Item = Body(embed=True) +``` + +yani şöyle: + +{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *} + + +Bu durumda **FastAPI** şu şekilde bir body bekler: + +```JSON hl_lines="2" +{ + "item": { + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 + } +} +``` + +şunun yerine: + +```JSON +{ + "name": "Foo", + "description": "The pretender", + "price": 42.0, + "tax": 3.2 +} +``` + +## Özet { #recap } + +Bir request yalnızca tek bir body içerebilse de, *path operation function*'ınıza birden fazla body parametresi ekleyebilirsiniz. + +Ancak **FastAPI** bunu yönetir; fonksiyonunuza doğru veriyi verir ve *path operation* içinde doğru şemayı validate edip dokümante eder. + +Ayrıca tekil değerlerin body'nin bir parçası olarak alınmasını da tanımlayabilirsiniz. + +Ve yalnızca tek bir parametre tanımlanmış olsa bile, **FastAPI**'ye body'yi bir anahtarın içine gömmesini söyleyebilirsiniz. diff --git a/docs/tr/docs/tutorial/body-nested-models.md b/docs/tr/docs/tutorial/body-nested-models.md new file mode 100644 index 0000000000..b4ffef3f15 --- /dev/null +++ b/docs/tr/docs/tutorial/body-nested-models.md @@ -0,0 +1,220 @@ +# Body - İç İçe Modeller { #body-nested-models } + +**FastAPI** ile (Pydantic sayesinde) istediğiniz kadar derin iç içe geçmiş modelleri tanımlayabilir, doğrulayabilir, dokümante edebilir ve kullanabilirsiniz. + +## List alanları { #list-fields } + +Bir attribute’u bir alt tipe sahip olacak şekilde tanımlayabilirsiniz. Örneğin, bir Python `list`: + +{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *} + +Bu, `tags`’in bir list olmasını sağlar; ancak list’in elemanlarının tipini belirtmez. + +## Tip parametresi olan list alanları { #list-fields-with-type-parameter } + +Ancak Python’da, iç tipleri olan list’leri (ya da "type parameter" içeren tipleri) tanımlamanın belirli bir yolu vardır: + +### Tip parametresiyle bir `list` tanımlayın { #declare-a-list-with-a-type-parameter } + +`list`, `dict`, `tuple` gibi type parameter (iç tip) alan tipleri tanımlamak için, iç tipi(leri) köşeli parantezlerle "type parameter" olarak verin: `[` ve `]` + +```Python +my_list: list[str] +``` + +Bu, tip tanımları için standart Python sözdizimidir. + +İç tipleri olan model attribute’ları için de aynı standart sözdizimini kullanın. + +Dolayısıyla örneğimizde, `tags`’i özel olarak bir "string list’i" yapabiliriz: + +{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *} + +## Set tipleri { #set-types } + +Sonra bunu düşününce, tag’lerin tekrar etmemesi gerektiğini fark ederiz; büyük ihtimalle benzersiz string’ler olmalıdır. + +Python’da benzersiz öğelerden oluşan kümeler için özel bir veri tipi vardır: `set`. + +O zaman `tags`’i string’lerden oluşan bir set olarak tanımlayabiliriz: + +{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *} + +Böylece duplicate veri içeren bir request alsanız bile, bu veri benzersiz öğelerden oluşan bir set’e dönüştürülür. + +Ve bu veriyi ne zaman output etseniz, kaynakta duplicate olsa bile, benzersiz öğelerden oluşan bir set olarak output edilir. + +Ayrıca buna göre annotate / dokümante edilir. + +## İç İçe Modeller { #nested-models } + +Bir Pydantic modelinin her attribute’unun bir tipi vardır. + +Ancak bu tip, kendi başına başka bir Pydantic modeli de olabilir. + +Yani belirli attribute adları, tipleri ve validation kurallarıyla derin iç içe JSON "object"leri tanımlayabilirsiniz. + +Hem de istediğiniz kadar iç içe. + +### Bir alt model tanımlayın { #define-a-submodel } + +Örneğin bir `Image` modeli tanımlayabiliriz: + +{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *} + +### Alt modeli tip olarak kullanın { #use-the-submodel-as-a-type } + +Ardından bunu bir attribute’un tipi olarak kullanabiliriz: + +{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *} + +Bu da **FastAPI**’nin aşağıdakine benzer bir body bekleyeceği anlamına gelir: + +```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" + } +} +``` + +Yine, sadece bu tanımı yaparak **FastAPI** ile şunları elde edersiniz: + +* Editör desteği (tamamlama vb.), iç içe modeller için bile +* Veri dönüştürme +* Veri doğrulama (validation) +* Otomatik dokümantasyon + +## Özel tipler ve doğrulama { #special-types-and-validation } + +`str`, `int`, `float` vb. normal tekil tiplerin yanında, `str`’den türeyen daha karmaşık tekil tipleri de kullanabilirsiniz. + +Tüm seçenekleri görmek için Pydantic Type Overview sayfasına göz atın. Sonraki bölümde bazı örnekleri göreceksiniz. + +Örneğin `Image` modelinde bir `url` alanımız olduğuna göre, bunu `str` yerine Pydantic’in `HttpUrl` tipinden bir instance olacak şekilde tanımlayabiliriz: + +{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *} + +String’in geçerli bir URL olup olmadığı kontrol edilir ve JSON Schema / OpenAPI’de de buna göre dokümante edilir. + +## Alt modellerden oluşan list’lere sahip attribute’lar { #attributes-with-lists-of-submodels } + +Pydantic modellerini `list`, `set` vb. tiplerin alt tipi olarak da kullanabilirsiniz: + +{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *} + +Bu, aşağıdaki gibi bir JSON body bekler (dönüştürür, doğrular, dokümante eder vb.): + +```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 | Bilgi + +`images` key’inin artık image object’lerinden oluşan bir list içerdiğine dikkat edin. + +/// + +## Çok derin iç içe modeller { #deeply-nested-models } + +İstediğiniz kadar derin iç içe modeller tanımlayabilirsiniz: + +{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *} + +/// info | Bilgi + +`Offer`’ın bir `Item` list’i olduğuna, `Item`’ların da opsiyonel bir `Image` list’ine sahip olduğuna dikkat edin. + +/// + +## Sadece list olan body’ler { #bodies-of-pure-lists } + +Beklediğiniz JSON body’nin en üst seviye değeri bir JSON `array` (Python’da `list`) ise, tipi Pydantic modellerinde olduğu gibi fonksiyonun parametresinde tanımlayabilirsiniz: + +```Python +images: list[Image] +``` + +şu örnekte olduğu gibi: + +{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *} + +## Her yerde editör desteği { #editor-support-everywhere } + +Ve her yerde editör desteği alırsınız. + +List içindeki öğeler için bile: + + + +Pydantic modelleri yerine doğrudan `dict` ile çalışsaydınız bu tür bir editör desteğini alamazdınız. + +Ancak bunlarla uğraşmanız da gerekmez; gelen dict’ler otomatik olarak dönüştürülür ve output’unuz da otomatik olarak JSON’a çevrilir. + +## Rastgele `dict` body’leri { #bodies-of-arbitrary-dicts } + +Body’yi, key’leri bir tipte ve value’ları başka bir tipte olan bir `dict` olarak da tanımlayabilirsiniz. + +Bu şekilde (Pydantic modellerinde olduğu gibi) geçerli field/attribute adlarının önceden ne olduğunu bilmeniz gerekmez. + +Bu, önceden bilmediğiniz key’leri almak istediğiniz durumlarda faydalıdır. + +--- + +Bir diğer faydalı durum da key’lerin başka bir tipte olmasını istediğiniz zamandır (ör. `int`). + +Burada göreceğimiz şey de bu. + +Bu durumda, `int` key’lere ve `float` value’lara sahip olduğu sürece herhangi bir `dict` kabul edersiniz: + +{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *} + +/// tip | İpucu + +JSON key olarak yalnızca `str` destekler, bunu unutmayın. + +Ancak Pydantic otomatik veri dönüştürme yapar. + +Yani API client’larınız key’leri sadece string olarak gönderebilse bile, bu string’ler saf tamsayı içeriyorsa Pydantic bunları dönüştürür ve doğrular. + +Ve `weights` olarak aldığınız `dict`, gerçekte `int` key’lere ve `float` value’lara sahip olur. + +/// + +## Özet { #recap } + +**FastAPI** ile Pydantic modellerinin sağladığı en yüksek esnekliği elde ederken, kodunuzu da basit, kısa ve şık tutarsınız. + +Üstelik tüm avantajlarla birlikte: + +* Editör desteği (her yerde tamamlama!) +* Veri dönüştürme (diğer adıyla parsing / serialization) +* Veri doğrulama (validation) +* Schema dokümantasyonu +* Otomatik dokümanlar diff --git a/docs/tr/docs/tutorial/body-updates.md b/docs/tr/docs/tutorial/body-updates.md new file mode 100644 index 0000000000..a9ad13d2ee --- /dev/null +++ b/docs/tr/docs/tutorial/body-updates.md @@ -0,0 +1,100 @@ +# Body - Güncellemeler { #body-updates } + +## `PUT` ile değiştirerek güncelleme { #update-replacing-with-put } + +Bir öğeyi güncellemek için HTTP `PUT` operasyonunu kullanabilirsiniz. + +Girdi verisini JSON olarak saklanabilecek bir formata (ör. bir NoSQL veritabanı ile) dönüştürmek için `jsonable_encoder` kullanabilirsiniz. Örneğin, `datetime` değerlerini `str`'ye çevirmek gibi. + +{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *} + +`PUT`, mevcut verinin yerine geçmesi gereken veriyi almak için kullanılır. + +### Değiştirerek güncelleme uyarısı { #warning-about-replacing } + +Bu, `bar` öğesini `PUT` ile, body içinde şu verilerle güncellemek isterseniz: + +```Python +{ + "name": "Barz", + "price": 3, + "description": None, +} +``` + +zaten kayıtlı olan `"tax": 20.2` alanını içermediği için, input model `"tax": 10.5` varsayılan değerini kullanacaktır. + +Ve veri, bu "yeni" `tax` değeri olan `10.5` ile kaydedilecektir. + +## `PATCH` ile kısmi güncellemeler { #partial-updates-with-patch } + +Veriyi *kısmen* güncellemek için HTTP `PATCH` operasyonunu da kullanabilirsiniz. + +Bu, yalnızca güncellemek istediğiniz veriyi gönderip, geri kalanını olduğu gibi bırakabileceğiniz anlamına gelir. + +/// note | Not + +`PATCH`, `PUT`'a göre daha az yaygın kullanılır ve daha az bilinir. + +Hatta birçok ekip, kısmi güncellemeler için bile yalnızca `PUT` kullanır. + +Bunları nasıl isterseniz öyle kullanmakta **özgürsünüz**; **FastAPI** herhangi bir kısıtlama dayatmaz. + +Ancak bu kılavuz, aşağı yukarı, bunların nasıl kullanılması amaçlandığını gösterir. + +/// + +### Pydantic'in `exclude_unset` parametresini kullanma { #using-pydantics-exclude-unset-parameter } + +Kısmi güncellemeler almak istiyorsanız, Pydantic modelinin `.model_dump()` metodundaki `exclude_unset` parametresini kullanmak çok faydalıdır. + +Örneğin: `item.model_dump(exclude_unset=True)`. + +Bu, `item` modeli oluşturulurken set edilmiş verileri içeren; varsayılan değerleri hariç tutan bir `dict` üretir. + +Sonrasında bunu, yalnızca set edilmiş (request'te gönderilmiş) veriyi içeren; varsayılan değerleri atlayan bir `dict` üretmek için kullanabilirsiniz: + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *} + +### Pydantic'in `update` parametresini kullanma { #using-pydantics-update-parameter } + +Artık `.model_copy()` ile mevcut modelin bir kopyasını oluşturup, güncellenecek verileri içeren bir `dict` ile `update` parametresini geçebilirsiniz. + +Örneğin: `stored_item_model.model_copy(update=update_data)`: + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *} + +### Kısmi güncellemeler özeti { #partial-updates-recap } + +Özetle, kısmi güncelleme uygulamak için şunları yaparsınız: + +* (İsteğe bağlı olarak) `PUT` yerine `PATCH` kullanın. +* Kayıtlı veriyi alın. +* Bu veriyi bir Pydantic modeline koyun. +* Input modelinden, varsayılan değerler olmadan bir `dict` üretin (`exclude_unset` kullanarak). + * Bu şekilde, modelinizdeki varsayılan değerlerle daha önce saklanmış değerlerin üzerine yazmak yerine, yalnızca kullanıcının gerçekten set ettiği değerleri güncellersiniz. +* Kayıtlı modelin bir kopyasını oluşturun ve alınan kısmi güncellemeleri kullanarak attribute'larını güncelleyin (`update` parametresini kullanarak). +* Kopyalanan modeli DB'nizde saklanabilecek bir şeye dönüştürün (ör. `jsonable_encoder` kullanarak). + * Bu, modelin `.model_dump()` metodunu yeniden kullanmaya benzer; ancak değerlerin JSON'a dönüştürülebilecek veri tiplerine çevrilmesini garanti eder (ör. `datetime` -> `str`). +* Veriyi DB'nize kaydedin. +* Güncellenmiş modeli döndürün. + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *} + +/// tip | İpucu + +Aynı tekniği HTTP `PUT` operasyonu ile de kullanabilirsiniz. + +Ancak buradaki örnek `PATCH` kullanıyor, çünkü bu kullanım senaryoları için tasarlanmıştır. + +/// + +/// note | Not + +Input modelin yine de doğrulandığına dikkat edin. + +Dolayısıyla, tüm attribute'ların atlanabildiği kısmi güncellemeler almak istiyorsanız, tüm attribute'ları optional olarak işaretlenmiş (varsayılan değerlerle veya `None` ile) bir modele ihtiyacınız vardır. + +**Güncelleme** için tüm değerleri optional olan modeller ile **oluşturma** için zorunlu değerlere sahip modelleri ayırmak için, [Extra Models](extra-models.md){.internal-link target=_blank} bölümünde anlatılan fikirleri kullanabilirsiniz. + +/// diff --git a/docs/tr/docs/tutorial/body.md b/docs/tr/docs/tutorial/body.md new file mode 100644 index 0000000000..0557ef737a --- /dev/null +++ b/docs/tr/docs/tutorial/body.md @@ -0,0 +1,166 @@ +# Request Body { #request-body } + +Bir client'ten (örneğin bir tarayıcıdan) API'nize veri göndermeniz gerektiğinde, bunu **request body** olarak gönderirsiniz. + +Bir **request** body, client'in API'nize gönderdiği veridir. Bir **response** body ise API'nizin client'e gönderdiği veridir. + +API'niz neredeyse her zaman bir **response** body göndermek zorundadır. Ancak client'lerin her zaman **request body** göndermesi gerekmez; bazen sadece bir path isterler, belki birkaç query parametresiyle birlikte, ama body göndermezler. + +Bir **request** body tanımlamak için, tüm gücü ve avantajlarıyla Pydantic modellerini kullanırsınız. + +/// info | Bilgi + +Veri göndermek için şunlardan birini kullanmalısınız: `POST` (en yaygını), `PUT`, `DELETE` veya `PATCH`. + +`GET` request'i ile body göndermek, spesifikasyonlarda tanımsız bir davranıştır; yine de FastAPI bunu yalnızca çok karmaşık/uç kullanım senaryoları için destekler. + +Önerilmediği için Swagger UI ile etkileşimli dokümanlar, `GET` kullanırken body için dokümantasyonu göstermez ve aradaki proxy'ler bunu desteklemeyebilir. + +/// + +## Pydantic'in `BaseModel`'ini import edin { #import-pydantics-basemodel } + +Önce, `pydantic` içinden `BaseModel`'i import etmeniz gerekir: + +{* ../../docs_src/body/tutorial001_py310.py hl[2] *} + +## Veri modelinizi oluşturun { #create-your-data-model } + +Sonra veri modelinizi, `BaseModel`'den kalıtım alan bir class olarak tanımlarsınız. + +Tüm attribute'lar için standart Python type'larını kullanın: + +{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *} + + +Query parametrelerini tanımlarken olduğu gibi, bir model attribute'ü default bir değere sahipse zorunlu değildir. Aksi halde zorunludur. Sadece opsiyonel yapmak için `None` kullanın. + +Örneğin, yukarıdaki model şu şekilde bir JSON "`object`" (veya Python `dict`) tanımlar: + +```JSON +{ + "name": "Foo", + "description": "An optional description", + "price": 45.2, + "tax": 3.5 +} +``` + +...`description` ve `tax` opsiyonel olduğu için (default değerleri `None`), şu JSON "`object`" da geçerli olur: + +```JSON +{ + "name": "Foo", + "price": 45.2 +} +``` + +## Parametre olarak tanımlayın { #declare-it-as-a-parameter } + +Bunu *path operation*'ınıza eklemek için, path ve query parametrelerini tanımladığınız şekilde tanımlayın: + +{* ../../docs_src/body/tutorial001_py310.py hl[16] *} + +...ve type'ını, oluşturduğunuz model olan `Item` olarak belirtin. + +## Sonuçlar { #results } + +Sadece bu Python type tanımıyla, **FastAPI** şunları yapar: + +* Request'in body'sini JSON olarak okur. +* İlgili type'lara dönüştürür (gerekirse). +* Veriyi doğrular (validate eder). + * Veri geçersizse, tam olarak nerede ve hangi verinin hatalı olduğunu söyleyen, anlaşılır bir hata döndürür. +* Aldığı veriyi `item` parametresi içinde size verir. + * Fonksiyonda bunun type'ını `Item` olarak tanımladığınız için, tüm attribute'lar ve type'ları için editor desteğini (tamamlama vb.) de alırsınız. +* Modeliniz için JSON Schema tanımları üretir; projeniz için anlamlıysa bunları başka yerlerde de kullanabilirsiniz. +* Bu şemalar üretilen OpenAPI şemasının bir parçası olur ve otomatik dokümantasyon UIs tarafından kullanılır. + +## Otomatik dokümanlar { #automatic-docs } + +Modellerinizin JSON Schema'ları, OpenAPI tarafından üretilen şemanın bir parçası olur ve etkileşimli API dokümanlarında gösterilir: + + + +Ayrıca, ihtiyaç duyan her *path operation* içindeki API dokümanlarında da kullanılır: + + + +## Editor desteği { #editor-support } + +Editor'ünüzde, fonksiyonunuzun içinde her yerde type hint'leri ve tamamlama (completion) alırsınız (Pydantic modeli yerine `dict` alsaydınız bu olmazdı): + + + +Yanlış type işlemleri için hata kontrolleri de alırsınız: + + + +Bu bir tesadüf değil; tüm framework bu tasarımın etrafında inşa edildi. + +Ayrıca, bunun tüm editor'lerle çalışacağından emin olmak için herhangi bir implementasyon yapılmadan önce tasarım aşamasında kapsamlı şekilde test edildi. + +Hatta bunu desteklemek için Pydantic'in kendisinde bile bazı değişiklikler yapıldı. + +Önceki ekran görüntüleri Visual Studio Code ile alınmıştır. + +Ancak PyCharm ve diğer Python editor'lerinin çoğunda da aynı editor desteğini alırsınız: + + + +/// tip | İpucu + +Editor olarak PyCharm kullanıyorsanız, Pydantic PyCharm Plugin kullanabilirsiniz. + +Pydantic modelleri için editor desteğini şu açılardan iyileştirir: + +* auto-completion +* type checks +* refactoring +* searching +* inspections + +/// + +## Modeli kullanın { #use-the-model } + +Fonksiyonun içinde model nesnesinin tüm attribute'larına doğrudan erişebilirsiniz: + +{* ../../docs_src/body/tutorial002_py310.py *} + +## Request body + path parametreleri { #request-body-path-parameters } + +Path parametrelerini ve request body'yi aynı anda tanımlayabilirsiniz. + +**FastAPI**, path parametreleriyle eşleşen fonksiyon parametrelerinin **path'ten alınması** gerektiğini ve Pydantic model olarak tanımlanan fonksiyon parametrelerinin **request body'den alınması** gerektiğini anlayacaktır. + +{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *} + + +## Request body + path + query parametreleri { #request-body-path-query-parameters } + +**body**, **path** ve **query** parametrelerini aynı anda da tanımlayabilirsiniz. + +**FastAPI** bunların her birini tanır ve veriyi doğru yerden alır. + +{* ../../docs_src/body/tutorial004_py310.py hl[16] *} + +Fonksiyon parametreleri şu şekilde tanınır: + +* Parametre, **path** içinde de tanımlıysa path parametresi olarak kullanılır. +* Parametre **tekil bir type**'taysa (`int`, `float`, `str`, `bool` vb.), **query** parametresi olarak yorumlanır. +* Parametre bir **Pydantic model** type'ı olarak tanımlandıysa, request **body** olarak yorumlanır. + +/// note | Not + +FastAPI, `q` değerinin zorunlu olmadığını `= None` default değerinden anlayacaktır. + +`str | None` (Python 3.10+) veya `Union[str, None]` (Python 3.9+) içindeki `Union`, FastAPI tarafından bu değerin zorunlu olmadığını belirlemek için kullanılmaz; FastAPI bunun zorunlu olmadığını `= None` default değeri olduğu için bilir. + +Ancak type annotation'larını eklemek, editor'ünüzün size daha iyi destek vermesini ve hataları yakalamasını sağlar. + +/// + +## Pydantic olmadan { #without-pydantic } + +Pydantic modellerini kullanmak istemiyorsanız, **Body** parametrelerini de kullanabilirsiniz. [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank} dokümanına bakın. diff --git a/docs/tr/docs/tutorial/cookie-param-models.md b/docs/tr/docs/tutorial/cookie-param-models.md new file mode 100644 index 0000000000..a5bf515609 --- /dev/null +++ b/docs/tr/docs/tutorial/cookie-param-models.md @@ -0,0 +1,76 @@ +# Cookie Parameter Models { #cookie-parameter-models } + +Birbirleriyle ilişkili bir **cookie** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz. + +Bu sayede **model'i yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation ve metadata'yı tek seferde tanımlayabilirsiniz. + +/// note | Not + +Bu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir. + +/// + +/// tip | İpucu + +Aynı teknik `Query`, `Cookie` ve `Header` için de geçerlidir. + +/// + +## Pydantic Model ile Cookies { #cookies-with-a-pydantic-model } + +İhtiyacınız olan **cookie** parametrelerini bir **Pydantic model** içinde tanımlayın ve ardından parametreyi `Cookie` olarak bildirin: + +{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *} + +**FastAPI**, request ile gelen **cookies** içinden **her bir field** için veriyi **extract** eder ve size tanımladığınız Pydantic model'i verir. + +## Dokümanları Kontrol Edin { #check-the-docs } + +Tanımlanan cookie'leri `/docs` altındaki docs UI'da görebilirsiniz: + +
+ +
+ +/// info | Bilgi + +Tarayıcıların cookie'leri özel biçimlerde ve arka planda yönetmesi nedeniyle, **JavaScript**'in cookie'lere erişmesine kolayca izin vermediğini aklınızda bulundurun. + +`/docs` altındaki **API docs UI**'a giderseniz, *path operation*'larınız için cookie'lerin **dokümantasyonunu** görebilirsiniz. + +Ancak verileri **doldurup** "Execute" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için cookie'ler gönderilmez; dolayısıyla hiç değer girmemişsiniz gibi bir **error** mesajı görürsünüz. + +/// + +## Fazladan Cookies'leri Yasaklayın { #forbid-extra-cookies } + +Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değildir) almak istediğiniz cookie'leri **kısıtlamak** isteyebilirsiniz. + +API'niz artık kendi cookie consent'ını kontrol etme gücüne sahip. + +Pydantic'in model configuration'ını kullanarak `extra` olan herhangi bir field'ı `forbid` edebilirsiniz: + +{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *} + +Bir client **fazladan cookie** göndermeye çalışırsa, bir **error** response alır. + +Onayınızı almak için bunca çaba harcayan zavallı cookie banner'ları... API'nin bunu reddetmesi için. + +Örneğin client, değeri `good-list-please` olan bir `santa_tracker` cookie'si göndermeye çalışırsa, client `santa_tracker` cookie is not allowed diyen bir **error** response alır: + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["cookie", "santa_tracker"], + "msg": "Extra inputs are not permitted", + "input": "good-list-please", + } + ] +} +``` + +## Özet { #summary } + +**FastAPI**'de **cookies** tanımlamak için **Pydantic model**'lerini kullanabilirsiniz. 😎 diff --git a/docs/tr/docs/tutorial/cors.md b/docs/tr/docs/tutorial/cors.md new file mode 100644 index 0000000000..aae560022a --- /dev/null +++ b/docs/tr/docs/tutorial/cors.md @@ -0,0 +1,89 @@ +# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing } + +CORS veya "Cross-Origin Resource Sharing", tarayıcıda çalışan bir frontend’in JavaScript kodunun bir backend ile iletişim kurduğu ve backend’in frontend’den farklı bir "origin"de olduğu durumları ifade eder. + +## Origin { #origin } + +Origin; protocol (`http`, `https`), domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`) ve port’un (`80`, `443`, `8080`) birleşimidir. + +Dolayısıyla şunların hepsi farklı origin’lerdir: + +* `http://localhost` +* `https://localhost` +* `http://localhost:8080` + +Hepsi `localhost` üzerinde olsa bile, farklı protocol veya port kullandıkları için farklı "origin" sayılırlar. + +## Adımlar { #steps } + +Diyelim ki tarayıcınızda `http://localhost:8080` adresinde çalışan bir frontend’iniz var ve JavaScript’i, `http://localhost` adresinde çalışan bir backend ile iletişim kurmaya çalışıyor (port belirtmediğimiz için tarayıcı varsayılan port olan `80`’i kullanacaktır). + +Bu durumda tarayıcı, `:80`-backend’e bir HTTP `OPTIONS` request’i gönderir. Eğer backend, bu farklı origin’den (`http://localhost:8080`) gelen iletişimi yetkilendiren uygun header’ları gönderirse, `:8080`-tarayıcı frontend’deki JavaScript’in `:80`-backend’e request göndermesine izin verir. + +Bunu sağlayabilmek için `:80`-backend’in bir "allowed origins" listesi olmalıdır. + +Bu örnekte `:8080`-frontend’in doğru çalışması için listede `http://localhost:8080` bulunmalıdır. + +## Wildcard'lar { #wildcards } + +Listeyi `"*"` (bir "wildcard") olarak tanımlayıp, hepsine izin verildiğini söylemek de mümkündür. + +Ancak bu, credentials içeren her şeyi hariç tutarak yalnızca belirli iletişim türlerine izin verir: Cookie’ler, Bearer Token’larla kullanılanlar gibi Authorization header’ları, vb. + +Bu yüzden her şeyin düzgün çalışması için, izin verilen origin’leri açıkça belirtmek daha iyidir. + +## `CORSMiddleware` Kullanımı { #use-corsmiddleware } + +Bunu **FastAPI** uygulamanızda `CORSMiddleware` ile yapılandırabilirsiniz. + +* `CORSMiddleware`’i import edin. +* İzin verilen origin’lerden (string) oluşan bir liste oluşturun. +* Bunu **FastAPI** uygulamanıza bir "middleware" olarak ekleyin. + +Ayrıca backend’in şunlara izin verip vermediğini de belirtebilirsiniz: + +* Credentials (Authorization header’ları, Cookie’ler, vb). +* Belirli HTTP method’ları (`POST`, `PUT`) veya wildcard `"*"` ile hepsini. +* Belirli HTTP header’ları veya wildcard `"*"` ile hepsini. + +{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *} + + +`CORSMiddleware` implementasyonu tarafından kullanılan varsayılan parametreler kısıtlayıcıdır; bu nedenle tarayıcıların Cross-Domain bağlamında kullanmasına izin vermek için belirli origin’leri, method’ları veya header’ları açıkça etkinleştirmeniz gerekir. + +Aşağıdaki argümanlar desteklenir: + +* `allow_origins` - Cross-origin request yapmasına izin verilmesi gereken origin’lerin listesi. Örn. `['https://example.org', 'https://www.example.org']`. Herhangi bir origin’e izin vermek için `['*']` kullanabilirsiniz. +* `allow_origin_regex` - Cross-origin request yapmasına izin verilmesi gereken origin’lerle eşleşecek bir regex string’i. Örn. `'https://.*\.example\.org'`. +* `allow_methods` - Cross-origin request’lerde izin verilmesi gereken HTTP method’larının listesi. Varsayılanı `['GET']`. Tüm standart method’lara izin vermek için `['*']` kullanabilirsiniz. +* `allow_headers` - Cross-origin request’lerde desteklenmesi gereken HTTP request header’larının listesi. Varsayılanı `[]`. Tüm header’lara izin vermek için `['*']` kullanabilirsiniz. `Accept`, `Accept-Language`, `Content-Language` ve `Content-Type` header’larına basit CORS request'leri için her zaman izin verilir. +* `allow_credentials` - Cross-origin request’ler için cookie desteği olup olmayacağını belirtir. Varsayılanı `False`. + + `allow_credentials` `True` olarak ayarlanmışsa, `allow_origins`, `allow_methods` ve `allow_headers` değerlerinin hiçbiri `['*']` olamaz. Hepsinin açıkça belirtilmesi gerekir. + +* `expose_headers` - Tarayıcının erişebilmesi gereken response header’larını belirtir. Varsayılanı `[]`. +* `max_age` - Tarayıcıların CORS response’larını cache’lemesi için saniye cinsinden azami süreyi ayarlar. Varsayılanı `600`. + +Middleware iki özel HTTP request türüne yanıt verir... + +### CORS preflight request'leri { #cors-preflight-requests } + +Bunlar, `Origin` ve `Access-Control-Request-Method` header’larına sahip herhangi bir `OPTIONS` request’idir. + +Bu durumda middleware gelen request’i intercept eder ve uygun CORS header’larıyla yanıt verir; bilgilendirme amaçlı olarak da `200` veya `400` response döndürür. + +### Basit request'ler { #simple-requests } + +`Origin` header’ı olan herhangi bir request. Bu durumda middleware request’i normal şekilde geçirir, ancak response’a uygun CORS header’larını ekler. + +## Daha Fazla Bilgi { #more-info } + +CORS hakkında daha fazla bilgi için Mozilla CORS dokümantasyonuna bakın. + +/// note | Teknik Detaylar + +`from starlette.middleware.cors import CORSMiddleware` şeklinde de kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olması için `fastapi.middleware` içinde bazı middleware’ler sağlar. Ancak mevcut middleware’lerin çoğu doğrudan Starlette’ten gelir. + +/// diff --git a/docs/tr/docs/tutorial/debugging.md b/docs/tr/docs/tutorial/debugging.md new file mode 100644 index 0000000000..54d5c9252a --- /dev/null +++ b/docs/tr/docs/tutorial/debugging.md @@ -0,0 +1,113 @@ +# Debugging { #debugging } + +Visual Studio Code veya PyCharm gibi editörünüzde debugger'ı bağlayabilirsiniz. + +## `uvicorn`'ı Çağırma { #call-uvicorn } + +FastAPI uygulamanızda `uvicorn`'ı import edip doğrudan çalıştırın: + +{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} + +### `__name__ == "__main__"` Hakkında { #about-name-main } + +`__name__ == "__main__"` ifadesinin temel amacı, dosyanız şu şekilde çağrıldığında çalışacak: + +
+ +```console +$ python myapp.py +``` + +
+ +ancak başka bir dosya onu import ettiğinde çalışmayacak bir kod bölümüne sahip olmaktır, örneğin: + +```Python +from myapp import app +``` + +#### Daha fazla detay { #more-details } + +Dosyanızın adının `myapp.py` olduğunu varsayalım. + +Şu şekilde çalıştırırsanız: + +
+ +```console +$ python myapp.py +``` + +
+ +Python tarafından otomatik oluşturulan, dosyanızın içindeki `__name__` adlı dahili değişkenin değeri `"__main__"` string'i olur. + +Dolayısıyla şu bölüm: + +```Python + uvicorn.run(app, host="0.0.0.0", port=8000) +``` + +çalışır. + +--- + +Ancak modülü (dosyayı) import ederseniz bu gerçekleşmez. + +Yani örneğin `importer.py` adında başka bir dosyanız var ve içinde şunlar bulunuyorsa: + +```Python +from myapp import app + +# Some more code +``` + +bu durumda `myapp.py` içindeki otomatik oluşturulan `__name__` değişkeni `"__main__"` değerine sahip olmaz. + +Bu yüzden şu satır: + +```Python + uvicorn.run(app, host="0.0.0.0", port=8000) +``` + +çalıştırılmaz. + +/// info | Bilgi + +Daha fazla bilgi için resmi Python dokümantasyonuna bakın. + +/// + +## Kodunuzu Debugger ile Çalıştırma { #run-your-code-with-your-debugger } + +Uvicorn server'ını doğrudan kodunuzdan çalıştırdığınız için, Python programınızı (FastAPI uygulamanızı) debugger'dan doğrudan başlatabilirsiniz. + +--- + +Örneğin Visual Studio Code'da şunları yapabilirsiniz: + +* "Debug" paneline gidin. +* "Add configuration..." seçin. +* "Python" seçin +* "`Python: Current File (Integrated Terminal)`" seçeneğiyle debugger'ı çalıştırın. + +Böylece server, **FastAPI** kodunuzla başlar; breakpoint'lerinizde durur vb. + +Aşağıdaki gibi görünebilir: + + + +--- + +PyCharm kullanıyorsanız şunları yapabilirsiniz: + +* "Run" menüsünü açın. +* "Debug..." seçeneğini seçin. +* Bir context menü açılır. +* Debug edilecek dosyayı seçin (bu örnekte `main.py`). + +Böylece server, **FastAPI** kodunuzla başlar; breakpoint'lerinizde durur vb. + +Aşağıdaki gibi görünebilir: + + diff --git a/docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md new file mode 100644 index 0000000000..9ee57cb291 --- /dev/null +++ b/docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md @@ -0,0 +1,288 @@ +# Dependency Olarak Class'lar { #classes-as-dependencies } + +**Dependency Injection** sistemine daha derinlemesine geçmeden önce, bir önceki örneği geliştirelim. + +## Önceki Örnekten Bir `dict` { #a-dict-from-the-previous-example } + +Önceki örnekte, dependency'mizden ("dependable") bir `dict` döndürüyorduk: + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *} + +Ama sonra *path operation function* içindeki `commons` parametresinde bir `dict` alıyoruz. + +Ve biliyoruz ki editor'ler `dict`'ler için çok fazla destek (ör. completion) veremez; çünkü key'lerini ve value type'larını bilemezler. + +Daha iyisini yapabiliriz... + +## Bir Şeyi Dependency Yapan Nedir { #what-makes-a-dependency } + +Şimdiye kadar dependency'leri function olarak tanımlanmış şekilde gördünüz. + +Ancak dependency tanımlamanın tek yolu bu değil (muhtemelen en yaygını bu olsa da). + +Buradaki kritik nokta, bir dependency'nin "callable" olması gerektiğidir. + +Python'da "**callable**", Python'ın bir function gibi "çağırabildiği" her şeydir. + +Yani elinizde `something` adlı bir nesne varsa (function _olmak zorunda değil_) ve onu şöyle "çağırabiliyorsanız" (çalıştırabiliyorsanız): + +```Python +something() +``` + +veya + +```Python +something(some_argument, some_keyword_argument="foo") +``` + +o zaman bu bir "callable" demektir. + +## Dependency Olarak Class'lar { #classes-as-dependencies_1 } + +Python'da bir class'tan instance oluştururken de aynı söz dizimini kullandığınızı fark etmiş olabilirsiniz. + +Örneğin: + +```Python +class Cat: + def __init__(self, name: str): + self.name = name + + +fluffy = Cat(name="Mr Fluffy") +``` + +Bu durumda `fluffy`, `Cat` class'ının bir instance'ıdır. + +Ve `fluffy` oluşturmak için `Cat`'i "çağırmış" olursunuz. + +Dolayısıyla bir Python class'ı da bir **callable**'dır. + +O zaman **FastAPI** içinde bir Python class'ını dependency olarak kullanabilirsiniz. + +FastAPI'nin aslında kontrol ettiği şey, bunun bir "callable" olması (function, class ya da başka bir şey) ve tanımlı parametreleridir. + +Eğer **FastAPI**'de bir dependency olarak bir "callable" verirseniz, FastAPI o "callable" için parametreleri analiz eder ve bunları *path operation function* parametreleriyle aynı şekilde işler. Sub-dependency'ler dahil. + +Bu, hiç parametresi olmayan callable'lar için de geçerlidir. Tıpkı hiç parametresi olmayan *path operation function*'larda olduğu gibi. + +O zaman yukarıdaki `common_parameters` adlı "dependable" dependency'sini `CommonQueryParams` class'ına çevirebiliriz: + +{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *} + +Class instance'ını oluşturmak için kullanılan `__init__` metoduna dikkat edin: + +{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *} + +...bizim önceki `common_parameters` ile aynı parametrelere sahip: + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *} + +Bu parametreler, dependency'yi "çözmek" için **FastAPI**'nin kullanacağı şeylerdir. + +Her iki durumda da şunlar olacak: + +* `str` olan opsiyonel bir `q` query parametresi. +* Default değeri `0` olan `int` tipinde bir `skip` query parametresi. +* Default değeri `100` olan `int` tipinde bir `limit` query parametresi. + +Her iki durumda da veriler dönüştürülecek, doğrulanacak, OpenAPI şemasında dokümante edilecek, vb. + +## Kullanalım { #use-it } + +Artık bu class'ı kullanarak dependency'nizi tanımlayabilirsiniz. + +{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *} + +**FastAPI**, `CommonQueryParams` class'ını çağırır. Bu, o class'ın bir "instance"ını oluşturur ve bu instance, sizin function'ınıza `commons` parametresi olarak geçirilir. + +## Type Annotation vs `Depends` { #type-annotation-vs-depends } + +Yukarıdaki kodda `CommonQueryParams`'ı iki kez yazdığımıza dikkat edin: + +//// tab | Python 3.9+ + +```Python +commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.9+ Annotated Olmadan + +/// tip | İpucu + +Mümkünse `Annotated` sürümünü kullanmayı tercih edin. + +/// + +```Python +commons: CommonQueryParams = Depends(CommonQueryParams) +``` + +//// + +Şuradaki son `CommonQueryParams`: + +```Python +... Depends(CommonQueryParams) +``` + +...FastAPI'nin dependency'nin ne olduğunu anlamak için gerçekten kullandığı şeydir. + +FastAPI tanımlanan parametreleri buradan çıkarır ve aslında çağıracağı şey de budur. + +--- + +Bu durumda, şuradaki ilk `CommonQueryParams`: + +//// tab | Python 3.9+ + +```Python +commons: Annotated[CommonQueryParams, ... +``` + +//// + +//// tab | Python 3.9+ Annotated Olmadan + +/// tip | İpucu + +Mümkünse `Annotated` sürümünü kullanmayı tercih edin. + +/// + +```Python +commons: CommonQueryParams ... +``` + +//// + +...**FastAPI** için özel bir anlam taşımaz. FastAPI bunu veri dönüştürme, doğrulama vb. için kullanmaz (çünkü bunlar için `Depends(CommonQueryParams)` kullanıyor). + +Hatta şunu bile yazabilirsiniz: + +//// tab | Python 3.9+ + +```Python +commons: Annotated[Any, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.9+ Annotated Olmadan + +/// tip | İpucu + +Mümkünse `Annotated` sürümünü kullanmayı tercih edin. + +/// + +```Python +commons = Depends(CommonQueryParams) +``` + +//// + +...şu örnekte olduğu gibi: + +{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *} + +Ancak type'ı belirtmeniz önerilir; böylece editor'ünüz `commons` parametresine ne geçirileceğini bilir ve size code completion, type check'leri vb. konularda yardımcı olur: + + + +## Kısayol { #shortcut } + +Ama burada bir miktar kod tekrarımız olduğunu görüyorsunuz; `CommonQueryParams`'ı iki kez yazıyoruz: + +//// tab | Python 3.9+ + +```Python +commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.9+ Annotated Olmadan + +/// tip | İpucu + +Mümkünse `Annotated` sürümünü kullanmayı tercih edin. + +/// + +```Python +commons: CommonQueryParams = Depends(CommonQueryParams) +``` + +//// + +**FastAPI**, bu durumlar için bir kısayol sağlar: dependency'nin *özellikle* FastAPI'nin bir instance oluşturmak için "çağıracağı" bir class olduğu durumlar. + +Bu özel durumlarda şunu yapabilirsiniz: + +Şunu yazmak yerine: + +//// tab | Python 3.9+ + +```Python +commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] +``` + +//// + +//// tab | Python 3.9+ Annotated Olmadan + +/// tip | İpucu + +Mümkünse `Annotated` sürümünü kullanmayı tercih edin. + +/// + +```Python +commons: CommonQueryParams = Depends(CommonQueryParams) +``` + +//// + +...şunu yazarsınız: + +//// tab | Python 3.9+ + +```Python +commons: Annotated[CommonQueryParams, Depends()] +``` + +//// + +//// tab | Python 3.9+ Annotated Olmadan + +/// tip | İpucu + +Mümkünse `Annotated` sürümünü kullanmayı tercih edin. + +/// + +```Python +commons: CommonQueryParams = Depends() +``` + +//// + +Dependency'yi parametrenin type'ı olarak tanımlarsınız ve `Depends(CommonQueryParams)` içinde class'ı *yeniden* yazmak yerine, parametre vermeden `Depends()` kullanırsınız. + +Aynı örnek şu hale gelir: + +{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *} + +...ve **FastAPI** ne yapması gerektiğini bilir. + +/// tip | İpucu + +Bu size faydalı olmaktan çok kafa karıştırıcı geliyorsa, kullanmayın; buna *ihtiyacınız* yok. + +Bu sadece bir kısayoldur. Çünkü **FastAPI** kod tekrarını en aza indirmenize yardımcı olmayı önemser. + +/// diff --git a/docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md new file mode 100644 index 0000000000..4903aec4a4 --- /dev/null +++ b/docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -0,0 +1,69 @@ +# Path Operation Decorator'lerinde Dependency'ler { #dependencies-in-path-operation-decorators } + +Bazı durumlarda bir dependency'nin döndürdüğü değere *path operation function* içinde gerçekten ihtiyacınız olmaz. + +Ya da dependency zaten bir değer döndürmüyordur. + +Ancak yine de çalıştırılmasını/çözülmesini istersiniz. + +Bu gibi durumlarda, `Depends` ile bir *path operation function* parametresi tanımlamak yerine, *path operation decorator*'üne `dependencies` adında bir `list` ekleyebilirsiniz. + +## *Path Operation Decorator*'üne `dependencies` Ekleyin { #add-dependencies-to-the-path-operation-decorator } + +*Path operation decorator*, opsiyonel bir `dependencies` argümanı alır. + +Bu, `Depends()` öğelerinden oluşan bir `list` olmalıdır: + +{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *} + +Bu dependency'ler normal dependency'lerle aynı şekilde çalıştırılır/çözülür. Ancak (eğer bir değer döndürüyorlarsa) bu değer *path operation function*'ınıza aktarılmaz. + +/// tip | İpucu + +Bazı editörler, kullanılmayan function parametrelerini kontrol eder ve bunları hata olarak gösterebilir. + +Bu `dependencies` yaklaşımıyla, editör/araç hatalarına takılmadan dependency'lerin çalıştırılmasını sağlayabilirsiniz. + +Ayrıca kodunuzda kullanılmayan bir parametreyi gören yeni geliştiricilerin bunun gereksiz olduğunu düşünmesi gibi bir kafa karışıklığını da azaltabilir. + +/// + +/// info | Bilgi + +Bu örnekte uydurma özel header'lar olan `X-Key` ve `X-Token` kullanıyoruz. + +Ancak gerçek senaryolarda, security uygularken, entegre [Security yardımcı araçlarını (bir sonraki bölüm)](../security/index.md){.internal-link target=_blank} kullanmak size daha fazla fayda sağlar. + +/// + +## Dependency Hataları ve Return Değerleri { #dependencies-errors-and-return-values } + +Normalde kullandığınız aynı dependency *function*'larını burada da kullanabilirsiniz. + +### Dependency Gereksinimleri { #dependency-requirements } + +Request gereksinimleri (header'lar gibi) veya başka alt dependency'ler tanımlayabilirler: + +{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *} + +### Exception Fırlatmak { #raise-exceptions } + +Bu dependency'ler, normal dependency'lerde olduğu gibi `raise` ile exception fırlatabilir: + +{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *} + +### Return Değerleri { #return-values } + +Ayrıca değer döndürebilirler ya da döndürmeyebilirler; dönen değer kullanılmayacaktır. + +Yani başka bir yerde zaten kullandığınız, değer döndüren normal bir dependency'yi tekrar kullanabilirsiniz; değer kullanılmasa bile dependency çalıştırılacaktır: + +{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *} + +## Bir *Path Operation* Grubu İçin Dependency'ler { #dependencies-for-a-group-of-path-operations } + +Daha sonra, muhtemelen birden fazla dosya kullanarak daha büyük uygulamaları nasıl yapılandıracağınızı okurken ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}), bir *path operation* grubu için tek bir `dependencies` parametresini nasıl tanımlayacağınızı öğreneceksiniz. + +## Global Dependency'ler { #global-dependencies } + +Sırada, dependency'leri tüm `FastAPI` uygulamasına nasıl ekleyeceğimizi göreceğiz; böylece her *path operation* için geçerli olacaklar. diff --git a/docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md new file mode 100644 index 0000000000..bd025f799b --- /dev/null +++ b/docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md @@ -0,0 +1,289 @@ +# `yield` ile Dependency'ler { #dependencies-with-yield } + +FastAPI, işini bitirdikten sonra ek adımlar çalıştıran dependency'leri destekler. + +Bunu yapmak için `return` yerine `yield` kullanın ve ek adımları (kodu) `yield` satırından sonra yazın. + +/// tip | İpucu + +Her dependency için yalnızca **bir kez** `yield` kullandığınızdan emin olun. + +/// + +/// note | Teknik Detaylar + +Şunlarla kullanılabilen herhangi bir fonksiyon: + +* `@contextlib.contextmanager` veya +* `@contextlib.asynccontextmanager` + +bir **FastAPI** dependency'si olarak kullanılabilir. + +Hatta FastAPI bu iki decorator'ı içeride (internally) kullanır. + +/// + +## `yield` ile Bir Veritabanı Dependency'si { #a-database-dependency-with-yield } + +Örneğin bunu, bir veritabanı session'ı oluşturmak ve iş bittikten sonra kapatmak için kullanabilirsiniz. + +Response oluşturulmadan önce yalnızca `yield` satırına kadar olan (ve `yield` dahil) kod çalıştırılır: + +{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *} + +`yield` edilen değer, *path operation*'lara ve diğer dependency'lere enjekte edilen (injected) değerdir: + +{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *} + +Response'dan sonra `yield` satırını takip eden kod çalıştırılır: + +{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *} + +/// tip | İpucu + +`async` ya da normal fonksiyonlar kullanabilirsiniz. + +**FastAPI**, normal dependency'lerde olduğu gibi her ikisinde de doğru şekilde davranır. + +/// + +## `yield` ve `try` ile Bir Dependency { #a-dependency-with-yield-and-try } + +`yield` kullanan bir dependency içinde bir `try` bloğu kullanırsanız, dependency kullanılırken fırlatılan (raised) herhangi bir exception'ı alırsınız. + +Örneğin, başka bir dependency'de veya bir *path operation* içinde çalışan bir kod, bir veritabanı transaction'ını "rollback" yaptıysa ya da başka bir exception oluşturduysa, o exception dependency'nizde size gelir. + +Dolayısıyla `except SomeException` ile dependency içinde o spesifik exception'ı yakalayabilirsiniz. + +Aynı şekilde, exception olsun ya da olmasın çıkış (exit) adımlarının çalıştırılmasını garanti etmek için `finally` kullanabilirsiniz. + +{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *} + +## `yield` ile Alt Dependency'ler { #sub-dependencies-with-yield } + +Her boyutta ve şekilde alt dependency'ler ve alt dependency "ağaçları" (trees) oluşturabilirsiniz; bunların herhangi biri veya hepsi `yield` kullanabilir. + +**FastAPI**, `yield` kullanan her dependency'deki "exit code"'un doğru sırayla çalıştırılmasını sağlar. + +Örneğin, `dependency_c`, `dependency_b`'ye; `dependency_b` de `dependency_a`'ya bağlı olabilir: + +{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *} + +Ve hepsi `yield` kullanabilir. + +Bu durumda `dependency_c`, exit code'unu çalıştırabilmek için `dependency_b`'den gelen değerin (burada `dep_b`) hâlâ erişilebilir olmasına ihtiyaç duyar. + +Aynı şekilde `dependency_b` de exit code'u için `dependency_a`'dan gelen değerin (burada `dep_a`) erişilebilir olmasına ihtiyaç duyar. + +{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *} + +Benzer şekilde, bazı dependency'ler `yield`, bazıları `return` kullanabilir ve bunların bazıları diğerlerine bağlı olabilir. + +Ayrıca birden fazla `yield` kullanan dependency gerektiren tek bir dependency'niz de olabilir, vb. + +İstediğiniz herhangi bir dependency kombinasyonunu kullanabilirsiniz. + +**FastAPI** her şeyin doğru sırada çalışmasını sağlar. + +/// note | Teknik Detaylar + +Bu, Python'un Context Managers yapısı sayesinde çalışır. + +**FastAPI** bunu sağlamak için içeride onları kullanır. + +/// + +## `yield` ve `HTTPException` ile Dependency'ler { #dependencies-with-yield-and-httpexception } + +`yield` kullanan dependency'lerde `try` bloklarıyla bazı kodları çalıştırıp ardından `finally` sonrasında exit code çalıştırabileceğinizi gördünüz. + +Ayrıca `except` ile fırlatılan exception'ı yakalayıp onunla bir şey yapabilirsiniz. + +Örneğin `HTTPException` gibi farklı bir exception fırlatabilirsiniz. + +/// tip | İpucu + +Bu biraz ileri seviye bir tekniktir ve çoğu durumda gerçekten ihtiyaç duymazsınız; çünkü exception'ları (`HTTPException` dahil) uygulamanızın geri kalan kodundan, örneğin *path operation function* içinden fırlatabilirsiniz. + +Ama ihtiyaç duyarsanız diye burada. 🤓 + +/// + +{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *} + +Exception yakalayıp buna göre özel bir response oluşturmak istiyorsanız bir [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} oluşturun. + +## `yield` ve `except` ile Dependency'ler { #dependencies-with-yield-and-except } + +`yield` kullanan bir dependency içinde `except` ile bir exception yakalar ve bunu tekrar fırlatmazsanız (ya da yeni bir exception fırlatmazsanız), FastAPI normal Python'da olduğu gibi bir exception olduğunu fark edemez: + +{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *} + +Bu durumda client, biz `HTTPException` veya benzeri bir şey fırlatmadığımız için olması gerektiği gibi *HTTP 500 Internal Server Error* response'u görür; ancak server **hiç log üretmez** ve hatanın ne olduğuna dair başka bir işaret de olmaz. 😱 + +### `yield` ve `except` Kullanan Dependency'lerde Her Zaman `raise` Edin { #always-raise-in-dependencies-with-yield-and-except } + +`yield` kullanan bir dependency içinde bir exception yakalarsanız, başka bir `HTTPException` veya benzeri bir şey fırlatmıyorsanız, **orijinal exception'ı tekrar raise etmelisiniz**. + +Aynı exception'ı `raise` ile tekrar fırlatabilirsiniz: + +{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *} + +Artık client yine aynı *HTTP 500 Internal Server Error* response'unu alır, ama server log'larda bizim özel `InternalError`'ımızı görür. 😎 + +## `yield` Kullanan Dependency'lerin Çalıştırılması { #execution-of-dependencies-with-yield } + +Çalıştırma sırası kabaca aşağıdaki diyagramdaki gibidir. Zaman yukarıdan aşağı akar. Her sütun, etkileşime giren veya kod çalıştıran parçalardan birini temsil eder. + +```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 | Bilgi + +Client'a yalnızca **tek bir response** gönderilir. Bu, error response'lardan biri olabilir ya da *path operation*'dan dönen response olabilir. + +Bu response'lardan biri gönderildikten sonra başka bir response gönderilemez. + +/// + +/// tip | İpucu + +*Path operation function* içindeki koddan herhangi bir exception raise ederseniz, `HTTPException` dahil olmak üzere bu exception `yield` kullanan dependency'lere aktarılır. Çoğu durumda, doğru şekilde ele alındığından emin olmak için `yield` kullanan dependency'den aynı exception'ı (veya yeni bir tanesini) yeniden raise etmek istersiniz. + +/// + +## Erken Çıkış ve `scope` { #early-exit-and-scope } + +Normalde `yield` kullanan dependency'lerin exit code'u, client'a response gönderildikten **sonra** çalıştırılır. + +Ama *path operation function*'dan döndükten sonra dependency'yi kullanmayacağınızı biliyorsanız, `Depends(scope="function")` kullanarak FastAPI'ye dependency'yi *path operation function* döndükten sonra kapatmasını, ancak **response gönderilmeden önce** kapatmasını söyleyebilirsiniz. + +{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *} + +`Depends()` şu değerleri alabilen bir `scope` parametresi alır: + +* `"function"`: dependency'yi request'i işleyen *path operation function* çalışmadan önce başlat, *path operation function* bittikten sonra bitir, ancak response client'a geri gönderilmeden **önce** sonlandır. Yani dependency fonksiyonu, *path operation **function***'ın **etrafında** çalıştırılır. +* `"request"`: dependency'yi request'i işleyen *path operation function* çalışmadan önce başlat (`"function"` kullanımına benzer), ancak response client'a geri gönderildikten **sonra** sonlandır. Yani dependency fonksiyonu, **request** ve response döngüsünün **etrafında** çalıştırılır. + +Belirtilmezse ve dependency `yield` kullanıyorsa, varsayılan olarak `scope` `"request"` olur. + +### Alt dependency'ler için `scope` { #scope-for-sub-dependencies } + +`scope="request"` (varsayılan) ile bir dependency tanımladığınızda, herhangi bir alt dependency'nin `scope` değeri de `"request"` olmalıdır. + +Ancak `scope` değeri `"function"` olan bir dependency, hem `"function"` hem de `"request"` scope'una sahip dependency'lere bağlı olabilir. + +Bunun nedeni, bir dependency'nin exit code'unu alt dependency'lerden önce çalıştırabilmesi gerekmesidir; çünkü exit code sırasında hâlâ onları kullanması gerekebilir. + +```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 +``` + +## `yield`, `HTTPException`, `except` ve Background Tasks ile Dependency'ler { #dependencies-with-yield-httpexception-except-and-background-tasks } + +`yield` kullanan dependency'ler, zaman içinde farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için gelişti. + +FastAPI'nin farklı sürümlerinde nelerin değiştiğini görmek isterseniz, advanced guide'da şu bölümü okuyabilirsiniz: [Advanced Dependencies - Dependencies with `yield`, `HTTPException`, `except` and Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}. + +## Context Managers { #context-managers } + +### "Context Managers" Nedir? { #what-are-context-managers } + +"Context Managers", `with` ifadesiyle kullanabildiğiniz Python nesneleridir. + +Örneğin, bir dosyayı okumak için `with` kullanabilirsiniz: + +```Python +with open("./somefile.txt") as f: + contents = f.read() + print(contents) +``` + +Temelde `open("./somefile.txt")`, "Context Manager" olarak adlandırılan bir nesne oluşturur. + +`with` bloğu bittiğinde, exception olsa bile dosyanın kapatılmasını garanti eder. + +`yield` ile bir dependency oluşturduğunuzda, **FastAPI** içeride bunun için bir context manager oluşturur ve bazı ilgili başka araçlarla birleştirir. + +### `yield` kullanan dependency'lerde context manager kullanma { #using-context-managers-in-dependencies-with-yield } + +/// warning | Uyarı + +Bu, az çok "ileri seviye" bir fikirdir. + +**FastAPI**'ye yeni başlıyorsanız şimdilik bunu atlamak isteyebilirsiniz. + +/// + +Python'da Context Manager'ları, iki method'a sahip bir class oluşturarak: `__enter__()` ve `__exit__()` yaratabilirsiniz. + +Ayrıca dependency fonksiyonunun içinde `with` veya `async with` ifadeleri kullanarak **FastAPI**'de `yield` kullanan dependency'lerin içinde de kullanabilirsiniz: + +{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *} + +/// tip | İpucu + +Bir context manager oluşturmanın başka bir yolu da şunlardır: + +* `@contextlib.contextmanager` veya +* `@contextlib.asynccontextmanager` + +Bunları, tek bir `yield` içeren bir fonksiyonu decorate etmek için kullanabilirsiniz. + +FastAPI, `yield` kullanan dependency'ler için içeride bunu yapar. + +Ancak FastAPI dependency'leri için bu decorator'ları kullanmak zorunda değilsiniz (hatta kullanmamalısınız). + +FastAPI bunu sizin yerinize içeride yapar. + +/// diff --git a/docs/tr/docs/tutorial/dependencies/global-dependencies.md b/docs/tr/docs/tutorial/dependencies/global-dependencies.md new file mode 100644 index 0000000000..7f0025eaf2 --- /dev/null +++ b/docs/tr/docs/tutorial/dependencies/global-dependencies.md @@ -0,0 +1,16 @@ +# Global Dependencies { #global-dependencies } + +Bazı uygulama türlerinde, tüm uygulama için dependency eklemek isteyebilirsiniz. + +[`dependencies`'i *path operation decorator*'larına ekleyebildiğiniz](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} gibi, `FastAPI` uygulamasına da ekleyebilirsiniz. + +Bu durumda, uygulamadaki tüm *path operation*'lara uygulanırlar: + +{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *} + + +Ve [*path operation decorator*'larına `dependencies` ekleme](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} bölümündeki tüm fikirler hâlâ geçerlidir; ancak bu sefer, uygulamadaki tüm *path operation*'lar için geçerli olur. + +## *Path operations* grupları için Dependencies { #dependencies-for-groups-of-path-operations } + +İleride, daha büyük uygulamaları nasıl yapılandıracağınızı ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md){.internal-link target=_blank}) okurken, muhtemelen birden fazla dosyayla birlikte, bir *path operations* grubu için tek bir `dependencies` parametresini nasıl tanımlayacağınızı öğreneceksiniz. diff --git a/docs/tr/docs/tutorial/dependencies/index.md b/docs/tr/docs/tutorial/dependencies/index.md new file mode 100644 index 0000000000..f1e446d67d --- /dev/null +++ b/docs/tr/docs/tutorial/dependencies/index.md @@ -0,0 +1,250 @@ +# Bağımlılıklar { #dependencies } + +**FastAPI**, çok güçlü ama aynı zamanda sezgisel bir **Dependency Injection** sistemine sahiptir. + +Kullanımı çok basit olacak şekilde tasarlanmıştır ve herhangi bir geliştiricinin diğer bileşenleri **FastAPI** ile entegre etmesini kolaylaştırır. + +## "Dependency Injection" Nedir? { #what-is-dependency-injection } + +Programlamada **"Dependency Injection"**, kodunuzun (bu örnekte *path operation function*'larınızın) çalışmak ve kullanmak için ihtiyaç duyduğu şeyleri: "dependencies" (bağımlılıklar) olarak beyan edebilmesi anlamına gelir. + +Ardından bu sistem (bu örnekte **FastAPI**), kodunuza gerekli bağımlılıkları sağlamak ("inject" etmek) için gereken her şeyi sizin yerinize halleder. + +Bu yaklaşım, şunlara ihtiyaç duyduğunuzda özellikle faydalıdır: + +* Paylaşılan bir mantığa sahip olmak (aynı kod mantığını tekrar tekrar kullanmak). +* Veritabanı bağlantılarını paylaşmak. +* Güvenlik, authentication, rol gereksinimleri vb. kuralları zorunlu kılmak. +* Ve daha birçok şey... + +Tüm bunları, kod tekrarını minimumda tutarak yaparsınız. + +## İlk Adımlar { #first-steps } + +Çok basit bir örneğe bakalım. Şimdilik o kadar basit olacak ki pek işe yaramayacak. + +Ama bu sayede **Dependency Injection** sisteminin nasıl çalıştığına odaklanabiliriz. + +### Bir dependency (bağımlılık) veya "dependable" Oluşturun { #create-a-dependency-or-dependable } + +Önce dependency'e odaklanalım. + +Bu, bir *path operation function*'ın alabileceği parametrelerin aynısını alabilen basit bir fonksiyondur: + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *} + +Bu kadar. + +**2 satır**. + +Ve tüm *path operation function*'larınızla aynı şekle ve yapıya sahiptir. + +Bunu, "decorator" olmadan (yani `@app.get("/some-path")` olmadan) yazılmış bir *path operation function* gibi düşünebilirsiniz. + +Ayrıca istediğiniz herhangi bir şeyi döndürebilir. + +Bu örnekte, bu dependency şunları bekler: + +* `str` olan, opsiyonel bir query parametresi `q`. +* `int` olan, opsiyonel bir query parametresi `skip` ve varsayılanı `0`. +* `int` olan, opsiyonel bir query parametresi `limit` ve varsayılanı `100`. + +Sonra da bu değerleri içeren bir `dict` döndürür. + +/// info | Bilgi + +FastAPI, `Annotated` desteğini 0.95.0 sürümünde ekledi (ve önermeye başladı). + +Daha eski bir sürüm kullanıyorsanız `Annotated` kullanmaya çalıştığınızda hata alırsınız. + +`Annotated` kullanmadan önce **FastAPI** sürümünü en az 0.95.1'e yükseltmek için [FastAPI sürümünü yükseltin](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}. + +/// + +### `Depends`'i Import Edin { #import-depends } + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *} + +### "Dependant" İçinde Dependency'yi Tanımlayın { #declare-the-dependency-in-the-dependant } + +*Path operation function* parametrelerinizde `Body`, `Query` vb. kullandığınız gibi, yeni bir parametreyle `Depends` kullanın: + +{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *} + +Fonksiyon parametrelerinde `Depends`'i `Body`, `Query` vb. ile aynı şekilde kullansanız da `Depends` biraz farklı çalışır. + +`Depends`'e yalnızca tek bir parametre verirsiniz. + +Bu parametre, bir fonksiyon gibi bir şey olmalıdır. + +Onu doğrudan **çağırmazsınız** (sonuna parantez eklemezsiniz), sadece `Depends()`'e parametre olarak verirsiniz. + +Ve bu fonksiyon da, *path operation function*'lar gibi parametre alır. + +/// tip | İpucu + +Fonksiyonların dışında başka hangi "şeylerin" dependency olarak kullanılabildiğini bir sonraki bölümde göreceksiniz. + +/// + +Yeni bir request geldiğinde, **FastAPI** şunları sizin yerinize yapar: + +* Dependency ("dependable") fonksiyonunuzu doğru parametrelerle çağırır. +* Fonksiyonunuzun sonucunu alır. +* Bu sonucu *path operation function*'ınızdaki parametreye atar. + +```mermaid +graph TB + +common_parameters(["common_parameters"]) +read_items["/items/"] +read_users["/users/"] + +common_parameters --> read_items +common_parameters --> read_users +``` + +Bu şekilde paylaşılan kodu bir kez yazarsınız ve onu *path operation*'larda çağırma işini **FastAPI** halleder. + +/// check | Ek bilgi + +Dikkat edin: Bunu "register" etmek ya da benzeri bir şey yapmak için özel bir class oluşturup **FastAPI**'ye bir yere geçirmeniz gerekmez. + +Sadece `Depends`'e verirsiniz ve gerisini **FastAPI** nasıl yapacağını bilir. + +/// + +## `Annotated` Dependency'lerini Paylaşın { #share-annotated-dependencies } + +Yukarıdaki örneklerde, ufak bir **kod tekrarı** olduğunu görüyorsunuz. + +`common_parameters()` dependency'sini kullanmanız gerektiğinde, type annotation ve `Depends()` içeren parametrenin tamamını yazmanız gerekir: + +```Python +commons: Annotated[dict, Depends(common_parameters)] +``` + +Ancak `Annotated` kullandığımız için bu `Annotated` değerini bir değişkende saklayıp birden fazla yerde kullanabiliriz: + +{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *} + +/// tip | İpucu + +Bu aslında standart Python'dır; buna "type alias" denir ve **FastAPI**'ye özel bir şey değildir. + +Ama **FastAPI**, `Annotated` dahil Python standartları üzerine kurulu olduğu için bu tekniği kodunuzda kullanabilirsiniz. 😎 + +/// + +Dependency'ler beklediğiniz gibi çalışmaya devam eder ve **en güzel kısmı** da şudur: **type bilgisi korunur**. Bu da editörünüzün size **autocompletion**, **inline errors** vb. sağlamaya devam edeceği anlamına gelir. `mypy` gibi diğer araçlar için de aynısı geçerlidir. + +Bu özellikle, **büyük bir kod tabanında**, aynı dependency'leri **birçok *path operation*** içinde tekrar tekrar kullandığınızda çok faydalı olacaktır. + +## `async` Olsa da Olmasa da { #to-async-or-not-to-async } + +Dependency'ler de **FastAPI** tarafından çağrılacağı için (tıpkı *path operation function*'larınız gibi), fonksiyonları tanımlarken aynı kurallar geçerlidir. + +`async def` ya da normal `def` kullanabilirsiniz. + +Ayrıca normal `def` *path operation function*'ları içinde `async def` dependency tanımlayabilir veya `async def` *path operation function*'ları içinde `def` dependency kullanabilirsiniz vb. + +Fark etmez. **FastAPI** ne yapacağını bilir. + +/// note | Not + +Eğer bilmiyorsanız, dokümanlarda `async` ve `await` için [Async: *"In a hurry?"*](../../async.md#in-a-hurry){.internal-link target=_blank} bölümüne bakın. + +/// + +## OpenAPI ile Entegre { #integrated-with-openapi } + +Dependency'lerinizin (ve alt dependency'lerin) tüm request tanımları, doğrulamaları ve gereksinimleri aynı OpenAPI şemasına entegre edilir. + +Bu nedenle interaktif dokümanlar, bu dependency'lerden gelen tüm bilgileri de içerir: + + + +## Basit Kullanım { #simple-usage } + +Şöyle düşünürseniz: *Path operation function*'lar, bir *path* ve *operation* eşleştiğinde kullanılacak şekilde tanımlanır; ardından **FastAPI** fonksiyonu doğru parametrelerle çağırır ve request'ten veriyi çıkarır. + +Aslında tüm (veya çoğu) web framework'ü de aynı şekilde çalışır. + +Bu fonksiyonları hiçbir zaman doğrudan çağırmazsınız. Onları framework'ünüz (bu örnekte **FastAPI**) çağırır. + +Dependency Injection sistemiyle, *path operation function*'ınızın, ondan önce çalıştırılması gereken başka bir şeye de "bağlı" olduğunu **FastAPI**'ye söyleyebilirsiniz; **FastAPI** bunu çalıştırır ve sonuçları "inject" eder. + +Aynı "dependency injection" fikri için kullanılan diğer yaygın terimler: + +* resources +* providers +* services +* injectables +* components + +## **FastAPI** Plug-in'leri { #fastapi-plug-ins } + +Entegrasyonlar ve "plug-in"ler **Dependency Injection** sistemi kullanılarak inşa edilebilir. Ancak aslında **"plug-in" oluşturmanıza gerek yoktur**; çünkü dependency'leri kullanarak *path operation function*'larınıza sunulabilecek sınırsız sayıda entegrasyon ve etkileşim tanımlayabilirsiniz. + +Dependency'ler, çok basit ve sezgisel bir şekilde oluşturulabilir. Böylece ihtiyacınız olan Python package'larını import edip, API fonksiyonlarınızla birkaç satır kodla *kelimenin tam anlamıyla* entegre edebilirsiniz. + +İlerleyen bölümlerde ilişkisel ve NoSQL veritabanları, güvenlik vb. konularda bunun örneklerini göreceksiniz. + +## **FastAPI** Uyumluluğu { #fastapi-compatibility } + +Dependency injection sisteminin sadeliği, **FastAPI**'yi şunlarla uyumlu hale getirir: + +* tüm ilişkisel veritabanları +* NoSQL veritabanları +* harici paketler +* harici API'ler +* authentication ve authorization sistemleri +* API kullanım izleme (monitoring) sistemleri +* response verisi injection sistemleri +* vb. + +## Basit ve Güçlü { #simple-and-powerful } + +Hiyerarşik dependency injection sistemi tanımlamak ve kullanmak çok basit olsa da, hâlâ oldukça güçlüdür. + +Kendileri de dependency tanımlayabilen dependency'ler tanımlayabilirsiniz. + +Sonuçta hiyerarşik bir dependency ağacı oluşur ve **Dependency Injection** sistemi tüm bu dependency'leri (ve alt dependency'lerini) sizin için çözer ve her adımda sonuçları sağlar ("inject" eder). + +Örneğin, 4 API endpoint'iniz (*path operation*) olduğunu varsayalım: + +* `/items/public/` +* `/items/private/` +* `/users/{user_id}/activate` +* `/items/pro/` + +O zaman her biri için farklı izin gereksinimlerini yalnızca dependency'ler ve alt dependency'lerle ekleyebilirsiniz: + +```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 +``` + +## **OpenAPI** ile Entegre { #integrated-with-openapi_1 } + +Bu dependency'lerin tümü, gereksinimlerini beyan ederken aynı zamanda *path operation*'larınıza parametreler, doğrulamalar vb. da ekler. + +**FastAPI**, bunların hepsini OpenAPI şemasına eklemekle ilgilenir; böylece interaktif dokümantasyon sistemlerinde gösterilir. diff --git a/docs/tr/docs/tutorial/dependencies/sub-dependencies.md b/docs/tr/docs/tutorial/dependencies/sub-dependencies.md new file mode 100644 index 0000000000..184db839bc --- /dev/null +++ b/docs/tr/docs/tutorial/dependencies/sub-dependencies.md @@ -0,0 +1,105 @@ +# Alt Bağımlılıklar { #sub-dependencies } + +**Alt bağımlılıkları** olan bağımlılıklar oluşturabilirsiniz. + +İhtiyacınız olduğu kadar **derine** gidebilirler. + +Bunları çözme işini **FastAPI** üstlenir. + +## İlk bağımlılık "dependable" { #first-dependency-dependable } + +Şöyle bir ilk bağımlılık ("dependable") oluşturabilirsiniz: + +{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *} + +Burada `q` adında opsiyonel bir query parametresi `str` olarak tanımlanır ve sonra doğrudan geri döndürülür. + +Bu oldukça basit (pek faydalı değil), ama alt bağımlılıkların nasıl çalıştığına odaklanmamıza yardımcı olacak. + +## İkinci bağımlılık: "dependable" ve "dependant" { #second-dependency-dependable-and-dependant } + +Ardından, aynı zamanda kendi içinde bir bağımlılık da tanımlayan başka bir bağımlılık fonksiyonu (bir "dependable") oluşturabilirsiniz (yani o da bir "dependant" olur): + +{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *} + +Tanımlanan parametrelere odaklanalım: + +* Bu fonksiyonun kendisi bir bağımlılık ("dependable") olmasına rağmen, ayrıca başka bir bağımlılık daha tanımlar (başka bir şeye "depends" olur). + * `query_extractor`'a bağlıdır ve ondan dönen değeri `q` parametresine atar. +* Ayrıca `last_query` adında opsiyonel bir cookie'yi `str` olarak tanımlar. + * Kullanıcı herhangi bir query `q` sağlamadıysa, daha önce cookie'ye kaydettiğimiz en son kullanılan query'yi kullanırız. + +## Bağımlılığı Kullanma { #use-the-dependency } + +Sonra bu bağımlılığı şöyle kullanabiliriz: + +{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *} + +/// info | Bilgi + +Dikkat edin, *path operation function* içinde yalnızca tek bir bağımlılık tanımlıyoruz: `query_or_cookie_extractor`. + +Ancak **FastAPI**, `query_or_cookie_extractor`'ı çağırmadan önce `query_extractor`'ı önce çözmesi gerektiğini bilir ve onun sonucunu `query_or_cookie_extractor`'a aktarır. + +/// + +```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 +``` + +## Aynı Bağımlılığı Birden Fazla Kez Kullanma { #using-the-same-dependency-multiple-times } + +Bağımlılıklarınızdan biri aynı *path operation* için birden fazla kez tanımlanırsa (örneğin birden fazla bağımlılığın ortak bir alt bağımlılığı varsa), **FastAPI** o alt bağımlılığı request başına yalnızca bir kez çağıracağını bilir. + +Dönen değeri bir "cache" içinde saklar ve aynı request içinde buna ihtiyaç duyan tüm "dependant"lara aktarır; böylece aynı request için bağımlılığı tekrar tekrar çağırmaz. + +Daha ileri bir senaryoda, "cached" değeri kullanmak yerine aynı request içinde her adımda (muhtemelen birden fazla kez) bağımlılığın çağrılması gerektiğini biliyorsanız, `Depends` kullanırken `use_cache=False` parametresini ayarlayabilirsiniz: + +//// tab | Python 3.9+ + +```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.9+ Annotated olmayan + +/// tip | İpucu + +Mümkünse `Annotated` sürümünü tercih edin. + +/// + +```Python hl_lines="1" +async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)): + return {"fresh_value": fresh_value} +``` + +//// + +## Özet { #recap } + +Burada kullanılan havalı terimlerin ötesinde, **Dependency Injection** sistemi aslında oldukça basittir. + +*Path operation function*'lara benzeyen fonksiyonlardan ibarettir. + +Yine de çok güçlüdür ve keyfi derecede derin iç içe geçmiş bağımlılık "graph"ları (ağaçları) tanımlamanıza izin verir. + +/// tip | İpucu + +Bu basit örneklerle çok faydalı görünmeyebilir. + +Ancak **security** ile ilgili bölümlerde bunun ne kadar işe yaradığını göreceksiniz. + +Ayrıca size ne kadar kod kazandırdığını da göreceksiniz. + +/// diff --git a/docs/tr/docs/tutorial/encoder.md b/docs/tr/docs/tutorial/encoder.md new file mode 100644 index 0000000000..e4790a032e --- /dev/null +++ b/docs/tr/docs/tutorial/encoder.md @@ -0,0 +1,35 @@ +# JSON Uyumlu Encoder { #json-compatible-encoder } + +Bazı durumlarda, bir veri tipini (örneğin bir Pydantic model) JSON ile uyumlu bir şeye (örneğin `dict`, `list` vb.) dönüştürmeniz gerekebilir. + +Örneğin, bunu bir veritabanında saklamanız gerekiyorsa. + +Bunun için **FastAPI**, `jsonable_encoder()` fonksiyonunu sağlar. + +## `jsonable_encoder` Kullanımı { #using-the-jsonable-encoder } + +Yalnızca JSON ile uyumlu veri kabul eden bir veritabanınız olduğunu düşünelim: `fake_db`. + +Örneğin bu veritabanı, JSON ile uyumlu olmadıkları için `datetime` objelerini kabul etmez. + +Dolayısıyla bir `datetime` objesinin, ISO formatında veriyi içeren bir `str`'e dönüştürülmesi gerekir. + +Aynı şekilde bu veritabanı bir Pydantic model'i (attribute'lara sahip bir obje) de kabul etmez; yalnızca bir `dict` kabul eder. + +Bunun için `jsonable_encoder` kullanabilirsiniz. + +Bir Pydantic model gibi bir obje alır ve JSON ile uyumlu bir versiyonunu döndürür: + +{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *} + +Bu örnekte, Pydantic model'i bir `dict`'e, `datetime`'ı da bir `str`'e dönüştürür. + +Bu fonksiyonun çağrılmasıyla elde edilen sonuç, Python standardındaki `json.dumps()` ile encode edilebilecek bir şeydir. + +JSON formatında (string olarak) veriyi içeren büyük bir `str` döndürmez. Bunun yerine, tüm değerleri ve alt değerleri JSON ile uyumlu olacak şekilde, Python’un standart bir veri yapısını (örneğin bir `dict`) döndürür. + +/// note | Not + +`jsonable_encoder`, aslında **FastAPI** tarafından veriyi dönüştürmek için internal olarak kullanılır. Ancak birçok farklı senaryoda da oldukça faydalıdır. + +/// diff --git a/docs/tr/docs/tutorial/extra-data-types.md b/docs/tr/docs/tutorial/extra-data-types.md new file mode 100644 index 0000000000..464d3a82a9 --- /dev/null +++ b/docs/tr/docs/tutorial/extra-data-types.md @@ -0,0 +1,62 @@ +# Ek Veri Tipleri { #extra-data-types } + +Şimdiye kadar şunlar gibi yaygın veri tiplerini kullanıyordunuz: + +* `int` +* `float` +* `str` +* `bool` + +Ancak daha karmaşık veri tiplerini de kullanabilirsiniz. + +Ve yine, şimdiye kadar gördüğünüz özelliklerin aynısına sahip olursunuz: + +* Harika editör desteği. +* Gelen request'lerden veri dönüştürme. +* response verileri için veri dönüştürme. +* Veri doğrulama. +* Otomatik annotation ve dokümantasyon. + +## Diğer veri tipleri { #other-data-types } + +Kullanabileceğiniz ek veri tiplerinden bazıları şunlardır: + +* `UUID`: + * Birçok veritabanı ve sistemde ID olarak yaygın kullanılan, standart bir "Universally Unique Identifier". + * request ve response'larda `str` olarak temsil edilir. +* `datetime.datetime`: + * Python `datetime.datetime`. + * request ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15T15:53:00+05:00`. +* `datetime.date`: + * Python `datetime.date`. + * request ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15`. +* `datetime.time`: + * Python `datetime.time`. + * request ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `14:23:55.003`. +* `datetime.timedelta`: + * Python `datetime.timedelta`. + * request ve response'larda toplam saniye sayısını ifade eden bir `float` olarak temsil edilir. + * Pydantic, bunu ayrıca bir "ISO 8601 time diff encoding" olarak temsil etmeye de izin verir, daha fazla bilgi için dokümanlara bakın. +* `frozenset`: + * request ve response'larda, `set` ile aynı şekilde ele alınır: + * request'lerde bir list okunur, tekrarlar kaldırılır ve `set`'e dönüştürülür. + * response'larda `set`, `list`'e dönüştürülür. + * Üretilen schema, `set` değerlerinin benzersiz olduğunu belirtir (JSON Schema'nın `uniqueItems` özelliğini kullanarak). +* `bytes`: + * Standart Python `bytes`. + * request ve response'larda `str` gibi ele alınır. + * Üretilen schema, bunun `binary` "format"ına sahip bir `str` olduğunu belirtir. +* `Decimal`: + * Standart Python `Decimal`. + * request ve response'larda `float` ile aynı şekilde işlenir. +* Geçerli tüm Pydantic veri tiplerini burada görebilirsiniz: Pydantic data types. + +## Örnek { #example } + +Yukarıdaki tiplerden bazılarını kullanan parametrelere sahip bir örnek *path operation* şöyle: + +{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *} + +Fonksiyonun içindeki parametrelerin doğal veri tiplerinde olduğunu unutmayın; örneğin normal tarih işlemleri yapabilirsiniz: + +{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *} diff --git a/docs/tr/docs/tutorial/extra-models.md b/docs/tr/docs/tutorial/extra-models.md new file mode 100644 index 0000000000..9aae28e05f --- /dev/null +++ b/docs/tr/docs/tutorial/extra-models.md @@ -0,0 +1,211 @@ +# Ek Modeller { #extra-models } + +Önceki örnekten devam edersek, birbiriyle ilişkili birden fazla modelin olması oldukça yaygındır. + +Bu durum özellikle kullanıcı modellerinde sık görülür, çünkü: + +* **input modeli** bir `password` içerebilmelidir. +* **output modeli** `password` içermemelidir. +* **database modeli** büyük ihtimalle hash'lenmiş bir `password` tutmalıdır. + +/// danger + +Kullanıcının düz metin (plaintext) `password`'ünü asla saklamayın. Her zaman sonradan doğrulayabileceğiniz "güvenli bir hash" saklayın. + +Eğer bilmiyorsanız, "password hash" nedir konusunu [güvenlik bölümlerinde](security/simple-oauth2.md#password-hashing){.internal-link target=_blank} öğreneceksiniz. + +/// + +## Birden Çok Model { #multiple-models } + +`password` alanlarıyla birlikte modellerin genel olarak nasıl görünebileceğine ve nerelerde kullanılacaklarına dair bir fikir: + +{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} + +### `**user_in.model_dump()` Hakkında { #about-user-in-model-dump } + +#### Pydantic'in `.model_dump()` Metodu { #pydantics-model-dump } + +`user_in`, `UserIn` sınıfına ait bir Pydantic modelidir. + +Pydantic modellerinde, model verilerini içeren bir `dict` döndüren `.model_dump()` metodu bulunur. + +Yani, şöyle bir Pydantic nesnesi `user_in` oluşturursak: + +```Python +user_in = UserIn(username="john", password="secret", email="john.doe@example.com") +``` + +ve sonra şunu çağırırsak: + +```Python +user_dict = user_in.model_dump() +``` + +artık `user_dict` değişkeninde modelin verilerini içeren bir `dict` vardır (Pydantic model nesnesi yerine bir `dict` elde etmiş oluruz). + +Ve eğer şunu çağırırsak: + +```Python +print(user_dict) +``` + +şöyle bir Python `dict` elde ederiz: + +```Python +{ + 'username': 'john', + 'password': 'secret', + 'email': 'john.doe@example.com', + 'full_name': None, +} +``` + +#### Bir `dict`'i Unpack Etmek { #unpacking-a-dict } + +`user_dict` gibi bir `dict` alıp bunu bir fonksiyona (ya da sınıfa) `**user_dict` ile gönderirsek, Python bunu "unpack" eder. Yani `user_dict` içindeki key ve value'ları doğrudan key-value argümanları olarak geçirir. + +Dolayısıyla, yukarıdaki `user_dict` ile devam edersek, şunu yazmak: + +```Python +UserInDB(**user_dict) +``` + +şuna eşdeğer bir sonuç üretir: + +```Python +UserInDB( + username="john", + password="secret", + email="john.doe@example.com", + full_name=None, +) +``` + +Ya da daha net şekilde, `user_dict`'i doğrudan kullanarak, gelecekte içeriği ne olursa olsun: + +```Python +UserInDB( + username = user_dict["username"], + password = user_dict["password"], + email = user_dict["email"], + full_name = user_dict["full_name"], +) +``` + +#### Bir Pydantic Modelinden Diğerinin İçeriğiyle Pydantic Model Oluşturmak { #a-pydantic-model-from-the-contents-of-another } + +Yukarıdaki örnekte `user_dict`'i `user_in.model_dump()` ile elde ettiğimiz için, şu kod: + +```Python +user_dict = user_in.model_dump() +UserInDB(**user_dict) +``` + +şuna eşdeğerdir: + +```Python +UserInDB(**user_in.model_dump()) +``` + +...çünkü `user_in.model_dump()` bir `dict` döndürür ve biz de bunu `UserInDB`'ye `**` önekiyle vererek Python'ın "unpack" etmesini sağlarız. + +Böylece, bir Pydantic modelindeki verilerden başka bir Pydantic model üretmiş oluruz. + +#### Bir `dict`'i Unpack Etmek ve Ek Keyword'ler { #unpacking-a-dict-and-extra-keywords } + +Sonrasında, aşağıdaki gibi ek keyword argümanı `hashed_password=hashed_password` eklemek: + +```Python +UserInDB(**user_in.model_dump(), hashed_password=hashed_password) +``` + +...şuna benzer bir sonuca dönüşür: + +```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 + +Ek destek fonksiyonları olan `fake_password_hasher` ve `fake_save_user` sadece verinin olası bir akışını göstermek içindir; elbette gerçek bir güvenlik sağlamazlar. + +/// + +## Tekrarı Azaltma { #reduce-duplication } + +Kod tekrarını azaltmak, **FastAPI**'nin temel fikirlerinden biridir. + +Kod tekrarı; bug, güvenlik problemi, kodun senkron dışına çıkması (bir yeri güncelleyip diğerlerini güncellememek) gibi sorunların olasılığını artırır. + +Bu modellerin hepsi verinin büyük bir kısmını paylaşıyor ve attribute adlarını ve type'larını tekrar ediyor. + +Daha iyisini yapabiliriz. + +Diğer modellerimiz için temel olacak bir `UserBase` modeli tanımlayabiliriz. Sonra da bu modelden türeyen (subclass) modeller oluşturup onun attribute'larını (type deklarasyonları, doğrulama vb.) miras aldırabiliriz. + +Tüm veri dönüştürme, doğrulama, dokümantasyon vb. her zamanki gibi çalışmaya devam eder. + +Bu sayede modeller arasındaki farkları (plaintext `password` olan, `hashed_password` olan ve `password` olmayan) sadece o farklılıklar olarak tanımlayabiliriz: + +{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *} + +## `Union` veya `anyOf` { #union-or-anyof } + +Bir response'u iki ya da daha fazla type'ın `Union`'ı olarak tanımlayabilirsiniz; bu, response'un bunlardan herhangi biri olabileceği anlamına gelir. + +OpenAPI'de bu `anyOf` ile tanımlanır. + +Bunu yapmak için standart Python type hint'i olan `typing.Union`'ı kullanın: + +/// note + +Bir `Union` tanımlarken en spesifik type'ı önce, daha az spesifik olanı sonra ekleyin. Aşağıdaki örnekte daha spesifik olan `PlaneItem`, `Union[PlaneItem, CarItem]` içinde `CarItem`'dan önce gelir. + +/// + +{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *} + +### Python 3.10'da `Union` { #union-in-python-3-10 } + +Bu örnekte `Union[PlaneItem, CarItem]` değerini `response_model` argümanına veriyoruz. + +Bunu bir **type annotation** içine koymak yerine bir **argümana değer** olarak geçtiğimiz için, Python 3.10'da bile `Union` kullanmamız gerekiyor. + +Eğer bu bir type annotation içinde olsaydı, dikey çizgiyi kullanabilirdik: + +```Python +some_variable: PlaneItem | CarItem +``` + +Ancak bunu `response_model=PlaneItem | CarItem` atamasına koyarsak hata alırız; çünkü Python bunu bir type annotation olarak yorumlamak yerine `PlaneItem` ile `CarItem` arasında **geçersiz bir işlem** yapmaya çalışır. + +## Model Listesi { #list-of-models } + +Aynı şekilde, nesne listesi döndüren response'ları da tanımlayabilirsiniz. + +Bunun için standart Python `typing.List`'i (ya da Python 3.9 ve üzeri için sadece `list`) kullanın: + +{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *} + +## Rastgele `dict` ile Response { #response-with-arbitrary-dict } + +Bir Pydantic modeli kullanmadan, sadece key ve value type'larını belirterek düz, rastgele bir `dict` ile de response tanımlayabilirsiniz. + +Bu, geçerli field/attribute adlarını (Pydantic modeli için gerekli olurdu) önceden bilmiyorsanız kullanışlıdır. + +Bu durumda `typing.Dict` (ya da Python 3.9 ve üzeri için sadece `dict`) kullanabilirsiniz: + +{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *} + +## Özet { #recap } + +Her duruma göre birden fazla Pydantic modeli kullanın ve gerekirse özgürce inheritance uygulayın. + +Bir entity'nin farklı "state"lere sahip olması gerekiyorsa, o entity için tek bir veri modeli kullanmak zorunda değilsiniz. Örneğin `password` içeren, `password_hash` içeren ve `password` içermeyen state'lere sahip kullanıcı "entity"si gibi. diff --git a/docs/tr/docs/tutorial/handling-errors.md b/docs/tr/docs/tutorial/handling-errors.md new file mode 100644 index 0000000000..a4d6937922 --- /dev/null +++ b/docs/tr/docs/tutorial/handling-errors.md @@ -0,0 +1,244 @@ +# Hataları Yönetme { #handling-errors } + +API’nizi kullanan bir client’a hata bildirmek zorunda olduğunuz pek çok durum vardır. + +Bu client; frontend’i olan bir tarayıcı, başka birinin yazdığı bir kod, bir IoT cihazı vb. olabilir. + +Client’a şunları söylemeniz gerekebilir: + +* Client’ın bu işlem için yeterli yetkisi yok. +* Client’ın bu kaynağa erişimi yok. +* Client’ın erişmeye çalıştığı öğe mevcut değil. +* vb. + +Bu durumlarda genellikle **400** aralığında (**400** ile **499** arası) bir **HTTP status code** döndürürsünüz. + +Bu, 200 HTTP status code’larına (200 ile 299 arası) benzer. Bu "200" status code’ları, request’in bir şekilde "başarılı" olduğunu ifade eder. + +400 aralığındaki status code’lar ise hatanın client tarafından kaynaklandığını gösterir. + +Şu meşhur **"404 Not Found"** hatalarını (ve şakalarını) hatırlıyor musunuz? + +## `HTTPException` Kullanma { #use-httpexception } + +Client’a hata içeren HTTP response’ları döndürmek için `HTTPException` kullanırsınız. + +### `HTTPException`’ı Import Etme { #import-httpexception } + +{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *} + +### Kodunuzda Bir `HTTPException` Raise Etme { #raise-an-httpexception-in-your-code } + +`HTTPException`, API’lerle ilgili ek veriler içeren normal bir Python exception’ıdır. + +Python exception’ı olduğu için `return` etmezsiniz, `raise` edersiniz. + +Bu aynı zamanda şunu da ifade eder: *path operation function*’ınızın içinde çağırdığınız bir yardımcı (utility) fonksiyonun içindeyken `HTTPException` raise ederseniz, *path operation function* içindeki kodun geri kalanı çalışmaz; request’i hemen sonlandırır ve `HTTPException` içindeki HTTP hatasını client’a gönderir. + +Bir değer döndürmek yerine exception raise etmenin faydası, Dependencies ve Security bölümünde daha da netleşecektir. + +Bu örnekte, client var olmayan bir ID ile bir item istediğinde, `404` status code’u ile bir exception raise edelim: + +{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *} + +### Ortaya Çıkan Response { #the-resulting-response } + +Client `http://example.com/items/foo` (bir `item_id` `"foo"`) isterse, HTTP status code olarak 200 ve şu JSON response’u alır: + +```JSON +{ + "item": "The Foo Wrestlers" +} +``` + +Ancak client `http://example.com/items/bar` (mevcut olmayan bir `item_id` `"bar"`) isterse, HTTP status code olarak 404 ("not found" hatası) ve şu JSON response’u alır: + +```JSON +{ + "detail": "Item not found" +} +``` + +/// tip | İpucu + +Bir `HTTPException` raise ederken, `detail` parametresine sadece `str` değil, JSON’a dönüştürülebilen herhangi bir değer geçebilirsiniz. + +Örneğin `dict`, `list` vb. geçebilirsiniz. + +Bunlar **FastAPI** tarafından otomatik olarak işlenir ve JSON’a dönüştürülür. + +/// + +## Özel Header’lar Eklemek { #add-custom-headers } + +Bazı durumlarda HTTP hata response’una özel header’lar eklemek faydalıdır. Örneğin bazı güvenlik türlerinde. + +Muhtemelen bunu doğrudan kendi kodunuzda kullanmanız gerekmeyecek. + +Ama ileri seviye bir senaryo için ihtiyaç duyarsanız, özel header’lar ekleyebilirsiniz: + +{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *} + +## Özel Exception Handler’ları Kurmak { #install-custom-exception-handlers } + +Starlette’in aynı exception yardımcı araçlarıyla özel exception handler’lar ekleyebilirsiniz. + +Diyelim ki sizin (ya da kullandığınız bir kütüphanenin) `raise` edebileceği `UnicornException` adında özel bir exception’ınız var. + +Ve bu exception’ı FastAPI ile global olarak handle etmek istiyorsunuz. + +`@app.exception_handler()` ile özel bir exception handler ekleyebilirsiniz: + +{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *} + +Burada `/unicorns/yolo` için request atarsanız, *path operation* bir `UnicornException` `raise` eder. + +Ancak bu, `unicorn_exception_handler` tarafından handle edilir. + +Böylece HTTP status code’u `418` olan, JSON içeriği şu şekilde temiz bir hata response’u alırsınız: + +```JSON +{"message": "Oops! yolo did something. There goes a rainbow..."} +``` + +/// note | Teknik Detaylar + +`from starlette.requests import Request` ve `from starlette.responses import JSONResponse` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir. `Request` için de aynısı geçerlidir. + +/// + +## Varsayılan Exception Handler’ları Override Etmek { #override-the-default-exception-handlers } + +**FastAPI** bazı varsayılan exception handler’lara sahiptir. + +Bu handler’lar, `HTTPException` `raise` ettiğinizde ve request geçersiz veri içerdiğinde varsayılan JSON response’ları döndürmekten sorumludur. + +Bu exception handler’ları kendi handler’larınızla override edebilirsiniz. + +### Request Validation Exception’larını Override Etmek { #override-request-validation-exceptions } + +Bir request geçersiz veri içerdiğinde, **FastAPI** içeride `RequestValidationError` raise eder. + +Ve bunun için varsayılan bir exception handler da içerir. + +Override etmek için `RequestValidationError`’ı import edin ve exception handler’ı `@app.exception_handler(RequestValidationError)` ile decorate edin. + +Exception handler, bir `Request` ve exception’ı alır. + +{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *} + +Artık `/items/foo`’ya giderseniz, şu varsayılan JSON hatası yerine: + +```JSON +{ + "detail": [ + { + "loc": [ + "path", + "item_id" + ], + "msg": "value is not a valid integer", + "type": "type_error.integer" + } + ] +} +``` + +şu şekilde bir metin (text) versiyonu alırsınız: + +``` +Validation errors: +Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer +``` + +### `HTTPException` Hata Handler’ını Override Etmek { #override-the-httpexception-error-handler } + +Benzer şekilde `HTTPException` handler’ını da override edebilirsiniz. + +Örneğin bu hatalar için JSON yerine plain text response döndürmek isteyebilirsiniz: + +{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *} + +/// note | Teknik Detaylar + +`from starlette.responses import PlainTextResponse` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir. + +/// + +/// warning | Uyarı + +`RequestValidationError`, validation hatasının gerçekleştiği dosya adı ve satır bilgilerini içerir; isterseniz bunu log’larınıza ilgili bilgilerle birlikte yazdırabilirsiniz. + +Ancak bu, eğer sadece string’e çevirip bu bilgiyi doğrudan response olarak döndürürseniz sisteminiz hakkında bir miktar bilgi sızdırabileceğiniz anlamına gelir. Bu yüzden burada kod, her bir hatayı ayrı ayrı çıkarıp gösterir. + +/// + +### `RequestValidationError` Body’sini Kullanmak { #use-the-requestvalidationerror-body } + +`RequestValidationError`, geçersiz veriyle aldığı `body`’yi içerir. + +Uygulamanızı geliştirirken body’yi log’lamak, debug etmek, kullanıcıya döndürmek vb. için bunu kullanabilirsiniz. + +{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *} + +Şimdi şu gibi geçersiz bir item göndermeyi deneyin: + +```JSON +{ + "title": "towel", + "size": "XL" +} +``` + +Aldığınız body’yi de içeren, verinin geçersiz olduğunu söyleyen bir response alırsınız: + +```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" + } +} +``` + +#### FastAPI’nin `HTTPException`’ı vs Starlette’in `HTTPException`’ı { #fastapis-httpexception-vs-starlettes-httpexception } + +**FastAPI**’nin kendi `HTTPException`’ı vardır. + +Ve **FastAPI**’nin `HTTPException` hata sınıfı, Starlette’in `HTTPException` hata sınıfından kalıtım alır (inherit). + +Tek fark şudur: **FastAPI**’nin `HTTPException`’ı `detail` alanı için JSON’a çevrilebilir herhangi bir veri kabul ederken, Starlette’in `HTTPException`’ı burada sadece string kabul eder. + +Bu yüzden kodunuzda her zamanki gibi **FastAPI**’nin `HTTPException`’ını raise etmeye devam edebilirsiniz. + +Ancak bir exception handler register ederken, bunu Starlette’in `HTTPException`’ı için register etmelisiniz. + +Böylece Starlette’in internal kodunun herhangi bir bölümü ya da bir Starlette extension/plug-in’i Starlette `HTTPException` raise ederse, handler’ınız bunu yakalayıp (catch) handle edebilir. + +Bu örnekte, iki `HTTPException`’ı da aynı kodda kullanabilmek için Starlette’in exception’ı `StarletteHTTPException` olarak yeniden adlandırılıyor: + +```Python +from starlette.exceptions import HTTPException as StarletteHTTPException +``` + +### **FastAPI**’nin Exception Handler’larını Yeniden Kullanmak { #reuse-fastapis-exception-handlers } + +Exception’ı, **FastAPI**’nin aynı varsayılan exception handler’larıyla birlikte kullanmak isterseniz, varsayılan exception handler’ları `fastapi.exception_handlers` içinden import edip yeniden kullanabilirsiniz: + +{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *} + +Bu örnekte sadece oldukça açıklayıcı bir mesajla hatayı yazdırıyorsunuz; ama fikir anlaşılıyor. Exception’ı kullanıp ardından varsayılan exception handler’ları olduğu gibi yeniden kullanabilirsiniz. diff --git a/docs/tr/docs/tutorial/header-param-models.md b/docs/tr/docs/tutorial/header-param-models.md new file mode 100644 index 0000000000..9170515dcf --- /dev/null +++ b/docs/tr/docs/tutorial/header-param-models.md @@ -0,0 +1,72 @@ +# Header Parametre Modelleri { #header-parameter-models } + +Birbiriyle ilişkili **header parametreleri**nden oluşan bir grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz. + +Bu sayede modeli **birden fazla yerde yeniden kullanabilir**, ayrıca tüm parametreler için doğrulamaları ve metadata bilgilerini tek seferde tanımlayabilirsiniz. 😎 + +/// note | Not + +Bu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir. 🤓 + +/// + +## Pydantic Model ile Header Parametreleri { #header-parameters-with-a-pydantic-model } + +İhtiyacınız olan **header parametreleri**ni bir **Pydantic model** içinde tanımlayın, ardından parametreyi `Header` olarak belirtin: + +{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *} + +**FastAPI**, request içindeki **headers** bölümünden **her alan** için veriyi **çıkarır** ve size tanımladığınız Pydantic model örneğini verir. + +## Dokümanları Kontrol Edin { #check-the-docs } + +Gerekli header'ları `/docs` altındaki doküman arayüzünde görebilirsiniz: + +
+ +
+ +## Ek Header'ları Yasaklayın { #forbid-extra-headers } + +Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değil), kabul etmek istediğiniz header'ları **kısıtlamak** isteyebilirsiniz. + +Pydantic'in model yapılandırmasını kullanarak `extra` alanları `forbid` edebilirsiniz: + +{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *} + +Bir client bazı **ek header'lar** göndermeye çalışırsa, **hata** response'u alır. + +Örneğin client, değeri `plumbus` olan bir `tool` header'ı göndermeye çalışırsa, `tool` header parametresine izin verilmediğini söyleyen bir **hata** response'u alır: + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["header", "tool"], + "msg": "Extra inputs are not permitted", + "input": "plumbus", + } + ] +} +``` + +## Alt Çizgileri Dönüştürmeyi Kapatın { #disable-convert-underscores } + +Normal header parametrelerinde olduğu gibi, parametre adlarında alt çizgi karakterleri olduğunda bunlar **otomatik olarak tireye dönüştürülür**. + +Örneğin kodda `save_data` adlı bir header parametreniz varsa, beklenen HTTP header `save-data` olur ve dokümanlarda da bu şekilde görünür. + +Herhangi bir sebeple bu otomatik dönüşümü kapatmanız gerekiyorsa, header parametreleri için kullandığınız Pydantic model'lerde de bunu devre dışı bırakabilirsiniz. + +{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *} + +/// warning | Uyarı + +`convert_underscores` değerini `False` yapmadan önce, bazı HTTP proxy'lerinin ve server'ların alt çizgi içeren header'ların kullanımına izin vermediğini unutmayın. + +/// + +## Özet { #summary } + +**FastAPI**'de **headers** tanımlamak için **Pydantic model** kullanabilirsiniz. 😎 diff --git a/docs/tr/docs/tutorial/header-params.md b/docs/tr/docs/tutorial/header-params.md new file mode 100644 index 0000000000..ca787f534c --- /dev/null +++ b/docs/tr/docs/tutorial/header-params.md @@ -0,0 +1,91 @@ +# Header Parametreleri { #header-parameters } + +`Query`, `Path` ve `Cookie` parametrelerini nasıl tanımlıyorsanız, Header parametrelerini de aynı şekilde tanımlayabilirsiniz. + +## `Header`'ı Import Edin { #import-header } + +Önce `Header`'ı import edin: + +{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *} + +## `Header` Parametrelerini Tanımlayın { #declare-header-parameters } + +Ardından header parametrelerini, `Path`, `Query` ve `Cookie` ile kullandığınız yapının aynısıyla tanımlayın. + +Default değeri ve ek validation ya da annotation parametrelerinin tamamını belirleyebilirsiniz: + +{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *} + +/// note | Teknik Detaylar + +`Header`, `Path`, `Query` ve `Cookie`'nin "kardeş" sınıfıdır. Ayrıca aynı ortak `Param` sınıfından kalıtım alır. + +Ancak şunu unutmayın: `fastapi`'den `Query`, `Path`, `Header` ve diğerlerini import ettiğinizde, bunlar aslında özel sınıfları döndüren fonksiyonlardır. + +/// + +/// info | Bilgi + +Header'ları tanımlamak için `Header` kullanmanız gerekir; aksi halde parametreler query parametreleri olarak yorumlanır. + +/// + +## Otomatik Dönüştürme { #automatic-conversion } + +`Header`, `Path`, `Query` ve `Cookie`'nin sağladıklarına ek olarak küçük bir ekstra işlevsellik sunar. + +Standart header'ların çoğu, "hyphen" karakteri (diğer adıyla "minus symbol" (`-`)) ile ayrılır. + +Ancak `user-agent` gibi bir değişken adı Python'da geçersizdir. + +Bu yüzden, default olarak `Header`, header'ları almak ve dokümante etmek için parametre adlarındaki underscore (`_`) karakterlerini hyphen (`-`) ile dönüştürür. + +Ayrıca HTTP header'ları büyük/küçük harfe duyarlı değildir; dolayısıyla onları standart Python stiliyle (diğer adıyla "snake_case") tanımlayabilirsiniz. + +Yani `User_Agent` gibi bir şey yazıp ilk harfleri büyütmeniz gerekmeden, Python kodunda normalde kullandığınız gibi `user_agent` kullanabilirsiniz. + +Herhangi bir nedenle underscore'ların hyphen'lara otomatik dönüştürülmesini kapatmanız gerekirse, `Header`'ın `convert_underscores` parametresini `False` yapın: + +{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *} + +/// warning | Uyarı + +`convert_underscores`'u `False` yapmadan önce, bazı HTTP proxy'lerinin ve server'ların underscore içeren header'ların kullanımına izin vermediğini unutmayın. + +/// + +## Yinelenen Header'lar { #duplicate-headers } + +Yinelenen header'lar almak mümkündür. Yani aynı header'ın birden fazla değeri olabilir. + +Bu tür durumları, type tanımında bir list kullanarak belirtebilirsiniz. + +Yinelenen header'daki tüm değerleri Python `list` olarak alırsınız. + +Örneğin, birden fazla kez gelebilen `X-Token` header'ını tanımlamak için şöyle yazabilirsiniz: + +{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *} + +Eğer bu *path operation* ile iki HTTP header göndererek iletişim kurarsanız: + +``` +X-Token: foo +X-Token: bar +``` + +response şöyle olur: + +```JSON +{ + "X-Token values": [ + "bar", + "foo" + ] +} +``` + +## Özet { #recap } + +Header'ları `Header` ile tanımlayın; `Query`, `Path` ve `Cookie` ile kullanılan ortak kalıbı burada da kullanın. + +Değişkenlerinizdeki underscore'lar konusunda endişelenmeyin, **FastAPI** bunları dönüştürmeyi halleder. diff --git a/docs/tr/docs/tutorial/index.md b/docs/tr/docs/tutorial/index.md new file mode 100644 index 0000000000..f672c9e20b --- /dev/null +++ b/docs/tr/docs/tutorial/index.md @@ -0,0 +1,95 @@ +# Eğitim - Kullanıcı Rehberi { #tutorial-user-guide } + +Bu eğitim, **FastAPI**'yi özelliklerinin çoğuyla birlikte adım adım nasıl kullanacağınızı gösterir. + +Her bölüm bir öncekilerin üzerine kademeli olarak eklenir, ancak konular birbirinden ayrılacak şekilde yapılandırılmıştır; böylece API ihtiyaçlarınıza göre doğrudan belirli bir konuya gidip aradığınızı bulabilirsiniz. + +Ayrıca, ileride tekrar dönüp tam olarak ihtiyaç duyduğunuz şeyi görebileceğiniz bir referans olarak da tasarlanmıştır. + +## Kodu Çalıştırın { #run-the-code } + +Tüm code block'lar kopyalanıp doğrudan kullanılabilir (zaten test edilmiş Python dosyalarıdır). + +Örneklerden herhangi birini çalıştırmak için, kodu `main.py` adlı bir dosyaya kopyalayın ve şu komutla `fastapi dev`'i başlatın: + +
+ +```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. +``` + +
+ +Kodu yazmanız ya da kopyalayıp düzenlemeniz ve yerelinizde çalıştırmanız **şiddetle önerilir**. + +Editörünüzde kullanmak FastAPI'nin avantajlarını gerçekten gösterir: ne kadar az kod yazmanız gerektiğini, type check'leri, autocompletion'ı vb. görürsünüz. + +--- + +## FastAPI'yi Kurun { #install-fastapi } + +İlk adım FastAPI'yi kurmaktır. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan emin olun, etkinleştirin ve ardından **FastAPI'yi kurun**: + +
+ +```console +$ pip install "fastapi[standard]" + +---> 100% +``` + +
+ +/// note | Not + +`pip install "fastapi[standard]"` ile kurduğunuzda, bazı varsayılan opsiyonel standard bağımlılıklarla birlikte gelir. Bunlara `fastapi-cloud-cli` da dahildir; bu sayede FastAPI Cloud'a deploy edebilirsiniz. + +Bu opsiyonel bağımlılıkları istemiyorsanız bunun yerine `pip install fastapi` kurabilirsiniz. + +Standard bağımlılıkları kurmak istiyor ama `fastapi-cloud-cli` olmasın diyorsanız, `pip install "fastapi[standard-no-fastapi-cloud-cli]"` ile kurabilirsiniz. + +/// + +## İleri Düzey Kullanıcı Rehberi { #advanced-user-guide } + +Bu **Eğitim - Kullanıcı Rehberi**'ni bitirdikten sonra daha sonra okuyabileceğiniz bir **İleri Düzey Kullanıcı Rehberi** de var. + +**İleri Düzey Kullanıcı Rehberi** bunun üzerine inşa eder, aynı kavramları kullanır ve size bazı ek özellikler öğretir. + +Ancak önce **Eğitim - Kullanıcı Rehberi**'ni (şu anda okuduğunuz bölümü) okumalısınız. + +Yalnızca **Eğitim - Kullanıcı Rehberi** ile eksiksiz bir uygulama oluşturabilmeniz hedeflenmiştir; ardından ihtiyaçlarınıza göre, **İleri Düzey Kullanıcı Rehberi**'ndeki ek fikirlerden bazılarını kullanarak farklı şekillerde genişletebilirsiniz. diff --git a/docs/tr/docs/tutorial/metadata.md b/docs/tr/docs/tutorial/metadata.md new file mode 100644 index 0000000000..dacd68cf56 --- /dev/null +++ b/docs/tr/docs/tutorial/metadata.md @@ -0,0 +1,120 @@ +# Metadata ve Doküman URL'leri { #metadata-and-docs-urls } + +**FastAPI** uygulamanızda çeşitli metadata yapılandırmalarını özelleştirebilirsiniz. + +## API için Metadata { #metadata-for-api } + +OpenAPI spesifikasyonunda ve otomatik API doküman arayüzlerinde kullanılan şu alanları ayarlayabilirsiniz: + +| Parametre | Tip | Açıklama | +|------------|------|-------------| +| `title` | `str` | API'nin başlığı. | +| `summary` | `str` | API'nin kısa özeti. OpenAPI 3.1.0, FastAPI 0.99.0 sürümünden itibaren mevcut. | +| `description` | `str` | API'nin kısa açıklaması. Markdown kullanabilir. | +| `version` | `string` | API'nin sürümü. Bu, OpenAPI'nin değil, kendi uygulamanızın sürümüdür. Örneğin `2.5.0`. | +| `terms_of_service` | `str` | API'nin Kullanım Koşulları (Terms of Service) için bir URL. Verilirse, URL formatında olmalıdır. | +| `contact` | `dict` | Yayınlanan API için iletişim bilgileri. Birden fazla alan içerebilir.
contact alanları
ParametreTipAçıklama
namestrİletişim kişisi/kuruluşunu tanımlayan ad.
urlstrİletişim bilgilerine işaret eden URL. URL formatında OLMALIDIR.
emailstrİletişim kişisi/kuruluşunun e-posta adresi. E-posta adresi formatında OLMALIDIR.
| +| `license_info` | `dict` | Yayınlanan API için lisans bilgileri. Birden fazla alan içerebilir.
license_info alanları
ParametreTipAçıklama
namestrZORUNLU (license_info ayarlanmışsa). API için kullanılan lisans adı.
identifierstrAPI için bir SPDX lisans ifadesi. identifier alanı, url alanıyla karşılıklı olarak dışlayıcıdır (ikisi aynı anda kullanılamaz). OpenAPI 3.1.0, FastAPI 0.99.0 sürümünden itibaren mevcut.
urlstrAPI için kullanılan lisansa ait URL. URL formatında OLMALIDIR.
| + +Şu şekilde ayarlayabilirsiniz: + +{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *} + +/// tip | İpucu + +`description` alanına Markdown yazabilirsiniz; çıktı tarafında render edilir. + +/// + +Bu yapılandırmayla otomatik API dokümanları şöyle görünür: + + + +## License identifier { #license-identifier } + +OpenAPI 3.1.0 ve FastAPI 0.99.0 sürümünden itibaren, `license_info` içinde `url` yerine bir `identifier` da ayarlayabilirsiniz. + +Örneğin: + +{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *} + +## Tag'ler için Metadata { #metadata-for-tags } + +`openapi_tags` parametresiyle, path operation'larınızı gruplamak için kullandığınız farklı tag'ler adına ek metadata da ekleyebilirsiniz. + +Bu parametre, her tag için bir sözlük (dictionary) içeren bir liste alır. + +Her sözlük şunları içerebilir: + +* `name` (**zorunlu**): *path operation*'larda ve `APIRouter`'larda `tags` parametresinde kullandığınız tag adıyla aynı olan bir `str`. +* `description`: tag için kısa bir açıklama içeren `str`. Markdown içerebilir ve doküman arayüzünde gösterilir. +* `externalDocs`: harici dokümanları tanımlayan bir `dict`: + * `description`: harici dokümanlar için kısa açıklama içeren `str`. + * `url` (**zorunlu**): harici dokümantasyonun URL'sini içeren `str`. + +### Tag'ler için metadata oluşturun { #create-metadata-for-tags } + +`users` ve `items` tag'lerini içeren bir örnekle deneyelim. + +Tag'leriniz için metadata oluşturup `openapi_tags` parametresine geçin: + +{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *} + +Açıklamaların içinde Markdown kullanabileceğinizi unutmayın; örneğin "login" kalın (**login**) ve "fancy" italik (_fancy_) olarak gösterilecektir. + +/// tip | İpucu + +Kullandığınız tüm tag'ler için metadata eklemek zorunda değilsiniz. + +/// + +### Tag'lerinizi kullanın { #use-your-tags } + +*path operation*'larınızı (ve `APIRouter`'ları) farklı tag'lere atamak için `tags` parametresini kullanın: + +{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *} + +/// info | Bilgi + +Tag'ler hakkında daha fazlası için: [Path Operation Configuration](path-operation-configuration.md#tags){.internal-link target=_blank}. + +/// + +### Dokümanları kontrol edin { #check-the-docs } + +Artık dokümanlara baktığınızda, eklediğiniz tüm metadata gösterilir: + + + +### Tag sırası { #order-of-tags } + +Her tag metadata sözlüğünün listedeki sırası, doküman arayüzünde gösterilecek sırayı da belirler. + +Örneğin alfabetik sıralamada `users`, `items`'tan sonra gelirdi; ancak listedeki ilk sözlük olarak `users` metadata'sını eklediğimiz için, dokümanlarda önce o görünür. + +## OpenAPI URL'si { #openapi-url } + +Varsayılan olarak OpenAPI şeması `/openapi.json` adresinden sunulur. + +Ancak bunu `openapi_url` parametresiyle yapılandırabilirsiniz. + +Örneğin `/api/v1/openapi.json` adresinden sunulacak şekilde ayarlamak için: + +{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *} + +OpenAPI şemasını tamamen kapatmak isterseniz `openapi_url=None` ayarlayabilirsiniz; bu, onu kullanan dokümantasyon arayüzlerini de devre dışı bırakır. + +## Doküman URL'leri { #docs-urls } + +Dahil gelen iki dokümantasyon arayüzünü yapılandırabilirsiniz: + +* **Swagger UI**: `/docs` adresinden sunulur. + * URL'sini `docs_url` parametresiyle ayarlayabilirsiniz. + * `docs_url=None` ayarlayarak devre dışı bırakabilirsiniz. +* **ReDoc**: `/redoc` adresinden sunulur. + * URL'sini `redoc_url` parametresiyle ayarlayabilirsiniz. + * `redoc_url=None` ayarlayarak devre dışı bırakabilirsiniz. + +Örneğin Swagger UI'yi `/documentation` adresinden sunup ReDoc'u kapatmak için: + +{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *} diff --git a/docs/tr/docs/tutorial/middleware.md b/docs/tr/docs/tutorial/middleware.md new file mode 100644 index 0000000000..68222265e7 --- /dev/null +++ b/docs/tr/docs/tutorial/middleware.md @@ -0,0 +1,95 @@ +# Middleware { #middleware } + +**FastAPI** uygulamalarına middleware ekleyebilirsiniz. + +"Middleware", herhangi bir özel *path operation* tarafından işlenmeden önce her **request** ile çalışan bir fonksiyondur. Ayrıca geri döndürmeden önce her **response** ile de çalışır. + +* Uygulamanıza gelen her **request**'i alır. +* Ardından o **request** üzerinde bir işlem yapabilir veya gerekli herhangi bir kodu çalıştırabilir. +* Sonra **request**'i uygulamanın geri kalanı tarafından işlenmesi için iletir (bir *path operation* tarafından). +* Ardından uygulama tarafından üretilen **response**'u alır (bir *path operation* tarafından). +* Sonra o **response** üzerinde bir işlem yapabilir veya gerekli herhangi bir kodu çalıştırabilir. +* Son olarak **response**'u döndürür. + +/// note | Teknik Detaylar + +`yield` ile dependency'leriniz varsa, çıkış (exit) kodu middleware'den *sonra* çalışır. + +Herhangi bir background task varsa ([Background Tasks](background-tasks.md){.internal-link target=_blank} bölümünde ele alınıyor, ileride göreceksiniz), bunlar tüm middleware'ler *tamamlandıktan sonra* çalışır. + +/// + +## Middleware Oluşturma { #create-a-middleware } + +Bir middleware oluşturmak için bir fonksiyonun üzerine `@app.middleware("http")` decorator'ünü kullanırsınız. + +Middleware fonksiyonu şunları alır: + +* `request`. +* Parametre olarak `request` alacak bir `call_next` fonksiyonu. + * Bu fonksiyon `request`'i ilgili *path operation*'a iletir. + * Ardından ilgili *path operation* tarafından üretilen `response`'u döndürür. +* Sonrasında `response`'u döndürmeden önce ayrıca değiştirebilirsiniz. + +{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *} + +/// tip | İpucu + +Özel (proprietary) header'lar `X-` prefix'i kullanılarak eklenebilir, bunu aklınızda tutun. + +Ancak tarayıcıdaki bir client'ın görebilmesini istediğiniz özel header'larınız varsa, bunları CORS konfigürasyonlarınıza ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) eklemeniz gerekir. Bunun için, Starlette'ın CORS dokümanlarında belgelenen `expose_headers` parametresini kullanın. + +/// + +/// note | Teknik Detaylar + +`from starlette.requests import Request` da kullanabilirdiniz. + +**FastAPI** bunu geliştirici olarak size kolaylık olsun diye sunar. Ancak doğrudan Starlette'tan gelir. + +/// + +### `response`'tan Önce ve Sonra { #before-and-after-the-response } + +Herhangi bir *path operation* `request`'i almadan önce, `request` ile birlikte çalışacak kod ekleyebilirsiniz. + +Ayrıca `response` üretildikten sonra, geri döndürmeden önce de kod çalıştırabilirsiniz. + +Örneğin, request'i işleyip response üretmenin kaç saniye sürdüğünü içeren `X-Process-Time` adlı özel bir header ekleyebilirsiniz: + +{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *} + +/// tip | İpucu + +Burada `time.time()` yerine `time.perf_counter()` kullanıyoruz, çünkü bu kullanım senaryolarında daha hassas olabilir. 🤓 + +/// + +## Birden Fazla Middleware Çalıştırma Sırası { #multiple-middleware-execution-order } + +`@app.middleware()` decorator'ü veya `app.add_middleware()` metodu ile birden fazla middleware eklediğinizde, eklenen her yeni middleware uygulamayı sarar ve bir stack oluşturur. En son eklenen middleware en *dıştaki* (outermost), ilk eklenen ise en *içteki* (innermost) olur. + +Request tarafında önce en *dıştaki* middleware çalışır. + +Response tarafında ise en son o çalışır. + +Örneğin: + +```Python +app.add_middleware(MiddlewareA) +app.add_middleware(MiddlewareB) +``` + +Bu, aşağıdaki çalıştırma sırasını oluşturur: + +* **Request**: MiddlewareB → MiddlewareA → route + +* **Response**: route → MiddlewareA → MiddlewareB + +Bu stack davranışı, middleware'lerin öngörülebilir ve kontrol edilebilir bir sırayla çalıştırılmasını sağlar. + +## Diğer Middleware'ler { #other-middlewares } + +Diğer middleware'ler hakkında daha fazlasını daha sonra [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank} bölümünde okuyabilirsiniz. + +Bir sonraki bölümde, middleware ile CORS'un nasıl ele alınacağını göreceksiniz. diff --git a/docs/tr/docs/tutorial/path-operation-configuration.md b/docs/tr/docs/tutorial/path-operation-configuration.md new file mode 100644 index 0000000000..610b863a4a --- /dev/null +++ b/docs/tr/docs/tutorial/path-operation-configuration.md @@ -0,0 +1,107 @@ +# Path Operation Yapılandırması { #path-operation-configuration } + +Onu yapılandırmak için *path operation decorator*’ınıza geçebileceğiniz çeşitli parametreler vardır. + +/// warning | Uyarı + +Bu parametrelerin *path operation function*’ınıza değil, doğrudan *path operation decorator*’ına verildiğine dikkat edin. + +/// + +## Response Status Code { #response-status-code } + +*Path operation*’ınızın response’unda kullanılacak (HTTP) `status_code`’u tanımlayabilirsiniz. + +`404` gibi `int` kodu doğrudan verebilirsiniz. + +Ancak her sayısal kodun ne işe yaradığını hatırlamıyorsanız, `status` içindeki kısayol sabitlerini kullanabilirsiniz: + +{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *} + +Bu status code response’da kullanılacak ve OpenAPI şemasına eklenecektir. + +/// note | Teknik Detaylar + +`from starlette import status` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak işinizi kolaylaştırmak için `starlette.status`’u `fastapi.status` olarak da sunar. Ancak kaynağı doğrudan Starlette’tir. + +/// + +## Tags { #tags } + +*Path operation*’ınıza tag ekleyebilirsiniz; `tags` parametresine `str` öğelerinden oluşan bir `list` verin (genellikle tek bir `str`): + +{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *} + +Bunlar OpenAPI şemasına eklenecek ve otomatik dokümantasyon arayüzleri tarafından kullanılacaktır: + + + +### Enum ile Tags { #tags-with-enums } + +Büyük bir uygulamanız varsa, zamanla **birden fazla tag** birikebilir ve ilişkili *path operation*’lar için her zaman **aynı tag**’i kullandığınızdan emin olmak isteyebilirsiniz. + +Bu durumlarda tag’leri bir `Enum` içinde tutmak mantıklı olabilir. + +**FastAPI** bunu düz string’lerde olduğu gibi aynı şekilde destekler: + +{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *} + +## Özet ve açıklama { #summary-and-description } + +Bir `summary` ve `description` ekleyebilirsiniz: + +{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *} + +## Docstring’den Description { #description-from-docstring } + +Açıklamalar genelde uzun olur ve birden fazla satıra yayılır; bu yüzden *path operation* açıklamasını, fonksiyonun içinde docstring olarak tanımlayabilirsiniz; **FastAPI** de onu buradan okur. + +Docstring içinde Markdown yazabilirsiniz; doğru şekilde yorumlanır ve gösterilir (docstring girintisi dikkate alınarak). + +{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *} + +Interactive docs’ta şöyle kullanılacaktır: + + + +## Response description { #response-description } + +`response_description` parametresi ile response açıklamasını belirtebilirsiniz: + +{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *} + +/// info | Bilgi + +`response_description` özellikle response’u ifade eder; `description` ise genel olarak *path operation*’ı ifade eder. + +/// + +/// check | Ek bilgi + +OpenAPI, her *path operation* için bir response description zorunlu kılar. + +Bu yüzden siz sağlamazsanız, **FastAPI** otomatik olarak "Successful response" üretir. + +/// + + + +## Bir *path operation*’ı Deprecate Etmek { #deprecate-a-path-operation } + +Bir *path operation*’ı kaldırmadan, deprecated olarak işaretlemeniz gerekiyorsa `deprecated` parametresini verin: + +{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} + +Interactive docs’ta deprecated olduğu net şekilde işaretlenecektir: + + + +Deprecated olan ve olmayan *path operation*’ların nasıl göründüğüne bakın: + + + +## Özet { #recap } + +*Path operation*’larınızı, *path operation decorator*’larına parametre geçirerek kolayca yapılandırabilir ve metadata ekleyebilirsiniz. diff --git a/docs/tr/docs/tutorial/path-params-numeric-validations.md b/docs/tr/docs/tutorial/path-params-numeric-validations.md new file mode 100644 index 0000000000..e0118d71da --- /dev/null +++ b/docs/tr/docs/tutorial/path-params-numeric-validations.md @@ -0,0 +1,154 @@ +# Path Parametreleri ve Sayısal Doğrulamalar { #path-parameters-and-numeric-validations } + +`Query` ile query parametreleri için daha fazla doğrulama ve metadata tanımlayabildiğiniz gibi, `Path` ile de path parametreleri için aynı tür doğrulama ve metadata tanımlayabilirsiniz. + +## `Path`'i İçe Aktarın { #import-path } + +Önce `fastapi` içinden `Path`'i ve `Annotated`'ı içe aktarın: + +{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *} + +/// info | Bilgi + +FastAPI, 0.95.0 sürümünde `Annotated` desteğini ekledi (ve bunu önermeye başladı). + +Daha eski bir sürüm kullanıyorsanız, `Annotated` kullanmaya çalıştığınızda hata alırsınız. + +`Annotated` kullanmadan önce mutlaka FastAPI sürümünü en az 0.95.1 olacak şekilde [FastAPI sürümünü yükseltin](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}. + +/// + +## Metadata Tanımlayın { #declare-metadata } + +`Query` için geçerli olan parametrelerin aynısını tanımlayabilirsiniz. + +Örneğin, `item_id` path parametresi için bir `title` metadata değeri tanımlamak isterseniz şunu yazabilirsiniz: + +{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *} + +/// note | Not + +Bir path parametresi her zaman zorunludur, çünkü path'in bir parçası olmak zorundadır. `None` ile tanımlasanız veya bir varsayılan değer verseniz bile bu hiçbir şeyi değiştirmez; yine her zaman zorunlu olur. + +/// + +## Parametreleri İhtiyacınıza Göre Sıralayın { #order-the-parameters-as-you-need } + +/// tip | İpucu + +`Annotated` kullanıyorsanız, bu muhtemelen o kadar önemli ya da gerekli değildir. + +/// + +Diyelim ki query parametresi `q`'yu zorunlu bir `str` olarak tanımlamak istiyorsunuz. + +Ayrıca bu parametre için başka bir şey tanımlamanız gerekmiyor; dolayısıyla `Query` kullanmanıza da aslında gerek yok. + +Ancak `item_id` path parametresi için yine de `Path` kullanmanız gerekiyor. Ve bir sebepten `Annotated` kullanmak istemiyorsunuz. + +Python, "default" değeri olan bir parametreyi, "default" değeri olmayan bir parametreden önce yazarsanız şikayet eder. + +Ama bunların sırasını değiştirebilir ve default değeri olmayan parametreyi (query parametresi `q`) en başa koyabilirsiniz. + +Bu **FastAPI** için önemli değildir. FastAPI parametreleri isimlerine, tiplerine ve default tanımlarına (`Query`, `Path`, vb.) göre tespit eder; sırayla ilgilenmez. + +Dolayısıyla fonksiyonunuzu şöyle tanımlayabilirsiniz: + +{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} + +Ancak şunu unutmayın: `Annotated` kullanırsanız bu problem olmaz; çünkü `Query()` veya `Path()` için fonksiyon parametresi default değerlerini kullanmıyorsunuz. + +{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *} + +## Parametreleri İhtiyacınıza Göre Sıralayın: Küçük Hileler { #order-the-parameters-as-you-need-tricks } + +/// tip | İpucu + +`Annotated` kullanıyorsanız, bu muhtemelen o kadar önemli ya da gerekli değildir. + +/// + +İşte bazen işe yarayan **küçük bir hile**; ama çok sık ihtiyacınız olmayacak. + +Şunları yapmak istiyorsanız: + +* `q` query parametresini `Query` kullanmadan ve herhangi bir default değer vermeden tanımlamak +* `item_id` path parametresini `Path` kullanarak tanımlamak +* bunları farklı bir sırada yazmak +* `Annotated` kullanmamak + +...Python bunun için küçük, özel bir sözdizimi sunar. + +Fonksiyonun ilk parametresi olarak `*` geçin. + +Python bu `*` ile bir şey yapmaz; ama bundan sonraki tüm parametrelerin keyword argument (anahtar-değer çiftleri) olarak çağrılması gerektiğini bilir; buna kwargs da denir. Default değerleri olmasa bile. + +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} + +### `Annotated` ile Daha İyi { #better-with-annotated } + +Şunu da unutmayın: `Annotated` kullanırsanız, fonksiyon parametresi default değerlerini kullanmadığınız için bu sorun ortaya çıkmaz ve muhtemelen `*` kullanmanız da gerekmez. + +{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *} + +## Sayı Doğrulamaları: Büyük Eşit { #number-validations-greater-than-or-equal } + +`Query` ve `Path` (ve ileride göreceğiniz diğerleri) ile sayı kısıtları tanımlayabilirsiniz. + +Burada `ge=1` ile, `item_id` değerinin `1`'den "`g`reater than or `e`qual" olacak şekilde bir tam sayı olması gerekir. + +{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *} + +## Sayı Doğrulamaları: Büyük ve Küçük Eşit { #number-validations-greater-than-and-less-than-or-equal } + +Aynısı şunlar için de geçerlidir: + +* `gt`: `g`reater `t`han +* `le`: `l`ess than or `e`qual + +{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *} + +## Sayı Doğrulamaları: `float` Değerler, Büyük ve Küçük { #number-validations-floats-greater-than-and-less-than } + +Sayı doğrulamaları `float` değerler için de çalışır. + +Burada gt tanımlayabilmek (sadece ge değil) önemli hale gelir. Çünkü örneğin bir değerin `0`'dan büyük olmasını isteyebilirsiniz; `1`'den küçük olsa bile. + +Bu durumda `0.5` geçerli bir değer olur. Ancak `0.0` veya `0` geçerli olmaz. + +Aynısı lt için de geçerlidir. + +{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *} + +## Özet { #recap } + +`Query`, `Path` (ve henüz görmedikleriniz) ile metadata ve string doğrulamalarını, [Query Parametreleri ve String Doğrulamalar](query-params-str-validations.md){.internal-link target=_blank} bölümündekiyle aynı şekilde tanımlayabilirsiniz. + +Ayrıca sayısal doğrulamalar da tanımlayabilirsiniz: + +* `gt`: `g`reater `t`han +* `ge`: `g`reater than or `e`qual +* `lt`: `l`ess `t`han +* `le`: `l`ess than or `e`qual + +/// info | Bilgi + +`Query`, `Path` ve ileride göreceğiniz diğer class'lar ortak bir `Param` class'ının alt class'larıdır. + +Hepsi, gördüğünüz ek doğrulama ve metadata parametrelerini paylaşır. + +/// + +/// note | Teknik Detaylar + +`Query`, `Path` ve diğerlerini `fastapi` içinden import ettiğinizde, bunlar aslında birer fonksiyondur. + +Çağrıldıklarında, aynı isme sahip class'ların instance'larını döndürürler. + +Yani `Query`'yi import edersiniz; bu bir fonksiyondur. Onu çağırdığınızda, yine `Query` adlı bir class'ın instance'ını döndürür. + +Bu fonksiyonlar (class'ları doğrudan kullanmak yerine) editörünüzün type'larıyla ilgili hata işaretlememesi için vardır. + +Bu sayede, bu hataları yok saymak üzere özel ayarlar eklemeden normal editörünüzü ve coding araçlarınızı kullanabilirsiniz. + +/// diff --git a/docs/tr/docs/tutorial/query-param-models.md b/docs/tr/docs/tutorial/query-param-models.md new file mode 100644 index 0000000000..75139a6777 --- /dev/null +++ b/docs/tr/docs/tutorial/query-param-models.md @@ -0,0 +1,68 @@ +# Query Parameter Modelleri { #query-parameter-models } + +Birbirleriyle ilişkili bir **query parameter** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz. + +Böylece **modeli yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation (doğrulama) ile metadata’yı tek seferde tanımlayabilirsiniz. 😎 + +/// note | Not + +Bu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir. 🤓 + +/// + +## Pydantic Model ile Query Parameters { #query-parameters-with-a-pydantic-model } + +İhtiyacınız olan **query parameter**’ları bir **Pydantic model** içinde tanımlayın, ardından parametreyi `Query` olarak belirtin: + +{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *} + +**FastAPI**, request’teki **query parameter**’lardan **her field** için veriyi **extract** eder ve tanımladığınız Pydantic model’i size verir. + +## Dokümanları Kontrol Edin { #check-the-docs } + +Query parameter’ları `/docs` altındaki dokümantasyon arayüzünde görebilirsiniz: + +
+ +
+ +## Ek Query Parameter'ları Yasaklayın { #forbid-extra-query-parameters } + +Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değil), almak istediğiniz query parameter’ları **kısıtlamak** isteyebilirsiniz. + +Pydantic’in model konfigürasyonunu kullanarak `extra` field’ları `forbid` edebilirsiniz: + +{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *} + +Bir client, **query parameter**’larda **ek (extra)** veri göndermeye çalışırsa, **error** response alır. + +Örneğin client, değeri `plumbus` olan bir `tool` query parameter’ı göndermeye çalışırsa: + +```http +https://example.com/items/?limit=10&tool=plumbus +``` + +`tool` query parameter’ına izin verilmediğini söyleyen bir **error** response alır: + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["query", "tool"], + "msg": "Extra inputs are not permitted", + "input": "plumbus" + } + ] +} +``` + +## Özet { #summary } + +**FastAPI** içinde **query parameter**’ları tanımlamak için **Pydantic model**’leri kullanabilirsiniz. 😎 + +/// tip | İpucu + +Spoiler: cookie ve header’ları tanımlamak için de Pydantic model’leri kullanabilirsiniz; ancak bunu tutorial’ın ilerleyen bölümlerinde göreceksiniz. 🤫 + +/// diff --git a/docs/tr/docs/tutorial/query-params-str-validations.md b/docs/tr/docs/tutorial/query-params-str-validations.md new file mode 100644 index 0000000000..18f0249e54 --- /dev/null +++ b/docs/tr/docs/tutorial/query-params-str-validations.md @@ -0,0 +1,473 @@ +# Query Parametreleri ve String Doğrulamaları { #query-parameters-and-string-validations } + +**FastAPI**, parametreleriniz için ek bilgi ve doğrulamalar (validation) tanımlamanıza izin verir. + +Örnek olarak şu uygulamayı ele alalım: + +{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *} + +Query parametresi `q`, `str | None` tipindedir. Yani tipi `str`’dir ama `None` da olabilir. Nitekim varsayılan değer `None` olduğu için FastAPI bunun zorunlu olmadığını anlar. + +/// note | Not + +FastAPI, `q`’nun zorunlu olmadığını `= None` varsayılan değerinden anlar. + +`str | None` kullanmak, editörünüzün daha iyi destek vermesini ve hataları yakalamasını sağlar. + +/// + +## Ek doğrulama { #additional-validation } + +`q` opsiyonel olsa bile, verildiği durumda **uzunluğunun 50 karakteri geçmemesini** zorlayacağız. + +### `Query` ve `Annotated` import edin { #import-query-and-annotated } + +Bunu yapmak için önce şunları import edin: + +* `fastapi` içinden `Query` +* `typing` içinden `Annotated` + +{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *} + +/// info | Bilgi + +FastAPI, 0.95.0 sürümünde `Annotated` desteğini ekledi (ve önermeye başladı). + +Daha eski bir sürüm kullanıyorsanız `Annotated` kullanmaya çalışırken hata alırsınız. + +`Annotated` kullanmadan önce FastAPI sürümünü en az 0.95.1’e yükseltmek için [FastAPI sürümünü yükseltin](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank}. + +/// + +## `q` parametresinin tipinde `Annotated` kullanın { #use-annotated-in-the-type-for-the-q-parameter } + +[Python Types Intro](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} içinde `Annotated` ile parametrelerinize metadata ekleyebileceğinizi söylemiştim, hatırlıyor musunuz? + +Şimdi bunu FastAPI ile kullanmanın zamanı. 🚀 + +Şu tip anotasyonuna sahiptik: + +//// tab | Python 3.10+ + +```Python +q: str | None = None +``` + +//// + +//// tab | Python 3.9+ + +```Python +q: Union[str, None] = None +``` + +//// + +Şimdi bunu `Annotated` ile saracağız; şöyle olacak: + +//// tab | Python 3.10+ + +```Python +q: Annotated[str | None] = None +``` + +//// + +//// tab | Python 3.9+ + +```Python +q: Annotated[Union[str, None]] = None +``` + +//// + +Bu iki sürüm de aynı anlama gelir: `q`, `str` veya `None` olabilen bir parametredir ve varsayılan olarak `None`’dır. + +Şimdi işin eğlenceli kısmına geçelim. 🎉 + +## `q` parametresindeki `Annotated` içine `Query` ekleyin { #add-query-to-annotated-in-the-q-parameter } + +Artık ek bilgi (bu durumda ek doğrulama) koyabildiğimiz bir `Annotated`’ımız olduğuna göre, `Annotated` içine `Query` ekleyin ve `max_length` parametresini `50` olarak ayarlayın: + +{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *} + +Varsayılan değerin hâlâ `None` olduğuna dikkat edin; yani parametre hâlâ opsiyonel. + +Ama şimdi `Annotated` içinde `Query(max_length=50)` kullanarak FastAPI’ye bu değer için **ek doğrulama** istediğimizi söylüyoruz: en fazla 50 karakter. 😎 + +/// tip | İpucu + +Burada `Query()` kullanıyoruz çünkü bu bir **query parametresi**. İleride `Path()`, `Body()`, `Header()` ve `Cookie()` gibi, `Query()` ile aynı argümanları kabul eden diğerlerini de göreceğiz. + +/// + +FastAPI artık şunları yapacak: + +* Verinin uzunluğunun en fazla 50 karakter olduğundan emin olacak şekilde **doğrulayacak** +* Veri geçerli değilse client için **net bir hata** gösterecek +* Parametreyi OpenAPI şemasındaki *path operation* içinde **dokümante edecek** (dolayısıyla **otomatik dokümantasyon arayüzünde** görünecek) + +## Alternatif (eski): Varsayılan değer olarak `Query` { #alternative-old-query-as-the-default-value } + +FastAPI’nin önceki sürümlerinde (0.95.0 öncesi) `Query`’yi `Annotated` içine koymak yerine, parametrenizin varsayılan değeri olarak kullanmanız gerekiyordu. Etrafta bu şekilde yazılmış kod görme ihtimaliniz yüksek; bu yüzden açıklayalım. + +/// tip | İpucu + +Yeni kodlarda ve mümkün olduğunda, yukarıda anlatıldığı gibi `Annotated` kullanın. Birden fazla avantajı vardır (aşağıda anlatılıyor) ve dezavantajı yoktur. 🍰 + +/// + +Fonksiyon parametresinin varsayılan değeri olarak `Query()` kullanıp `max_length` parametresini 50 yapmak şöyle olurdu: + +{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *} + +Bu senaryoda (`Annotated` kullanmadığımız için) fonksiyondaki `None` varsayılan değerini `Query()` ile değiştirmemiz gerekiyor. Bu durumda varsayılan değeri `Query(default=None)` ile vermeliyiz; bu, (en azından FastAPI açısından) aynı varsayılan değeri tanımlama amacına hizmet eder. + +Yani: + +```Python +q: str | None = Query(default=None) +``` + +...parametreyi `None` varsayılan değeriyle opsiyonel yapar; şununla aynı: + +```Python +q: str | None = None +``` + +Ancak `Query` sürümü bunun bir query parametresi olduğunu açıkça belirtir. + +Sonrasında `Query`’ye daha fazla parametre geçebiliriz. Bu örnekte string’ler için geçerli olan `max_length`: + +```Python +q: str | None = Query(default=None, max_length=50) +``` + +Bu, veriyi doğrular, veri geçerli değilse net bir hata gösterir ve parametreyi OpenAPI şemasındaki *path operation* içinde dokümante eder. + +### Varsayılan değer olarak `Query` veya `Annotated` içinde `Query` { #query-as-the-default-value-or-in-annotated } + +`Annotated` içinde `Query` kullanırken `Query` için `default` parametresini kullanamayacağınızı unutmayın. + +Bunun yerine fonksiyon parametresinin gerçek varsayılan değerini kullanın. Aksi halde tutarsız olur. + +Örneğin şu kullanım izinli değildir: + +```Python +q: Annotated[str, Query(default="rick")] = "morty" +``` + +...çünkü varsayılan değerin `"rick"` mi `"morty"` mi olması gerektiği belli değildir. + +Bu nedenle (tercihen) şöyle kullanırsınız: + +```Python +q: Annotated[str, Query()] = "rick" +``` + +...veya eski kod tabanlarında şuna rastlarsınız: + +```Python +q: str = Query(default="rick") +``` + +### `Annotated`’ın avantajları { #advantages-of-annotated } + +Fonksiyon parametrelerindeki varsayılan değer stiline göre **`Annotated` kullanmanız önerilir**; birden fazla nedenle **daha iyidir**. 🤓 + +**Fonksiyon parametresinin** **varsayılan** değeri, **gerçek varsayılan** değerdir; bu genel olarak Python açısından daha sezgiseldir. 😌 + +Aynı fonksiyonu FastAPI olmadan **başka yerlerde** de **çağırabilirsiniz** ve **beklendiği gibi çalışır**. Eğer **zorunlu** bir parametre varsa (varsayılan değer yoksa) editörünüz hata ile bunu belirtir; ayrıca gerekli parametreyi vermeden çalıştırırsanız **Python** da şikayet eder. + +`Annotated` kullanmayıp bunun yerine **(eski) varsayılan değer stilini** kullanırsanız, o fonksiyonu FastAPI olmadan **başka yerlerde** çağırdığınızda doğru çalışması için argümanları geçmeniz gerektiğini **hatırlamak** zorunda kalırsınız; yoksa değerler beklediğinizden farklı olur (ör. `str` yerine `QueryInfo` veya benzeri). Üstelik editörünüz de şikayet etmez ve Python da fonksiyonu çalıştırırken şikayet etmez; ancak içerideki operasyonlar hata verince ortaya çıkar. + +`Annotated` birden fazla metadata anotasyonu alabildiği için, artık aynı fonksiyonu Typer gibi başka araçlarla da kullanabilirsiniz. 🚀 + +## Daha fazla doğrulama ekleyin { #add-more-validations } + +`min_length` parametresini de ekleyebilirsiniz: + +{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *} + +## Regular expression ekleyin { #add-regular-expressions } + +Parametrenin eşleşmesi gereken bir `pattern` regular expression tanımlayabilirsiniz: + +{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *} + +Bu özel regular expression pattern’i, gelen parametre değerinin şunları sağladığını kontrol eder: + +* `^`: Aşağıdaki karakterlerle başlar; öncesinde karakter yoktur. +* `fixedquery`: Tam olarak `fixedquery` değerine sahiptir. +* `$`: Orada biter; `fixedquery` sonrasında başka karakter yoktur. + +Bu **"regular expression"** konuları gözünüzü korkutuyorsa sorun değil. Birçok kişi için zor bir konudur. Regular expression’lara ihtiyaç duymadan da pek çok şey yapabilirsiniz. + +Artık ihtiyaç duyduğunuzda **FastAPI** içinde kullanabileceğinizi biliyorsunuz. + +## Varsayılan değerler { #default-values } + +Elbette `None` dışında varsayılan değerler de kullanabilirsiniz. + +Örneğin `q` query parametresi için `min_length` değerini `3` yapmak ve varsayılan değer olarak `"fixedquery"` vermek istediğinizi düşünelim: + +{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *} + +/// note | Not + +`None` dahil herhangi bir tipte varsayılan değere sahip olmak, parametreyi opsiyonel (zorunlu değil) yapar. + +/// + +## Zorunlu parametreler { #required-parameters } + +Daha fazla doğrulama veya metadata tanımlamamız gerekmiyorsa, `q` query parametresini yalnızca varsayılan değer tanımlamayarak zorunlu yapabiliriz: + +```Python +q: str +``` + +şunun yerine: + +```Python +q: str | None = None +``` + +Ancak biz artık `Query` ile tanımlıyoruz; örneğin şöyle: + +```Python +q: Annotated[str | None, Query(min_length=3)] = None +``` + +Dolayısıyla `Query` kullanırken bir değeri zorunlu yapmak istediğinizde, varsayılan değer tanımlamamanız yeterlidir: + +{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *} + +### Zorunlu ama `None` olabilir { #required-can-be-none } + +Bir parametrenin `None` kabul edebileceğini söyleyip yine de zorunlu olmasını sağlayabilirsiniz. Bu, client’ların değer göndermesini zorunlu kılar; değer `None` olsa bile. + +Bunu yapmak için `None`’ı geçerli bir tip olarak tanımlayın ama varsayılan değer vermeyin: + +{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *} + +## Query parametresi listesi / birden fazla değer { #query-parameter-list-multiple-values } + +Bir query parametresini `Query` ile açıkça tanımladığınızda, bir değer listesi alacak şekilde (başka bir deyişle, birden fazla değer alacak şekilde) de tanımlayabilirsiniz. + +Örneğin URL’de `q` query parametresinin birden fazla kez görünebilmesini istiyorsanız şöyle yazabilirsiniz: + +{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *} + +Sonra şu URL ile: + +``` +http://localhost:8000/items/?q=foo&q=bar +``` + +*path operation function* içinde, *function parameter* olan `q` parametresinde, birden fazla `q` *query parameters* değerini (`foo` ve `bar`) bir Python `list`’i olarak alırsınız. + +Dolayısıyla bu URL’ye response şöyle olur: + +```JSON +{ + "q": [ + "foo", + "bar" + ] +} +``` + +/// tip | İpucu + +Yukarıdaki örnekte olduğu gibi tipi `list` olan bir query parametresi tanımlamak için `Query`’yi açıkça kullanmanız gerekir; aksi halde request body olarak yorumlanır. + +/// + +Etkileşimli API dokümanları da buna göre güncellenir ve birden fazla değere izin verir: + + + +### Varsayılanlarla query parametresi listesi / birden fazla değer { #query-parameter-list-multiple-values-with-defaults } + +Hiç değer verilmezse varsayılan bir `list` de tanımlayabilirsiniz: + +{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *} + +Şu adrese giderseniz: + +``` +http://localhost:8000/items/ +``` + +`q`’nun varsayılanı `["foo", "bar"]` olur ve response şöyle olur: + +```JSON +{ + "q": [ + "foo", + "bar" + ] +} +``` + +#### Sadece `list` kullanmak { #using-just-list } + +`list[str]` yerine doğrudan `list` de kullanabilirsiniz: + +{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *} + +/// note | Not + +Bu durumda FastAPI, listenin içeriğini kontrol etmez. + +Örneğin `list[int]`, listenin içeriğinin integer olduğunu kontrol eder (ve dokümante eder). Ancak tek başına `list` bunu yapmaz. + +/// + +## Daha fazla metadata tanımlayın { #declare-more-metadata } + +Parametre hakkında daha fazla bilgi ekleyebilirsiniz. + +Bu bilgiler oluşturulan OpenAPI’a dahil edilir ve dokümantasyon arayüzleri ile harici araçlar tarafından kullanılır. + +/// note | Not + +Farklı araçların OpenAPI desteği farklı seviyelerde olabilir. + +Bazıları tanımladığınız ek bilgilerin hepsini göstermeyebilir; ancak çoğu durumda eksik özellik geliştirme planındadır. + +/// + +Bir `title` ekleyebilirsiniz: + +{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *} + +Ve bir `description`: + +{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *} + +## Alias parametreleri { #alias-parameters } + +Parametrenin adının `item-query` olmasını istediğinizi düşünün. + +Örneğin: + +``` +http://127.0.0.1:8000/items/?item-query=foobaritems +``` + +Ancak `item-query` geçerli bir Python değişken adı değildir. + +En yakın seçenek `item_query` olur. + +Ama sizin hâlâ tam olarak `item-query` olmasına ihtiyacınız var... + +O zaman bir `alias` tanımlayabilirsiniz; bu alias, parametre değerini bulmak için kullanılacaktır: + +{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *} + +## Parametreleri deprecated yapmak { #deprecating-parameters } + +Diyelim ki artık bu parametreyi istemiyorsunuz. + +Bazı client’lar hâlâ kullandığı için bir süre tutmanız gerekiyor, ama dokümanların bunu açıkça deprecated olarak göstermesini istiyorsunuz. + +O zaman `Query`’ye `deprecated=True` parametresini geçin: + +{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *} + +Dokümanlarda şöyle görünür: + + + +## Parametreleri OpenAPI’dan hariç tutun { #exclude-parameters-from-openapi } + +Oluşturulan OpenAPI şemasından (dolayısıyla otomatik dokümantasyon sistemlerinden) bir query parametresini hariç tutmak için `Query`’nin `include_in_schema` parametresini `False` yapın: + +{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *} + +## Özel Doğrulama { #custom-validation } + +Yukarıdaki parametrelerle yapılamayan bazı **özel doğrulama** ihtiyaçlarınız olabilir. + +Bu durumlarda, normal doğrulamadan sonra (ör. değerin `str` olduğunun doğrulanmasından sonra) uygulanacak bir **custom validator function** kullanabilirsiniz. + +Bunu, `Annotated` içinde Pydantic’in `AfterValidator`’ını kullanarak yapabilirsiniz. + +/// tip | İpucu + +Pydantic’te `BeforeValidator` ve başka validator’lar da vardır. 🤓 + +/// + +Örneğin bu custom validator, bir item ID’sinin ISBN kitap numarası için `isbn-` ile veya IMDB film URL ID’si için `imdb-` ile başladığını kontrol eder: + +{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *} + +/// info | Bilgi + +Bu özellik Pydantic 2 ve üzeri sürümlerde mevcuttur. 😎 + +/// + +/// tip | İpucu + +Veritabanı veya başka bir API gibi herhangi bir **harici bileşen** ile iletişim gerektiren bir doğrulama yapmanız gerekiyorsa, bunun yerine **FastAPI Dependencies** kullanmalısınız; onları ileride öğreneceksiniz. + +Bu custom validator’lar, request’te sağlanan **yalnızca** **aynı veri** ile kontrol edilebilen şeyler içindir. + +/// + +### O Kodu Anlamak { #understand-that-code } + +Önemli nokta, **`Annotated` içinde bir fonksiyonla birlikte `AfterValidator` kullanmak**. İsterseniz bu kısmı atlayabilirsiniz. 🤸 + +--- + +Ama bu örnek kodun detaylarını merak ediyorsanız, birkaç ek bilgi: + +#### `value.startswith()` ile String { #string-with-value-startswith } + +Fark ettiniz mi? `value.startswith()` ile bir string, tuple alabilir ve tuple içindeki her değeri kontrol eder: + +{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *} + +#### Rastgele Bir Item { #a-random-item } + +`data.items()` ile, her dictionary öğesi için key ve value içeren tuple’lardan oluşan bir iterable object elde ederiz. + +Bu iterable object’i `list(data.items())` ile düzgün bir `list`’e çeviririz. + +Ardından `random.choice()` ile list’ten **rastgele bir değer** alırız; yani `(id, name)` içeren bir tuple elde ederiz. Şuna benzer: `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`. + +Sonra tuple içindeki bu **iki değeri** `id` ve `name` değişkenlerine **atarız**. + +Böylece kullanıcı bir item ID’si vermemiş olsa bile yine de rastgele bir öneri alır. + +...bütün bunları **tek bir basit satırda** yapıyoruz. 🤯 Python’u sevmemek elde mi? 🐍 + +{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *} + +## Özet { #recap } + +Parametreleriniz için ek doğrulamalar ve metadata tanımlayabilirsiniz. + +Genel doğrulamalar ve metadata: + +* `alias` +* `title` +* `description` +* `deprecated` + +String’lere özel doğrulamalar: + +* `min_length` +* `max_length` +* `pattern` + +`AfterValidator` ile custom doğrulamalar. + +Bu örneklerde `str` değerleri için doğrulamanın nasıl tanımlanacağını gördünüz. + +Sayılar gibi diğer tipler için doğrulamaları nasıl tanımlayacağınızı öğrenmek için sonraki bölümlere geçin. diff --git a/docs/tr/docs/tutorial/request-files.md b/docs/tr/docs/tutorial/request-files.md new file mode 100644 index 0000000000..0bbc557e01 --- /dev/null +++ b/docs/tr/docs/tutorial/request-files.md @@ -0,0 +1,176 @@ +# Request Dosyaları { #request-files } + +İstemcinin upload edeceği dosyaları `File` kullanarak tanımlayabilirsiniz. + +/// info | Bilgi + +Upload edilen dosyaları alabilmek için önce `python-multipart` yükleyin. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, aktive ettiğinizden ve ardından paketi yüklediğinizden emin olun. Örneğin: + +```console +$ pip install python-multipart +``` + +Bunun nedeni, upload edilen dosyaların "form data" olarak gönderilmesidir. + +/// + +## `File` Import Edin { #import-file } + +`fastapi` içinden `File` ve `UploadFile` import edin: + +{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *} + +## `File` Parametrelerini Tanımlayın { #define-file-parameters } + +`Body` veya `Form` için yaptığınız gibi dosya parametreleri oluşturun: + +{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *} + +/// info | Bilgi + +`File`, doğrudan `Form`’dan türeyen bir sınıftır. + +Ancak unutmayın: `fastapi` içinden `Query`, `Path`, `File` ve diğerlerini import ettiğinizde, bunlar aslında özel sınıflar döndüren fonksiyonlardır. + +/// + +/// tip | İpucu + +File body’leri tanımlamak için `File` kullanmanız gerekir; aksi halde parametreler query parametreleri veya body (JSON) parametreleri olarak yorumlanır. + +/// + +Dosyalar "form data" olarak upload edilir. + +*path operation function* parametrenizin tipini `bytes` olarak tanımlarsanız, **FastAPI** dosyayı sizin için okur ve içeriği `bytes` olarak alırsınız. + +Bunun, dosyanın tüm içeriğinin bellekte tutulacağı anlamına geldiğini unutmayın. Küçük dosyalar için iyi çalışır. + +Ancak bazı durumlarda `UploadFile` kullanmak size fayda sağlayabilir. + +## `UploadFile` ile Dosya Parametreleri { #file-parameters-with-uploadfile } + +Tipi `UploadFile` olan bir dosya parametresi tanımlayın: + +{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *} + +`UploadFile` kullanmanın `bytes`’a göre birkaç avantajı vardır: + +* Parametrenin varsayılan değerinde `File()` kullanmak zorunda değilsiniz. +* "Spooled" bir dosya kullanır: + * Belirli bir maksimum boyuta kadar bellekte tutulan, bu limiti aşınca diske yazılan bir dosya. +* Bu sayede görüntüler, videolar, büyük binary’ler vb. gibi büyük dosyalarda tüm belleği tüketmeden iyi çalışır. +* Upload edilen dosyadan metadata alabilirsiniz. +* file-like bir `async` arayüze sahiptir. +* `SpooledTemporaryFile` nesnesini dışa açar; bunu, file-like nesne bekleyen diğer library’lere doğrudan geçebilirsiniz. + +### `UploadFile` { #uploadfile } + +`UploadFile` şu attribute’lara sahiptir: + +* `filename`: Upload edilen orijinal dosya adını içeren bir `str` (örn. `myimage.jpg`). +* `content_type`: Content type’ı (MIME type / media type) içeren bir `str` (örn. `image/jpeg`). +* `file`: Bir `SpooledTemporaryFile` (bir file-like nesne). Bu, "file-like" nesne bekleyen diğer fonksiyonlara veya library’lere doğrudan verebileceğiniz gerçek Python file nesnesidir. + +`UploadFile` şu `async` method’lara sahiptir. Bunların hepsi altta ilgili dosya method’larını çağırır (dahili `SpooledTemporaryFile` kullanarak). + +* `write(data)`: Dosyaya `data` (`str` veya `bytes`) yazar. +* `read(size)`: Dosyadan `size` (`int`) kadar byte/karakter okur. +* `seek(offset)`: Dosyada `offset` (`int`) byte pozisyonuna gider. + * Örn. `await myfile.seek(0)` dosyanın başına gider. + * Bu, özellikle bir kez `await myfile.read()` çalıştırdıysanız ve sonra içeriği yeniden okumaya ihtiyaç duyuyorsanız faydalıdır. +* `close()`: Dosyayı kapatır. + +Bu method’ların hepsi `async` olduğundan, bunları "await" etmeniz gerekir. + +Örneğin, bir `async` *path operation function* içinde içeriği şöyle alabilirsiniz: + +```Python +contents = await myfile.read() +``` + +Normal bir `def` *path operation function* içindeyseniz `UploadFile.file`’a doğrudan erişebilirsiniz, örneğin: + +```Python +contents = myfile.file.read() +``` + +/// note | `async` Teknik Detaylar + +`async` method’ları kullandığınızda, **FastAPI** dosya method’larını bir threadpool içinde çalıştırır ve bunları await eder. + +/// + +/// note | Starlette Teknik Detaylar + +**FastAPI**’nin `UploadFile`’ı doğrudan **Starlette**’in `UploadFile`’ından türetilmiştir; ancak **Pydantic** ve FastAPI’nin diğer parçalarıyla uyumlu olması için bazı gerekli eklemeler yapar. + +/// + +## "Form Data" Nedir { #what-is-form-data } + +HTML formları (`
`) veriyi server’a gönderirken normalde JSON’dan farklı, veri için "özel" bir encoding kullanır. + +**FastAPI**, JSON yerine bu veriyi doğru yerden okuyacağından emin olur. + +/// note | Teknik Detaylar + +Formlardan gelen veri, dosya içermiyorsa normalde "media type" olarak `application/x-www-form-urlencoded` ile encode edilir. + +Ancak form dosya içeriyorsa `multipart/form-data` olarak encode edilir. `File` kullanırsanız, **FastAPI** dosyaları body’nin doğru kısmından alması gerektiğini bilir. + +Bu encoding’ler ve form alanları hakkında daha fazla okumak isterseniz MDN web dokümanlarındaki POST sayfasına bakın. + +/// + +/// warning | Uyarı + +Bir *path operation* içinde birden fazla `File` ve `Form` parametresi tanımlayabilirsiniz, ancak JSON olarak almayı beklediğiniz `Body` alanlarını ayrıca tanımlayamazsınız; çünkü request body `application/json` yerine `multipart/form-data` ile encode edilmiş olur. + +Bu, **FastAPI**’nin bir kısıtı değildir; HTTP protocol’ünün bir parçasıdır. + +/// + +## Opsiyonel Dosya Upload { #optional-file-upload } + +Standart type annotation’ları kullanıp varsayılan değeri `None` yaparak bir dosyayı opsiyonel hale getirebilirsiniz: + +{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *} + +## Ek Metadata ile `UploadFile` { #uploadfile-with-additional-metadata } + +Ek metadata ayarlamak için `UploadFile` ile birlikte `File()` da kullanabilirsiniz. Örneğin: + +{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *} + +## Birden Fazla Dosya Upload { #multiple-file-uploads } + +Aynı anda birden fazla dosya upload etmek mümkündür. + +Bu dosyalar, "form data" ile gönderilen aynı "form field" ile ilişkilendirilir. + +Bunu kullanmak için `bytes` veya `UploadFile` listesini tanımlayın: + +{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *} + +Tanımladığınız gibi, `bytes` veya `UploadFile`’lardan oluşan bir `list` alırsınız. + +/// note | Teknik Detaylar + +`from starlette.responses import HTMLResponse` da kullanabilirsiniz. + +**FastAPI**, geliştiriciye kolaylık olsun diye `starlette.responses` modülünü `fastapi.responses` olarak da sağlar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir. + +/// + +### Ek Metadata ile Birden Fazla Dosya Upload { #multiple-file-uploads-with-additional-metadata } + +Daha önce olduğu gibi, `UploadFile` için bile ek parametreler ayarlamak amacıyla `File()` kullanabilirsiniz: + +{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *} + +## Özet { #recap } + +Request’te (form data olarak gönderilen) upload edilecek dosyaları tanımlamak için `File`, `bytes` ve `UploadFile` kullanın. diff --git a/docs/tr/docs/tutorial/request-form-models.md b/docs/tr/docs/tutorial/request-form-models.md new file mode 100644 index 0000000000..c35f956fce --- /dev/null +++ b/docs/tr/docs/tutorial/request-form-models.md @@ -0,0 +1,78 @@ +# Form Model'leri { #form-models } + +FastAPI'de **form field**'larını tanımlamak için **Pydantic model**'lerini kullanabilirsiniz. + +/// info | Bilgi + +Form'ları kullanmak için önce `python-multipart`'ı yükleyin. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu etkinleştirdiğinizden ve ardından paketi kurduğunuzdan emin olun. Örneğin: + +```console +$ pip install python-multipart +``` + +/// + +/// note | Not + +Bu özellik FastAPI `0.113.0` sürümünden itibaren desteklenmektedir. 🤓 + +/// + +## Form'lar için Pydantic Model'leri { #pydantic-models-for-forms } + +Sadece, **form field** olarak almak istediğiniz alanlarla bir **Pydantic model** tanımlayın ve ardından parametreyi `Form` olarak bildirin: + +{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *} + +**FastAPI**, request içindeki **form data**'dan **her bir field** için veriyi **çıkarır** ve size tanımladığınız Pydantic model'ini verir. + +## Dokümanları Kontrol Edin { #check-the-docs } + +Bunu `/docs` altındaki doküman arayüzünde doğrulayabilirsiniz: + +
+ +
+ +## Fazladan Form Field'larını Yasaklayın { #forbid-extra-form-fields } + +Bazı özel kullanım senaryolarında (muhtemelen çok yaygın değildir), form field'larını yalnızca Pydantic model'inde tanımlananlarla **sınırlamak** isteyebilirsiniz. Ve **fazladan** gelen field'ları **yasaklayabilirsiniz**. + +/// note | Not + +Bu özellik FastAPI `0.114.0` sürümünden itibaren desteklenmektedir. 🤓 + +/// + +Herhangi bir `extra` field'ı `forbid` etmek için Pydantic'in model konfigürasyonunu kullanabilirsiniz: + +{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *} + +Bir client fazladan veri göndermeye çalışırsa, bir **error** response alır. + +Örneğin, client şu form field'larını göndermeye çalışırsa: + +* `username`: `Rick` +* `password`: `Portal Gun` +* `extra`: `Mr. Poopybutthole` + +`extra` field'ının izinli olmadığını söyleyen bir error response alır: + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["body", "extra"], + "msg": "Extra inputs are not permitted", + "input": "Mr. Poopybutthole" + } + ] +} +``` + +## Özet { #summary } + +FastAPI'de form field'larını tanımlamak için Pydantic model'lerini kullanabilirsiniz. 😎 diff --git a/docs/tr/docs/tutorial/request-forms-and-files.md b/docs/tr/docs/tutorial/request-forms-and-files.md new file mode 100644 index 0000000000..86d26b4989 --- /dev/null +++ b/docs/tr/docs/tutorial/request-forms-and-files.md @@ -0,0 +1,41 @@ +# Request Forms ve Files { #request-forms-and-files } + +`File` ve `Form` kullanarak aynı anda hem dosyaları hem de form alanlarını tanımlayabilirsiniz. + +/// info | Bilgi + +Yüklenen dosyaları ve/veya form verisini almak için önce `python-multipart` paketini kurun. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktive ettiğinizden ve ardından paketi kurduğunuzdan emin olun, örneğin: + +```console +$ pip install python-multipart +``` + +/// + +## `File` ve `Form` Import Edin { #import-file-and-form } + +{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *} + +## `File` ve `Form` Parametrelerini Tanımlayın { #define-file-and-form-parameters } + +Dosya ve form parametrelerini, `Body` veya `Query` için yaptığınız şekilde oluşturun: + +{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *} + +Dosyalar ve form alanları form data olarak upload edilir ve siz de dosyaları ve form alanlarını alırsınız. + +Ayrıca bazı dosyaları `bytes` olarak, bazılarını da `UploadFile` olarak tanımlayabilirsiniz. + +/// warning | Uyarı + +Bir *path operation* içinde birden fazla `File` ve `Form` parametresi tanımlayabilirsiniz; ancak request'in body'si `application/json` yerine `multipart/form-data` ile encode edileceği için, JSON olarak almayı beklediğiniz `Body` alanlarını aynı anda tanımlayamazsınız. + +Bu **FastAPI** kısıtı değildir; HTTP protokolünün bir parçasıdır. + +/// + +## Özet { #recap } + +Aynı request içinde hem veri hem de dosya almanız gerektiğinde `File` ve `Form`'u birlikte kullanın. diff --git a/docs/tr/docs/tutorial/response-model.md b/docs/tr/docs/tutorial/response-model.md new file mode 100644 index 0000000000..f1d1f7d15e --- /dev/null +++ b/docs/tr/docs/tutorial/response-model.md @@ -0,0 +1,343 @@ +# Response Model - Dönüş Tipi { #response-model-return-type } + +*Path operation function* **dönüş tipini** (return type) type annotation ile belirtip response için kullanılacak tipi tanımlayabilirsiniz. + +Fonksiyon **parametreleri** için input data’da kullandığınız **type annotations** yaklaşımının aynısını burada da kullanabilirsiniz; Pydantic model’leri, list’ler, dict’ler, integer, boolean gibi skaler değerler vb. + +{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *} + +FastAPI bu dönüş tipini şunlar için kullanır: + +* Dönen veriyi **doğrulamak** (validate). + * Veri geçersizse (ör. bir field eksikse), bu *sizin* uygulama kodunuzun bozuk olduğu, olması gerekeni döndürmediği anlamına gelir; bu yüzden yanlış veri döndürmek yerine server error döner. Böylece siz ve client’larınız, beklenen veri ve veri şeklinin geleceğinden emin olabilirsiniz. +* OpenAPI’deki *path operation* içine response için bir **JSON Schema** eklemek. + * Bu, **otomatik dokümantasyon** tarafından kullanılır. + * Ayrıca otomatik client code generation araçları tarafından da kullanılır. + +Ama en önemlisi: + +* Çıktı verisini, dönüş tipinde tanımlı olana göre **sınırlar ve filtreler**. + * Bu, özellikle **güvenlik** açısından önemlidir; aşağıda daha fazlasını göreceğiz. + +## `response_model` Parametresi { #response-model-parameter } + +Bazı durumlarda, tam olarak dönüş tipinin söylediği gibi olmayan bir veriyi döndürmeniz gerekebilir ya da isteyebilirsiniz. + +Örneğin, **bir dict** veya bir veritabanı objesi döndürmek isteyip, ama **onu bir Pydantic model olarak declare etmek** isteyebilirsiniz. Böylece Pydantic model, döndürdüğünüz obje (ör. dict veya veritabanı objesi) için dokümantasyon, doğrulama vb. işlerin tamamını yapar. + +Eğer dönüş tipi annotation’ını eklerseniz, araçlar ve editörler (doğru şekilde) fonksiyonunuzun, declare ettiğiniz tipten (ör. Pydantic model) farklı bir tip (ör. dict) döndürdüğünü söyleyip hata verir. + +Bu gibi durumlarda, dönüş tipi yerine *path operation decorator* parametresi olan `response_model`’i kullanabilirsiniz. + +`response_model` parametresini herhangi bir *path operation* içinde kullanabilirsiniz: + +* `@app.get()` +* `@app.post()` +* `@app.put()` +* `@app.delete()` +* vb. + +{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *} + +/// note | Not + +`response_model`’in "decorator" metodunun (`get`, `post` vb.) bir parametresi olduğuna dikkat edin. Body ve diğer parametreler gibi, sizin *path operation function*’ınızın parametresi değildir. + +/// + +`response_model`, Pydantic model field’ı için declare edeceğiniz aynı tipi alır; yani bir Pydantic model olabilir ama örneğin `List[Item]` gibi Pydantic model’lerden oluşan bir `list` de olabilir. + +FastAPI bu `response_model`’i; dokümantasyon, doğrulama vb. her şey için ve ayrıca çıktı verisini **tip tanımına göre dönüştürmek ve filtrelemek** için kullanır. + +/// tip | İpucu + +Editörünüzde, mypy vb. ile sıkı type kontrolü yapıyorsanız, fonksiyon dönüş tipini `Any` olarak declare edebilirsiniz. + +Böylece editöre bilerek her şeyi döndürebileceğinizi söylemiş olursunuz. Ancak FastAPI, `response_model` ile dokümantasyon, doğrulama, filtreleme vb. işlemleri yine de yapar. + +/// + +### `response_model` Önceliği { #response-model-priority } + +Hem dönüş tipi hem de `response_model` declare ederseniz, FastAPI’de `response_model` önceliklidir ve o kullanılır. + +Böylece, response model’den farklı bir tip döndürdüğünüz durumlarda bile editör ve mypy gibi araçlar için fonksiyonlarınıza doğru type annotation’lar ekleyebilir, aynı zamanda FastAPI’nin `response_model` üzerinden veri doğrulama, dokümantasyon vb. yapmasını sağlayabilirsiniz. + +Ayrıca `response_model=None` kullanarak, ilgili *path operation* için response model oluşturulmasını devre dışı bırakabilirsiniz. Bu, Pydantic field’ı olarak geçerli olmayan şeyler için type annotation eklediğinizde gerekebilir; aşağıdaki bölümlerden birinde bunun örneğini göreceksiniz. + +## Aynı input verisini geri döndürmek { #return-the-same-input-data } + +Burada `UserIn` adında bir model declare ediyoruz; bu model plaintext bir password içerecek: + +{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *} + +/// info | Bilgi + +`EmailStr` kullanmak için önce `email-validator` paketini kurun. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktive ettiğinizden emin olun ve ardından örneğin şöyle kurun: + +```console +$ pip install email-validator +``` + +veya şöyle: + +```console +$ pip install "pydantic[email]" +``` + +/// + +Bu model ile hem input’u declare ediyoruz hem de output’u aynı model ile declare ediyoruz: + +{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *} + +Artık bir browser password ile user oluşturduğunda, API response içinde aynı password’ü geri döndürecek. + +Bu örnekte sorun olmayabilir; çünkü password’ü gönderen kullanıcı zaten aynı kişi. + +Ancak aynı modeli başka bir *path operation* için kullanırsak, kullanıcının password’lerini her client’a gönderiyor olabiliriz. + +/// danger + +Tüm riskleri bildiğinizden ve ne yaptığınızdan emin olmadığınız sürece, bir kullanıcının plain password’ünü asla saklamayın ve bu şekilde response içinde göndermeyin. + +/// + +## Bir output modeli ekleyin { #add-an-output-model } + +Bunun yerine, plaintext password içeren bir input modeli ve password’ü içermeyen bir output modeli oluşturabiliriz: + +{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *} + +Burada *path operation function* password içeren aynı input user’ı döndürüyor olsa bile: + +{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *} + +...`response_model` olarak, password’ü içermeyen `UserOut` modelimizi declare ettik: + +{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *} + +Dolayısıyla **FastAPI**, output model’de declare edilmemiş tüm verileri (Pydantic kullanarak) filtrelemekle ilgilenir. + +### `response_model` mi Return Type mı? { #response-model-or-return-type } + +Bu durumda iki model farklı olduğu için fonksiyon dönüş tipini `UserOut` olarak annotate etseydik, editör ve araçlar farklı class’lar olduğu için geçersiz bir tip döndürdüğümüzü söyleyip hata verecekti. + +Bu yüzden bu örnekte `response_model` parametresinde declare etmek zorundayız. + +...ama bunu nasıl aşabileceğinizi görmek için aşağıyı okumaya devam edin. + +## Return Type ve Veri Filtreleme { #return-type-and-data-filtering } + +Önceki örnekten devam edelim. Fonksiyonu **tek bir tip ile annotate etmek** istiyoruz; ama fonksiyondan gerçekte **daha fazla veri** içeren bir şey döndürebilmek istiyoruz. + +FastAPI’nin response model’i kullanarak veriyi **filtrelemeye** devam etmesini istiyoruz. Yani fonksiyon daha fazla veri döndürse bile response, sadece response model’de declare edilmiş field’ları içersin. + +Önceki örnekte class’lar farklı olduğu için `response_model` parametresini kullanmak zorundaydık. Ancak bu, editör ve araçların fonksiyon dönüş tipi kontrolünden gelen desteğini alamadığımız anlamına da geliyor. + +Ama bu tarz durumların çoğunda modelin amacı, bu örnekteki gibi bazı verileri **filtrelemek/kaldırmak** olur. + +Bu gibi durumlarda class’lar ve inheritance kullanarak, fonksiyon **type annotations** sayesinde editör ve araçlarda daha iyi destek alabilir, aynı zamanda FastAPI’nin **veri filtrelemesini** de koruyabiliriz. + +{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *} + +Bununla birlikte, code type’lar açısından doğru olduğu için editörler ve mypy araç desteği verir; ayrıca FastAPI’den veri filtrelemeyi de alırız. + +Bu nasıl çalışıyor? Bir bakalım. 🤓 + +### Type Annotations ve Araç Desteği { #type-annotations-and-tooling } + +Önce editörler, mypy ve diğer araçlar bunu nasıl görür, ona bakalım. + +`BaseUser` temel field’lara sahiptir. Ardından `UserIn`, `BaseUser`’dan miras alır ve `password` field’ını ekler; yani iki modelin field’larının tamamını içerir. + +Fonksiyonun dönüş tipini `BaseUser` olarak annotate ediyoruz ama gerçekte bir `UserIn` instance’ı döndürüyoruz. + +Editör, mypy ve diğer araçlar buna itiraz etmez; çünkü typing açısından `UserIn`, `BaseUser`’ın subclass’ıdır. Bu da, bir `BaseUser` bekleniyorken `UserIn`’in *geçerli* bir tip olduğu anlamına gelir. + +### FastAPI Veri Filtreleme { #fastapi-data-filtering } + +FastAPI açısından ise dönüş tipini görür ve döndürdüğünüz şeyin **yalnızca** tipte declare edilen field’ları içerdiğinden emin olur. + +FastAPI, Pydantic ile içeride birkaç işlem yapar; böylece class inheritance kurallarının dönen veri filtrelemede aynen kullanılmasına izin vermez. Aksi halde beklediğinizden çok daha fazla veriyi response’ta döndürebilirdiniz. + +Bu sayede iki dünyanın da en iyisini alırsınız: **araç desteği** veren type annotations ve **veri filtreleme**. + +## Dokümanlarda görün { #see-it-in-the-docs } + +Otomatik dokümanları gördüğünüzde, input model ve output model’in her birinin kendi JSON Schema’sına sahip olduğunu kontrol edebilirsiniz: + + + +Ve her iki model de etkileşimli API dokümantasyonunda kullanılır: + + + +## Diğer Return Type Annotation’ları { #other-return-type-annotations } + +Bazı durumlarda Pydantic field olarak geçerli olmayan bir şey döndürebilir ve bunu fonksiyonda annotate edebilirsiniz; amaç sadece araçların (editör, mypy vb.) sağladığı desteği almaktır. + +### Doğrudan Response Döndürmek { #return-a-response-directly } + +En yaygın durum, [ileri seviye dokümanlarda daha sonra anlatıldığı gibi doğrudan bir Response döndürmektir](../advanced/response-directly.md){.internal-link target=_blank}. + +{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *} + +Bu basit durum FastAPI tarafından otomatik olarak ele alınır; çünkü dönüş tipi annotation’ı `Response` class’ıdır (veya onun bir subclass’ı). + +Araçlar da memnun olur; çünkü hem `RedirectResponse` hem `JSONResponse`, `Response`’un subclass’ıdır. Yani type annotation doğrudur. + +### Bir Response Subclass’ını Annotate Etmek { #annotate-a-response-subclass } + +Type annotation içinde `Response`’un bir subclass’ını da kullanabilirsiniz: + +{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *} + +Bu da çalışır; çünkü `RedirectResponse`, `Response`’un subclass’ıdır ve FastAPI bu basit durumu otomatik olarak yönetir. + +### Geçersiz Return Type Annotation’ları { #invalid-return-type-annotations } + +Ancak geçerli bir Pydantic tipi olmayan başka rastgele bir obje (ör. bir veritabanı objesi) döndürür ve fonksiyonu da öyle annotate ederseniz, FastAPI bu type annotation’dan bir Pydantic response model oluşturmaya çalışır ve başarısız olur. + +Aynı şey, farklı tipler arasında bir union kullandığınızda ve bu tiplerden biri veya birkaçı geçerli bir Pydantic tipi değilse de olur; örneğin şu kullanım patlar 💥: + +{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *} + +...bu, type annotation Pydantic tipi olmadığı ve tek bir `Response` class’ı (veya subclass’ı) olmadığı için başarısız olur; bu, bir `Response` ile bir `dict` arasında union’dır (ikiden herhangi biri). + +### Response Model’i Devre Dışı Bırakmak { #disable-response-model } + +Yukarıdaki örnekten devam edersek; FastAPI’nin varsayılan olarak yaptığı veri doğrulama, dokümantasyon, filtreleme vb. işlemleri istemiyor olabilirsiniz. + +Ancak yine de editörler ve type checker’lar (ör. mypy) gibi araçların desteğini almak için fonksiyonda dönüş tipi annotation’ını korumak isteyebilirsiniz. + +Bu durumda `response_model=None` ayarlayarak response model üretimini devre dışı bırakabilirsiniz: + +{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *} + +Bu, FastAPI’nin response model üretimini atlamasını sağlar; böylece FastAPI uygulamanızı etkilemeden ihtiyacınız olan herhangi bir return type annotation’ını kullanabilirsiniz. 🤓 + +## Response Model encoding parametreleri { #response-model-encoding-parameters } + +Response model’inizde şu şekilde default değerler olabilir: + +{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *} + +* `description: Union[str, None] = None` (veya Python 3.10’da `str | None = None`) için default `None`’dır. +* `tax: float = 10.5` için default `10.5`’tir. +* `tags: List[str] = []` için default, boş bir list’tir: `[]`. + +Ancak gerçekte kaydedilmedilerse, bunları sonuçtan çıkarmak isteyebilirsiniz. + +Örneğin NoSQL veritabanında çok sayıda optional attribute içeren modelleriniz varsa, default değerlerle dolu çok uzun JSON response’ları göndermek istemeyebilirsiniz. + +### `response_model_exclude_unset` parametresini kullanın { #use-the-response-model-exclude-unset-parameter } + +*Path operation decorator* parametresi olarak `response_model_exclude_unset=True` ayarlayabilirsiniz: + +{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *} + +böylece response’a default değerler dahil edilmez; yalnızca gerçekten set edilmiş değerler gelir. + +Dolayısıyla ID’si `foo` olan item için bu *path operation*’a request atarsanız, response (default değerler olmadan) şöyle olur: + +```JSON +{ + "name": "Foo", + "price": 50.2 +} +``` + +/// info | Bilgi + +Ayrıca şunları da kullanabilirsiniz: + +* `response_model_exclude_defaults=True` +* `response_model_exclude_none=True` + +Bunlar, `exclude_defaults` ve `exclude_none` için Pydantic dokümanlarında anlatıldığı gibidir. + +/// + +#### Default’u olan field’lar için değer içeren data { #data-with-values-for-fields-with-defaults } + +Ama data’nız modelde default değeri olan field’lar için değer içeriyorsa, örneğin ID’si `bar` olan item gibi: + +```Python hl_lines="3 5" +{ + "name": "Bar", + "description": "The bartenders", + "price": 62, + "tax": 20.2 +} +``` + +bunlar response’a dahil edilir. + +#### Default değerlerle aynı değerlere sahip data { #data-with-the-same-values-as-the-defaults } + +Eğer data, default değerlerle aynı değerlere sahipse, örneğin ID’si `baz` olan item gibi: + +```Python hl_lines="3 5-6" +{ + "name": "Baz", + "description": None, + "price": 50.2, + "tax": 10.5, + "tags": [] +} +``` + +FastAPI yeterince akıllıdır (aslında Pydantic yeterince akıllıdır) ve `description`, `tax`, `tags` default ile aynı olsa bile bunların explicit olarak set edildiğini (default’tan alınmadığını) anlar. + +Bu yüzden JSON response içinde yer alırlar. + +/// tip | İpucu + +Default değerlerin yalnızca `None` olmak zorunda olmadığını unutmayın. + +Bir list (`[]`), `10.5` gibi bir `float` vb. olabilirler. + +/// + +### `response_model_include` ve `response_model_exclude` { #response-model-include-and-response-model-exclude } + +Ayrıca *path operation decorator* parametreleri `response_model_include` ve `response_model_exclude`’u da kullanabilirsiniz. + +Bunlar; dahil edilecek attribute isimlerini (geri kalanını atlayarak) ya da hariç tutulacak attribute isimlerini (geri kalanını dahil ederek) belirten `str` değerlerinden oluşan bir `set` alır. + +Tek bir Pydantic model’iniz varsa ve output’tan bazı verileri hızlıca çıkarmak istiyorsanız, bu yöntem pratik bir kısayol olabilir. + +/// tip | İpucu + +Ancak yine de, bu parametreler yerine yukarıdaki yaklaşımı (birden fazla class kullanmayı) tercih etmeniz önerilir. + +Çünkü `response_model_include` veya `response_model_exclude` ile bazı attribute’ları atlıyor olsanız bile, uygulamanızın OpenAPI’sinde (ve dokümanlarda) üretilen JSON Schema hâlâ tam modelin JSON Schema’sı olacaktır. + +Bu durum, benzer şekilde çalışan `response_model_by_alias` için de geçerlidir. + +/// + +{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *} + +/// tip | İpucu + +`{"name", "description"}` sözdizimi, bu iki değere sahip bir `set` oluşturur. + +Bu, `set(["name", "description"])` ile eşdeğerdir. + +/// + +#### `set` yerine `list` kullanmak { #using-lists-instead-of-sets } + +Yanlışlıkla `set` yerine `list` veya `tuple` kullanırsanız, FastAPI bunu yine `set`’e çevirir ve doğru şekilde çalışır: + +{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *} + +## Özet { #recap } + +Response model’leri tanımlamak ve özellikle private data’nın filtrelendiğinden emin olmak için *path operation decorator* parametresi `response_model`’i kullanın. + +Yalnızca explicit olarak set edilmiş değerleri döndürmek için `response_model_exclude_unset` kullanın. diff --git a/docs/tr/docs/tutorial/response-status-code.md b/docs/tr/docs/tutorial/response-status-code.md new file mode 100644 index 0000000000..57ae7bde34 --- /dev/null +++ b/docs/tr/docs/tutorial/response-status-code.md @@ -0,0 +1,101 @@ +# Response Status Code { #response-status-code } + +Bir response model tanımlayabildiğiniz gibi, herhangi bir *path operation* içinde `status_code` parametresiyle response için kullanılacak HTTP status code'u da belirtebilirsiniz: + +* `@app.get()` +* `@app.post()` +* `@app.put()` +* `@app.delete()` +* vb. + +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} + +/// note | Not + +`status_code`'un, "decorator" metodunun (`get`, `post`, vb.) bir parametresi olduğuna dikkat edin. Tüm parametreler ve body gibi, sizin *path operation function*'ınızın bir parametresi değildir. + +/// + +`status_code` parametresi, HTTP status code'u içeren bir sayı alır. + +/// info | Bilgi + +Alternatif olarak `status_code`, Python'un `http.HTTPStatus`'ı gibi bir `IntEnum` da alabilir. + +/// + +Bu sayede: + +* Response'da o status code döner. +* OpenAPI şemasında (dolayısıyla kullanıcı arayüzlerinde de) bu şekilde dokümante edilir: + + + +/// note | Not + +Bazı response code'lar (bir sonraki bölümde göreceğiz) response'un bir body'ye sahip olmadığını belirtir. + +FastAPI bunu bilir ve response body olmadığını söyleyen OpenAPI dokümantasyonunu üretir. + +/// + +## HTTP status code'lar hakkında { #about-http-status-codes } + +/// note | Not + +HTTP status code'ların ne olduğunu zaten biliyorsanız, bir sonraki bölüme geçin. + +/// + +HTTP'de, response'un bir parçası olarak 3 basamaklı sayısal bir status code gönderirsiniz. + +Bu status code'ların tanınmalarını sağlayan bir isimleri de vardır; ancak önemli olan kısım sayıdır. + +Kısaca: + +* `100 - 199` "Information" içindir. Doğrudan nadiren kullanırsınız. Bu status code'lara sahip response'lar body içeremez. +* **`200 - 299`** "Successful" response'lar içindir. En sık kullanacağınız aralık budur. + * `200`, varsayılan status code'dur ve her şeyin "OK" olduğunu ifade eder. + * Başka bir örnek `201` ("Created") olabilir. Genellikle veritabanında yeni bir kayıt oluşturduktan sonra kullanılır. + * Özel bir durum ise `204` ("No Content")'tür. Client'a döndürülecek içerik olmadığında kullanılır; bu nedenle response body olmamalıdır. +* **`300 - 399`** "Redirection" içindir. Bu status code'lara sahip response'lar, `304` ("Not Modified") hariç, body içerebilir de içermeyebilir de; `304` kesinlikle body içermemelidir. +* **`400 - 499`** "Client error" response'ları içindir. Muhtemelen en sık kullanacağınız ikinci aralık budur. + * Örneğin `404`, "Not Found" response'u içindir. + * Client kaynaklı genel hatalar için doğrudan `400` kullanabilirsiniz. +* `500 - 599` server hataları içindir. Neredeyse hiç doğrudan kullanmazsınız. Uygulama kodunuzun bir bölümünde ya da server'da bir şeyler ters giderse, otomatik olarak bu status code'lardan biri döner. + +/// tip | İpucu + +Her bir status code hakkında daha fazla bilgi almak ve hangi kodun ne için kullanıldığını görmek için HTTP status code'lar hakkında MDN dokümantasyonuna göz atın. + +/// + +## İsimleri hatırlamak için kısayol { #shortcut-to-remember-the-names } + +Önceki örneğe tekrar bakalım: + +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} + +`201`, "Created" için kullanılan status code'dur. + +Ancak bu kodların her birinin ne anlama geldiğini ezberlemek zorunda değilsiniz. + +`fastapi.status` içindeki kolaylık değişkenlerini (convenience variables) kullanabilirsiniz. + +{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *} + +Bunlar sadece kolaylık sağlar; aynı sayıyı taşırlar. Ancak bu şekilde editörün autocomplete özelliğiyle kolayca bulabilirsiniz: + + + +/// note | Teknik Detaylar + +`from starlette import status` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.status`'u `fastapi.status` olarak da sunar. Ancak bu aslında doğrudan Starlette'den gelir. + +/// + +## Varsayılanı değiştirmek { #changing-the-default } + +Daha sonra, [İleri Düzey Kullanıcı Kılavuzu](../advanced/response-change-status-code.md){.internal-link target=_blank} içinde, burada tanımladığınız varsayılanın dışında farklı bir status code nasıl döndüreceğinizi göreceksiniz. diff --git a/docs/tr/docs/tutorial/schema-extra-example.md b/docs/tr/docs/tutorial/schema-extra-example.md new file mode 100644 index 0000000000..a91dda8924 --- /dev/null +++ b/docs/tr/docs/tutorial/schema-extra-example.md @@ -0,0 +1,202 @@ +# Request Örnek Verilerini Tanımlama { #declare-request-example-data } + +Uygulamanızın alabileceği veriler için örnekler (examples) tanımlayabilirsiniz. + +Bunu yapmanın birkaç yolu var. + +## Pydantic modellerinde ek JSON Schema verisi { #extra-json-schema-data-in-pydantic-models } + +Oluşturulan JSON Schema’ya eklenecek şekilde bir Pydantic model için `examples` tanımlayabilirsiniz. + +{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *} + +Bu ek bilgi, o modelin çıktı **JSON Schema**’sına olduğu gibi eklenir ve API dokümanlarında kullanılır. + +Pydantic dokümanları: Configuration bölümünde anlatıldığı gibi, bir `dict` alan `model_config` niteliğini kullanabilirsiniz. + +Üretilen JSON Schema’da görünmesini istediğiniz (ör. `examples` dahil) her türlü ek veriyi içeren bir `dict` ile `"json_schema_extra"` ayarlayabilirsiniz. + +/// tip | İpucu + +Aynı tekniği JSON Schema’yı genişletmek ve kendi özel ek bilgilerinizi eklemek için de kullanabilirsiniz. + +Örneğin, bir frontend kullanıcı arayüzü için metadata eklemek vb. amaçlarla kullanılabilir. + +/// + +/// info | Bilgi + +OpenAPI 3.1.0 (FastAPI 0.99.0’dan beri kullanılıyor), **JSON Schema** standardının bir parçası olan `examples` için destek ekledi. + +Bundan önce yalnızca tek bir örnek için `example` anahtar kelimesini destekliyordu. Bu hâlâ OpenAPI 3.1.0 tarafından desteklenir; ancak artık deprecated durumdadır ve JSON Schema standardının parçası değildir. Bu nedenle `example` kullanımını `examples`’a taşımanız önerilir. 🤓 + +Daha fazlasını sayfanın sonunda okuyabilirsiniz. + +/// + +## `Field` ek argümanları { #field-additional-arguments } + +Pydantic modelleriyle `Field()` kullanırken ek `examples` de tanımlayabilirsiniz: + +{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *} + +## JSON Schema - OpenAPI içinde `examples` { #examples-in-json-schema-openapi } + +Aşağıdakilerden herhangi birini kullanırken: + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +OpenAPI içindeki **JSON Schema**’larına eklenecek ek bilgilerle birlikte bir `examples` grubu da tanımlayabilirsiniz. + +### `examples` ile `Body` { #body-with-examples } + +Burada `Body()` içinde beklenen veri için tek bir örnek içeren `examples` geçiriyoruz: + +{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *} + +### Doküman arayüzünde örnek { #example-in-the-docs-ui } + +Yukarıdaki yöntemlerden herhangi biriyle `/docs` içinde şöyle görünür: + + + +### Birden fazla `examples` ile `Body` { #body-with-multiple-examples } + +Elbette birden fazla `examples` da geçebilirsiniz: + +{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *} + +Bunu yaptığınızda, örnekler bu body verisi için dahili **JSON Schema**’nın bir parçası olur. + +Buna rağmen, time of writing this, doküman arayüzünü gösteren araç olan Swagger UI, **JSON Schema** içindeki veriler için birden fazla örneği göstermeyi desteklemiyor. Ancak aşağıda bir çözüm yolu var. + +### OpenAPI’ye özel `examples` { #openapi-specific-examples } + +**JSON Schema** `examples`’ı desteklemeden önce OpenAPI, yine `examples` adlı farklı bir alanı destekliyordu. + +Bu **OpenAPI’ye özel** `examples`, OpenAPI spesifikasyonunda başka bir bölümde yer alır. Her bir JSON Schema’nın içinde değil, **her bir *path operation* detayları** içinde bulunur. + +Swagger UI da bu özel `examples` alanını bir süredir destekliyor. Dolayısıyla bunu, **doküman arayüzünde** farklı **örnekleri göstermek** için kullanabilirsiniz. + +OpenAPI’ye özel bu `examples` alanının şekli, (bir `list` yerine) **birden fazla örnek** içeren bir `dict`’tir; her örnek ayrıca **OpenAPI**’ye eklenecek ekstra bilgiler içerir. + +Bu, OpenAPI’nin içerdiği JSON Schema’ların içine girmez; bunun yerine doğrudan *path operation* üzerinde, dışarıda yer alır. + +### `openapi_examples` Parametresini Kullanma { #using-the-openapi-examples-parameter } + +FastAPI’de OpenAPI’ye özel `examples`’ı, şu araçlar için `openapi_examples` parametresiyle tanımlayabilirsiniz: + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +`dict`’in anahtarları her bir örneği tanımlar; her bir değer ise başka bir `dict`’tir. + +`examples` içindeki her bir örnek `dict`’i şunları içerebilir: + +* `summary`: Örnek için kısa açıklama. +* `description`: Markdown metni içerebilen uzun açıklama. +* `value`: Gösterilecek gerçek örnek (ör. bir `dict`). +* `externalValue`: `value`’a alternatif; örneğe işaret eden bir URL. Ancak bu, `value` kadar çok araç tarafından desteklenmiyor olabilir. + +Şöyle kullanabilirsiniz: + +{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *} + +### Doküman Arayüzünde OpenAPI Örnekleri { #openapi-examples-in-the-docs-ui } + +`Body()`’ye `openapi_examples` eklendiğinde `/docs` şöyle görünür: + + + +## Teknik Detaylar { #technical-details } + +/// tip | İpucu + +Zaten **FastAPI** sürümü **0.99.0 veya üzerini** kullanıyorsanız, büyük olasılıkla bu detayları **atlanabilirsiniz**. + +Bunlar daha çok OpenAPI 3.1.0’ın henüz mevcut olmadığı eski sürümler için geçerlidir. + +Bunu kısa bir OpenAPI ve JSON Schema **tarih dersi** gibi düşünebilirsiniz. 🤓 + +/// + +/// warning | Uyarı + +Bunlar **JSON Schema** ve **OpenAPI** standartları hakkında oldukça teknik detaylardır. + +Yukarıdaki fikirler sizin için zaten çalışıyorsa bu kadarı yeterli olabilir; muhtemelen bu detaylara ihtiyacınız yoktur, gönül rahatlığıyla atlayabilirsiniz. + +/// + +OpenAPI 3.1.0’dan önce OpenAPI, **JSON Schema**’nın daha eski ve değiştirilmiş bir sürümünü kullanıyordu. + +JSON Schema’da `examples` yoktu; bu yüzden OpenAPI, değiştirilmiş sürümüne kendi `example` alanını ekledi. + +OpenAPI ayrıca spesifikasyonun diğer bölümlerine de `example` ve `examples` alanlarını ekledi: + +* `Parameter Object` (spesifikasyonda) — FastAPI’de şunlar tarafından kullanılıyordu: + * `Path()` + * `Query()` + * `Header()` + * `Cookie()` +* `Request Body Object`; `content` alanında, `Media Type Object` üzerinde (spesifikasyonda) — FastAPI’de şunlar tarafından kullanılıyordu: + * `Body()` + * `File()` + * `Form()` + +/// info | Bilgi + +Bu eski OpenAPI’ye özel `examples` parametresi, FastAPI `0.103.0` sürümünden beri `openapi_examples` olarak kullanılıyor. + +/// + +### JSON Schema’nın `examples` alanı { #json-schemas-examples-field } + +Sonrasında JSON Schema, spesifikasyonun yeni bir sürümüne `examples` alanını ekledi. + +Ardından yeni OpenAPI 3.1.0, bu yeni `examples` alanını içeren en güncel sürümü (JSON Schema 2020-12) temel aldı. + +Ve artık, deprecated olan eski tekil (ve özel) `example` alanına kıyasla bu yeni `examples` alanı önceliklidir. + +JSON Schema’daki bu yeni `examples` alanı, OpenAPI’de başka yerlerde kullanılan (yukarıda anlatılan) metadata’lı `dict` yapısından farklı olarak **sadece örneklerden oluşan bir `list`**’tir. + +/// info | Bilgi + +OpenAPI 3.1.0, JSON Schema ile bu yeni ve daha basit entegrasyonla yayımlandıktan sonra bile bir süre, otomatik dokümantasyonu sağlayan araç Swagger UI OpenAPI 3.1.0’ı desteklemiyordu (5.0.0 sürümünden beri destekliyor 🎉). + +Bu nedenle, FastAPI’nin 0.99.0 öncesi sürümleri OpenAPI 3.1.0’dan daha düşük sürümleri kullanmaya devam etti. + +/// + +### Pydantic ve FastAPI `examples` { #pydantic-and-fastapi-examples } + +Bir Pydantic modelinin içine `schema_extra` ya da `Field(examples=["something"])` kullanarak `examples` eklediğinizde, bu örnek o Pydantic modelinin **JSON Schema**’sına eklenir. + +Ve Pydantic modelinin bu **JSON Schema**’sı, API’nizin **OpenAPI**’sine dahil edilir; ardından doküman arayüzünde kullanılır. + +FastAPI 0.99.0’dan önceki sürümlerde (0.99.0 ve üzeri daha yeni OpenAPI 3.1.0’ı kullanır) `Query()`, `Body()` vb. diğer araçlarla `example` veya `examples` kullandığınızda, bu örnekler o veriyi tanımlayan JSON Schema’ya (OpenAPI’nin kendi JSON Schema sürümüne bile) eklenmiyordu; bunun yerine doğrudan OpenAPI’deki *path operation* tanımına ekleniyordu (JSON Schema kullanan OpenAPI bölümlerinin dışında). + +Ancak artık FastAPI 0.99.0 ve üzeri OpenAPI 3.1.0 kullandığı (JSON Schema 2020-12) ve Swagger UI 5.0.0 ve üzeriyle birlikte, her şey daha tutarlı ve örnekler JSON Schema’ya dahil ediliyor. + +### Swagger UI ve OpenAPI’ye özel `examples` { #swagger-ui-and-openapi-specific-examples } + +Swagger UI (2023-08-26 itibarıyla) birden fazla JSON Schema örneğini desteklemediği için, kullanıcıların dokümanlarda birden fazla örnek göstermesi mümkün değildi. + +Bunu çözmek için FastAPI `0.103.0`, yeni `openapi_examples` parametresiyle aynı eski **OpenAPI’ye özel** `examples` alanını tanımlamayı **desteklemeye başladı**. 🤓 + +### Özet { #summary } + +Eskiden tarihten pek hoşlanmadığımı söylerdim... şimdi bakın, "teknoloji tarihi" dersi anlatıyorum. 😅 + +Kısacası, **FastAPI 0.99.0 veya üzerine yükseltin**; her şey çok daha **basit, tutarlı ve sezgisel** olur ve bu tarihsel detayların hiçbirini bilmeniz gerekmez. 😎 diff --git a/docs/tr/docs/tutorial/security/first-steps.md b/docs/tr/docs/tutorial/security/first-steps.md new file mode 100644 index 0000000000..7e0a70a02c --- /dev/null +++ b/docs/tr/docs/tutorial/security/first-steps.md @@ -0,0 +1,203 @@ +# Güvenlik - İlk Adımlar { #security-first-steps } + +**backend** API’nizin bir domain’de olduğunu düşünelim. + +Ve başka bir domain’de ya da aynı domain’in farklı bir path’inde (veya bir mobil uygulamada) bir **frontend**’iniz var. + +Ve frontend’in, **username** ve **password** kullanarak backend ile kimlik doğrulaması yapabilmesini istiyorsunuz. + +Bunu **FastAPI** ile **OAuth2** kullanarak oluşturabiliriz. + +Ama ihtiyacınız olan küçük bilgi parçalarını bulmak için uzun spesifikasyonun tamamını okuma zahmetine girmeyelim. + +Güvenliği yönetmek için **FastAPI**’nin sunduğu araçları kullanalım. + +## Nasıl Görünüyor { #how-it-looks } + +Önce kodu kullanıp nasıl çalıştığına bakalım, sonra neler olup bittiğini anlamak için geri döneriz. + +## `main.py` Oluşturun { #create-main-py } + +Örneği `main.py` adlı bir dosyaya kopyalayın: + +{* ../../docs_src/security/tutorial001_an_py39.py *} + +## Çalıştırın { #run-it } + +/// info | Bilgi + +`python-multipart` paketi, `pip install "fastapi[standard]"` komutunu çalıştırdığınızda **FastAPI** ile birlikte otomatik olarak kurulur. + +Ancak `pip install fastapi` komutunu kullanırsanız, `python-multipart` paketi varsayılan olarak dahil edilmez. + +Elle kurmak için bir [virtual environment](../../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktive ettiğinizden emin olun ve ardından şununla kurun: + +```console +$ pip install python-multipart +``` + +Bunun nedeni, **OAuth2**’nin `username` ve `password` göndermek için "form data" kullanmasıdır. + +/// + +Örneği şu şekilde çalıştırın: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +## Kontrol Edin { #check-it } + +Etkileşimli dokümantasyona gidin: http://127.0.0.1:8000/docs. + +Şuna benzer bir şey göreceksiniz: + + + +/// check | Authorize butonu! + +Artık parıl parıl yeni bir "Authorize" butonunuz var. + +Ayrıca *path operation*’ınızın sağ üst köşesinde tıklayabileceğiniz küçük bir kilit simgesi de bulunuyor. + +/// + +Ve ona tıklarsanız, `username` ve `password` (ve diğer opsiyonel alanları) girebileceğiniz küçük bir yetkilendirme formu görürsünüz: + + + +/// note | Not + +Formda ne yazdığınızın önemi yok; şimdilik çalışmayacak. Ama birazdan oraya da geleceğiz. + +/// + +Bu, elbette son kullanıcılar için bir frontend değil; ancak tüm API’nizi etkileşimli şekilde belgelemek için harika bir otomatik araçtır. + +Frontend ekibi tarafından kullanılabilir (bu ekip siz de olabilirsiniz). + +Üçüncü taraf uygulamalar ve sistemler tarafından kullanılabilir. + +Ve aynı uygulamayı debug etmek, kontrol etmek ve test etmek için sizin tarafınızdan da kullanılabilir. + +## `password` Flow { #the-password-flow } + +Şimdi biraz geri dönüp bunların ne olduğuna bakalım. + +`password` "flow"u, OAuth2’de güvenlik ve authentication’ı yönetmek için tanımlanmış yöntemlerden ("flow"lardan) biridir. + +OAuth2, backend’in veya API’nin, kullanıcıyı authenticate eden server’dan bağımsız olabilmesi için tasarlanmıştır. + +Ancak bu örnekte, aynı **FastAPI** uygulaması hem API’yi hem de authentication’ı yönetecek. + +O yüzden basitleştirilmiş bu bakış açısından üzerinden geçelim: + +* Kullanıcı frontend’de `username` ve `password` yazar ve `Enter`’a basar. +* Frontend (kullanıcının browser’ında çalışır), bu `username` ve `password` değerlerini API’mizdeki belirli bir URL’ye gönderir (`tokenUrl="token"` ile tanımlanan). +* API, `username` ve `password` değerlerini kontrol eder ve bir "token" ile response döner (henüz bunların hiçbirini implement etmedik). + * "Token", daha sonra bu kullanıcıyı doğrulamak için kullanabileceğimiz içerik taşıyan bir string’dir. + * Normalde token’ın bir süre sonra süresi dolacak şekilde ayarlanması beklenir. + * Böylece kullanıcının bir noktada tekrar giriş yapması gerekir. + * Ayrıca token çalınırsa risk daha düşük olur. Çoğu durumda, sonsuza kadar çalışacak kalıcı bir anahtar gibi değildir. +* Frontend bu token’ı geçici olarak bir yerde saklar. +* Kullanıcı frontend’de tıklayarak web uygulamasının başka bir bölümüne gider. +* Frontend’in API’den daha fazla veri alması gerekir. + * Ancak o endpoint için authentication gereklidir. + * Bu yüzden API’mizle authenticate olmak için `Authorization` header’ını, `Bearer ` + token değeriyle gönderir. + * Token `foobar` içeriyorsa `Authorization` header’ının içeriği `Bearer foobar` olur. + +## **FastAPI**’nin `OAuth2PasswordBearer`’ı { #fastapis-oauth2passwordbearer } + +**FastAPI**, bu güvenlik özelliklerini implement etmek için farklı soyutlama seviyelerinde çeşitli araçlar sağlar. + +Bu örnekte **OAuth2**’yi, **Password** flow ile, **Bearer** token kullanarak uygulayacağız. Bunu `OAuth2PasswordBearer` sınıfı ile yaparız. + +/// info | Bilgi + +"Bearer" token tek seçenek değildir. + +Ama bizim kullanım senaryomuz için en iyi seçenek odur. + +Ayrıca bir OAuth2 uzmanı değilseniz ve ihtiyaçlarınıza daha uygun başka bir seçeneğin neden gerekli olduğunu net olarak bilmiyorsanız, çoğu kullanım senaryosu için de en uygun seçenek olacaktır. + +Bu durumda bile **FastAPI**, onu oluşturabilmeniz için gereken araçları sunar. + +/// + +`OAuth2PasswordBearer` sınıfının bir instance’ını oluştururken `tokenUrl` parametresini veririz. Bu parametre, client’ın (kullanıcının browser’ında çalışan frontend’in) token almak için `username` ve `password` göndereceği URL’yi içerir. + +{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *} + +/// tip | İpucu + +Burada `tokenUrl="token"`, henüz oluşturmadığımız göreli bir URL olan `token`’ı ifade eder. Göreli URL olduğu için `./token` ile eşdeğerdir. + +Göreli URL kullandığımız için, API’niz `https://example.com/` adresinde olsaydı `https://example.com/token` anlamına gelirdi. Ama API’niz `https://example.com/api/v1/` adresinde olsaydı, bu kez `https://example.com/api/v1/token` anlamına gelirdi. + +Göreli URL kullanmak, [Behind a Proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank} gibi daha ileri kullanım senaryolarında bile uygulamanızın çalışmaya devam etmesini garanti etmek açısından önemlidir. + +/// + +Bu parametre o endpoint’i / *path operation*’ı oluşturmaz; fakat `/token` URL’sinin client’ın token almak için kullanması gereken URL olduğunu bildirir. Bu bilgi OpenAPI’de, dolayısıyla etkileşimli API dokümantasyon sistemlerinde kullanılır. + +Birazdan gerçek path operation’ı da oluşturacağız. + +/// info | Teknik Detaylar + +Eğer çok katı bir "Pythonista" iseniz, `token_url` yerine `tokenUrl` şeklindeki parametre adlandırma stilini sevmeyebilirsiniz. + +Bunun nedeni, OpenAPI spesifikasyonundaki isimle aynı adın kullanılmasıdır. Böylece bu güvenlik şemalarından herhangi biri hakkında daha fazla araştırma yapmanız gerekirse, adı kopyalayıp yapıştırarak kolayca daha fazla bilgi bulabilirsiniz. + +/// + +`oauth2_scheme` değişkeni, `OAuth2PasswordBearer`’ın bir instance’ıdır; ama aynı zamanda "callable"dır. + +Şu şekilde çağrılabilir: + +```Python +oauth2_scheme(some, parameters) +``` + +Dolayısıyla `Depends` ile kullanılabilir. + +### Kullanın { #use-it } + +Artık `Depends` ile bir dependency olarak `oauth2_scheme`’i geçebilirsiniz. + +{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *} + +Bu dependency, *path operation function* içindeki `token` parametresine atanacak bir `str` sağlar. + +**FastAPI**, bu dependency’yi OpenAPI şemasında (ve otomatik API dokümanlarında) bir "security scheme" tanımlamak için kullanabileceğini bilir. + +/// info | Teknik Detaylar + +**FastAPI**, bir dependency içinde tanımlanan `OAuth2PasswordBearer` sınıfını OpenAPI’de security scheme tanımlamak için kullanabileceğini bilir; çünkü bu sınıf `fastapi.security.oauth2.OAuth2`’den kalıtım alır, o da `fastapi.security.base.SecurityBase`’den kalıtım alır. + +OpenAPI (ve otomatik API dokümanları) ile entegre olan tüm security araçları `SecurityBase`’den kalıtım alır; **FastAPI** bu sayede onları OpenAPI’ye nasıl entegre edeceğini anlayabilir. + +/// + +## Ne Yapar { #what-it-does } + +Request içinde `Authorization` header’ını arar, değerin `Bearer ` + bir token olup olmadığını kontrol eder ve token’ı `str` olarak döndürür. + +Eğer `Authorization` header’ını görmezse ya da değer `Bearer ` token’ı içermiyorsa, doğrudan 401 status code hatasıyla (`UNAUTHORIZED`) response döner. + +Token’ın var olup olmadığını kontrol edip ayrıca hata döndürmenize bile gerek yoktur. Fonksiyonunuz çalışıyorsa, token içinde bir `str` olacağından emin olabilirsiniz. + +Bunu şimdiden etkileşimli dokümanlarda deneyebilirsiniz: + + + +Henüz token’ın geçerliliğini doğrulamıyoruz, ama başlangıç için bu bile yeterli. + +## Özet { #recap } + +Yani sadece 3 veya 4 ekstra satırla, şimdiden ilkel de olsa bir güvenlik katmanı elde etmiş oldunuz. diff --git a/docs/tr/docs/tutorial/security/get-current-user.md b/docs/tr/docs/tutorial/security/get-current-user.md new file mode 100644 index 0000000000..9f56c76289 --- /dev/null +++ b/docs/tr/docs/tutorial/security/get-current-user.md @@ -0,0 +1,105 @@ +# Mevcut Kullanıcıyı Alma { #get-current-user } + +Önceki bölümde güvenlik sistemi (dependency injection sistemine dayanır) *path operation function*'a `str` olarak bir `token` veriyordu: + +{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *} + +Ancak bu hâlâ pek kullanışlı değil. + +Bize mevcut kullanıcıyı verecek şekilde düzenleyelim. + +## Bir kullanıcı modeli oluşturun { #create-a-user-model } + +Önce bir Pydantic kullanıcı modeli oluşturalım. + +Body'leri bildirmek için Pydantic'i nasıl kullanıyorsak, aynı şekilde onu başka her yerde de kullanabiliriz: + +{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *} + +## `get_current_user` dependency'si oluşturun { #create-a-get-current-user-dependency } + +Bir `get_current_user` dependency'si oluşturalım. + +Dependency'lerin alt dependency'leri olabileceğini hatırlıyor musunuz? + +`get_current_user`, daha önce oluşturduğumuz `oauth2_scheme` ile aynı dependency'yi kullanacak. + +Daha önce *path operation* içinde doğrudan yaptığımız gibi, yeni dependency'miz `get_current_user`, alt dependency olan `oauth2_scheme` üzerinden `str` olarak bir `token` alacak: + +{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *} + +## Kullanıcıyı alın { #get-the-user } + +`get_current_user`, oluşturduğumuz (sahte) bir yardımcı (utility) fonksiyonu kullanacak; bu fonksiyon `str` olarak bir token alır ve Pydantic `User` modelimizi döndürür: + +{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *} + +## Mevcut kullanıcıyı enjekte edin { #inject-the-current-user } + +Artık *path operation* içinde `get_current_user` ile aynı `Depends` yaklaşımını kullanabiliriz: + +{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *} + +`current_user` tipini Pydantic `User` modeli olarak belirttiğimize dikkat edin. + +Bu sayede fonksiyonun içinde otomatik tamamlama ve tip kontrollerinin tamamından faydalanırız. + +/// tip | İpucu + +Request body'lerinin de Pydantic modelleri ile bildirildiğini hatırlıyor olabilirsiniz. + +Burada `Depends` kullandığınız için **FastAPI** karışıklık yaşamaz. + +/// + +/// check | Ek bilgi + +Bu dependency sisteminin tasarımı, hepsi `User` modeli döndüren farklı dependency'lere (farklı "dependable"lara) sahip olmamıza izin verir. + +Bu tipte veri döndürebilen yalnızca tek bir dependency ile sınırlı değiliz. + +/// + +## Diğer modeller { #other-models } + +Artık *path operation function* içinde mevcut kullanıcıyı doğrudan alabilir ve güvenlik mekanizmalarını `Depends` kullanarak **Dependency Injection** seviyesinde yönetebilirsiniz. + +Ayrıca güvenlik gereksinimleri için herhangi bir model veya veri kullanabilirsiniz (bu örnekte bir Pydantic `User` modeli). + +Ancak belirli bir data model, class ya da type kullanmak zorunda değilsiniz. + +Modelinizde bir `id` ve `email` olsun, ama `username` olmasın mı istiyorsunuz? Elbette. Aynı araçları kullanabilirsiniz. + +Sadece bir `str` mı istiyorsunuz? Ya da sadece bir `dict`? Veya doğrudan bir veritabanı class model instance'ı? Hepsi aynı şekilde çalışır. + +Uygulamanıza giriş yapan kullanıcılar yok da robotlar, botlar veya yalnızca bir access token'a sahip başka sistemler mi var? Yine, her şey aynı şekilde çalışır. + +Uygulamanız için neye ihtiyacınız varsa o türden bir model, class ve veritabanı kullanın. **FastAPI**, dependency injection sistemiyle bunları destekler. + +## Kod boyutu { #code-size } + +Bu örnek biraz uzun görünebilir. Güvenlik, data model'ler, utility fonksiyonlar ve *path operation*'ları aynı dosyada bir araya getirdiğimizi unutmayın. + +Ama kritik nokta şu: + +Güvenlik ve dependency injection tarafını bir kez yazarsınız. + +İstediğiniz kadar karmaşık hâle getirebilirsiniz. Yine de hepsi tek bir yerde ve sadece bir kez yazılmış olur. Üstelik tüm esneklikle. + +Sonrasında aynı güvenlik sistemini kullanan binlerce endpoint (*path operation*) olabilir. + +Ve bunların hepsi (ya da istediğiniz bir kısmı) bu dependency'leri veya oluşturacağınız başka dependency'leri yeniden kullanmaktan faydalanabilir. + +Hatta bu binlerce *path operation* 3 satır kadar kısa olabilir: + +{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *} + +## Özet { #recap } + +Artık *path operation function* içinde mevcut kullanıcıyı doğrudan alabilirsiniz. + +Yolun yarısına geldik. + +Kullanıcının/istemcinin gerçekten `username` ve `password` göndermesini sağlayacak bir *path operation* eklememiz gerekiyor. + +Sırada bu var. diff --git a/docs/tr/docs/tutorial/security/index.md b/docs/tr/docs/tutorial/security/index.md new file mode 100644 index 0000000000..a592db6df5 --- /dev/null +++ b/docs/tr/docs/tutorial/security/index.md @@ -0,0 +1,106 @@ +# Güvenlik { #security } + +Güvenlik, authentication ve authorization’ı ele almanın birçok yolu vardır. + +Ve bu konu genellikle karmaşık ve "zor"dur. + +Birçok framework ve sistemde yalnızca security ve authentication’ı yönetmek bile ciddi miktarda emek ve kod gerektirir (çoğu durumda yazılan toplam kodun %50’si veya daha fazlası olabilir). + +**FastAPI**, tüm security spesifikasyonlarını baştan sona inceleyip öğrenmek zorunda kalmadan **Security** konusunu kolay, hızlı ve standart bir şekilde ele almanıza yardımcı olacak çeşitli araçlar sunar. + +Ama önce, küçük birkaç kavrama bakalım. + +## Acelem var? { #in-a-hurry } + +Bu terimlerin hiçbirini umursamıyorsanız ve sadece kullanıcı adı ve parola tabanlı authentication ile security’yi *hemen şimdi* eklemeniz gerekiyorsa, bir sonraki bölümlere geçin. + +## OAuth2 { #oauth2 } + +OAuth2, authentication ve authorization’ı yönetmek için çeşitli yöntemleri tanımlayan bir spesifikasyondur. + +Oldukça kapsamlı bir spesifikasyondur ve birkaç karmaşık use case’i kapsar. + +"Üçüncü taraf" kullanarak authentication yapmanın yollarını da içerir. + +"Facebook, Google, X (Twitter), GitHub ile giriş yap" bulunan sistemlerin arka planda kullandığı şey de budur. + +### OAuth 1 { #oauth-1 } + +OAuth 1 de vardı; OAuth2’den çok farklıdır ve daha karmaşıktır, çünkü iletişimi nasıl şifreleyeceğinize dair doğrudan spesifikasyonlar içeriyordu. + +Günümüzde pek popüler değildir veya pek kullanılmaz. + +OAuth2 ise iletişimin nasıl şifreleneceğini belirtmez; uygulamanızın HTTPS ile sunulmasını bekler. + +/// tip | İpucu + +**deployment** bölümünde Traefik ve Let's Encrypt kullanarak ücretsiz şekilde HTTPS’i nasıl kuracağınızı göreceksiniz. + +/// + +## OpenID Connect { #openid-connect } + +OpenID Connect, **OAuth2** tabanlı başka bir spesifikasyondur. + +OAuth2’de nispeten belirsiz kalan bazı noktaları tanımlayarak onu daha birlikte çalışabilir (interoperable) hâle getirmeye çalışır. + +Örneğin, Google ile giriş OpenID Connect kullanır (arka planda OAuth2 kullanır). + +Ancak Facebook ile giriş OpenID Connect’i desteklemez. Kendine özgü bir OAuth2 çeşidi vardır. + +### OpenID ("OpenID Connect" değil) { #openid-not-openid-connect } + +Bir de "OpenID" spesifikasyonu vardı. Bu da **OpenID Connect** ile aynı problemi çözmeye çalışıyordu ama OAuth2 tabanlı değildi. + +Dolayısıyla tamamen ayrı, ek bir sistemdi. + +Günümüzde pek popüler değildir veya pek kullanılmaz. + +## OpenAPI { #openapi } + +OpenAPI (önceden Swagger olarak biliniyordu), API’ler inşa etmek için açık spesifikasyondur (artık Linux Foundation’ın bir parçası). + +**FastAPI**, **OpenAPI** tabanlıdır. + +Bu sayede birden fazla otomatik etkileşimli dokümantasyon arayüzü, code generation vb. mümkün olur. + +OpenAPI, birden fazla security "scheme" tanımlamanın bir yolunu sunar. + +Bunları kullanarak, etkileşimli dokümantasyon sistemleri de dahil olmak üzere tüm bu standart tabanlı araçlardan faydalanabilirsiniz. + +OpenAPI şu security scheme’lerini tanımlar: + +* `apiKey`: uygulamaya özel bir anahtar; şuradan gelebilir: + * Bir query parameter. + * Bir header. + * Bir cookie. +* `http`: standart HTTP authentication sistemleri, örneğin: + * `bearer`: `Authorization` header’ı; değeri `Bearer ` + bir token olacak şekilde. Bu, OAuth2’den gelir. + * HTTP Basic authentication. + * HTTP Digest, vb. +* `oauth2`: OAuth2 ile security’yi yönetmenin tüm yolları ("flow" olarak adlandırılır). + * Bu flow’ların birçoğu, bir OAuth 2.0 authentication provider (Google, Facebook, X (Twitter), GitHub vb.) oluşturmak için uygundur: + * `implicit` + * `clientCredentials` + * `authorizationCode` + * Ancak, aynı uygulamanın içinde doğrudan authentication yönetmek için mükemmel şekilde kullanılabilecek özel bir "flow" vardır: + * `password`: sonraki bazı bölümlerde bunun örnekleri ele alınacak. +* `openIdConnect`: OAuth2 authentication verisinin otomatik olarak nasıl keşfedileceğini tanımlamanın bir yolunu sunar. + * Bu otomatik keşif, OpenID Connect spesifikasyonunda tanımlanan şeydir. + + +/// tip | İpucu + +Google, Facebook, X (Twitter), GitHub vb. gibi diğer authentication/authorization provider’larını entegre etmek de mümkündür ve nispeten kolaydır. + +En karmaşık kısım, bu tür bir authentication/authorization provider’ı inşa etmektir; ancak **FastAPI** ağır işleri sizin yerinize yaparken bunu kolayca yapabilmeniz için araçlar sunar. + +/// + +## **FastAPI** yardımcı araçları { #fastapi-utilities } + +FastAPI, `fastapi.security` modülünde bu security scheme’lerinin her biri için, bu mekanizmaları kullanmayı kolaylaştıran çeşitli araçlar sağlar. + +Sonraki bölümlerde, **FastAPI**’nin sunduğu bu araçları kullanarak API’nize nasıl security ekleyeceğinizi göreceksiniz. + +Ayrıca bunun etkileşimli dokümantasyon sistemine nasıl otomatik olarak entegre edildiğini de göreceksiniz. diff --git a/docs/tr/docs/tutorial/security/oauth2-jwt.md b/docs/tr/docs/tutorial/security/oauth2-jwt.md new file mode 100644 index 0000000000..716761157c --- /dev/null +++ b/docs/tr/docs/tutorial/security/oauth2-jwt.md @@ -0,0 +1,273 @@ +# Password ile OAuth2 (ve hashing), JWT token'ları ile Bearer { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens } + +Artık tüm security flow elimizde olduğuna göre, uygulamayı gerçekten güvenli hâle getirelim: JWT token'ları ve güvenli password hashing kullanacağız. + +Bu kodu uygulamanızda gerçekten kullanabilirsiniz; password hash'lerini veritabanınıza kaydedebilirsiniz, vb. + +Bir önceki bölümde bıraktığımız yerden başlayıp üzerine ekleyerek ilerleyeceğiz. + +## JWT Hakkında { #about-jwt } + +JWT, "JSON Web Tokens" anlamına gelir. + +Bir JSON nesnesini, boşluk içermeyen uzun ve yoğun bir string'e kodlamak için kullanılan bir standarttır. Şuna benzer: + +``` +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +``` + +Şifrelenmiş değildir; yani herkes içeriğindeki bilgiyi geri çıkarabilir. + +Ancak imzalanmıştır. Bu yüzden, sizin ürettiğiniz bir token'ı aldığınızda, gerçekten onu sizin ürettiğinizi doğrulayabilirsiniz. + +Bu şekilde, örneğin 1 haftalık süre sonu (expiration) olan bir token oluşturabilirsiniz. Sonra kullanıcı ertesi gün token ile geri geldiğinde, kullanıcının hâlâ sisteminizde oturum açmış olduğunu bilirsiniz. + +Bir hafta sonra token'ın süresi dolar; kullanıcı yetkilendirilmez ve yeni bir token almak için tekrar giriş yapmak zorunda kalır. Ayrıca kullanıcı (veya üçüncü bir taraf) token'ı değiştirip süre sonunu farklı göstermek isterse bunu tespit edebilirsiniz; çünkü imzalar eşleşmez. + +JWT token'larıyla oynayıp nasıl çalıştıklarını görmek isterseniz https://jwt.io adresine bakın. + +## `PyJWT` Kurulumu { #install-pyjwt } + +Python'da JWT token'larını üretmek ve doğrulamak için `PyJWT` kurmamız gerekiyor. + +Bir [virtual environment](../../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan emin olun, aktif edin ve ardından `pyjwt` kurun: + +
+ +```console +$ pip install pyjwt + +---> 100% +``` + +
+ +/// info | Bilgi + +RSA veya ECDSA gibi dijital imza algoritmaları kullanmayı planlıyorsanız, `pyjwt[crypto]` bağımlılığı olan `cryptography` kütüphanesini kurmalısınız. + +Daha fazla bilgi için PyJWT Installation docs sayfasını okuyabilirsiniz. + +/// + +## Password hashing { #password-hashing } + +"Hashing", bazı içerikleri (bu örnekte bir password) anlamsız görünen bir bayt dizisine (pratikte bir string) dönüştürmek demektir. + +Aynı içeriği (aynı password'ü) her seferinde verirseniz, her seferinde aynı anlamsız çıktıyı elde edersiniz. + +Ancak bu anlamsız çıktıdan geri password'e dönüştürme yapılamaz. + +### Neden password hashing kullanılır { #why-use-password-hashing } + +Veritabanınız çalınırsa, hırsız kullanıcılarınızın düz metin (plaintext) password'lerini değil, sadece hash'leri elde eder. + +Dolayısıyla, o password'ü başka bir sistemde denemek kolay olmaz (pek çok kullanıcı her yerde aynı password'ü kullandığı için bu tehlikeli olurdu). + +## `pwdlib` Kurulumu { #install-pwdlib } + +pwdlib, password hash'leriyle çalışmak için çok iyi bir Python paketidir. + +Birçok güvenli hashing algoritmasını ve bunlarla çalışmak için yardımcı araçları destekler. + +Önerilen algoritma "Argon2"dir. + +Bir [virtual environment](../../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan emin olun, aktif edin ve sonra Argon2 ile birlikte pwdlib'i kurun: + +
+ +```console +$ pip install "pwdlib[argon2]" + +---> 100% +``` + +
+ +/// tip | İpucu + +`pwdlib` ile, **Django** tarafından oluşturulmuş password'leri, bir **Flask** security eklentisinin ürettiklerini veya başka birçok kaynaktan gelen password'leri okuyabilecek şekilde bile yapılandırabilirsiniz. + +Böylece örneğin bir Django uygulamasındaki verileri aynı veritabanında bir FastAPI uygulamasıyla paylaşabilirsiniz. Ya da aynı veritabanını kullanarak bir Django uygulamasını kademeli şekilde taşıyabilirsiniz. + +Ayrıca kullanıcılarınız, aynı anda hem Django uygulamanızdan hem de **FastAPI** uygulamanızdan login olabilir. + +/// + +## Password'leri hash'leme ve doğrulama { #hash-and-verify-the-passwords } + +Gerekli araçları `pwdlib` içinden import edelim. + +Önerilen ayarlarla bir PasswordHash instance'ı oluşturalım; bunu password'leri hash'lemek ve doğrulamak için kullanacağız. + +/// tip | İpucu + +pwdlib, bcrypt hashing algoritmasını da destekler; ancak legacy algoritmaları içermez. Eski hash'lerle çalışmak için passlib kütüphanesini kullanmanız önerilir. + +Örneğin, başka bir sistemin (Django gibi) ürettiği password'leri okuyup doğrulayabilir, ancak yeni password'leri Argon2 veya Bcrypt gibi farklı bir algoritmayla hash'leyebilirsiniz. + +Ve aynı anda hepsiyle uyumlu kalabilirsiniz. + +/// + +Kullanıcıdan gelen password'ü hash'lemek için bir yardımcı (utility) fonksiyon oluşturalım. + +Sonra, alınan password'ün kayıttaki hash ile eşleşip eşleşmediğini doğrulayan başka bir yardımcı fonksiyon yazalım. + +Bir tane de kullanıcıyı authenticate edip geri döndüren bir yardımcı fonksiyon ekleyelim. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *} + +/// note | Not + +Yeni (sahte) veritabanı `fake_users_db`'ye bakarsanız, hash'lenmiş password'ün artık nasıl göründüğünü görebilirsiniz: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. + +/// + +## JWT token'larını yönetme { #handle-jwt-tokens } + +Kurulu modülleri import edelim. + +JWT token'larını imzalamak için kullanılacak rastgele bir secret key oluşturalım. + +Güvenli, rastgele bir secret key üretmek için şu komutu kullanın: + +
+ +```console +$ openssl rand -hex 32 + +09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7 +``` + +
+ +Çıktıyı `SECRET_KEY` değişkenine kopyalayın (örnektekini kullanmayın). + +JWT token'ını imzalamak için kullanılan algoritmayı tutacak `ALGORITHM` adlı bir değişken oluşturup değerini `"HS256"` yapın. + +Token'ın süre sonu (expiration) için bir değişken oluşturun. + +Response için token endpoint'inde kullanılacak bir Pydantic Model tanımlayın. + +Yeni bir access token üretmek için bir yardımcı fonksiyon oluşturun. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *} + +## Dependency'leri güncelleme { #update-the-dependencies } + +`get_current_user` fonksiyonunu, öncekiyle aynı token'ı alacak şekilde güncelleyelim; ancak bu sefer JWT token'larını kullanacağız. + +Gelen token'ı decode edin, doğrulayın ve mevcut kullanıcıyı döndürün. + +Token geçersizse, hemen bir HTTP hatası döndürün. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *} + +## `/token` *path operation*'ını güncelleme { #update-the-token-path-operation } + +Token'ın süre sonu için bir `timedelta` oluşturun. + +Gerçek bir JWT access token üretip döndürün. + +{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *} + +### JWT "subject" `sub` Hakkında Teknik Detaylar { #technical-details-about-the-jwt-subject-sub } + +JWT spesifikasyonu, token'ın konusu (subject) için `sub` adlı bir anahtar olduğunu söyler. + +Bunu kullanmak zorunlu değildir; ancak kullanıcı kimliğini koymak için uygun yer burasıdır, bu yüzden burada onu kullanıyoruz. + +JWT, sadece bir kullanıcıyı tanımlamak ve API'nizde doğrudan işlem yapmasına izin vermek dışında başka amaçlarla da kullanılabilir. + +Örneğin bir "araba"yı veya bir "blog post"u tanımlayabilirsiniz. + +Sonra o varlık için izinler ekleyebilirsiniz; örneğin (araba için) "drive" ya da (blog için) "edit". + +Ardından bu JWT token'ını bir kullanıcıya (veya bot'a) verebilirsiniz; onlar da, hesapları olmasına bile gerek kalmadan, sadece API'nizin bunun için ürettiği JWT token'ıyla bu aksiyonları gerçekleştirebilir (arabayı sürmek veya blog post'u düzenlemek gibi). + +Bu fikirlerle JWT, çok daha gelişmiş senaryolarda kullanılabilir. + +Bu durumlarda, birden fazla varlığın aynı ID'ye sahip olması mümkündür; örneğin `foo` (kullanıcı `foo`, araba `foo`, blog post `foo`). + +Dolayısıyla ID çakışmalarını önlemek için, kullanıcı için JWT token oluştururken `sub` anahtarının değerine bir önek ekleyebilirsiniz; örneğin `username:`. Bu örnekte `sub` değeri şöyle olabilirdi: `username:johndoe`. + +Unutmamanız gereken önemli nokta şudur: `sub` anahtarı, tüm uygulama genelinde benzersiz bir tanımlayıcı olmalı ve string olmalıdır. + +## Kontrol Edelim { #check-it } + +Server'ı çalıştırın ve docs'a gidin: http://127.0.0.1:8000/docs. + +Şuna benzer bir arayüz göreceksiniz: + + + +Uygulamayı, öncekiyle aynı şekilde authorize edin. + +Şu kimlik bilgilerini kullanarak: + +Username: `johndoe` +Password: `secret` + +/// check | Ek bilgi + +Kodun hiçbir yerinde düz metin password "`secret`" yok; sadece hash'lenmiş hâli var. + +/// + + + +`/users/me/` endpoint'ini çağırın; response şöyle olacaktır: + +```JSON +{ + "username": "johndoe", + "email": "johndoe@example.com", + "full_name": "John Doe", + "disabled": false +} +``` + + + +Developer tools'u açarsanız, gönderilen verinin sadece token'ı içerdiğini görebilirsiniz. Password sadece kullanıcıyı authenticate edip access token almak için yapılan ilk request'te gönderilir, sonrasında gönderilmez: + + + +/// note | Not + +`Authorization` header'ına dikkat edin; değeri `Bearer ` ile başlıyor. + +/// + +## `scopes` ile İleri Seviye Kullanım { #advanced-usage-with-scopes } + +OAuth2'nin "scopes" kavramı vardır. + +Bunları kullanarak bir JWT token'a belirli bir izin seti ekleyebilirsiniz. + +Sonra bu token'ı bir kullanıcıya doğrudan veya bir üçüncü tarafa verip, API'nizle belirli kısıtlarla etkileşime girmesini sağlayabilirsiniz. + +Nasıl kullanıldıklarını ve **FastAPI** ile nasıl entegre olduklarını, ileride **Advanced User Guide** içinde öğreneceksiniz. + +## Özet { #recap } + +Şimdiye kadar gördüklerinizle, OAuth2 ve JWT gibi standartları kullanarak güvenli bir **FastAPI** uygulaması kurabilirsiniz. + +Neredeyse her framework'te security'yi ele almak oldukça hızlı bir şekilde karmaşık bir konu hâline gelir. + +Bunu çok basitleştiren birçok paket, veri modeli, veritabanı ve mevcut özelliklerle ilgili pek çok ödün vermek zorunda kalır. Hatta bazıları işi aşırı basitleştirirken arka planda güvenlik açıkları da barındırır. + +--- + +**FastAPI**, hiçbir veritabanı, veri modeli veya araç konusunda ödün vermez. + +Projenize en uygun olanları seçebilmeniz için size tam esneklik sağlar. + +Ayrıca `pwdlib` ve `PyJWT` gibi iyi bakımı yapılan ve yaygın kullanılan paketleri doğrudan kullanabilirsiniz; çünkü **FastAPI**, haricî paketleri entegre etmek için karmaşık mekanizmalara ihtiyaç duymaz. + +Buna rağmen, esneklikten, sağlamlıktan veya güvenlikten ödün vermeden süreci mümkün olduğunca basitleştiren araçları sağlar. + +Ve OAuth2 gibi güvenli, standart protokolleri nispeten basit bir şekilde kullanabilir ve uygulayabilirsiniz. + +Aynı standartları izleyerek, daha ince taneli (fine-grained) bir izin sistemi için OAuth2 "scopes" kullanımını **Advanced User Guide** içinde daha detaylı öğrenebilirsiniz. Scopes'lu OAuth2; Facebook, Google, GitHub, Microsoft, X (Twitter) vb. pek çok büyük kimlik doğrulama sağlayıcısının, üçüncü taraf uygulamaların kullanıcıları adına API'leriyle etkileşebilmesine izin vermek için kullandığı mekanizmadır. diff --git a/docs/tr/docs/tutorial/security/simple-oauth2.md b/docs/tr/docs/tutorial/security/simple-oauth2.md new file mode 100644 index 0000000000..88efd98e51 --- /dev/null +++ b/docs/tr/docs/tutorial/security/simple-oauth2.md @@ -0,0 +1,289 @@ +# Password ve Bearer ile Basit OAuth2 { #simple-oauth2-with-password-and-bearer } + +Şimdi önceki bölümün üzerine inşa edip, eksik parçaları ekleyerek tam bir güvenlik akışı oluşturalım. + +## `username` ve `password`’ü Alma { #get-the-username-and-password } + +`username` ve `password`’ü almak için **FastAPI** security yardımcı araçlarını kullanacağız. + +OAuth2, (bizim kullandığımız) "password flow" kullanılırken client/kullanıcının form verisi olarak `username` ve `password` alanlarını göndermesi gerektiğini belirtir. + +Ayrıca spesifikasyon, bu alanların adlarının tam olarak böyle olması gerektiğini söyler. Yani `user-name` veya `email` işe yaramaz. + +Ancak merak etmeyin, frontend’de son kullanıcılarınıza dilediğiniz gibi gösterebilirsiniz. + +Veritabanı model(ler)inizde de istediğiniz başka isimleri kullanabilirsiniz. + +Fakat login *path operation*’ı için, spesifikasyonla uyumlu olmak (ve örneğin entegre API dokümantasyon sistemini kullanabilmek) adına bu isimleri kullanmamız gerekiyor. + +Spesifikasyon ayrıca `username` ve `password`’ün form verisi olarak gönderilmesi gerektiğini de söyler (yani burada JSON yok). + +### `scope` { #scope } + +Spesifikasyon, client’ın "`scope`" adlı başka bir form alanı da gönderebileceğini söyler. + +Form alanının adı `scope`’tur (tekil), ama aslında boşluklarla ayrılmış "scope"’lardan oluşan uzun bir string’dir. + +Her bir "scope" sadece bir string’dir (boşluk içermez). + +Genelde belirli güvenlik izinlerini (permission) belirtmek için kullanılırlar, örneğin: + +* `users:read` veya `users:write` yaygın örneklerdir. +* `instagram_basic` Facebook / Instagram tarafından kullanılır. +* `https://www.googleapis.com/auth/drive` Google tarafından kullanılır. + +/// info | Bilgi + +OAuth2’de bir "scope", gerekli olan belirli bir izni ifade eden basit bir string’dir. + +`:` gibi başka karakterler içermesi veya URL olması önemli değildir. + +Bu detaylar implementasyon’a özeldir. + +OAuth2 açısından bunlar sadece string’lerdir. + +/// + +## `username` ve `password`’ü Almak İçin Kod { #code-to-get-the-username-and-password } + +Şimdi bunu yönetmek için **FastAPI**’nin sağladığı araçları kullanalım. + +### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform } + +Önce `OAuth2PasswordRequestForm`’u import edin ve `/token` için *path operation* içinde `Depends` ile dependency olarak kullanın: + +{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *} + +`OAuth2PasswordRequestForm`, şu alanları içeren bir form body tanımlayan bir class dependency’sidir: + +* `username`. +* `password`. +* Boşlukla ayrılmış string’lerden oluşan büyük bir string olarak opsiyonel `scope` alanı. +* Opsiyonel `grant_type`. + +/// tip | İpucu + +OAuth2 spesifikasyonu aslında `grant_type` alanını sabit bir `password` değeriyle *zorunlu kılar*, ancak `OAuth2PasswordRequestForm` bunu zorlamaz. + +Bunu zorlamak istiyorsanız, `OAuth2PasswordRequestForm` yerine `OAuth2PasswordRequestFormStrict` kullanın. + +/// + +* Opsiyonel `client_id` (bu örnekte ihtiyacımız yok). +* Opsiyonel `client_secret` (bu örnekte ihtiyacımız yok). + +/// info | Bilgi + +`OAuth2PasswordRequestForm`, `OAuth2PasswordBearer` gibi **FastAPI**’ye özel “özel bir sınıf” değildir. + +`OAuth2PasswordBearer`, bunun bir security scheme olduğunu **FastAPI**’ye bildirir. Bu yüzden OpenAPI’ye o şekilde eklenir. + +Ama `OAuth2PasswordRequestForm` sadece bir class dependency’dir; bunu kendiniz de yazabilirdiniz ya da doğrudan `Form` parametreleri tanımlayabilirdiniz. + +Fakat çok yaygın bir kullanım olduğu için **FastAPI** bunu işleri kolaylaştırmak adına doğrudan sağlar. + +/// + +### Form Verisini Kullanma { #use-the-form-data } + +/// tip | İpucu + +`OAuth2PasswordRequestForm` dependency class’ının instance’ında boşluklarla ayrılmış uzun string olarak bir `scope` attribute’u olmaz; bunun yerine gönderilen her scope için gerçek string listesini içeren `scopes` attribute’u olur. + +Bu örnekte `scopes` kullanmıyoruz, ama ihtiyacınız olursa bu özellik hazır. + +/// + +Şimdi form alanındaki `username`’i kullanarak (sahte) veritabanından kullanıcı verisini alın. + +Böyle bir kullanıcı yoksa, "Incorrect username or password" diyerek bir hata döndürelim. + +Hata için `HTTPException` exception’ını kullanıyoruz: + +{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *} + +### Password’ü Kontrol Etme { #check-the-password } + +Bu noktada veritabanından kullanıcı verisine sahibiz, ancak password’ü henüz kontrol etmedik. + +Önce bu veriyi Pydantic `UserInDB` modeline koyalım. + +Asla düz metin (plaintext) password kaydetmemelisiniz; bu yüzden (sahte) password hashing sistemini kullanacağız. + +Password’ler eşleşmezse, aynı hatayı döndürürüz. + +#### Password hashing { #password-hashing } + +"Hashing" şudur: bir içeriği (bu örnekte password) anlaşılmaz görünen bayt dizisine (yani bir string’e) dönüştürmek. + +Aynı içeriği (aynı password’ü) her verdiğinizde, birebir aynı anlamsız görünen çıktıyı elde edersiniz. + +Ama bu anlamsız çıktıyı tekrar password’e geri çeviremezsiniz. + +##### Neden password hashing kullanılır { #why-use-password-hashing } + +Veritabanınız çalınırsa, hırsız kullanıcılarınızın düz metin password’lerine değil, sadece hash’lere sahip olur. + +Dolayısıyla hırsız, aynı password’leri başka bir sistemde denemeye çalışamaz (birçok kullanıcı her yerde aynı password’ü kullandığı için bu tehlikeli olurdu). + +{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *} + +#### `**user_dict` Hakkında { #about-user-dict } + +`UserInDB(**user_dict)` şu anlama gelir: + +*`user_dict` içindeki key ve value’ları doğrudan key-value argümanları olarak geçir; şu ifadeyle eşdeğerdir:* + +```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 | Bilgi + +`**user_dict` için daha kapsamlı bir açıklama için [**Extra Models** dokümantasyonundaki ilgili bölüme](../extra-models.md#about-user-in-dict){.internal-link target=_blank} geri dönüp bakın. + +/// + +## Token’ı Döndürme { #return-the-token } + +`token` endpoint’inin response’u bir JSON object olmalıdır. + +Bir `token_type` içermelidir. Biz "Bearer" token’ları kullandığımız için token type "`bearer`" olmalıdır. + +Ayrıca `access_token` içermelidir; bunun değeri access token’ımızı içeren bir string olmalıdır. + +Bu basit örnekte tamamen güvensiz davranıp token olarak aynı `username`’i döndüreceğiz. + +/// tip | İpucu + +Bir sonraki bölümde, password hashing ve JWT token’ları ile gerçekten güvenli bir implementasyon göreceksiniz. + +Ama şimdilik ihtiyacımız olan spesifik detaylara odaklanalım. + +/// + +{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *} + +/// tip | İpucu + +Spesifikasyona göre, bu örnekteki gibi `access_token` ve `token_type` içeren bir JSON döndürmelisiniz. + +Bunu kendi kodunuzda kendiniz yapmalı ve bu JSON key’lerini kullandığınızdan emin olmalısınız. + +Spesifikasyonlara uyum için, doğru yapmanız gereken neredeyse tek şey budur. + +Geri kalanını **FastAPI** sizin yerinize yönetir. + +/// + +## Dependency’leri Güncelleme { #update-the-dependencies } + +Şimdi dependency’lerimizi güncelleyeceğiz. + +`current_user`’ı *sadece* kullanıcı aktifse almak istiyoruz. + +Bu yüzden, `get_current_user`’ı dependency olarak kullanan ek bir dependency olan `get_current_active_user`’ı oluşturuyoruz. + +Bu iki dependency de kullanıcı yoksa veya pasifse sadece HTTP hatası döndürecek. + +Dolayısıyla endpoint’imizde kullanıcıyı ancak kullanıcı varsa, doğru şekilde authenticate edildiyse ve aktifse alacağız: + +{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *} + +/// info | Bilgi + +Burada `Bearer` değerine sahip ek `WWW-Authenticate` header’ını döndürmemiz de spesifikasyonun bir parçasıdır. + +Herhangi bir HTTP (hata) durum kodu 401 "UNAUTHORIZED", ayrıca `WWW-Authenticate` header’ı da döndürmelidir. + +Bearer token’lar (bizim durumumuz) için bu header’ın değeri `Bearer` olmalıdır. + +Aslında bu ekstra header’ı atlayabilirsiniz, yine de çalışır. + +Ama spesifikasyonlara uyumlu olması için burada eklenmiştir. + +Ayrıca, bunu bekleyen ve kullanan araçlar olabilir (şimdi veya ileride) ve bu da sizin ya da kullanıcılarınız için faydalı olabilir. + +Standartların faydası da bu... + +/// + +## Çalışır Halini Görün { #see-it-in-action } + +Etkileşimli dokümanları açın: http://127.0.0.1:8000/docs. + +### Authenticate Olma { #authenticate } + +"Authorize" butonuna tıklayın. + +Şu bilgileri kullanın: + +User: `johndoe` + +Password: `secret` + + + +Sistemde authenticate olduktan sonra şöyle görürsünüz: + + + +### Kendi Kullanıcı Verinizi Alma { #get-your-own-user-data } + +Şimdi `/users/me` path’inde `GET` operasyonunu kullanın. + +Kullanıcınızın verisini şöyle alırsınız: + +```JSON +{ + "username": "johndoe", + "email": "johndoe@example.com", + "full_name": "John Doe", + "disabled": false, + "hashed_password": "fakehashedsecret" +} +``` + + + +Kilit ikonuna tıklayıp logout olursanız ve sonra aynı operasyonu tekrar denerseniz, şu şekilde bir HTTP 401 hatası alırsınız: + +```JSON +{ + "detail": "Not authenticated" +} +``` + +### Pasif Kullanıcı { #inactive-user } + +Şimdi pasif bir kullanıcıyla deneyin; şu bilgilerle authenticate olun: + +User: `alice` + +Password: `secret2` + +Ve `/users/me` path’inde `GET` operasyonunu kullanmayı deneyin. + +Şöyle bir "Inactive user" hatası alırsınız: + +```JSON +{ + "detail": "Inactive user" +} +``` + +## Özet { #recap } + +Artık API’niz için `username` ve `password` tabanlı, eksiksiz bir güvenlik sistemi implement etmek için gerekli araçlara sahipsiniz. + +Bu araçlarla güvenlik sistemini herhangi bir veritabanıyla ve herhangi bir user veya veri modeliyle uyumlu hale getirebilirsiniz. + +Eksik kalan tek detay, bunun henüz gerçekten "güvenli" olmamasıdır. + +Bir sonraki bölümde güvenli bir password hashing kütüphanesini ve JWT token’larını nasıl kullanacağınızı göreceksiniz. diff --git a/docs/tr/docs/tutorial/sql-databases.md b/docs/tr/docs/tutorial/sql-databases.md new file mode 100644 index 0000000000..e1638cb04f --- /dev/null +++ b/docs/tr/docs/tutorial/sql-databases.md @@ -0,0 +1,357 @@ +# SQL (İlişkisel) Veritabanları { #sql-relational-databases } + +**FastAPI**, SQL (ilişkisel) bir veritabanı kullanmanızı zorunlu kılmaz. Ancak isterseniz **istediğiniz herhangi bir veritabanını** kullanabilirsiniz. + +Burada SQLModel kullanarak bir örnek göreceğiz. + +**SQLModel**, SQLAlchemy ve Pydantic’in üzerine inşa edilmiştir. **FastAPI**’nin yazarı tarafından, **SQL veritabanları** kullanması gereken FastAPI uygulamalarıyla mükemmel uyum sağlaması için geliştirilmiştir. + +/// tip | İpucu + +İstediğiniz başka bir SQL veya NoSQL veritabanı kütüphanesini kullanabilirsiniz (bazı durumlarda "ORMs" olarak adlandırılır). FastAPI sizi hiçbir şeye zorlamaz. + +/// + +SQLModel, SQLAlchemy tabanlı olduğu için SQLAlchemy’nin **desteklediği herhangi bir veritabanını** kolayca kullanabilirsiniz (bu da SQLModel tarafından da desteklendikleri anlamına gelir), örneğin: + +* PostgreSQL +* MySQL +* SQLite +* Oracle +* Microsoft SQL Server, vb. + +Bu örnekte **SQLite** kullanacağız; çünkü tek bir dosya kullanır ve Python’da yerleşik desteği vardır. Yani bu örneği kopyalayıp olduğu gibi çalıştırabilirsiniz. + +Daha sonra, production uygulamanız için **PostgreSQL** gibi bir veritabanı sunucusu kullanmak isteyebilirsiniz. + +/// tip | İpucu + +Frontend ve daha fazla araçla birlikte **FastAPI** + **PostgreSQL** içeren resmi bir proje oluşturucu (project generator) var: https://github.com/fastapi/full-stack-fastapi-template + +/// + +Bu çok basit ve kısa bir eğitimdir. Veritabanları genelinde, SQL hakkında veya daha ileri özellikler hakkında öğrenmek isterseniz SQLModel dokümantasyonuna gidin. + +## `SQLModel` Kurulumu { #install-sqlmodel } + +Önce [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan emin olun, aktive edin ve ardından `sqlmodel`’i yükleyin: + +
+ +```console +$ pip install sqlmodel +---> 100% +``` + +
+ +## Tek Model ile Uygulamayı Oluşturma { #create-the-app-with-a-single-model } + +Önce, tek bir **SQLModel** modeliyle uygulamanın en basit ilk sürümünü oluşturacağız. + +Aşağıda, **birden fazla model** kullanarak güvenliği ve esnekliği artırıp geliştireceğiz. + +### Modelleri Oluşturma { #create-models } + +`SQLModel`’i import edin ve bir veritabanı modeli oluşturun: + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *} + +`Hero` sınıfı, bir Pydantic modeline çok benzer (hatta altta aslında *bir Pydantic modelidir*). + +Birkaç fark var: + +* `table=True`, SQLModel’e bunun bir *table model* olduğunu söyler; SQL veritabanında bir **table**’ı temsil etmelidir, sadece bir *data model* değildir (diğer normal Pydantic sınıflarında olduğu gibi). + +* `Field(primary_key=True)`, SQLModel’e `id`’nin SQL veritabanındaki **primary key** olduğunu söyler (SQL primary key’leri hakkında daha fazlasını SQLModel dokümantasyonunda öğrenebilirsiniz). + + **Not:** primary key alanı için `int | None` kullanıyoruz; böylece Python kodunda *`id` olmadan bir nesne oluşturabiliriz* (`id=None`) ve veritabanının *kaydederken bunu üreteceğini* varsayarız. SQLModel, veritabanının `id` sağlayacağını anlar ve *veritabanı şemasında sütunu null olamayan bir `INTEGER`* olarak tanımlar. Detaylar için primary key’ler hakkında SQLModel dokümantasyonuna bakın. + +* `Field(index=True)`, SQLModel’e bu sütun için bir **SQL index** oluşturmasını söyler; bu da bu sütuna göre filtrelenmiş verileri okurken veritabanında daha hızlı arama yapılmasını sağlar. + + SQLModel, `str` olarak tanımlanan bir şeyin SQL tarafında `TEXT` (veya veritabanına bağlı olarak `VARCHAR`) tipinde bir sütun olacağını bilir. + +### Engine Oluşturma { #create-an-engine } + +Bir SQLModel `engine`’i (altta aslında bir SQLAlchemy `engine`’idir) veritabanına olan **bağlantıları tutan** yapıdır. + +Tüm kodunuzun aynı veritabanına bağlanması için **tek bir `engine` nesnesi** kullanırsınız. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *} + +`check_same_thread=False` kullanmak, FastAPI’nin aynı SQLite veritabanını farklı thread’lerde kullanmasına izin verir. Bu gereklidir; çünkü **tek bir request** **birden fazla thread** kullanabilir (örneğin dependency’lerde). + +Merak etmeyin; kodun yapısı gereği, ileride **her request için tek bir SQLModel *session*** kullandığımızdan emin olacağız. Zaten `check_same_thread` de temelde bunu mümkün kılmaya çalışır. + +### Table’ları Oluşturma { #create-the-tables } + +Sonra `SQLModel.metadata.create_all(engine)` kullanan bir fonksiyon ekleyerek tüm *table model*’ler için **table’ları oluştururuz**. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *} + +### Session Dependency’si Oluşturma { #create-a-session-dependency } + +Bir **`Session`**, **nesneleri memory’de** tutar ve verideki gerekli değişiklikleri takip eder; ardından veritabanıyla iletişim kurmak için **`engine` kullanır**. + +`yield` ile, her request için yeni bir `Session` sağlayacak bir FastAPI **dependency** oluşturacağız. Bu da her request’te tek session kullanmamızı garanti eder. + +Ardından bu dependency’yi kullanacak kodun geri kalanını sadeleştirmek için `Annotated` ile `SessionDep` dependency’sini oluştururuz. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *} + +### Startup’ta Veritabanı Table’larını Oluşturma { #create-database-tables-on-startup } + +Uygulama başlarken veritabanı table’larını oluşturacağız. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *} + +Burada bir uygulama startup event’inde table’ları oluşturuyoruz. + +Production’da büyük ihtimalle uygulamayı başlatmadan önce çalışan bir migration script’i kullanırsınız. + +/// tip | İpucu + +SQLModel, Alembic’i saran migration araçlarına sahip olacak; ancak şimdilik Alembic’i doğrudan kullanabilirsiniz. + +/// + +### Hero Oluşturma { #create-a-hero } + +Her SQLModel modeli aynı zamanda bir Pydantic modeli olduğu için, Pydantic modelleriyle kullanabildiğiniz **type annotation**’larda aynı şekilde kullanabilirsiniz. + +Örneğin `Hero` tipinde bir parametre tanımlarsanız, bu parametre **JSON body**’den okunur. + +Aynı şekilde, bunu fonksiyonun **return type**’ı olarak da tanımlayabilirsiniz; böylece verinin şekli otomatik API docs arayüzünde görünür. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *} + +Burada `SessionDep` dependency’sini (bir `Session`) kullanarak yeni `Hero`’yu `Session` instance’ına ekliyoruz, değişiklikleri veritabanına commit ediyoruz, `hero` içindeki veriyi refresh ediyoruz ve sonra geri döndürüyoruz. + +### Hero’ları Okuma { #read-heroes } + +`select()` kullanarak veritabanından `Hero`’ları **okuyabiliriz**. Sonuçları sayfalama (pagination) yapmak için `limit` ve `offset` ekleyebiliriz. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *} + +### Tek Bir Hero Okuma { #read-one-hero } + +Tek bir `Hero` **okuyabiliriz**. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *} + +### Hero Silme { #delete-a-hero } + +Bir `Hero`’yu **silebiliriz**. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *} + +### Uygulamayı Çalıştırma { #run-the-app } + +Uygulamayı çalıştırabilirsiniz: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Sonra `/docs` arayüzüne gidin; **FastAPI**’nin API’yi **dokümante etmek** için bu **modelleri** kullandığını göreceksiniz. Ayrıca veriyi **serialize** ve **validate** etmek için de onları kullanacaktır. + +
+ +
+ +## Birden Fazla Model ile Uygulamayı Güncelleme { #update-the-app-with-multiple-models } + +Şimdi bu uygulamayı biraz **refactor** edelim ve **güvenliği** ile **esnekliği** artıralım. + +Önceki uygulamaya bakarsanız, UI’da şu ana kadar client’ın oluşturulacak `Hero`’nun `id` değerini belirlemesine izin verdiğini görebilirsiniz. + +Buna izin vermemeliyiz; DB’de zaten atanmış bir `id`’yi ezebilirler. `id` belirlemek **client** tarafından değil, **backend** veya **veritabanı** tarafından yapılmalıdır. + +Ayrıca hero için bir `secret_name` oluşturuyoruz ama şimdiye kadar her yerde geri döndürüyoruz; bu pek de **secret** sayılmaz... + +Bunları birkaç **ek model** ekleyerek düzelteceğiz. SQLModel’in parlayacağı yer de burası. + +### Birden Fazla Model Oluşturma { #create-multiple-models } + +**SQLModel**’de, `table=True` olan herhangi bir model sınıfı bir **table model**’dir. + +`table=True` olmayan her model sınıfı ise bir **data model**’dir; bunlar aslında sadece Pydantic modelleridir (bazı küçük ek özelliklerle). + +SQLModel ile **inheritance** kullanarak her durumda tüm alanları tekrar tekrar yazmaktan **kaçınabiliriz**. + +#### `HeroBase` - temel sınıf { #herobase-the-base-class } + +Önce tüm modeller tarafından **paylaşılan alanları** içeren bir `HeroBase` modeliyle başlayalım: + +* `name` +* `age` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *} + +#### `Hero` - *table model* { #hero-the-table-model } + +Sonra gerçek *table model* olan `Hero`’yu, diğer modellerde her zaman bulunmayan **ek alanlarla** oluşturalım: + +* `id` +* `secret_name` + +`Hero`, `HeroBase`’ten miras aldığı için `HeroBase`’te tanımlanan alanlara da sahiptir. Dolayısıyla `Hero` için tüm alanlar: + +* `id` +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *} + +#### `HeroPublic` - public *data model* { #heropublic-the-public-data-model } + +Sonraki adımda `HeroPublic` modelini oluştururuz; bu model API client’larına **geri döndürülecek** modeldir. + +`HeroBase` ile aynı alanlara sahiptir; dolayısıyla `secret_name` içermez. + +Sonunda kahramanlarımızın kimliği korunmuş oldu! + +Ayrıca `id: int` alanını yeniden tanımlar. Bunu yaparak API client’larıyla bir **contract** (sözleşme) oluşturmuş oluruz; böylece `id` alanının her zaman var olacağını ve `int` olacağını (asla `None` olmayacağını) bilirler. + +/// tip | İpucu + +Return model’in bir değerin her zaman mevcut olduğunu ve her zaman `int` olduğunu (`None` değil) garanti etmesi API client’ları için çok faydalıdır; bu kesinlik sayesinde daha basit kod yazabilirler. + +Ayrıca **otomatik üretilen client**’ların arayüzleri de daha basit olur; böylece API’nizle çalışan geliştiriciler için süreç çok daha rahat olur. + +/// + +`HeroPublic` içindeki tüm alanlar `HeroBase` ile aynıdır; tek fark `id`’nin `int` olarak tanımlanmasıdır (`None` değil): + +* `id` +* `name` +* `age` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *} + +#### `HeroCreate` - hero oluşturmak için *data model* { #herocreate-the-data-model-to-create-a-hero } + +Şimdi `HeroCreate` modelini oluştururuz; bu model client’tan gelen veriyi **validate** etmek için kullanılır. + +`HeroBase` ile aynı alanlara sahiptir ve ek olarak `secret_name` içerir. + +Artık client’lar **yeni bir hero oluştururken** `secret_name` gönderecek; bu değer veritabanında saklanacak, ancak API response’larında client’a geri döndürülmeyecek. + +/// tip | İpucu + +**Password**’ları bu şekilde ele alırsınız: alırsınız ama API’de geri döndürmezsiniz. + +Ayrıca password değerlerini saklamadan önce **hash** etmelisiniz; **asla plain text olarak saklamayın**. + +/// + +`HeroCreate` alanları: + +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *} + +#### `HeroUpdate` - hero güncellemek için *data model* { #heroupdate-the-data-model-to-update-a-hero } + +Uygulamanın önceki sürümünde bir hero’yu **güncellemenin** bir yolu yoktu; ancak artık **birden fazla model** ile bunu yapabiliriz. + +`HeroUpdate` *data model* biraz özeldir: yeni bir hero oluşturmak için gereken alanların **tamamına** sahiptir, ancak tüm alanlar **opsiyoneldir** (hepsinin bir default değeri vardır). Bu sayede hero güncellerken sadece güncellemek istediğiniz alanları gönderebilirsiniz. + +Tüm **alanlar aslında değiştiği** için (tip artık `None` içeriyor ve default değerleri `None` oluyor), onları **yeniden tanımlamamız** gerekir. + +Aslında `HeroBase`’ten miras almamız gerekmiyor; çünkü tüm alanları yeniden tanımlıyoruz. Tutarlılık için miras almayı bırakıyorum ama bu gerekli değil. Daha çok kişisel tercih meselesi. + +`HeroUpdate` alanları: + +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *} + +### `HeroCreate` ile Oluşturma ve `HeroPublic` Döndürme { #create-with-herocreate-and-return-a-heropublic } + +Artık **birden fazla model** olduğuna göre, onları kullanan uygulama kısımlarını güncelleyebiliriz. + +Request’te bir `HeroCreate` *data model* alırız ve bundan bir `Hero` *table model* oluştururuz. + +Bu yeni *table model* `Hero`, client’ın gönderdiği alanlara sahip olur ve ayrıca veritabanının ürettiği bir `id` alır. + +Sonra fonksiyondan bu *table model* `Hero`’yu olduğu gibi döndürürüz. Ancak `response_model`’i `HeroPublic` *data model* olarak belirlediğimiz için **FastAPI**, veriyi validate ve serialize etmek için `HeroPublic` kullanır. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *} + +/// tip | İpucu + +Burada **return type annotation** `-> HeroPublic` yerine `response_model=HeroPublic` kullanıyoruz; çünkü gerçekte döndürdüğümüz değer *bir* `HeroPublic` değil. + +Eğer `-> HeroPublic` yazsaydık, editörünüz ve linter’ınız (haklı olarak) `HeroPublic` yerine `Hero` döndürdüğünüz için şikayet edecekti. + +Bunu `response_model` içinde belirterek **FastAPI**’ye işini yapmasını söylüyoruz; type annotation’lara ve editörünüzün/diğer araçların sağladığı desteğe karışmamış oluyoruz. + +/// + +### `HeroPublic` ile Hero’ları Okuma { #read-heroes-with-heropublic } + +Daha öncekiyle aynı şekilde `Hero`’ları **okuyabiliriz**; yine `response_model=list[HeroPublic]` kullanarak verinin doğru biçimde validate ve serialize edilmesini garanti ederiz. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *} + +### `HeroPublic` ile Tek Bir Hero Okuma { #read-one-hero-with-heropublic } + +Tek bir hero’yu **okuyabiliriz**: + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *} + +### `HeroUpdate` ile Hero Güncelleme { #update-a-hero-with-heroupdate } + +Bir hero’yu **güncelleyebiliriz**. Bunun için HTTP `PATCH` operasyonu kullanırız. + +Kodda, client’ın gönderdiği tüm verilerle bir `dict` alırız; **yalnızca client’ın gönderdiği veriler**, yani sadece default değer oldukları için orada bulunan değerler hariç. Bunu yapmak için `exclude_unset=True` kullanırız. Asıl numara bu. + +Sonra `hero_db.sqlmodel_update(hero_data)` ile `hero_db`’yi `hero_data` içindeki verilerle güncelleriz. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *} + +### Hero’yu Tekrar Silme { #delete-a-hero-again } + +Bir hero’yu **silmek** büyük ölçüde aynı kalıyor. + +Bu örnekte her şeyi refactor etme isteğimizi bastıracağız. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *} + +### Uygulamayı Tekrar Çalıştırma { #run-the-app-again } + +Uygulamayı tekrar çalıştırabilirsiniz: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +`/docs` API UI’a giderseniz artık güncellendiğini göreceksiniz; hero oluştururken client’tan `id` beklemeyecek, vb. + +
+ +
+ +## Özet { #recap } + +Bir SQL veritabanıyla etkileşim kurmak için **SQLModel** kullanabilir ve *data model* ile *table model* yaklaşımıyla kodu sadeleştirebilirsiniz. + +**SQLModel** dokümantasyonunda çok daha fazlasını öğrenebilirsiniz; **FastAPI** ile SQLModel kullanımı için daha uzun bir mini tutorial da bulunuyor. diff --git a/docs/tr/docs/tutorial/testing.md b/docs/tr/docs/tutorial/testing.md new file mode 100644 index 0000000000..8871566066 --- /dev/null +++ b/docs/tr/docs/tutorial/testing.md @@ -0,0 +1,190 @@ +# Test Etme { #testing } + +Starlette sayesinde **FastAPI** uygulamalarını test etmek kolay ve keyiflidir. + +Temelde HTTPX üzerine kuruludur; HTTPX de Requests’i temel alarak tasarlandığı için oldukça tanıdık ve sezgiseldir. + +Bununla birlikte **FastAPI** ile pytest'i doğrudan kullanabilirsiniz. + +## `TestClient` Kullanımı { #using-testclient } + +/// info | Bilgi + +`TestClient` kullanmak için önce `httpx`'i kurun. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin: + +```console +$ pip install httpx +``` + +/// + +`TestClient`'ı import edin. + +**FastAPI** uygulamanızı ona vererek bir `TestClient` oluşturun. + +Adı `test_` ile başlayan fonksiyonlar oluşturun (bu, `pytest`'in standart konvansiyonudur). + +`TestClient` nesnesini `httpx` ile kullandığınız şekilde kullanın. + +Kontrol etmeniz gereken şeyler için standart Python ifadeleriyle basit `assert` satırları yazın (bu da `pytest` standardıdır). + +{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *} + +/// tip | İpucu + +Test fonksiyonlarının `async def` değil, normal `def` olduğuna dikkat edin. + +Client'a yapılan çağrılar da `await` kullanılmadan, normal çağrılardır. + +Bu sayede `pytest`'i ek bir karmaşıklık olmadan doğrudan kullanabilirsiniz. + +/// + +/// note | Teknik Detaylar + +İsterseniz `from starlette.testclient import TestClient` da kullanabilirsiniz. + +**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.testclient`'ı `fastapi.testclient` üzerinden de sunar. Ancak asıl kaynak doğrudan Starlette'tır. + +/// + +/// tip | İpucu + +FastAPI uygulamanıza request göndermenin dışında testlerinizde `async` fonksiyonlar çağırmak istiyorsanız (örn. asenkron veritabanı fonksiyonları), ileri seviye bölümdeki [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} dokümanına göz atın. + +/// + +## Testleri Ayırma { #separating-tests } + +Gerçek bir uygulamada testlerinizi büyük ihtimalle farklı bir dosyada tutarsınız. + +Ayrıca **FastAPI** uygulamanız birden fazla dosya/modül vb. ile de oluşturulmuş olabilir. + +### **FastAPI** Uygulama Dosyası { #fastapi-app-file } + +[Bigger Applications](bigger-applications.md){.internal-link target=_blank}'te anlatılan şekilde bir dosya yapınız olduğunu varsayalım: + +``` +. +├── app +│   ├── __init__.py +│   └── main.py +``` + +`main.py` dosyasında **FastAPI** uygulamanız bulunuyor olsun: + +{* ../../docs_src/app_testing/app_a_py39/main.py *} + +### Test Dosyası { #testing-file } + +Sonra testlerinizin olduğu bir `test_main.py` dosyanız olabilir. Bu dosya aynı Python package içinde (yani `__init__.py` dosyası olan aynı dizinde) durabilir: + +``` hl_lines="5" +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +Bu dosya aynı package içinde olduğu için, `main` modülünden (`main.py`) `app` nesnesini import etmek üzere relative import kullanabilirsiniz: + +{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *} + +...ve test kodunu da öncekiyle aynı şekilde yazabilirsiniz. + +## Test Etme: Genişletilmiş Örnek { #testing-extended-example } + +Şimdi bu örneği genişletelim ve farklı parçaların nasıl test edildiğini görmek için daha fazla detay ekleyelim. + +### Genişletilmiş **FastAPI** Uygulama Dosyası { #extended-fastapi-app-file } + +Aynı dosya yapısıyla devam edelim: + +``` +. +├── app +│   ├── __init__.py +│   ├── main.py +│   └── test_main.py +``` + +Diyelim ki **FastAPI** uygulamanızın bulunduğu `main.py` dosyasında artık başka **path operations** da var. + +Hata döndürebilecek bir `GET` operation'ı var. + +Birden fazla farklı hata döndürebilecek bir `POST` operation'ı var. + +Her iki *path operation* da `X-Token` header'ını gerektiriyor. + +{* ../../docs_src/app_testing/app_b_an_py310/main.py *} + +### Genişletilmiş Test Dosyası { #extended-testing-file } + +Sonrasında `test_main.py` dosyanızı genişletilmiş testlerle güncelleyebilirsiniz: + +{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *} + +Client'ın request içinde bir bilgi göndermesi gerektiğinde ve bunu nasıl yapacağınızı bilemediğinizde, `httpx` ile nasıl yapılacağını aratabilirsiniz (Google) ya da HTTPX’in tasarımı Requests’e dayandığı için `requests` ile nasıl yapıldığını da arayabilirsiniz. + +Sonra testlerinizde aynısını uygularsınız. + +Örn.: + +* Bir *path* veya *query* parametresi geçirmek için, URL’nin kendisine ekleyin. +* JSON body göndermek için, `json` parametresine bir Python nesnesi (örn. bir `dict`) verin. +* JSON yerine *Form Data* göndermeniz gerekiyorsa, bunun yerine `data` parametresini kullanın. +* *headers* göndermek için, `headers` parametresine bir `dict` verin. +* *cookies* için, `cookies` parametresine bir `dict` verin. + +Backend'e veri geçme hakkında daha fazla bilgi için (`httpx` veya `TestClient` kullanarak) HTTPX dokümantasyonu'na bakın. + +/// info | Bilgi + +`TestClient`'ın Pydantic model'lerini değil, JSON'a dönüştürülebilen verileri aldığını unutmayın. + +Testinizde bir Pydantic model'iniz varsa ve test sırasında verisini uygulamaya göndermek istiyorsanız, [JSON Compatible Encoder](encoder.md){.internal-link target=_blank} içinde açıklanan `jsonable_encoder`'ı kullanabilirsiniz. + +/// + +## Çalıştırma { #run-it } + +Bundan sonra yapmanız gereken tek şey `pytest`'i kurmaktır. + +Bir [virtual environment](../virtual-environments.md){.internal-link target=_blank} oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin: + +
+ +```console +$ pip install pytest + +---> 100% +``` + +
+ +Dosyaları ve testleri otomatik olarak bulur, çalıştırır ve sonuçları size raporlar. + +Testleri şu şekilde çalıştırın: + +
+ +```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/tr/docs/virtual-environments.md b/docs/tr/docs/virtual-environments.md new file mode 100644 index 0000000000..cf7fab778b --- /dev/null +++ b/docs/tr/docs/virtual-environments.md @@ -0,0 +1,862 @@ +# Virtual Environments { #virtual-environments } + +Python projeleriyle çalışırken, her proje için kurduğunuz package'leri birbirinden izole etmek adına büyük ihtimalle bir **virtual environment** (veya benzer bir mekanizma) kullanmalısınız. + +/// info | Bilgi + +Virtual environment'leri, nasıl oluşturulduklarını ve nasıl kullanıldıklarını zaten biliyorsanız bu bölümü atlamak isteyebilirsiniz. 🤓 + +/// + +/// tip | İpucu + +**Virtual environment**, **environment variable** ile aynı şey değildir. + +**Environment variable**, sistemde bulunan ve programların kullanabildiği bir değişkendir. + +**Virtual environment** ise içinde bazı dosyalar bulunan bir klasördür. + +/// + +/// info | Bilgi + +Bu sayfada **virtual environment**'leri nasıl kullanacağınızı ve nasıl çalıştıklarını öğreneceksiniz. + +Eğer Python'ı kurmak dahil her şeyi sizin yerinize yöneten bir **tool** kullanmaya hazırsanız, uv'yi deneyin. + +/// + +## Proje Oluşturun { #create-a-project } + +Önce projeniz için bir klasör oluşturun. + +Ben genelde home/user klasörümün içinde `code` adlı bir klasör oluştururum. + +Sonra bunun içinde her proje için ayrı bir klasör oluştururum. + +
+ +```console +// Go to the home directory +$ cd +// Create a directory for all your code projects +$ mkdir code +// Enter into that code directory +$ cd code +// Create a directory for this project +$ mkdir awesome-project +// Enter into that project directory +$ cd awesome-project +``` + +
+ +## Virtual Environment Oluşturun { #create-a-virtual-environment } + +Bir Python projesi üzerinde **ilk kez** çalışmaya başladığınızda, projenizin içinde **virtual environment** oluşturun. + +/// tip | İpucu + +Bunu her çalıştığınızda değil, **proje başına sadece bir kez** yapmanız yeterlidir. + +/// + +//// tab | `venv` + +Bir virtual environment oluşturmak için, Python ile birlikte gelen `venv` modülünü kullanabilirsiniz. + +
+ +```console +$ python -m venv .venv +``` + +
+ +/// details | Bu komut ne anlama geliyor + +* `python`: `python` adlı programı kullan +* `-m`: bir modülü script gibi çalıştır; bir sonraki kısımda hangi modül olduğunu söyleyeceğiz +* `venv`: normalde Python ile birlikte kurulu gelen `venv` modülünü kullan +* `.venv`: virtual environment'i yeni `.venv` klasörünün içine oluştur + +/// + +//// + +//// tab | `uv` + +Eğer `uv` kuruluysa, onunla da virtual environment oluşturabilirsiniz. + +
+ +```console +$ uv venv +``` + +
+ +/// tip | İpucu + +Varsayılan olarak `uv`, `.venv` adlı bir klasörde virtual environment oluşturur. + +Ancak ek bir argümanla klasör adını vererek bunu özelleştirebilirsiniz. + +/// + +//// + +Bu komut `.venv` adlı bir klasörün içinde yeni bir virtual environment oluşturur. + +/// details | `.venv` veya başka bir ad + +Virtual environment'i başka bir klasörde de oluşturabilirsiniz; ancak buna `.venv` demek yaygın bir konvansiyondur. + +/// + +## Virtual Environment'i Aktif Edin { #activate-the-virtual-environment } + +Oluşturduğunuz virtual environment'i aktif edin; böylece çalıştırdığınız her Python komutu veya kurduğunuz her package onu kullanır. + +/// tip | İpucu + +Projede çalışmak için **yeni bir terminal oturumu** başlattığınız **her seferinde** bunu yapın. + +/// + +//// tab | Linux, macOS + +
+ +```console +$ source .venv/bin/activate +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ .venv\Scripts\Activate.ps1 +``` + +
+ +//// + +//// tab | Windows Bash + +Ya da Windows'ta Bash kullanıyorsanız (örn. Git Bash): + +
+ +```console +$ source .venv/Scripts/activate +``` + +
+ +//// + +/// tip | İpucu + +Bu environment'e **yeni bir package** kurduğunuz her seferinde environment'i yeniden **aktif edin**. + +Böylece, o package'in kurduğu bir **terminal (CLI) programı** kullanıyorsanız, global olarak kurulu (ve muhtemelen ihtiyacınız olandan farklı bir versiyona sahip) başka bir program yerine, virtual environment'inizdeki programı kullanmış olursunuz. + +/// + +## Virtual Environment'in Aktif Olduğunu Kontrol Edin { #check-the-virtual-environment-is-active } + +Virtual environment'in aktif olduğunu (bir önceki komutun çalıştığını) kontrol edin. + +/// tip | İpucu + +Bu **opsiyoneldir**; ancak her şeyin beklendiği gibi çalıştığını ve hedeflediğiniz virtual environment'i kullandığınızı **kontrol etmek** için iyi bir yöntemdir. + +/// + +//// tab | Linux, macOS, Windows Bash + +
+ +```console +$ which python + +/home/user/code/awesome-project/.venv/bin/python +``` + +
+ +Eğer `python` binary'sini projenizin içinde (bu örnekte `awesome-project`) `.venv/bin/python` yolunda gösteriyorsa, tamamdır. 🎉 + +//// + +//// tab | Windows PowerShell + +
+ +```console +$ Get-Command python + +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +
+ +Eğer `python` binary'sini projenizin içinde (bu örnekte `awesome-project`) `.venv\Scripts\python` yolunda gösteriyorsa, tamamdır. 🎉 + +//// + +## `pip`'i Yükseltin { #upgrade-pip } + +/// tip | İpucu + +`uv` kullanıyorsanız, `pip` yerine onunla kurulum yaparsınız; dolayısıyla `pip`'i yükseltmeniz gerekmez. 😎 + +/// + +Package'leri kurmak için `pip` kullanıyorsanız (Python ile varsayılan olarak gelir), en güncel sürüme **yükseltmeniz** gerekir. + +Bir package kurarken görülen birçok garip hata, önce `pip`'i yükseltince çözülür. + +/// tip | İpucu + +Bunu genelde virtual environment'i oluşturduktan hemen sonra **bir kez** yaparsınız. + +/// + +Virtual environment'in aktif olduğundan emin olun (yukarıdaki komutla) ve sonra şunu çalıştırın: + +
+ +```console +$ python -m pip install --upgrade pip + +---> 100% +``` + +
+ +/// tip | İpucu + +Bazen pip'i yükseltmeye çalışırken **`No module named pip`** hatası alabilirsiniz. + +Böyle olursa, aşağıdaki komutla pip'i kurup yükseltin: + +
+ +```console +$ python -m ensurepip --upgrade + +---> 100% +``` + +
+ +Bu komut pip kurulu değilse kurar ve ayrıca kurulu pip sürümünün `ensurepip` içinde bulunan sürüm kadar güncel olmasını garanti eder. + +/// + +## `.gitignore` Ekleyin { #add-gitignore } + +**Git** kullanıyorsanız (kullanmalısınız), `.venv` içindeki her şeyi Git'ten hariç tutmak için bir `.gitignore` dosyası ekleyin. + +/// tip | İpucu + +Virtual environment'i `uv` ile oluşturduysanız, bunu zaten sizin için yaptı; bu adımı atlayabilirsiniz. 😎 + +/// + +/// tip | İpucu + +Bunu virtual environment'i oluşturduktan hemen sonra **bir kez** yapın. + +/// + +
+ +```console +$ echo "*" > .venv/.gitignore +``` + +
+ +/// details | Bu komut ne anlama geliyor + +* `echo "*"`: terminale `*` metnini "yazar" (sonraki kısım bunu biraz değiştiriyor) +* `>`: `>` işaretinin solundaki komutun terminale yazdıracağı çıktı, ekrana basılmak yerine sağ taraftaki dosyaya yazılsın +* `.gitignore`: metnin yazılacağı dosyanın adı + +Git'te `*` "her şey" demektir. Yani `.venv` klasörü içindeki her şeyi ignore eder. + +Bu komut, içeriği şu olan bir `.gitignore` dosyası oluşturur: + +```gitignore +* +``` + +/// + +## Package'leri Kurun { #install-packages } + +Environment'i aktif ettikten sonra, içine package kurabilirsiniz. + +/// tip | İpucu + +Projede ihtiyaç duyduğunuz package'leri ilk kez kurarken veya yükseltirken bunu **bir kez** yapın. + +Bir sürümü yükseltmeniz veya yeni bir package eklemeniz gerekirse **tekrar** yaparsınız. + +/// + +### Package'leri Doğrudan Kurun { #install-packages-directly } + +Acele ediyorsanız ve projenizin package gereksinimlerini bir dosyada belirtmek istemiyorsanız, doğrudan kurabilirsiniz. + +/// tip | İpucu + +Programınızın ihtiyaç duyduğu package'leri ve versiyonlarını bir dosyada tutmak (ör. `requirements.txt` veya `pyproject.toml`) (çok) iyi bir fikirdir. + +/// + +//// tab | `pip` + +
+ +```console +$ pip install "fastapi[standard]" + +---> 100% +``` + +
+ +//// + +//// tab | `uv` + +Eğer `uv` varsa: + +
+ +```console +$ uv pip install "fastapi[standard]" +---> 100% +``` + +
+ +//// + +### `requirements.txt`'ten Kurun { #install-from-requirements-txt } + +Bir `requirements.txt` dosyanız varsa, içindeki package'leri kurmak için artık onu kullanabilirsiniz. + +//// tab | `pip` + +
+ +```console +$ pip install -r requirements.txt +---> 100% +``` + +
+ +//// + +//// tab | `uv` + +Eğer `uv` varsa: + +
+ +```console +$ uv pip install -r requirements.txt +---> 100% +``` + +
+ +//// + +/// details | `requirements.txt` + +Bazı package'ler içeren bir `requirements.txt` şöyle görünebilir: + +```requirements.txt +fastapi[standard]==0.113.0 +pydantic==2.8.0 +``` + +/// + +## Programınızı Çalıştırın { #run-your-program } + +Virtual environment'i aktif ettikten sonra programınızı çalıştırabilirsiniz; program, virtual environment'in içindeki Python'ı ve oraya kurduğunuz package'leri kullanır. + +
+ +```console +$ python main.py + +Hello World +``` + +
+ +## Editörünüzü Yapılandırın { #configure-your-editor } + +Muhtemelen bir editör kullanırsınız; otomatik tamamlamayı ve satır içi hataları alabilmek için, editörünüzü oluşturduğunuz aynı virtual environment'i kullanacak şekilde yapılandırdığınızdan emin olun (muhtemelen otomatik algılar). + +Örneğin: + +* VS Code +* PyCharm + +/// tip | İpucu + +Bunu genelde yalnızca **bir kez**, virtual environment'i oluşturduğunuzda yapmanız gerekir. + +/// + +## Virtual Environment'i Devre Dışı Bırakın { #deactivate-the-virtual-environment } + +Projeniz üzerinde işiniz bittiğinde virtual environment'i **deactivate** edebilirsiniz. + +
+ +```console +$ deactivate +``` + +
+ +Böylece `python` çalıştırdığınızda, o virtual environment içinden (ve oraya kurulu package'lerle) çalıştırmaya çalışmaz. + +## Çalışmaya Hazırsınız { #ready-to-work } + +Artık projeniz üzerinde çalışmaya başlayabilirsiniz. + +/// tip | İpucu + +Yukarıdaki her şeyin aslında ne olduğunu anlamak ister misiniz? + +Okumaya devam edin. 👇🤓 + +/// + +## Neden Virtual Environment { #why-virtual-environments } + +FastAPI ile çalışmak için Python kurmanız gerekir. + +Sonrasında FastAPI'yi ve kullanmak istediğiniz diğer tüm **package**'leri **kurmanız** gerekir. + +Package kurmak için genelde Python ile gelen `pip` komutunu (veya benzeri alternatifleri) kullanırsınız. + +Ancak `pip`'i doğrudan kullanırsanız, package'ler **global Python environment**'ınıza (Python'ın global kurulumuna) yüklenir. + +### Problem { #the-problem } + +Peki package'leri global Python environment'a kurmanın sorunu ne? + +Bir noktada, muhtemelen **farklı package**'lere bağımlı birçok farklı program yazacaksınız. Ayrıca üzerinde çalıştığınız bazı projeler, aynı package'in **farklı versiyonlarına** ihtiyaç duyacak. 😱 + +Örneğin `philosophers-stone` adında bir proje oluşturduğunuzu düşünün; bu program, `harry` adlı başka bir package'e **`1` versiyonu ile** bağlı. Yani `harry`'yi kurmanız gerekir. + +```mermaid +flowchart LR + stone(philosophers-stone) -->|requires| harry-1[harry v1] +``` + +Sonra daha ileri bir zamanda `prisoner-of-azkaban` adlı başka bir proje oluşturuyorsunuz; bu proje de `harry`'ye bağlı, fakat bu proje **`harry` versiyon `3`** istiyor. + +```mermaid +flowchart LR + azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3] +``` + +Şimdi sorun şu: package'leri local bir **virtual environment** yerine global (global environment) olarak kurarsanız, `harry`'nin hangi versiyonunu kuracağınıza karar vermek zorunda kalırsınız. + +`philosophers-stone`'u çalıştırmak istiyorsanız önce `harry` versiyon `1`'i kurmanız gerekir; örneğin: + +
+ +```console +$ pip install "harry==1" +``` + +
+ +Sonuç olarak global Python environment'ınızda `harry` versiyon `1` kurulu olur. + +```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 +``` + +Fakat `prisoner-of-azkaban`'ı çalıştırmak istiyorsanız, `harry` versiyon `1`'i kaldırıp `harry` versiyon `3`'ü kurmanız gerekir (ya da sadece `3`'ü kurmak, otomatik olarak `1`'i kaldırabilir). + +
+ +```console +$ pip install "harry==3" +``` + +
+ +Sonuç olarak global Python environment'ınızda `harry` versiyon `3` kurulu olur. + +Ve `philosophers-stone`'u tekrar çalıştırmaya kalkarsanız, `harry` versiyon `1`'e ihtiyaç duyduğu için **çalışmama** ihtimali vardır. + +```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 | İpucu + +Python package'lerinde **yeni versiyonlarda** **breaking change**'lerden kaçınmak oldukça yaygındır; ancak yine de daha güvenlisi, yeni versiyonları bilinçli şekilde kurmak ve mümkünse test'leri çalıştırıp her şeyin doğru çalıştığını doğrulamaktır. + +/// + +Şimdi bunu, **projelerinizin bağımlı olduğu** daha **birçok** başka **package** ile birlikte düşünün. Yönetmesi epey zorlaşır. Sonunda bazı projeleri package'lerin **uyumsuz versiyonlarıyla** çalıştırıp, bir şeylerin neden çalışmadığını anlamamak gibi durumlara düşebilirsiniz. + +Ayrıca işletim sisteminize (örn. Linux, Windows, macOS) bağlı olarak Python zaten kurulu gelmiş olabilir. Bu durumda, sisteminizin **ihtiyaç duyduğu** bazı package'ler belirli versiyonlarla önceden kurulu olabilir. Global Python environment'a package kurarsanız, işletim sistemiyle gelen bazı programları **bozma** ihtimaliniz olabilir. + +## Package'ler Nereye Kuruluyor { #where-are-packages-installed } + +Python'ı kurduğunuzda, bilgisayarınızda bazı dosyalar içeren klasörler oluşturulur. + +Bu klasörlerin bir kısmı, kurduğunuz tüm package'leri barındırmaktan sorumludur. + +Şunu çalıştırdığınızda: + +
+ +```console +// Don't run this now, it's just an example 🤓 +$ pip install "fastapi[standard]" +---> 100% +``` + +
+ +Bu, FastAPI kodunu içeren sıkıştırılmış bir dosyayı genellikle PyPI'dan indirir. + +Ayrıca FastAPI'nin bağımlı olduğu diğer package'ler için de dosyaları **indirir**. + +Sonra tüm bu dosyaları **açar (extract)** ve bilgisayarınızdaki bir klasöre koyar. + +Varsayılan olarak bu indirilip çıkarılan dosyaları, Python kurulumunuzla birlikte gelen klasöre yerleştirir; yani **global environment**'a. + +## Virtual Environment Nedir { #what-are-virtual-environments } + +Global environment'da tüm package'leri bir arada tutmanın sorunlarına çözüm, çalıştığınız her proje için ayrı bir **virtual environment** kullanmaktır. + +Virtual environment, global olana çok benzeyen bir **klasördür**; bir projenin ihtiyaç duyduğu package'leri buraya kurarsınız. + +Böylece her projenin kendi virtual environment'i (`.venv` klasörü) ve kendi package'leri olur. + +```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 +``` + +## Virtual Environment'i Aktif Etmek Ne Demek { #what-does-activating-a-virtual-environment-mean } + +Bir virtual environment'i örneğin şununla aktif ettiğinizde: + +//// tab | Linux, macOS + +
+ +```console +$ source .venv/bin/activate +``` + +
+ +//// + +//// tab | Windows PowerShell + +
+ +```console +$ .venv\Scripts\Activate.ps1 +``` + +
+ +//// + +//// tab | Windows Bash + +Ya da Windows'ta Bash kullanıyorsanız (örn. Git Bash): + +
+ +```console +$ source .venv/Scripts/activate +``` + +
+ +//// + +Bu komut, sonraki komutlarda kullanılabilecek bazı [environment variable](environment-variables.md){.internal-link target=_blank}'ları oluşturur veya değiştirir. + +Bunlardan biri `PATH` değişkenidir. + +/// tip | İpucu + +`PATH` environment variable hakkında daha fazla bilgiyi [Environment Variables](environment-variables.md#path-environment-variable){.internal-link target=_blank} bölümünde bulabilirsiniz. + +/// + +Bir virtual environment'i aktive etmek, onun `.venv/bin` (Linux ve macOS'ta) veya `.venv\Scripts` (Windows'ta) yolunu `PATH` environment variable'ına ekler. + +Diyelim ki environment'i aktive etmeden önce `PATH` değişkeni şöyleydi: + +//// tab | Linux, macOS + +```plaintext +/usr/bin:/bin:/usr/sbin:/sbin +``` + +Bu, sistemin programları şu klasörlerde arayacağı anlamına gelir: + +* `/usr/bin` +* `/bin` +* `/usr/sbin` +* `/sbin` + +//// + +//// tab | Windows + +```plaintext +C:\Windows\System32 +``` + +Bu, sistemin programları şurada arayacağı anlamına gelir: + +* `C:\Windows\System32` + +//// + +Virtual environment'i aktive ettikten sonra `PATH` değişkeni şuna benzer hale gelir: + +//// tab | Linux, macOS + +```plaintext +/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin +``` + +Bu, sistemin artık programları önce şurada aramaya başlayacağı anlamına gelir: + +```plaintext +/home/user/code/awesome-project/.venv/bin +``` + +diğer klasörlere bakmadan önce. + +Dolayısıyla terminale `python` yazdığınızda, sistem Python programını şurada bulur: + +```plaintext +/home/user/code/awesome-project/.venv/bin/python +``` + +ve onu kullanır. + +//// + +//// tab | Windows + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32 +``` + +Bu, sistemin artık programları önce şurada aramaya başlayacağı anlamına gelir: + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts +``` + +diğer klasörlere bakmadan önce. + +Dolayısıyla terminale `python` yazdığınızda, sistem Python programını şurada bulur: + +```plaintext +C:\Users\user\code\awesome-project\.venv\Scripts\python +``` + +ve onu kullanır. + +//// + +Önemli bir detay: virtual environment yolu `PATH` değişkeninin **en başına** eklenir. Sistem, mevcut başka herhangi bir Python'ı bulmadan **önce** bunu bulur. Böylece `python` çalıştırdığınızda, başka bir `python` (örneğin global environment'tan gelen `python`) yerine **virtual environment'taki** Python kullanılır. + +Virtual environment'i aktive etmek birkaç şeyi daha değiştirir; ancak yaptığı en önemli işlerden biri budur. + +## Virtual Environment'i Kontrol Etmek { #checking-a-virtual-environment } + +Bir virtual environment'in aktif olup olmadığını örneğin şununla kontrol ettiğinizde: + +//// 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 +``` + +
+ +//// + +Bu, kullanılacak `python` programının **virtual environment'in içindeki** Python olduğu anlamına gelir. + +Linux ve macOS'ta `which`, Windows PowerShell'de ise `Get-Command` kullanırsınız. + +Bu komutun çalışma mantığı şudur: `PATH` environment variable içindeki **her yolu sırayla** dolaşır, `python` adlı programı arar. Bulduğunda, size o programın **dosya yolunu** gösterir. + +En önemli kısım şu: `python` dediğinizde çalışacak olan "`python`" tam olarak budur. + +Yani doğru virtual environment'da olup olmadığınızı doğrulayabilirsiniz. + +/// tip | İpucu + +Bir virtual environment'i aktive etmek kolaydır; sonra o Python ile kalıp **başka bir projeye geçmek** de kolaydır. + +Bu durumda ikinci proje, başka bir projenin virtual environment'ından gelen **yanlış Python**'ı kullandığınız için **çalışmayabilir**. + +Hangi `python`'ın kullanıldığını kontrol edebilmek bu yüzden faydalıdır. 🤓 + +/// + +## Neden Virtual Environment'i Deactivate Edelim { #why-deactivate-a-virtual-environment } + +Örneğin `philosophers-stone` projesi üzerinde çalışıyor olabilirsiniz; **o virtual environment'i aktive eder**, package kurar ve o environment ile çalışırsınız. + +Sonra **başka bir proje** olan `prisoner-of-azkaban` üzerinde çalışmak istersiniz. + +O projeye gidersiniz: + +
+ +```console +$ cd ~/code/prisoner-of-azkaban +``` + +
+ +Eğer `philosophers-stone` için olan virtual environment'i deactivate etmezseniz, terminalde `python` çalıştırdığınızda `philosophers-stone`'dan gelen Python'ı kullanmaya çalışır. + +
+ +```console +$ cd ~/code/prisoner-of-azkaban + +$ python main.py + +// Error importing sirius, it's not installed 😱 +Traceback (most recent call last): + File "main.py", line 1, in + import sirius +``` + +
+ +Ama virtual environment'i deactivate edip `prisoner-of-askaban` için yeni olanı aktive ederseniz, `python` çalıştırdığınızda `prisoner-of-azkaban` içindeki virtual environment'dan gelen Python kullanılır. + +
+ +```console +$ cd ~/code/prisoner-of-azkaban + +// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎 +$ deactivate + +// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀 +$ source .venv/bin/activate + +// Now when you run python, it will find the package sirius installed in this virtual environment ✨ +$ python main.py + +I solemnly swear 🐺 +``` + +
+ +## Alternatifler { #alternatives } + +Bu, başlamanız için basit bir rehber ve alttaki mekanizmaların nasıl çalıştığını öğretmeyi amaçlıyor. + +Virtual environment'leri, package bağımlılıklarını (requirements) ve projeleri yönetmek için birçok **alternatif** vardır. + +Hazır olduğunuzda ve package bağımlılıkları, virtual environment'ler vb. dahil **tüm projeyi yönetmek** için bir tool kullanmak istediğinizde, uv'yi denemenizi öneririm. + +`uv` birçok şey yapabilir, örneğin: + +* Sizin için **Python kurabilir**, farklı sürümler dahil +* Projelerinizin **virtual environment**'ini yönetebilir +* **Package** kurabilir +* Projeniz için package **bağımlılıklarını ve versiyonlarını** yönetebilir +* Bağımlılıkları dahil, kurulacak package ve versiyonların **tam (exact)** bir setini garanti edebilir; böylece geliştirirken bilgisayarınızda çalıştırdığınız projeyi production'da da birebir aynı şekilde çalıştırabileceğinizden emin olursunuz; buna **locking** denir +* Ve daha birçok şey + +## Sonuç { #conclusion } + +Buradaki her şeyi okuduysanız ve anladıysanız, artık birçok geliştiriciden **çok daha fazla** virtual environment bilgisine sahipsiniz. 🤓 + +Bu detayları bilmek, ileride karmaşık görünen bir sorunu debug ederken büyük olasılıkla işinize yarayacak; çünkü **altta nasıl çalıştığını** biliyor olacaksınız. 😎 diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md index 526409c5cf..4f089c4e1a 100644 --- a/docs/uk/docs/index.md +++ b/docs/uk/docs/index.md @@ -8,7 +8,7 @@ FastAPI

- Фреймворк FastAPI: висока продуктивність, легко вивчати, швидко писати код, готовий до продакшину + Фреймворк FastAPI - це висока продуктивність, легко вивчати, швидко писати код, готовий до продакшину

@@ -33,14 +33,14 @@ --- -FastAPI — це сучасний, швидкий (високопродуктивний) вебфреймворк для створення API за допомогою Python, що базується на стандартних підказках типів Python. +FastAPI - це сучасний, швидкий (високопродуктивний) вебфреймворк для створення API за допомогою Python, що базується на стандартних підказках типів Python. Ключові особливості: * **Швидкий**: дуже висока продуктивність, на рівні з **NodeJS** та **Go** (завдяки Starlette та Pydantic). [Один із найшвидших Python-фреймворків](#performance). * **Швидке написання коду**: пришвидшує розробку функціоналу приблизно на 200%–300%. * * **Менше помилок**: зменшує приблизно на 40% кількість помилок, спричинених людиною (розробником). * -* **Інтуїтивний**: чудова підтримка редакторами коду. Автодоповнення всюди. Менше часу на налагодження. +* **Інтуїтивний**: чудова підтримка редакторами коду. Автодоповнення всюди. Менше часу на налагодження. * **Простий**: спроєктований так, щоб бути простим у використанні та вивченні. Менше часу на читання документації. * **Короткий**: мінімізує дублювання коду. Кілька можливостей з кожного оголошення параметра. Менше помилок. * **Надійний**: ви отримуєте код, готовий до продакшину. З автоматичною інтерактивною документацією. @@ -127,9 +127,9 @@ FastAPI — це сучасний, швидкий (високопродукти -Якщо ви створюєте застосунок CLI для використання в терміналі замість веб-API, зверніть увагу на **Typer**. +Якщо ви створюєте застосунок CLI для використання в терміналі замість веб-API, зверніть увагу на **Typer**. -**Typer** — молодший брат FastAPI. І його задумано як **FastAPI для CLI**. ⌨️ 🚀 +**Typer** - молодший брат FastAPI. І його задумано як **FastAPI для CLI**. ⌨️ 🚀 ## Вимоги { #requirements } @@ -161,8 +161,6 @@ $ pip install "fastapi[standard]" Створіть файл `main.py` з: ```Python -from typing import Union - from fastapi import FastAPI app = FastAPI() @@ -174,7 +172,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): +def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} ``` @@ -183,9 +181,7 @@ def read_item(item_id: int, q: Union[str, None] = None): Якщо ваш код використовує `async` / `await`, скористайтеся `async def`: -```Python hl_lines="9 14" -from typing import Union - +```Python hl_lines="7 12" from fastapi import FastAPI app = FastAPI() @@ -197,7 +193,7 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): +async def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} ``` @@ -288,9 +284,7 @@ INFO: Application startup complete. Оголосіть тіло, використовуючи стандартні типи Python, завдяки Pydantic. -```Python hl_lines="4 9-12 25-27" -from typing import Union - +```Python hl_lines="2 7-10 23-25" from fastapi import FastAPI from pydantic import BaseModel @@ -300,7 +294,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Union[bool, None] = None + is_offer: bool | None = None @app.get("/") @@ -309,7 +303,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): +def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} @@ -374,7 +368,7 @@ item: Item * Валідацію даних: * Автоматичні та зрозумілі помилки, коли дані некоректні. * Валідацію навіть для глибоко вкладених JSON-обʼєктів. -* Перетворення вхідних даних: з мережі до даних і типів Python. Читання з: +* Перетворення вхідних даних: з мережі до даних і типів Python. Читання з: * JSON. * Параметрів шляху. * Параметрів запиту. @@ -382,7 +376,7 @@ item: Item * Headers. * Forms. * Files. -* Перетворення вихідних даних: перетворення з даних і типів Python у мережеві дані (як JSON): +* Перетворення вихідних даних: перетворення з даних і типів Python у мережеві дані (як JSON): * Перетворення типів Python (`str`, `int`, `float`, `bool`, `list`, тощо). * Обʼєктів `datetime`. * Обʼєктів `UUID`. @@ -439,9 +433,9 @@ item: Item ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -Для більш повного прикладу, що включає більше можливостей, перегляньте Туторіал — Посібник користувача. +Для більш повного прикладу, що включає більше можливостей, перегляньте Навчальний посібник - Посібник користувача. -**Spoiler alert**: туторіал — посібник користувача містить: +**Попередження про спойлер**: навчальний посібник - посібник користувача містить: * Оголошення **параметрів** з інших різних місць, як-от: **headers**, **cookies**, **form fields** та **files**. * Як встановлювати **обмеження валідації** як `maximum_length` або `regex`. @@ -500,11 +494,11 @@ Deploying to FastAPI Cloud... Він забезпечує той самий **developer experience** створення застосунків на FastAPI під час їх **розгортання** у хмарі. 🎉 -FastAPI Cloud — основний спонсор і джерело фінансування open source проєктів *FastAPI and friends*. ✨ +FastAPI Cloud - основний спонсор і джерело фінансування open source проєктів *FastAPI and friends*. ✨ #### Розгортання в інших хмарних провайдерів { #deploy-to-other-cloud-providers } -FastAPI — open source і базується на стандартах. Ви можете розгортати застосунки FastAPI в будь-якому хмарному провайдері, який ви оберете. +FastAPI - open source проект і базується на стандартах. Ви можете розгортати застосунки FastAPI в будь-якому хмарному провайдері, який ви оберете. Дотримуйтеся інструкцій вашого хмарного провайдера, щоб розгорнути застосунки FastAPI у нього. 🤓 @@ -530,7 +524,7 @@ FastAPI залежить від Pydantic і Starlette. * httpx - потрібно, якщо ви хочете використовувати `TestClient`. * jinja2 - потрібно, якщо ви хочете використовувати конфігурацію шаблонів за замовчуванням. -* python-multipart - потрібно, якщо ви хочете підтримувати «parsing» форм за допомогою `request.form()`. +* python-multipart - потрібно, якщо ви хочете підтримувати «parsing» форм за допомогою `request.form()`. Використовується FastAPI: diff --git a/docs/uk/docs/tutorial/body-multiple-params.md b/docs/uk/docs/tutorial/body-multiple-params.md index dc9a768c35..f541beea76 100644 --- a/docs/uk/docs/tutorial/body-multiple-params.md +++ b/docs/uk/docs/tutorial/body-multiple-params.md @@ -102,15 +102,16 @@ Оскільки за замовчуванням одиничні значення інтерпретуються як параметри запиту, вам не потрібно явно додавати `Query`, ви можете просто зробити: +```Python +q: str | None = None +``` + +Або в Python 3.9: + ```Python q: Union[str, None] = None ``` -Або в Python 3.10 і вище: - -```Python -q: str | None = None -``` Наприклад: @@ -129,7 +130,7 @@ q: str | None = None За замовчуванням **FastAPI** очікуватиме його тіло безпосередньо. -Але якщо ви хочете, щоб він очікував JSON з ключем `item`, а всередині нього — вміст моделі, як це відбувається, коли ви оголошуєте додаткові параметри тіла, ви можете використати спеціальний параметр `Body` — `embed`: +Але якщо ви хочете, щоб він очікував JSON з ключем `item`, а всередині нього - вміст моделі, як це відбувається, коли ви оголошуєте додаткові параметри тіла, ви можете використати спеціальний параметр `Body` - `embed`: ```Python item: Item = Body(embed=True) diff --git a/docs/zh-hant/docs/about/index.md b/docs/zh-hant/docs/about/index.md index 5dcee68f2d..cf5b5742c5 100644 --- a/docs/zh-hant/docs/about/index.md +++ b/docs/zh-hant/docs/about/index.md @@ -1,3 +1,3 @@ -# 關於 FastAPI +# 關於 { #about } 關於 FastAPI、其設計、靈感來源等更多資訊。 🤓 diff --git a/docs/zh-hant/docs/benchmarks.md b/docs/zh-hant/docs/benchmarks.md index c59e8e71c6..df49621c53 100644 --- a/docs/zh-hant/docs/benchmarks.md +++ b/docs/zh-hant/docs/benchmarks.md @@ -1,10 +1,10 @@ -# 基準測試 +# 基準測試 { #benchmarks } 由第三方機構 TechEmpower 的基準測試表明在 Uvicorn 下運行的 **FastAPI** 應用程式是 最快的 Python 可用框架之一,僅次於 Starlette 和 Uvicorn 本身(於 FastAPI 內部使用)。 但是在查看基準得分和對比時,請注意以下幾點。 -## 基準測試和速度 +## 基準測試和速度 { #benchmarks-and-speed } 當你查看基準測試時,時常會見到幾個不同類型的工具被同時進行測試。 @@ -31,4 +31,4 @@ * FastAPI 在 Starlette 基礎之上提供了更多功能。包含建構 API 時所需要的功能,例如資料驗證和序列化。FastAPI 可以幫助你自動產生 API 文件,(應用程式啟動時將會自動生成文件,所以不會增加應用程式運行時的開銷)。 * 如果你沒有使用 FastAPI 而是直接使用 Starlette(或其他工具,如 Sanic、Flask、Responder 等),你將必須自行實現所有資料驗證和序列化。因此,你的最終應用程式仍然具有與使用 FastAPI 建置相同的開銷。在許多情況下,這種資料驗證和序列化是應用程式中編寫最大量的程式碼。 * 因此透過使用 FastAPI,你可以節省開發時間、錯誤與程式碼數量,並且相比不使用 FastAPI 你很大可能會獲得相同或更好的效能(因為那樣你必須在程式碼中實現所有相同的功能)。 - * 如果你要與 FastAPI 比較,請將其與能夠提供資料驗證、序列化和文件的網頁應用程式框架(或工具集)進行比較,例如 Flask-apispec、NestJS、Molten 等框架。 + * 如果你要與 FastAPI 比較,請將其與能夠提供資料驗證、序列化和文件的網頁應用程式框架(或工具集)進行比較,例如 Flask-apispec、NestJS、Molten 等框架。具備整合式自動資料驗證、序列化與文件的框架。 diff --git a/docs/zh-hant/docs/deployment/cloud.md b/docs/zh-hant/docs/deployment/cloud.md index 426937d3e4..fffb2fcfeb 100644 --- a/docs/zh-hant/docs/deployment/cloud.md +++ b/docs/zh-hant/docs/deployment/cloud.md @@ -1,13 +1,24 @@ -# 在雲端部署 FastAPI +# 在雲端供應商上部署 FastAPI { #deploy-fastapi-on-cloud-providers } 你幾乎可以使用**任何雲端供應商**來部署你的 FastAPI 應用程式。 在大多數情況下,主要的雲端供應商都有部署 FastAPI 的指南。 -## 雲端供應商 - 贊助商 +## FastAPI Cloud { #fastapi-cloud } -一些雲端供應商 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨,這確保了 FastAPI 及其**生態系統**持續健康地**發展**。 +**FastAPI Cloud** 由 **FastAPI** 的同一位作者與團隊打造。 -這也展現了他們對 FastAPI 和其**社群**(包括你)的真正承諾,他們不僅希望為你提供**優質的服務**,還希望確保你擁有一個**良好且健康的框架**:FastAPI。🙇 +它讓你以最少的投入,簡化 **建置**、**部署** 與 **存取** API 的流程。 -你可能會想嘗試他們的服務,以下有他們的指南. +它把使用 FastAPI 開發應用的同樣**優秀的開發者體驗**,帶到將它們**部署**到雲端的過程中。🎉 + +FastAPI Cloud 是 *FastAPI and friends* 開源專案的主要贊助與資金提供者。✨ + +## 雲端供應商 - 贊助商 { #cloud-providers-sponsors } + +其他一些雲端供應商也會 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨。🙇 + +你也可以參考他們的指南並試用其服務: + +* Render +* Railway diff --git a/docs/zh-hant/docs/deployment/index.md b/docs/zh-hant/docs/deployment/index.md index 1726562b40..9edd3368b2 100644 --- a/docs/zh-hant/docs/deployment/index.md +++ b/docs/zh-hant/docs/deployment/index.md @@ -1,8 +1,8 @@ -# 部署 +# 部署 { #deployment } 部署 **FastAPI** 應用程式相對容易。 -## 部署是什麼意思 +## 部署是什麼意思 { #what-does-deployment-mean } **部署**應用程式指的是執行一系列必要的步驟,使其能夠**讓使用者存取和使用**。 @@ -10,12 +10,14 @@ 這與**開發**階段形成鮮明對比,在**開發**階段,你會不斷更改程式碼、破壞程式碼、修復程式碼,然後停止和重新啟動伺服器等。 -## 部署策略 +## 部署策略 { #deployment-strategies } 根據你的使用場景和使用工具,有多種方法可以實現此目的。 你可以使用一些工具自行**部署伺服器**,你也可以使用能為你完成部分工作的**雲端服務**,或其他可能的選項。 +例如,我們(FastAPI 的團隊)打造了 **FastAPI Cloud**,讓將 FastAPI 應用程式部署到雲端變得盡可能流暢,並保持與使用 FastAPI 開發時相同的開發者體驗。 + 我將向你展示在部署 **FastAPI** 應用程式時你可能應該記住的一些主要概念(儘管其中大部分適用於任何其他類型的 Web 應用程式)。 在接下來的部分中,你將看到更多需要記住的細節以及一些技巧。 ✨ diff --git a/docs/zh-hant/docs/environment-variables.md b/docs/zh-hant/docs/environment-variables.md index a1598fc018..5b684b9e6a 100644 --- a/docs/zh-hant/docs/environment-variables.md +++ b/docs/zh-hant/docs/environment-variables.md @@ -1,4 +1,4 @@ -# 環境變數 +# 環境變數 { #environment-variables } /// tip @@ -10,7 +10,7 @@ 環境變數對於處理應用程式**設定**(作為 Python **安裝**的一部分等方面)非常有用。 -## 建立和使用環境變數 +## 建立和使用環境變數 { #create-and-use-env-vars } 你在 **shell(終端機)**中就可以**建立**和使用環境變數,並不需要用到 Python: @@ -50,7 +50,7 @@ Hello Wade Wilson //// -## 在 Python 中讀取環境變數 +## 在 Python 中讀取環境變數 { #read-env-vars-in-python } 你也可以在 Python **之外**的終端機中建立環境變數(或使用其他方法),然後在 Python 中**讀取**它們。 @@ -65,7 +65,7 @@ print(f"Hello {name} from Python") /// tip -第二個參數是 `os.getenv()` 的預設回傳值。 +第二個參數是 `os.getenv()` 的預設回傳值。 如果沒有提供,預設值為 `None`,這裡我們提供 `"World"` 作為預設值。 @@ -153,19 +153,19 @@ Hello World from Python /// tip -你可以在 The Twelve-Factor App: 配置中了解更多資訊。 +你可以在 The Twelve-Factor App: 配置中了解更多資訊。 /// -## 型別和驗證 +## 型別和驗證 { #types-and-validation } 這些環境變數只能處理**文字字串**,因為它們是位於 Python 範疇之外的,必須與其他程式和作業系統的其餘部分相容(甚至與不同的作業系統相容,如 Linux、Windows、macOS)。 這意味著從環境變數中讀取的**任何值**在 Python 中都將是一個 `str`,任何型別轉換或驗證都必須在程式碼中完成。 -你將在[進階使用者指南 - 設定和環境變數](./advanced/settings.md)中了解更多關於使用環境變數處理**應用程式設定**的資訊。 +你將在[進階使用者指南 - 設定和環境變數](./advanced/settings.md){.internal-link target=_blank}中了解更多關於使用環境變數處理**應用程式設定**的資訊。 -## `PATH` 環境變數 +## `PATH` 環境變數 { #path-environment-variable } 有一個**特殊的**環境變數稱為 **`PATH`**,作業系統(Linux、macOS、Windows)用它來查找要執行的程式。 @@ -209,7 +209,7 @@ C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System3 如果找到了,那麼作業系統將**使用它**;否則,作業系統會繼續在**其他目錄**中查找。 -### 安裝 Python 並更新 `PATH` +### 安裝 Python 並更新 `PATH` { #installing-python-and-updating-the-path } 安裝 Python 時,可能會詢問你是否要更新 `PATH` 環境變數。 @@ -233,7 +233,7 @@ C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System3 假設你安裝了 Python,並將其安裝在目錄 `C:\opt\custompython\bin` 中。 -如果你選擇更新 `PATH` 環境變數(在 Python 安裝程式中,這個選項是名為 `Add Python x.xx to PATH` 的勾選框——譯者註),那麼安裝程式會將 `C:\opt\custompython\bin` 加入到 `PATH` 環境變數中。 +如果你選擇更新 `PATH` 環境變數,那麼安裝程式會將 `C:\opt\custompython\bin` 加入到 `PATH` 環境變數中。 ```plaintext C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin @@ -285,13 +285,13 @@ $ C:\opt\custompython\bin\python //// -當學習[虛擬環境](virtual-environments.md)時,這些資訊將會很有用。 +當學習[虛擬環境](virtual-environments.md){.internal-link target=_blank}時,這些資訊將會很有用。 -## 結論 +## 結論 { #conclusion } 透過這個教學,你應該對**環境變數**是什麼以及如何在 Python 中使用它們有了基本的了解。 -你也可以在環境變數 - 維基百科 (Wikipedia for Environment Variable) 中了解更多關於它們的資訊。 +你也可以在 環境變數的維基百科條目 中閱讀更多。 在許多情況下,環境變數的用途和適用性可能不會立刻顯現。但是在開發過程中,它們會在許多不同的場景中出現,因此瞭解它們是非常必要的。 diff --git a/docs/zh-hant/docs/how-to/index.md b/docs/zh-hant/docs/how-to/index.md index db740140d0..6c9a8202c0 100644 --- a/docs/zh-hant/docs/how-to/index.md +++ b/docs/zh-hant/docs/how-to/index.md @@ -1,4 +1,4 @@ -# 使用指南 - 範例集 +# 使用指南 - 範例集 { #how-to-recipes } 在這裡,你將會看到**不同主題**的範例或「如何使用」的指南。 diff --git a/docs/zh-hant/docs/index.md b/docs/zh-hant/docs/index.md index 4390d96096..a31647f3cd 100644 --- a/docs/zh-hant/docs/index.md +++ b/docs/zh-hant/docs/index.md @@ -1,5 +1,11 @@ +# FastAPI { #fastapi } + + +

- FastAPI + FastAPI

FastAPI 框架,高效能,易於學習,快速開發,適用於生產環境 @@ -21,138 +27,140 @@ --- -**文件**: https://fastapi.tiangolo.com +**文件**: https://fastapi.tiangolo.com/zh-hant **程式碼**: https://github.com/fastapi/fastapi --- -FastAPI 是一個現代、快速(高效能)的 web 框架,用於 Python 並採用標準 Python 型別提示。 +FastAPI 是一個現代、快速(高效能)的 Web 框架,用於以 Python 並基於標準的 Python 型別提示來構建 API。 主要特點包含: -- **快速**: 非常高的效能,可與 **NodeJS** 和 **Go** 效能相當 (歸功於 Starlette and Pydantic)。 [FastAPI 是最快的 Python web 框架之一](#performance)。 -- **極速開發**: 提高開發功能的速度約 200% 至 300%。 \* -- **更少的 Bug**: 減少約 40% 的人為(開發者)導致的錯誤。 \* -- **直覺**: 具有出色的編輯器支援,處處都有自動補全以減少偵錯時間。 -- **簡單**: 設計上易於使用和學習,大幅減少閱讀文件的時間。 -- **簡潔**: 最小化程式碼重複性。可以通過不同的參數聲明來實現更豐富的功能,和更少的錯誤。 -- **穩健**: 立即獲得生產級可用的程式碼,還有自動生成互動式文件。 -- **標準化**: 基於 (且完全相容於) OpenAPIs 的相關標準:OpenAPI(之前被稱為 Swagger)和JSON Schema。 +* **快速**:非常高的效能,可與 **NodeJS** 和 **Go** 相當(歸功於 Starlette 和 Pydantic)。[最快的 Python 框架之一](#performance)。 +* **極速開發**:開發功能的速度可提升約 200% 至 300%。* +* **更少的 Bug**:減少約 40% 的人為(開發者)錯誤。* +* **直覺**:具有出色的編輯器支援,處處都有 自動補全。更少的偵錯時間。 +* **簡單**:設計上易於使用與學習。更少的讀文件時間。 +* **簡潔**:最小化程式碼重複性。每個參數宣告可帶來多個功能。更少的錯誤。 +* **穩健**:立即獲得可投入生產的程式碼,並自動生成互動式文件。 +* **標準化**:基於(且完全相容於)API 的開放標準:OpenAPI(之前稱為 Swagger)和 JSON Schema。 -\* 基於內部開發團隊在建立生產應用程式時的測試預估。 +* 基於內部開發團隊在建立生產應用程式時的測試預估。 -## 贊助 +## 贊助 { #sponsors } -{% if sponsors %} +### 基石贊助商 { #keystone-sponsor } + +{% for sponsor in sponsors.keystone -%} + +{% endfor -%} + +### 金級與銀級贊助商 { #gold-and-silver-sponsors } + {% for sponsor in sponsors.gold -%} {% endfor -%} {%- for sponsor in sponsors.silver -%} {% endfor %} -{% endif %} -其他贊助商 +其他贊助商 -## 評價 +## 評價 { #opinions } -"_[...] 近期大量的使用 **FastAPI**。 [...] 目前正在計畫在**微軟**團隊的**機器學習**服務中導入。其中一些正在整合到核心的 **Windows** 產品和一些 **Office** 產品。_" +"_[...] 近期大量使用 **FastAPI**。[...] 我實際上打算在我在**微軟**團隊的所有**機器學習**服務上使用它。其中一些正在整合到核心的 **Windows** 產品,以及一些 **Office** 產品。_"

Kabir Khan - Microsoft (ref)
--- -"_我們使用 **FastAPI** 來建立產生**預測**結果的 **REST** 伺服器。 [for Ludwig]_" +"_我們採用了 **FastAPI** 函式庫來啟動一個 **REST** 伺服器,供查詢以取得**預測**。[for Ludwig]_"
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
--- -"_**Netflix** 很榮幸地宣布開源**危機管理**協調框架: **Dispatch**! [是使用 **FastAPI** 建構]_" +"_**Netflix** 很高興宣布我們的**危機管理**協調框架 **Dispatch** 開源![使用 **FastAPI** 建構]_"
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
--- -"_我對 **FastAPI** 興奮得不得了。它太有趣了!_" +"_我對 **FastAPI** 興奮得不得了。超好玩!_" -
Brian Okken - Python Bytes podcast host (ref)
+
Brian Okken - Python Bytes podcast 主持人 (ref)
--- -"_老實說,你建造的東西看起來非常堅固和精緻。在很多方面,這就是我想要的,看到有人建造它真的很鼓舞人心。_" +"_老實說,你們做的看起來非常穩健又精緻。很多方面都正是我希望 **Hug** 成為的樣子——看到有人把它建出來真的很鼓舞人心。_" -
Timothy Crosley - Hug creator (ref)
+
Timothy Crosley - Hug 創作者 (ref)
--- -"_如果您想學習一種用於構建 REST API 的**現代框架**,不能錯過 **FastAPI** [...] 它非常快速、且易於使用和學習 [...]_" +"_如果你想學一個用於構建 REST API 的**現代框架**,看看 **FastAPI** [...] 它很快、易用、也容易學習 [...]_" -"_我們的 **APIs** 已經改用 **FastAPI** [...] 我想你會喜歡它 [...]_" +"_我們的 **API** 已經改用 **FastAPI** [...] 我想你會喜歡它 [...]_" -
Ines Montani - Matthew Honnibal - Explosion AI 創辦人 - spaCy creators (ref) - (ref)
+
Ines Montani - Matthew Honnibal - Explosion AI 創辦人 - spaCy 創作者 (ref) - (ref)
--- -"_如果有人想要建立一個生產環境的 Python API,我強烈推薦 **FastAPI**,它**設計精美**,**使用簡單**且**高度可擴充**,它已成為我們 API 優先開發策略中的**關鍵組件**,並且驅動了許多自動化服務,例如我們的 Virtual TAC Engineer。_" +"_如果有人想要建立一個可投入生產的 Python API,我強烈推薦 **FastAPI**。它**設計精美**、**使用簡單**且**高度可擴充**,已成為我們 API 優先開發策略中的**關鍵組件**,推動了許多自動化與服務,例如我們的 Virtual TAC Engineer。_"
Deon Pillsbury - Cisco (ref)
--- -## **Typer**,命令列中的 FastAPI +## FastAPI 迷你紀錄片 { #fastapi-mini-documentary } + +在 2025 年底發布了一支 FastAPI 迷你紀錄片,你可以在線上觀看: + +FastAPI Mini Documentary + +## **Typer**,命令列的 FastAPI { #typer-the-fastapi-of-clis } -如果你不是在開發網頁 API,而是正在開發一個在終端機中運行的命令列應用程式,不妨嘗試 **Typer**。 +如果你不是在做 Web API,而是要建立一個在終端機中使用的 CLI 應用程式,可以看看 **Typer**。 -**Typer** 是 FastAPI 的小兄弟。他立志成為命令列的 **FastAPI**。 ⌨️ 🚀 +**Typer** 是 FastAPI 的小老弟。他立志成為命令列世界的 **FastAPI**。⌨️ 🚀 -## 安裝需求 +## 需求 { #requirements } FastAPI 是站在以下巨人的肩膀上: -- Starlette 負責網頁的部分 -- Pydantic 負責資料的部分 +* Starlette 負責 Web 部分。 +* Pydantic 負責資料部分。 -## 安裝 +## 安裝 { #installation } + +建立並啟用一個虛擬環境,然後安裝 FastAPI:
```console -$ pip install fastapi +$ pip install "fastapi[standard]" ---> 100% ```
-你同時也會需要 ASGI 伺服器用於生產環境,像是 UvicornHypercorn。 +**注意**:請務必將 `"fastapi[standard]"` 用引號包起來,以確保在所有終端機中都能正常運作。 -
+## 範例 { #example } -```console -$ pip install "uvicorn[standard]" +### 建立 { #create-it } ----> 100% -``` - -
- -## 範例 - -### 建立 - -- 建立一個 python 檔案 `main.py`,並寫入以下程式碼: +建立檔案 `main.py`,內容如下: ```Python -from typing import Union - from fastapi import FastAPI app = FastAPI() @@ -164,18 +172,16 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): +def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} ```
-或可以使用 async def... +或使用 async def... -如果你的程式使用 `async` / `await`,請使用 `async def`: - -```Python hl_lines="9 14" -from typing import Union +如果你的程式碼使用 `async` / `await`,請使用 `async def`: +```Python hl_lines="7 12" from fastapi import FastAPI app = FastAPI() @@ -187,28 +193,41 @@ async def read_root(): @app.get("/items/{item_id}") -async def read_item(item_id: int, q: Union[str, None] = None): +async def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} ``` **注意**: -如果你不知道是否會用到,可以查看 _"In a hurry?"_ 章節中,關於 `async` 和 `await` 的部分。 +如果你不確定,請查看文件中 _"In a hurry?"_ 章節的 `async` 與 `await`
-### 運行 +### 運行 { #run-it } 使用以下指令運行伺服器:
```console -$ uvicorn main:app --reload +$ fastapi dev main.py + ╭────────── FastAPI CLI - Development mode ───────────╮ + │ │ + │ Serving at: http://127.0.0.1:8000 │ + │ │ + │ API docs: http://127.0.0.1:8000/docs │ + │ │ + │ Running in development mode, for production use: │ + │ │ + │ fastapi run │ + │ │ + ╰─────────────────────────────────────────────────────╯ + +INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp'] INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) -INFO: Started reloader process [28720] -INFO: Started server process [28722] +INFO: Started reloader process [2248755] using WatchFiles +INFO: Started server process [2248757] INFO: Waiting for application startup. INFO: Application startup complete. ``` @@ -216,21 +235,21 @@ INFO: Application startup complete.
-關於指令 uvicorn main:app --reload... +關於指令 fastapi dev main.py... -該指令 `uvicorn main:app` 指的是: +指令 `fastapi dev` 會讀取你的 `main.py`,偵測其中的 **FastAPI** 應用,並使用 Uvicorn 啟動伺服器。 -- `main`:`main.py` 檔案(一個 python 的 "模組")。 -- `app`:在 `main.py` 檔案中,使用 `app = FastAPI()` 建立的物件。 -- `--reload`:程式碼更改後會自動重新啟動,請僅在開發時使用此參數。 +預設情況下,`fastapi dev` 會在本機開發時啟用自動重新載入。 + +可在 FastAPI CLI 文件中閱讀更多資訊。
-### 檢查 +### 檢查 { #check-it } 使用瀏覽器開啟 http://127.0.0.1:8000/items/5?q=somequery。 -你將會看到以下的 JSON 回應: +你將會看到以下 JSON 回應: ```JSON {"item_id": 5, "q": "somequery"} @@ -238,36 +257,34 @@ INFO: Application startup complete. 你已經建立了一個具有以下功能的 API: -- 透過路徑 `/` 和 `/items/{item_id}` 接受 HTTP 請求。 -- 以上路經都接受 `GET` 請求(也被稱為 HTTP _方法_)。 -- 路徑 `/items/{item_id}` 有一個 `int` 型別的 `item_id` 參數。 -- 路徑 `/items/{item_id}` 有一個 `str` 型別的查詢參數 `q`。 +* 透過路徑 `/` 和 `/items/{item_id}` 接受 HTTP 請求。 +* 以上兩個路徑都接受 `GET` 操作(也被稱為 HTTP _方法_)。 +* 路徑 `/items/{item_id}` 有一個 `int` 型別的路徑參數 `item_id`。 +* 路徑 `/items/{item_id}` 有一個可選的 `str` 查詢參數 `q`。 -### 互動式 API 文件 +### 互動式 API 文件 { #interactive-api-docs } -使用瀏覽器開啟 http://127.0.0.1:8000/docs。 +接著前往 http://127.0.0.1:8000/docs。 -你會看到自動生成的互動式 API 文件(由 Swagger UI 生成): +你會看到自動生成的互動式 API 文件(由 Swagger UI 提供): ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -### ReDoc API 文件 +### 替代 API 文件 { #alternative-api-docs } -使用瀏覽器開啟 http://127.0.0.1:8000/redoc。 +現在前往 http://127.0.0.1:8000/redoc。 -你將看到 ReDoc 文件 (由 ReDoc 生成): +你會看到另一種自動文件(由 ReDoc 提供): ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -## 範例升級 +## 範例升級 { #example-upgrade } -現在繼續修改 `main.py` 檔案,來接收一個帶有 body 的 `PUT` 請求。 +現在修改 `main.py` 檔案,使其能從 `PUT` 請求接收 body。 -我們使用 Pydantic 來使用標準的 Python 型別聲明請求。 - -```Python hl_lines="4 9-12 25-27" -from typing import Union +多虧了 Pydantic,你可以用標準的 Python 型別來宣告 body。 +```Python hl_lines="2 7-10 23-25" from fastapi import FastAPI from pydantic import BaseModel @@ -277,7 +294,7 @@ app = FastAPI() class Item(BaseModel): name: str price: float - is_offer: Union[bool, None] = None + is_offer: bool | None = None @app.get("/") @@ -286,7 +303,7 @@ def read_root(): @app.get("/items/{item_id}") -def read_item(item_id: int, q: Union[str, None] = None): +def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q} @@ -295,43 +312,43 @@ def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id} ``` -伺服器將自動重新載入(因為在上一步中,你向 `uvicorn` 指令添加了 `--reload` 的選項)。 +`fastapi dev` 伺服器應會自動重新載入。 -### 互動式 API 文件升級 +### 互動式 API 文件升級 { #interactive-api-docs-upgrade } -使用瀏覽器開啟 http://127.0.0.1:8000/docs。 +前往 http://127.0.0.1:8000/docs。 -- 互動式 API 文件會自動更新,並加入新的 body 請求: +* 互動式 API 文件會自動更新,包含新的 body: ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) -- 點擊 "Try it out" 按鈕, 你可以填寫參數並直接與 API 互動: +* 點擊「Try it out」按鈕,你可以填寫參數並直接與 API 互動: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) -- 然後點擊 "Execute" 按鈕,使用者介面將會向 API 發送請求,並將結果顯示在螢幕上: +* 然後點擊「Execute」按鈕,使用者介面會與你的 API 溝通、送出參數、取得結果並顯示在螢幕上: ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) -### ReDoc API 文件升級 +### 替代 API 文件升級 { #alternative-api-docs-upgrade } -使用瀏覽器開啟 http://127.0.0.1:8000/redoc。 +現在前往 http://127.0.0.1:8000/redoc。 -- ReDoc API 文件會自動更新,並加入新的參數和 body 請求: +* 替代文件也會反映新的查詢參數與 body: ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) -### 總結 +### 總結 { #recap } -總結來說, 你就像宣告函式的參數型別一樣,只宣告了一次請求參數和請求主體參數等型別。 +總結來說,你只需在函式參數中**一次**宣告參數、body 等的型別。 -你使用 Python 標準型別來完成聲明。 +你使用的是現代標準的 Python 型別。 -你不需要學習新的語法、類別、方法或函式庫等等。 +你不需要學新的語法、特定函式庫的方法或類別,等等。 -只需要使用 **Python 以上的版本**。 +就用標準的 **Python**。 -舉個範例,比如宣告 int 的型別: +例如,對於一個 `int`: ```Python item_id: int @@ -343,126 +360,200 @@ item_id: int item: Item ``` -在進行一次宣告後,你將獲得: +…透過一次宣告,你將獲得: -- 編輯器支援: - - 自動補全 - - 型別檢查 -- 資料驗證: - - 驗證失敗時自動生成清楚的錯誤訊息 - - 可驗證多層巢狀的 JSON 物件 -- 轉換輸入的資料: 轉換來自網路請求到 Python 資料型別。包含以下數據: - - JSON - - 路徑參數 - - 查詢參數 - - Cookies - - 請求標頭 - - 表單 - - 文件 -- 轉換輸出的資料: 轉換 Python 資料型別到網路傳輸的 JSON: - - 轉換 Python 型別 (`str`、 `int`、 `float`、 `bool`、 `list` 等) - - `datetime` 物件 - - `UUID` 物件 - - 數據模型 - - ...還有其他更多 -- 自動生成的 API 文件,包含 2 種不同的使用介面: - - Swagger UI - - ReDoc +* 編輯器支援,包括: + * 自動補全。 + * 型別檢查。 +* 資料驗證: + * 當資料無效時,自動且清楚的錯誤。 + * 即使是深度巢狀的 JSON 物件也能驗證。 +* 輸入資料的 轉換:從網路讀入到 Python 資料與型別。包含: + * JSON。 + * 路徑參數。 + * 查詢參數。 + * Cookies。 + * 標頭。 + * 表單。 + * 檔案。 +* 輸出資料的 轉換:從 Python 資料與型別轉換為網路資料(JSON): + * 轉換 Python 型別(`str`、`int`、`float`、`bool`、`list` 等)。 + * `datetime` 物件。 + * `UUID` 物件。 + * 資料庫模型。 + * ...還有更多。 +* 自動生成的互動式 API 文件,包含 2 種替代的使用者介面: + * Swagger UI。 + * ReDoc。 --- -回到前面的的程式碼範例,**FastAPI** 還會: +回到前面的程式碼範例,**FastAPI** 會: -- 驗證 `GET` 和 `PUT` 請求路徑中是否包含 `item_id`。 -- 驗證 `GET` 和 `PUT` 請求中的 `item_id` 是否是 `int` 型別。 - - 如果驗證失敗,將會返回清楚有用的錯誤訊息。 -- 查看 `GET` 請求中是否有命名為 `q` 的查詢參數 (例如 `http://127.0.0.1:8000/items/foo?q=somequery`)。 - - 因為 `q` 參數被宣告為 `= None`,所以是選填的。 - - 如果沒有宣告 `None`,則此參數將會是必填 (例如 `PUT` 範例的請求 body)。 -- 對於 `PUT` 的請求 `/items/{item_id}`,將會讀取 body 為 JSON: - - 驗證是否有必填屬性 `name` 且型別是 `str`。 - - 驗證是否有必填屬性 `price` 且型別是 `float`。 - - 驗證是否有選填屬性 `is_offer` 且型別是 `bool`。 - - 以上驗證都適用於多層次巢狀 JSON 物件。 -- 自動轉換 JSON 格式。 -- 透過 OpenAPI 文件來記錄所有內容,可以被用於: - - 互動式文件系統。 - - 自動為多種程式語言生成用戶端的程式碼。 -- 提供兩種交互式文件介面。 +* 驗證 `GET` 與 `PUT` 請求的路徑中是否包含 `item_id`。 +* 驗證 `GET` 與 `PUT` 請求中的 `item_id` 是否為 `int` 型別。 + * 如果不是,客戶端會看到清楚有用的錯誤。 +* 在 `GET` 請求中檢查是否有名為 `q` 的可選查詢參數(如 `http://127.0.0.1:8000/items/foo?q=somequery`)。 + * 因為 `q` 參數被宣告為 `= None`,所以它是可選的。 + * 若沒有 `None`,則它會是必填(就像 `PUT` 時的 body)。 +* 對於 `/items/{item_id}` 的 `PUT` 請求,以 JSON 讀取 body: + * 檢查是否有必填屬性 `name`,且為 `str`。 + * 檢查是否有必填屬性 `price`,且為 `float`。 + * 檢查是否有可選屬性 `is_offer`,若存在則應為 `bool`。 + * 以上也適用於深度巢狀的 JSON 物件。 +* 自動在 JSON 與 Python 之間轉換。 +* 以 OpenAPI 記錄所有內容,可用於: + * 互動式文件系統。 + * 為多種語言自動產生用戶端程式碼的系統。 +* 直接提供兩種互動式文件網頁介面。 --- -雖然我們只敘述了表面的功能,但其實你已經理解了它是如何執行。 +我們只觸及了表面,但你已經了解它的運作方式了。 -試著修改以下程式碼: +試著把這一行: ```Python return {"item_name": item.name, "item_id": item_id} ``` -從: +…從: ```Python ... "item_name": item.name ... ``` -修改為: +…改為: ```Python ... "item_price": item.price ... ``` -然後觀察你的編輯器,會自動補全並且還知道他們的型別: +…然後看看你的編輯器如何自動補全屬性並知道它們的型別: ![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) -有關更多功能的完整範例,可以參考 教學 - 使用者指南。 +若想看包含更多功能的完整範例,請參考 教學 - 使用者指南。 -**劇透警告**: 教學 - 使用者指南內容有: +**劇透警告**:教學 - 使用者指南包含: -- 對來自不同地方的**參數**進行宣告:像是 **headers**, **cookies**, **form 表單**以及**上傳檔案**。 -- 如何設定 **驗證限制** 像是 `maximum_length` or `regex`。 -- 簡單且非常容易使用的 **依賴注入** 系統。 -- 安全性和身份驗證,包含提供支援 **OAuth2**、**JWT tokens** 和 **HTTP Basic** 驗證。 -- 更進階 (但同樣簡單) 的宣告 **多層次的巢狀 JSON 格式** (感謝 Pydantic)。 -- **GraphQL** 與 Strawberry 以及其他的相關函式庫進行整合。 -- 更多其他的功能 (感謝 Starlette) 像是: - - **WebSockets** - - 於 HTTPX 和 `pytest` 的非常簡單測試 - - **CORS** - - **Cookie Sessions** - - ...以及更多 +* 來自不同來源的**參數**宣告:例如 **headers**、**cookies**、**form fields** 和 **files**。 +* 如何設定**驗證限制**,如 `maximum_length` 或 `regex`。 +* 一個非常強大且易用的 **依賴注入** 系統。 +* 安全與驗證,包含支援 **OAuth2** 搭配 **JWT tokens** 與 **HTTP Basic** 驗證。 +* 宣告**深度巢狀 JSON 模型**的進階(但同樣簡單)技巧(感謝 Pydantic)。 +* 與 Strawberry 及其他函式庫的 **GraphQL** 整合。 +* 許多額外功能(感謝 Starlette),例如: + * **WebSockets** + * 基於 HTTPX 與 `pytest` 的極其簡單的測試 + * **CORS** + * **Cookie Sessions** + * ...以及更多。 -## 效能 +### 部署你的應用(可選) { #deploy-your-app-optional } -來自獨立機構 TechEmpower 的測試結果,顯示在 Uvicorn 執行下的 **FastAPI** 是 最快的 Python 框架之一, 僅次於 Starlette 和 Uvicorn 本身 (兩者是 FastAPI 的底層)。 (\*) +你也可以選擇將 FastAPI 應用部署到 FastAPI Cloud,如果你還沒加入,去登記等候名單吧。🚀 -想了解更多訊息,可以參考 測試結果。 +如果你已經有 **FastAPI Cloud** 帳號(我們已從等候名單邀請你 😉),你可以用一個指令部署你的應用。 -## 可選的依賴套件 +部署前,先確認你已登入: -用於 Pydantic: +
-- email-validator - 用於電子郵件驗證。 -- pydantic-settings - 用於設定管理。 -- pydantic-extra-types - 用於與 Pydantic 一起使用的額外型別。 +```console +$ fastapi login -用於 Starlette: +You are logged in to FastAPI Cloud 🚀 +``` -- httpx - 使用 `TestClient`時必須安裝。 -- jinja2 - 使用預設的模板配置時必須安裝。 -- python-multipart - 需要使用 `request.form()` 對表單進行 "解析" 時安裝。 -- itsdangerous - 需要使用 `SessionMiddleware` 支援時安裝。 -- pyyaml - 用於支援 Starlette 的 `SchemaGenerator` (如果你使用 FastAPI,可能不需要它)。 +
-用於 FastAPI / Starlette: +接著部署你的應用: -- uvicorn - 用於加載和運行應用程式的服務器。 -- orjson - 使用 `ORJSONResponse`時必須安裝。 -- ujson - 使用 `UJSONResponse` 時必須安裝。 +
-你可以使用 `pip install "fastapi[all]"` 來安裝這些所有依賴套件。 +```console +$ fastapi deploy -## 授權 +Deploying to FastAPI Cloud... -該項目遵循 MIT 許可協議。 +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
+ +就這樣!現在你可以在該 URL 造訪你的應用。✨ + +#### 關於 FastAPI Cloud { #about-fastapi-cloud } + +**FastAPI Cloud** 由 **FastAPI** 的同一位作者與團隊打造。 + +它讓你以最小的努力精簡地完成 API 的**建置**、**部署**與**存取**流程。 + +它把用 FastAPI 開發應用的**開發者體驗**帶到**部署**到雲端的流程中。🎉 + +FastAPI Cloud 是「FastAPI 與好朋友們」這些開源專案的主要贊助與資金來源。✨ + +#### 部署到其他雲端供應商 { #deploy-to-other-cloud-providers } + +FastAPI 是開源且基於標準。你可以把 FastAPI 應用部署到任何你選擇的雲端供應商。 + +依照你雲端供應商的指南來部署 FastAPI 應用吧。🤓 + +## 效能 { #performance } + +獨立的 TechEmpower 基準測試顯示,在 Uvicorn 下運行的 **FastAPI** 應用是最快的 Python 框架之一,僅次於 Starlette 與 Uvicorn 本身(FastAPI 內部使用它們)。(*) + +想了解更多,請參閱測試結果。 + +## 依賴套件 { #dependencies } + +FastAPI 依賴 Pydantic 與 Starlette。 + +### `standard` 依賴套件 { #standard-dependencies } + +當你以 `pip install "fastapi[standard]"` 安裝 FastAPI 時,會包含 `standard` 這組可選依賴套件: + +Pydantic 會使用: + +* email-validator - 用於電子郵件驗證。 + +Starlette 會使用: + +* httpx - 若要使用 `TestClient` 必須安裝。 +* jinja2 - 若要使用預設的模板設定必須安裝。 +* python-multipart - 若要支援表單 "解析",搭配 `request.form()`。 + +FastAPI 會使用: + +* uvicorn - 用於載入並服務你的應用的伺服器。這包含 `uvicorn[standard]`,其中含有一些高效能服務所需的依賴(例如 `uvloop`)。 +* `fastapi-cli[standard]` - 提供 `fastapi` 指令。 + * 其中包含 `fastapi-cloud-cli`,可讓你將 FastAPI 應用部署到 FastAPI Cloud。 + +### 不含 `standard` 依賴套件 { #without-standard-dependencies } + +如果你不想包含 `standard` 可選依賴,可以改用 `pip install fastapi`(而不是 `pip install "fastapi[standard]"`)。 + +### 不含 `fastapi-cloud-cli` { #without-fastapi-cloud-cli } + +如果你想安裝帶有 standard 依賴、但不包含 `fastapi-cloud-cli`,可以使用 `pip install "fastapi[standard-no-fastapi-cloud-cli]"`。 + +### 額外可選依賴套件 { #additional-optional-dependencies } + +有些額外依賴你可能也會想安裝。 + +Pydantic 的額外可選依賴: + +* pydantic-settings - 設定管理。 +* pydantic-extra-types - 與 Pydantic 一起使用的額外型別。 + +FastAPI 的額外可選依賴: + +* orjson - 若要使用 `ORJSONResponse` 必須安裝。 +* ujson - 若要使用 `UJSONResponse` 必須安裝。 + +## 授權 { #license } + +本專案以 MIT 授權條款釋出。 diff --git a/docs/zh-hant/docs/learn/index.md b/docs/zh-hant/docs/learn/index.md index eb7d7096a5..43e4519a50 100644 --- a/docs/zh-hant/docs/learn/index.md +++ b/docs/zh-hant/docs/learn/index.md @@ -1,5 +1,5 @@ -# 學習 +# 學習 { #learn } -以下是學習 FastAPI 的入門介紹和教學。 +以下是學習 **FastAPI** 的入門介紹和教學。 你可以將其視為一本**書籍**或一門**課程**,這是**官方**認可並推薦的 FastAPI 學習方式。 😎 diff --git a/docs/zh-hant/docs/resources/index.md b/docs/zh-hant/docs/resources/index.md index f4c70a3a04..ea77cb728e 100644 --- a/docs/zh-hant/docs/resources/index.md +++ b/docs/zh-hant/docs/resources/index.md @@ -1,3 +1,3 @@ -# 資源 +# 資源 { #resources } -額外的資源、外部連結、文章等。 ✈️ +額外的資源、外部連結等。 ✈️ diff --git a/docs/zh-hant/docs/tutorial/first-steps.md b/docs/zh-hant/docs/tutorial/first-steps.md index d6684bc513..6bcb453bff 100644 --- a/docs/zh-hant/docs/tutorial/first-steps.md +++ b/docs/zh-hant/docs/tutorial/first-steps.md @@ -1,8 +1,8 @@ -# 第一步 +# 第一步 { #first-steps } 最簡單的 FastAPI 檔案可能看起來像這樣: -{* ../../docs_src/first_steps/tutorial001.py *} +{* ../../docs_src/first_steps/tutorial001_py39.py *} 將其複製到一個名為 `main.py` 的文件中。 @@ -11,47 +11,39 @@
```console -$ fastapi dev main.py -INFO Using path main.py -INFO Resolved absolute path /home/user/code/awesomeapp/main.py -INFO Searching for package file structure from directories with __init__.py files -INFO Importing from /home/user/code/awesomeapp +$ fastapi dev main.py - ╭─ Python module file ─╮ - │ │ - │ 🐍 main.py │ - │ │ - ╰──────────────────────╯ + FastAPI Starting development server 🚀 -INFO Importing module main -INFO Found importable FastAPI app + Searching for package file structure from directories + with __init__.py files + Importing from /home/user/code/awesomeapp - ╭─ Importable FastAPI app ─╮ - │ │ - │ from main import app │ - │ │ - ╰──────────────────────────╯ + module 🐍 main.py -INFO Using import string main:app + code Importing the FastAPI app object from the module with + the following code: - ╭────────── FastAPI CLI - Development mode ───────────╮ - │ │ - │ Serving at: http://127.0.0.1:8000 │ - │ │ - │ API docs: http://127.0.0.1:8000/docs │ - │ │ - │ Running in development mode, for production use: │ - │ │ - fastapi run - │ │ - ╰─────────────────────────────────────────────────────╯ + from main import app -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 [2265862] using WatchFiles -INFO: Started server process [2265873] -INFO: Waiting for application startup. -INFO: Application startup complete. + 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. ```
@@ -64,7 +56,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) 那列顯示了你的應用程式正在本地端機器上運行的 URL。 -### 查看它 +### 查看它 { #check-it } 在瀏覽器中打開 http://127.0.0.1:8000. @@ -74,7 +66,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) {"message": "Hello World"} ``` -### 互動式 API 文件 +### 互動式 API 文件 { #interactive-api-docs } 現在,前往 http://127.0.0.1:8000/docs. @@ -82,7 +74,7 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) -### 替代 API 文件 +### 替代 API 文件 { #alternative-api-docs } 現在,前往 http://127.0.0.1:8000/redoc. @@ -90,33 +82,33 @@ INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) -### OpenAPI +### OpenAPI { #openapi } -**FastAPI** 使用定義 API 的 **OpenAPI** 標準來生成一個 「schema」 與你的所有 API。 +**FastAPI** 使用定義 API 的 **OpenAPI** 標準來生成一個「schema」,涵蓋你的全部 API。 -#### 「Schema」 +#### 「Schema」 { #schema } 「schema」是對某個事物的定義或描述。它並不是實作它的程式碼,而僅僅是一個抽象的描述。 -#### API 「schema」 +#### API 「schema」 { #api-schema } 在這種情況下,OpenAPI 是一個規範,它規定了如何定義 API 的 schema。 這個 schema 定義包含了你的 API 路徑、可能接收的參數等內容。 -#### 資料 「schema」 +#### 資料「schema」 { #data-schema } 「schema」這個術語也可能指某些資料的結構,比如 JSON 內容的結構。 在這種情況下,它指的是 JSON 的屬性、資料型別等。 -#### OpenAPI 和 JSON Schema +#### OpenAPI 和 JSON Schema { #openapi-and-json-schema } -OpenAPI 定義了 API 的 schema。這個 schema 包含了使用 **JSON Schema** 定義的資料,這是 JSON 資料 schema 的標準。 +OpenAPI 為你的 API 定義了 API 的 schema。而該 schema 會包含你的 API 所傳送與接收資料的定義(或稱「schemas」),使用 **JSON Schema**,這是 JSON 資料 schema 的標準。 -#### 檢查 `openapi.json` +#### 檢查 `openapi.json` { #check-the-openapi-json } -如果你好奇原始的 OpenAPI schema 長什麼樣子,FastAPI 會自動生成一個包含所有 API 描述的 JSON (schema)。 +如果你好奇原始的 OpenAPI schema 長什麼樣子,FastAPI 會自動生成一個包含所有 API 描述的 JSON(schema)。 你可以直接在 http://127.0.0.1:8000/openapi.json 查看它。 @@ -143,23 +135,59 @@ OpenAPI 定義了 API 的 schema。這個 schema 包含了使用 **JSON Schema** ... ``` -#### OpenAPI 的用途 +#### OpenAPI 的用途 { #what-is-openapi-for } OpenAPI schema 驅動了兩個互動式文件系統。 而且有許多替代方案,所有這些都是基於 OpenAPI。你可以輕鬆地將任何這些替代方案添加到使用 **FastAPI** 建置的應用程式中。 -你也可以用它自動生成程式碼,讓前端、手機應用程式或物聯網設備等與你的 API 進行通訊。 +你也可以用它自動生成程式碼,讓用戶端與你的 API 通訊。例如前端、手機或物聯網(IoT)應用程式。 -## 逐步回顧 +### 部署你的應用程式(可選) { #deploy-your-app-optional } -### 第一步:引入 `FastAPI` +你可以選擇將你的 FastAPI 應用程式部署到 FastAPI Cloud,如果還沒有,去加入候補名單吧。🚀 -{* ../../docs_src/first_steps/tutorial001.py h1[1] *} +如果你已經有 **FastAPI Cloud** 帳號(我們已從候補名單邀請你 😉),你可以用一個指令部署你的應用程式。 + +部署之前,先確保你已登入: + +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
+ +接著部署你的應用程式: + +
+ +```console +$ fastapi deploy + +Deploying to FastAPI Cloud... + +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
+ +就這樣!現在你可以透過該 URL 存取你的應用程式了。✨ + +## 逐步回顧 { #recap-step-by-step } + +### 第一步:引入 `FastAPI` { #step-1-import-fastapi } + +{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *} `FastAPI` 是一個 Python 類別,提供所有 API 的全部功能。 -/// note | Technical Details +/// note | 技術細節 `FastAPI` 是一個直接繼承自 `Starlette` 的類別。 @@ -167,17 +195,17 @@ OpenAPI schema 驅動了兩個互動式文件系統。 /// -### 第二步:建立一個 `FastAPI` 「實例」 +### 第二步:建立一個 `FastAPI`「實例」 { #step-2-create-a-fastapi-instance } -{* ../../docs_src/first_steps/tutorial001.py h1[3] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *} 這裡的 `app` 變數將會是 `FastAPI` 類別的「實例」。 這將是你建立所有 API 的主要互動點。 -### 第三步:建立一個 *路徑操作* +### 第三步:建立一個「路徑操作」 { #step-3-create-a-path-operation } -#### 路徑 +#### 路徑 { #path } 這裡的「路徑」指的是 URL 中自第一個 `/` 以後的部分。 @@ -201,7 +229,7 @@ https://example.com/items/foo 在建置 API 時,「路徑」是分離「關注點」和「資源」的主要方式。 -#### 操作 +#### 操作 { #operation } 這裡的「操作」指的是 HTTP 的「方法」之一。 @@ -236,16 +264,16 @@ https://example.com/items/foo 我們將會稱它們為「**操作**」。 -#### 定義一個 *路徑操作裝飾器* +#### 定義一個「路徑操作裝飾器」 { #define-a-path-operation-decorator } -{* ../../docs_src/first_steps/tutorial001.py h1[6] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *} `@app.get("/")` 告訴 **FastAPI** 那個函式負責處理請求: * 路徑 `/` * 使用 get操作 -/// info | `@decorator` Info +/// info | `@decorator` 說明 Python 中的 `@something` 語法被稱為「裝飾器」。 @@ -253,7 +281,7 @@ Python 中的 `@something` 語法被稱為「裝飾器」。 一個「裝飾器」會對下面的函式做一些事情。 -在這種情況下,這個裝飾器告訴 **FastAPI** 那個函式對應於 **路徑** `/` 和 **操作** `get`. +在這種情況下,這個裝飾器告訴 **FastAPI** 那個函式對應於 **路徑** `/` 和 **操作** `get`。 這就是「**路徑操作裝飾器**」。 @@ -284,27 +312,27 @@ Python 中的 `@something` 語法被稱為「裝飾器」。 /// -### 第四步:定義 **路徑操作函式** +### 第四步:定義「路徑操作函式」 { #step-4-define-the-path-operation-function } 這是我們的「**路徑操作函式**」: -* **path**: 是 `/`. -* **operation**: 是 `get`. -* **function**: 是裝飾器下面的函式(在 `@app.get("/")` 下面)。 +* **path**:是 `/`。 +* **operation**:是 `get`。 +* **function**:是裝飾器下面的函式(在 `@app.get("/")` 下面)。 -{* ../../docs_src/first_steps/tutorial001.py h1[7] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *} 這就是一個 Python 函式。 -它將會在 **FastAPI** 收到一個請求時被呼叫,使用 `GET` 操作。 +它將會在 **FastAPI** 收到一個使用 `GET` 操作、網址為「`/`」的請求時被呼叫。 在這種情況下,它是一個 `async` 函式。 --- -你可以將它定義為一個正常的函式,而不是 `async def`: +你也可以將它定義為一般函式,而不是 `async def`: -{* ../../docs_src/first_steps/tutorial003.py h1[7] *} +{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *} /// note @@ -312,9 +340,9 @@ Python 中的 `@something` 語法被稱為「裝飾器」。 /// -### 第五步:回傳內容 +### 第五步:回傳內容 { #step-5-return-the-content } -{* ../../docs_src/first_steps/tutorial001.py h1[8] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *} 你可以返回一個 `dict`、`list`、單個值作為 `str`、`int` 等。 @@ -322,10 +350,31 @@ Python 中的 `@something` 語法被稱為「裝飾器」。 有很多其他物件和模型會自動轉換為 JSON(包括 ORMs,等等)。試用你最喜歡的,很有可能它們已經有支援。 -## 回顧 +### 第六步:部署 { #step-6-deploy-it } -* 引入 `FastAPI`. +用一行指令將你的應用程式部署到 **FastAPI Cloud**:`fastapi deploy`。🎉 + +#### 關於 FastAPI Cloud { #about-fastapi-cloud } + +**FastAPI Cloud** 由 **FastAPI** 的作者與團隊打造。 + +它讓你以最小的成本完成 API 的**建置**、**部署**與**存取**流程。 + +它把用 FastAPI 開發應用的同樣**開發者體驗**帶到將應用**部署**到雲端的流程中。🎉 + +FastAPI Cloud 也是「FastAPI 與其好友」這些開源專案的主要贊助與資金提供者。✨ + +#### 部署到其他雲端供應商 { #deploy-to-other-cloud-providers } + +FastAPI 是開源並基於標準的。你可以把 FastAPI 應用部署到你選擇的任何雲端供應商。 + +依照你的雲端供應商的指南部署 FastAPI 應用吧。🤓 + +## 回顧 { #recap } + +* 引入 `FastAPI`。 * 建立一個 `app` 實例。 -* 寫一個 **路徑操作裝飾器** 使用裝飾器像 `@app.get("/")`。 -* 定義一個 **路徑操作函式**;例如,`def root(): ...`。 +* 寫一個「路徑操作裝飾器」,像是 `@app.get("/")`。 +* 定義一個「路徑操作函式」;例如,`def root(): ...`。 * 使用命令 `fastapi dev` 執行開發伺服器。 +* 可選:使用 `fastapi deploy` 部署你的應用程式。 diff --git a/docs/zh-hant/docs/tutorial/index.md b/docs/zh-hant/docs/tutorial/index.md index ae0056f528..5e1961fd7b 100644 --- a/docs/zh-hant/docs/tutorial/index.md +++ b/docs/zh-hant/docs/tutorial/index.md @@ -1,4 +1,4 @@ -# 教學 - 使用者指南 +# 教學 - 使用者指南 { #tutorial-user-guide } 本教學將一步一步展示如何使用 **FastAPI** 及其大多數功能。 @@ -6,7 +6,7 @@ 它也被設計成可作為未來的參考,讓你隨時回來查看所需的內容。 -## 運行程式碼 +## 運行程式碼 { #run-the-code } 所有程式碼區塊都可以直接複製和使用(它們實際上是經過測試的 Python 檔案)。 @@ -15,48 +15,39 @@
```console -$ fastapi dev main.py -INFO Using path main.py -INFO Resolved absolute path /home/user/code/awesomeapp/main.py -INFO Searching for package file structure from directories with __init__.py files -INFO Importing from /home/user/code/awesomeapp +$ fastapi dev main.py - ╭─ Python module file ─╮ - │ │ - │ 🐍 main.py │ - │ │ - ╰──────────────────────╯ + FastAPI Starting development server 🚀 -INFO Importing module main -INFO Found importable FastAPI app + Searching for package file structure from directories + with __init__.py files + Importing from /home/user/code/awesomeapp - ╭─ Importable FastAPI app ─╮ - │ │ - │ from main import app │ - │ │ - ╰──────────────────────────╯ + module 🐍 main.py -INFO Using import string main:app + code Importing the FastAPI app object from the module with + the following code: - ╭────────── FastAPI CLI - Development mode ───────────╮ - │ │ - │ Serving at: http://127.0.0.1:8000 │ - │ │ - │ API docs: http://127.0.0.1:8000/docs │ - │ │ - │ Running in development mode, for production use: │ - │ │ - fastapi run - │ │ - ╰─────────────────────────────────────────────────────╯ + from main import app -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 [2265862] using WatchFiles -INFO: Started server process [2265873] -INFO: Waiting for application startup. -INFO: Application startup complete. - + 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. ```
@@ -67,7 +58,7 @@ $ fastapi dev -/// note +/// note | 注意 -當你使用 `pip install "fastapi[standard]"` 安裝時,會包含一些預設的可選標準依賴項。 +當你使用 `pip install "fastapi[standard]"` 安裝時,會包含一些預設的可選標準依賴項,其中包括 `fastapi-cloud-cli`,它可以讓你部署到 FastAPI Cloud。 -如果你不想包含那些可選的依賴項,你可以使用 `pip install fastapi` 來安裝。 +如果你不想包含那些可選的依賴項,你可以改為安裝 `pip install fastapi`。 + +如果你想安裝標準依賴項,但不包含 `fastapi-cloud-cli`,可以使用 `pip install "fastapi[standard-no-fastapi-cloud-cli]"` 安裝。 /// -## 進階使用者指南 +## 進階使用者指南 { #advanced-user-guide } -還有一個**進階使用者指南**你可以稍後閱讀。 +還有一個**進階使用者指南**你可以在讀完這個**教學 - 使用者指南**後再閱讀。 **進階使用者指南**建立在這個教學之上,使用相同的概念,並教你一些額外的功能。 diff --git a/docs/zh-hant/docs/tutorial/query-param-models.md b/docs/zh-hant/docs/tutorial/query-param-models.md index 76ee740169..e360281990 100644 --- a/docs/zh-hant/docs/tutorial/query-param-models.md +++ b/docs/zh-hant/docs/tutorial/query-param-models.md @@ -1,4 +1,4 @@ -# 查詢參數模型 +# 查詢參數模型 { #query-parameter-models } 如果你有一組具有相關性的**查詢參數**,你可以建立一個 **Pydantic 模型**來聲明它們。 @@ -10,7 +10,7 @@ FastAPI 從 `0.115.0` 版本開始支援這個特性。🤓 /// -## 使用 Pydantic 模型的查詢參數 +## 使用 Pydantic 模型的查詢參數 { #query-parameters-with-a-pydantic-model } 在一個 **Pydantic 模型**中聲明你需要的**查詢參數**,然後將參數聲明為 `Query`: @@ -18,7 +18,7 @@ FastAPI 從 `0.115.0` 版本開始支援這個特性。🤓 **FastAPI** 將會從請求的**查詢參數**中**提取**出**每個欄位**的資料,並將其提供給你定義的 Pydantic 模型。 -## 查看文件 +## 查看文件 { #check-the-docs } 你可以在 `/docs` 頁面的 UI 中查看查詢參數: @@ -26,7 +26,7 @@ FastAPI 從 `0.115.0` 版本開始支援這個特性。🤓 -## 禁止額外的查詢參數 +## 禁止額外的查詢參數 { #forbid-extra-query-parameters } 在一些特殊的使用場景中(可能不是很常見),你可能希望**限制**你要收到的查詢參數。 @@ -57,7 +57,7 @@ https://example.com/items/?limit=10&tool=plumbus } ``` -## 總結 +## 總結 { #summary } 你可以使用 **Pydantic 模型**在 **FastAPI** 中聲明**查詢參數**。😎 diff --git a/docs/zh-hant/docs/virtual-environments.md b/docs/zh-hant/docs/virtual-environments.md index d8e31e08e0..acd1d914ea 100644 --- a/docs/zh-hant/docs/virtual-environments.md +++ b/docs/zh-hant/docs/virtual-environments.md @@ -1,4 +1,4 @@ -# 虛擬環境 +# 虛擬環境 { #virtual-environments } 當你在 Python 專案中工作時,你可能會需要使用一個**虛擬環境**(或類似的機制)來隔離你為每個專案安裝的套件。 @@ -26,7 +26,7 @@ /// -## 建立一個專案 +## 建立一個專案 { #create-a-project } 首先,為你的專案建立一個目錄。 @@ -51,7 +51,7 @@ $ cd awesome-project -## 建立一個虛擬環境 +## 建立一個虛擬環境 { #create-a-virtual-environment } 在開始一個 Python 專案的**第一時間**,**在你的專案內部**建立一個虛擬環境。 @@ -114,7 +114,7 @@ $ uv venv /// -## 啟動虛擬環境 +## 啟動虛擬環境 { #activate-the-virtual-environment } 啟動新的虛擬環境來確保你運行的任何 Python 指令或安裝的套件都能使用到它。 @@ -166,11 +166,11 @@ $ source .venv/Scripts/activate 每次你在這個環境中安裝一個**新的套件**時,都需要**重新啟動**這個環境。 -這麼做確保了當你使用一個由這個套件安裝的**終端(CLI)程式**時,你使用的是你的虛擬環境中的程式,而不是全域安裝、可能版本不同的程式。 +這麼做確保了當你使用一個由這個套件安裝的**終端(CLI)程式**時,你使用的是你的虛擬環境中的程式,而不是全域安裝、可能版本不同的程式。 /// -## 檢查虛擬環境是否啟動 +## 檢查虛擬環境是否啟動 { #check-the-virtual-environment-is-active } 檢查虛擬環境是否啟動(前面的指令是否生效)。 @@ -212,7 +212,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python //// -## 升級 `pip` +## 升級 `pip` { #upgrade-pip } /// tip @@ -242,7 +242,27 @@ $ python -m pip install --upgrade pip -## 加入 `.gitignore` +/// tip | 注意 + +有時你在嘗試升級 pip 時,可能會遇到 **`No module named pip`** 的錯誤。 + +如果發生這種情況,請用下面的指令安裝並升級 pip: + +
+ +```console +$ python -m ensurepip --upgrade + +---> 100% +``` + +
+ +此指令會在未安裝 pip 時為你安裝它,並確保安裝的 pip 版本至少與 `ensurepip` 所提供的版本一樣新。 + +/// + +## 加入 `.gitignore` { #add-gitignore } 如果你使用 **Git**(這是你應該使用的),加入一個 `.gitignore` 檔案來排除你的 `.venv` 中的所有內容。 @@ -282,7 +302,7 @@ $ echo "*" > .venv/.gitignore /// -## 安裝套件 +## 安裝套件 { #install-packages } 在啟用虛擬環境後,你可以在其中安裝套件。 @@ -294,7 +314,7 @@ $ echo "*" > .venv/.gitignore /// -### 直接安裝套件 +### 直接安裝套件 { #install-packages-directly } 如果你急於安裝,不想使用檔案來聲明專案的套件依賴,你可以直接安裝它們。 @@ -333,7 +353,7 @@ $ uv pip install "fastapi[standard]" //// -### 從 `requirements.txt` 安裝 +### 從 `requirements.txt` 安裝 { #install-from-requirements-txt } 如果你有一個 `requirements.txt` 檔案,你可以使用它來安裝其中的套件。 @@ -376,7 +396,7 @@ pydantic==2.8.0 /// -## 執行程式 +## 執行程式 { #run-your-program } 在啟用虛擬環境後,你可以執行你的程式,它將使用虛擬環境中的 Python 和你在其中安裝的套件。 @@ -390,7 +410,7 @@ Hello World -## 設定編輯器 +## 設定編輯器 { #configure-your-editor } 你可能會用到編輯器,請確保設定它使用你建立的相同虛擬環境(它可能會自動偵測到),以便你可以獲得自動完成和内嵌錯誤提示。 @@ -405,7 +425,7 @@ Hello World /// -## 退出虛擬環境 +## 退出虛擬環境 { #deactivate-the-virtual-environment } 當你完成工作後,你可以**退出**虛擬環境。 @@ -419,7 +439,7 @@ $ deactivate 這樣,當你執行 `python` 時它不會嘗試從已安裝套件的虛擬環境中執行。 -## 開始工作 +## 開始工作 { #ready-to-work } 現在你已經準備好開始你的工作了。 @@ -433,7 +453,7 @@ $ deactivate /// -## 為什麼要使用虛擬環境 +## 為什麼要使用虛擬環境 { #why-virtual-environments } 你需要安裝 Python 才能使用 FastAPI。 @@ -443,7 +463,7 @@ $ deactivate 然而,如果你直接使用 `pip`,套件將會安裝在你的**全域 Python 環境**中(即 Python 的全域安裝)。 -### 存在的問題 +### 存在的問題 { #the-problem } 那麼,在全域 Python 環境中安裝套件有什麼問題呢? @@ -526,7 +546,7 @@ Python 套件在推出**新版本**時通常會儘量**避免破壞性更改** 此外,取決於你的操作系統(例如 Linux、Windows、macOS),它可能已經預先安裝了 Python。在這種情況下,它可能已經有一些系統所需的套件和特定版本。如果你在全域 Python 環境中安裝套件,可能會**破壞**某些隨作業系統一起安裝的程式。 -## 套件安裝在哪裡 +## 套件安裝在哪裡 { #where-are-packages-installed } 當你安裝 Python 時,它會在你的電腦中建立一些目錄並放置一些檔案。 @@ -552,7 +572,7 @@ $ pip install "fastapi[standard]" 預設情況下,這些下載和解壓的檔案會放置於隨 Python 安裝的目錄中,即**全域環境**。 -## 什麼是虛擬環境 +## 什麼是虛擬環境 { #what-are-virtual-environments } 解決套件都安裝在全域環境中的問題方法是為你所做的每個專案使用一個**虛擬環境**。 @@ -577,7 +597,7 @@ flowchart TB stone-project ~~~ azkaban-project ``` -## 啟用虛擬環境意味著什麼 +## 啟用虛擬環境意味著什麼 { #what-does-activating-a-virtual-environment-mean } 當你啟用了虛擬環境,例如: @@ -714,7 +734,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python 啟用虛擬環境還會改變其他一些內容,但這是它所做的最重要的事情之一。 -## 檢查虛擬環境 +## 檢查虛擬環境 { #checking-a-virtual-environment } 當你檢查虛擬環境是否啟動時,例如: @@ -766,7 +786,7 @@ C:\Users\user\code\awesome-project\.venv\Scripts\python /// -## 為什麼要停用虛擬環境 +## 為什麼要停用虛擬環境 { #why-deactivate-a-virtual-environment } 例如,你可能正在一個專案 `philosophers-stone` 上工作,**啟動了該虛擬環境**,安裝了套件並使用了該環境, @@ -820,7 +840,7 @@ I solemnly swear 🐺 -## 替代方案 +## 替代方案 { #alternatives } 這是一個簡單的指南,幫助你入門並教會你如何理解一切**底層**的原理。 @@ -837,7 +857,7 @@ I solemnly swear 🐺 * 確保你有一個**精確**的套件和版本集合來安裝,包括它們的依賴項,這樣你可以確保專案在生產環境中運行的狀態與開發時在你的電腦上運行的狀態完全相同,這被稱為**鎖定** * 還有很多其他功能 -## 結論 +## 結論 { #conclusion } 如果你讀過並理解了所有這些,現在**你對虛擬環境的了解已超過許多開發者**。🤓