diff --git a/docs/fr/docs/tutorial/index.md b/docs/fr/docs/tutorial/index.md
new file mode 100644
index 000000000..4dc202b33
--- /dev/null
+++ b/docs/fr/docs/tutorial/index.md
@@ -0,0 +1,80 @@
+# Tutoriel - Guide utilisateur - Introduction
+
+Ce tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape.
+
+Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour résoudre vos besoins spécifiques en matière d'API.
+
+Il est également conçu pour fonctionner comme une référence future.
+
+Vous pouvez donc revenir et voir exactement ce dont vous avez besoin.
+
+## Exécuter le code
+
+Tous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés).
+
+Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et commencez `uvicorn` avec :
+
+
+
+```console
+$ uvicorn main:app --reload
+
+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.
+```
+
+
+
+Il est **FORTEMENT encouragé** que vous écriviez ou copiez le code, l'éditiez et l'exécutiez localement.
+
+L'utiliser dans votre éditeur est ce qui vous montre vraiment les avantages de FastAPI, en voyant le peu de code que vous avez à écrire, toutes les vérifications de type, l'autocomplétion, etc.
+
+---
+
+## Installer FastAPI
+
+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 :
+
+
+
+```console
+$ pip install fastapi[all]
+
+---> 100%
+```
+
+
+
+... qui comprend également `uvicorn`, que vous pouvez utiliser comme serveur pour exécuter votre code.
+
+!!! note
+ Vous pouvez également l'installer pièce par pièce.
+
+ C'est ce que vous feriez probablement une fois que vous voudrez déployer votre application en production :
+
+ ```
+ pip install fastapi
+ ```
+
+ Installez également `uvicorn` pour qu'il fonctionne comme serveur :
+
+ ```
+ pip install uvicorn
+ ```
+
+ Et la même chose pour chacune des dépendances facultatives que vous voulez utiliser.
+
+## Guide utilisateur avancé
+
+Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**.
+
+Le **Guide d'utilisation avancé**, qui s'appuie sur cette base, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
+
+Mais vous devez d'abord lire le **Tutoriel - Guide d'utilisation** (ce que vous êtes en train de lire en ce moment).
+
+Il est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide d'utilisation**, puis l'étendre de différentes manières, en fonction de vos besoins, en utilisant certaines des idées supplémentaires du **Guide d'utilisation avancé**.
diff --git a/docs/fr/docs/tutorial/query-params-str-validations.md b/docs/fr/docs/tutorial/query-params-str-validations.md
new file mode 100644
index 000000000..f5248fe8b
--- /dev/null
+++ b/docs/fr/docs/tutorial/query-params-str-validations.md
@@ -0,0 +1,305 @@
+# Paramètres de requête et validations de chaînes de caractères
+
+**FastAPI** vous permet de déclarer des informations et des validateurs additionnels pour vos paramètres de requêtes.
+
+Commençons avec cette application pour exemple :
+
+```Python hl_lines="9"
+{!../../../docs_src/query_params_str_validations/tutorial001.py!}
+```
+
+Le paramètre de requête `q` a pour type `Union[str, None]` (ou `str | None` en Python 3.10), signifiant qu'il est de type `str` mais pourrait aussi être égal à `None`, et bien sûr, la valeur par défaut est `None`, donc **FastAPI** saura qu'il n'est pas requis.
+
+!!! note
+ **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.
+
+## Validation additionnelle
+
+Nous allons imposer que bien que `q` soit un paramètre optionnel, dès qu'il est fourni, **sa longueur n'excède pas 50 caractères**.
+
+## Importer `Query`
+
+Pour cela, importez d'abord `Query` depuis `fastapi` :
+
+```Python hl_lines="3"
+{!../../../docs_src/query_params_str_validations/tutorial002.py!}
+```
+
+## Utiliser `Query` comme valeur par défaut
+
+Construisez ensuite la valeur par défaut de votre paramètre avec `Query`, en choisissant 50 comme `max_length` :
+
+```Python hl_lines="9"
+{!../../../docs_src/query_params_str_validations/tutorial002.py!}
+```
+
+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.
+
+Donc :
+
+```Python
+q: Union[str, None] = Query(default=None)
+```
+
+... rend le paramètre optionnel, et est donc équivalent à :
+
+```Python
+q: Union[str, None] = None
+```
+
+Mais déclare explicitement `q` comme étant un paramètre de requête.
+
+!!! info
+ Gardez à l'esprit que la partie la plus importante pour rendre un paramètre optionnel est :
+
+ ```Python
+ = None
+ ```
+
+ ou :
+
+ ```Python
+ = Query(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.
+
+Ensuite, nous pouvons passer d'autres paramètres à `Query`. Dans cet exemple, le paramètre `max_length` qui s'applique aux chaînes de caractères :
+
+```Python
+q: Union[str, None] = Query(default=None, max_length=50)
+```
+
+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*.
+
+## Rajouter plus de validation
+
+Vous pouvez aussi rajouter un second paramètre `min_length` :
+
+```Python hl_lines="9"
+{!../../../docs_src/query_params_str_validations/tutorial003.py!}
+```
+
+## Ajouter des validations par expressions régulières
+
+On peut définir une
expression régulière à laquelle le paramètre doit correspondre :
+
+```Python hl_lines="10"
+{!../../../docs_src/query_params_str_validations/tutorial004.py!}
+```
+
+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"` :
+
+```Python hl_lines="7"
+{!../../../docs_src/query_params_str_validations/tutorial005.py!}
+```
+
+!!! note "Rappel"
+ Avoir une valeur par défaut rend le paramètre optionnel.
+
+## Rendre ce paramètre requis
+
+Quand on ne déclare ni validation, ni métadonnée, on peut rendre le paramètre `q` requis en ne lui déclarant juste aucune valeur par défaut :
+
+```Python
+q: str
+```
+
+à la place de :
+
+```Python
+q: Union[str, None] = None
+```
+
+Mais maintenant, on déclare `q` avec `Query`, comme ceci :
+
+```Python
+q: Union[str, None] = Query(default=None, min_length=3)
+```
+
+Donc pour déclarer une valeur comme requise tout en utilisant `Query`, il faut utiliser `...` comme premier argument :
+
+```Python hl_lines="7"
+{!../../../docs_src/query_params_str_validations/tutorial006.py!}
+```
+
+!!! info
+ Si vous n'avez jamais vu ce `...` auparavant : c'est une des constantes natives de Python
appelée "Ellipsis".
+
+Cela indiquera à **FastAPI** que la présence de ce paramètre est obligatoire.
+
+## Liste de paramètres / valeurs multiples via Query
+
+Quand on définit un paramètre de requête explicitement avec `Query` on peut aussi déclarer qu'il reçoit une liste de valeur, ou des "valeurs multiples".
+
+Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans une URL, on écrit :
+
+```Python hl_lines="9"
+{!../../../docs_src/query_params_str_validations/tutorial011.py!}
+```
+
+Ce qui fait qu'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`.
+
+Donc la réponse de cette URL serait :
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+!!! 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.
+
+La documentation sera donc mise à jour automatiquement pour autoriser plusieurs valeurs :
+
+

+
+### Combiner liste de paramètres et valeurs par défaut
+
+Et l'on peut aussi définir une liste de valeurs par défaut si aucune n'est fournie :
+
+```Python hl_lines="9"
+{!../../../docs_src/query_params_str_validations/tutorial012.py!}
+```
+
+Si vous allez à :
+
+```
+http://localhost:8000/items/
+```
+
+la valeur par défaut de `q` sera : `["foo", "bar"]`
+
+et la réponse sera :
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+#### Utiliser `list`
+
+Il est aussi possible d'utiliser directement `list` plutôt que `List[str]` :
+
+```Python hl_lines="7"
+{!../../../docs_src/query_params_str_validations/tutorial013.py!}
+```
+
+!!! note
+ Dans ce cas-là, **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.
+
+## Déclarer des métadonnées supplémentaires
+
+On peut aussi ajouter plus d'informations sur le 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.
+
+!!! note
+ Gardez en tête que les outils externes utilisés ne supportent pas forcément tous parfaitement OpenAPI.
+
+ Il se peut donc que certains d'entre eux n'utilisent pas toutes les métadonnées que vous avez déclarées pour le moment, bien que dans la plupart des cas, les fonctionnalités manquantes ont prévu d'être implémentées.
+
+Vous pouvez ajouter un `title` :
+
+```Python hl_lines="10"
+{!../../../docs_src/query_params_str_validations/tutorial007.py!}
+```
+
+Et une `description` :
+
+```Python hl_lines="13"
+{!../../../docs_src/query_params_str_validations/tutorial008.py!}
+```
+
+## Alias de paramètres
+
+Imaginez que vous vouliez que votre paramètre se nomme `item-query`.
+
+Comme dans la requête :
+
+```
+http://127.0.0.1:8000/items/?item-query=foobaritems
+```
+
+Mais `item-query` n'est pas un nom de variable valide en Python.
+
+Le nom le plus proche serait `item_query`.
+
+Mais vous avez vraiment envie 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 :
+
+```Python hl_lines="9"
+{!../../../docs_src/query_params_str_validations/tutorial009.py!}
+```
+
+## Déprécier des paramètres
+
+Disons que vous ne vouliez plus utiliser ce paramètre désormais.
+
+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é.
+
+On utilise alors l'argument `deprecated=True` de `Query` :
+
+```Python hl_lines="18"
+{!../../../docs_src/query_params_str_validations/tutorial010.py!}
+```
+
+La documentation le présentera comme il suit :
+
+

+
+## Pour résumer
+
+Il est possible d'ajouter des validateurs et métadonnées pour vos paramètres.
+
+Validateurs et métadonnées génériques:
+
+* `alias`
+* `title`
+* `description`
+* `deprecated`
+
+Validateurs spécifiques aux chaînes de caractères :
+
+* `min_length`
+* `max_length`
+* `regex`
+
+Parmi ces exemples, vous avez pu voir comment déclarer des validateurs pour les chaînes de caractères.
+
+Dans les prochains chapitres, vous verrez comment déclarer des validateurs 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 7bf3b9e79..962135f63 100644
--- a/docs/fr/docs/tutorial/query-params.md
+++ b/docs/fr/docs/tutorial/query-params.md
@@ -75,7 +75,7 @@ Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut.
!!! note
**FastAPI** saura que `q` est optionnel grâce au `=None`.
- 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 editeur de texte pour détecter des erreurs dans votre code.
+ 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.
## Conversion des types des paramètres de requête
diff --git a/docs/ja/docs/deployment/concepts.md b/docs/ja/docs/deployment/concepts.md
new file mode 100644
index 000000000..38cbca219
--- /dev/null
+++ b/docs/ja/docs/deployment/concepts.md
@@ -0,0 +1,323 @@
+# デプロイメントのコンセプト
+
+**FastAPI**を用いたアプリケーションをデプロイするとき、もしくはどのようなタイプのWeb APIであっても、おそらく気になるコンセプトがいくつかあります。
+
+それらを活用することでアプリケーションを**デプロイするための最適な方法**を見つけることができます。
+
+重要なコンセプトのいくつかを紹介します:
+
+* セキュリティ - HTTPS
+* 起動時の実行
+* 再起動
+* レプリケーション(実行中のプロセス数)
+* メモリー
+* 開始前の事前のステップ
+
+これらが**デプロイメント**にどのような影響を与えるかを見ていきましょう。
+
+最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**(例えばリモートサーバー/仮想マシン)を可能な限り効率的に使用することです。🚀
+
+この章では前述した**コンセプト**についてそれぞれ説明します。
+
+この説明を通して、普段とは非常に異なる環境や存在しないであろう**将来の**環境に対し、デプロイの方法を決める上で必要な**直感**を与えてくれることを願っています。
+
+これらのコンセプトを意識することにより、**あなた自身のAPI**をデプロイするための最適な方法を**評価**し、**設計**することができるようになるでしょう。
+
+次の章では、FastAPIアプリケーションをデプロイするための**具体的なレシピ**を紹介します。
+
+しかし、今はこれらの重要な**コンセプトに基づくアイデア**を確認しましょう。これらのコンセプトは、他のどのタイプのWeb APIにも当てはまります。💡
+
+## セキュリティ - HTTPS
+
+
+[前チャプターのHTTPSについて](./https.md){.internal-link target=_blank}では、HTTPSがどのようにAPIを暗号化するのかについて学びました。
+
+通常、アプリケーションサーバにとって**外部の**コンポーネントである**TLS Termination Proxy**によって提供されることが一般的です。このプロキシは通信の暗号化を担当します。
+
+さらにセキュアな通信において、HTTPS証明書の定期的な更新を行いますが、これはTLS Termination Proxyと同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。
+
+### HTTPS 用ツールの例
+TLS Termination Proxyとして使用できるツールには以下のようなものがあります:
+
+* Traefik
+ * 証明書の更新を自動的に処理 ✨
+* Caddy
+ * 証明書の更新を自動的に処理 ✨
+* Nginx
+ * 証明書更新のためにCertbotのような外部コンポーネントを使用
+* HAProxy
+ * 証明書更新のためにCertbotのような外部コンポーネントを使用
+* Nginx のような Ingress Controller を持つ Kubernetes
+ * 証明書の更新に cert-manager のような外部コンポーネントを使用
+* クラウド・プロバイダーがサービスの一部として内部的に処理(下記を参照👇)
+
+もう1つの選択肢は、HTTPSのセットアップを含んだより多くの作業を行う**クラウド・サービス**を利用することです。 このサービスには制限があったり、料金が高くなったりする可能性があります。しかしその場合、TLS Termination Proxyを自分でセットアップする必要はないです。
+
+次の章で具体例をいくつか紹介します。
+
+---
+
+次に考慮すべきコンセプトは、実際のAPIを実行するプログラム(例:Uvicorn)に関連するものすべてです。
+
+## プログラム と プロセス
+
+私たちは「**プロセス**」という言葉についてたくさん話すので、その意味や「**プログラム**」という言葉との違いを明確にしておくと便利です。
+
+### プログラムとは何か
+
+**プログラム**という言葉は、一般的にいろいろなものを表現するのに使われます:
+
+* プログラマが書く**コード**、**Pythonファイル**
+* OSによって実行することができるファイル(例: `python`, `python.exe` or `uvicorn`)
+* OS上で**実行**している間、CPUを使用し、メモリ上に何かを保存する特定のプログラム(**プロセス**とも呼ばれる)
+
+### プロセスとは何か
+
+**プロセス**という言葉は通常、より具体的な意味で使われ、OSで実行されているものだけを指します(先ほどの最後の説明のように):
+
+* OS上で**実行**している特定のプログラム
+ * これはファイルやコードを指すのではなく、OSによって**実行**され、管理されているものを指します。
+* どんなプログラムやコードも、それが**実行されているときにだけ機能**します。つまり、**プロセスとして実行されているときだけ**です。
+* プロセスは、ユーザーにあるいはOSによって、 **終了**(あるいは "kill")させることができます。その時点で、プロセスは実行/実行されることを停止し、それ以降は**何もできなくなります**。
+* コンピュータで実行されている各アプリケーションは、実行中のプログラムや各ウィンドウなど、その背後にいくつかのプロセスを持っています。そして通常、コンピュータが起動している間、**多くのプロセスが**同時に実行されています。
+* **同じプログラム**の**複数のプロセス**が同時に実行されていることがあります。
+
+OSの「タスク・マネージャー」や「システム・モニター」(または同様のツール)を確認すれば、これらのプロセスの多くが実行されているの見ることができるでしょう。
+
+例えば、同じブラウザプログラム(Firefox、Chrome、Edgeなど)を実行しているプロセスが複数あることがわかります。通常、1つのタブにつき1つのプロセスが実行され、さらに他のプロセスも実行されます。
+
+

+
+---
+
+さて、**プロセス**と**プログラム**という用語の違いを確認したところで、デプロイメントについて話を続けます。
+
+## 起動時の実行
+
+ほとんどの場合、Web APIを作成するときは、クライアントがいつでもアクセスできるように、**常に**中断されることなく**実行される**ことを望みます。もちろん、特定の状況でのみ実行させたい特別な理由がある場合は別ですが、その時間のほとんどは、常に実行され、**利用可能**であることを望みます。
+
+### リモートサーバー上での実行
+
+リモートサーバー(クラウドサーバー、仮想マシンなど)をセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、Uvicorn(または同様のもの)を手動で実行することです。 この方法は**開発中**には役に立つと思われます。
+
+しかし、サーバーへの接続が切れた場合、**実行中のプロセス**はおそらくダウンしてしまうでしょう。
+
+そしてサーバーが再起動された場合(アップデートやクラウドプロバイダーからのマイグレーションの後など)、おそらくあなたはそれに**気づかないでしょう**。そのため、プロセスを手動で再起動しなければならないことすら気づかないでしょう。つまり、APIはダウンしたままなのです。😱
+
+### 起動時に自動的に実行
+
+一般的に、サーバープログラム(Uvicornなど)はサーバー起動時に自動的に開始され、**人の介入**を必要とせずに、APIと一緒にプロセスが常に実行されるようにしたいと思われます(UvicornがFastAPIアプリを実行するなど)。
+
+### 別のプログラムの用意
+
+これを実現するために、通常は**別のプログラム**を用意し、起動時にアプリケーションが実行されるようにします。そして多くの場合、他のコンポーネントやアプリケーション、例えばデータベースも実行されるようにします。
+
+### 起動時に実行するツールの例
+
+実行するツールの例をいくつか挙げます:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Swarm モードによる Docker
+* Systemd
+* Supervisor
+* クラウドプロバイダーがサービスの一部として内部的に処理
+* そのほか...
+
+次の章で、より具体的な例を挙げていきます。
+
+## 再起動
+
+起動時にアプリケーションが実行されることを確認するのと同様に、失敗後にアプリケーションが**再起動**されることも確認したいと思われます。
+
+### 我々は間違いを犯す
+
+私たち人間は常に**間違い**を犯します。ソフトウェアには、ほとんど常に**バグ**があらゆる箇所に隠されています。🐛
+
+### 小さなエラーは自動的に処理される
+
+FastAPIでWeb APIを構築する際に、コードにエラーがある場合、FastAPIは通常、エラーを引き起こした単一のリクエストにエラーを含めます。🛡
+
+クライアントはそのリクエストに対して**500 Internal Server Error**を受け取りますが、アプリケーションは完全にクラッシュするのではなく、次のリクエストのために動作を続けます。
+
+### 重大なエラー - クラッシュ
+
+しかしながら、**アプリケーション全体をクラッシュさせるようなコードを書いて**UvicornとPythonをクラッシュさせるようなケースもあるかもしれません。💥
+
+それでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*パスオペレーション*については、**実行し続けたい**はずです。
+
+### クラッシュ後の再起動
+
+しかし、実行中の**プロセス**をクラッシュさせるような本当にひどいエラーの場合、少なくとも2〜3回ほどプロセスを**再起動**させる外部コンポーネントが必要でしょう。
+
+!!! tip
+ ...とはいえ、アプリケーション全体が**すぐにクラッシュする**のであれば、いつまでも再起動し続けるのは意味がないでしょう。しかし、その場合はおそらく開発中か少なくともデプロイ直後に気づくと思われます。
+
+ そこで、**将来**クラッシュする可能性があり、それでも再スタートさせることに意味があるような、主なケースに焦点を当ててみます。
+
+あなたはおそらく**外部コンポーネント**がアプリケーションの再起動を担当することを望むと考えます。 なぜなら、その時点でUvicornとPythonを使った同じアプリケーションはすでにクラッシュしており、同じアプリケーションの同じコードに対して何もできないためです。
+
+### 自動的に再起動するツールの例
+
+ほとんどの場合、前述した**起動時にプログラムを実行する**ために使用されるツールは、自動で**再起動**することにも利用されます。
+
+例えば、次のようなものがあります:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Swarm モードによる Docker
+* Systemd
+* Supervisor
+* クラウドプロバイダーがサービスの一部として内部的に処理
+* そのほか...
+
+## レプリケーション - プロセスとメモリー
+
+FastAPI アプリケーションでは、Uvicorn のようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。
+
+しかし、多くの場合、複数のワーカー・プロセスを同時に実行したいと考えるでしょう。
+
+### 複数のプロセス - Worker
+
+クライアントの数が単一のプロセスで処理できる数を超えており(たとえば仮想マシンがそれほど大きくない場合)、かつサーバーの CPU に**複数のコア**がある場合、同じアプリケーションで同時に**複数のプロセス**を実行させ、すべてのリクエストを分散させることができます。
+
+同じAPIプログラムの**複数のプロセス**を実行する場合、それらは一般的に**Worker/ワーカー**と呼ばれます。
+
+### ワーカー・プロセス と ポート
+
+
+[HTTPSについて](./https.md){.internal-link target=_blank}のドキュメントで、1つのサーバーで1つのポートとIPアドレスの組み合わせでリッスンできるのは1つのプロセスだけであることを覚えていますでしょうか?
+
+これはいまだに同じです。
+
+そのため、**複数のプロセス**を同時に持つには**ポートでリッスンしている単一のプロセス**が必要であり、それが何らかの方法で各ワーカー・プロセスに通信を送信することが求められます。
+
+### プロセスあたりのメモリー
+
+さて、プログラムがメモリにロードする際には、例えば機械学習モデルや大きなファイルの内容を変数に入れたりする場合では、**サーバーのメモリ(RAM)**を少し消費します。
+
+そして複数のプロセスは通常、**メモリを共有しません**。これは、実行中の各プロセスがそれぞれ独自の変数やメモリ等を持っていることを意味します。つまり、コード内で大量のメモリを消費している場合、**各プロセス**は同等の量のメモリを消費することになります。
+
+### サーバーメモリー
+
+例えば、あなたのコードが **1GBのサイズの機械学習モデル**をロードする場合、APIで1つのプロセスを実行すると、少なくとも1GBのRAMを消費します。
+
+また、**4つのプロセス**(4つのワーカー)を起動すると、それぞれが1GBのRAMを消費します。つまり、合計でAPIは**4GBのRAM**を消費することになります。
+
+リモートサーバーや仮想マシンのRAMが3GBしかない場合、4GB以上のRAMをロードしようとすると問題が発生します。🚨
+
+### 複数プロセス - 例
+
+この例では、2つの**ワーカー・プロセス**を起動し制御する**マネージャー・ プロセス**があります。
+
+このマネージャー・ プロセスは、おそらくIPの**ポート**でリッスンしているものです。そして、すべての通信をワーカー・プロセスに転送します。
+
+これらのワーカー・プロセスは、アプリケーションを実行するものであり、**リクエスト**を受けて**レスポンス**を返すための主要な計算を行い、あなたが変数に入れたものは何でもRAMにロードします。
+
+

+
+そしてもちろん、同じマシンでは、あなたのアプリケーションとは別に、**他のプロセス**も実行されているでしょう。
+
+興味深いことに、各プロセスが使用する**CPU**の割合は時間とともに大きく**変動**する可能性がありますが、**メモリ(RAM)**は通常、多かれ少なかれ**安定**します。
+
+毎回同程度の計算を行うAPIがあり、多くのクライアントがいるのであれば、**CPU使用率**もおそらく**安定**するでしょう(常に急激に上下するのではなく)。
+
+### レプリケーション・ツールと戦略の例
+
+これを実現するにはいくつかのアプローチがありますが、具体的な戦略については次の章(Dockerやコンテナの章など)で詳しく説明します。
+
+考慮すべき主な制約は、**パブリックIP**の**ポート**を処理する**単一の**コンポーネントが存在しなければならないということです。
+
+そして、レプリケートされた**プロセス/ワーカー**に通信を**送信**する方法を持つ必要があります。
+
+考えられる組み合わせと戦略をいくつか紹介します:
+
+* **Gunicorn**が**Uvicornワーカー**を管理
+ * Gunicornは**IP**と**ポート**をリッスンする**プロセスマネージャ**で、レプリケーションは**複数のUvicornワーカー・プロセス**を持つことによって行われる。
+* **Uvicorn**が**Uvicornワーカー**を管理
+ * 1つのUvicornの**プロセスマネージャー**が**IP**と**ポート**をリッスンし、**複数のUvicornワーカー・プロセス**を起動する。
+* **Kubernetes**やその他の分散**コンテナ・システム**
+ * **Kubernetes**レイヤーの何かが**IP**と**ポート**をリッスンする。レプリケーションは、**複数のコンテナ**にそれぞれ**1つのUvicornプロセス**を実行させることで行われる。
+* **クラウド・サービス**によるレプリケーション
+ * クラウド・サービスはおそらく**あなたのためにレプリケーションを処理**します。**実行するプロセス**や使用する**コンテナイメージ**を定義できるかもしれませんが、いずれにせよ、それはおそらく**単一のUvicornプロセス**であり、クラウドサービスはそのレプリケーションを担当するでしょう。
+
+!!! tip
+ これらの**コンテナ**やDockerそしてKubernetesに関する項目が、まだあまり意味をなしていなくても心配しないでください。
+
+
+ コンテナ・イメージ、Docker、Kubernetesなどについては、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}.
+
+## 開始前の事前のステップ
+
+アプリケーションを**開始する前**に、いくつかのステップを実行したい場合が多くあります。
+
+例えば、**データベース・マイグレーション** を実行したいかもしれません。
+
+しかしほとんどの場合、これらの手順を**1度**に実行したいと考えるでしょう。
+
+そのため、アプリケーションを開始する前の**事前のステップ**を実行する**単一のプロセス**を用意したいと思われます。
+
+そして、それらの事前のステップを実行しているのが単一のプロセスであることを確認する必要があります。このことはその後アプリケーション自体のために**複数のプロセス**(複数のワーカー)を起動した場合も同様です。
+
+これらのステップが**複数のプロセス**によって実行された場合、**並列**に実行されることによって作業が**重複**することになります。そして、もしそのステップがデータベースのマイグレーションのような繊細なものであった場合、互いに競合を引き起こす可能性があります。
+
+もちろん、事前のステップを何度も実行しても問題がない場合もあり、その際は対処がかなり楽になります。
+
+!!! tip
+ また、セットアップによっては、アプリケーションを開始する前の**事前のステップ**が必要ない場合もあることを覚えておいてください。
+
+ その場合は、このようなことを心配する必要はないです。🤷
+
+### 事前ステップの戦略例
+
+これは**システムを**デプロイする方法に**大きく依存**するだろうし、おそらくプログラムの起動方法や再起動の処理などにも関係してくるでしょう。
+
+考えられるアイデアをいくつか挙げてみます:
+
+* アプリコンテナの前に実行されるKubernetesのInitコンテナ
+* 事前のステップを実行し、アプリケーションを起動するbashスクリプト
+ * 利用するbashスクリプトを起動/再起動したり、エラーを検出したりする方法は以前として必要になるでしょう。
+
+!!! tip
+
+ コンテナを使った具体的な例については、次の章で紹介します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}.
+
+## リソースの利用
+
+あなたのサーバーは**リソース**であり、プログラムを実行しCPUの計算時間や利用可能なRAMメモリを消費または**利用**することができます。
+
+システムリソースをどれくらい消費/利用したいですか? 「少ない方が良い」と考えるのは簡単かもしれないですが、実際には、**クラッシュせずに可能な限り**最大限に活用したいでしょう。
+
+3台のサーバーにお金を払っているにも関わらず、そのRAMとCPUを少ししか使っていないとしたら、おそらく**お金を無駄にしている** 💸、おそらく**サーバーの電力を無駄にしている** 🌎ことになるでしょう。
+
+その場合は、サーバーを2台だけにして、そのリソース(CPU、メモリ、ディスク、ネットワーク帯域幅など)をより高い割合で使用する方がよいでしょう。
+
+一方、2台のサーバーがあり、そのCPUとRAMの**100%を使用している**場合、ある時点で1つのプロセスがより多くのメモリを要求し、サーバーはディスクを「メモリ」として使用しないといけません。(何千倍も遅くなる可能性があります。)
+もしくは**クラッシュ**することもあれば、あるいはあるプロセスが何らかの計算をする必要があり、そしてCPUが再び空くまで待たなければならないかもしれません。
+
+この場合、**1つ余分なサーバー**を用意し、その上でいくつかのプロセスを実行し、すべてのサーバーが**十分なRAMとCPU時間を持つようにする**のがよいでしょう。
+
+また、何らかの理由でAPIの利用が急増する可能性もあります。もしかしたらそれが流行ったのかもしれないし、他のサービスやボットが使い始めたのかもしれないです。そのような場合に備えて、余分なリソースを用意しておくと安心でしょう。
+
+例えば、リソース使用率の**50%から90%の範囲**で**任意の数字**をターゲットとすることができます。
+
+重要なのは、デプロイメントを微調整するためにターゲットを設定し測定することが、おそらく使用したい主要な要素であることです。
+
+`htop`のような単純なツールを使って、サーバーで使用されているCPUやRAM、あるいは各プロセスで使用されている量を見ることができます。あるいは、より複雑な監視ツールを使って、サーバに分散して使用することもできます。
+
+## まとめ
+
+アプリケーションのデプロイ方法を決定する際に、考慮すべきであろう主要なコンセプトのいくつかを紹介していきました:
+
+* セキュリティ - HTTPS
+* 起動時の実行
+* 再起動
+* レプリケーション(実行中のプロセス数)
+* メモリー
+* 開始前の事前ステップ
+
+これらの考え方とその適用方法を理解することで、デプロイメントを設定したり調整したりする際に必要な直感的な判断ができるようになるはずです。🤓
+
+次のセクションでは、あなたが取り得る戦略について、より具体的な例を挙げます。🚀
diff --git a/docs/ja/docs/deployment/deta.md b/docs/ja/docs/deployment/deta.md
deleted file mode 100644
index 723f169a0..000000000
--- a/docs/ja/docs/deployment/deta.md
+++ /dev/null
@@ -1,240 +0,0 @@
-# Deta にデプロイ
-
-このセクションでは、**FastAPI** アプリケーションを
Deta の無料プランを利用して、簡単にデプロイする方法を学習します。🎁
-
-所要時間は約**10分**です。
-
-!!! info "備考"
-
Deta は **FastAPI** のスポンサーです。🎉
-
-## ベーシックな **FastAPI** アプリ
-
-* アプリのためのディレクトリ (例えば `./fastapideta/`) を作成し、その中に入ってください。
-
-### FastAPI のコード
-
-* 以下の `main.py` ファイルを作成してください:
-
-```Python
-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):
- return {"item_id": item_id}
-```
-
-### Requirements
-
-では、同じディレクトリに以下の `requirements.txt` ファイルを作成してください:
-
-```text
-fastapi
-```
-
-!!! tip "豆知識"
- アプリのローカルテストのために Uvicorn をインストールしたくなるかもしれませんが、Deta へのデプロイには不要です。
-
-### ディレクトリ構造
-
-以下の2つのファイルと1つの `./fastapideta/` ディレクトリがあるはずです:
-
-```
-.
-└── main.py
-└── requirements.txt
-```
-
-## Detaの無料アカウントの作成
-
-それでは、
Detaの無料アカウントを作成しましょう。必要なものはメールアドレスとパスワードだけです。
-
-クレジットカードさえ必要ありません。
-
-## CLIのインストール
-
-アカウントを取得したら、Deta
CLI をインストールしてください:
-
-=== "Linux, macOS"
-
-
-
- ```console
- $ curl -fsSL https://get.deta.dev/cli.sh | sh
- ```
-
-
-
-=== "Windows PowerShell"
-
-
-
- ```console
- $ iwr https://get.deta.dev/cli.ps1 -useb | iex
- ```
-
-
-
-インストールしたら、インストールした CLI を有効にするために新たなターミナルを開いてください。
-
-新たなターミナル上で、正しくインストールされたか確認します:
-
-
-
-```console
-$ deta --help
-
-Deta command line interface for managing deta micros.
-Complete documentation available at https://docs.deta.sh
-
-Usage:
- deta [flags]
- deta [command]
-
-Available Commands:
- auth Change auth settings for a deta micro
-
-...
-```
-
-
-
-!!! tip "豆知識"
- CLI のインストールに問題が発生した場合は、
Deta 公式ドキュメントを参照してください。
-
-## CLIでログイン
-
-CLI から Deta にログインしてみましょう:
-
-
-
-```console
-$ deta login
-
-Please, log in from the web page. Waiting..
-Logged in successfully.
-```
-
-
-
-自動的にウェブブラウザが開いて、認証処理が行われます。
-
-## Deta でデプロイ
-
-次に、アプリケーションを Deta CLIでデプロイしましょう:
-
-
-
-```console
-$ deta new
-
-Successfully created a new micro
-
-// Notice the "endpoint" 🔍
-
-{
- "name": "fastapideta",
- "runtime": "python3.7",
- "endpoint": "https://qltnci.deta.dev",
- "visor": "enabled",
- "http_auth": "enabled"
-}
-
-Adding dependencies...
-
-
----> 100%
-
-
-Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
-```
-
-
-
-次のようなJSONメッセージが表示されます:
-
-```JSON hl_lines="4"
-{
- "name": "fastapideta",
- "runtime": "python3.7",
- "endpoint": "https://qltnci.deta.dev",
- "visor": "enabled",
- "http_auth": "enabled"
-}
-```
-
-!!! tip "豆知識"
- あなたのデプロイでは異なる `"endpoint"` URLが表示されるでしょう。
-
-## 確認
-
-それでは、`endpoint` URLをブラウザで開いてみましょう。上記の例では `https://qltnci.deta.dev` ですが、あなたのURLは異なるはずです。
-
-FastAPIアプリから返ってきたJSONレスポンスが表示されます:
-
-```JSON
-{
- "Hello": "World"
-}
-```
-
-そして `/docs` へ移動してください。上記の例では、`https://qltnci.deta.dev/docs` です。
-
-次のようなドキュメントが表示されます:
-
-

-
-## パブリックアクセスの有効化
-
-デフォルトでは、Deta はクッキーを用いてアカウントの認証を行います。
-
-しかし、準備が整えば、以下の様に公開できます:
-
-
-
-```console
-$ deta auth disable
-
-Successfully disabled http auth
-```
-
-
-
-ここで、URLを共有するとAPIにアクセスできるようになります。🚀
-
-## HTTPS
-
-おめでとうございます!あなたの FastAPI アプリが Deta へデプロイされました!🎉 🍰
-
-また、DetaがHTTPSを正しく処理するため、その処理を行う必要がなく、クライアントは暗号化された安全な通信が利用できます。✅ 🔒
-
-## Visor を確認
-
-ドキュメントUI (`https://qltnci.deta.dev/docs` のようなURLにある) は *path operation* `/items/{item_id}` へリクエストを送ることができます。
-
-ID `5` の例を示します。
-
-まず、
https://web.deta.sh へアクセスします。
-
-左側に各アプリの
「Micros」 というセクションが表示されます。
-
-また、「Details」や「Visor」タブが表示されています。「Visor」タブへ移動してください。
-
-そこでアプリに送られた直近のリクエストが調べられます。
-
-また、それらを編集してリプレイできます。
-
-

-
-## さらに詳しく知る
-
-様々な箇所で永続的にデータを保存したくなるでしょう。そのためには
Deta Base を使用できます。惜しみない **無料利用枠** もあります。
-
-詳しくは
Deta ドキュメントを参照してください。
diff --git a/docs/ja/docs/deployment/docker.md b/docs/ja/docs/deployment/docker.md
index f10312b51..ca9dedc3c 100644
--- a/docs/ja/docs/deployment/docker.md
+++ b/docs/ja/docs/deployment/docker.md
@@ -1,71 +1,157 @@
-# Dockerを使用したデプロイ
+# コンテナ内のFastAPI - Docker
-このセクションでは以下の使い方の紹介とガイドへのリンクが確認できます:
+FastAPIアプリケーションをデプロイする場合、一般的なアプローチは**Linuxコンテナ・イメージ**をビルドすることです。
-* **5分**程度で、**FastAPI** のアプリケーションを、パフォーマンスを最大限に発揮するDockerイメージ (コンテナ)にする。
-* (オプション) 開発者として必要な範囲でHTTPSを理解する。
-* **20分**程度で、自動的なHTTPS生成とともにDockerのSwarmモード クラスタをセットアップする (月5ドルのシンプルなサーバー上で)。
-* **10分**程度で、DockerのSwarmモード クラスタを使って、HTTPSなどを使用した完全な**FastAPI** アプリケーションの作成とデプロイ。
+基本的には
**Docker**を用いて行われます。生成されたコンテナ・イメージは、いくつかの方法のいずれかでデプロイできます。
-デプロイのために、
**Docker** を利用できます。セキュリティ、再現性、開発のシンプルさなどに利点があります。
+Linuxコンテナの使用には、**セキュリティ**、**反復可能性(レプリカビリティ)**、**シンプリシティ**など、いくつかの利点があります。
-Dockerを使う場合、公式のDockerイメージが利用できます:
+!!! tip
+ TODO: なぜか遷移できない
+ お急ぎで、すでにこれらの情報をご存じですか? [以下の`Dockerfile`の箇所👇](#build-a-docker-image-for-fastapi)へジャンプしてください。
-##
tiangolo/uvicorn-gunicorn-fastapi
+
+Dockerfile プレビュー 👀
-このイメージは「自動チューニング」機構を含んでいます。犠牲を払うことなく、ただコードを加えるだけで自動的に高パフォーマンスを実現できます。
+```Dockerfile
+FROM python:3.9
-ただし、環境変数や設定ファイルを使って全ての設定の変更や更新を行えます。
+WORKDIR /code
-!!! tip "豆知識"
- 全ての設定とオプションを確認するには、Dockerイメージページを開いて下さい: tiangolo/uvicorn-gunicorn-fastapi.
+COPY ./requirements.txt /code/requirements.txt
-## `Dockerfile` の作成
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
-* プロジェクトディレクトリへ移動。
-* 以下の`Dockerfile` を作成:
+COPY ./app /code/app
-```Dockerfile
-FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
+CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
-COPY ./app /app
+# If running behind a proxy like Nginx or Traefik add --proxy-headers
+# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
```
-### より大きなアプリケーション
+
-[Bigger Applications with Multiple Files](tutorial/bigger-applications.md){.internal-link target=_blank} セクションに倣う場合は、`Dockerfile` は上記の代わりに、以下の様になるかもしれません:
+## コンテナとは何か
-```Dockerfile
-FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
+コンテナ(主にLinuxコンテナ)は、同じシステム内の他のコンテナ(他のアプリケーションやコンポーネント)から隔離された状態を保ちながら、すべての依存関係や必要なファイルを含むアプリケーションをパッケージ化する非常に**軽量**な方法です。
-COPY ./app /app/app
-```
+Linuxコンテナは、ホスト(マシン、仮想マシン、クラウドサーバーなど)の同じLinuxカーネルを使用して実行されます。これは、(OS全体をエミュレートする完全な仮想マシンと比べて)非常に軽量であることを意味します。
-### Raspberry Piなどのアーキテクチャ
+このように、コンテナは**リソースをほとんど消費しません**が、プロセスを直接実行するのに匹敵する量です(仮想マシンはもっと消費します)。
-Raspberry Pi (ARMプロセッサ搭載)やそれ以外のアーキテクチャでDockerが作動している場合、(マルチアーキテクチャである) Pythonベースイメージを使って、一から`Dockerfile`を作成し、Uvicornを単体で使用できます。
+コンテナはまた、独自の**分離された**実行プロセス(通常は1つのプロセスのみ)や、ファイルシステム、ネットワークを持ちます。 このことはデプロイ、セキュリティ、開発などを簡素化させます。
-この場合、`Dockerfile` は以下の様になるかもしれません:
+## コンテナ・イメージとは何か
-```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"]
+これらの変更はそのコンテナ内にのみ存在しますが、基盤となるコンテナ・イメージには残りません(ディスクに保存されません)。
+
+コンテナイメージは **プログラム** ファイルやその内容、例えば `python` と `main.py` ファイルに匹敵します。
+
+そして、**コンテナ**自体は(**コンテナイメージ**とは対照的に)イメージをもとにした実際の実行中のインスタンスであり、**プロセス**に匹敵します。
+
+実際、コンテナが実行されているのは、**プロセスが実行されている**ときだけです(通常は単一のプロセスだけです)。 コンテナ内で実行中のプロセスがない場合、コンテナは停止します。
+
+## コンテナ・イメージ
+
+Dockerは、**コンテナ・イメージ**と**コンテナ**を作成・管理するための主要なツールの1つです。
+
+そして、DockerにはDockerイメージ(コンテナ)を共有する
Docker Hubというものがあります。
+
+Docker Hubは 多くのツールや環境、データベース、アプリケーションに対応している予め作成された**公式のコンテナ・イメージ**をパブリックに提供しています。
+
+例えば、公式イメージの1つに
Python Imageがあります。
+
+その他にも、データベースなどさまざまなイメージがあります:
+
+*
PostgreSQL
+*
MySQL
+*
MongoDB
+*
Redis, etc.
+
+予め作成されたコンテナ・イメージを使用することで、異なるツールを**組み合わせて**使用することが非常に簡単になります。例えば、新しいデータベースを試す場合に特に便利です。ほとんどの場合、**公式イメージ**を使い、環境変数で設定するだけで良いです。
+
+そうすれば多くの場合、コンテナとDockerについて学び、その知識をさまざまなツールやコンポーネントによって再利用することができます。
+
+つまり、データベース、Pythonアプリケーション、Reactフロントエンド・アプリケーションを備えたウェブ・サーバーなど、さまざまなものを**複数のコンテナ**で実行し、それらを内部ネットワーク経由で接続します。
+
+すべてのコンテナ管理システム(DockerやKubernetesなど)には、こうしたネットワーキング機能が統合されています。
+
+## コンテナとプロセス
+
+通常、**コンテナ・イメージ**はそのメタデータに**コンテナ**の起動時に実行されるデフォルトのプログラムまたはコマンドと、そのプログラムに渡されるパラメータを含みます。コマンドラインでの操作とよく似ています。
+
+**コンテナ**が起動されると、そのコマンド/プログラムが実行されます(ただし、別のコマンド/プログラムをオーバーライドして実行させることもできます)。
+
+コンテナは、**メイン・プロセス**(コマンドまたはプログラム)が実行されている限り実行されます。
+
+コンテナは通常**1つのプロセス**を持ちますが、メイン・プロセスからサブ・プロセスを起動することも可能で、そうすれば同じコンテナ内に**複数のプロセス**を持つことになります。
+
+しかし、**少なくとも1つの実行中のプロセス**がなければ、実行中のコンテナを持つことはできないです。メイン・プロセスが停止すれば、コンテナも停止します。
+
+## Build a Docker Image for FastAPI
+
+ということで、何か作りましょう!🚀
+
+FastAPI用の**Dockerイメージ**を、**公式Python**イメージに基づいて**ゼロから**ビルドする方法をお見せします。
+
+これは**ほとんどの場合**にやりたいことです。例えば:
+
+* **Kubernetes**または同様のツールを使用する場合
+* **Raspberry Pi**で実行する場合
+* コンテナ・イメージを実行してくれるクラウド・サービスなどを利用する場合
+
+### パッケージ要件(package requirements)
+
+アプリケーションの**パッケージ要件**は通常、何らかのファイルに記述されているはずです。
+
+パッケージ要件は主に**インストール**するために使用するツールに依存するでしょう。
+
+最も一般的な方法は、`requirements.txt` ファイルにパッケージ名とそのバージョンを 1 行ずつ書くことです。
+
+もちろん、[FastAPI バージョンについて](./versions.md){.internal-link target=_blank}で読んだのと同じアイデアを使用して、バージョンの範囲を設定します。
+
+例えば、`requirements.txt` は次のようになります:
+
+```
+fastapi>=0.68.0,<0.69.0
+pydantic>=1.8.0,<2.0.0
+uvicorn>=0.15.0,<0.16.0
```
-## **FastAPI** コードの作成
+そして通常、例えば `pip` を使ってこれらのパッケージの依存関係をインストールします:
+
+
-* `app` ディレクトリを作成し、移動。
-* 以下の`main.py` ファイルを作成:
+```console
+$ pip install -r requirements.txt
+---> 100%
+Successfully installed fastapi pydantic uvicorn
+```
+
+
+
+!!! info
+ パッケージの依存関係を定義しインストールするためのフォーマットやツールは他にもあります。
+
+ Poetryを使った例は、後述するセクションでご紹介します。👇
+
+### **FastAPI**コードを作成する
+
+* `app` ディレクトリを作成し、その中に入ります
+* 空のファイル `__init__.py` を作成します
+* `main.py` ファイルを作成します:
```Python
-from typing import Optional
+from typing import Union
from fastapi import FastAPI
@@ -78,23 +164,136 @@ def read_root():
@app.get("/items/{item_id}")
-def read_item(item_id: int, q: Optional[str] = None):
+def read_item(item_id: int, q: Union[str, None] = None):
return {"item_id": item_id, "q": q}
```
-* ここでは、以下の様なディレクトリ構造になっているはずです:
+### Dockerfile
+
+同じプロジェクト・ディレクトリに`Dockerfile`というファイルを作成します:
+
+```{ .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 ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+```
+
+1. 公式のPythonベースイメージから始めます
+
+2. 現在の作業ディレクトリを `/code` に設定します
+
+ ここに `requirements.txt` ファイルと `app` ディレクトリを置きます。
+
+3. 要件が書かれたファイルを `/code` ディレクトリにコピーします
+
+ 残りのコードではなく、最初に必要なファイルだけをコピーしてください。
+
+ このファイルは**頻繁には変更されない**ので、Dockerはこのステップではそれを検知し**キャッシュ**を使用し、次のステップでもキャッシュを有効にします。
+
+4. 要件ファイルにあるパッケージの依存関係をインストールします
+ `--no-cache-dir` オプションはダウンロードしたパッケージをローカルに保存しないように `pip` に指示します。これは、同じパッケージをインストールするために `pip` を再度実行する場合にのみ有効ですが、コンテナで作業する場合はそうではないです。
+
+ !!! note
+ `--no-cache-dir`は`pip`に関連しているだけで、Dockerやコンテナとは何の関係もないです。
+
+ `--upgrade` オプションは、パッケージが既にインストールされている場合、`pip` にアップグレードするように指示します。
+
+ 何故ならファイルをコピーする前のステップは**Dockerキャッシュ**によって検出される可能性があるためであり、このステップも利用可能な場合は**Dockerキャッシュ**を使用します。
+
+ このステップでキャッシュを使用すると、開発中にイメージを何度もビルドする際に、**毎回**すべての依存関係を**ダウンロードしてインストールする**代わりに多くの**時間**を**節約**できます。
+
+5. ./app` ディレクトリを `/code` ディレクトリの中にコピーする。
+
+ これには**最も頻繁に変更される**すべてのコードが含まれているため、Dockerの**キャッシュ**は**これ以降のステップ**に簡単に使用されることはありません。
+
+ そのため、コンテナイメージのビルド時間を最適化するために、`Dockerfile`の **最後** にこれを置くことが重要です。
+
+6. `uvicorn`サーバーを実行するための**コマンド**を設定します
+
+ `CMD` は文字列のリストを取り、それぞれの文字列はスペースで区切られたコマンドラインに入力するものです。
+
+ このコマンドは **現在の作業ディレクトリ**から実行され、上記の `WORKDIR /code` にて設定した `/code` ディレクトリと同じです。
+
+ そのためプログラムは `/code` で開始しその中にあなたのコードがある `./app` ディレクトリがあるので、**Uvicorn** は `app.main` から `app` を参照し、**インポート** することができます。
+
+!!! tip
+ コード内の"+"の吹き出しをクリックして、各行が何をするのかをレビューしてください。👆
+
+これで、次のようなディレクトリ構造になるはずです:
```
.
├── app
+│ ├── __init__.py
│ └── main.py
-└── Dockerfile
+├── Dockerfile
+└── requirements.txt
+```
+
+#### TLS Termination Proxyの裏側
+
+Nginx や Traefik のような TLS Termination Proxy (ロードバランサ) の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションを追加します。
+
+このオプションは、Uvicornにプロキシ経由でHTTPSで動作しているアプリケーションに対して、送信されるヘッダを信頼するよう指示します。
+
+```Dockerfile
+CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
+```
+
+#### Dockerキャッシュ
+
+この`Dockerfile`には重要なトリックがあり、まず**依存関係だけのファイル**をコピーします。その理由を説明します。
+
+```Dockerfile
+COPY ./requirements.txt /code/requirements.txt
+```
+
+Dockerや他のツールは、これらのコンテナイメージを**段階的に**ビルドし、**1つのレイヤーを他のレイヤーの上に**追加します。`Dockerfile`の先頭から開始し、`Dockerfile`の各命令によって作成されたファイルを追加していきます。
+
+Dockerや同様のツールは、イメージをビルドする際に**内部キャッシュ**も使用します。前回コンテナイメージを構築したときからファイルが変更されていない場合、ファイルを再度コピーしてゼロから新しいレイヤーを作成する代わりに、**前回作成した同じレイヤーを再利用**します。
+
+ただファイルのコピーを避けるだけではあまり改善されませんが、そのステップでキャッシュを利用したため、**次のステップ**でキャッシュを使うことができます。
+
+例えば、依存関係をインストールする命令のためにキャッシュを使うことができます:
+
+```Dockerfile
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```
-## Dockerイメージをビルド
+パッケージ要件のファイルは**頻繁に変更されることはありません**。そのため、そのファイルだけをコピーすることで、Dockerはそのステップでは**キャッシュ**を使用することができます。
+
+そして、Dockerは**次のステップのためにキャッシュ**を使用し、それらの依存関係をダウンロードしてインストールすることができます。そして、ここで**多くの時間を節約**します。✨ ...そして退屈な待ち時間を避けることができます。😪😆
+
+パッケージの依存関係をダウンロードしてインストールするには**数分**かかりますが、**キャッシュ**を使えば**せいぜい数秒**です。
-* プロジェクトディレクトリ (`app` ディレクトリを含んだ、`Dockerfile` のある場所) へ移動
-* FastAPIイメージのビルド:
+加えて、開発中にコンテナ・イメージを何度もビルドして、コードの変更が機能しているかどうかをチェックすることになるため、多くの時間を節約することができます。
+
+そして`Dockerfile`の最終行の近くですべてのコードをコピーします。この理由は、**最も頻繁に**変更されるものなので、このステップの後にあるものはほとんどキャッシュを使用することができないのためです。
+
+```Dockerfile
+COPY ./app /code/app
+```
+
+### Dockerイメージをビルドする
+
+すべてのファイルが揃ったので、コンテナ・イメージをビルドしましょう。
+
+* プロジェクトディレクトリに移動します(`Dockerfile`がある場所で、`app`ディレクトリがあります)
+* FastAPI イメージをビルドします:
@@ -106,9 +305,14 @@ $ docker build -t myimage .
-## Dockerコンテナを起動
+!!! tip
+ 末尾の `.` に注目してほしいです。これは `./` と同じ意味です。 これはDockerにコンテナイメージのビルドに使用するディレクトリを指示します。
+
+ この場合、同じカレント・ディレクトリ(`.`)です。
-* 用意したイメージを基にしたコンテナの起動:
+### Dockerコンテナの起動する
+
+* イメージに基づいてコンテナを実行します:
@@ -118,62 +322,394 @@ $ docker run -d --name mycontainer -p 80:80 myimage
-これで、Dockerコンテナ内に最適化されたFastAPIサーバが動作しています。使用しているサーバ (そしてCPUコア数) に沿った自動チューニングが行われています。
-
-## 確認
+## 確認する
-DockerコンテナのURLで確認できるはずです。例えば:
http://192.168.99.100/items/5?q=somequery や
http://127.0.0.1/items/5?q=somequery (もしくはDockerホストを使用したこれらと同等のもの)。
+Dockerコンテナの
http://192.168.99.100/items/5?q=somequery や
http://127.0.0.1/items/5?q=somequery (またはそれに相当するDockerホストを使用したもの)といったURLで確認できるはずです。
-以下の様なものが返されます:
+アクセスすると以下のようなものが表示されます:
```JSON
{"item_id": 5, "q": "somequery"}
```
-## 対話的APIドキュメント
+## インタラクティブなAPIドキュメント
-ここで、
http://192.168.99.100/docs や
http://127.0.0.1/docs (もしくはDockerホストを使用したこれらと同等のもの) を開いて下さい。
+これらのURLにもアクセスできます:
http://192.168.99.100/docs や
http://127.0.0.1/docs (またはそれに相当するDockerホストを使用したもの)
-自動生成された対話的APIドキュメントが確認できます (
Swagger UIによって提供されます):
+アクセスすると、自動対話型APIドキュメント(
Swagger UIが提供)が表示されます:

-## その他のAPIドキュメント
+## 代替のAPIドキュメント
-また同様に、
http://192.168.99.100/redoc や
http://127.0.0.1/redoc (もしくはDockerホストを使用したこれらと同等のもの) を開いて下さい。
+また、
http://192.168.99.100/redoc や
http://127.0.0.1/redoc (またはそれに相当するDockerホストを使用したもの)にもアクセスできます。
-他の自動生成された対話的なAPIドキュメントが確認できます (
ReDocによって提供されます):
+代替の自動ドキュメント(
ReDocによって提供される)が表示されます:

-## Traefik
+## 単一ファイルのFastAPIでDockerイメージをビルドする
+
+FastAPI が単一のファイル、例えば `./app` ディレクトリのない `main.py` の場合、ファイル構造は次のようになります:
+```
+.
+├── Dockerfile
+├── main.py
+└── requirements.txt
+```
+
+そうすれば、`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 ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
+```
+
+1. main.py`ファイルを `/code` ディレクトリに直接コピーします。
+
+2. Uvicornを実行し、`main`から`app`オブジェクトをインポートするように指示します(`app.main`からインポートするのではなく)。
+
+次にUvicornコマンドを調整して、`app.main` の代わりに新しいモジュール `main` を使用し、FastAPIオブジェクトである `app` をインポートします。
+
+## デプロイメントのコンセプト
+
+コンテナという観点から、[デプロイのコンセプト](./concepts.md){.internal-link target=_blank}に共通するいくつかについて、もう一度説明しましょう。
+
+コンテナは主に、アプリケーションの**ビルドとデプロイ**のプロセスを簡素化するためのツールですが、これらの**デプロイのコンセプト**を扱うための特定のアプローチを強制するものではないです。
-
Traefikは、高性能なリバースプロキシ/ロードバランサーです。「TLSターミネーションプロキシ」ジョブを実行できます(他の機能と切り離して)。
+**良いニュース**は、それぞれの異なる戦略には、すべてのデプロイメントのコンセプトをカバーする方法があるということです。🎉
-Let's Encryptと統合されています。そのため、証明書の取得と更新を含むHTTPSに関するすべての処理を実行できます。
+これらの**デプロイメントのコンセプト**をコンテナの観点から見直してみましょう:
-また、Dockerとも統合されています。したがって、各アプリケーション構成でドメインを宣言し、それらの構成を読み取って、HTTPS証明書を生成し、構成に変更を加えることなく、アプリケーションにHTTPSを自動的に提供できます。
+* セキュリティ - HTTPS
+* 起動時の実行
+* 再起動
+* **レプリケーション(実行中のプロセス数)**
+* メモリ
+* 開始前の事前ステップ
+
+## HTTPS
+
+FastAPI アプリケーションの **コンテナ・イメージ**(および後で実行中の **コンテナ**)だけに焦点を当てると、通常、HTTPSは別のツールを用いて**外部で**処理されます。
+
+例えば
Traefikのように、**HTTPS**と**証明書**の**自動**取得を扱う別のコンテナである可能性もあります。
+
+!!! tip
+ TraefikはDockerやKubernetesなどと統合されているので、コンテナ用のHTTPSの設定や構成はとても簡単です。
+
+あるいは、(コンテナ内でアプリケーションを実行しながら)クラウド・プロバイダーがサービスの1つとしてHTTPSを処理することもできます。
+
+## 起動時および再起動時の実行
+
+通常、コンテナの**起動と実行**を担当する別のツールがあります。
+
+それは直接**Docker**であったり、**Docker Compose**であったり、**Kubernetes**であったり、**クラウドサービス**であったりします。
+
+ほとんどの場合(またはすべての場合)、起動時にコンテナを実行し、失敗時に再起動を有効にする簡単なオプションがあります。例えばDockerでは、コマンドラインオプションの`--restart`が該当します。
+
+コンテナを使わなければ、アプリケーションを起動時や再起動時に実行させるのは面倒で難しいかもしれません。しかし、**コンテナ**で作業する場合、ほとんどのケースでその機能はデフォルトで含まれています。✨
+
+## レプリケーション - プロセス数
+
+**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの
クラスターを構成している場合、 各コンテナで(Workerを持つGunicornのような)**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。
+
+Kubernetesのような分散コンテナ管理システムの1つは通常、入ってくるリクエストの**ロードバランシング**をサポートしながら、**コンテナのレプリケーション**を処理する統合された方法を持っています。このことはすべて**クラスタレベル**にてです。
+
+そのような場合、UvicornワーカーでGunicornのようなものを実行するのではなく、[上記の説明](#dockerfile)のように**Dockerイメージをゼロから**ビルドし、依存関係をインストールして、**単一のUvicornプロセス**を実行したいでしょう。
+
+### ロードバランサー
+
+コンテナを使用する場合、通常はメイン・ポート**でリスニング**しているコンポーネントがあるはずです。それはおそらく、**HTTPS**を処理するための**TLS Termination Proxy**でもある別のコンテナであったり、同様のツールであったりするでしょう。
+
+このコンポーネントはリクエストの **負荷** を受け、 (うまくいけば) その負荷を**バランスよく** ワーカーに分配するので、一般に **ロードバランサ** とも呼ばれます。
+
+!!! tip
+ HTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネントは、おそらく**ロードバランサー**にもなるでしょう。
+
+そしてコンテナで作業する場合、コンテナの起動と管理に使用する同じシステムには、**ロードバランサー**(**TLS Termination Proxy**の可能性もある)から**ネットワーク通信**(HTTPリクエストなど)をアプリのあるコンテナ(複数可)に送信するための内部ツールが既にあるはずです。
+
+### 1つのロードバランサー - 複数のワーカーコンテナー
+
+**Kubernetes**や同様の分散コンテナ管理システムで作業する場合、その内部のネットワーキングのメカニズムを使用することで、メインの**ポート**でリッスンしている単一の**ロードバランサー**が、アプリを実行している可能性のある**複数のコンテナ**に通信(リクエスト)を送信できるようになります。
+
+アプリを実行するこれらのコンテナには、通常**1つのプロセス**(たとえば、FastAPIアプリケーションを実行するUvicornプロセス)があります。これらはすべて**同一のコンテナ**であり同じものを実行しますが、それぞれが独自のプロセスやメモリなどを持ちます。そうすることで、CPUの**異なるコア**、あるいは**異なるマシン**での**並列化**を利用できます。
+
+そして、**ロードバランサー**を備えた分散コンテナシステムは、**順番に**あなたのアプリを含む各コンテナに**リクエストを分配**します。つまり、各リクエストは、あなたのアプリを実行している複数の**レプリケートされたコンテナ**の1つによって処理されます。
+
+そして通常、この**ロードバランサー**は、クラスタ内の*他の*アプリケーション(例えば、異なるドメインや異なるURLパスのプレフィックスの配下)へのリクエストを処理することができ、その通信をクラスタ内で実行されている*他の*アプリケーションのための適切なコンテナに送信します。
+
+### 1コンテナにつき1プロセス
+
+この種のシナリオでは、すでにクラスタ・レベルでレプリケーションを処理しているため、おそらくコンテナごとに**単一の(Uvicorn)プロセス**を持ちたいでしょう。
+
+この場合、Uvicornワーカーを持つGunicornのようなプロセスマネージャーや、Uvicornワーカーを使うUvicornは**避けたい**でしょう。**コンテナごとにUvicornのプロセスは1つだけ**にしたいでしょう(おそらく複数のコンテナが必要でしょう)。
+
+(GunicornやUvicornがUvicornワーカーを管理するように)コンテナ内に別のプロセスマネージャーを持つことは、クラスターシステムですでに対処しているであろう**不要な複雑さ**を追加するだけです。
+
+### Containers with Multiple Processes and Special Cases
+
+もちろん、**特殊なケース**として、**Gunicornプロセスマネージャ**を持つ**コンテナ**内で複数の**Uvicornワーカープロセス**を起動させたい場合があります。
+
+このような場合、**公式のDockerイメージ**を使用することができます。このイメージには、複数の**Uvicornワーカープロセス**を実行するプロセスマネージャとして**Gunicorn**が含まれており、現在のCPUコアに基づいてワーカーの数を自動的に調整するためのデフォルト設定がいくつか含まれています。詳しくは後述の[Gunicornによる公式Dockerイメージ - Uvicorn](#gunicornによる公式dockerイメージ---Uvicorn)で説明します。
+
+以下は、それが理にかなっている場合の例です:
+
+#### シンプルなアプリケーション
+
+アプリケーションを**シンプル**な形で実行する場合、プロセス数の細かい調整が必要ない場合、自動化されたデフォルトを使用するだけで、コンテナ内にプロセスマネージャが必要かもしれません。例えば、公式Dockerイメージでシンプルな設定が可能です。
+
+#### Docker Compose
+
+Docker Composeで**シングルサーバ**(クラスタではない)にデプロイすることもできますので、共有ネットワークと**ロードバランシング**を維持しながら(Docker Composeで)コンテナのレプリケーションを管理する簡単な方法はないでしょう。
+
+その場合、**単一のコンテナ**で、**プロセスマネージャ**が内部で**複数のワーカープロセス**を起動するようにします。
+
+#### Prometheusとその他の理由
+
+また、**1つのコンテナ**に**1つのプロセス**を持たせるのではなく、**1つのコンテナ**に**複数のプロセス**を持たせる方が簡単だという**他の理由**もあるでしょう。
+
+例えば、(セットアップにもよりますが)Prometheusエクスポーターのようなツールを同じコンテナ内に持つことができます。
+
+この場合、**複数のコンテナ**があると、デフォルトでは、Prometheusが**メトリクスを**読みに来たとき、すべてのレプリケートされたコンテナの**蓄積されたメトリクス**を取得するのではなく、毎回**単一のコンテナ**(その特定のリクエストを処理したコンテナ)のものを取得することになります。
+
+その場合、**複数のプロセス**を持つ**1つのコンテナ**を用意し、同じコンテナ上のローカルツール(例えばPrometheusエクスポーター)がすべての内部プロセスのPrometheusメトリクスを収集し、その1つのコンテナ上でそれらのメトリクスを公開する方がシンプルかもしれません。
---
-次のセクションに進み、この情報とツールを使用して、すべてを組み合わせます。
+重要なのは、盲目的に従わなければならない普遍のルールはないということです。
+
+これらのアイデアは、**あなた自身のユースケース**を評価し、あなたのシステムに最適なアプローチを決定するために使用することができます:
+
+* セキュリティ - HTTPS
+* 起動時の実行
+* 再起動
+* **レプリケーション(実行中のプロセス数)**
+* メモリ
+* 開始前の事前ステップ
+
+## メモリー
+
+コンテナごとに**単一のプロセスを実行する**と、それらのコンテナ(レプリケートされている場合は1つ以上)によって消費される多かれ少なかれ明確に定義された、安定し制限された量のメモリを持つことになります。
+
+そして、コンテナ管理システム(**Kubernetes**など)の設定で、同じメモリ制限と要件を設定することができます。
+
+そうすれば、コンテナが必要とするメモリ量とクラスタ内のマシンで利用可能なメモリ量を考慮して、**利用可能なマシン**に**コンテナ**をレプリケートできるようになります。
+
+アプリケーションが**シンプル**なものであれば、これはおそらく**問題にはならない**でしょうし、ハードなメモリ制限を指定する必要はないかもしれないです。
+
+しかし、**多くのメモリを使用**している場合(たとえば**機械学習**モデルなど)、どれだけのメモリを消費しているかを確認し、**各マシンで実行するコンテナの数**を調整する必要があります(そしておそらくクラスタにマシンを追加します)。
+
+**コンテナごとに複数のプロセス**を実行する場合(たとえば公式のDockerイメージで)、起動するプロセスの数が**利用可能なメモリ以上に消費しない**ようにする必要があります。
+
+## 開始前の事前ステップとコンテナ
+
+コンテナ(DockerやKubernetesなど)を使っている場合、主に2つのアプローチがあります。
+
+### 複数のコンテナ
+
+複数の**コンテナ**があり、おそらくそれぞれが**単一のプロセス**を実行している場合(**Kubernetes**クラスタなど)、レプリケートされたワーカーコンテナを実行する**前に**、単一のコンテナで**事前のステップ**の作業を行う**別のコンテナ**を持ちたいと思うでしょう。
+
+!!! info
+ もしKubernetesを使用している場合, これはおそらく
Init コンテナでしょう。
+
+ユースケースが事前のステップを**並列で複数回**実行するのに問題がない場合(例:データベースの準備チェック)、メインプロセスを開始する前に、それらのステップを各コンテナに入れることが可能です。
+
+### 単一コンテナ
+
+単純なセットアップで、**単一のコンテナ**で複数の**ワーカー・プロセス**(または1つのプロセスのみ)を起動する場合、アプリでプロセスを開始する直前に、同じコンテナで事前のステップを実行できます。公式Dockerイメージは、内部的にこれをサポートしています。
+
+## Gunicornによる公式Dockerイメージ - Uvicorn
+
+前の章で詳しく説明したように、Uvicornワーカーで動作するGunicornを含む公式のDockerイメージがあります: [Server Workers - Gunicorn と Uvicorn](./server-workers.md){.internal-link target=_blank}で詳しく説明しています。
+
+このイメージは、主に上記で説明した状況で役に立つでしょう: [複数のプロセスと特殊なケースを持つコンテナ(Containers with Multiple Processes and Special Cases)](#containers-with-multiple-processes-and-special-cases)
+
+*
tiangolo/uvicorn-gunicorn-fastapi.
+
+!!! warning
+ このベースイメージや類似のイメージは**必要ない**可能性が高いので、[上記の: FastAPI用のDockerイメージをビルドする(Build a Docker Image for FastAPI)](#build-a-docker-image-for-fastapi)のようにゼロからイメージをビルドする方が良いでしょう。
+
+このイメージには、利用可能なCPUコアに基づいて**ワーカー・プロセスの数**を設定する**オートチューニング**メカニズムが含まれています。
+
+これは**賢明なデフォルト**を備えていますが、**環境変数**や設定ファイルを使ってすべての設定を変更したり更新したりすることができます。
-## TraefikとHTTPSを使用したDocker Swarmモードのクラスタ
+また、スクリプトで
**開始前の事前ステップ**を実行することもサポートしている。
-HTTPSを処理する(証明書の取得と更新を含む)Traefikを使用して、Docker Swarmモードのクラスタを数分(20分程度)でセットアップできます。
+!!! tip
+ すべての設定とオプションを見るには、Dockerイメージのページをご覧ください:
tiangolo/uvicorn-gunicorn-fastapi
-Docker Swarmモードを使用することで、1台のマシンの「クラスタ」から開始でき(1か月あたり5ドルのサーバーでもできます)、後から必要なだけサーバーを拡張できます。
+### 公式Dockerイメージのプロセス数
-TraefikおよびHTTPS処理を備えたDocker Swarm Modeクラスターをセットアップするには、次のガイドに従います:
+このイメージの**プロセス数**は、利用可能なCPU**コア**から**自動的に計算**されます。
+
+つまり、CPUから可能な限り**パフォーマンス**を**引き出そう**とします。
+
+また、**環境変数**などを使った設定で調整することもできます。
+
+しかし、プロセスの数はコンテナが実行しているCPUに依存するため、**消費されるメモリの量**もそれに依存することになります。
+
+そのため、(機械学習モデルなどで)大量のメモリを消費するアプリケーションで、サーバーのCPUコアが多いが**メモリが少ない**場合、コンテナは利用可能なメモリよりも多くのメモリを使おうとすることになります。
+
+その結果、パフォーマンスが大幅に低下する(あるいはクラッシュする)可能性があります。🚨
+
+### Dockerfileを作成する
+
+この画像に基づいて`Dockerfile`を作成する方法を以下に示します:
+
+```Dockerfile
+FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
+
+COPY ./requirements.txt /app/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
+
+COPY ./app /app
+```
+
+### より大きなアプリケーション
+
+[複数のファイルを持つ大きなアプリケーション](../tutorial/bigger-applications.md){.internal-link target=_blank}を作成するセクションに従った場合、`Dockerfile`は次のようになります:
+
+```Dockerfile hl_lines="7"
+FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
+
+COPY ./requirements.txt /app/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
+
+COPY ./app /app/app
+```
+
+### いつ使うのか
+
+おそらく、**Kubernetes**(または他のもの)を使用していて、すでにクラスタレベルで複数の**コンテナ**で**レプリケーション**を設定している場合は、この公式ベースイメージ(または他の類似のもの)は**使用すべきではありません**。
+
+そのような場合は、上記のように**ゼロから**イメージを構築する方がよいでしょう: [FastAPI用のDockerイメージをビルドする(Build a Docker Image for FastAPI)](#build-a-docker-image-for-fastapi) を参照してください。
+
+このイメージは、主に上記の[複数のプロセスと特殊なケースを持つコンテナ(Containers with Multiple Processes and Special Cases)](#containers-with-multiple-processes-and-special-cases)で説明したような特殊なケースで役に立ちます。
+
+例えば、アプリケーションが**シンプル**で、CPUに応じたデフォルトのプロセス数を設定すればうまくいく場合や、クラスタレベルでレプリケーションを手動で設定する手間を省きたい場合、アプリで複数のコンテナを実行しない場合などです。
+
+または、**Docker Compose**でデプロイし、単一のサーバで実行している場合などです。
+
+## コンテナ・イメージのデプロイ
+
+コンテナ(Docker)イメージを手に入れた後、それをデプロイするにはいくつかの方法があります。
+
+例えば以下のリストの方法です:
+
+* 単一サーバーの**Docker Compose**
+* **Kubernetes**クラスタ
+* Docker Swarmモードのクラスター
+* Nomadのような別のツール
+* コンテナ・イメージをデプロイするクラウド・サービス
+
+## Poetryを利用したDockerイメージ
+
+もしプロジェクトの依存関係を管理するために
Poetryを利用する場合、マルチステージビルドを使うと良いでしょう。
+
+```{ .dockerfile .annotate }
+# (1)
+FROM python:3.9 as requirements-stage
+
+# (2)
+WORKDIR /tmp
+
+# (3)
+RUN pip install poetry
+
+# (4)
+COPY ./pyproject.toml ./poetry.lock* /tmp/
+
+# (5)
+RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
+
+# (6)
+FROM python:3.9
+
+# (7)
+WORKDIR /code
+
+# (8)
+COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
+
+# (9)
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (10)
+COPY ./app /code/app
+
+# (11)
+CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+```
+
+1. これは最初のステージで、`requirements-stage`と名付けられます
+2. `/tmp` を現在の作業ディレクトリに設定します
+ ここで `requirements.txt` というファイルを生成します。
+
+3. このDockerステージにPoetryをインストールします
+
+4. pyproject.toml`と`poetry.lock`ファイルを`/tmp` ディレクトリにコピーします
+
+ `./poetry.lock*`(末尾に`*`)を使用するため、そのファイルがまだ利用できない場合でもクラッシュすることはないです。
+5. requirements.txt`ファイルを生成します
+
+6. これは最後のステージであり、ここにあるものはすべて最終的なコンテナ・イメージに保存されます
+7. 現在の作業ディレクトリを `/code` に設定します
+8. `requirements.txt`ファイルを `/code` ディレクトリにコピーします
+ このファイルは前のDockerステージにしか存在しないため、`--from-requirements-stage`を使ってコピーします。
+9. 生成された `requirements.txt` ファイルにあるパッケージの依存関係をインストールします
+10. app` ディレクトリを `/code` ディレクトリにコピーします
+11. uvicorn` コマンドを実行して、`app.main` からインポートした `app` オブジェクトを使用するように指示します
+!!! tip
+ "+"の吹き出しをクリックすると、それぞれの行が何をするのかを見ることができます
+
+**Dockerステージ**は`Dockerfile`の一部で、**一時的なコンテナイメージ**として動作します。
+
+最初のステージは **Poetryのインストール**と Poetry の `pyproject.toml` ファイルからプロジェクトの依存関係を含む**`requirements.txt`を生成**するためだけに使用されます。
+
+この `requirements.txt` ファイルは後半の **次のステージ**で `pip` と共に使用されます。
+
+最終的なコンテナイメージでは、**最終ステージ**のみが保存されます。前のステージは破棄されます。
+
+Poetryを使用する場合、**Dockerマルチステージビルド**を使用することは理にかなっています。
+
+なぜなら、最終的なコンテナイメージにPoetryとその依存関係がインストールされている必要はなく、**必要なのは**プロジェクトの依存関係をインストールするために生成された `requirements.txt` ファイルだけだからです。
+
+そして次の(そして最終的な)ステージでは、前述とほぼ同じ方法でイメージをビルドします。
+
+### TLS Termination Proxyの裏側 - Poetry
+
+繰り返しになりますが、NginxやTraefikのようなTLS Termination Proxy(ロードバランサー)の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションをコマンドに追加します:
+
+```Dockerfile
+CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
+```
-###
Docker Swarm Mode and Traefik for an HTTPS cluster
+## まとめ
-### FastAPIアプリケーションのデプロイ
+コンテナ・システム(例えば**Docker**や**Kubernetes**など)を使えば、すべての**デプロイメントのコンセプト**を扱うのがかなり簡単になります:
-すべてを設定するための最も簡単な方法は、[**FastAPI** Project Generators](../project-generation.md){.internal-link target=_blank}を使用することでしょう。
+* セキュリティ - HTTPS
+* 起動時の実行
+* 再起動
+* **レプリケーション(実行中のプロセス数)**
+* メモリ
+* 開始前の事前ステップ
-上述したTraefikとHTTPSを備えたDocker Swarm クラスタが統合されるように設計されています。
+ほとんどの場合、ベースとなるイメージは使用せず、公式のPython Dockerイメージをベースにした**コンテナイメージをゼロからビルド**します。
-2分程度でプロジェクトが生成されます。
+`Dockerfile`と**Dockerキャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**することができ、生産性を最大化することができます(そして退屈を避けることができます)。😎
-生成されたプロジェクトはデプロイの指示がありますが、それを実行するとさらに2分かかります。
+特別なケースでは、FastAPI用の公式Dockerイメージを使いたいかもしれません。🤓
diff --git a/docs/ja/docs/deployment/https.md b/docs/ja/docs/deployment/https.md
new file mode 100644
index 000000000..a291f870f
--- /dev/null
+++ b/docs/ja/docs/deployment/https.md
@@ -0,0 +1,200 @@
+# HTTPS について
+
+HTTPSは単に「有効」か「無効」かで決まるものだと思いがちです。
+
+しかし、それよりもはるかに複雑です。
+
+!!! tip
+ もし急いでいたり、HTTPSの仕組みについて気にしないのであれば、次のセクションに進み、さまざまなテクニックを使ってすべてをセットアップするステップ・バイ・ステップの手順をご覧ください。
+
+利用者の視点から **HTTPS の基本を学ぶ**に当たっては、次のリソースをオススメします:
https://howhttps.works/.
+
+さて、**開発者の視点**から、HTTPSについて考える際に念頭に置くべきことをいくつかみていきましょう:
+
+* HTTPSの場合、**サーバ**は**第三者**によって生成された**「証明書」を持つ**必要があります。
+ * これらの証明書は「生成」されたものではなく、実際には第三者から**取得**されたものです。
+* 証明書には**有効期限**があります。
+ * つまりいずれ失効します。
+ * そのため**更新**をし、第三者から**再度取得**する必要があります。
+* 接続の暗号化は**TCPレベル**で行われます。
+ * それは**HTTPの1つ下**のレイヤーです。
+ * つまり、**証明書と暗号化**の処理は、**HTTPの前**に行われます。
+* **TCPは "ドメイン "について知りません**。IPアドレスについてのみ知っています。
+ * 要求された**特定のドメイン**に関する情報は、**HTTPデータ**に入ります。
+* **HTTPS証明書**は、**特定のドメイン**を「証明」しますが、プロトコルと暗号化はTCPレベルで行われ、どのドメインが扱われているかを**知る前**に行われます。
+* **デフォルトでは**、**IPアドレスごとに1つのHTTPS証明書**しか持てないことになります。
+ * これは、サーバーの規模やアプリケーションの規模に寄りません。
+ * しかし、これには**解決策**があります。
+* **TLS**プロトコル(HTTPの前に、TCPレベルで暗号化を処理するもの)には、**
SNI**と呼ばれる**拡張**があります。
+ * このSNI拡張機能により、1つのサーバー(**単一のIPアドレス**を持つ)が**複数のHTTPS証明書**を持ち、**複数のHTTPSドメイン/アプリケーション**にサービスを提供できるようになります。
+ * これが機能するためには、**パブリックIPアドレス**でリッスンしている、サーバー上で動作している**単一の**コンポーネント(プログラム)が、サーバー内の**すべてのHTTPS証明書**を持っている必要があります。
+
+* セキュアな接続を取得した**後**でも、通信プロトコルは**HTTPのまま**です。
+ * コンテンツは**HTTPプロトコル**で送信されているにもかかわらず、**暗号化**されています。
+
+
+サーバー(マシン、ホストなど)上で**1つのプログラム/HTTPサーバー**を実行させ、**HTTPSに関する全てのこと**を管理するのが一般的です。
+
+**暗号化された HTTPS リクエスト** を受信し、**復号化された HTTP リクエスト** を同じサーバーで実行されている実際の HTTP アプリケーション(この場合は **FastAPI** アプリケーション)に送信し、アプリケーションから **HTTP レスポンス** を受け取り、適切な **HTTPS 証明書** を使用して **暗号化** し、そして**HTTPS** を使用してクライアントに送り返します。
+
+このサーバーはしばしば **
TLS Termination Proxy**と呼ばれます。
+
+TLS Termination Proxyとして使えるオプションには、以下のようなものがあります:
+
+* Traefik(証明書の更新も対応)
+* Caddy (証明書の更新も対応)
+* Nginx
+* HAProxy
+
+
+## Let's Encrypt
+
+Let's Encrypt以前は、これらの**HTTPS証明書**は信頼できる第三者によって販売されていました。
+
+これらの証明書を取得するための手続きは面倒で、かなりの書類を必要とし、証明書はかなり高価なものでした。
+
+しかしその後、**
Let's Encrypt** が作られました。
+
+これはLinux Foundationのプロジェクトから生まれたものです。 自動化された方法で、**HTTPS証明書を無料で**提供します。これらの証明書は、すべての標準的な暗号化セキュリティを使用し、また短命(約3ヶ月)ですが、こういった寿命の短さによって、**セキュリティは実際に優れています**。
+
+ドメインは安全に検証され、証明書は自動的に生成されます。また、証明書の更新も自動化されます。
+
+このアイデアは、これらの証明書の取得と更新を自動化することで、**安全なHTTPSを、無料で、永遠に**利用できるようにすることです。
+
+## 開発者のための HTTPS
+
+ここでは、HTTPS APIがどのように見えるかの例を、主に開発者にとって重要なアイデアに注意を払いながら、ステップ・バイ・ステップで説明します。
+
+### ドメイン名
+
+ステップの初めは、**ドメイン名**を**取得すること**から始まるでしょう。その後、DNSサーバー(おそらく同じクラウドプロバイダー)に設定します。
+
+おそらくクラウドサーバー(仮想マシン)かそれに類するものを手に入れ、
固定の **パブリックIPアドレス**を持つことになるでしょう。
+
+DNSサーバーでは、**取得したドメイン**をあなたのサーバーのパプリック**IPアドレス**に向けるレコード(「`Aレコード`」)を設定します。
+
+これはおそらく、最初の1回だけあり、すべてをセットアップするときに行うでしょう。
+
+!!! tip
+ ドメイン名の話はHTTPSに関する話のはるか前にありますが、すべてがドメインとIPアドレスに依存するため、ここで言及する価値があります。
+
+### DNS
+
+では、実際のHTTPSの部分に注目してみよう。
+
+まず、ブラウザは**DNSサーバー**に**ドメインに対するIP**が何であるかを確認します。今回は、`someapp.example.com`とします。
+
+DNSサーバーは、ブラウザに特定の**IPアドレス**を使用するように指示します。このIPアドレスは、DNSサーバーで設定した、あなたのサーバーが使用するパブリックIPアドレスになります。
+
+

+
+### TLS Handshake の開始
+
+ブラウザはIPアドレスと**ポート443**(HTTPSポート)で通信します。
+
+通信の最初の部分は、クライアントとサーバー間の接続を確立し、使用する暗号鍵などを決めるだけです。
+
+

+
+TLS接続を確立するためのクライアントとサーバー間のこのやりとりは、**TLSハンドシェイク**と呼ばれます。
+
+### SNI拡張機能付きのTLS
+
+サーバー内の**1つのプロセス**だけが、特定 の**IPアドレス**の特定の**ポート** で待ち受けることができます。
+
+同じIPアドレスの他のポートで他のプロセスがリッスンしている可能性もありますが、IPアドレスとポートの組み合わせごとに1つだけです。
+
+TLS(HTTPS)はデフォルトで`443`という特定のポートを使用する。つまり、これが必要なポートです。
+
+このポートをリッスンできるのは1つのプロセスだけなので、これを実行するプロセスは**TLS Termination Proxy**となります。
+
+TLS Termination Proxyは、1つ以上の**TLS証明書**(HTTPS証明書)にアクセスできます。
+
+前述した**SNI拡張機能**を使用して、TLS Termination Proxy は、利用可能なTLS (HTTPS)証明書のどれを接続先として使用すべきかをチェックし、クライアントが期待するドメインに一致するものを使用します。
+
+今回は、`someapp.example.com`の証明書を使うことになります。
+
+

+
+クライアントは、そのTLS証明書を生成したエンティティ(この場合はLet's Encryptですが、これについては後述します)をすでに**信頼**しているため、その証明書が有効であることを**検証**することができます。
+
+次に証明書を使用して、クライアントとTLS Termination Proxy は、 **TCP通信**の残りを**どのように暗号化するかを決定**します。これで**TLSハンドシェイク**の部分が完了します。
+
+この後、クライアントとサーバーは**暗号化されたTCP接続**を持ちます。そして、その接続を使って実際の**HTTP通信**を開始することができます。
+
+これが**HTTPS**であり、純粋な(暗号化されていない)TCP接続ではなく、**セキュアなTLS接続**の中に**HTTP**があるだけです。
+
+!!! tip
+ 通信の暗号化は、HTTPレベルではなく、**TCPレベル**で行われることに注意してください。
+
+### HTTPS リクエスト
+
+これでクライアントとサーバー(具体的にはブラウザとTLS Termination Proxy)は**暗号化されたTCP接続**を持つことになり、**HTTP通信**を開始することができます。
+
+そこで、クライアントは**HTTPSリクエスト**を送信します。これは、暗号化されたTLSコネクションを介した単なるHTTPリクエストです。
+
+

+
+### リクエストの復号化
+
+TLS Termination Proxy は、合意が取れている暗号化を使用して、**リクエストを復号化**し、**プレーン (復号化された) HTTP リクエスト** をアプリケーションを実行しているプロセス (例えば、FastAPI アプリケーションを実行している Uvicorn を持つプロセス) に送信します。
+
+

+
+### HTTP レスポンス
+
+アプリケーションはリクエストを処理し、**プレーン(暗号化されていない)HTTPレスポンス** をTLS Termination Proxyに送信します。
+
+

+
+### HTTPS レスポンス
+
+TLS Termination Proxyは次に、事前に合意が取れている暗号(`someapp.example.com`の証明書から始まる)を使って**レスポンスを暗号化し**、ブラウザに送り返す。
+
+その後ブラウザでは、レスポンスが有効で正しい暗号キーで暗号化されていることなどを検証します。そして、ブラウザはレスポンスを**復号化**して処理します。
+
+

+
+クライアント(ブラウザ)は、レスポンスが正しいサーバーから来たことを知ることができます。 なぜなら、そのサーバーは、以前に**HTTPS証明書**を使って合意した暗号を使っているからです。
+
+### 複数のアプリケーション
+
+同じサーバー(または複数のサーバー)に、例えば他のAPIプログラムやデータベースなど、**複数のアプリケーション**が存在する可能性があります。
+
+特定のIPとポート(この例ではTLS Termination Proxy)を扱うことができるのは1つのプロセスだけですが、他のアプリケーション/プロセスも、同じ**パブリックIPとポート**の組み合わせを使用しようとしない限り、サーバー上で実行することができます。
+
+

+
+そうすれば、TLS Termination Proxy は、**複数のドメイン**や複数のアプリケーションのHTTPSと証明書を処理し、それぞれのケースで適切なアプリケーションにリクエストを送信することができます。
+
+### 証明書の更新
+
+将来のある時点で、各証明書は(取得後約3ヶ月で)**失効**します。
+
+その後、Let's Encryptと通信する別のプログラム(別のプログラムである場合もあれば、同じTLS Termination Proxyである場合もある)によって、証明書を更新します。
+
+

+
+**TLS証明書**は、IPアドレスではなく、**ドメイン名に関連付けられて**います。
+
+したがって、証明書を更新するために、更新プログラムは、認証局(Let's Encrypt)に対して、**そのドメインが本当に「所有」し、管理している**ことを**証明**する必要があります。
+
+そのために、またさまざまなアプリケーションのニーズに対応するために、いくつかの方法があります。よく使われる方法としては:
+
+* **いくつかのDNSレコードを修正します。**
+ * これをするためには、更新プログラムはDNSプロバイダーのAPIをサポートする必要があります。したがって、使用しているDNSプロバイダーによっては、このオプションが使える場合もあれば、使えない場合もあります。
+* ドメインに関連付けられたパブリックIPアドレス上で、(少なくとも証明書取得プロセス中は)**サーバー**として実行します。
+ * 上で述べたように、特定のIPとポートでリッスンできるプロセスは1つだけです。
+ * これは、同じTLS Termination Proxyが証明書の更新処理も行う場合に非常に便利な理由の1つです。
+ * そうでなければ、TLS Termination Proxyを一時的に停止し、証明書を取得するために更新プログラムを起動し、TLS Termination Proxyで証明書を設定し、TLS Termination Proxyを再起動しなければならないかもしれません。TLS Termination Proxyが停止している間はアプリが利用できなくなるため、これは理想的ではありません。
+
+
+アプリを提供しながらこのような更新処理を行うことは、アプリケーション・サーバー(Uvicornなど)でTLS証明書を直接使用するのではなく、TLS Termination Proxyを使用して**HTTPSを処理する別のシステム**を用意したくなる主な理由の1つです。
+
+## まとめ
+
+**HTTPS**を持つことは非常に重要であり、ほとんどの場合、かなり**クリティカル**です。開発者として HTTPS に関わる労力のほとんどは、これらの**概念とその仕組みを理解する**ことです。
+
+しかし、ひとたび**開発者向けHTTPS**の基本的な情報を知れば、簡単な方法ですべてを管理するために、さまざまなツールを組み合わせて設定することができます。
+
+次の章では、**FastAPI** アプリケーションのために **HTTPS** をセットアップする方法について、いくつかの具体例を紹介します。🔒
diff --git a/docs/ja/docs/deployment/server-workers.md b/docs/ja/docs/deployment/server-workers.md
new file mode 100644
index 000000000..e1ea165a2
--- /dev/null
+++ b/docs/ja/docs/deployment/server-workers.md
@@ -0,0 +1,182 @@
+# Server Workers - Gunicorn と Uvicorn
+
+前回のデプロイメントのコンセプトを振り返ってみましょう:
+
+* セキュリティ - HTTPS
+* 起動時の実行
+* 再起動
+* **レプリケーション(実行中のプロセス数)**
+* メモリ
+* 開始前の事前ステップ
+
+ここまでのドキュメントのチュートリアルでは、おそらくUvicornのような**サーバープログラム**を**単一のプロセス**で実行しています。
+
+アプリケーションをデプロイする際には、**複数のコア**を利用し、そしてより多くのリクエストを処理できるようにするために、プロセスの**レプリケーション**を持つことを望むでしょう。
+
+前のチャプターである[デプロイメントのコンセプト](./concepts.md){.internal-link target=_blank}にて見てきたように、有効な戦略がいくつかあります。
+
+ここでは
**Gunicorn**が**Uvicornのワーカー・プロセス**を管理する場合の使い方について紹介していきます。
+
+!!! info
+
+ DockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します: [コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}
+
+ 特に**Kubernetes**上で実行する場合は、おそらく**Gunicornを使用せず**、**コンテナごとに単一のUvicornプロセス**を実行することになりますが、それについてはこの章の後半で説明します。
+
+## GunicornによるUvicornのワーカー・プロセスの管理
+
+**Gunicorn**は**WSGI標準**のアプリケーションサーバーです。このことは、GunicornはFlaskやDjangoのようなアプリケーションにサービスを提供できることを意味します。Gunicornそれ自体は**FastAPI**と互換性がないですが、というのもFastAPIは最新の**
ASGI 標準**を使用しているためです。
+
+しかし、Gunicornは**プロセスマネージャー**として動作し、ユーザーが特定の**ワーカー・プロセスクラス**を使用するように指示することができます。するとGunicornはそのクラスを使い1つ以上の**ワーカー・プロセス**を開始します。
+
+そして**Uvicorn**には**Gunicorn互換のワーカークラス**があります。
+
+この組み合わせで、Gunicornは**プロセスマネージャー**として動作し、**ポート**と**IP**をリッスンします。そして、**Uvicornクラス**を実行しているワーカー・プロセスに通信を**転送**します。
+
+そして、Gunicorn互換の**Uvicornワーカー**クラスが、FastAPIが使えるように、Gunicornから送られてきたデータをASGI標準に変換する役割を担います。
+
+## GunicornとUvicornをインストールする
+
+
+
+```console
+$ pip install "uvicorn[standard]" gunicorn
+
+---> 100%
+```
+
+
+
+これによりUvicornと(高性能を得るための)標準(`standard`)の追加パッケージとGunicornの両方がインストールされます。
+
+## UvicornのワーカーとともにGunicornを実行する
+
+Gunicornを以下のように起動させることができます:
+
+
+
+```console
+$ gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80
+
+[19499] [INFO] Starting gunicorn 20.1.0
+[19499] [INFO] Listening at: http://0.0.0.0:80 (19499)
+[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker
+[19511] [INFO] Booting worker with pid: 19511
+[19513] [INFO] Booting worker with pid: 19513
+[19514] [INFO] Booting worker with pid: 19514
+[19515] [INFO] Booting worker with pid: 19515
+[19511] [INFO] Started server process [19511]
+[19511] [INFO] Waiting for application startup.
+[19511] [INFO] Application startup complete.
+[19513] [INFO] Started server process [19513]
+[19513] [INFO] Waiting for application startup.
+[19513] [INFO] Application startup complete.
+[19514] [INFO] Started server process [19514]
+[19514] [INFO] Waiting for application startup.
+[19514] [INFO] Application startup complete.
+[19515] [INFO] Started server process [19515]
+[19515] [INFO] Waiting for application startup.
+[19515] [INFO] Application startup complete.
+```
+
+
+
+それぞれのオプションの意味を見てみましょう:
+
+* `main:app`: `main`は"`main`"という名前のPythonモジュール、つまりファイル`main.py`を意味します。そして `app` は **FastAPI** アプリケーションの変数名です。
+ * main:app`はPythonの`import`文と同じようなものだと想像できます:
+
+ ```Python
+ from main import app
+ ```
+
+ * つまり、`main:app`のコロンは、`from main import app`のPythonの`import`の部分と同じになります。
+
+* `--workers`: 使用するワーカー・プロセスの数で、それぞれがUvicornのワーカーを実行します。
+
+* `--worker-class`: ワーカー・プロセスで使用するGunicorn互換のワーカークラスです。
+ * ここではGunicornがインポートして使用できるクラスを渡します:
+
+ ```Python
+ import uvicorn.workers.UvicornWorker
+ ```
+
+* `--bind`: GunicornにリッスンするIPとポートを伝えます。コロン(`:`)でIPとポートを区切ります。
+ * Uvicornを直接実行している場合は、`--bind 0.0.0.0:80` (Gunicornのオプション)の代わりに、`--host 0.0.0.0`と `--port 80`を使います。
+
+出力では、各プロセスの**PID**(プロセスID)が表示されているのがわかります(単なる数字です)。
+
+以下の通りです:
+
+* Gunicornの**プロセス・マネージャー**はPID `19499`(あなたの場合は違う番号でしょう)で始まります。
+* 次に、`Listening at: http://0.0.0.0:80`を開始します。
+* それから `uvicorn.workers.UvicornWorker` でワーカークラスを使用することを検出します。
+* そして、**4つのワーカー**を起動します。それぞれのワーカーのPIDは、`19511`、`19513`、`19514`、`19515`です。
+
+Gunicornはまた、ワーカーの数を維持するために必要であれば、**ダウンしたプロセス**を管理し、**新しいプロセスを**再起動**させます。そのため、上記のリストにある**再起動**の概念に一部役立ちます。
+
+しかしながら、必要であればGunicornを**再起動**させ、**起動時に実行**させるなど、外部のコンポーネントを持たせることも必要かもしれません。
+
+## Uvicornとワーカー
+
+Uvicornには複数の**ワーカー・プロセス**を起動し実行するオプションもあります。
+
+とはいうものの、今のところUvicornのワーカー・プロセスを扱う機能はGunicornよりも制限されています。そのため、このレベル(Pythonレベル)でプロセスマネージャーを持ちたいのであれば、Gunicornをプロセスマネージャーとして使ってみた方が賢明かもしれないです。
+
+どんな場合であれ、以下のように実行します:
+
+
+
+```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.
+```
+
+
+
+ここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカー・プロセスを起動するように指示しています。
+
+各プロセスの **PID** が表示され、親プロセスの `27365` (これは **プロセスマネージャ**) と、各ワーカー・プロセスの **PID** が表示されます: `27368`、`27369`、`27370`、`27367`になります。
+
+## デプロイメントのコンセプト
+
+ここでは、アプリケーションの実行を**並列化**し、CPUの**マルチコア**を活用し、**より多くのリクエスト**に対応できるようにするために、**Gunicorn**(またはUvicorn)を使用して**Uvicornワーカー・プロセス**を管理する方法を見ていきました。
+
+上記のデプロイのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれます:
+
+* セキュリティ - HTTPS
+* 起動時の実行
+* 再起動
+* レプリケーション(実行中のプロセス数)
+* メモリー
+* 開始前の事前のステップ
+
+
+## コンテナとDocker
+
+次章の[コンテナ内のFastAPI - Docker](./docker.md){.internal-link target=_blank}では、その他の**デプロイのコンセプト**を扱うために実施するであろう戦略をいくつか紹介します。
+
+また、**GunicornとUvicornワーカー**を含む**公式Dockerイメージ**と、簡単なケースに役立ついくつかのデフォルト設定も紹介します。
+
+また、(Gunicornを使わずに)Uvicornプロセスを1つだけ実行するために、**ゼロから独自のイメージを**構築する方法も紹介します。これは簡単なプロセスで、おそらく**Kubernetes**のような分散コンテナ管理システムを使うときにやりたいことでしょう。
+
+## まとめ
+
+Uvicornワーカーを使ったプロセスマネージャとして**Gunicorn**(またはUvicorn)を使えば、**マルチコアCPU**を活用して**複数のプロセスを並列実行**できます。
+
+これらのツールやアイデアは、**あなた自身のデプロイシステム**をセットアップしながら、他のデプロイコンセプトを自分で行う場合にも使えます。
+
+次の章では、コンテナ(DockerやKubernetesなど)を使った**FastAPI**について学んでいきましょう。これらのツールには、他の**デプロイのコンセプト**も解決する簡単な方法があることがわかるでしょう。✨
diff --git a/docs/ja/docs/external-links.md b/docs/ja/docs/external-links.md
index 6703f5fc2..aca5d5b34 100644
--- a/docs/ja/docs/external-links.md
+++ b/docs/ja/docs/external-links.md
@@ -9,70 +9,21 @@
!!! tip "豆知識"
ここにまだ載っていない**FastAPI**に関連する記事、プロジェクト、ツールなどがある場合は、
プルリクエストして下さい。
-## 記事
+{% for section_name, section_content in external_links.items() %}
-### 英語
+## {{ section_name }}
-{% if external_links %}
-{% for article in external_links.articles.english %}
+{% for lang_name, lang_content in section_content.items() %}
-*
{{ article.title }} by
{{ article.author }}.
-{% endfor %}
-{% endif %}
-
-### 日本語
-
-{% if external_links %}
-{% for article in external_links.articles.japanese %}
-
-*
{{ article.title }} by
{{ article.author }}.
-{% endfor %}
-{% endif %}
+### {{ lang_name }}
-### ベトナム語
+{% for item in lang_content %}
-{% if external_links %}
-{% for article in external_links.articles.vietnamese %}
+*
{{ item.title }} by
{{ item.author }}.
-*
{{ article.title }} by
{{ article.author }}.
{% endfor %}
-{% endif %}
-
-### ロシア語
-
-{% if external_links %}
-{% for article in external_links.articles.russian %}
-
-*
{{ article.title }} by
{{ article.author }}.
{% endfor %}
-{% endif %}
-
-### ドイツ語
-
-{% if external_links %}
-{% for article in external_links.articles.german %}
-
-*
{{ article.title }} by
{{ article.author }}.
-{% endfor %}
-{% endif %}
-
-## ポッドキャスト
-
-{% if external_links %}
-{% for article in external_links.podcasts.english %}
-
-*
{{ article.title }} by
{{ article.author }}.
-{% endfor %}
-{% endif %}
-
-## トーク
-
-{% if external_links %}
-{% for article in external_links.talks.english %}
-
-*
{{ article.title }} by
{{ article.author }}.
{% endfor %}
-{% endif %}
## プロジェクト
diff --git a/docs/ja/docs/features.md b/docs/ja/docs/features.md
index a40b48cf0..853364f11 100644
--- a/docs/ja/docs/features.md
+++ b/docs/ja/docs/features.md
@@ -24,7 +24,7 @@
### 現代的なPython
-FastAPIの機能はすべて、標準のPython 3.6型宣言に基づいています(Pydanticの功績)。新しい構文はありません。ただの現代的な標準のPythonです。
+FastAPIの機能はすべて、標準のPython 3.8型宣言に基づいています(Pydanticの功績)。新しい構文はありません。ただの現代的な標準のPythonです。
(FastAPIを使用しない場合でも)Pythonの型の使用方法について簡単な復習が必要な場合は、短いチュートリアル([Python Types](python-types.md){.internal-link target=_blank})を参照してください。
diff --git a/docs/ja/docs/help-fastapi.md b/docs/ja/docs/help-fastapi.md
index 166acb586..e753b7ce3 100644
--- a/docs/ja/docs/help-fastapi.md
+++ b/docs/ja/docs/help-fastapi.md
@@ -82,20 +82,6 @@ GitHubレポジトリで
https://gitter.im/tiangolo/fastapi.
-
-そこで、他の人と手早く会話したり、手助けやアイデアの共有などができます。
-
-しかし、「自由な会話」が許容されているので一般的すぎて回答が難しい質問もしやすくなります。そのせいで回答を得られないかもしれません。
-
-GitHub issuesでは良い回答を得やすい質問ができるように、もしくは、質問する前に自身で解決できるようにテンプレートがガイドしてくれます。そして、GitHubではたとえ時間がかかっても全てに答えているか確認できます。個人的にはGitterチャットでは同じことはできないです。😅
-
-Gitterでの会話はGitHubほど簡単に検索できないので、質問と回答が会話の中に埋もれてしまいます。
-
-一方、チャットには1000人以上いるので、いつでも話し相手が見つかる可能性が高いです。😄
-
## 開発者のスポンサーになる
GitHub sponsorsを通して開発者を経済的にサポートできます。
diff --git a/docs/ja/docs/advanced/conditional-openapi.md b/docs/ja/docs/how-to/conditional-openapi.md
similarity index 100%
rename from docs/ja/docs/advanced/conditional-openapi.md
rename to docs/ja/docs/how-to/conditional-openapi.md
diff --git a/docs/ja/docs/index.md b/docs/ja/docs/index.md
index a9c381a23..f340fdb87 100644
--- a/docs/ja/docs/index.md
+++ b/docs/ja/docs/index.md
@@ -107,7 +107,7 @@ FastAPI は、Pythonの標準である型ヒントに基づいてPython 3.6 以
## 必要条件
-Python 3.7+
+Python 3.8+
FastAPI は巨人の肩の上に立っています。
diff --git a/docs/ko/docs/async.md b/docs/ko/docs/async.md
new file mode 100644
index 000000000..47dbaa1b0
--- /dev/null
+++ b/docs/ko/docs/async.md
@@ -0,0 +1,404 @@
+# 동시성과 async / await
+
+*경로 작동 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경
+
+##
바쁘신 경우
+
+
요약
+
+다음과 같이 `await`를 사용해 호출하는 제3의 라이브러리를 사용하는 경우:
+
+```Python
+results = await some_library()
+```
+
+다음처럼 *경로 작동 함수*를 `async def`를 사용해 선언하십시오:
+
+```Python hl_lines="2"
+@app.get('/')
+async def read_results():
+ results = await some_library()
+ return results
+```
+
+!!! note "참고"
+ `async def`로 생성된 함수 내부에서만 `await`를 사용할 수 있습니다.
+
+---
+
+데이터베이스, API, 파일시스템 등과 의사소통하는 제3의 라이브러리를 사용하고, 그것이 `await`를 지원하지 않는 경우(현재 거의 모든 데이터베이스 라이브러리가 그러합니다), *경로 작동 함수*를 일반적인 `def`를 사용해 선언하십시오:
+
+```Python hl_lines="2"
+@app.get('/')
+def results():
+ results = some_library()
+ return results
+```
+
+---
+
+만약 당신의 응용프로그램이 (어째서인지) 다른 무엇과 의사소통하고 그것이 응답하기를 기다릴 필요가 없다면 `async def`를 사용하십시오.
+
+---
+
+모르겠다면, 그냥 `def`를 사용하십시오.
+
+---
+
+**참고**: *경로 작동 함수*에서 필요한만큼 `def`와 `async def`를 혼용할 수 있고, 가장 알맞은 것을 선택해서 정의할 수 있습니다. FastAPI가 자체적으로 알맞은 작업을 수행할 것입니다.
+
+어찌되었든, 상기 어떠한 경우라도, FastAPI는 여전히 비동기적으로 작동하고 매우 빠릅니다.
+
+그러나 상기 작업을 수행함으로써 어느 정도의 성능 최적화가 가능합니다.
+
+## 기술적 세부사항
+
+최신 파이썬 버전은 `async`와 `await` 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
+
+아래 섹션들에서 해당 문장을 부분별로 살펴보겠습니다:
+
+* **비동기 코드**
+* **`async`와 `await`**
+* **코루틴**
+
+## 비동기 코드
+
+비동기 코드란 언어 💬 가 코드의 어느 한 부분에서, 컴퓨터 / 프로그램🤖에게 *다른 무언가*가 어딘가에서 끝날 때까지 기다려야한다고 말하는 방식입니다. *다른 무언가*가 “느린-파일" 📝 이라고 불린다고 가정해봅시다.
+
+따라서 “느린-파일” 📝이 끝날때까지 컴퓨터는 다른 작업을 수행할 수 있습니다.
+
+그 다음 컴퓨터 / 프로그램 🤖 은 다시 기다리고 있기 때문에 기회가 있을 때마다 다시 돌아오거나, 혹은 당시에 수행해야하는 작업들이 완료될 때마다 다시 돌아옵니다. 그리고 그것 🤖 은 기다리고 있던 작업 중 어느 것이 이미 완료되었는지, 그것 🤖 이 해야하는 모든 작업을 수행하면서 확인합니다.
+
+다음으로, 그것 🤖 은 완료할 첫번째 작업에 착수하고(우리의 "느린-파일" 📝 이라고 가정합시다) 그에 대해 수행해야하는 작업을 계속합니다.
+
+"다른 무언가를 기다리는 것"은 일반적으로 비교적 "느린" (프로세서와 RAM 메모리 속도에 비해)
I/O 작업을 의미합니다. 예를 들면 다음의 것들을 기다리는 것입니다:
+
+* 네트워크를 통해 클라이언트로부터 전송되는 데이터
+* 네트워크를 통해 클라이언트가 수신할, 당신의 프로그램으로부터 전송되는 데이터
+* 시스템이 읽고 프로그램에 전달할 디스크 내의 파일 내용
+* 당신의 프로그램이 시스템에 전달하는, 디스크에 작성될 내용
+* 원격 API 작업
+* 완료될 데이터베이스 작업
+* 결과를 반환하는 데이터베이스 쿼리
+* 기타
+
+수행 시간의 대부분이
I/O 작업을 기다리는데에 소요되기 때문에, "I/O에 묶인" 작업이라고 불립니다.
+
+이것은 "비동기"라고 불리는데 컴퓨터 / 프로그램이 작업 결과를 가지고 일을 수행할 수 있도록, 느린 작업에 "동기화"되어 아무것도 하지 않으면서 작업이 완료될 정확한 시점만을 기다릴 필요가 없기 때문입니다.
+
+이 대신에, "비동기" 시스템에서는, 작업은 일단 완료되면, 컴퓨터 / 프로그램이 수행하고 있는 일을 완료하고 이후 다시 돌아와서 그것의 결과를 받아 이를 사용해 작업을 지속할 때까지 잠시 (몇 마이크로초) 대기할 수 있습니다.
+
+"동기"("비동기"의 반대)는 컴퓨터 / 프로그램이 상이한 작업들간 전환을 하기 전에 그것이 대기를 동반하게 될지라도 모든 순서를 따르기 때문에 "순차"라는 용어로도 흔히 불립니다.
+
+### 동시성과 버거
+
+위에서 설명한 **비동기** 코드에 대한 개념은 종종 **"동시성"**이라고도 불립니다. 이것은 **"병렬성"**과는 다릅니다.
+
+**동시성**과 **병렬성**은 모두 "동시에 일어나는 서로 다른 일들"과 관련이 있습니다.
+
+하지만 *동시성*과 *병렬성*의 세부적인 개념에는 꽤 차이가 있습니다.
+
+차이를 확인하기 위해, 다음의 버거에 대한 이야기를 상상해보십시오:
+
+### 동시 버거
+
+당신은 짝사랑 상대 😍 와 패스트푸드 🍔 를 먹으러 갔습니다. 당신은 점원 💁 이 당신 앞에 있는 사람들의 주문을 받을 동안 줄을 서서 기다리고 있습니다.
+
+이제 당신의 순서가 되어서, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
+
+당신이 돈을 냅니다 💸.
+
+점원 💁 은 주방 👨🍳 에 요리를 하라고 전달하고, 따라서 그들은 당신의 버거 🍔 를 준비해야한다는 사실을 알게됩니다(그들이 지금은 당신 앞 고객들의 주문을 준비하고 있을지라도 말입니다).
+
+점원 💁 은 당신의 순서가 적힌 번호표를 줍니다.
+
+기다리는 동안, 당신은 짝사랑 상대 😍 와 함께 테이블을 고르고, 자리에 앉아 오랫동안 (당신이 주문한 버거는 꽤나 고급스럽기 때문에 준비하는데 시간이 조금 걸립니다 ✨🍔✨) 대화를 나눕니다.
+
+짝사랑 상대 😍 와 테이블에 앉아서 버거 🍔 를 기다리는 동안, 그 사람 😍 이 얼마나 멋지고, 사랑스럽고, 똑똑한지 감탄하며 시간을 보냅니다 ✨😍✨.
+
+짝사랑 상대 😍 와 기다리면서 얘기하는 동안, 때때로, 당신은 당신의 차례가 되었는지 보기 위해 카운터의 번호를 확인합니다.
+
+그러다 어느 순간, 당신의 차례가 됩니다. 카운터에 가서, 버거 🍔 를 받고, 테이블로 다시 돌아옵니다.
+
+당신과 짝사랑 상대 😍 는 버거 🍔 를 먹으며 좋은 시간을 보냅니다 ✨.
+
+---
+
+당신이 이 이야기에서 컴퓨터 / 프로그램 🤖 이라고 상상해보십시오.
+
+줄을 서서 기다리는 동안, 당신은 아무것도 하지 않고 😴 당신의 차례를 기다리며, 어떠한 "생산적인" 일도 하지 않습니다. 하지만 점원 💁 이 (음식을 준비하지는 않고) 주문을 받기만 하기 때문에 줄이 빨리 줄어들어서 괜찮습니다.
+
+그다음, 당신이 차례가 오면, 당신은 실제로 "생산적인" 일 🤓 을 합니다. 당신은 메뉴를 보고, 무엇을 먹을지 결정하고, 짝사랑 상대 😍 의 선택을 묻고, 돈을 내고 💸 , 맞는 카드를 냈는지 확인하고, 비용이 제대로 지불되었는지 확인하고, 주문이 제대로 들어갔는지 확인을 하는 작업 등등을 수행합니다.
+
+하지만 이후에는, 버거 🍔 를 아직 받지 못했음에도, 버거가 준비될 때까지 기다려야 🕙 하기 때문에 점원 💁 과의 작업은 "일시정지" ⏸ 상태입니다.
+
+하지만 번호표를 받고 카운터에서 나와 테이블에 앉으면, 당신은 짝사랑 상대 😍 와 그 "작업" ⏯ 🤓 에 번갈아가며 🔀 집중합니다. 그러면 당신은 다시 짝사랑 상대 😍 에게 작업을 거는 매우 "생산적인" 일 🤓 을 합니다.
+
+점원 💁 이 카운터 화면에 당신의 번호를 표시함으로써 "버거 🍔 가 준비되었습니다"라고 해도, 당신은 즉시 뛰쳐나가지는 않을 것입니다. 당신은 당신의 번호를 갖고있고, 다른 사람들은 그들의 번호를 갖고있기 때문에, 아무도 당신의 버거 🍔 를 훔쳐가지 않는다는 사실을 알기 때문입니다.
+
+그래서 당신은 짝사랑 상대 😍 가 이야기를 끝낼 때까지 기다린 후 (현재 작업 완료 ⏯ / 진행 중인 작업 처리 🤓 ), 정중하게 미소짓고 버거를 가지러 가겠다고 말합니다 ⏸.
+
+그다음 당신은 카운터에 가서 🔀 , 초기 작업을 이제 완료하고 ⏯ , 버거 🍔 를 받고, 감사하다고 말하고 테이블로 가져옵니다. 이로써 카운터와의 상호작용 단계 / 작업이 종료됩니다 ⏹.
+
+이전 작업인 "버거 받기"가 종료되면 ⏹ "버거 먹기"라는 새로운 작업이 생성됩니다 🔀 ⏯.
+
+### 병렬 버거
+
+이제 "동시 버거"가 아닌 "병렬 버거"를 상상해보십시오.
+
+당신은 짝사랑 상대 😍 와 함께 병렬 패스트푸드 🍔 를 먹으러 갔습니다.
+
+당신은 여러명(8명이라고 가정합니다)의 점원이 당신 앞 사람들의 주문을 받으며 동시에 요리 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 도 하는 동안 줄을 서서 기다립니다.
+
+당신 앞 모든 사람들이 버거가 준비될 때까지 카운터에서 떠나지 않고 기다립니다 🕙 . 왜냐하면 8명의 직원들이 다음 주문을 받기 전에 버거를 준비하러 가기 때문입니다.
+
+마침내 당신의 차례가 왔고, 당신은 당신과 짝사랑 상대 😍 를 위한 두 개의 고급스러운 버거 🍔 를 주문합니다.
+
+당신이 비용을 지불합니다 💸 .
+
+점원이 주방에 갑니다 👨🍳 .
+
+당신은 번호표가 없기 때문에 누구도 당신의 버거 🍔 를 대신 가져갈 수 없도록 카운터에 서서 기다립니다 🕙 .
+
+당신과 짝사랑 상대 😍 는 다른 사람이 새치기해서 버거를 가져가지 못하게 하느라 바쁘기 때문에 🕙 , 짝사랑 상대에게 주의를 기울일 수 없습니다 😞 .
+
+이것은 "동기" 작업이고, 당신은 점원/요리사 👨🍳 와 "동기화" 되었습니다. 당신은 기다리고 🕙 , 점원/요리사 👨🍳 가 버거 🍔 준비를 완료한 후 당신에게 주거나, 누군가가 그것을 가져가는 그 순간에 그 곳에 있어야합니다.
+
+카운터 앞에서 오랫동안 기다린 후에 🕙 , 점원/요리사 👨🍳 가 당신의 버거 🍔 를 가지고 돌아옵니다.
+
+당신은 버거를 받고 짝사랑 상대와 함께 테이블로 돌아옵니다.
+
+단지 먹기만 하다가, 다 먹었습니다 🍔 ⏹.
+
+카운터 앞에서 기다리면서 🕙 너무 많은 시간을 허비했기 때문에 대화를 하거나 작업을 걸 시간이 거의 없었습니다 😞 .
+
+---
+
+이 병렬 버거 시나리오에서, 당신은 기다리고 🕙 , 오랜 시간동안 "카운터에서 기다리는" 🕙 데에 주의를 기울이는 ⏯ 두 개의 프로세서(당신과 짝사랑 상대😍)를 가진 컴퓨터 / 프로그램 🤖 입니다.
+
+패스트푸드점에는 8개의 프로세서(점원/요리사) 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 가 있습니다. 동시 버거는 단 두 개(한 명의 직원과 한 명의 요리사) 💁 👨🍳 만을 가지고 있었습니다.
+
+하지만 여전히, 병렬 버거 예시가 최선은 아닙니다 😞 .
+
+---
+
+이 예시는 버거🍔 이야기와 결이 같습니다.
+
+더 "현실적인" 예시로, 은행을 상상해보십시오.
+
+최근까지, 대다수의 은행에는 다수의 은행원들 👨💼👨💼👨💼👨💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있습니다.
+
+모든 은행원들은 한 명 한 명의 고객들을 차례로 상대합니다 👨💼⏯ .
+
+그리고 당신은 오랫동안 줄에서 기다려야하고 🕙 , 그렇지 않으면 당신의 차례를 잃게 됩니다.
+
+아마 당신은 은행 🏦 심부름에 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다.
+
+### 버거 예시의 결론
+
+"짝사랑 상대와의 패스트푸드점 버거" 시나리오에서, 오랜 기다림 🕙 이 있기 때문에 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 더 합리적입니다.
+
+대다수의 웹 응용프로그램의 경우가 그러합니다.
+
+매우 많은 수의 유저가 있지만, 서버는 그들의 요청을 전송하기 위해 그닥-좋지-않은 연결을 기다려야 합니다 🕙 .
+
+그리고 응답이 돌아올 때까지 다시 기다려야 합니다 🕙 .
+
+이 "기다림" 🕙 은 마이크로초 단위이지만, 모두 더해지면, 결국에는 매우 긴 대기시간이 됩니다.
+
+따라서 웹 API를 위해 비동기 ⏸🔀⏯ 코드를 사용하는 것이 합리적입니다.
+
+대부분의 존재하는 유명한 파이썬 프레임워크 (Flask와 Django 등)은 새로운 비동기 기능들이 파이썬에 존재하기 전에 만들어졌습니다. 그래서, 그들의 배포 방식은 병렬 실행과 새로운 기능만큼 강력하지는 않은 예전 버전의 비동기 실행을 지원합니다.
+
+비동기 웹 파이썬(ASGI)에 대한 주요 명세가 웹소켓을 지원하기 위해 Django에서 개발 되었음에도 그렇습니다.
+
+이러한 종류의 비동기성은 (NodeJS는 병렬적이지 않음에도) NodeJS가 사랑받는 이유이고, 프로그래밍 언어로서의 Go의 강점입니다.
+
+그리고 **FastAPI**를 사용함으로써 동일한 성능을 낼 수 있습니다.
+
+또한 병렬성과 비동기성을 동시에 사용할 수 있기 때문에, 대부분의 테스트가 완료된 NodeJS 프레임워크보다 더 높은 성능을 얻고 C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다
(모두 Starlette 덕분입니다).
+
+### 동시성이 병렬성보다 더 나은가?
+
+그렇지 않습니다! 그것이 이야기의 교훈은 아닙니다.
+
+동시성은 병렬성과 다릅니다. 그리고 그것은 많은 대기를 필요로하는 **특정한** 시나리오에서는 더 낫습니다. 이로 인해, 웹 응용프로그램 개발에서 동시성이 병렬성보다 일반적으로 훨씬 낫습니다. 하지만 모든 경우에 그런 것은 아닙니다.
+
+따라서, 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보십시오:
+
+> 당신은 크고, 더러운 집을 청소해야합니다.
+
+*네, 이게 전부입니다*.
+
+---
+
+어디에도 대기 🕙 는 없고, 집안 곳곳에서 해야하는 많은 작업들만 있습니다.
+
+버거 예시처럼 처음에는 거실, 그 다음은 부엌과 같은 식으로 순서를 정할 수도 있으나, 무엇도 기다리지 🕙 않고 계속해서 청소 작업만 수행하기 때문에, 순서는 아무런 영향을 미치지 않습니다.
+
+순서가 있든 없든 동일한 시간이 소요될 것이고(동시성) 동일한 양의 작업을 하게 될 것입니다.
+
+하지만 이 경우에서, 8명의 전(前)-점원/요리사이면서-현(現)-청소부 👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳👩🍳👨🍳 를 고용할 수 있고, 그들 각자(그리고 당신)가 집의 한 부분씩 맡아 청소를 한다면, 당신은 **병렬적**으로 작업을 수행할 수 있고, 조금의 도움이 있다면, 훨씬 더 빨리 끝낼 수 있습니다.
+
+이 시나리오에서, (당신을 포함한) 각각의 청소부들은 프로세서가 될 것이고, 각자의 역할을 수행합니다.
+
+실행 시간의 대부분이 대기가 아닌 실제 작업에 소요되고, 컴퓨터에서 작업은
CPU에서 이루어지므로, 이러한 문제를 "CPU에 묶였"다고 합니다.
+
+---
+
+CPU에 묶인 연산에 관한 흔한 예시는 복잡한 수학 처리를 필요로 하는 경우입니다.
+
+예를 들어:
+
+* **오디오** 또는 **이미지** 처리.
+* **컴퓨터 비전**: 하나의 이미지는 수백개의 픽셀로 구성되어있고, 각 픽셀은 3개의 값 / 색을 갖고 있으며, 일반적으로 해당 픽셀들에 대해 동시에 무언가를 계산해야하는 처리.
+* **머신러닝**: 일반적으로 많은 "행렬"과 "벡터" 곱셈이 필요합니다. 거대한 스프레드 시트에 수들이 있고 그 수들을 동시에 곱해야 한다고 생각해보십시오.
+* **딥러닝**: 머신러닝의 하위영역으로, 동일한 예시가 적용됩니다. 단지 이 경우에는 하나의 스프레드 시트에 곱해야할 수들이 있는 것이 아니라, 거대한 세트의 스프레드 시트들이 있고, 많은 경우에, 이 모델들을 만들고 사용하기 위해 특수한 프로세서를 사용합니다.
+
+### 동시성 + 병렬성: 웹 + 머신러닝
+
+**FastAPI**를 사용하면 웹 개발에서는 매우 흔한 동시성의 이점을 (NodeJS의 주된 매력만큼) 얻을 수 있습니다.
+
+뿐만 아니라 머신러닝 시스템과 같이 **CPU에 묶인** 작업을 위해 병렬성과 멀티프로세싱(다수의 프로세스를 병렬적으로 동작시키는 것)을 이용하는 것도 가능합니다.
+
+파이썬이 **데이터 사이언스**, 머신러닝과 특히 딥러닝에 의 주된 언어라는 간단한 사실에 더해서, 이것은 FastAPI를 데이터 사이언스 / 머신러닝 웹 API와 응용프로그램에 (다른 것들보다) 좋은 선택지가 되게 합니다.
+
+배포시 병렬을 어떻게 가능하게 하는지 알고싶다면, [배포](/ko/deployment){.internal-link target=_blank}문서를 참고하십시오.
+
+## `async`와 `await`
+
+최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이는 이것을 평범한 "순차적" 코드로 보이게 하고, 적절한 순간에 당신을 위해 "대기"합니다.
+
+연산이 결과를 전달하기 전에 대기를 해야하고 새로운 파이썬 기능들을 지원한다면, 이렇게 코드를 작성할 수 있습니다:
+
+```Python
+burgers = await get_burgers(2)
+```
+
+여기서 핵심은 `await`입니다. 이것은 파이썬에게 `burgers` 결과를 저장하기 이전에 `get_burgers(2)`의 작업이 완료되기를 🕙 기다리라고 ⏸ 말합니다. 이로 인해, 파이썬은 그동안 (다른 요청을 받는 것과 같은) 다른 작업을 수행해도 된다는 것을 🔀 ⏯ 알게될 것입니다.
+
+`await`가 동작하기 위해, 이것은 비동기를 지원하는 함수 내부에 있어야 합니다. 이를 위해서 함수를 `async def`를 사용해 정의하기만 하면 됩니다:
+
+```Python hl_lines="1"
+async def get_burgers(number: int):
+ # Do some asynchronous stuff to create the burgers
+ return burgers
+```
+
+...`def`를 사용하는 대신:
+
+```Python hl_lines="2"
+# This is not asynchronous
+def get_sequential_burgers(number: int):
+ # Do some sequential stuff to create the burgers
+ return burgers
+```
+
+`async def`를 사용하면, 파이썬은 해당 함수 내에서 `await` 표현에 주의해야한다는 사실과, 해당 함수의 실행을 "일시정지"⏸하고 다시 돌아오기 전까지 다른 작업을 수행🔀할 수 있다는 것을 알게됩니다.
+
+`async def`f 함수를 호출하고자 할 때, "대기"해야합니다. 따라서, 아래는 동작하지 않습니다.
+
+```Python
+# This won't work, because get_burgers was defined with: async def
+burgers = get_burgers(2)
+```
+
+---
+
+따라서, `await`f를 사용해서 호출할 수 있는 라이브러리를 사용한다면, 다음과 같이 `async def`를 사용하는 *경로 작동 함수*를 생성해야 합니다:
+
+```Python hl_lines="2-3"
+@app.get('/burgers')
+async def read_burgers():
+ burgers = await get_burgers(2)
+ return burgers
+```
+
+### 더 세부적인 기술적 사항
+
+`await`가 `async def`를 사용하는 함수 내부에서만 사용이 가능하다는 것을 눈치채셨을 것입니다.
+
+하지만 동시에, `async def`로 정의된 함수들은 "대기"되어야만 합니다. 따라서, `async def`를 사용한 함수들은 역시 `async def`를 사용한 함수 내부에서만 호출될 수 있습니다.
+
+그렇다면 닭이 먼저냐, 달걀이 먼저냐, 첫 `async` 함수를 어떻게 호출할 수 있겠습니까?
+
+**FastAPI**를 사용해 작업한다면 이것을 걱정하지 않아도 됩니다. 왜냐하면 그 "첫" 함수는 당신의 *경로 작동 함수*가 될 것이고, FastAPI는 어떻게 올바르게 처리할지 알고있기 때문입니다.
+
+하지만 FastAPI를 사용하지 않고 `async` / `await`를 사용하고 싶다면, 이 역시 가능합니다.
+
+### 당신만의 비동기 코드 작성하기
+
+Starlette(그리고 FastAPI)는
AnyIO를 기반으로 하고있고, 따라서 파이썬 표준 라이브러리인
asyncio 및
Trio와 호환됩니다.
+
+특히, 코드에서 고급 패턴이 필요한 고급 동시성을 사용하는 경우 직접적으로
AnyIO를 사용할 수 있습니다.
+
+FastAPI를 사용하지 않더라도, 높은 호환성 및
AnyIO의 이점(예: *구조화된 동시성*)을 취하기 위해
AnyIO를 사용해 비동기 응용프로그램을 작성할 수 있습니다.
+
+### 비동기 코드의 다른 형태
+
+파이썬에서 `async`와 `await`를 사용하게 된 것은 비교적 최근의 일입니다.
+
+하지만 이로 인해 비동기 코드 작업이 훨씬 간단해졌습니다.
+
+같은 (또는 거의 유사한) 문법은 최신 버전의 자바스크립트(브라우저와 NodeJS)에도 추가되었습니다.
+
+하지만 그 이전에, 비동기 코드를 처리하는 것은 꽤 복잡하고 어려운 일이었습니다.
+
+파이썬의 예전 버전이라면, 스레드 또는
Gevent를 사용할 수 있을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는게 훨씬 복잡합니다.
+
+예전 버전의 NodeJS / 브라우저 자바스크립트라면, "콜백 함수"를 사용했을 것입니다. 그리고 이로 인해
콜백 지옥에 빠지게 될 수 있습니다.
+
+## 코루틴
+
+**코루틴**은 `async def` 함수가 반환하는 것을 칭하는 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 시작되고 어느 시점에서 완료되지만 내부에 `await`가 있을 때마다 내부적으로 일시정지⏸될 수도 있는 함수와 유사한 것이라는 사실을 알고있습니다.
+
+그러나 `async` 및 `await`와 함께 비동기 코드를 사용하는 이 모든 기능들은 "코루틴"으로 간단히 요약됩니다. 이것은 Go의 주된 핵심 기능인 "고루틴"에 견줄 수 있습니다.
+
+## 결론
+
+상기 문장을 다시 한 번 봅시다:
+
+> 최신 파이썬 버전은 **`async` 및 `await`** 문법과 함께 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 지원합니다.
+
+이제 이 말을 조금 더 이해할 수 있을 것입니다. ✨
+
+이것이 (Starlette을 통해) FastAPI를 강하게 하면서 그것이 인상적인 성능을 낼 수 있게 합니다.
+
+## 매우 세부적인 기술적 사항
+
+!!! warning "경고"
+ 이 부분은 넘어가도 됩니다.
+
+ 이것들은 **FastAPI**가 내부적으로 어떻게 동작하는지에 대한 매우 세부적인 기술사항입니다.
+
+ 만약 기술적 지식(코루틴, 스레드, 블록킹 등)이 있고 FastAPI가 어떻게 `async def` vs `def`를 다루는지 궁금하다면, 계속하십시오.
+
+### 경로 작동 함수
+
+경로 작동 함수를 `async def` 대신 일반적인 `def`로 선언하는 경우, (서버를 차단하는 것처럼) 그것을 직접 호출하는 대신 대기중인 외부 스레드풀에서 실행됩니다.
+
+만약 상기에 묘사된대로 동작하지 않는 비동기 프로그램을 사용해왔고 약간의 성능 향상 (약 100 나노초)을 위해 `def`를 사용해서 계산만을 위한 사소한 *경로 작동 함수*를 정의해왔다면, **FastAPI**는 이와는 반대라는 것에 주의하십시오. 이러한 경우에, *경로 작동 함수*가 블로킹
I/O를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다.
+
+하지만 두 경우 모두, FastAPI가 당신이 전에 사용하던 프레임워크보다 [더 빠를](/#performance){.internal-link target=_blank} (최소한 비견될) 확률이 높습니다.
+
+### 의존성
+
+의존성에도 동일하게 적용됩니다. 의존성이 `async def`가 아닌 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다.
+
+### 하위-의존성
+
+함수 정의시 매개변수로 서로를 필요로하는 다수의 의존성과 하위-의존성을 가질 수 있고, 그 중 일부는 `async def`로, 다른 일부는 일반적인 `def`로 생성되었을 수 있습니다. 이것은 여전히 잘 동작하고, 일반적인 `def`로 생성된 것들은 "대기"되는 대신에 (스레드풀로부터) 외부 스레드에서 호출됩니다.
+
+### 다른 유틸리티 함수
+
+직접 호출되는 다른 모든 유틸리티 함수는 일반적인 `def`나 `async def`로 생성될 수 있고 FastAPI는 이를 호출하는 방식에 영향을 미치지 않습니다.
+
+이것은 FastAPI가 당신을 위해 호출하는 함수와는 반대입니다: *경로 작동 함수*와 의존성
+
+만약 당신의 유틸리티 함수가 `def`를 사용한 일반적인 함수라면, 스레드풀에서가 아니라 직접 호출(당신이 코드에 작성한 대로)될 것이고, `async def`로 생성된 함수라면 코드에서 호출할 때 그 함수를 `await` 해야 합니다.
+
+---
+
+다시 말하지만, 이것은 당신이 이것에 대해 찾고있던 경우에 한해 유용할 매우 세부적인 기술사항입니다.
+
+그렇지 않은 경우, 상기의 가이드라인만으로도 충분할 것입니다: [바쁘신 경우](#in-a-hurry).
diff --git a/docs/ko/docs/deployment/cloud.md b/docs/ko/docs/deployment/cloud.md
new file mode 100644
index 000000000..f2b965a91
--- /dev/null
+++ b/docs/ko/docs/deployment/cloud.md
@@ -0,0 +1,17 @@
+# FastAPI를 클라우드 제공업체에서 배포하기
+
+사실상 거의 **모든 클라우드 제공업체**를 사용하여 여러분의 FastAPI 애플리케이션을 배포할 수 있습니다.
+
+대부분의 경우, 주요 클라우드 제공업체에서는 FastAPI를 배포할 수 있도록 가이드를 제공합니다.
+
+## 클라우드 제공업체 - 후원자들
+
+몇몇 클라우드 제공업체들은 [**FastAPI를 후원하며**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, 이를 통해 FastAPI와 FastAPI **생태계**가 지속적이고 건전한 **발전**을 할 수 있습니다.
+
+이는 FastAPI와 **커뮤니티** (여러분)에 대한 진정한 헌신을 보여줍니다. 그들은 여러분에게 **좋은 서비스**를 제공할 뿐 만이 아니라 여러분이 **훌륭하고 건강한 프레임워크인** FastAPI 를 사용하길 원하기 때문입니다. 🙇
+
+아래와 같은 서비스를 사용해보고 각 서비스의 가이드를 따를 수도 있습니다:
+
+*
Platform.sh
+*
Porter
+*
Deta
diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md
index a6991a9b8..7ce938106 100644
--- a/docs/ko/docs/index.md
+++ b/docs/ko/docs/index.md
@@ -107,7 +107,7 @@ FastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트
## 요구사항
-Python 3.7+
+Python 3.8+
FastAPI는 거인들의 어깨 위에 서 있습니다:
diff --git a/docs/pl/docs/features.md b/docs/pl/docs/features.md
index 49d362dd9..ed10af9bc 100644
--- a/docs/pl/docs/features.md
+++ b/docs/pl/docs/features.md
@@ -25,7 +25,7 @@ Interaktywna dokumentacja i webowe interfejsy do eksploracji API. Z racji tego,
### Nowoczesny Python
-Wszystko opiera się na standardowych deklaracjach typu **Python 3.6** (dzięki Pydantic). Brak nowej składni do uczenia. Po prostu standardowy, współczesny Python.
+Wszystko opiera się na standardowych deklaracjach typu **Python 3.8** (dzięki Pydantic). Brak nowej składni do uczenia. Po prostu standardowy, współczesny Python.
Jeśli potrzebujesz szybkiego przypomnienia jak używać deklaracji typów w Pythonie (nawet jeśli nie używasz FastAPI), sprawdź krótki samouczek: [Python Types](python-types.md){.internal-link target=_blank}.
diff --git a/docs/pl/docs/help-fastapi.md b/docs/pl/docs/help-fastapi.md
new file mode 100644
index 000000000..3d02a8741
--- /dev/null
+++ b/docs/pl/docs/help-fastapi.md
@@ -0,0 +1,263 @@
+# Pomóż FastAPI - Uzyskaj pomoc
+
+Czy podoba Ci się **FastAPI**?
+
+Czy chciałbyś pomóc FastAPI, jego użytkownikom i autorowi?
+
+Może napotkałeś na trudności z **FastAPI** i potrzebujesz pomocy?
+
+Istnieje kilka bardzo łatwych sposobów, aby pomóc (czasami wystarczy jedno lub dwa kliknięcia).
+
+Istnieje również kilka sposobów uzyskania pomocy.
+
+## Zapisz się do newslettera
+
+Możesz zapisać się do rzadkiego [newslettera o **FastAPI i jego przyjaciołach**](/newsletter/){.internal-link target=_blank}, aby być na bieżąco z:
+
+* Aktualnościami o FastAPI i przyjaciołach 🚀
+* Przewodnikami 📝
+* Funkcjami ✨
+* Przełomowymi zmianami 🚨
+* Poradami i sztuczkami ✅
+
+## Śledź FastAPI na Twitterze
+
+
Śledź @fastapi na **Twitterze** aby być na bieżąco z najnowszymi wiadomościami o **FastAPI**. 🐦
+
+## Dodaj gwiazdkę **FastAPI** na GitHubie
+
+Możesz "dodać gwiazdkę" FastAPI na GitHubie (klikając przycisk gwiazdki w prawym górnym rogu):
https://github.com/tiangolo/fastapi. ⭐️
+
+Dodając gwiazdkę, inni użytkownicy będą mogli łatwiej znaleźć projekt i zobaczyć, że był już przydatny dla innych.
+
+## Obserwuj repozytorium GitHub w poszukiwaniu nowych wydań
+
+Możesz "obserwować" FastAPI na GitHubie (klikając przycisk "obserwuj" w prawym górnym rogu):
https://github.com/tiangolo/fastapi. 👀
+
+Wybierz opcję "Tylko wydania".
+
+Dzięki temu będziesz otrzymywać powiadomienia (na swój adres e-mail) za każdym razem, gdy pojawi się nowe wydanie (nowa wersja) **FastAPI** z poprawkami błędów i nowymi funkcjami.
+
+## Skontaktuj się z autorem
+
+Możesz skontaktować się
ze mną (Sebastián Ramírez / `tiangolo`), autorem.
+
+Możesz:
+
+*
Śledzić mnie na **GitHubie**.
+ * Zobacz inne projekty open source, które stworzyłem, a mogą być dla Ciebie pomocne.
+ * Śledź mnie, aby dostać powiadomienie, gdy utworzę nowy projekt open source.
+*
Śledzić mnie na **Twitterze** lub na
Mastodonie.
+ * Napisz mi, w jaki sposób korzystasz z FastAPI (uwielbiam o tym czytać).
+ * Dowiedz się, gdy ogłoszę coś nowego lub wypuszczę nowe narzędzia.
+ * Możesz także
śledzić @fastapi na Twitterze (to oddzielne konto).
+*
Nawiąż ze mną kontakt na **Linkedinie**.
+ * Dowiedz się, gdy ogłoszę coś nowego lub wypuszczę nowe narzędzia (chociaż częściej korzystam z Twittera 🤷♂).
+* Czytaj moje posty (lub śledź mnie) na
**Dev.to** lub na
**Medium**.
+ * Czytaj o innych pomysłach, artykułach i dowiedz się o narzędziach, które stworzyłem.
+ * Śledź mnie, by wiedzieć gdy opublikuję coś nowego.
+
+## Napisz tweeta o **FastAPI**
+
+
Napisz tweeta o **FastAPI** i powiedz czemu Ci się podoba. 🎉
+
+Uwielbiam czytać w jaki sposób **FastAPI** jest używane, co Ci się w nim podobało, w jakim projekcie/firmie go używasz itp.
+
+## Głosuj na FastAPI
+
+*
Głosuj na **FastAPI** w Slant.
+*
Głosuj na **FastAPI** w AlternativeTo.
+*
Powiedz, że używasz **FastAPI** na StackShare.
+
+## Pomagaj innym, odpowiadając na ich pytania na GitHubie
+
+Możesz spróbować pomóc innym, odpowiadając w:
+
+*
Dyskusjach na GitHubie
+*
Problemach na GitHubie
+
+W wielu przypadkach możesz już znać odpowiedź na te pytania. 🤓
+
+Jeśli pomożesz wielu ludziom, możesz zostać oficjalnym [Ekspertem FastAPI](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
+
+Pamiętaj tylko o najważniejszym: bądź życzliwy. Ludzie przychodzą sfrustrowani i w wielu przypadkach nie zadają pytań w najlepszy sposób, ale mimo to postaraj się być dla nich jak najbardziej życzliwy. 🤗
+
+Chciałbym, by społeczność **FastAPI** była życzliwa i przyjazna. Nie akceptuj prześladowania ani braku szacunku wobec innych. Dbajmy o siebie nawzajem.
+
+---
+
+Oto, jak pomóc innym z pytaniami (w dyskusjach lub problemach):
+
+### Zrozum pytanie
+
+* Upewnij się, czy rozumiesz **cel** i przypadek użycia osoby pytającej.
+
+* Następnie sprawdź, czy pytanie (większość to pytania) jest **jasne**.
+
+* W wielu przypadkach zadane pytanie dotyczy rozwiązania wymyślonego przez użytkownika, ale może istnieć **lepsze** rozwiązanie. Jeśli dokładnie zrozumiesz problem i przypadek użycia, być może będziesz mógł zaproponować lepsze **alternatywne rozwiązanie**.
+
+* Jeśli nie rozumiesz pytania, poproś o więcej **szczegółów**.
+
+### Odtwórz problem
+
+W większości przypadków problem wynika z **autorskiego kodu** osoby pytającej.
+
+Często pytający umieszczają tylko fragment kodu, niewystarczający do **odtworzenia problemu**.
+
+* Możesz poprosić ich o dostarczenie
minimalnego, odtwarzalnego przykładu, który możesz **skopiować i wkleić** i uruchomić lokalnie, aby zobaczyć ten sam błąd lub zachowanie, które widzą, lub lepiej zrozumieć ich przypadki użycia.
+
+* Jeśli jesteś wyjątkowo pomocny, możesz spróbować **stworzyć taki przykład** samodzielnie, opierając się tylko na opisie problemu. Miej na uwadze, że może to zająć dużo czasu i lepiej może być najpierw poprosić ich o wyjaśnienie problemu.
+
+### Proponuj rozwiązania
+
+* Po zrozumieniu pytania możesz podać im możliwą **odpowiedź**.
+
+* W wielu przypadkach lepiej zrozumieć ich **podstawowy problem lub przypadek użycia**, ponieważ może istnieć lepszy sposób rozwiązania niż to, co próbują zrobić.
+
+### Poproś o zamknięcie
+
+Jeśli odpowiedzą, jest duża szansa, że rozwiązałeś ich problem, gratulacje, **jesteś bohaterem**! 🦸
+
+* Jeśli Twoja odpowiedź rozwiązała problem, możesz poprosić o:
+
+ * W Dyskusjach na GitHubie: oznaczenie komentarza jako **odpowiedź**.
+ * W Problemach na GitHubie: **zamknięcie** problemu.
+
+## Obserwuj repozytorium na GitHubie
+
+Możesz "obserwować" FastAPI na GitHubie (klikając przycisk "obserwuj" w prawym górnym rogu):
https://github.com/tiangolo/fastapi. 👀
+
+Jeśli wybierzesz "Obserwuj" zamiast "Tylko wydania", otrzymasz powiadomienia, gdy ktoś utworzy nowy problem lub pytanie. Możesz również określić, że chcesz być powiadamiany tylko o nowych problemach, dyskusjach, PR-ach itp.
+
+Następnie możesz spróbować pomóc rozwiązać te problemy.
+
+## Zadawaj pytania
+
+Możesz
utworzyć nowe pytanie w repozytorium na GitHubie, na przykład aby:
+
+* Zadać **pytanie** lub zapytać o **problem**.
+* Zaproponować nową **funkcję**.
+
+**Uwaga**: jeśli to zrobisz, poproszę Cię również o pomoc innym. 😉
+
+## Przeglądaj Pull Requesty
+
+Możesz pomóc mi w przeglądaniu pull requestów autorstwa innych osób.
+
+Jak wcześniej wspomniałem, postaraj się być jak najbardziej życzliwy. 🤗
+
+---
+
+Oto, co warto mieć na uwadze podczas oceny pull requestu:
+
+### Zrozum problem
+
+* Najpierw upewnij się, że **rozumiesz problem**, który próbuje rozwiązać pull request. Może być osadzony w większym kontekście w GitHubowej dyskusji lub problemie.
+
+* Jest też duża szansa, że pull request nie jest konieczny, ponieważ problem można rozwiązać w **inny sposób**. Wtedy możesz to zasugerować lub o to zapytać.
+
+### Nie martw się stylem
+
+* Nie przejmuj się zbytnio rzeczami takimi jak style wiadomości commitów, przy wcielaniu pull requesta łączę commity i modyfikuję opis sumarycznego commita ręcznie.
+
+* Nie przejmuj się również stylem kodu, automatyczne narzędzia w repozytorium sprawdzają to samodzielnie.
+
+A jeśli istnieje jakaś konkretna potrzeba dotycząca stylu lub spójności, sam poproszę o zmiany lub dodam commity z takimi zmianami.
+
+### Sprawdź kod
+
+* Przeczytaj kod, zastanów się czy ma sens, **uruchom go lokalnie** i potwierdź czy faktycznie rozwiązuje problem.
+
+* Następnie dodaj **komentarz** z informacją o tym, że sprawdziłeś kod, dzięki temu będę miał pewność, że faktycznie go sprawdziłeś.
+
+!!! info
+ Niestety, nie mogę ślepo ufać PR-om, nawet jeśli mają kilka zatwierdzeń.
+
+ Kilka razy zdarzyło się, że PR-y miały 3, 5 lub więcej zatwierdzeń (prawdopodobnie dlatego, że opis obiecuje rozwiązanie ważnego problemu), ale gdy sam sprawdziłem danego PR-a, okazał się być zbugowany lub nie rozwiązywał problemu, który rzekomo miał rozwiązywać. 😅
+
+ Dlatego tak ważne jest, abyś faktycznie przeczytał i uruchomił kod oraz napisał w komentarzu, że to zrobiłeś. 🤓
+
+* Jeśli PR można uprościć w jakiś sposób, możesz o to poprosić, ale nie ma potrzeby być zbyt wybrednym, może być wiele subiektywnych punktów widzenia (a ja też będę miał swój 🙈), więc lepiej żebyś skupił się na kluczowych rzeczach.
+
+### Testy
+
+* Pomóż mi sprawdzić, czy PR ma **testy**.
+
+* Sprawdź, czy testy **nie przechodzą** przed PR. 🚨
+
+* Następnie sprawdź, czy testy **przechodzą** po PR. ✅
+
+* Wiele PR-ów nie ma testów, możesz **przypomnieć** im o dodaniu testów, a nawet **zaproponować** samemu jakieś testy. To jedna z rzeczy, które pochłaniają najwięcej czasu i możesz w tym bardzo pomóc.
+
+* Następnie skomentuj również to, czego spróbowałeś, wtedy będę wiedział, że to sprawdziłeś. 🤓
+
+## Utwórz Pull Request
+
+Możesz [wnieść wkład](contributing.md){.internal-link target=_blank} do kodu źródłowego za pomocą Pull Requestu, na przykład:
+
+* Naprawić literówkę, którą znalazłeś w dokumentacji.
+* Podzielić się artykułem, filmem lub podcastem, który stworzyłeś lub znalazłeś na temat FastAPI,
edytując ten plik.
+ * Upewnij się, że dodajesz swój link na początku odpowiedniej sekcji.
+* Pomóc w [tłumaczeniu dokumentacji](contributing.md#translations){.internal-link target=_blank} na Twój język.
+ * Możesz również pomóc w weryfikacji tłumaczeń stworzonych przez innych.
+* Zaproponować nowe sekcje dokumentacji.
+* Naprawić istniejący problem/błąd.
+ * Upewnij się, że dodajesz testy.
+* Dodać nową funkcję.
+ * Upewnij się, że dodajesz testy.
+ * Upewnij się, że dodajesz dokumentację, jeśli jest to istotne.
+
+## Pomóż w utrzymaniu FastAPI
+
+Pomóż mi utrzymać **FastAPI**! 🤓
+
+Jest wiele pracy do zrobienia, a w większości przypadków **TY** możesz to zrobić.
+
+Główne zadania, które możesz wykonać teraz to:
+
+* [Pomóc innym z pytaniami na GitHubie](#help-others-with-questions-in-github){.internal-link target=_blank} (zobacz sekcję powyżej).
+* [Oceniać Pull Requesty](#review-pull-requests){.internal-link target=_blank} (zobacz sekcję powyżej).
+
+Te dwie czynności **zajmują najwięcej czasu**. To główna praca związana z utrzymaniem FastAPI.
+
+Jeśli możesz mi w tym pomóc, **pomożesz mi utrzymać FastAPI** i zapewnisz że będzie **rozwijać się szybciej i lepiej**. 🚀
+
+## Dołącz do czatu
+
+Dołącz do 👥
serwera czatu na Discordzie 👥 i spędzaj czas z innymi w społeczności FastAPI.
+
+!!! wskazówka
+ Jeśli masz pytania, zadaj je w
Dyskusjach na GitHubie, jest dużo większa szansa, że otrzymasz pomoc od [Ekspertów FastAPI](fastapi-people.md#experts){.internal-link target=_blank}.
+
+ Używaj czatu tylko do innych ogólnych rozmów.
+
+### Nie zadawaj pytań na czacie
+
+Miej na uwadze, że ponieważ czaty pozwalają na bardziej "swobodną rozmowę", łatwo jest zadawać pytania, które są zbyt ogólne i trudniejsze do odpowiedzi, więc możesz nie otrzymać odpowiedzi.
+
+Na GitHubie szablon poprowadzi Cię do napisania odpowiedniego pytania, dzięki czemu łatwiej uzyskasz dobrą odpowiedź, a nawet rozwiążesz problem samodzielnie, zanim zapytasz. Ponadto na GitHubie mogę się upewnić, że zawsze odpowiadam na wszystko, nawet jeśli zajmuje to trochę czasu. Osobiście nie mogę tego zrobić z systemami czatu. 😅
+
+Rozmów w systemach czatu nie można tak łatwo przeszukiwać, jak na GitHubie, więc pytania i odpowiedzi mogą zaginąć w rozmowie. A tylko te na GitHubie liczą się do zostania [Ekspertem FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, więc najprawdopodobniej otrzymasz więcej uwagi na GitHubie.
+
+Z drugiej strony w systemach czatu są tysiące użytkowników, więc jest duża szansa, że znajdziesz tam kogoś do rozmowy, prawie w każdej chwili. 😄
+
+## Wspieraj autora
+
+Możesz również finansowo wesprzeć autora (mnie) poprzez
sponsoring na GitHubie.
+
+Tam możesz postawić mi kawę ☕️ aby podziękować. 😄
+
+Możesz także zostać srebrnym lub złotym sponsorem FastAPI. 🏅🎉
+
+## Wspieraj narzędzia, które napędzają FastAPI
+
+Jak widziałeś w dokumentacji, FastAPI stoi na ramionach gigantów, Starlette i Pydantic.
+
+Możesz również wesprzeć:
+
+*
Samuel Colvin (Pydantic)
+*
Encode (Starlette, Uvicorn)
+
+---
+
+Dziękuję! 🚀
diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md
index bade7a88c..43a20383c 100644
--- a/docs/pl/docs/index.md
+++ b/docs/pl/docs/index.md
@@ -106,7 +106,7 @@ Jeżeli tworzysz aplikacje
CLI<
## Wymagania
-Python 3.7+
+Python 3.8+
FastAPI oparty jest na:
@@ -321,7 +321,7 @@ Robisz to tak samo jak ze standardowymi typami w Pythonie.
Nie musisz sie uczyć żadnej nowej składni, metod lub klas ze specyficznych bibliotek itp.
-Po prostu standardowy **Python 3.6+**.
+Po prostu standardowy **Python 3.8+**.
Na przykład, dla danych typu `int`:
diff --git a/docs/pt/docs/deployment/deta.md b/docs/pt/docs/deployment/deta.md
deleted file mode 100644
index 9271bba42..000000000
--- a/docs/pt/docs/deployment/deta.md
+++ /dev/null
@@ -1,258 +0,0 @@
-# Implantação FastAPI na Deta
-
-Nessa seção você aprenderá sobre como realizar a implantação de uma aplicação **FastAPI** na Deta utilizando o plano gratuito. 🎁
-
-Isso tudo levará aproximadamente **10 minutos**.
-
-!!! info "Informação"
- Deta é uma patrocinadora do **FastAPI**. 🎉
-
-## Uma aplicação **FastAPI** simples
-
-* Crie e entre em um diretório para a sua aplicação, por exemplo, `./fastapideta/`.
-
-### Código FastAPI
-
-* Crie o arquivo `main.py` com:
-
-```Python
-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):
- return {"item_id": item_id}
-```
-
-### Requisitos
-
-Agora, no mesmo diretório crie o arquivo `requirements.txt` com:
-
-```text
-fastapi
-```
-
-!!! tip "Dica"
- Você não precisa instalar Uvicorn para realizar a implantação na Deta, embora provavelmente queira instalá-lo para testar seu aplicativo localmente.
-
-### Estrutura de diretório
-
-Agora você terá o diretório `./fastapideta/` com dois arquivos:
-
-```
-.
-└── main.py
-└── requirements.txt
-```
-
-## Crie uma conta gratuita na Deta
-
-Agora crie uma conta gratuita na Deta, você precisará apenas de um email e senha.
-
-Você nem precisa de um cartão de crédito.
-
-## Instale a CLI
-
-Depois de ter sua conta criada, instale Deta CLI:
-
-=== "Linux, macOS"
-
-
-
- ```console
- $ curl -fsSL https://get.deta.dev/cli.sh | sh
- ```
-
-
-
-=== "Windows PowerShell"
-
-
-
- ```console
- $ iwr https://get.deta.dev/cli.ps1 -useb | iex
- ```
-
-
-
-Após a instalação, abra um novo terminal para que a CLI seja detectada.
-
-Em um novo terminal, confirme se foi instalado corretamente com:
-
-
-
-```console
-$ deta --help
-
-Deta command line interface for managing deta micros.
-Complete documentation available at https://docs.deta.sh
-
-Usage:
- deta [flags]
- deta [command]
-
-Available Commands:
- auth Change auth settings for a deta micro
-
-...
-```
-
-
-
-!!! tip "Dica"
- Se você tiver problemas ao instalar a CLI, verifique a documentação oficial da Deta.
-
-## Login pela CLI
-
-Agora faça login na Deta pela CLI com:
-
-
-
-```console
-$ deta login
-
-Please, log in from the web page. Waiting..
-Logged in successfully.
-```
-
-
-
-Isso abrirá um navegador da Web e autenticará automaticamente.
-
-## Implantação com Deta
-
-Em seguida, implante seu aplicativo com a Deta CLI:
-
-
-
-```console
-$ deta new
-
-Successfully created a new micro
-
-// Notice the "endpoint" 🔍
-
-{
- "name": "fastapideta",
- "runtime": "python3.7",
- "endpoint": "https://qltnci.deta.dev",
- "visor": "enabled",
- "http_auth": "enabled"
-}
-
-Adding dependencies...
-
-
----> 100%
-
-
-Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6
-```
-
-
-
-Você verá uma mensagem JSON semelhante a:
-
-```JSON hl_lines="4"
-{
- "name": "fastapideta",
- "runtime": "python3.7",
- "endpoint": "https://qltnci.deta.dev",
- "visor": "enabled",
- "http_auth": "enabled"
-}
-```
-
-!!! tip "Dica"
- Sua implantação terá um URL `"endpoint"` diferente.
-
-## Confira
-
-Agora, abra seu navegador na URL do `endpoint`. No exemplo acima foi `https://qltnci.deta.dev`, mas o seu será diferente.
-
-Você verá a resposta JSON do seu aplicativo FastAPI:
-
-```JSON
-{
- "Hello": "World"
-}
-```
-
-Agora vá para o `/docs` da sua API, no exemplo acima seria `https://qltnci.deta.dev/docs`.
-
-Ele mostrará sua documentação como:
-
-
-
-## Permitir acesso público
-
-Por padrão, a Deta lidará com a autenticação usando cookies para sua conta.
-
-Mas quando estiver pronto, você pode torná-lo público com:
-
-
-
-```console
-$ deta auth disable
-
-Successfully disabled http auth
-```
-
-
-
-Agora você pode compartilhar essa URL com qualquer pessoa e elas conseguirão acessar sua API. 🚀
-
-## HTTPS
-
-Parabéns! Você realizou a implantação do seu app FastAPI na Deta! 🎉 🍰
-
-Além disso, observe que a Deta lida corretamente com HTTPS para você, para que você não precise cuidar disso e tenha a certeza de que seus clientes terão uma conexão criptografada segura. ✅ 🔒
-
-## Verifique o Visor
-
-Na UI da sua documentação (você estará em um URL como `https://qltnci.deta.dev/docs`) envie um request para *operação de rota* `/items/{item_id}`.
-
-Por exemplo com ID `5`.
-
-Agora vá para https://web.deta.sh.
-
-Você verá que há uma seção à esquerda chamada "Micros" com cada um dos seus apps.
-
-Você verá uma aba com "Detalhes", e também a aba "Visor", vá para "Visor".
-
-Lá você pode inspecionar as solicitações recentes enviadas ao seu aplicativo.
-
-Você também pode editá-los e reproduzi-los novamente.
-
-
-
-## Saiba mais
-
-Em algum momento, você provavelmente desejará armazenar alguns dados para seu aplicativo de uma forma que persista ao longo do tempo. Para isso você pode usar Deta Base, que também tem um generoso **nível gratuito**.
-
-Você também pode ler mais na documentação da Deta.
-
-## Conceitos de implantação
-
-Voltando aos conceitos que discutimos em [Deployments Concepts](./concepts.md){.internal-link target=_blank}, veja como cada um deles seria tratado com a Deta:
-
-* **HTTPS**: Realizado pela Deta, eles fornecerão um subdomínio e lidarão com HTTPS automaticamente.
-* **Executando na inicialização**: Realizado pela Deta, como parte de seu serviço.
-* **Reinicialização**: Realizado pela Deta, como parte de seu serviço.
-* **Replicação**: Realizado pela Deta, como parte de seu serviço.
-* **Memória**: Limite predefinido pela Deta, você pode contatá-los para aumentá-lo.
-* **Etapas anteriores a inicialização**: Não suportado diretamente, você pode fazê-lo funcionar com o sistema Cron ou scripts adicionais.
-
-!!! note "Nota"
- O Deta foi projetado para facilitar (e gratuitamente) a implantação rápida de aplicativos simples.
-
- Ele pode simplificar vários casos de uso, mas, ao mesmo tempo, não suporta outros, como o uso de bancos de dados externos (além do próprio sistema de banco de dados NoSQL da Deta), máquinas virtuais personalizadas, etc.
-
- Você pode ler mais detalhes na documentação da Deta para ver se é a escolha certa para você.
diff --git a/docs/pt/docs/external-links.md b/docs/pt/docs/external-links.md
index 6ec6c3a27..77ec32351 100644
--- a/docs/pt/docs/external-links.md
+++ b/docs/pt/docs/external-links.md
@@ -9,70 +9,21 @@ Aqui tem uma lista, incompleta, de algumas delas.
!!! tip "Dica"
Se você tem um artigo, projeto, ferramenta ou qualquer coisa relacionada ao **FastAPI** que ainda não está listada aqui, crie um _Pull Request_ adicionando ele.
-## Artigos
+{% for section_name, section_content in external_links.items() %}
-### Inglês
+## {{ section_name }}
-{% if external_links %}
-{% for article in external_links.articles.english %}
+{% for lang_name, lang_content in section_content.items() %}
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
-
-### Japonês
-
-{% if external_links %}
-{% for article in external_links.articles.japanese %}
-
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
+### {{ lang_name }}
-### Vietnamita
+{% for item in lang_content %}
-{% if external_links %}
-{% for article in external_links.articles.vietnamese %}
+* {{ item.title }} by {{ item.author }}.
-* {{ article.title }} by {{ article.author }}.
{% endfor %}
-{% endif %}
-
-### Russo
-
-{% if external_links %}
-{% for article in external_links.articles.russian %}
-
-* {{ article.title }} by {{ article.author }}.
{% endfor %}
-{% endif %}
-
-### Alemão
-
-{% if external_links %}
-{% for article in external_links.articles.german %}
-
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
-
-## Podcasts
-
-{% if external_links %}
-{% for article in external_links.podcasts.english %}
-
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
-
-## Palestras
-
-{% if external_links %}
-{% for article in external_links.talks.english %}
-
-* {{ article.title }} by {{ article.author }}.
{% endfor %}
-{% endif %}
## Projetos
diff --git a/docs/pt/docs/features.md b/docs/pt/docs/features.md
index bd0db8e76..822992c5b 100644
--- a/docs/pt/docs/features.md
+++ b/docs/pt/docs/features.md
@@ -25,7 +25,7 @@ Documentação interativa da API e navegação _web_ da interface de usuário. C
### Apenas Python moderno
-Tudo é baseado no padrão das declarações de **tipos do Python 3.6** (graças ao Pydantic). Nenhuma sintaxe nova para aprender. Apenas o padrão moderno do Python.
+Tudo é baseado no padrão das declarações de **tipos do Python 3.8** (graças ao Pydantic). Nenhuma sintaxe nova para aprender. Apenas o padrão moderno do Python.
Se você precisa refrescar a memória rapidamente sobre como usar tipos do Python (mesmo que você não use o FastAPI), confira esse rápido tutorial: [Tipos do Python](python-types.md){.internal-link target=_blank}.
diff --git a/docs/pt/docs/help-fastapi.md b/docs/pt/docs/help-fastapi.md
index d82ce3414..d04905197 100644
--- a/docs/pt/docs/help-fastapi.md
+++ b/docs/pt/docs/help-fastapi.md
@@ -114,8 +114,6 @@ do FastAPI.
Use o chat apenas para outro tipo de assunto.
-Também existe o chat do Gitter, porém ele não possuí canais e recursos avançados, conversas são mais engessadas, por isso o Discord é mais recomendado.
-
### Não faça perguntas no chat
Tenha em mente que os chats permitem uma "conversa mais livre", dessa forma é muito fácil fazer perguntas que são muito genéricas e dificeís de responder, assim você pode acabar não sendo respondido.
diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md
index 591e7f3d4..d1e64b3b9 100644
--- a/docs/pt/docs/index.md
+++ b/docs/pt/docs/index.md
@@ -24,7 +24,7 @@
---
-FastAPI é um moderno e rápido (alta performance) _framework web_ para construção de APIs com Python 3.6 ou superior, baseado nos _type hints_ padrões do Python.
+FastAPI é um moderno e rápido (alta performance) _framework web_ para construção de APIs com Python 3.8 ou superior, baseado nos _type hints_ padrões do Python.
Os recursos chave são:
@@ -100,7 +100,7 @@ Se você estiver construindo uma aplicação ../../../docs_src/body_multiple_params/tutorial001.py!}
@@ -44,7 +44,7 @@ Mas você pode também declarar múltiplos parâmetros de corpo, por exemplo, `i
{!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial002.py!}
@@ -87,7 +87,7 @@ Se você declará-lo como é, porque é um valor singular, o **FastAPI** assumir
Mas você pode instruir o **FastAPI** para tratá-lo como outra chave do corpo usando `Body`:
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial003.py!}
@@ -143,7 +143,7 @@ Por exemplo:
{!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="27"
{!> ../../../docs_src/body_multiple_params/tutorial004.py!}
@@ -172,7 +172,7 @@ como em:
{!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="17"
{!> ../../../docs_src/body_multiple_params/tutorial005.py!}
diff --git a/docs/pt/docs/tutorial/encoder.md b/docs/pt/docs/tutorial/encoder.md
index bb4483fdc..b9bfbf63b 100644
--- a/docs/pt/docs/tutorial/encoder.md
+++ b/docs/pt/docs/tutorial/encoder.md
@@ -26,7 +26,7 @@ A função recebe um objeto, como um modelo Pydantic e retorna uma versão compa
{!> ../../../docs_src/encoder/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="5 22"
{!> ../../../docs_src/encoder/tutorial001.py!}
diff --git a/docs/pt/docs/tutorial/extra-models.md b/docs/pt/docs/tutorial/extra-models.md
index dd5407eb2..1343a3ae4 100644
--- a/docs/pt/docs/tutorial/extra-models.md
+++ b/docs/pt/docs/tutorial/extra-models.md
@@ -17,7 +17,7 @@ Isso é especialmente o caso para modelos de usuários, porque:
Aqui está uma ideia geral de como os modelos poderiam parecer com seus campos de senha e os lugares onde são usados:
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
{!> ../../../docs_src/extra_models/tutorial001.py!}
@@ -158,7 +158,7 @@ Toda conversão de dados, validação, documentação, etc. ainda funcionará no
Dessa forma, podemos declarar apenas as diferenças entre os modelos (com `password` em texto claro, com `hashed_password` e sem senha):
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="9 15-16 19-20 23-24"
{!> ../../../docs_src/extra_models/tutorial002.py!}
@@ -181,7 +181,7 @@ Para fazer isso, use a dica de tipo padrão do Python `Union`, inclua o tipo mais específico primeiro, seguido pelo tipo menos específico. No exemplo abaixo, o tipo mais específico `PlaneItem` vem antes de `CarItem` em `Union[PlaneItem, CarItem]`.
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="1 14-15 18-20 33"
{!> ../../../docs_src/extra_models/tutorial003.py!}
@@ -213,7 +213,7 @@ Da mesma forma, você pode declarar respostas de listas de objetos.
Para isso, use o padrão Python `typing.List` (ou simplesmente `list` no Python 3.9 e superior):
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="1 20"
{!> ../../../docs_src/extra_models/tutorial004.py!}
@@ -233,7 +233,7 @@ Isso é útil se você não souber os nomes de campo / atributo válidos (que se
Neste caso, você pode usar `typing.Dict` (ou simplesmente dict no Python 3.9 e superior):
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="1 8"
{!> ../../../docs_src/extra_models/tutorial005.py!}
diff --git a/docs/pt/docs/tutorial/header-params.md b/docs/pt/docs/tutorial/header-params.md
index bc8843327..4bdfb7e9c 100644
--- a/docs/pt/docs/tutorial/header-params.md
+++ b/docs/pt/docs/tutorial/header-params.md
@@ -12,7 +12,7 @@ Primeiro importe `Header`:
{!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="3"
{!> ../../../docs_src/header_params/tutorial001.py!}
@@ -30,7 +30,7 @@ O primeiro valor é o valor padrão, você pode passar todas as validações adi
{!> ../../../docs_src/header_params/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial001.py!}
@@ -66,7 +66,7 @@ Se por algum motivo você precisar desabilitar a conversão automática de subli
{!> ../../../docs_src/header_params/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/header_params/tutorial002.py!}
@@ -97,7 +97,7 @@ Por exemplo, para declarar um cabeçalho de `X-Token` que pode aparecer mais de
{!> ../../../docs_src/header_params/tutorial003_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/header_params/tutorial003.py!}
diff --git a/docs/pt/docs/tutorial/path-operation-configuration.md b/docs/pt/docs/tutorial/path-operation-configuration.md
index e0a23f665..13a87240f 100644
--- a/docs/pt/docs/tutorial/path-operation-configuration.md
+++ b/docs/pt/docs/tutorial/path-operation-configuration.md
@@ -13,7 +13,7 @@ Você pode passar diretamente o código `int`, como `404`.
Mas se você não se lembrar o que cada código numérico significa, pode usar as constantes de atalho em `status`:
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
@@ -42,7 +42,7 @@ Esse código de status será usado na resposta e será adicionado ao esquema Ope
Você pode adicionar tags para sua *operação de rota*, passe o parâmetro `tags` com uma `list` de `str` (comumente apenas um `str`):
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
@@ -80,7 +80,7 @@ Nestes casos, pode fazer sentido armazenar as tags em um `Enum`.
Você pode adicionar um `summary` e uma `description`:
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
@@ -104,7 +104,7 @@ Como as descrições tendem a ser longas e cobrir várias linhas, você pode dec
Você pode escrever Markdown na docstring, ele será interpretado e exibido corretamente (levando em conta a indentação da docstring).
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
@@ -131,7 +131,7 @@ Ela será usada nas documentações interativas:
Você pode especificar a descrição da resposta com o parâmetro `response_description`:
-=== "Python 3.6 and above"
+=== "Python 3.8 and above"
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
diff --git a/docs/pt/docs/tutorial/path-params-numeric-validations.md b/docs/pt/docs/tutorial/path-params-numeric-validations.md
index ec9b74b30..eb0d31dc3 100644
--- a/docs/pt/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/pt/docs/tutorial/path-params-numeric-validations.md
@@ -12,7 +12,7 @@ Primeiro, importe `Path` de `fastapi`:
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="3"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
@@ -30,7 +30,7 @@ Por exemplo para declarar um valor de metadado `title` para o parâmetro de rota
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
diff --git a/docs/pt/docs/tutorial/path-params.md b/docs/pt/docs/tutorial/path-params.md
index 5de3756ed..cd8c18858 100644
--- a/docs/pt/docs/tutorial/path-params.md
+++ b/docs/pt/docs/tutorial/path-params.md
@@ -236,7 +236,6 @@ Então, você poderia usar ele com:
Com o **FastAPI**, usando as declarações de tipo do Python, você obtém:
* Suporte no editor: verificação de erros, e opção de autocompletar, etc.
-* Parsing de dados
* "Parsing" de dados
* Validação de dados
* Anotação da API e documentação automática
diff --git a/docs/pt/docs/tutorial/query-params.md b/docs/pt/docs/tutorial/query-params.md
index 3ada4fd21..08bb99dbc 100644
--- a/docs/pt/docs/tutorial/query-params.md
+++ b/docs/pt/docs/tutorial/query-params.md
@@ -69,7 +69,7 @@ Da mesma forma, você pode declarar parâmetros de consulta opcionais, definindo
{!> ../../../docs_src/query_params/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial002.py!}
@@ -91,7 +91,7 @@ Você também pode declarar tipos `bool`, e eles serão convertidos:
{!> ../../../docs_src/query_params/tutorial003_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial003.py!}
@@ -143,7 +143,7 @@ Eles serão detectados pelo nome:
{!> ../../../docs_src/query_params/tutorial004_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="8 10"
{!> ../../../docs_src/query_params/tutorial004.py!}
@@ -209,7 +209,7 @@ E claro, você pode definir alguns parâmetros como obrigatórios, alguns possui
{!> ../../../docs_src/query_params/tutorial006_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params/tutorial006.py!}
diff --git a/docs/ru/docs/deployment/docker.md b/docs/ru/docs/deployment/docker.md
new file mode 100644
index 000000000..f045ca944
--- /dev/null
+++ b/docs/ru/docs/deployment/docker.md
@@ -0,0 +1,700 @@
+# FastAPI и Docker-контейнеры
+
+При развёртывании приложений FastAPI, часто начинают с создания **образа контейнера на основе Linux**. Обычно для этого используют **Docker**. Затем можно развернуть такой контейнер на сервере одним из нескольких способов.
+
+Использование контейнеров на основе Linux имеет ряд преимуществ, включая **безопасность**, **воспроизводимость**, **простоту** и прочие.
+
+!!! tip "Подсказка"
+ Торопитесь или уже знакомы с этой технологией? Перепрыгните на раздел [Создать Docker-образ для FastAPI 👇](#docker-fastapi)
+
+
+Развернуть Dockerfile 👀
+
+```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 ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+
+# Если используете прокси-сервер, такой как Nginx или Traefik, добавьте --proxy-headers
+# CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--proxy-headers"]
+```
+
+
+
+## Что такое "контейнер"
+
+Контейнеризация - это **легковесный** способ упаковать приложение, включая все его зависимости и необходимые файлы, чтобы изолировать его от других контейнеров (других приложений и компонентов) работающих на этой же системе.
+
+Контейнеры, основанные на Linux, запускаются используя ядро Linux хоста (машины, виртуальной машины, облачного сервера и т.п.). Это значит, что они очень легковесные (по сравнению с полноценными виртуальными машинами, полностью эмулирующими работу операционной системы).
+
+Благодаря этому, контейнеры потребляют **малое количество ресурсов**, сравнимое с процессом запущенным напрямую (виртуальная машина потребует гораздо больше ресурсов).
+
+Контейнеры также имеют собственные запущенные **изолированные** процессы (но часто только один процесс), файловую систему и сеть, что упрощает развёртывание, разработку, управление доступом и т.п.
+
+## Что такое "образ контейнера"
+
+Для запуска **контейнера** нужен **образ контейнера**.
+
+Образ контейнера - это **замороженная** версия всех файлов, переменных окружения, программ и команд по умолчанию, необходимых для работы приложения. **Замороженный** - означает, что **образ** не запущен и не выполняется, это всего лишь упакованные вместе файлы и метаданные.
+
+В отличие от **образа контейнера**, хранящего неизменное содержимое, под термином **контейнер** подразумевают запущенный образ, то есть объёкт, который **исполняется**.
+
+Когда **контейнер** запущен (на основании **образа**), он может создавать и изменять файлы, переменные окружения и т.д. Эти изменения будут существовать только внутри контейнера, но не будут сохраняться в образе контейнера (не будут сохранены на диск).
+
+Образ контейнера можно сравнить с файлом, содержащем **программу**, например, как файл `main.py`.
+
+И **контейнер** (в отличие от **образа**) - это на самом деле выполняемый экземпляр образа, примерно как **процесс**. По факту, контейнер запущен только когда запущены его процессы (чаще, всего один процесс) и остановлен, когда запущенных процессов нет.
+
+## Образы контейнеров
+
+Docker является одним оз основных инструментов для создания **образов** и **контейнеров** и управления ими.
+
+Существует общедоступный Docker Hub с подготовленными **официальными образами** многих инструментов, окружений, баз данных и приложений.
+
+К примеру, есть официальный образ Python.
+
+Также там представлены и другие полезные образы, такие как базы данных:
+
+* PostgreSQL
+* MySQL
+* MongoDB
+* Redis
+
+и т.п.
+
+Использование подготовленных образов значительно упрощает **комбинирование** и использование разных инструментов. Например, Вы можете попытаться использовать новую базу данных. В большинстве случаев можно использовать **официальный образ** и всего лишь указать переменные окружения.
+
+Таким образом, Вы можете изучить, что такое контейнеризация и Docker, и использовать полученные знания с разными инструментами и компонентами.
+
+Так, Вы можете запустить одновременно **множество контейнеров** с базой данных, Python-приложением, веб-сервером, React-приложением и соединить их вместе через внутреннюю сеть.
+
+Все системы управления контейнерами (такие, как Docker или Kubernetes) имеют встроенные возможности для организации такого сетевого взаимодействия.
+
+## Контейнеры и процессы
+
+Обычно **образ контейнера** содержит метаданные предустановленной программы или команду, которую следует выполнить при запуске **контейнера**. Также он может содержать параметры, передаваемые предустановленной программе. Похоже на то, как если бы Вы запускали такую программу через терминал.
+
+Когда **контейнер** запущен, он будет выполнять прописанные в нём команды и программы. Но Вы можете изменить его так, чтоб он выполнял другие команды и программы.
+
+Контейнер буде работать до тех пор, пока выполняется его **главный процесс** (команда или программа).
+
+В контейнере обычно выполняется **только один процесс**, но от его имени можно запустить другие процессы, тогда в этом же в контейнере будет выполняться **множество процессов**.
+
+Контейнер не считается запущенным, если в нём **не выполняется хотя бы один процесс**. Если главный процесс остановлен, значит и контейнер остановлен.
+
+## Создать Docker-образ для FastAPI
+
+Что ж, давайте ужё создадим что-нибудь! 🚀
+
+Я покажу Вам, как собирать **Docker-образ** для FastAPI **с нуля**, основываясь на **официальном образе Python**.
+
+Такой подход сгодится для **большинства случаев**, например:
+
+* Использование с **Kubernetes** или аналогичным инструментом
+* Запуск в **Raspberry Pi**
+* Использование в облачных сервисах, запускающих образы контейнеров для Вас и т.п.
+
+### Установить зависимости
+
+Обычно Вашему приложению необходимы **дополнительные библиотеки**, список которых находится в отдельном файле.
+
+На название и содержание такого файла влияет выбранный Вами инструмент **установки** этих библиотек (зависимостей).
+
+Чаще всего это простой файл `requirements.txt` с построчным перечислением библиотек и их версий.
+
+При этом Вы, для выбора версий, будете использовать те же идеи, что упомянуты на странице [О версиях FastAPI](./versions.md){.internal-link target=_blank}.
+
+Ваш файл `requirements.txt` может выглядеть как-то так:
+
+```
+fastapi>=0.68.0,<0.69.0
+pydantic>=1.8.0,<2.0.0
+uvicorn>=0.15.0,<0.16.0
+```
+
+Устанавливать зависимости проще всего с помощью `pip`:
+
+
+
+```console
+$ pip install -r requirements.txt
+---> 100%
+Successfully installed fastapi pydantic uvicorn
+```
+
+
+
+!!! info "Информация"
+ Существуют и другие инструменты управления зависимостями.
+
+ В этом же разделе, но позже, я покажу Вам пример использования Poetry. 👇
+
+### Создать приложение **FastAPI**
+
+* Создайте директорию `app` и перейдите в неё.
+* Создайте пустой файл `__init__.py`.
+* Создайте файл `main.py` и заполните его:
+
+```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` и заполните его:
+
+```{ .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 ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+```
+
+1. Начните с официального образа Python, который будет основой для образа приложения.
+
+2. Укажите, что в дальнейшем команды запускаемые в контейнере, будут выполняться в директории `/code`.
+
+ Инструкция создаст эту директорию внутри контейнера и мы поместим в неё файл `requirements.txt` и директорию `app`.
+
+3. Скопируете файл с зависимостями из текущей директории в `/code`.
+
+ Сначала копируйте **только** файл с зависимостями.
+
+ Этот файл **изменяется довольно редко**, Docker ищет изменения при постройке образа и если не находит, то использует **кэш**, в котором хранятся предыдущии версии сборки образа.
+
+4. Установите библиотеки перечисленные в файле с зависимостями.
+
+ Опция `--no-cache-dir` указывает `pip` не сохранять загружаемые библиотеки на локальной машине для использования их в случае повторной загрузки. В контейнере, в случае пересборки этого шага, они всё равно будут удалены.
+
+ !!! note "Заметка"
+ Опция `--no-cache-dir` нужна только для `pip`, она никак не влияет на Docker или контейнеры.
+
+ Опция `--upgrade` указывает `pip` обновить библиотеки, емли они уже установлены.
+
+ Ка и в предыдущем шаге с копированием файла, этот шаг также будет использовать **кэш Docker** в случае отсутствия изменений.
+
+ Использрвание кэша, особенно на этом шаге, позволит Вам **сэкономить** кучу времени при повторной сборке образа, так как зависимости будут сохранены в кеше, а не **загружаться и устанавливаться каждый раз**.
+
+5. Скопируйте директорию `./app` внутрь директории `/code` (в контейнере).
+
+ Так как в этой директории расположен код, который **часто изменяется**, то использование **кэша** на этом шаге будет наименее эффективно, а значит лучше поместить этот шаг **ближе к концу** `Dockerfile`, дабы не терять выгоду от оптимизации предыдущих шагов.
+
+6. Укажите **команду**, запускающую сервер `uvicorn`.
+
+ `CMD` принимает список строк, разделённых запятыми, но при выполнении объединит их через пробел, собрав из них одну команду, которую Вы могли бы написать в терминале.
+
+ Эта команда будет выполнена в **текущей рабочей директории**, а именно в директории `/code`, котоая указана командой `WORKDIR /code`.
+
+ Так как команда выполняется внутрии директории `/code`, в которую мы поместили папку `./app` с приложением, то **Uvicorn** сможет найти и **импортировать** объект `app` из файла `app.main`.
+
+!!! tip "Подсказка"
+ Если ткнёте на кружок с плюсом, то увидите пояснения. 👆
+
+На данном этапе структура проекта должны выглядеть так:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+├── Dockerfile
+└── requirements.txt
+```
+
+#### Использование прокси-сервера
+
+Если Вы запускаете контейнер за прокси-сервером завершения TLS (балансирующего нагрузку), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`, которая укажет Uvicorn, что он работает позади прокси-сервера и может доверять заголовкам отправляемым им.
+
+```Dockerfile
+CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
+```
+
+#### Кэш Docker'а
+
+В нашем `Dockerfile` использована полезная хитрость, когда сначала копируется **только файл с зависимостями**, а не вся папка с кодом приложения.
+
+```Dockerfile
+COPY ./requirements.txt /code/requirements.txt
+```
+
+Docker и подобные ему инструменты **создают** образы контейнеров **пошагово**, добавляя **один слой над другим**, начиная с первой строки `Dockerfile` и добавляя файлы, создаваемые при выполнении каждой инструкции из `Dockerfile`.
+
+При создании образа используется **внутренний кэш** и если в файлах нет изменений с момента последней сборки образа, то будет **переиспользован** ранее созданный слой образа, а не повторное копирование файлов и создание слоя с нуля.
+Заметьте, что так как слой следующего шага зависит от слоя предыдущего, то изменения внесённые в промежуточный слой, также повлияют на последующие.
+
+Избегание копирования файлов не обязательно улучшит ситуацию, но использование кэша на одном шаге, позволит **использовать кэш и на следующих шагах**. Например, можно использовать кэш при установке зависимостей:
+
+```Dockerfile
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+```
+
+Файл со списком зависимостей **изменяется довольно редко**. Так что выполнив команду копирования только этого файла, Docker сможет **использовать кэш** на этом шаге.
+
+А затем **использовать кэш и на следующем шаге**, загружающем и устанавливающем зависимости. И вот тут-то мы и **сэкономим много времени**. ✨ ...а не будем томиться в тягостном ожидании. 😪😆
+
+Для загрузки и установки необходимых библиотек **может понадобиться несколько минут**, но использование **кэша** занимает несколько **секунд** максимум.
+
+И так как во время разработки Вы будете часто пересобирать контейнер для проверки работоспособности внесённых изменений, то сэкономленные минуты сложатся в часы, а то и дни.
+
+Так как папка с кодом приложения **изменяется чаще всего**, то мы расположили её в конце `Dockerfile`, ведь после внесённых в код изменений кэш не будет использован на этом и следующих шагах.
+
+```Dockerfile
+COPY ./app /code/app
+```
+
+### Создать Docker-образ
+
+Теперь, когда все файлы на своих местах, давайте создадим образ контейнера.
+
+* Перейдите в директорию проекта (в ту, где расположены `Dockerfile` и папка `app` с приложением).
+* Создай образ приложения FastAPI:
+
+
+
+```console
+$ docker build -t myimage .
+
+---> 100%
+```
+
+
+
+!!! tip "Подсказка"
+ Обратите внимание, что в конце написана точка - `.`, это то же самое что и `./`, тем самым мы указываем Docker директорию, из которой нужно выполнять сборку образа контейнера.
+
+ В данном случае это та же самая директория (`.`).
+
+### Запуск Docker-контейнера
+
+* Запустите контейнер, основанный на Вашем образе:
+
+
+
+```console
+$ docker run -d --name mycontainer -p 80:80 myimage
+```
+
+
+
+## Проверка
+
+Вы можете проверить, что Ваш Docker-контейнер работает перейдя по ссылке: http://192.168.99.100/items/5?q=somequery или http://127.0.0.1/items/5?q=somequery (или похожей, которую использует Ваш Docker-хост).
+
+Там Вы увидите:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+## Интерактивная документация API
+
+Теперь перейдите по ссылке http://192.168.99.100/docs или http://127.0.0.1/docs (или похожей, которую использует Ваш Docker-хост).
+
+Здесь Вы увидите автоматическую интерактивную документацию API (предоставляемую Swagger UI):
+
+
+
+## Альтернативная документация API
+
+Также Вы можете перейти по ссылке http://192.168.99.100/redoc or http://127.0.0.1/redoc (или похожей, которую использует Ваш Docker-хост).
+
+Здесь Вы увидите альтернативную автоматическую документацию API (предоставляемую ReDoc):
+
+
+
+## Создание Docker-образа на основе однофайлового приложения FastAPI
+
+Если Ваше приложение FastAPI помещено в один файл, например, `main.py` и структура Ваших файлов похожа на эту:
+
+```
+.
+├── Dockerfile
+├── main.py
+└── requirements.txt
+```
+
+Вам нужно изменить в `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 ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
+```
+
+1. Скопируйте непосредственно файл `main.py` в директорию `/code` (не указывайте `./app`).
+
+2. При запуске Uvicorn укажите ему, что объект `app` нужно импортировать из файла `main` (вместо импортирования из `app.main`).
+
+Настройте Uvicorn на использование `main` вместо `app.main` для импорта объекта `app`.
+
+## Концепции развёртывания
+
+Давайте вспомним о [Концепциях развёртывания](./concepts.md){.internal-link target=_blank} и применим их к контейнерам.
+
+Контейнеры - это, в основном, инструмент упрощающий **сборку и развёртывание** приложения и они не обязыают к применению какой-то определённой **концепции развёртывания**, а значит мы можем выбирать нужную стратегию.
+
+**Хорошая новость** в том, что независимо от выбранной стратегии, мы всё равно можем покрыть все концепции развёртывания. 🎉
+
+Рассмотрим эти **концепции развёртывания** применительно к контейнерам:
+
+* Использование более безопасного протокола HTTPS
+* Настройки запуска приложения
+* Перезагрузка приложения
+* Запуск нескольких экземпляров приложения
+* Управление памятью
+* Использование перечисленных функций перед запуском приложения
+
+## Использование более безопасного протокола HTTPS
+
+Если мы определимся, что **образ контейнера** будет содержать только приложение FastAPI, то работу с HTTPS можно организовать **снаружи** контейнера при помощи другого инструмента.
+
+Это может быть другой контейнер, в котором есть, например, Traefik, работающий с **HTTPS** и **самостоятельно** обновляющий **сертификаты**.
+
+!!! tip "Подсказка"
+ Traefik совместим с Docker, Kubernetes и им подобными инструментами. Он очень прост в установке и настройке использования HTTPS для Ваших контейнеров.
+
+В качестве альтернативы, работу с HTTPS можно доверить облачному провайдеру, если он предоставляет такую услугу.
+
+## Настройки запуска и перезагрузки приложения
+
+Обычно **запуском контейнера с приложением** занимается какой-то отдельный инструмент.
+
+Это может быть сам **Docker**, **Docker Compose**, **Kubernetes**, **облачный провайдер** и т.п.
+
+В большинстве случаев это простейшие настройки запуска и перезагрузки приложения (при падении). Например, команде запуска Docker-контейнера можно добавить опцию `--restart`.
+
+Управление запуском и перезагрузкой приложений без использования контейнеров - весьма затруднительно. Но при **работе с контейнерами** - это всего лишь функционал доступный по умолчанию. ✨
+
+## Запуск нескольких экземпляров приложения - Указание количества процессов
+
+Если у Вас есть кластер машин под управлением **Kubernetes**, Docker Swarm Mode, Nomad или аналогичной сложной системой оркестрации контейнеров, скорее всего, вместо использования менеджера процессов (типа Gunicorn и его воркеры) в каждом контейнере, Вы захотите **управлять количеством запущенных экземпляров приложения** на **уровне кластера**.
+
+В любую из этих систем управления контейнерами обычно встроен способ управления **количеством запущенных контейнеров** для распределения **нагрузки** от входящих запросов на **уровне кластера**.
+
+В такой ситуации Вы, вероятно, захотите создать **образ Docker**, как [описано выше](#dockerfile), с установленными зависимостями и запускающий **один процесс Uvicorn** вместо того, чтобы запускать Gunicorn управляющий несколькими воркерами Uvicorn.
+
+### Балансировщик нагрузки
+
+Обычно при использовании контейнеров один компонент **прослушивает главный порт**. Это может быть контейнер содержащий **прокси-сервер завершения работы TLS** для работы с **HTTPS** или что-то подобное.
+
+Поскольку этот компонент **принимает запросы** и равномерно **распределяет** их между компонентами, его также называют **балансировщиком нагрузки**.
+
+!!! tip "Подсказка"
+ **Прокси-сервер завершения работы TLS** одновременно может быть **балансировщиком нагрузки**.
+
+Система оркестрации, которую Вы используете для запуска и управления контейнерами, имеет встроенный инструмент **сетевого взаимодействия** (например, для передачи HTTP-запросов) между контейнерами с Вашими приложениями и **балансировщиком нагрузки** (который также может быть **прокси-сервером**).
+
+### Один балансировщик - Множество контейнеров
+
+При работе с **Kubernetes** или аналогичными системами оркестрации использование их внутреннней сети позволяет иметь один **балансировщик нагрузки**, который прослушивает **главный** порт и передаёт запросы **множеству запущенных контейнеров** с Вашими приложениями.
+
+В каждом из контейнеров обычно работает **только один процесс** (например, процесс Uvicorn управляющий Вашим приложением FastAPI). Контейнеры могут быть **идентичными**, запущенными на основе одного и того же образа, но у каждого будут свои отдельные процесс, память и т.п. Таким образом мы получаем преимущества **распараллеливания** работы по **разным ядрам** процессора или даже **разным машинам**.
+
+Система управления контейнерами с **балансировщиком нагрузки** будет **распределять запросы** к контейнерам с приложениями **по очереди**. То есть каждый запрос будет обработан одним из множества **одинаковых контейнеров** с одним и тем же приложением.
+
+**Балансировщик нагрузки** может обрабатывать запросы к *разным* приложениям, расположенным в Вашем кластере (например, если у них разные домены или префиксы пути) и передавать запросы нужному контейнеру с требуемым приложением.
+
+### Один процесс на контейнер
+
+В этом варианте **в одном контейнере будет запущен только один процесс (Uvicorn)**, а управление изменением количества запущенных копий приложения происходит на уровне кластера.
+
+Здесь **не нужен** менеджер процессов типа Gunicorn, управляющий процессами Uvicorn, или же Uvicorn, управляющий другими процессами Uvicorn. Достаточно **только одного процесса Uvicorn** на контейнер (но запуск нескольких процессов не запрещён).
+
+Использование менеджера процессов (Gunicorn или Uvicorn) внутри контейнера только добавляет **излишнее усложнение**, так как управление следует осуществлять системой оркестрации.
+
+### Множество процессов внутри контейнера для особых случаев
+
+Безусловно, бывают **особые случаи**, когда может понадобится внутри контейнера запускать **менеджер процессов Gunicorn**, управляющий несколькими **процессами Uvicorn**.
+
+Для таких случаев Вы можете использовать **официальный Docker-образ** (прим. пер: - *здесь и далее на этой странице, если Вы встретите сочетание "официальный Docker-образ" без уточнений, то автор имеет в виду именно предоставляемый им образ*), где в качестве менеджера процессов используется **Gunicorn**, запускающий несколько **процессов Uvicorn** и некоторые настройки по умолчанию, автоматически устанавливающие количество запущенных процессов в зависимости от количества ядер Вашего процессора. Я расскажу Вам об этом подробнее тут: [Официальный Docker-образ со встроенными Gunicorn и Uvicorn](#docker-gunicorn-uvicorn).
+
+Некоторые примеры подобных случаев:
+
+#### Простое приложение
+
+Вы можете использовать менеджер процессов внутри контейнера, если Ваше приложение **настолько простое**, что у Вас нет необходимости (по крайней мере, пока нет) в тщательных настройках количества процессов и Вам достаточно имеющихся настроек по умолчанию (если используется официальный Docker-образ) для запуска приложения **только на одном сервере**, а не в кластере.
+
+#### Docker Compose
+
+С помощью **Docker Compose** можно разворачивать несколько контейнеров на **одном сервере** (не кластере), но при это у Вас не будет простого способа управления количеством запущенных контейнеров с одновременным сохранением общей сети и **балансировки нагрузки**.
+
+В этом случае можно использовать **менеджер процессов**, управляющий **несколькими процессами**, внутри **одного контейнера**.
+
+#### Prometheus и прочие причины
+
+У Вас могут быть и **другие причины**, когда использование **множества процессов** внутри **одного контейнера** будет проще, нежели запуск **нескольких контейнеров** с **единственным процессом** в каждом из них.
+
+Например (в зависимости от конфигурации), у Вас могут быть инструменты подобные экспортёру Prometheus, которые должны иметь доступ к **каждому запросу** приходящему в контейнер.
+
+Если у Вас будет **несколько контейнеров**, то Prometheus, по умолчанию, **при сборе метрик** получит их **только с одного контейнера**, который обрабатывает конкретный запрос, вместо **сбора метрик** со всех работающих контейнеров.
+
+В таком случае может быть проще иметь **один контейнер** со **множеством процессов**, с нужным инструментом (таким как экспортёр Prometheus) в этом же контейнере и собирающем метрики со всех внутренних процессов этого контейнера.
+
+---
+
+Самое главное - **ни одно** из перечисленных правил не является **высеченным в камне** и Вы не обязаны слепо их повторять. Вы можете использовать эти идеи при **рассмотрении Вашего конкретного случая** и самостоятельно решать, какая из концепции подходит лучше:
+
+* Использование более безопасного протокола HTTPS
+* Настройки запуска приложения
+* Перезагрузка приложения
+* Запуск нескольких экземпляров приложения
+* Управление памятью
+* Использование перечисленных функций перед запуском приложения
+
+## Управление памятью
+
+При **запуске одного процесса на контейнер** Вы получаете относительно понятный, стабильный и ограниченный объём памяти, потребляемый одним контейнером.
+
+Вы можете установить аналогичные ограничения по памяти при конфигурировании своей системы управления контейнерами (например, **Kubernetes**). Таким образом система сможет **изменять количество контейнеров** на **доступных ей машинах** приводя в соответствие количество памяти нужной контейнерам с количеством памяти доступной в кластере (наборе доступных машин).
+
+Если у Вас **простенькое** приложение, вероятно у Вас не будет **необходимости** устанавливать жёсткие ограничения на выделяемую ему память. Но если приложение **использует много памяти** (например, оно использует модели **машинного обучения**), Вам следует проверить, как много памяти ему требуется и отрегулировать **количество контейнеров** запущенных на **каждой машине** (может быть даже добавить машин в кластер).
+
+Если Вы запускаете **несколько процессов в контейнере**, то должны быть уверены, что эти процессы не **займут памяти больше**, чем доступно для контейнера.
+
+## Подготовительные шаги при запуске контейнеров
+
+Есть два основных подхода, которые Вы можете использовать при запуске контейнеров (Docker, Kubernetes и т.п.).
+
+### Множество контейнеров
+
+Когда Вы запускаете **множество контейнеров**, в каждом из которых работает **только один процесс** (например, в кластере **Kubernetes**), может возникнуть необходимость иметь **отдельный контейнер**, который осуществит **предварительные шаги перед запуском** остальных контейнеров (например, применяет миграции к базе данных).
+
+!!! info "Информация"
+ При использовании Kubernetes, это может быть Инициализирующий контейнер.
+
+При отсутствии такой необходимости (допустим, не нужно применять миграции к базе данных, а только проверить, что она готова принимать соединения), Вы можете проводить такую проверку в каждом контейнере перед запуском его основного процесса и запускать все контейнеры **одновременно**.
+
+### Только один контейнер
+
+Если у Вас несложное приложение для работы которого достаточно **одного контейнера**, но в котором работает **несколько процессов** (или один процесс), то прохождение предварительных шагов можно осуществить в этом же контейнере до запуска основного процесса. Официальный Docker-образ поддерживает такие действия.
+
+## Официальный Docker-образ с Gunicorn и Uvicorn
+
+Я подготовил для Вас Docker-образ, в который включён Gunicorn управляющий процессами (воркерами) Uvicorn, в соответствии с концепциями рассмотренными в предыдущей главе: [Рабочие процессы сервера (воркеры) - Gunicorn совместно с Uvicorn](./server-workers.md){.internal-link target=_blank}.
+
+Этот образ может быть полезен для ситуаций описанных тут: [Множество процессов внутри контейнера для особых случаев](#special-cases).
+
+* tiangolo/uvicorn-gunicorn-fastapi.
+
+!!! warning "Предупреждение"
+ Скорее всего у Вас **нет необходимости** в использовании этого образа или подобного ему и лучше создать свой образ с нуля как описано тут: [Создать Docker-образ для FastAPI](#docker-fastapi).
+
+В этом образе есть **автоматический** механизм подстройки для запуска **необходимого количества процессов** в соответствии с доступным количеством ядер процессора.
+
+В нём установлены **разумные значения по умолчанию**, но можно изменять и обновлять конфигурацию с помощью **переменных окружения** или конфигурационных файлов.
+
+Он также поддерживает прохождение **Подготовительных шагов при запуске контейнеров** при помощи скрипта.
+
+!!! tip "Подсказка"
+ Для просмотра всех возможных настроек перейдите на страницу этого Docker-образа: tiangolo/uvicorn-gunicorn-fastapi.
+
+### Количество процессов в официальном Docker-образе
+
+**Количество процессов** в этом образе **вычисляется автоматически** и зависит от доступного количества **ядер** центрального процессора.
+
+Это означает, что он будет пытаться **выжать** из процессора как можно больше **производительности**.
+
+Но Вы можете изменять и обновлять конфигурацию с помощью **переменных окружения** и т.п.
+
+Поскольку количество процессов зависит от процессора, на котором работает контейнер, **объём потребляемой памяти** также будет зависеть от этого.
+
+А значит, если Вашему приложению требуется много оперативной памяти (например, оно использует модели машинного обучения) и Ваш сервер имеет центральный процессор с большим количеством ядер, но **не слишком большим объёмом оперативной памяти**, то может дойти до того, что контейнер попытается занять памяти больше, чем доступно, из-за чего будет падение производительности (или сервер вовсе упадёт). 🚨
+
+
+### Написание `Dockerfile`
+
+Итак, теперь мы можем написать `Dockerfile` основанный на этом официальном Docker-образе:
+
+```Dockerfile
+FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
+
+COPY ./requirements.txt /app/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
+
+COPY ./app /app
+```
+
+### Большие приложения
+
+Если Вы успели ознакомиться с разделом [Приложения содержащие много файлов](../tutorial/bigger-applications.md){.internal-link target=_blank}, состоящие из множества файлов, Ваш Dockerfile может выглядеть так:
+
+```Dockerfile hl_lines="7"
+FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9
+
+COPY ./requirements.txt /app/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
+
+COPY ./app /app/app
+```
+
+### Как им пользоваться
+
+Если Вы используете **Kubernetes** (или что-то вроде того), скорее всего Вам **не нужно** использовать официальный Docker-образ (или другой похожий) в качестве основы, так как управление **количеством запущенных контейнеров** должно быть настроено на уровне кластера. В таком случае лучше **создать образ с нуля**, как описано в разделе Создать [Docker-образ для FastAPI](#docker-fastapi).
+
+Официальный образ может быть полезен в отдельных случаях, описанных выше в разделе [Множество процессов внутри контейнера для особых случаев](#special-cases). Например, если Ваше приложение **достаточно простое**, не требует запуска в кластере и способно уместиться в один контейнер, то его настройки по умолчанию будут работать довольно хорошо. Или же Вы развертываете его с помощью **Docker Compose**, работаете на одном сервере и т. д
+
+## Развёртывание образа контейнера
+
+После создания образа контейнера существует несколько способов его развёртывания.
+
+Например:
+
+* С использованием **Docker Compose** при развёртывании на одном сервере
+* С использованием **Kubernetes** в кластере
+* С использованием режима Docker Swarm в кластере
+* С использованием других инструментов, таких как Nomad
+* С использованием облачного сервиса, который будет управлять разворачиванием Вашего контейнера
+
+## Docker-образ и Poetry
+
+Если Вы пользуетесь Poetry для управления зависимостями Вашего проекта, то можете использовать многоэтапную сборку образа:
+
+```{ .dockerfile .annotate }
+# (1)
+FROM python:3.9 as requirements-stage
+
+# (2)
+WORKDIR /tmp
+
+# (3)
+RUN pip install poetry
+
+# (4)
+COPY ./pyproject.toml ./poetry.lock* /tmp/
+
+# (5)
+RUN poetry export -f requirements.txt --output requirements.txt --without-hashes
+
+# (6)
+FROM python:3.9
+
+# (7)
+WORKDIR /code
+
+# (8)
+COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt
+
+# (9)
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (10)
+COPY ./app /code/app
+
+# (11)
+CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
+```
+
+1. Это первый этап, которому мы дадим имя `requirements-stage`.
+
+2. Установите директорию `/tmp` в качестве рабочей директории.
+
+ В ней будет создан файл `requirements.txt`
+
+3. На этом шаге установите Poetry.
+
+4. Скопируйте файлы `pyproject.toml` и `poetry.lock` в директорию `/tmp`.
+
+ Поскольку название файла написано как `./poetry.lock*` (с `*` в конце), то ничего не сломается, если такой файл не будет найден.
+
+5. Создайте файл `requirements.txt`.
+
+6. Это второй (и последний) этап сборки, который и создаст окончательный образ контейнера.
+
+7. Установите директорию `/code` в качестве рабочей.
+
+8. Скопируйте файл `requirements.txt` в директорию `/code`.
+
+ Этот файл находится в образе, созданном на предыдущем этапе, которому мы дали имя requirements-stage, потому при копировании нужно написать `--from-requirements-stage`.
+
+9. Установите зависимости, указанные в файле `requirements.txt`.
+
+10. Скопируйте папку `app` в папку `/code`.
+
+11. Запустите `uvicorn`, указав ему использовать объект `app`, расположенный в `app.main`.
+
+!!! tip "Подсказка"
+ Если ткнёте на кружок с плюсом, то увидите объяснения, что происходит в этой строке.
+
+**Этапы сборки Docker-образа** являются частью `Dockerfile` и работают как **временные образы контейнеров**. Они нужны только для создания файлов, используемых в дальнейших этапах.
+
+Первый этап был нужен только для **установки Poetry** и **создания файла `requirements.txt`**, в которым прописаны зависимости Вашего проекта, взятые из файла `pyproject.toml`.
+
+На **следующем этапе** `pip` будет использовать файл `requirements.txt`.
+
+В итоговом образе будет содержаться **только последний этап сборки**, предыдущие этапы будут отброшены.
+
+При использовании Poetry, имеет смысл использовать **многоэтапную сборку Docker-образа**, потому что на самом деле Вам не нужен Poetry и его зависимости в окончательном образе контейнера, Вам **нужен только** сгенерированный файл `requirements.txt` для установки зависимостей Вашего проекта.
+
+А на последнем этапе, придерживаясь описанных ранее правил, создаётся итоговый образ
+
+### Использование прокси-сервера завершения TLS и Poetry
+
+И снова повторюсь, если используете прокси-сервер (балансировщик нагрузки), такой, как Nginx или Traefik, добавьте в команду запуска опцию `--proxy-headers`:
+
+```Dockerfile
+CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"]
+```
+
+## Резюме
+
+При помощи систем контейнеризации (таких, как **Docker** и **Kubernetes**), становится довольно просто обрабатывать все **концепции развертывания**:
+
+* Использование более безопасного протокола HTTPS
+* Настройки запуска приложения
+* Перезагрузка приложения
+* Запуск нескольких экземпляров приложения
+* Управление памятью
+* Использование перечисленных функций перед запуском приложения
+
+В большинстве случаев Вам, вероятно, не нужно использовать какой-либо базовый образ, **лучше создать образ контейнера с нуля** на основе официального Docker-образа Python.
+
+Позаботившись о **порядке написания** инструкций в `Dockerfile`, Вы сможете использовать **кэш Docker'а**, **минимизировав время сборки**, максимально повысив свою производительность (и избежать скуки). 😎
+
+В некоторых особых случаях вы можете использовать официальный образ Docker для FastAPI. 🤓
diff --git a/docs/ru/docs/external-links.md b/docs/ru/docs/external-links.md
index 4daf65898..2448ef82e 100644
--- a/docs/ru/docs/external-links.md
+++ b/docs/ru/docs/external-links.md
@@ -9,70 +9,21 @@
!!! tip
Если у вас есть статья, проект, инструмент или что-либо, связанное с **FastAPI**, что еще не перечислено здесь, создайте Pull Request.
-## Статьи
+{% for section_name, section_content in external_links.items() %}
-### На английском
+## {{ section_name }}
-{% if external_links %}
-{% for article in external_links.articles.english %}
+{% for lang_name, lang_content in section_content.items() %}
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
-
-### На японском
-
-{% if external_links %}
-{% for article in external_links.articles.japanese %}
-
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
+### {{ lang_name }}
-### На вьетнамском
+{% for item in lang_content %}
-{% if external_links %}
-{% for article in external_links.articles.vietnamese %}
+* {{ item.title }} by {{ item.author }}.
-* {{ article.title }} by {{ article.author }}.
{% endfor %}
-{% endif %}
-
-### На русском
-
-{% if external_links %}
-{% for article in external_links.articles.russian %}
-
-* {{ article.title }} by {{ article.author }}.
{% endfor %}
-{% endif %}
-
-### На немецком
-
-{% if external_links %}
-{% for article in external_links.articles.german %}
-
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
-
-## Подкасты
-
-{% if external_links %}
-{% for article in external_links.podcasts.english %}
-
-* {{ article.title }} by {{ article.author }}.
-{% endfor %}
-{% endif %}
-
-## Talks
-
-{% if external_links %}
-{% for article in external_links.talks.english %}
-
-* {{ article.title }} by {{ article.author }}.
{% endfor %}
-{% endif %}
## Проекты
diff --git a/docs/ru/docs/features.md b/docs/ru/docs/features.md
index e18f7bc87..97841cc83 100644
--- a/docs/ru/docs/features.md
+++ b/docs/ru/docs/features.md
@@ -27,7 +27,7 @@
### Только современный Python
-Все эти возможности основаны на стандартных **аннотациях типов Python 3.6** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только лишь стандартный современный Python.
+Все эти возможности основаны на стандартных **аннотациях типов Python 3.8** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только лишь стандартный современный Python.
Если вам нужно освежить знания, как использовать аннотации типов в Python (даже если вы не используете FastAPI), выделите 2 минуты и просмотрите краткое руководство: [Введение в аннотации типов Python¶
](python-types.md){.internal-link target=_blank}.
diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md
index a69e37bd8..65ff768d1 100644
--- a/docs/ru/docs/help-fastapi.md
+++ b/docs/ru/docs/help-fastapi.md
@@ -223,8 +223,6 @@
Используйте этот чат только для бесед на отвлечённые темы.
-Существует также чат в Gitter, но поскольку в нем нет каналов и расширенных функций, общение в нём сложнее, потому рекомендуемой системой является Discord.
-
### Не использовать чаты для вопросов
Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md
index 30c32e046..97a3947bd 100644
--- a/docs/ru/docs/index.md
+++ b/docs/ru/docs/index.md
@@ -27,7 +27,7 @@
---
-FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API используя Python 3.6+, в основе которого лежит стандартная аннотация типов Python.
+FastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API используя Python 3.8+, в основе которого лежит стандартная аннотация типов Python.
Ключевые особенности:
@@ -109,7 +109,7 @@ FastAPI — это современный, быстрый (высокопрои
## Зависимости
-Python 3.7+
+Python 3.8+
FastAPI стоит на плечах гигантов:
@@ -325,7 +325,7 @@ def update_item(item_id: int, item: Item):
Вам не нужно изучать новый синтаксис, методы или классы конкретной библиотеки и т. д.
-Только стандартный **Python 3.6+**.
+Только стандартный **Python 3.8+**.
Например, для `int`:
diff --git a/docs/ru/docs/tutorial/background-tasks.md b/docs/ru/docs/tutorial/background-tasks.md
index 81efda786..7a3cf6d83 100644
--- a/docs/ru/docs/tutorial/background-tasks.md
+++ b/docs/ru/docs/tutorial/background-tasks.md
@@ -63,7 +63,7 @@
{!> ../../../docs_src/background_tasks/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="13 15 22 25"
{!> ../../../docs_src/background_tasks/tutorial002.py!}
diff --git a/docs/ru/docs/tutorial/body-fields.md b/docs/ru/docs/tutorial/body-fields.md
index 674b8bde4..02a598004 100644
--- a/docs/ru/docs/tutorial/body-fields.md
+++ b/docs/ru/docs/tutorial/body-fields.md
@@ -12,7 +12,7 @@
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="4"
{!> ../../../docs_src/body_fields/tutorial001.py!}
@@ -31,13 +31,13 @@
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="11-14"
{!> ../../../docs_src/body_fields/tutorial001.py!}
```
-Функция `Field` работает так же, как `Query`, `Path` и `Body`, у ее такие же параметры и т.д.
+Функция `Field` работает так же, как `Query`, `Path` и `Body`, у неё такие же параметры и т.д.
!!! note "Технические детали"
На самом деле, `Query`, `Path` и другие функции, которые вы увидите в дальнейшем, создают объекты подклассов общего класса `Param`, который сам по себе является подклассом `FieldInfo` из Pydantic.
diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md
index a20457092..e52ef6f6f 100644
--- a/docs/ru/docs/tutorial/body-multiple-params.md
+++ b/docs/ru/docs/tutorial/body-multiple-params.md
@@ -20,7 +20,7 @@
{!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="19-21"
{!> ../../../docs_src/body_multiple_params/tutorial001_an.py!}
@@ -35,7 +35,7 @@
{!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
```
-=== "Python 3.6+ non-Annotated"
+=== "Python 3.8+ non-Annotated"
!!! Заметка
Рекомендуется использовать версию с `Annotated`, если это возможно.
@@ -68,7 +68,7 @@
{!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="22"
{!> ../../../docs_src/body_multiple_params/tutorial002.py!}
@@ -123,7 +123,7 @@
{!> ../../../docs_src/body_multiple_params/tutorial003_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="24"
{!> ../../../docs_src/body_multiple_params/tutorial003_an.py!}
@@ -138,7 +138,7 @@
{!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
```
-=== "Python 3.6+ non-Annotated"
+=== "Python 3.8+ non-Annotated"
!!! Заметка
Рекомендуется использовать `Annotated` версию, если это возможно.
@@ -197,7 +197,7 @@ q: str | None = None
{!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="28"
{!> ../../../docs_src/body_multiple_params/tutorial004_an.py!}
@@ -212,7 +212,7 @@ q: str | None = None
{!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
```
-=== "Python 3.6+ non-Annotated"
+=== "Python 3.8+ non-Annotated"
!!! Заметка
Рекомендуется использовать `Annotated` версию, если это возможно.
@@ -250,7 +250,7 @@ item: Item = Body(embed=True)
{!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="18"
{!> ../../../docs_src/body_multiple_params/tutorial005_an.py!}
@@ -265,7 +265,7 @@ item: Item = Body(embed=True)
{!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
```
-=== "Python 3.6+ non-Annotated"
+=== "Python 3.8+ non-Annotated"
!!! Заметка
Рекомендуется использовать `Annotated` версию, если это возможно.
diff --git a/docs/ru/docs/tutorial/body-nested-models.md b/docs/ru/docs/tutorial/body-nested-models.md
index 6435e316f..a6d123d30 100644
--- a/docs/ru/docs/tutorial/body-nested-models.md
+++ b/docs/ru/docs/tutorial/body-nested-models.md
@@ -12,7 +12,7 @@
{!> ../../../docs_src/body_nested_models/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial001.py!}
@@ -73,7 +73,7 @@ my_list: List[str]
{!> ../../../docs_src/body_nested_models/tutorial002_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002.py!}
@@ -99,7 +99,7 @@ my_list: List[str]
{!> ../../../docs_src/body_nested_models/tutorial003_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="1 14"
{!> ../../../docs_src/body_nested_models/tutorial003.py!}
@@ -137,7 +137,7 @@ my_list: List[str]
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
@@ -159,7 +159,7 @@ my_list: List[str]
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
@@ -208,7 +208,7 @@ my_list: List[str]
{!> ../../../docs_src/body_nested_models/tutorial005_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005.py!}
@@ -232,7 +232,7 @@ my_list: List[str]
{!> ../../../docs_src/body_nested_models/tutorial006_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006.py!}
@@ -283,7 +283,7 @@ my_list: List[str]
{!> ../../../docs_src/body_nested_models/tutorial007_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007.py!}
@@ -314,7 +314,7 @@ images: list[Image]
{!> ../../../docs_src/body_nested_models/tutorial008_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="15"
{!> ../../../docs_src/body_nested_models/tutorial008.py!}
@@ -354,7 +354,7 @@ images: list[Image]
{!> ../../../docs_src/body_nested_models/tutorial009_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/body_nested_models/tutorial009.py!}
diff --git a/docs/ru/docs/tutorial/cookie-params.md b/docs/ru/docs/tutorial/cookie-params.md
index a6f2caa26..5f99458b6 100644
--- a/docs/ru/docs/tutorial/cookie-params.md
+++ b/docs/ru/docs/tutorial/cookie-params.md
@@ -12,7 +12,7 @@
{!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="3"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
@@ -30,7 +30,7 @@
{!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/cookie_params/tutorial001.py!}
diff --git a/docs/ru/docs/tutorial/dependencies/global-dependencies.md b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
new file mode 100644
index 000000000..eb1b4d7c1
--- /dev/null
+++ b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
@@ -0,0 +1,34 @@
+# Глобальные зависимости
+
+Для некоторых типов приложений может потребоваться добавить зависимости ко всему приложению.
+
+Подобно тому, как вы можете [добавлять зависимости через параметр `dependencies` в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, вы можете добавлять зависимости сразу ко всему `FastAPI` приложению.
+
+В этом случае они будут применяться ко всем *операциям пути* в приложении:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/dependencies/tutorial012_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/dependencies/tutorial012_an.py!}
+ ```
+
+=== "Python 3.8 non-Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать 'Annotated' версию, если это возможно.
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/dependencies/tutorial012.py!}
+ ```
+
+Все способы [добавления зависимостей в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
+
+## Зависимости для групп *операций пути*
+
+Позднее, читая о том, как структурировать более крупные [приложения, содержащие много файлов](../../tutorial/bigger-applications.md){.internal-link target=_blank}, вы узнаете, как объявить один параметр dependencies для целой группы *операций пути*.
diff --git a/docs/ru/docs/tutorial/extra-data-types.md b/docs/ru/docs/tutorial/extra-data-types.md
index efcbcb38a..0f613a6b2 100644
--- a/docs/ru/docs/tutorial/extra-data-types.md
+++ b/docs/ru/docs/tutorial/extra-data-types.md
@@ -55,7 +55,7 @@
Вот пример *операции пути* с параметрами, который демонстрирует некоторые из вышеперечисленных типов.
-=== "Python 3.6 и выше"
+=== "Python 3.8 и выше"
```Python hl_lines="1 3 12-16"
{!> ../../../docs_src/extra_data_types/tutorial001.py!}
@@ -69,7 +69,7 @@
Обратите внимание, что параметры внутри функции имеют свой естественный тип данных, и вы, например, можете выполнять обычные манипуляции с датами, такие как:
-=== "Python 3.6 и выше"
+=== "Python 3.8 и выше"
```Python hl_lines="18-19"
{!> ../../../docs_src/extra_data_types/tutorial001.py!}
diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md
index a346f7432..30176b4e3 100644
--- a/docs/ru/docs/tutorial/extra-models.md
+++ b/docs/ru/docs/tutorial/extra-models.md
@@ -23,7 +23,7 @@
{!> ../../../docs_src/extra_models/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
{!> ../../../docs_src/extra_models/tutorial001.py!}
@@ -164,7 +164,7 @@ UserInDB(
{!> ../../../docs_src/extra_models/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9 15-16 19-20 23-24"
{!> ../../../docs_src/extra_models/tutorial002.py!}
@@ -187,7 +187,7 @@ UserInDB(
{!> ../../../docs_src/extra_models/tutorial003_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="1 14-15 18-20 33"
{!> ../../../docs_src/extra_models/tutorial003.py!}
@@ -219,7 +219,7 @@ some_variable: PlaneItem | CarItem
{!> ../../../docs_src/extra_models/tutorial004_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="1 20"
{!> ../../../docs_src/extra_models/tutorial004.py!}
@@ -239,7 +239,7 @@ some_variable: PlaneItem | CarItem
{!> ../../../docs_src/extra_models/tutorial005_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="1 8"
{!> ../../../docs_src/extra_models/tutorial005.py!}
diff --git a/docs/ru/docs/tutorial/header-params.md b/docs/ru/docs/tutorial/header-params.md
new file mode 100644
index 000000000..1be4ac707
--- /dev/null
+++ b/docs/ru/docs/tutorial/header-params.md
@@ -0,0 +1,227 @@
+# Header-параметры
+
+Вы можете определить параметры заголовка таким же образом, как вы определяете параметры `Query`, `Path` и `Cookie`.
+
+## Импорт `Header`
+
+Сперва импортируйте `Header`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/header_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```
+
+## Объявление параметров `Header`
+
+Затем объявите параметры заголовка, используя ту же структуру, что и с `Path`, `Query` и `Cookie`.
+
+Первое значение является значением по умолчанию, вы можете передать все дополнительные параметры валидации или аннотации:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```
+
+!!! note "Технические детали"
+ `Header` - это "родственный" класс `Path`, `Query` и `Cookie`. Он также наследуется от того же общего класса `Param`.
+
+ Но помните, что когда вы импортируете `Query`, `Path`, `Header` и другие из `fastapi`, на самом деле это функции, которые возвращают специальные классы.
+
+!!! info "Дополнительная информация"
+ Чтобы объявить заголовки, важно использовать `Header`, иначе параметры интерпретируются как query-параметры.
+
+## Автоматическое преобразование
+
+`Header` обладает небольшой дополнительной функциональностью в дополнение к тому, что предоставляют `Path`, `Query` и `Cookie`.
+
+Большинство стандартных заголовков разделены символом "дефис", также известным как "минус" (`-`).
+
+Но переменная вроде `user-agent` недопустима в Python.
+
+По умолчанию `Header` преобразует символы имен параметров из символа подчеркивания (`_`) в дефис (`-`) для извлечения и документирования заголовков.
+
+Кроме того, HTTP-заголовки не чувствительны к регистру, поэтому вы можете объявить их в стандартном стиле Python (также известном как "snake_case").
+
+Таким образом вы можете использовать `user_agent`, как обычно, в коде Python, вместо того, чтобы вводить заглавные буквы как `User_Agent` или что-то подобное.
+
+Если по какой-либо причине вам необходимо отключить автоматическое преобразование подчеркиваний в дефисы, установите для параметра `convert_underscores` в `Header` значение `False`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/header_params/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/header_params/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/header_params/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.8+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial002.py!}
+ ```
+
+!!! warning "Внимание"
+ Прежде чем установить для `convert_underscores` значение `False`, имейте в виду, что некоторые HTTP-прокси и серверы запрещают использование заголовков с подчеркиванием.
+
+## Повторяющиеся заголовки
+
+Есть возможность получать несколько заголовков с одним и тем же именем, но разными значениями.
+
+Вы можете определить эти случаи, используя список в объявлении типа.
+
+Вы получите все значения из повторяющегося заголовка в виде `list` Python.
+
+Например, чтобы объявить заголовок `X-Token`, который может появляться более одного раза, вы можете написать:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.9+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.8+ без Annotated"
+
+ !!! tip "Подсказка"
+ Предпочтительнее использовать версию с аннотацией, если это возможно.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003.py!}
+ ```
+
+Если вы взаимодействуете с этой *операцией пути*, отправляя два HTTP-заголовка, таких как:
+
+```
+X-Token: foo
+X-Token: bar
+```
+
+Ответ был бы таким:
+
+```JSON
+{
+ "X-Token values": [
+ "bar",
+ "foo"
+ ]
+}
+```
+
+## Резюме
+
+Объявляйте заголовки с помощью `Header`, используя тот же общий шаблон, как при `Query`, `Path` и `Cookie`.
+
+И не беспокойтесь о символах подчеркивания в ваших переменных, **FastAPI** позаботится об их преобразовании.
diff --git a/docs/ru/docs/tutorial/path-operation-configuration.md b/docs/ru/docs/tutorial/path-operation-configuration.md
index 013903add..db99409f4 100644
--- a/docs/ru/docs/tutorial/path-operation-configuration.md
+++ b/docs/ru/docs/tutorial/path-operation-configuration.md
@@ -25,7 +25,7 @@
{!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="3 17"
{!> ../../../docs_src/path_operation_configuration/tutorial001.py!}
@@ -54,7 +54,7 @@
{!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="17 22 27"
{!> ../../../docs_src/path_operation_configuration/tutorial002.py!}
@@ -92,7 +92,7 @@
{!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="20-21"
{!> ../../../docs_src/path_operation_configuration/tutorial003.py!}
@@ -116,7 +116,7 @@
{!> ../../../docs_src/path_operation_configuration/tutorial004_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="19-27"
{!> ../../../docs_src/path_operation_configuration/tutorial004.py!}
@@ -142,7 +142,7 @@
{!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="21"
{!> ../../../docs_src/path_operation_configuration/tutorial005.py!}
diff --git a/docs/ru/docs/tutorial/path-params-numeric-validations.md b/docs/ru/docs/tutorial/path-params-numeric-validations.md
index 0d034ef34..bd2c29d0a 100644
--- a/docs/ru/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/ru/docs/tutorial/path-params-numeric-validations.md
@@ -18,7 +18,7 @@
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="3-4"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
@@ -33,7 +33,7 @@
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -67,7 +67,7 @@
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="11"
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
@@ -82,7 +82,7 @@
{!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -117,7 +117,7 @@
Поэтому вы можете определить функцию так:
-=== "Python 3.6 без Annotated"
+=== "Python 3.8 без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -134,7 +134,7 @@
{!> ../../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial002_an.py!}
@@ -174,7 +174,7 @@ Python не будет ничего делать с `*`, но он будет з
{!> ../../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial003_an.py!}
@@ -192,13 +192,13 @@ Python не будет ничего делать с `*`, но он будет з
{!> ../../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial004_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -220,13 +220,13 @@ Python не будет ничего делать с `*`, но он будет з
{!> ../../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/path_params_numeric_validations/tutorial005_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -251,13 +251,13 @@ Python не будет ничего делать с `*`, но он будет з
{!> ../../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="12"
{!> ../../../docs_src/path_params_numeric_validations/tutorial006_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md
index 68042db63..cc826b871 100644
--- a/docs/ru/docs/tutorial/query-params-str-validations.md
+++ b/docs/ru/docs/tutorial/query-params-str-validations.md
@@ -10,7 +10,7 @@
{!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
@@ -42,7 +42,7 @@ Query-параметр `q` имеет тип `Union[str, None]` (или `str | N
{!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
В версиях Python ниже Python 3.9 `Annotation` импортируется из `typing_extensions`.
@@ -66,7 +66,7 @@ Query-параметр `q` имеет тип `Union[str, None]` (или `str | N
q: str | None = None
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python
q: Union[str, None] = None
@@ -80,7 +80,7 @@ Query-параметр `q` имеет тип `Union[str, None]` (или `str | N
q: Annotated[str | None] = None
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python
q: Annotated[Union[str, None]] = None
@@ -100,7 +100,7 @@ Query-параметр `q` имеет тип `Union[str, None]` (или `str | N
{!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!}
@@ -131,7 +131,7 @@ Query-параметр `q` имеет тип `Union[str, None]` (или `str | N
{!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params_str_validations/tutorial002.py!}
@@ -244,7 +244,7 @@ q: str = Query(default="rick")
{!> ../../../docs_src/query_params_str_validations/tutorial003_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial003_an.py!}
@@ -259,7 +259,7 @@ q: str = Query(default="rick")
{!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -284,7 +284,7 @@ q: str = Query(default="rick")
{!> ../../../docs_src/query_params_str_validations/tutorial004_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="12"
{!> ../../../docs_src/query_params_str_validations/tutorial004_an.py!}
@@ -299,7 +299,7 @@ q: str = Query(default="rick")
{!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -330,13 +330,13 @@ q: str = Query(default="rick")
{!> ../../../docs_src/query_params_str_validations/tutorial005_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial005_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -384,13 +384,13 @@ q: Union[str, None] = None
{!> ../../../docs_src/query_params_str_validations/tutorial006_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial006_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -414,13 +414,13 @@ q: Union[str, None] = None
{!> ../../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial006b_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -454,7 +454,7 @@ q: Union[str, None] = None
{!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial006c_an.py!}
@@ -469,7 +469,7 @@ q: Union[str, None] = None
{!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -491,13 +491,13 @@ q: Union[str, None] = None
{!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="2 9"
{!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -527,7 +527,7 @@ q: Union[str, None] = None
{!> ../../../docs_src/query_params_str_validations/tutorial011_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial011_an.py!}
@@ -551,7 +551,7 @@ q: Union[str, None] = None
{!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -596,7 +596,7 @@ http://localhost:8000/items/?q=foo&q=bar
{!> ../../../docs_src/query_params_str_validations/tutorial012_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial012_an.py!}
@@ -611,7 +611,7 @@ http://localhost:8000/items/?q=foo&q=bar
{!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -647,13 +647,13 @@ http://localhost:8000/items/
{!> ../../../docs_src/query_params_str_validations/tutorial013_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="8"
{!> ../../../docs_src/query_params_str_validations/tutorial013_an.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -692,7 +692,7 @@ http://localhost:8000/items/
{!> ../../../docs_src/query_params_str_validations/tutorial007_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial007_an.py!}
@@ -707,7 +707,7 @@ http://localhost:8000/items/
{!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -730,7 +730,7 @@ http://localhost:8000/items/
{!> ../../../docs_src/query_params_str_validations/tutorial008_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="15"
{!> ../../../docs_src/query_params_str_validations/tutorial008_an.py!}
@@ -741,11 +741,11 @@ http://localhost:8000/items/
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
- ```Python hl_lines="12"
+ ```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -784,7 +784,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
{!> ../../../docs_src/query_params_str_validations/tutorial009_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params_str_validations/tutorial009_an.py!}
@@ -799,7 +799,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
{!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -828,7 +828,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
{!> ../../../docs_src/query_params_str_validations/tutorial010_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="20"
{!> ../../../docs_src/query_params_str_validations/tutorial010_an.py!}
@@ -839,11 +839,11 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
- ```Python hl_lines="17"
+ ```Python hl_lines="16"
{!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
@@ -872,7 +872,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
{!> ../../../docs_src/query_params_str_validations/tutorial014_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="11"
{!> ../../../docs_src/query_params_str_validations/tutorial014_an.py!}
@@ -887,7 +887,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
{!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
Рекомендуется использовать версию с `Annotated` если возможно.
diff --git a/docs/ru/docs/tutorial/query-params.md b/docs/ru/docs/tutorial/query-params.md
index 68333ec56..6e885cb65 100644
--- a/docs/ru/docs/tutorial/query-params.md
+++ b/docs/ru/docs/tutorial/query-params.md
@@ -69,7 +69,7 @@ http://127.0.0.1:8000/items/?skip=20
{!> ../../../docs_src/query_params/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial002.py!}
@@ -90,7 +90,7 @@ http://127.0.0.1:8000/items/?skip=20
{!> ../../../docs_src/query_params/tutorial003_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/query_params/tutorial003.py!}
@@ -143,7 +143,7 @@ http://127.0.0.1:8000/items/foo?short=yes
{!> ../../../docs_src/query_params/tutorial004_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="8 10"
{!> ../../../docs_src/query_params/tutorial004.py!}
@@ -209,7 +209,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
{!> ../../../docs_src/query_params/tutorial006_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/query_params/tutorial006.py!}
diff --git a/docs/ru/docs/tutorial/request-forms.md b/docs/ru/docs/tutorial/request-forms.md
new file mode 100644
index 000000000..0fc9e4eda
--- /dev/null
+++ b/docs/ru/docs/tutorial/request-forms.md
@@ -0,0 +1,92 @@
+# Данные формы
+
+Когда вам нужно получить поля формы вместо JSON, вы можете использовать `Form`.
+
+!!! info "Дополнительная информация"
+ Чтобы использовать формы, сначала установите `python-multipart`.
+
+ Например, выполните команду `pip install python-multipart`.
+
+## Импорт `Form`
+
+Импортируйте `Form` из `fastapi`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_forms/tutorial001_an.py!}
+ ```
+
+=== "Python 3.8+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать 'Annotated' версию, если это возможно.
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/request_forms/tutorial001.py!}
+ ```
+
+## Определение параметров `Form`
+
+Создайте параметры формы так же, как это делается для `Body` или `Query`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/request_forms/tutorial001_an.py!}
+ ```
+
+=== "Python 3.8+ без Annotated"
+
+ !!! tip "Подсказка"
+ Рекомендуется использовать 'Annotated' версию, если это возможно.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/request_forms/tutorial001.py!}
+ ```
+
+Например, в одном из способов использования спецификации OAuth2 (называемом "потоком пароля") требуется отправить `username` и `password` в виде полей формы.
+
+Данный способ требует отправку данных для авторизации посредством формы (а не JSON) и обязательного наличия в форме строго именованных полей `username` и `password`.
+
+Вы можете настроить `Form` точно так же, как настраиваете и `Body` ( `Query`, `Path`, `Cookie`), включая валидации, примеры, псевдонимы (например, `user-name` вместо `username`) и т.д.
+
+!!! info "Дополнительная информация"
+ `Form` - это класс, который наследуется непосредственно от `Body`.
+
+!!! tip "Подсказка"
+ Вам необходимо явно указывать параметр `Form` при объявлении каждого поля, иначе поля будут интерпретироваться как параметры запроса или параметры тела (JSON).
+
+## О "полях формы"
+
+Обычно способ, которым HTML-формы (``) отправляют данные на сервер, использует "специальное" кодирование для этих данных, отличное от JSON.
+
+**FastAPI** гарантирует правильное чтение этих данных из соответствующего места, а не из JSON.
+
+!!! note "Технические детали"
+ Данные из форм обычно кодируются с использованием "типа медиа" `application/x-www-form-urlencoded`.
+
+ Но когда форма содержит файлы, она кодируется как `multipart/form-data`. Вы узнаете о работе с файлами в следующей главе.
+
+ Если вы хотите узнать больше про кодировки и поля формы, ознакомьтесь с документацией MDN для `POST` на веб-сайте.
+
+!!! warning "Предупреждение"
+ Вы можете объявлять несколько параметров `Form` в *операции пути*, но вы не можете одновременно с этим объявлять поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с использованием `application/x-www-form-urlencoded`, а не `application/json`.
+
+ Это не ограничение **FastAPI**, это часть протокола HTTP.
+
+## Резюме
+
+Используйте `Form` для объявления входных параметров данных формы.
diff --git a/docs/ru/docs/tutorial/response-model.md b/docs/ru/docs/tutorial/response-model.md
index c5e111790..38b45e2a5 100644
--- a/docs/ru/docs/tutorial/response-model.md
+++ b/docs/ru/docs/tutorial/response-model.md
@@ -16,7 +16,7 @@ FastAPI позволяет использовать **аннотации тип
{!> ../../../docs_src/response_model/tutorial001_01_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="18 23"
{!> ../../../docs_src/response_model/tutorial001_01.py!}
@@ -65,7 +65,7 @@ FastAPI будет использовать этот возвращаемый т
{!> ../../../docs_src/response_model/tutorial001_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="17 22 24-27"
{!> ../../../docs_src/response_model/tutorial001.py!}
@@ -101,7 +101,7 @@ FastAPI будет использовать значение `response_model` д
{!> ../../../docs_src/response_model/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9 11"
{!> ../../../docs_src/response_model/tutorial002.py!}
@@ -120,7 +120,7 @@ FastAPI будет использовать значение `response_model` д
{!> ../../../docs_src/response_model/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="18"
{!> ../../../docs_src/response_model/tutorial002.py!}
@@ -145,7 +145,7 @@ FastAPI будет использовать значение `response_model` д
{!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9 11 16"
{!> ../../../docs_src/response_model/tutorial003.py!}
@@ -159,7 +159,7 @@ FastAPI будет использовать значение `response_model` д
{!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="24"
{!> ../../../docs_src/response_model/tutorial003.py!}
@@ -173,7 +173,7 @@ FastAPI будет использовать значение `response_model` д
{!> ../../../docs_src/response_model/tutorial003_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="22"
{!> ../../../docs_src/response_model/tutorial003.py!}
@@ -207,7 +207,7 @@ FastAPI будет использовать значение `response_model` д
{!> ../../../docs_src/response_model/tutorial003_01_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9-13 15-16 20"
{!> ../../../docs_src/response_model/tutorial003_01.py!}
@@ -283,7 +283,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
{!> ../../../docs_src/response_model/tutorial003_04_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10"
{!> ../../../docs_src/response_model/tutorial003_04.py!}
@@ -305,7 +305,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
{!> ../../../docs_src/response_model/tutorial003_05_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/response_model/tutorial003_05.py!}
@@ -329,7 +329,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
{!> ../../../docs_src/response_model/tutorial004_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="11 13-14"
{!> ../../../docs_src/response_model/tutorial004.py!}
@@ -359,7 +359,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
{!> ../../../docs_src/response_model/tutorial004_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="24"
{!> ../../../docs_src/response_model/tutorial004.py!}
@@ -446,7 +446,7 @@ FastAPI достаточно умен (на самом деле, это засл
{!> ../../../docs_src/response_model/tutorial005_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="31 37"
{!> ../../../docs_src/response_model/tutorial005.py!}
@@ -467,7 +467,7 @@ FastAPI достаточно умен (на самом деле, это засл
{!> ../../../docs_src/response_model/tutorial006_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="31 37"
{!> ../../../docs_src/response_model/tutorial006.py!}
diff --git a/docs/ru/docs/tutorial/schema-extra-example.md b/docs/ru/docs/tutorial/schema-extra-example.md
index a0363b9ba..a13ab5935 100644
--- a/docs/ru/docs/tutorial/schema-extra-example.md
+++ b/docs/ru/docs/tutorial/schema-extra-example.md
@@ -14,7 +14,7 @@
{!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="15-23"
{!> ../../../docs_src/schema_extra_example/tutorial001.py!}
@@ -39,7 +39,7 @@
{!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="4 10-13"
{!> ../../../docs_src/schema_extra_example/tutorial002.py!}
@@ -78,7 +78,7 @@
{!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="23-28"
{!> ../../../docs_src/schema_extra_example/tutorial003_an.py!}
@@ -93,7 +93,7 @@
{!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
```
-=== "Python 3.6+ non-Annotated"
+=== "Python 3.8+ non-Annotated"
!!! tip Заметка
Рекомендуется использовать версию с `Annotated`, если это возможно.
@@ -133,7 +133,7 @@
{!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="24-50"
{!> ../../../docs_src/schema_extra_example/tutorial004_an.py!}
@@ -148,7 +148,7 @@
{!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!}
```
-=== "Python 3.6+ non-Annotated"
+=== "Python 3.8+ non-Annotated"
!!! tip Заметка
Рекомендуется использовать версию с `Annotated`, если это возможно.
diff --git a/docs/ru/docs/tutorial/security/index.md b/docs/ru/docs/tutorial/security/index.md
new file mode 100644
index 000000000..d5fe4e76f
--- /dev/null
+++ b/docs/ru/docs/tutorial/security/index.md
@@ -0,0 +1,101 @@
+# Настройка авторизации
+
+Существует множество способов обеспечения безопасности, аутентификации и авторизации.
+
+Обычно эта тема является достаточно сложной и трудной.
+
+Во многих фреймворках и системах только работа с определением доступов к приложению и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять более 50% от всего написанного кода).
+
+**FastAPI** предоставляет несколько инструментов, которые помогут вам настроить **Авторизацию** легко, быстро, стандартным способом, без необходимости изучать все её тонкости.
+
+Но сначала давайте рассмотрим некоторые небольшие концепции.
+
+## Куда-то торопишься?
+
+Если вам не нужна информация о каких-либо из следующих терминов и вам просто нужно добавить защиту с аутентификацией на основе логина и пароля *прямо сейчас*, переходите к следующим главам.
+
+## OAuth2
+
+OAuth2 - это протокол, который определяет несколько способов обработки аутентификации и авторизации.
+
+Он довольно обширен и охватывает несколько сложных вариантов использования.
+
+OAuth2 включает в себя способы аутентификации с использованием "третьей стороны".
+
+Это то, что используют под собой все кнопки "вход с помощью Facebook, Google, Twitter, GitHub" на страницах авторизации.
+
+### OAuth 1
+
+Ранее использовался протокол OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые описания того, как шифровать сообщение.
+
+В настоящее время он не очень популярен и не используется.
+
+OAuth2 не указывает, как шифровать сообщение, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.
+
+!!! tip "Подсказка"
+ В разделе **Развертывание** вы увидите [как настроить протокол HTTPS бесплатно, используя Traefik и Let's Encrypt.](https://fastapi.tiangolo.com/ru/deployment/https/)
+
+
+## OpenID Connect
+
+OpenID Connect - это еще один протокол, основанный на **OAuth2**.
+
+Он просто расширяет OAuth2, уточняя некоторые вещи, не имеющие однозначного определения в OAuth2, в попытке сделать его более совместимым.
+
+Например, для входа в Google используется OpenID Connect (который под собой использует OAuth2).
+
+Но вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2.
+
+### OpenID (не "OpenID Connect")
+
+Также ранее использовался стандарт "OpenID", который пытался решить ту же проблему, что и **OpenID Connect**, но не был основан на OAuth2.
+
+Таким образом, это была полноценная дополнительная система.
+
+В настоящее время не очень популярен и не используется.
+
+## OpenAPI
+
+OpenAPI (ранее известный как Swagger) - это открытая спецификация для создания API (в настоящее время является частью Linux Foundation).
+
+**FastAPI** основан на **OpenAPI**.
+
+Это то, что делает возможным наличие множества автоматических интерактивных интерфейсов документирования, сгенерированного кода и т.д.
+
+В OpenAPI есть способ использовать несколько "схем" безопасности.
+
+Таким образом, вы можете воспользоваться преимуществами Всех этих стандартных инструментов, включая интерактивные системы документирования.
+
+OpenAPI может использовать следующие схемы авторизации:
+
+* `apiKey`: уникальный идентификатор для приложения, который может быть получен из:
+ * Параметров запроса.
+ * Заголовка.
+ * Cookies.
+* `http`: стандартные системы аутентификации по протоколу HTTP, включая:
+ * `bearer`: заголовок `Authorization` со значением `Bearer {уникальный токен}`. Это унаследовано от OAuth2.
+ * Базовая аутентификация по протоколу HTTP.
+ * HTTP Digest и т.д.
+* `oauth2`: все способы обеспечения безопасности OAuth2 называемые "потоки" (англ. "flows").
+ * Некоторые из этих "потоков" подходят для реализации аутентификации через сторонний сервис использующий OAuth 2.0 (например, Google, Facebook, Twitter, GitHub и т.д.):
+ * `implicit`
+ * `clientCredentials`
+ * `authorizationCode`
+ * Но есть один конкретный "поток", который может быть идеально использован для обработки аутентификации непосредственно в том же приложении:
+ * `password`: в некоторых следующих главах будут рассмотрены примеры этого.
+* `openIdConnect`: способ определить, как автоматически обнаруживать данные аутентификации OAuth2.
+ * Это автоматическое обнаружение определено в спецификации OpenID Connect.
+
+
+!!! tip "Подсказка"
+ Интеграция сторонних сервисов для аутентификации/авторизации таких как Google, Facebook, Twitter, GitHub и т.д. осуществляется достаточно легко.
+
+ Самой сложной проблемой является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжелую работу за вас.
+
+## Преимущества **FastAPI**
+
+Fast API предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.
+
+В следующих главах вы увидите, как обезопасить свой API, используя инструменты, предоставляемые **FastAPI**.
+
+И вы также увидите, как он автоматически интегрируется в систему интерактивной документации.
diff --git a/docs/ru/docs/tutorial/testing.md b/docs/ru/docs/tutorial/testing.md
index 3f9005112..ca47a6f51 100644
--- a/docs/ru/docs/tutorial/testing.md
+++ b/docs/ru/docs/tutorial/testing.md
@@ -122,7 +122,7 @@
{!> ../../../docs_src/app_testing/app_b_an_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python
{!> ../../../docs_src/app_testing/app_b_an/main.py!}
@@ -137,7 +137,7 @@
{!> ../../../docs_src/app_testing/app_b_py310/main.py!}
```
-=== "Python 3.6+ без Annotated"
+=== "Python 3.8+ без Annotated"
!!! tip "Подсказка"
По возможности используйте версию с `Annotated`.
diff --git a/docs/tr/docs/features.md b/docs/tr/docs/features.md
index f8220fb58..8b143ffe7 100644
--- a/docs/tr/docs/features.md
+++ b/docs/tr/docs/features.md
@@ -27,7 +27,7 @@ OpenAPI standartlarına dayalı olan bir framework olarak, geliştiricilerin bir
### Sadece modern Python
-Tamamiyle standartlar **Python 3.6**'nın type hintlerine dayanıyor (Pydantic'in sayesinde). Yeni bir syntax öğrenmene gerek yok. Sadece modern Python.
+Tamamiyle standartlar **Python 3.8**'nın type hintlerine dayanıyor (Pydantic'in sayesinde). Yeni bir syntax öğrenmene gerek yok. Sadece modern Python.
Eğer Python type hintlerini bilmiyorsan veya bir hatırlatmaya ihtiyacın var ise(FastAPI kullanmasan bile) şu iki dakikalık küçük bilgilendirici içeriğe bir göz at: [Python Types](python-types.md){.internal-link target=_blank}.
diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md
index e74efbc2f..e61f5b82c 100644
--- a/docs/tr/docs/index.md
+++ b/docs/tr/docs/index.md
@@ -24,7 +24,7 @@
---
-FastAPI, Python 3.6+'nın standart type hintlerine dayanan modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'ü.
+FastAPI, Python 3.8+'nın standart type hintlerine dayanan modern ve hızlı (yüksek performanslı) API'lar oluşturmak için kullanılabilecek web framework'ü.
Ana özellikleri:
@@ -115,7 +115,7 @@ Eğer API yerine komut satırı uygulaması
## Gereksinimler
-Python 3.7+
+Python 3.8+
FastAPI iki devin omuzları üstünde duruyor:
@@ -331,7 +331,7 @@ Type-hinting işlemini Python dilindeki standart veri tipleri ile yapabilirsin
Yeni bir syntax'e alışmana gerek yok, metodlar ve classlar zaten spesifik kütüphanelere ait.
-Sadece standart **Python 3.6+**.
+Sadece standart **Python 3.8+**.
Örnek olarak, `int` tanımlamak için:
diff --git a/docs/uk/docs/alternatives.md b/docs/uk/docs/alternatives.md
new file mode 100644
index 000000000..e71257976
--- /dev/null
+++ b/docs/uk/docs/alternatives.md
@@ -0,0 +1,412 @@
+# Альтернативи, натхнення та порівняння
+
+Що надихнуло на створення **FastAPI**, який він у порінянні з іншими альтернативами та чого він у них навчився.
+
+## Вступ
+
+**FastAPI** не існувало б, якби не попередні роботи інших.
+
+Раніше було створено багато інструментів, які надихнули на його створення.
+
+Я кілька років уникав створення нового фреймворку. Спочатку я спробував вирішити всі функції, охоплені **FastAPI**, використовуючи багато різних фреймворків, плагінів та інструментів.
+
+Але в якийсь момент не було іншого виходу, окрім створення чогось, що надавало б усі ці функції, взявши найкращі ідеї з попередніх інструментів і поєднавши їх найкращим чином, використовуючи мовні функції, які навіть не були доступні раніше (Python 3.6+ підказки типів).
+
+## Попередні інструменти
+
+### Django
+
+Це найпопулярніший фреймворк Python, який користується широкою довірою. Він використовується для створення таких систем, як Instagram.
+
+Він відносно тісно пов’язаний з реляційними базами даних (наприклад, MySQL або PostgreSQL), тому мати базу даних NoSQL (наприклад, Couchbase, MongoDB, Cassandra тощо) як основний механізм зберігання не дуже просто.
+
+Він був створений для створення HTML у серверній частині, а не для створення API, які використовуються сучасним інтерфейсом (як-от React, Vue.js і Angular) або іншими системами (як-от IoT пристрої), які спілкуються з ним.
+
+### Django REST Framework
+
+Фреймворк Django REST був створений як гнучкий інструментарій для створення веб-інтерфейсів API використовуючи Django в основі, щоб покращити його можливості API.
+
+Його використовують багато компаній, включаючи Mozilla, Red Hat і Eventbrite.
+
+Це був один із перших прикладів **автоматичної документації API**, і саме це була одна з перших ідей, яка надихнула на «пошук» **FastAPI**.
+
+!!! Примітка
+ Django REST Framework створив Том Крісті. Той самий творець Starlette і Uvicorn, на яких базується **FastAPI**.
+
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Мати автоматичний веб-інтерфейс документації API.
+
+### Flask
+
+Flask — це «мікрофреймворк», він не включає інтеграцію бази даних, а також багато речей, які за замовчуванням є в Django.
+
+Ця простота та гнучкість дозволяють використовувати бази даних NoSQL як основну систему зберігання даних.
+
+Оскільки він дуже простий, він порівняно легкий та інтуїтивний для освоєння, хоча в деяких моментах документація стає дещо технічною.
+
+Він також зазвичай використовується для інших програм, яким не обов’язково потрібна база даних, керування користувачами або будь-яка з багатьох функцій, які є попередньо вбудованими в Django. Хоча багато з цих функцій можна додати за допомогою плагінів.
+
+Відокремлення частин було ключовою особливістю, яку я хотів зберегти, при цьому залишаючись «мікрофреймворком», який можна розширити, щоб охопити саме те, що потрібно.
+
+Враховуючи простоту Flask, він здавався хорошим підходом для створення API. Наступним, що знайшов, був «Django REST Framework» для Flask.
+
+!!! Переглянте "Надихнуло **FastAPI** на"
+ Бути мікрофреймоворком. Зробити легким комбінування та поєднання необхідних інструментів та частин.
+
+ Мати просту та легку у використанні систему маршрутизації.
+
+
+### Requests
+
+**FastAPI** насправді не є альтернативою **Requests**. Сфера їх застосування дуже різна.
+
+Насправді цілком звична річ використовувати Requests *всередині* програми FastAPI.
+
+Але все ж FastAPI черпав натхнення з Requests.
+
+**Requests** — це бібліотека для *взаємодії* з API (як клієнт), а **FastAPI** — це бібліотека для *створення* API (як сервер).
+
+Вони більш-менш знаходяться на протилежних кінцях, доповнюючи одна одну.
+
+Requests мають дуже простий та інтуїтивно зрозумілий дизайн, дуже простий у використанні, з розумними параметрами за замовчуванням. Але в той же час він дуже потужний і налаштовується.
+
+Ось чому, як сказано на офіційному сайті:
+
+> Requests є одним із найбільш завантажуваних пакетів Python усіх часів
+
+Використовувати його дуже просто. Наприклад, щоб виконати запит `GET`, ви повинні написати:
+
+```Python
+response = requests.get("http://example.com/some/url")
+```
+
+Відповідна операція *роуту* API FastAPI може виглядати так:
+
+```Python hl_lines="1"
+@app.get("/some/url")
+def read_url():
+ return {"message": "Hello World"}
+```
+
+Зверніть увагу на схожість у `requests.get(...)` і `@app.get(...)`.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ * Майте простий та інтуїтивно зрозумілий API.
+ * Використовуйте імена (операції) методів HTTP безпосередньо, простим та інтуїтивно зрозумілим способом.
+ * Розумні параметри за замовчуванням, але потужні налаштування.
+
+
+### Swagger / OpenAPI
+
+Головною функцією, яку я хотів від Django REST Framework, була автоматична API документація.
+
+Потім я виявив, що існує стандарт для документування API з використанням JSON (або YAML, розширення JSON) під назвою Swagger.
+
+І вже був створений веб-інтерфейс користувача для Swagger API. Отже, можливість генерувати документацію Swagger для API дозволить використовувати цей веб-інтерфейс автоматично.
+
+У якийсь момент Swagger було передано Linux Foundation, щоб перейменувати його на OpenAPI.
+
+Тому, коли говорять про версію 2.0, прийнято говорити «Swagger», а про версію 3+ «OpenAPI».
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Прийняти і використовувати відкритий стандарт для специфікацій API замість спеціальної схеми.
+
+ Інтегрувати інструменти інтерфейсу на основі стандартів:
+
+ * Інтерфейс Swagger
+ * ReDoc
+
+ Ці два було обрано через те, що вони досить популярні та стабільні, але, виконавши швидкий пошук, ви можете знайти десятки додаткових альтернативних інтерфейсів для OpenAPI (які можна використовувати з **FastAPI**).
+
+### Фреймворки REST для Flask
+
+Існує кілька фреймворків Flask REST, але, витративши час і роботу на їх дослідження, я виявив, що багато з них припинено або залишено, з кількома постійними проблемами, які зробили їх непридатними.
+
+### Marshmallow
+
+Однією з головних функцій, необхідних для систем API, є "серіалізація", яка бере дані з коду (Python) і перетворює їх на щось, що можна надіслати через мережу. Наприклад, перетворення об’єкта, що містить дані з бази даних, на об’єкт JSON. Перетворення об’єктів `datetime` на строки тощо.
+
+Іншою важливою функцією, необхідною для API, є перевірка даних, яка забезпечує дійсність даних за певними параметрами. Наприклад, що деяке поле є `int`, а не деяка випадкова строка. Це особливо корисно для вхідних даних.
+
+Без системи перевірки даних вам довелося б виконувати всі перевірки вручну, у коді.
+
+Marshmallow створено для забезпечення цих функцій. Це чудова бібліотека, і я часто нею користувався раніше.
+
+Але він був створений до того, як існували підказки типу Python. Отже, щоб визначити кожну схему, вам потрібно використовувати спеціальні утиліти та класи, надані Marshmallow.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Використовувати код для автоматичного визначення "схем", які надають типи даних і перевірку.
+
+### Webargs
+
+Іншою важливою функцією, необхідною для API, є аналіз даних із вхідних запитів.
+
+Webargs — це інструмент, створений, щоб забезпечити це поверх кількох фреймворків, включаючи Flask.
+
+Він використовує Marshmallow в основі для перевірки даних. І створений тими ж розробниками.
+
+Це чудовий інструмент, і я також часто використовував його, перш ніж створити **FastAPI**.
+
+!!! Інформація
+ Webargs був створений тими ж розробниками Marshmallow.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Мати автоматичну перевірку даних вхідного запиту.
+
+### APISpec
+
+Marshmallow і Webargs забезпечують перевірку, аналіз і серіалізацію як плагіни.
+
+Але документація досі відсутня. Потім було створено APISpec.
+
+Це плагін для багатьох фреймворків (також є плагін для Starlette).
+
+Принцип роботи полягає в тому, що ви пишете визначення схеми, використовуючи формат YAML, у docstring кожної функції, що обробляє маршрут.
+
+І він генерує схеми OpenAPI.
+
+Так це працює у Flask, Starlette, Responder тощо.
+
+Але потім ми знову маємо проблему наявності мікросинтаксису всередині Python строки (великий YAML).
+
+Редактор тут нічим не може допомогти. І якщо ми змінимо параметри чи схеми Marshmallow і забудемо також змінити цю строку документа YAML, згенерована схема буде застарілою.
+
+!!! Інформація
+ APISpec був створений тими ж розробниками Marshmallow.
+
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Підтримувати відкритий стандарт API, OpenAPI.
+
+### Flask-apispec
+
+Це плагін Flask, який об’єднує Webargs, Marshmallow і APISpec.
+
+Він використовує інформацію з Webargs і Marshmallow для автоматичного створення схем OpenAPI за допомогою APISpec.
+
+Це чудовий інструмент, дуже недооцінений. Він має бути набагато популярнішим, ніж багато плагінів Flask. Це може бути пов’язано з тим, що його документація надто стисла й абстрактна.
+
+Це вирішило необхідність писати YAML (інший синтаксис) всередині рядків документів Python.
+
+Ця комбінація Flask, Flask-apispec із Marshmallow і Webargs була моїм улюбленим бекенд-стеком до створення **FastAPI**.
+
+Їі використання призвело до створення кількох генераторів повного стека Flask. Це основний стек, який я (та кілька зовнішніх команд) використовував досі:
+
+* https://github.com/tiangolo/full-stack
+* https://github.com/tiangolo/full-stack-flask-couchbase
+* https://github.com/tiangolo/full-stack-flask-couchdb
+
+І ці самі генератори повного стеку були основою [**FastAPI** генераторів проектів](project-generation.md){.internal-link target=_blank}.
+
+!!! Інформація
+ Flask-apispec був створений тими ж розробниками Marshmallow.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Створення схеми OpenAPI автоматично з того самого коду, який визначає серіалізацію та перевірку.
+
+### NestJS (та Angular)
+
+Це навіть не Python, NestJS — це фреймворк NodeJS JavaScript (TypeScript), натхненний Angular.
+
+Це досягає чогось подібного до того, що можна зробити з Flask-apispec.
+
+Він має інтегровану систему впровадження залежностей, натхненну Angular two. Він потребує попередньої реєстрації «injectables» (як і всі інші системи впровадження залежностей, які я знаю), тому це збільшує багатослівність та повторення коду.
+
+Оскільки параметри описані за допомогою типів TypeScript (подібно до підказок типу Python), підтримка редактора досить хороша.
+
+Але оскільки дані TypeScript не зберігаються після компіляції в JavaScript, вони не можуть покладатися на типи для визначення перевірки, серіалізації та документації одночасно. Через це та деякі дизайнерські рішення, щоб отримати перевірку, серіалізацію та автоматичну генерацію схеми, потрібно додати декоратори в багатьох місцях. Таким чином код стає досить багатослівним.
+
+Він не дуже добре обробляє вкладені моделі. Отже, якщо тіло JSON у запиті є об’єктом JSON із внутрішніми полями, які, у свою чергу, є вкладеними об’єктами JSON, його неможливо належним чином задокументувати та перевірити.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Використовувати типи Python, щоб мати чудову підтримку редактора.
+
+ Мати потужну систему впровадження залежностей. Знайдіть спосіб звести до мінімуму повторення коду.
+
+### Sanic
+
+Це був один із перших надзвичайно швидких фреймворків Python на основі `asyncio`. Він був дуже схожий на Flask.
+
+!!! Примітка "Технічні деталі"
+ Він використовував `uvloop` замість стандартного циклу Python `asyncio`. Ось що зробило його таким швидким.
+
+ Це явно надихнуло Uvicorn і Starlette, які зараз швидші за Sanic у відкритих тестах.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Знайти спосіб отримати божевільну продуктивність.
+
+ Ось чому **FastAPI** базується на Starlette, оскільки це найшвидша доступна структура (перевірена тестами сторонніх розробників).
+
+### Falcon
+
+Falcon — ще один високопродуктивний фреймворк Python, він розроблений як мінімальний і працює як основа інших фреймворків, таких як Hug.
+
+Він розроблений таким чином, щоб мати функції, які отримують два параметри, один «запит» і один «відповідь». Потім ви «читаєте» частини запиту та «записуєте» частини у відповідь. Через такий дизайн неможливо оголосити параметри запиту та тіла за допомогою стандартних підказок типу Python як параметри функції.
+
+Таким чином, перевірка даних, серіалізація та документація повинні виконуватися в коді, а не автоматично. Або вони повинні бути реалізовані як фреймворк поверх Falcon, як Hug. Така сама відмінність спостерігається в інших фреймворках, натхненних дизайном Falcon, що мають один об’єкт запиту та один об’єкт відповіді як параметри.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Знайти способи отримати чудову продуктивність.
+
+ Разом із Hug (оскільки Hug базується на Falcon) надихнув **FastAPI** оголосити параметр `response` у функціях.
+
+ Хоча у FastAPI це необов’язково, і використовується в основному для встановлення заголовків, файлів cookie та альтернативних кодів стану.
+
+### Molten
+
+Я відкрив для себе Molten на перших етапах створення **FastAPI**. І він має досить схожі ідеї:
+
+* Базується на підказках типу Python.
+* Перевірка та документація цих типів.
+* Система впровадження залежностей.
+
+Він не використовує перевірку даних, серіалізацію та бібліотеку документації сторонніх розробників, як Pydantic, він має свою власну. Таким чином, ці визначення типів даних не можна було б використовувати повторно так легко.
+
+Це вимагає трохи більш докладних конфігурацій. І оскільки він заснований на WSGI (замість ASGI), він не призначений для використання високопродуктивних інструментів, таких як Uvicorn, Starlette і Sanic.
+
+Система впровадження залежностей вимагає попередньої реєстрації залежностей, і залежності вирішуються на основі оголошених типів. Отже, неможливо оголосити більше ніж один «компонент», який надає певний тип.
+
+Маршрути оголошуються в одному місці з використанням функцій, оголошених в інших місцях (замість використання декораторів, які можна розмістити безпосередньо поверх функції, яка обробляє кінцеву точку). Це ближче до того, як це робить Django, ніж до Flask (і Starlette). Він розділяє в коді речі, які відносно тісно пов’язані.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Визначити додаткові перевірки для типів даних, використовуючи значення "за замовчуванням" атрибутів моделі. Це покращує підтримку редактора, а раніше вона була недоступна в Pydantic.
+
+ Це фактично надихнуло оновити частини Pydantic, щоб підтримувати той самий стиль оголошення перевірки (всі ці функції вже доступні в Pydantic).
+
+### Hug
+
+Hug був одним із перших фреймворків, який реалізував оголошення типів параметрів API за допомогою підказок типу Python. Це була чудова ідея, яка надихнула інші інструменти зробити те саме.
+
+Він використовував спеціальні типи у своїх оголошеннях замість стандартних типів Python, але це все одно був величезний крок вперед.
+
+Це також був один із перших фреймворків, який генерував спеціальну схему, що оголошувала весь API у JSON.
+
+Він не базувався на таких стандартах, як OpenAPI та JSON Schema. Тому було б непросто інтегрувати його з іншими інструментами, як-от Swagger UI. Але знову ж таки, це була дуже інноваційна ідея.
+
+Він має цікаву незвичайну функцію: використовуючи ту саму структуру, можна створювати API, а також CLI.
+
+Оскільки він заснований на попередньому стандарті для синхронних веб-фреймворків Python (WSGI), він не може працювати з Websockets та іншими речами, хоча він також має високу продуктивність.
+
+!!! Інформація
+ Hug створив Тімоті Крослі, той самий творець `isort`, чудовий інструмент для автоматичного сортування імпорту у файлах Python.
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Hug надихнув частину APIStar і був одним із найбільш перспективних інструментів, поряд із APIStar.
+
+ Hug надихнув **FastAPI** на використання підказок типу Python для оголошення параметрів і автоматичного створення схеми, що визначає API.
+
+ Hug надихнув **FastAPI** оголосити параметр `response` у функціях для встановлення заголовків і файлів cookie.
+
+### APIStar (<= 0,5)
+
+Безпосередньо перед тим, як вирішити створити **FastAPI**, я знайшов сервер **APIStar**. Він мав майже все, що я шукав, і мав чудовий дизайн.
+
+Це була одна з перших реалізацій фреймворку, що використовує підказки типу Python для оголошення параметрів і запитів, яку я коли-небудь бачив (до NestJS і Molten). Я знайшов його більш-менш одночасно з Hug. Але APIStar використовував стандарт OpenAPI.
+
+Він мав автоматичну перевірку даних, серіалізацію даних і генерацію схеми OpenAPI на основі підказок того самого типу в кількох місцях.
+
+Визначення схеми тіла не використовували ті самі підказки типу Python, як Pydantic, воно було трохи схоже на Marshmallow, тому підтримка редактора була б не такою хорошою, але все ж APIStar був найкращим доступним варіантом.
+
+Він мав найкращі показники продуктивності на той час (перевершив лише Starlette).
+
+Спочатку він не мав автоматичного веб-інтерфейсу документації API, але я знав, що можу додати до нього інтерфейс користувача Swagger.
+
+Він мав систему введення залежностей. Він вимагав попередньої реєстрації компонентів, як і інші інструменти, розглянуті вище. Але все одно це була чудова функція.
+
+Я ніколи не міг використовувати його в повноцінному проекті, оскільки він не мав інтеграції безпеки, тому я не міг замінити всі функції, які мав, генераторами повного стеку на основі Flask-apispec. У моїх невиконаних проектах я мав створити запит на вилучення, додавши цю функцію.
+
+Але потім фокус проекту змінився.
+
+Це вже не був веб-фреймворк API, оскільки творцю потрібно було зосередитися на Starlette.
+
+Тепер APIStar — це набір інструментів для перевірки специфікацій OpenAPI, а не веб-фреймворк.
+
+!!! Інформація
+ APIStar створив Том Крісті. Той самий хлопець, який створив:
+
+ * Django REST Framework
+ * Starlette (на якому базується **FastAPI**)
+ * Uvicorn (використовується Starlette і **FastAPI**)
+
+!!! Перегляньте "Надихнуло **FastAPI** на"
+ Існувати.
+
+ Ідею оголошення кількох речей (перевірки даних, серіалізації та документації) за допомогою тих самих типів Python, які в той же час забезпечували чудову підтримку редактора, я вважав геніальною ідеєю.
+
+ І після тривалого пошуку подібної структури та тестування багатьох різних альтернатив, APIStar став найкращим доступним варіантом.
+
+ Потім APIStar перестав існувати як сервер, і було створено Starlette, який став новою кращою основою для такої системи. Це стало останнім джерелом натхнення для створення **FastAPI**. Я вважаю **FastAPI** «духовним спадкоємцем» APIStar, удосконалюючи та розширюючи функції, систему введення тексту та інші частини на основі досвіду, отриманого від усіх цих попередніх інструментів.
+
+## Використовується **FastAPI**
+
+### Pydantic
+
+Pydantic — це бібліотека для визначення перевірки даних, серіалізації та документації (за допомогою схеми JSON) на основі підказок типу Python.
+
+Це робить його надзвичайно інтуїтивним.
+
+Його можна порівняти з Marshmallow. Хоча він швидший за Marshmallow у тестах. Оскільки він базується на тих самих підказках типу Python, підтримка редактора чудова.
+
+!!! Перегляньте "**FastAPI** використовує його для"
+ Виконання перевірки всіх даних, серіалізації даних і автоматичної документацію моделі (на основі схеми JSON).
+
+ Потім **FastAPI** бере ці дані схеми JSON і розміщує їх у OpenAPI, окремо від усіх інших речей, які він робить.
+
+### Starlette
+
+Starlette — це легкий фреймворк/набір інструментів ASGI, який ідеально підходить для створення високопродуктивних asyncio сервісів.
+
+Він дуже простий та інтуїтивно зрозумілий. Його розроблено таким чином, щоб його можна було легко розширювати та мати модульні компоненти.
+
+Він має:
+
+* Серйозно вражаючу продуктивність.
+* Підтримку WebSocket.
+* Фонові завдання в процесі.
+* Події запуску та завершення роботи.
+* Тестового клієнта, побудований на HTTPX.
+* CORS, GZip, статичні файли, потокові відповіді.
+* Підтримку сеансів і файлів cookie.
+* 100% покриття тестом.
+* 100% анотовану кодову базу.
+* Кілька жорстких залежностей.
+
+Starlette наразі є найшвидшим фреймворком Python із перевірених. Перевершує лише Uvicorn, який є не фреймворком, а сервером.
+
+Starlette надає всі основні функції веб-мікрофреймворку.
+
+Але він не забезпечує автоматичної перевірки даних, серіалізації чи документації.
+
+Це одна з головних речей, які **FastAPI** додає зверху, все на основі підказок типу Python (з використанням Pydantic). Це, а також система впровадження залежностей, утиліти безпеки, створення схеми OpenAPI тощо.
+
+!!! Примітка "Технічні деталі"
+ ASGI — це новий «стандарт», який розробляється членами основної команди Django. Це ще не «стандарт Python» (PEP), хоча вони в процесі цього.
+
+ Тим не менш, він уже використовується як «стандарт» кількома інструментами. Це значно покращує сумісність, оскільки ви можете переключити Uvicorn на будь-який інший сервер ASGI (наприклад, Daphne або Hypercorn), або ви можете додати інструменти, сумісні з ASGI, як-от `python-socketio`.
+
+!!! Перегляньте "**FastAPI** використовує його для"
+ Керування всіма основними веб-частинами. Додавання функцій зверху.
+
+ Сам клас `FastAPI` безпосередньо успадковує клас `Starlette`.
+
+ Отже, усе, що ви можете робити зі Starlette, ви можете робити це безпосередньо за допомогою **FastAPI**, оскільки це, по суті, Starlette на стероїдах.
+
+### Uvicorn
+
+Uvicorn — це блискавичний сервер ASGI, побудований на uvloop і httptools.
+
+Це не веб-фреймворк, а сервер. Наприклад, він не надає інструментів для маршрутизації. Це те, що фреймворк на кшталт Starlette (або **FastAPI**) забезпечить поверх нього.
+
+Це рекомендований сервер для Starlette і **FastAPI**.
+
+!!! Перегляньте "**FastAPI** рекомендує це як"
+ Основний веб-сервер для запуску програм **FastAPI**.
+
+ Ви можете поєднати його з Gunicorn, щоб мати асинхронний багатопроцесний сервер.
+
+ Додаткову інформацію див. у розділі [Розгортання](deployment/index.md){.internal-link target=_blank}.
+
+## Орієнтири та швидкість
+
+Щоб зрозуміти, порівняти та побачити різницю між Uvicorn, Starlette і FastAPI, перегляньте розділ про [Бенчмарки](benchmarks.md){.internal-link target=_blank}.
diff --git a/docs/uk/docs/fastapi-people.md b/docs/uk/docs/fastapi-people.md
new file mode 100644
index 000000000..b32f0e5ce
--- /dev/null
+++ b/docs/uk/docs/fastapi-people.md
@@ -0,0 +1,178 @@
+# Люди FastAPI
+
+FastAPI має дивовижну спільноту, яка вітає людей різного походження.
+
+## Творець – Супроводжувач
+
+Привіт! 👋
+
+Це я:
+
+{% if people %}
+
+{% for user in people.maintainers %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+Я - творець і супроводжувач **FastAPI**. Детальніше про це можна прочитати в [Довідка FastAPI - Отримати довідку - Зв'язатися з автором](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}.
+
+...Але тут я хочу показати вам спільноту.
+
+---
+
+**FastAPI** отримує велику підтримку від спільноти. І я хочу відзначити їхній внесок.
+
+Це люди, які:
+
+* [Допомагають іншим із проблемами (запитаннями) у GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}.
+* [Створюють пул реквести](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}.
+* Переглядають пул реквести, [особливо важливо для перекладів](contributing.md#translations){.internal-link target=_blank}.
+
+Оплески їм. 👏 🙇
+
+## Найбільш активні користувачі минулого місяця
+
+Це користувачі, які [найбільше допомагали іншим із проблемами (запитаннями) у GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} протягом минулого місяця. ☕
+
+{% if people %}
+
+{% for user in people.last_month_active %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+## Експерти
+
+Ось **експерти FastAPI**. 🤓
+
+Це користувачі, які [найбільше допомагали іншим із проблемами (запитаннями) у GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} протягом *всього часу*.
+
+Вони зарекомендували себе як експерти, допомагаючи багатьом іншим. ✨
+
+{% if people %}
+
+{% for user in people.experts %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+## Найкращі контрибютори
+
+Ось **Найкращі контрибютори**. 👷
+
+Ці користувачі [створили найбільшу кількість пул реквестів](help-fastapi.md#create-a-pull-request){.internal-link target=_blank} які були *змержені*.
+
+Вони надали програмний код, документацію, переклади тощо. 📦
+
+{% if people %}
+
+{% for user in people.top_contributors %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+Є багато інших контрибюторів (більше сотні), їх усіх можна побачити на сторінці FastAPI GitHub Contributors. 👷
+
+## Найкращі рецензенти
+
+Ці користувачі є **Найкращими рецензентами**. 🕵️
+
+### Рецензенти на переклади
+
+Я розмовляю лише кількома мовами (і не дуже добре 😅). Отже, рецензенти – це ті, хто має [**повноваження схвалювати переклади**](contributing.md#translations){.internal-link target=_blank} документації. Без них не було б документації кількома іншими мовами.
+
+---
+
+**Найкращі рецензенти** 🕵️ переглянули більшість пул реквестів від інших, забезпечуючи якість коду, документації і особливо **перекладів**.
+
+{% if people %}
+
+{% for user in people.top_reviewers %}
+
+
+{% endfor %}
+
+
+{% endif %}
+
+## Спонсори
+
+Це **Спонсори**. 😎
+
+Вони підтримують мою роботу з **FastAPI** (та іншими), переважно через GitHub Sponsors.
+
+{% if sponsors %}
+
+{% if sponsors.gold %}
+
+### Золоті спонсори
+
+{% for sponsor in sponsors.gold -%}
+
+{% endfor %}
+{% endif %}
+
+{% if sponsors.silver %}
+
+### Срібні спонсори
+
+{% for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+{% if sponsors.bronze %}
+
+### Бронзові спонсори
+
+{% for sponsor in sponsors.bronze -%}
+
+{% endfor %}
+{% endif %}
+
+{% endif %}
+
+### Індивідуальні спонсори
+
+{% if github_sponsors %}
+{% for group in github_sponsors.sponsors %}
+
+
+
+{% for user in group %}
+{% if user.login not in sponsors_badge.logins %}
+
+
+
+{% endif %}
+{% endfor %}
+
+
+
+{% endfor %}
+{% endif %}
+
+## Про дані - технічні деталі
+
+Основна мета цієї сторінки – висвітлити зусилля спільноти, щоб допомогти іншим.
+
+Особливо враховуючи зусилля, які зазвичай менш помітні, а в багатьох випадках більш важкі, як-от допомога іншим із проблемами та перегляд пул реквестів перекладів.
+
+Дані розраховуються щомісяця, ви можете ознайомитися з вихідним кодом тут.
+
+Тут я також підкреслюю внески спонсорів.
+
+Я також залишаю за собою право оновлювати алгоритми підрахунку, види рейтингів, порогові значення тощо (про всяк випадок 🤷).
diff --git a/docs/uk/docs/python-types.md b/docs/uk/docs/python-types.md
new file mode 100644
index 000000000..6c8e29016
--- /dev/null
+++ b/docs/uk/docs/python-types.md
@@ -0,0 +1,448 @@
+# Вступ до типів Python
+
+Python підтримує додаткові "підказки типу" ("type hints") (також звані "анотаціями типу" ("type annotations")).
+
+Ці **"type hints"** є спеціальним синтаксисом, що дозволяє оголошувати тип змінної.
+
+За допомогою оголошення типів для ваших змінних, редактори та інструменти можуть надати вам кращу підтримку.
+
+Це просто **швидкий посібник / нагадування** про анотації типів у Python. Він покриває лише мінімум, необхідний щоб використовувати їх з **FastAPI**... що насправді дуже мало.
+
+**FastAPI** повністю базується на цих анотаціях типів, вони дають йому багато переваг.
+
+Але навіть якщо ви ніколи не використаєте **FastAPI**, вам буде корисно дізнатись трохи про них.
+
+!!! note
+ Якщо ви експерт у Python і ви вже знаєте усе про анотації типів - перейдіть до наступного розділу.
+
+## Мотивація
+
+Давайте почнемо з простого прикладу:
+
+```Python
+{!../../../docs_src/python_types/tutorial001.py!}
+```
+
+Виклик цієї програми виводить:
+
+```
+John Doe
+```
+
+Функція виконує наступне:
+
+* Бере `first_name` та `last_name`.
+* Конвертує кожну літеру кожного слова у верхній регістр за допомогою `title()`.
+* Конкатенує їх разом із пробілом по середині.
+
+```Python hl_lines="2"
+{!../../../docs_src/python_types/tutorial001.py!}
+```
+
+### Редагуйте це
+
+Це дуже проста програма.
+
+Але тепер уявіть, що ви писали це з нуля.
+
+У певний момент ви розпочали б визначення функції, у вас були б готові параметри...
+
+Але тоді вам потрібно викликати "той метод, який переводить першу літеру у верхній регістр".
+
+Це буде `upper`? Чи `uppercase`? `first_uppercase`? `capitalize`?
+
+Тоді ви спробуєте давнього друга програміста - автозаповнення редактора коду.
+
+Ви надрукуєте перший параметр функції, `first_name`, тоді крапку (`.`), а тоді натиснете `Ctrl+Space`, щоб запустити автозаповнення.
+
+Але, на жаль, ви не отримаєте нічого корисного:
+
+
+
+### Додайте типи
+
+Давайте змінимо один рядок з попередньої версії.
+
+Ми змінимо саме цей фрагмент, параметри функції, з:
+
+```Python
+ first_name, last_name
+```
+
+на:
+
+```Python
+ first_name: str, last_name: str
+```
+
+Ось і все.
+
+Це "type hints":
+
+```Python hl_lines="1"
+{!../../../docs_src/python_types/tutorial002.py!}
+```
+
+Це не те саме, що оголошення значень за замовчуванням, як це було б з:
+
+```Python
+ first_name="john", last_name="doe"
+```
+
+Це зовсім інше.
+
+Ми використовуємо двокрапку (`:`), не дорівнює (`=`).
+
+І додавання анотації типу зазвичай не змінює того, що сталось би без них.
+
+Але тепер, уявіть що ви посеред процесу створення функції, але з анотаціями типів.
+
+В цей же момент, ви спробуєте викликати автозаповнення з допомогою `Ctrl+Space` і побачите:
+
+
+
+Разом з цим, ви можете прокручувати, переглядати опції, допоки ви не знайдете одну, що звучить схоже:
+
+
+
+## Більше мотивації
+
+Перевірте цю функцію, вона вже має анотацію типу:
+
+```Python hl_lines="1"
+{!../../../docs_src/python_types/tutorial003.py!}
+```
+
+Оскільки редактор знає типи змінних, ви не тільки отримаєте автозаповнення, ви також отримаєте перевірку помилок:
+
+
+
+Тепер ви знаєте, щоб виправити це, вам потрібно перетворити `age` у строку з допомогою `str(age)`:
+
+```Python hl_lines="2"
+{!../../../docs_src/python_types/tutorial004.py!}
+```
+
+## Оголошення типів
+
+Щойно ви побачили основне місце для оголошення анотацій типу. Як параметри функції.
+
+Це також основне місце, де ви б їх використовували у **FastAPI**.
+
+### Прості типи
+
+Ви можете оголошувати усі стандартні типи у Python, не тільки `str`.
+
+Ви можете використовувати, наприклад:
+
+* `int`
+* `float`
+* `bool`
+* `bytes`
+
+```Python hl_lines="1"
+{!../../../docs_src/python_types/tutorial005.py!}
+```
+
+### Generic-типи з параметрами типів
+
+Існують деякі структури даних, які можуть містити інші значення, наприклад `dict`, `list`, `set` та `tuple`. І внутрішні значення також можуть мати свій тип.
+
+Ці типи, які мають внутрішні типи, називаються "**generic**" типами. І оголосити їх можна навіть із внутрішніми типами.
+
+Щоб оголосити ці типи та внутрішні типи, ви можете використовувати стандартний модуль Python `typing`. Він існує спеціально для підтримки анотацій типів.
+
+#### Новіші версії Python
+
+Синтаксис із використанням `typing` **сумісний** з усіма версіями, від Python 3.6 до останніх, включаючи Python 3.9, Python 3.10 тощо.
+
+У міру розвитку Python **новіші версії** мають покращену підтримку анотацій типів і в багатьох випадках вам навіть не потрібно буде імпортувати та використовувати модуль `typing` для оголошення анотацій типу.
+
+Якщо ви можете вибрати новішу версію Python для свого проекту, ви зможете скористатися цією додатковою простотою. Дивіться кілька прикладів нижче.
+
+#### List (список)
+
+Наприклад, давайте визначимо змінну, яка буде `list` із `str`.
+
+=== "Python 3.8 і вище"
+
+ З модуля `typing`, імпортуємо `List` (з великої літери `L`):
+
+ ``` Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+ Оголосимо змінну з тим самим синтаксисом двокрапки (`:`).
+
+ Як тип вкажемо `List`, який ви імпортували з `typing`.
+
+ Оскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки:
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+=== "Python 3.9 і вище"
+
+ Оголосимо змінну з тим самим синтаксисом двокрапки (`:`).
+
+ Як тип вкажемо `list`.
+
+ Оскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки:
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006_py39.py!}
+ ```
+
+!!! info
+ Ці внутрішні типи в квадратних дужках називаються "параметрами типу".
+
+ У цьому випадку, `str` це параметр типу переданий у `List` (або `list` у Python 3.9 і вище).
+
+Це означає: "змінна `items` це `list`, і кожен з елементів у цьому списку - `str`".
+
+!!! tip
+ Якщо ви використовуєте Python 3.9 і вище, вам не потрібно імпортувати `List` з `typing`, ви можете використовувати натомість тип `list`.
+
+Зробивши це, ваш редактор може надати підтримку навіть під час обробки елементів зі списку:
+
+
+
+Без типів цього майже неможливо досягти.
+
+Зверніть увагу, що змінна `item` є одним із елементів у списку `items`.
+
+І все ж редактор знає, що це `str`, і надає підтримку для цього.
+
+#### Tuple and Set (кортеж та набір)
+
+Ви повинні зробити те ж саме, щоб оголосити `tuple` і `set`:
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial007.py!}
+ ```
+
+=== "Python 3.9 і вище"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial007_py39.py!}
+ ```
+
+Це означає:
+
+* Змінна `items_t` це `tuple` з 3 елементами, `int`, ще `int`, та `str`.
+* Змінна `items_s` це `set`, і кожен його елемент типу `bytes`.
+
+#### Dict (словник)
+
+Щоб оголосити `dict`, вам потрібно передати 2 параметри типу, розділені комами.
+
+Перший параметр типу для ключа у `dict`.
+
+Другий параметр типу для значення у `dict`:
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008.py!}
+ ```
+
+=== "Python 3.9 і вище"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008_py39.py!}
+ ```
+
+Це означає:
+
+* Змінна `prices` це `dict`:
+ * Ключі цього `dict` типу `str` (наприклад, назва кожного елементу).
+ * Значення цього `dict` типу `float` (наприклад, ціна кожного елементу).
+
+#### Union (об'єднання)
+
+Ви можете оголосити, що змінна може бути будь-яким із **кількох типів**, наприклад, `int` або `str`.
+
+У Python 3.6 і вище (включаючи Python 3.10) ви можете використовувати тип `Union` з `typing` і вставляти в квадратні дужки можливі типи, які можна прийняти.
+
+У Python 3.10 також є **альтернативний синтаксис**, у якому ви можете розділити можливі типи за допомогою вертикальної смуги (`|`).
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008b.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008b_py310.py!}
+ ```
+
+В обох випадках це означає, що `item` може бути `int` або `str`.
+
+#### Possibly `None` (Optional)
+
+Ви можете оголосити, що значення може мати тип, наприклад `str`, але також може бути `None`.
+
+У Python 3.6 і вище (включаючи Python 3.10) ви можете оголосити його, імпортувавши та використовуючи `Optional` з модуля `typing`.
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009.py!}
+```
+
+Використання `Optional[str]` замість просто `str` дозволить редактору допомогти вам виявити помилки, коли ви могли б вважати, що значенням завжди є `str`, хоча насправді воно також може бути `None`.
+
+`Optional[Something]` насправді є скороченням для `Union[Something, None]`, вони еквівалентні.
+
+Це також означає, що в Python 3.10 ви можете використовувати `Something | None`:
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009.py!}
+ ```
+
+=== "Python 3.8 і вище - альтернатива"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009b.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial009_py310.py!}
+ ```
+
+#### Generic типи
+
+Ці типи, які приймають параметри типу у квадратних дужках, називаються **Generic types** or **Generics**, наприклад:
+
+=== "Python 3.8 і вище"
+
+ * `List`
+ * `Tuple`
+ * `Set`
+ * `Dict`
+ * `Union`
+ * `Optional`
+ * ...та інші.
+
+=== "Python 3.9 і вище"
+
+ Ви можете використовувати ті самі вбудовані типи, як generic (з квадратними дужками та типами всередині):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ І те саме, що й у Python 3.8, із модуля `typing`:
+
+ * `Union`
+ * `Optional`
+ * ...та інші.
+
+=== "Python 3.10 і вище"
+
+ Ви можете використовувати ті самі вбудовані типи, як generic (з квадратними дужками та типами всередині):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ І те саме, що й у Python 3.8, із модуля `typing`:
+
+ * `Union`
+ * `Optional` (так само як у Python 3.8)
+ * ...та інші.
+
+ У Python 3.10, як альтернатива використанню `Union` та `Optional`, ви можете використовувати вертикальну смугу (`|`) щоб оголосити об'єднання типів.
+
+### Класи як типи
+
+Ви також можете оголосити клас як тип змінної.
+
+Скажімо, у вас є клас `Person` з імʼям:
+
+```Python hl_lines="1-3"
+{!../../../docs_src/python_types/tutorial010.py!}
+```
+
+Потім ви можете оголосити змінну типу `Person`:
+
+```Python hl_lines="6"
+{!../../../docs_src/python_types/tutorial010.py!}
+```
+
+І знову ж таки, ви отримуєте всю підтримку редактора:
+
+
+
+## Pydantic моделі
+
+Pydantic це бібліотека Python для валідації даних.
+
+Ви оголошуєте «форму» даних як класи з атрибутами.
+
+І кожен атрибут має тип.
+
+Потім ви створюєте екземпляр цього класу з деякими значеннями, і він перевірить ці значення, перетворить їх у відповідний тип (якщо є потреба) і надасть вам об’єкт з усіма даними.
+
+І ви отримуєте всю підтримку редактора з цим отриманим об’єктом.
+
+Приклад з документації Pydantic:
+
+=== "Python 3.8 і вище"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011.py!}
+ ```
+
+=== "Python 3.9 і вище"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py39.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py310.py!}
+ ```
+
+!!! info
+ Щоб дізнатись більше про Pydantic, перегляньте його документацію.
+
+**FastAPI** повністю базується на Pydantic.
+
+Ви побачите набагато більше цього всього на практиці в [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
+
+## Анотації типів у **FastAPI**
+
+**FastAPI** використовує ці підказки для виконання кількох речей.
+
+З **FastAPI** ви оголошуєте параметри з підказками типу, і отримуєте:
+
+* **Підтримку редактора**.
+* **Перевірку типів**.
+
+...і **FastAPI** використовує ті самі оголошення для:
+
+* **Визначення вимог**: з параметрів шляху запиту, параметрів запиту, заголовків, тіл, залежностей тощо.
+* **Перетворення даних**: із запиту в необхідний тип.
+* **Перевірка даних**: що надходять від кожного запиту:
+ * Генерування **автоматичних помилок**, що повертаються клієнту, коли дані недійсні.
+* **Документування** API за допомогою OpenAPI:
+ * який потім використовується для автоматичної інтерактивної документації користувальницьких інтерфейсів.
+
+Все це може здатися абстрактним. Не хвилюйтеся. Ви побачите все це в дії в [Туторіал - Посібник користувача](tutorial/index.md){.internal-link target=_blank}.
+
+Важливо те, що за допомогою стандартних типів Python в одному місці (замість того, щоб додавати більше класів, декораторів тощо), **FastAPI** зробить багато роботи за вас.
+
+!!! info
+ Якщо ви вже пройшли весь навчальний посібник і повернулися, щоб дізнатися більше про типи, ось хороший ресурс "шпаргалка" від `mypy`.
diff --git a/docs/uk/docs/tutorial/body.md b/docs/uk/docs/tutorial/body.md
new file mode 100644
index 000000000..9759e7f45
--- /dev/null
+++ b/docs/uk/docs/tutorial/body.md
@@ -0,0 +1,213 @@
+# Тіло запиту
+
+Коли вам потрібно надіслати дані з клієнта (скажімо, браузера) до вашого API, ви надсилаєте їх як **тіло запиту**.
+
+Тіло **запиту** — це дані, надіслані клієнтом до вашого API. Тіло **відповіді** — це дані, які ваш API надсилає клієнту.
+
+Ваш API майже завжди має надсилати тіло **відповіді**. Але клієнтам не обов’язково потрібно постійно надсилати тіла **запитів**.
+
+Щоб оголосити тіло **запиту**, ви використовуєте Pydantic моделі з усією їх потужністю та перевагами.
+
+!!! info
+ Щоб надіслати дані, ви повинні використовувати один із: `POST` (більш поширений), `PUT`, `DELETE` або `PATCH`.
+
+ Надсилання тіла із запитом `GET` має невизначену поведінку в специфікаціях, проте воно підтримується FastAPI лише для дуже складних/екстремальних випадків використання.
+
+ Оскільки це не рекомендується, інтерактивна документація з Swagger UI не відображатиме документацію для тіла запиту під час використання `GET`, і проксі-сервери в середині можуть не підтримувати її.
+
+## Імпортуйте `BaseModel` від Pydantic
+
+Спочатку вам потрібно імпортувати `BaseModel` з `pydantic`:
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body/tutorial001.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="2"
+ {!> ../../../docs_src/body/tutorial001_py310.py!}
+ ```
+
+## Створіть свою модель даних
+
+Потім ви оголошуєте свою модель даних як клас, який успадковується від `BaseModel`.
+
+Використовуйте стандартні типи Python для всіх атрибутів:
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="7-11"
+ {!> ../../../docs_src/body/tutorial001.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="5-9"
+ {!> ../../../docs_src/body/tutorial001_py310.py!}
+ ```
+
+Так само, як і при оголошенні параметрів запиту, коли атрибут моделі має значення за замовчуванням, він не є обов’язковим. В іншому випадку це потрібно. Використовуйте `None`, щоб зробити його необов'язковим.
+
+Наприклад, ця модель вище оголошує JSON "`об'єкт`" (або Python `dict`), як:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "An optional description",
+ "price": 45.2,
+ "tax": 3.5
+}
+```
+
+...оскільки `description` і `tax` є необов'язковими (зі значенням за замовчуванням `None`), цей JSON "`об'єкт`" також буде дійсним:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 45.2
+}
+```
+
+## Оголоси її як параметр
+
+Щоб додати модель даних до вашої *операції шляху*, оголосіть її так само, як ви оголосили параметри шляху та запиту:
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body/tutorial001.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/body/tutorial001_py310.py!}
+ ```
+
+...і вкажіть її тип як модель, яку ви створили, `Item`.
+
+## Результати
+
+Лише з цим оголошенням типу Python **FastAPI** буде:
+
+* Читати тіло запиту як JSON.
+* Перетворювати відповідні типи (якщо потрібно).
+* Валідувати дані.
+ * Якщо дані недійсні, він поверне гарну та чітку помилку, вказуючи, де саме і які дані були неправильними.
+* Надавати отримані дані у параметрі `item`.
+ * Оскільки ви оголосили його у функції як тип `Item`, ви також матимете всю підтримку редактора (автозаповнення, тощо) для всіх атрибутів та їх типів.
+* Генерувати JSON Schema визначення для вашої моделі, ви також можете використовувати їх де завгодно, якщо це має сенс для вашого проекту.
+* Ці схеми будуть частиною згенерованої схеми OpenAPI і використовуватимуться автоматичною документацією інтерфейсу користувача.
+
+## Автоматична документація
+
+Схеми JSON ваших моделей будуть частиною вашої схеми, згенерованої OpenAPI, і будуть показані в інтерактивній API документації:
+
+
+
+А також використовуватимуться в API документації всередині кожної *операції шляху*, якій вони потрібні:
+
+
+
+## Підтримка редактора
+
+У вашому редакторі, всередині вашої функції, ви будете отримувати підказки типу та завершення скрізь (це б не сталося, якби ви отримали `dict` замість моделі Pydantic):
+
+
+
+Ви також отримуєте перевірку помилок на наявність операцій з неправильним типом:
+
+
+
+Це не випадково, весь каркас був побудований навколо цього дизайну.
+
+І він був ретельно перевірений на етапі проектування, перед будь-яким впровадженням, щоб переконатися, що він працюватиме з усіма редакторами.
+
+Були навіть деякі зміни в самому Pydantic, щоб підтримати це.
+
+Попередні скріншоти були зроблені у Visual Studio Code.
+
+Але ви отримаєте ту саму підтримку редактора у PyCharm та більшість інших редакторів Python:
+
+
+
+!!! tip
+ Якщо ви використовуєте PyCharm як ваш редактор, ви можете використати Pydantic PyCharm Plugin.
+
+ Він покращує підтримку редакторів для моделей Pydantic за допомогою:
+
+ * автозаповнення
+ * перевірки типу
+ * рефакторингу
+ * пошуку
+ * інспекції
+
+## Використовуйте модель
+
+Усередині функції ви можете отримати прямий доступ до всіх атрибутів об’єкта моделі:
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="21"
+ {!> ../../../docs_src/body/tutorial002.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/body/tutorial002_py310.py!}
+ ```
+
+## Тіло запиту + параметри шляху
+
+Ви можете одночасно оголошувати параметри шляху та тіло запиту.
+
+**FastAPI** розпізнає, що параметри функції, які відповідають параметрам шляху, мають бути **взяті з шляху**, а параметри функції, які оголошуються як моделі Pydantic, **взяті з тіла запиту**.
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="17-18"
+ {!> ../../../docs_src/body/tutorial003.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="15-16"
+ {!> ../../../docs_src/body/tutorial003_py310.py!}
+ ```
+
+## Тіло запиту + шлях + параметри запиту
+
+Ви також можете оголосити параметри **тіло**, **шлях** і **запит** одночасно.
+
+**FastAPI** розпізнає кожен з них і візьме дані з потрібного місця.
+
+=== "Python 3.8 і вище"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body/tutorial004.py!}
+ ```
+
+=== "Python 3.10 і вище"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/body/tutorial004_py310.py!}
+ ```
+
+Параметри функції будуть розпізнаватися наступним чином:
+
+* Якщо параметр також оголошено в **шляху**, він використовуватиметься як параметр шляху.
+* Якщо параметр має **сингулярний тип** (наприклад, `int`, `float`, `str`, `bool` тощо), він буде інтерпретуватися як параметр **запиту**.
+* Якщо параметр оголошується як тип **Pydantic моделі**, він інтерпретується як **тіло** запиту.
+
+!!! note
+ FastAPI буде знати, що значення "q" не є обов'язковим через значення за замовчуванням "= None".
+
+ `Optional` у `Optional[str]` не використовується FastAPI, але дозволить вашому редактору надати вам кращу підтримку та виявляти помилки.
+
+## Без Pydantic
+
+Якщо ви не хочете використовувати моделі Pydantic, ви також можете використовувати параметри **Body**. Перегляньте документацію для [Тіло – Кілька параметрів: сингулярні значення в тілі](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
diff --git a/docs/uk/docs/tutorial/cookie-params.md b/docs/uk/docs/tutorial/cookie-params.md
new file mode 100644
index 000000000..199b93839
--- /dev/null
+++ b/docs/uk/docs/tutorial/cookie-params.md
@@ -0,0 +1,96 @@
+# Параметри Cookie
+
+Ви можете визначити параметри Cookie таким же чином, як визначаються параметри `Query` і `Path`.
+
+## Імпорт `Cookie`
+
+Спочатку імпортуйте `Cookie`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001.py!}
+ ```
+
+## Визначення параметрів `Cookie`
+
+Потім визначте параметри cookie, використовуючи таку ж конструкцію як для `Path` і `Query`.
+
+Перше значення це значення за замовчуванням, ви можете також передати всі додаткові параметри валідації чи анотації:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/cookie_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001.py!}
+ ```
+
+!!! note "Технічні Деталі"
+ `Cookie` це "сестра" класів `Path` і `Query`. Вони наслідуються від одного батьківського класу `Param`.
+ Але пам'ятайте, що коли ви імпортуєте `Query`, `Path`, `Cookie` та інше з `fastapi`, це фактично функції, що повертають спеціальні класи.
+
+!!! info
+ Для визначення cookies ви маєте використовувати `Cookie`, тому що в іншому випадку параметри будуть інтерпритовані, як параметри запиту.
+
+## Підсумки
+
+Визначайте cookies за допомогою `Cookie`, використовуючи той же спільний шаблон, що і `Query` та `Path`.
diff --git a/docs/uk/docs/tutorial/encoder.md b/docs/uk/docs/tutorial/encoder.md
new file mode 100644
index 000000000..b6583341f
--- /dev/null
+++ b/docs/uk/docs/tutorial/encoder.md
@@ -0,0 +1,42 @@
+# JSON Compatible Encoder
+
+Існують випадки, коли вам може знадобитися перетворити тип даних (наприклад, модель Pydantic) в щось сумісне з JSON (наприклад, `dict`, `list`, і т. д.).
+
+Наприклад, якщо вам потрібно зберегти це в базі даних.
+
+Для цього, **FastAPI** надає `jsonable_encoder()` функцію.
+
+## Використання `jsonable_encoder`
+
+Давайте уявимо, що у вас є база даних `fake_db`, яка приймає лише дані, сумісні з JSON.
+
+Наприклад, вона не приймає об'єкти типу `datetime`, оскільки вони не сумісні з JSON.
+
+Отже, об'єкт типу `datetime` потрібно перетворити в рядок `str`, який містить дані в ISO форматі.
+
+Тим самим способом ця база даних не прийматиме об'єкт типу Pydantic model (об'єкт з атрибутами), а лише `dict`.
+
+Ви можете використовувати `jsonable_encoder` для цього.
+
+Вона приймає об'єкт, такий як Pydantic model, і повертає його версію, сумісну з JSON:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="4 21"
+ {!> ../../../docs_src/encoder/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="5 22"
+ {!> ../../../docs_src/encoder/tutorial001.py!}
+ ```
+
+У цьому прикладі вона конвертує Pydantic model у `dict`, а `datetime` у `str`.
+
+Результат виклику цієї функції - це щось, що можна кодувати з використанням стандарту Python `json.dumps()`.
+
+Вона не повертає велику строку `str`, яка містить дані у форматі JSON (як строка). Вона повертає стандартну структуру даних Python (наприклад `dict`) із значеннями та підзначеннями, які є сумісними з JSON.
+
+!!! Примітка
+ `jsonable_encoder` фактично використовується **FastAPI** внутрішньо для перетворення даних. Проте вона корисна в багатьох інших сценаріях.
diff --git a/docs/uk/docs/tutorial/extra-data-types.md b/docs/uk/docs/tutorial/extra-data-types.md
new file mode 100644
index 000000000..ec5ec0d18
--- /dev/null
+++ b/docs/uk/docs/tutorial/extra-data-types.md
@@ -0,0 +1,130 @@
+# Додаткові типи даних
+
+До цього часу, ви використовували загальнопоширені типи даних, такі як:
+
+* `int`
+* `float`
+* `str`
+* `bool`
+
+Але можна також використовувати більш складні типи даних.
+
+І ви все ще матимете ті ж можливості, які були показані до цього:
+
+* Чудова підтримка редактора.
+* Конвертація даних з вхідних запитів.
+* Конвертація даних для відповіді.
+* Валідація даних.
+* Автоматична анотація та документація.
+
+## Інші типи даних
+
+Ось додаткові типи даних для використання:
+
+* `UUID`:
+ * Стандартний "Універсальний Унікальний Ідентифікатор", який часто використовується як ідентифікатор у багатьох базах даних та системах.
+ * У запитах та відповідях буде представлений як `str`.
+* `datetime.datetime`:
+ * Пайтонівський `datetime.datetime`.
+ * У запитах та відповідях буде представлений як `str` в форматі ISO 8601, як: `2008-09-15T15:53:00+05:00`.
+* `datetime.date`:
+ * Пайтонівський `datetime.date`.
+ * У запитах та відповідях буде представлений як `str` в форматі ISO 8601, як: `2008-09-15`.
+* `datetime.time`:
+ * Пайтонівський `datetime.time`.
+ * У запитах та відповідях буде представлений як `str` в форматі ISO 8601, як: `14:23:55.003`.
+* `datetime.timedelta`:
+ * Пайтонівський `datetime.timedelta`.
+ * У запитах та відповідях буде представлений як `float` загальної кількості секунд.
+ * Pydantic також дозволяє представляти це як "ISO 8601 time diff encoding", більше інформації дивись у документації.
+* `frozenset`:
+ * У запитах і відповідях це буде оброблено так само, як і `set`:
+ * У запитах список буде зчитано, дублікати будуть видалені та він буде перетворений на `set`.
+ * У відповідях, `set` буде перетворений на `list`.
+ * Згенерована схема буде вказувати, що значення `set` є унікальними (з використанням JSON Schema's `uniqueItems`).
+* `bytes`:
+ * Стандартний Пайтонівський `bytes`.
+ * У запитах і відповідях це буде оброблено як `str`.
+ * Згенерована схема буде вказувати, що це `str` з "форматом" `binary`.
+* `Decimal`:
+ * Стандартний Пайтонівський `Decimal`.
+ * У запитах і відповідях це буде оброблено так само, як і `float`.
+* Ви можете перевірити всі дійсні типи даних Pydantic тут: типи даних Pydantic.
+
+## Приклад
+
+Ось приклад *path operation* з параметрами, використовуючи деякі з вищезазначених типів.
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 3 13-17"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="1 2 11-15"
+ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="1 2 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
+
+Зверніть увагу, що параметри всередині функції мають свій звичайний тип даних, і ви можете, наприклад, виконувати звичайні маніпуляції з датами, такі як:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="19-20"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="17-18"
+ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ Бажано використовувати `Annotated` версію, якщо це можливо.
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
diff --git a/docs/uk/docs/tutorial/index.md b/docs/uk/docs/tutorial/index.md
new file mode 100644
index 000000000..e5bae74bc
--- /dev/null
+++ b/docs/uk/docs/tutorial/index.md
@@ -0,0 +1,80 @@
+# Туторіал - Посібник користувача
+
+У цьому посібнику показано, як користуватися **FastAPI** з більшістю його функцій, крок за кроком.
+
+Кожен розділ поступово надбудовується на попередні, але він структурований на окремі теми, щоб ви могли перейти безпосередньо до будь-якої конкретної, щоб вирішити ваші конкретні потреби API.
+
+Він також створений як довідник для роботи у майбутньому.
+
+Тож ви можете повернутися і побачити саме те, що вам потрібно.
+
+## Запустіть код
+
+Усі блоки коду можна скопіювати та використовувати безпосередньо (це фактично перевірені файли Python).
+
+Щоб запустити будь-який із прикладів, скопіюйте код у файл `main.py` і запустіть `uvicorn` за допомогою:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+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, бачите, як мало коду вам потрібно написати, всі перевірки типів, автозаповнення тощо.
+
+---
+
+## Встановлення FastAPI
+
+Першим кроком є встановлення FastAPI.
+
+Для туторіалу ви можете встановити його з усіма необов’язковими залежностями та функціями:
+
+
+
+```console
+$ pip install "fastapi[all]"
+
+---> 100%
+```
+
+
+
+...який також включає `uvicorn`, який ви можете використовувати як сервер, який запускає ваш код.
+
+!!! note
+ Ви також можете встановити його частина за частиною.
+
+ Це те, що ви, ймовірно, зробили б, коли захочете розгорнути свою програму у виробничому середовищі:
+
+ ```
+ pip install fastapi
+ ```
+
+ Також встановіть `uvicorn`, щоб він працював як сервер:
+
+ ```
+ pip install "uvicorn[standard]"
+ ```
+
+ І те саме для кожної з опціональних залежностей, які ви хочете використовувати.
+
+## Розширений посібник користувача
+
+Існує також **Розширений посібник користувача**, який ви зможете прочитати пізніше після цього **Туторіал - Посібник користувача**.
+
+**Розширений посібник користувача** засновано на цьому, використовує ті самі концепції та навчає вас деяким додатковим функціям.
+
+Але вам слід спочатку прочитати **Туторіал - Посібник користувача** (те, що ви зараз читаєте).
+
+Він розроблений таким чином, що ви можете створити повну програму лише за допомогою **Туторіал - Посібник користувача**, а потім розширити її різними способами, залежно від ваших потреб, використовуючи деякі з додаткових ідей з **Розширеного посібника користувача** .
diff --git a/docs/uk/mkdocs.yml b/docs/uk/mkdocs.yml
new file mode 100644
index 000000000..de18856f4
--- /dev/null
+++ b/docs/uk/mkdocs.yml
@@ -0,0 +1 @@
+INHERIT: ../en/mkdocs.yml
diff --git a/docs/ur/docs/benchmarks.md b/docs/ur/docs/benchmarks.md
new file mode 100644
index 000000000..9fc793e6f
--- /dev/null
+++ b/docs/ur/docs/benchmarks.md
@@ -0,0 +1,52 @@
+# بینچ مارکس
+
+انڈیپنڈنٹ ٹیک امپور بینچ مارک **FASTAPI** Uvicorn کے تحت چلنے والی ایپلی کیشنز کو ایک تیز رفتار Python فریم ورک میں سے ایک ، صرف Starlette اور Uvicorn کے نیچے ( FASTAPI کے ذریعہ اندرونی طور پر استعمال کیا جاتا ہے ) (*)
+
+لیکن جب بینچ مارک اور موازنہ کی جانچ پڑتال کرتے ہو تو آپ کو مندرجہ ذیل بات ذہن میں رکھنی چاہئے.
+
+## بینچ مارک اور رفتار
+
+جب آپ بینچ مارک کی جانچ کرتے ہیں تو ، مساوی کے مقابلے میں مختلف اقسام کے متعدد اوزار دیکھنا عام ہے.
+
+خاص طور پر ، Uvicorn, Starlette اور FastAPI کو دیکھنے کے لئے ( بہت سے دوسرے ٹولز ) کے ساتھ موازنہ کیا گیا.
+
+ٹول کے ذریعہ حل ہونے والا آسان مسئلہ ، اس کی بہتر کارکردگی ہوگی. اور زیادہ تر بینچ مارک ٹول کے ذریعہ فراہم کردہ اضافی خصوصیات کی جانچ نہیں کرتے ہیں.
+
+درجہ بندی کی طرح ہے:
+
+
+
+
+ Uvicorn:
+
+ بہترین کارکردگی ہوگی، کیونکہ اس میں سرور کے علاوہ زیادہ اضافی کوڈ نہیں ہے۔
+ آپ براہ راست Uvicorn میں درخواست نہیں لکھیں گے۔ اس کا مطلب یہ ہوگا کہ آپ کے کوڈ میں کم و بیش، کم از کم، Starlette (یا FastAPI) کی طرف سے فراہم کردہ تمام کوڈ شامل کرنا ہوں گے۔ اور اگر آپ نے ایسا کیا تو، آپ کی حتمی ایپلیکیشن کا وہی اوور ہیڈ ہوگا جیسا کہ ایک فریم ورک استعمال کرنے اور آپ کے ایپ کوڈ اور کیڑے کو کم سے کم کرنا۔
+ اگر آپ Uvicorn کا موازنہ کر رہے ہیں تو اس کا موازنہ Daphne، Hypercorn، uWSGI وغیرہ ایپلیکیشن سرورز سے کریں۔
+
+
+
+ Starlette:
+
+ Uvicorn کے بعد اگلی بہترین کارکردگی ہوگی۔ درحقیقت، Starlette چلانے کے لیے Uvicorn کا استعمال کرتی ہے۔ لہذا، یہ شاید زیادہ کوڈ پر عمل درآمد کرکے Uvicorn سے "سست" ہوسکتا ہے۔
+ لیکن یہ آپ کو آسان ویب ایپلیکیشنز بنانے کے لیے ٹولز فراہم کرتا ہے، راستوں پر مبنی روٹنگ کے ساتھ، وغیرہ۔
+ اگر آپ سٹارلیٹ کا موازنہ کر رہے ہیں تو اس کا موازنہ Sanic، Flask، Django وغیرہ سے کریں۔ ویب فریم ورکس (یا مائیکرو فریم ورکس)
+
+
+
+ FastAPI:
+
+ جس طرح سے Uvicorn Starlette کا استعمال کرتا ہے اور اس سے تیز نہیں ہو سکتا، Starlette FastAPI کا استعمال کرتا ہے، اس لیے یہ اس سے تیز نہیں ہو سکتا۔
+ Starlette FastAPI کے اوپری حصے میں مزید خصوصیات فراہم کرتا ہے۔ وہ خصوصیات جن کی آپ کو APIs بناتے وقت تقریباً ہمیشہ ضرورت ہوتی ہے، جیسے ڈیٹا کی توثیق اور سیریلائزیشن۔ اور اسے استعمال کرنے سے، آپ کو خودکار دستاویزات مفت میں مل جاتی ہیں (خودکار دستاویزات چلنے والی ایپلی کیشنز میں اوور ہیڈ کو بھی شامل نہیں کرتی ہیں، یہ اسٹارٹ اپ پر تیار ہوتی ہیں)۔
+ اگر آپ نے FastAPI کا استعمال نہیں کیا ہے اور Starlette کو براہ راست استعمال کیا ہے (یا کوئی دوسرا ٹول، جیسے Sanic، Flask، Responder، وغیرہ) آپ کو تمام ڈیٹا کی توثیق اور سیریلائزیشن کو خود نافذ کرنا ہوگا۔ لہذا، آپ کی حتمی ایپلیکیشن اب بھی وہی اوور ہیڈ ہوگی جیسا کہ اسے FastAPI کا استعمال کرتے ہوئے بنایا گیا تھا۔ اور بہت سے معاملات میں، یہ ڈیٹا کی توثیق اور سیریلائزیشن ایپلی کیشنز میں لکھے گئے کوڈ کی سب سے بڑی مقدار ہے۔
+ لہذا، FastAPI کا استعمال کرکے آپ ترقیاتی وقت، Bugs، کوڈ کی لائنوں کی بچت کر رہے ہیں، اور شاید آپ کو وہی کارکردگی (یا بہتر) ملے گی اگر آپ اسے استعمال نہیں کرتے (جیسا کہ آپ کو یہ سب اپنے کوڈ میں لاگو کرنا ہوگا۔ )
+ اگر آپ FastAPI کا موازنہ کر رہے ہیں، تو اس کا موازنہ ویب ایپلیکیشن فریم ورک (یا ٹولز کے سیٹ) سے کریں جو ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات فراہم کرتا ہے، جیسے Flask-apispec، NestJS، Molten، وغیرہ۔ مربوط خودکار ڈیٹا کی توثیق، سیریلائزیشن اور دستاویزات کے ساتھ فریم ورک۔
+
+
diff --git a/docs/ur/mkdocs.yml b/docs/ur/mkdocs.yml
new file mode 100644
index 000000000..de18856f4
--- /dev/null
+++ b/docs/ur/mkdocs.yml
@@ -0,0 +1 @@
+INHERIT: ../en/mkdocs.yml
diff --git a/docs/vi/docs/features.md b/docs/vi/docs/features.md
new file mode 100644
index 000000000..306aeb359
--- /dev/null
+++ b/docs/vi/docs/features.md
@@ -0,0 +1,197 @@
+# Tính năng
+
+## Tính năng của FastAPI
+
+**FastAPI** cho bạn những tính năng sau:
+
+### Dựa trên những tiêu chuẩn mở
+
+* OpenAPI cho việc tạo API, bao gồm những khai báo về đường dẫn các toán tử, tham số, body requests, cơ chế bảo mật, etc.
+* Tự động tài liệu hóa data model theo JSON Schema (OpenAPI bản thân nó được dựa trên JSON Schema).
+* Được thiết kế xung quanh các tiêu chuẩn này sau khi nghiên cứu tỉ mỉ thay vì chỉ suy nghĩ đơn giản và sơ xài.
+* Điều này cho phép tự động hóa **trình sinh code client** cho nhiều ngôn ngữ lập trình khác nhau.
+
+### Tự động hóa tài liệu
+
+
+Tài liệu tương tác API và web giao diện người dùng. Là một framework được dựa trên OpenAPI do đó có nhiều tùy chọn giao diện cho tài liệu API, 2 giao diện bên dưới là mặc định.
+
+* Swagger UI, với giao diện khám phá, gọi và kiểm thử API trực tiếp từ trình duyệt.
+
+
+
+* Thay thế với tài liệu API với ReDoc.
+
+
+
+### Chỉ cần phiên bản Python hiện đại
+
+Tất cả được dựa trên khai báo kiểu dữ liệu chuẩn của **Python 3.8** (cảm ơn Pydantic). Bạn không cần học cú pháp mới, chỉ cần biết chuẩn Python hiện đại.
+
+Nếu bạn cần 2 phút để làm mới lại cách sử dụng các kiểu dữ liệu mới của Python (thậm chí nếu bạn không sử dụng FastAPI), xem hướng dẫn ngắn: [Kiểu dữ liệu Python](python-types.md){.internal-link target=_blank}.
+
+Bạn viết chuẩn Python với kiểu dữ liệu như sau:
+
+```Python
+from datetime import date
+
+from pydantic import BaseModel
+
+# Declare a variable as a str
+# and get editor support inside the function
+def main(user_id: str):
+ return user_id
+
+
+# A Pydantic model
+class User(BaseModel):
+ id: int
+ name: str
+ joined: date
+```
+
+Sau đó có thể được sử dụng:
+
+```Python
+my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
+
+second_user_data = {
+ "id": 4,
+ "name": "Mary",
+ "joined": "2018-11-30",
+}
+
+my_second_user: User = User(**second_user_data)
+```
+
+!!! info
+ `**second_user_data` nghĩa là:
+
+ Truyền các khóa và giá trị của dict `second_user_data` trực tiếp như các tham số kiểu key-value, tương đương với: `User(id=4, name="Mary", joined="2018-11-30")`
+
+### Được hỗ trợ từ các trình soạn thảo
+
+
+Toàn bộ framework được thiết kế để sử dụng dễ dàng và trực quan, toàn bộ quyết định đã được kiểm thử trên nhiều trình soạn thảo thậm chí trước khi bắt đầu quá trình phát triển, để chắc chắn trải nghiệm phát triển là tốt nhất.
+
+Trong lần khảo sát cuối cùng dành cho các lập trình viên Python, đã rõ ràng rằng đa số các lập trình viên sử dụng tính năng "autocompletion".
+
+Toàn bộ framework "FastAPI" phải đảm bảo rằng: autocompletion hoạt động ở mọi nơi. Bạn sẽ hiếm khi cần quay lại để đọc tài liệu.
+
+Đây là các trình soạn thảo có thể giúp bạn:
+
+* trong Visual Studio Code:
+
+
+
+* trong PyCharm:
+
+
+
+Bạn sẽ có được auto-completion trong code, thậm chí trước đó là không thể. Như trong ví dụ, khóa `price` bên trong một JSON (đó có thể được lồng nhau) đến từ một request.
+
+Không còn nhập sai tên khóa, quay đi quay lại giữa các tài liệu hoặc cuộn lên cuộn xuống để tìm xem cuối cùng bạn đã sử dụng `username` hay `user_name`.
+
+### Ngắn gọn
+
+FastAPI có các giá trị mặc định hợp lý cho mọi thứ, với các cấu hình tùy chọn ở mọi nơi. Tất cả các tham số có thể được tinh chỉnh để thực hiện những gì bạn cần và để định nghĩa API bạn cần.
+
+Nhưng mặc định, tất cả **đều hoạt động**.
+
+### Validation
+
+* Validation cho đa số (hoặc tất cả?) **các kiểu dữ liệu** Python, bao gồm:
+ * JSON objects (`dict`).
+ * Mảng JSON (`list`) định nghĩa kiểu dữ liệu từng phần tử.
+ * Xâu (`str`), định nghĩa độ dài lớn nhất, nhỏ nhất.
+ * Số (`int`, `float`) với các giá trị lớn nhất, nhỏ nhất, etc.
+
+* Validation cho nhiều kiểu dữ liệu bên ngoài như:
+ * URL.
+ * Email.
+ * UUID.
+ * ...và nhiều cái khác.
+
+Tất cả validation được xử lí bằng những thiết lập tốt và mạnh mẽ của **Pydantic**.
+
+### Bảo mật và xác thực
+
+Bảo mật và xác thực đã tích hợp mà không làm tổn hại tới cơ sở dữ liệu hoặc data models.
+
+Tất cả cơ chế bảo mật định nghĩa trong OpenAPI, bao gồm:
+
+* HTTP Basic.
+* **OAuth2** (với **JWT tokens**). Xem hướng dẫn [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
+* API keys in:
+ * Headers.
+ * Các tham số trong query string.
+ * Cookies, etc.
+
+Cộng với tất cả các tính năng bảo mật từ Starlette (bao gồm **session cookies**).
+
+Tất cả được xây dựng dưới dạng các công cụ và thành phần có thể tái sử dụng, dễ dàng tích hợp với hệ thống, kho lưu trữ dữ liệu, cơ sở dữ liệu quan hệ và NoSQL của bạn,...
+
+### Dependency Injection
+
+FastAPI bao gồm một hệ thống Dependency Injection vô cùng dễ sử dụng nhưng vô cùng mạnh mẽ.
+
+* Thậm chí, các dependency có thể có các dependency khác, tạo thành một phân cấp hoặc **"một đồ thị" của các dependency**.
+* Tất cả **được xử lí tự động** bởi framework.
+* Tất cả các dependency có thể yêu cầu dữ liệu từ request và **tăng cường các ràng buộc từ đường dẫn** và tự động tài liệu hóa.
+* **Tự động hóa validation**, thậm chí với các tham số *đường dẫn* định nghĩa trong các dependency.
+* Hỗ trợ hệ thống xác thực người dùng phức tạp, **các kết nối cơ sở dữ liệu**,...
+* **Không làm tổn hại** cơ sở dữ liệu, frontends,... Nhưng dễ dàng tích hợp với tất cả chúng.
+
+### Không giới hạn "plug-ins"
+
+Hoặc theo một cách nào khác, không cần chúng, import và sử dụng code bạn cần.
+
+Bất kì tích hợp nào được thiết kế để sử dụng đơn giản (với các dependency), đến nỗi bạn có thể tạo một "plug-in" cho ứng dụng của mình trong 2 dòng code bằng cách sử dụng cùng một cấu trúc và cú pháp được sử dụng cho *path operations* của bạn.
+
+### Đã được kiểm thử
+
+* 100% test coverage.
+* 100% type annotated code base.
+* Được sử dụng cho các ứng dụng sản phẩm.
+
+## Tính năng của Starlette
+
+`FastAPI` is thực sự là một sub-class của `Starlette`. Do đó, nếu bạn đã biết hoặc đã sử dụng Starlette, đa số các chức năng sẽ làm việc giống như vậy.
+
+Với **FastAPI**, bạn có được tất cả những tính năng của **Starlette**:
+
+* Hiệu năng thực sự ấn tượng. Nó là một trong nhưng framework Python nhanh nhất, khi so sánh với **NodeJS** và **Go**.
+* Hỗ trợ **WebSocket**.
+* In-process background tasks.
+* Startup and shutdown events.
+* Client cho kiểm thử xây dựng trên HTTPX.
+* **CORS**, GZip, Static Files, Streaming responses.
+* Hỗ trợ **Session and Cookie**.
+* 100% test coverage.
+* 100% type annotated codebase.
+
+## Tính năng của Pydantic
+
+**FastAPI** tương thích đầy đủ với (và dựa trên) Pydantic. Do đó, bất kì code Pydantic nào bạn thêm vào cũng sẽ hoạt động.
+
+Bao gồm các thư viện bên ngoài cũng dựa trên Pydantic, như ORMs, ODMs cho cơ sở dữ liệu.
+
+Nó cũng có nghĩa là trong nhiều trường hợp, bạn có thể truyền cùng object bạn có từ một request **trực tiếp cho cơ sở dữ liệu**, vì mọi thứ được validate tự động.
+
+Điều tương tự áp dụng cho các cách khác nhau, trong nhiều trường hợp, bạn có thể chỉ truyền object từ cơ sở dữ liêu **trực tiếp tới client**.
+
+Với **FastAPI**, bạn có tất cả những tính năng của **Pydantic** (FastAPI dựa trên Pydantic cho tất cả những xử lí về dữ liệu):
+
+* **Không gây rối não**:
+ * Không cần học ngôn ngữ mô tả cấu trúc mới.
+ * Nếu bạn biết kiểu dữ liệu Python, bạn biết cách sử dụng Pydantic.
+* Sử dụng tốt với **IDE/linter/não của bạn**:
+
+ * Bởi vì các cấu trúc dữ liệu của Pydantic chỉ là các instances của class bạn định nghĩa; auto-completion, linting, mypy và trực giác của bạn nên làm việc riêng biệt với những dữ liệu mà bạn đã validate.
+* Validate **các cấu trúc phức tạp**:
+ * Sử dụng các models Pydantic phân tầng, `List` và `Dict` của Python `typing`,...
+ * Và các validators cho phép các cấu trúc dữ liệu phức tạp trở nên rõ ràng và dễ dàng để định nghĩa, kiểm tra và tài liệu hóa thành JSON Schema.
+ * Bạn có thể có các object **JSON lồng nhau** và tất cả chúng đã validate và annotated.
+* **Có khả năng mở rộng**:
+ * Pydantic cho phép bạn tùy chỉnh kiểu dữ liệu bằng việc định nghĩa hoặc bạn có thể mở rộng validation với các decorator trong model.
+* 100% test coverage.
diff --git a/docs/vi/docs/index.md b/docs/vi/docs/index.md
new file mode 100644
index 000000000..3f416dbec
--- /dev/null
+++ b/docs/vi/docs/index.md
@@ -0,0 +1,472 @@
+
+
+
+
+ FastAPI framework, hiệu năng cao, dễ học, dễ code, sẵn sàng để tạo ra sản phẩm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+**Tài liệu**: https://fastapi.tiangolo.com
+
+**Mã nguồn**: https://github.com/tiangolo/fastapi
+
+---
+
+FastAPI là một web framework hiện đại, hiệu năng cao để xây dựng web APIs với Python 3.8+ dựa trên tiêu chuẩn Python type hints.
+
+Những tính năng như:
+
+* **Nhanh**: Hiệu năng rất cao khi so sánh với **NodeJS** và **Go** (cảm ơn Starlette và Pydantic). [Một trong những Python framework nhanh nhất](#performance).
+* **Code nhanh**: Tăng tốc độ phát triển tính năng từ 200% tới 300%. *
+* **Ít lỗi hơn**: Giảm khoảng 40% những lỗi phát sinh bởi con người (nhà phát triển). *
+* **Trực giác tốt hơn**: Được các trình soạn thảo hỗ tuyệt vời. Completion mọi nơi. Ít thời gian gỡ lỗi.
+* **Dễ dàng**: Được thiết kế để dễ dàng học và sử dụng. Ít thời gian đọc tài liệu.
+* **Ngắn**: Tối thiểu code bị trùng lặp. Nhiều tính năng được tích hợp khi định nghĩa tham số. Ít lỗi hơn.
+* **Tăng tốc**: Có được sản phẩm cùng với tài liệu (được tự động tạo) có thể tương tác.
+* **Được dựa trên các tiêu chuẩn**: Dựa trên (và hoàn toàn tương thích với) các tiêu chuẩn mở cho APIs : OpenAPI (trước đó được biết đến là Swagger) và JSON Schema.
+
+* ước tính được dựa trên những kiểm chứng trong nhóm phát triển nội bộ, xây dựng các ứng dụng sản phẩm.
+
+## Nhà tài trợ
+
+
+
+{% if sponsors %}
+{% for sponsor in sponsors.gold -%}
+
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+
+
+Những nhà tài trợ khác
+
+## Ý kiến đánh giá
+
+"_[...] Tôi đang sử dụng **FastAPI** vô cùng nhiều vào những ngày này. [...] Tôi thực sự đang lên kế hoạch sử dụng nó cho tất cả các nhóm **dịch vụ ML tại Microsoft**. Một vài trong số đó đang tích hợp vào sản phẩm lõi của **Window** và một vài sản phẩm cho **Office**._"
+
+Kabir Khan -
Microsoft (ref)
+
+---
+
+"_Chúng tôi tích hợp thư viện **FastAPI** để sinh ra một **REST** server, nó có thể được truy vấn để thu được những **dự đoán**._ [bởi Ludwid] "
+
+Piero Molino, Yaroslav Dudin, và Sai Sumanth Miryala -
Uber (ref)
+
+---
+
+"_**Netflix** vui mừng thông báo việc phát hành framework mã nguồn mở của chúng tôi cho *quản lí khủng hoảng* tập trung: **Dispatch**! [xây dựng với **FastAPI**]_"
+
+Kevin Glisson, Marc Vilanova, Forest Monsen -
Netflix (ref)
+
+---
+
+"_Tôi vô cùng hào hứng về **FastAPI**. Nó rất thú vị_"
+
+
+
+---
+
+"_Thành thật, những gì bạn đã xây dựng nhìn siêu chắc chắn và bóng bẩy. Theo nhiều cách, nó là những gì tôi đã muốn Hug trở thành - thật sự truyền cảm hứng để thấy ai đó xây dựng nó._"
+
+Timothy Crosley - người tạo ra
Hug (ref)
+
+---
+
+"_Nếu bạn đang tìm kiếm một **framework hiện đại** để xây dựng một REST APIs, thử xem xét **FastAPI** [...] Nó nhanh, dễ dùng và dễ học [...]_"
+
+"_Chúng tôi đã chuyển qua **FastAPI cho **APIs** của chúng tôi [...] Tôi nghĩ bạn sẽ thích nó [...]_"
+
+
+
+
+---
+
+"_Nếu ai đó đang tìm cách xây dựng sản phẩm API bằng Python, tôi sẽ đề xuất **FastAPI**. Nó **được thiết kế đẹp đẽ**, **sử dụng đơn giản** và **có khả năng mở rộng cao**, nó đã trở thành một **thành phần quan trọng** trong chiến lược phát triển API của chúng tôi và đang thúc đẩy nhiều dịch vụ và mảng tự động hóa như Kỹ sư TAC ảo của chúng tôi._"
+
+Deon Pillsbury -
Cisco (ref)
+
+---
+
+## **Typer**, giao diện dòng lệnh của FastAPI
+
+
+
+Nếu bạn đang xây dựng một CLI - ứng dụng được sử dụng trong giao diện dòng lệnh, xem về **Typer**.
+
+**Typer** là một người anh em của FastAPI. Và nó được dự định trở thành **giao diện dòng lệnh cho FastAPI**. ⌨️ 🚀
+
+## Yêu cầu
+
+Python 3.8+
+
+FastAPI đứng trên vai những người khổng lồ:
+
+* Starlette cho phần web.
+* Pydantic cho phần data.
+
+## Cài đặt
+
+
+
+```console
+$ pip install fastapi
+
+---> 100%
+```
+
+
+
+Bạn cũng sẽ cần một ASGI server cho production như Uvicorn hoặc Hypercorn.
+
+
+
+```console
+$ pip install "uvicorn[standard]"
+
+---> 100%
+```
+
+
+
+## Ví dụ
+
+### Khởi tạo
+
+* Tạo một tệp tin `main.py` như sau:
+
+```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}
+```
+
+
+Hoặc sử dụng async def
...
+
+Nếu code của bạn sử dụng `async` / `await`, hãy sử dụng `async def`:
+
+```Python hl_lines="9 14"
+from typing import Union
+
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+async def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+async def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+```
+
+**Lưu ý**:
+
+Nếu bạn không biết, xem phần _"In a hurry?"_ về `async` và `await` trong tài liệu này.
+
+
+
+### Chạy ứng dụng
+
+Chạy server như sau:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+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.
+```
+
+
+
+
+Về lệnh uvicorn main:app --reload
...
+
+Lệnh `uvicorn main:app` tham chiếu tới những thành phần sau:
+
+* `main`: tệp tin `main.py` (một Python "module").
+* `app`: object được tạo trong tệp tin `main.py` tại dòng `app = FastAPI()`.
+* `--reload`: chạy lại server sau khi code thay đổi. Chỉ sử dụng trong quá trình phát triển.
+
+
+
+### Kiểm tra
+
+Mở trình duyệt của bạn tại http://127.0.0.1:8000/items/5?q=somequery.
+
+Bạn sẽ thấy một JSON response:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+Bạn đã sẵn sàng để tạo một API như sau:
+
+* Nhận HTTP request với _đường dẫn_ `/` và `/items/{item_id}`.
+* Cả hai _đường dẫn_ sử dụng toán tử `GET` (cũng đươc biết đến là _phương thức_ HTTP).
+* _Đường dẫn_ `/items/{item_id}` có một _tham số đường dẫn_ `item_id`, nó là một tham số kiểu `int`.
+* _Đường dẫn_ `/items/{item_id}` có một _tham số query string_ `q`, nó là một tham số tùy chọn kiểu `str`.
+
+### Tài liệu tương tác API
+
+Truy cập http://127.0.0.1:8000/docs.
+
+Bạn sẽ thấy tài liệu tương tác API được tạo tự động (cung cấp bởi Swagger UI):
+
+
+
+### Tài liệu API thay thế
+
+Và bây giờ, hãy truy cập tới http://127.0.0.1:8000/redoc.
+
+Bạn sẽ thấy tài liệu được thay thế (cung cấp bởi ReDoc):
+
+
+
+## Nâng cấp ví dụ
+
+Bây giờ sửa tệp tin `main.py` để nhận body từ một request `PUT`.
+
+Định nghĩa của body sử dụng kiểu dữ liệu chuẩn của Python, cảm ơn Pydantic.
+
+```Python hl_lines="4 9-12 25-27"
+from typing import Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+ is_offer: Union[bool, None] = None
+
+
+@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}
+
+
+@app.put("/items/{item_id}")
+def update_item(item_id: int, item: Item):
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+Server nên tự động chạy lại (bởi vì bạn đã thêm `--reload` trong lệnh `uvicorn` ở trên).
+
+### Nâng cấp tài liệu API
+
+Bây giờ truy cập tới http://127.0.0.1:8000/docs.
+
+* Tài liệu API sẽ được tự động cập nhật, bao gồm body mới:
+
+
+
+* Click vào nút "Try it out", nó cho phép bạn điền những tham số và tương tác trực tiếp với API:
+
+
+
+* Sau khi click vào nút "Execute", giao diện người dùng sẽ giao tiếp với API của bạn bao gồm: gửi các tham số, lấy kết quả và hiển thị chúng trên màn hình:
+
+
+
+### Nâng cấp tài liệu API thay thế
+
+Và bây giờ truy cập tới http://127.0.0.1:8000/redoc.
+
+* Tài liệu thay thế cũng sẽ phản ánh tham số và body mới:
+
+
+
+### Tóm lại
+
+Bạn khai báo **một lần** kiểu dữ liệu của các tham số, body, etc là các tham số của hàm số.
+
+Bạn định nghĩa bằng cách sử dụng các kiểu dữ liệu chuẩn của Python.
+
+Bạn không phải học một cú pháp mới, các phương thức và class của một thư viện cụ thể nào.
+
+Chỉ cần sử dụng các chuẩn của **Python 3.8+**.
+
+Ví dụ, với một tham số kiểu `int`:
+
+```Python
+item_id: int
+```
+
+hoặc với một model `Item` phức tạp hơn:
+
+```Python
+item: Item
+```
+
+...và với định nghĩa đơn giản đó, bạn có được:
+
+* Sự hỗ trợ từ các trình soạn thảo, bao gồm:
+ * Completion.
+ * Kiểm tra kiểu dữ liệu.
+* Kiểm tra kiểu dữ liệu:
+ * Tự động sinh lỗi rõ ràng khi dữ liệu không hợp lệ .
+ * Kiểm tra JSON lồng nhau .
+* Chuyển đổi dữ liệu đầu vào: tới từ network sang dữ liệu kiểu Python. Đọc từ:
+ * JSON.
+ * Các tham số trong đường dẫn.
+ * Các tham số trong query string.
+ * Cookies.
+ * Headers.
+ * Forms.
+ * Files.
+* Chuyển đổi dữ liệu đầu ra: chuyển đổi từ kiểu dữ liệu Python sang dữ liệu network (như JSON):
+ * Chuyển đổi kiểu dữ liệu Python (`str`, `int`, `float`, `bool`, `list`,...).
+ * `datetime` objects.
+ * `UUID` objects.
+ * Database models.
+ * ...và nhiều hơn thế.
+* Tự động tạo tài liệu tương tác API, bao gồm 2 giao diện người dùng:
+ * Swagger UI.
+ * ReDoc.
+
+---
+
+Quay trở lại ví dụ trước, **FastAPI** sẽ thực hiện:
+
+* Kiểm tra xem có một `item_id` trong đường dẫn với các request `GET` và `PUT` không?
+* Kiểm tra xem `item_id` có phải là kiểu `int` trong các request `GET` và `PUT` không?
+ * Nếu không, client sẽ thấy một lỗi rõ ràng và hữu ích.
+* Kiểm tra xem nếu có một tham số `q` trong query string (ví dụ như `http://127.0.0.1:8000/items/foo?q=somequery`) cho request `GET`.
+ * Tham số `q` được định nghĩa `= None`, nó là tùy chọn.
+ * Nếu không phải `None`, nó là bắt buộc (như body trong trường hợp của `PUT`).
+* Với request `PUT` tới `/items/{item_id}`, đọc body như JSON:
+ * Kiểm tra xem nó có một thuộc tính bắt buộc kiểu `str` là `name` không?
+ * Kiểm tra xem nó có một thuộc tính bắt buộc kiểu `float` là `price` không?
+ * Kiểm tra xem nó có một thuộc tính tùy chọn là `is_offer` không? Nếu có, nó phải có kiểu `bool`.
+ * Tất cả những kiểm tra này cũng được áp dụng với các JSON lồng nhau.
+* Chuyển đổi tự động các JSON object đến và JSON object đi.
+* Tài liệu hóa mọi thứ với OpenAPI, tài liệu đó có thể được sử dụng bởi:
+
+ * Các hệ thống tài liệu có thể tương tác.
+ * Hệ thống sinh code tự động, cho nhiều ngôn ngữ lập trình.
+* Cung cấp trực tiếp 2 giao diện web cho tài liệu tương tác
+
+---
+
+Chúng tôi chỉ trình bày những thứ cơ bản bên ngoài, nhưng bạn đã hiểu cách thức hoạt động của nó.
+
+Thử thay đổi dòng này:
+
+```Python
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+...từ:
+
+```Python
+ ... "item_name": item.name ...
+```
+
+...sang:
+
+```Python
+ ... "item_price": item.price ...
+```
+
+...và thấy trình soạn thảo của bạn nhận biết kiểu dữ liệu và gợi ý hoàn thiện các thuộc tính.
+
+
+
+Ví dụ hoàn chỉnh bao gồm nhiều tính năng hơn, xem Tutorial - User Guide.
+
+
+**Cảnh báo tiết lỗ**: Tutorial - User Guide:
+
+* Định nghĩa **tham số** từ các nguồn khác nhau như: **headers**, **cookies**, **form fields** và **files**.
+* Cách thiết lập **các ràng buộc cho validation** như `maximum_length` hoặc `regex`.
+* Một hệ thống **Dependency Injection vô cùng mạnh mẽ và dễ dàng sử dụng.
+* Bảo mật và xác thực, hỗ trợ **OAuth2**(với **JWT tokens**) và **HTTP Basic**.
+* Những kĩ thuật nâng cao hơn (nhưng tương đối dễ) để định nghĩa **JSON models lồng nhau** (cảm ơn Pydantic).
+* Tích hợp **GraphQL** với Strawberry và các thư viện khác.
+* Nhiều tính năng mở rộng (cảm ơn Starlette) như:
+ * **WebSockets**
+ * kiểm thử vô cùng dễ dàng dựa trên HTTPX và `pytest`
+ * **CORS**
+ * **Cookie Sessions**
+ * ...và nhiều hơn thế.
+
+## Hiệu năng
+
+Independent TechEmpower benchmarks cho thấy các ứng dụng **FastAPI** chạy dưới Uvicorn là một trong những Python framework nhanh nhất, chỉ đứng sau Starlette và Uvicorn (được sử dụng bên trong FastAPI). (*)
+
+Để hiểu rõ hơn, xem phần Benchmarks.
+
+## Các dependency tùy chọn
+
+Sử dụng bởi Pydantic:
+
+* ujson
- "Parse" JSON nhanh hơn.
+* email_validator
- cho email validation.
+
+Sử dụng Starlette:
+
+* httpx
- Bắt buộc nếu bạn muốn sử dụng `TestClient`.
+* jinja2
- Bắt buộc nếu bạn muốn sử dụng cấu hình template engine mặc định.
+* python-multipart
- Bắt buộc nếu bạn muốn hỗ trợ "parsing", form với `request.form()`.
+* itsdangerous
- Bắt buộc để hỗ trợ `SessionMiddleware`.
+* pyyaml
- Bắt buộc để hỗ trợ `SchemaGenerator` cho Starlette (bạn có thể không cần nó trong FastAPI).
+* ujson
- Bắt buộc nếu bạn muốn sử dụng `UJSONResponse`.
+
+Sử dụng bởi FastAPI / Starlette:
+
+* uvicorn
- Server để chạy ứng dụng của bạn.
+* orjson
- Bắt buộc nếu bạn muốn sử dụng `ORJSONResponse`.
+
+Bạn có thể cài đặt tất cả những dependency trên với `pip install "fastapi[all]"`.
+
+## Giấy phép
+
+Dự án này được cấp phép dưới những điều lệ của giấy phép MIT.
diff --git a/docs/vi/docs/python-types.md b/docs/vi/docs/python-types.md
new file mode 100644
index 000000000..4999caac3
--- /dev/null
+++ b/docs/vi/docs/python-types.md
@@ -0,0 +1,545 @@
+# Giới thiệu kiểu dữ liệu Python
+
+Python hỗ trợ tùy chọn "type hints" (còn được gọi là "type annotations").
+
+Những **"type hints"** hay chú thích là một cú pháp đặc biệt cho phép khai báo kiểu dữ liệu của một biến.
+
+Bằng việc khai báo kiểu dữ liệu cho các biến của bạn, các trình soạn thảo và các công cụ có thể hỗ trợ bạn tốt hơn.
+
+Đây chỉ là một **hướng dẫn nhanh** về gợi ý kiểu dữ liệu trong Python. Nó chỉ bao gồm những điều cần thiết tối thiểu để sử dụng chúng với **FastAPI**... đó thực sự là rất ít.
+
+**FastAPI** hoàn toàn được dựa trên những gợi ý kiểu dữ liệu, chúng mang đến nhiều ưu điểm và lợi ích.
+
+Nhưng thậm chí nếu bạn không bao giờ sử dụng **FastAPI**, bạn sẽ được lợi từ việc học một ít về chúng.
+
+!!! note
+ Nếu bạn là một chuyên gia về Python, và bạn đã biết mọi thứ về gợi ý kiểu dữ liệu, bỏ qua và đi tới chương tiếp theo.
+
+## Động lực
+
+Hãy bắt đầu với một ví dụ đơn giản:
+
+```Python
+{!../../../docs_src/python_types/tutorial001.py!}
+```
+
+Kết quả khi gọi chương trình này:
+
+```
+John Doe
+```
+
+Hàm thực hiện như sau:
+
+* Lấy một `first_name` và `last_name`.
+* Chuyển đổi kí tự đầu tiên của mỗi biến sang kiểu chữ hoa với `title()`.
+* Nối chúng lại với nhau bằng một kí tự trắng ở giữa.
+
+```Python hl_lines="2"
+{!../../../docs_src/python_types/tutorial001.py!}
+```
+
+### Sửa đổi
+
+Nó là một chương trình rất đơn giản.
+
+Nhưng bây giờ hình dung rằng bạn đang viết nó từ đầu.
+
+Tại một vài thời điểm, bạn sẽ bắt đầu định nghĩa hàm, bạn có các tham số...
+
+Nhưng sau đó bạn phải gọi "phương thức chuyển đổi kí tự đầu tiên sang kiểu chữ hoa".
+
+Có phải là `upper`? Có phải là `uppercase`? `first_uppercase`? `capitalize`?
+
+Sau đó, bạn thử hỏi người bạn cũ của mình, autocompletion của trình soạn thảo.
+
+Bạn gõ tham số đầu tiên của hàm, `first_name`, sau đó một dấu chấm (`.`) và sau đó ấn `Ctrl+Space` để kích hoạt bộ hoàn thành.
+
+Nhưng đáng buồn, bạn không nhận được điều gì hữu ích cả:
+
+
+
+### Thêm kiểu dữ liệu
+
+Hãy sửa một dòng từ phiên bản trước.
+
+Chúng ta sẽ thay đổi chính xác đoạn này, tham số của hàm, từ:
+
+```Python
+ first_name, last_name
+```
+
+sang:
+
+```Python
+ first_name: str, last_name: str
+```
+
+Chính là nó.
+
+Những thứ đó là "type hints":
+
+```Python hl_lines="1"
+{!../../../docs_src/python_types/tutorial002.py!}
+```
+
+Đó không giống như khai báo những giá trị mặc định giống như:
+
+```Python
+ first_name="john", last_name="doe"
+```
+
+Nó là một thứ khác.
+
+Chúng ta sử dụng dấu hai chấm (`:`), không phải dấu bằng (`=`).
+
+Và việc thêm gợi ý kiểu dữ liệu không làm thay đổi những gì xảy ra so với khi chưa thêm chúng.
+
+But now, imagine you are again in the middle of creating that function, but with type hints.
+
+Tại cùng một điểm, bạn thử kích hoạt autocomplete với `Ctrl+Space` và bạn thấy:
+
+
+
+Với cái đó, bạn có thể cuộn, nhìn thấy các lựa chọn, cho đến khi bạn tìm thấy một "tiếng chuông":
+
+
+
+## Động lực nhiều hơn
+
+Kiểm tra hàm này, nó đã có gợi ý kiểu dữ liệu:
+
+```Python hl_lines="1"
+{!../../../docs_src/python_types/tutorial003.py!}
+```
+
+Bởi vì trình soạn thảo biết kiểu dữ liệu của các biến, bạn không chỉ có được completion, bạn cũng được kiểm tra lỗi:
+
+
+
+Bây giờ bạn biết rằng bạn phải sửa nó, chuyển `age` sang một xâu với `str(age)`:
+
+```Python hl_lines="2"
+{!../../../docs_src/python_types/tutorial004.py!}
+```
+
+## Khai báo các kiểu dữ liệu
+
+Bạn mới chỉ nhìn thấy những nơi chủ yếu để đặt khai báo kiểu dữ liệu. Như là các tham số của hàm.
+
+Đây cũng là nơi chủ yếu để bạn sử dụng chúng với **FastAPI**.
+
+### Kiểu dữ liệu đơn giản
+
+Bạn có thể khai báo tất cả các kiểu dữ liệu chuẩn của Python, không chỉ là `str`.
+
+Bạn có thể sử dụng, ví dụ:
+
+* `int`
+* `float`
+* `bool`
+* `bytes`
+
+```Python hl_lines="1"
+{!../../../docs_src/python_types/tutorial005.py!}
+```
+
+### Các kiểu dữ liệu tổng quát với tham số kiểu dữ liệu
+
+Có một vài cấu trúc dữ liệu có thể chứa các giá trị khác nhau như `dict`, `list`, `set` và `tuple`. Và những giá trị nội tại cũng có thể có kiểu dữ liệu của chúng.
+
+Những kiểu dữ liệu nội bộ này được gọi là những kiểu dữ liệu "**tổng quát**". Và có khả năng khai báo chúng, thậm chí với các kiểu dữ liệu nội bộ của chúng.
+
+Để khai báo những kiểu dữ liệu và những kiểu dữ liệu nội bộ đó, bạn có thể sử dụng mô đun chuẩn của Python là `typing`. Nó có hỗ trợ những gợi ý kiểu dữ liệu này.
+
+#### Những phiên bản mới hơn của Python
+
+Cú pháp sử dụng `typing` **tương thích** với tất cả các phiên bản, từ Python 3.6 tới những phiên bản cuối cùng, bao gồm Python 3.9, Python 3.10,...
+
+As Python advances, **những phiên bản mới** mang tới sự hỗ trợ được cải tiến cho những chú thích kiểu dữ liệu và trong nhiều trường hợp bạn thậm chí sẽ không cần import và sử dụng mô đun `typing` để khai báo chú thích kiểu dữ liệu.
+
+Nếu bạn có thể chọn một phiên bản Python gần đây hơn cho dự án của bạn, ban sẽ có được những ưu điểm của những cải tiến đơn giản đó.
+
+Trong tất cả các tài liệu tồn tại những ví dụ tương thích với mỗi phiên bản Python (khi có một sự khác nhau).
+
+Cho ví dụ "**Python 3.6+**" có nghĩa là nó tương thích với Python 3.7 hoặc lớn hơn (bao gồm 3.7, 3.8, 3.9, 3.10,...). và "**Python 3.9+**" nghĩa là nó tương thích với Python 3.9 trở lên (bao gồm 3.10,...).
+
+Nếu bạn có thể sử dụng **phiên bản cuối cùng của Python**, sử dụng những ví dụ cho phiên bản cuối, những cái đó sẽ có **cú pháp đơn giản và tốt nhât**, ví dụ, "**Python 3.10+**".
+
+#### List
+
+Ví dụ, hãy định nghĩa một biến là `list` các `str`.
+
+=== "Python 3.9+"
+
+ Khai báo biến với cùng dấu hai chấm (`:`).
+
+ Tương tự kiểu dữ liệu `list`.
+
+ Như danh sách là một kiểu dữ liệu chứa một vài kiểu dữ liệu có sẵn, bạn đặt chúng trong các dấu ngoặc vuông:
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ Từ `typing`, import `List` (với chữ cái `L` viết hoa):
+
+ ``` Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+ Khai báo biến với cùng dấu hai chấm (`:`).
+
+ Tương tự như kiểu dữ liệu, `List` bạn import từ `typing`.
+
+ Như danh sách là một kiểu dữ liệu chứa các kiểu dữ liệu có sẵn, bạn đặt chúng bên trong dấu ngoặc vuông:
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/python_types/tutorial006.py!}
+ ```
+
+!!! info
+ Các kiểu dữ liệu có sẵn bên trong dấu ngoặc vuông được gọi là "tham số kiểu dữ liệu".
+
+ Trong trường hợp này, `str` là tham số kiểu dữ liệu được truyền tới `List` (hoặc `list` trong Python 3.9 trở lên).
+
+Có nghĩa là: "biến `items` là một `list`, và mỗi phần tử trong danh sách này là một `str`".
+
+!!! tip
+ Nếu bạn sử dụng Python 3.9 hoặc lớn hơn, bạn không phải import `List` từ `typing`, bạn có thể sử dụng `list` để thay thế.
+
+Bằng cách này, trình soạn thảo của bạn có thể hỗ trợ trong khi xử lí các phần tử trong danh sách:
+
+
+
+Đa phần đều không thể đạt được nếu không có các kiểu dữ liệu.
+
+Chú ý rằng, biến `item` là một trong các phần tử trong danh sách `items`.
+
+Và do vậy, trình soạn thảo biết nó là một `str`, và cung cấp sự hỗ trợ cho nó.
+
+#### Tuple and Set
+
+Bạn sẽ làm điều tương tự để khai báo các `tuple` và các `set`:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial007_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial007.py!}
+ ```
+
+Điều này có nghĩa là:
+
+* Biến `items_t` là một `tuple` với 3 phần tử, một `int`, một `int` nữa, và một `str`.
+* Biến `items_s` là một `set`, và mỗi phần tử của nó có kiểu `bytes`.
+
+#### Dict
+
+Để định nghĩa một `dict`, bạn truyền 2 tham số kiểu dữ liệu, phân cách bởi dấu phẩy.
+
+Tham số kiểu dữ liệu đầu tiên dành cho khóa của `dict`.
+
+Tham số kiểu dữ liệu thứ hai dành cho giá trị của `dict`.
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008.py!}
+ ```
+
+Điều này có nghĩa là:
+
+* Biến `prices` là một `dict`:
+ * Khóa của `dict` này là kiểu `str` (đó là tên của mỗi vật phẩm).
+ * Giá trị của `dict` này là kiểu `float` (đó là giá của mỗi vật phẩm).
+
+#### Union
+
+Bạn có thể khai báo rằng một biến có thể là **một vài kiểu dữ liệu" bất kì, ví dụ, một `int` hoặc một `str`.
+
+Trong Python 3.6 hoặc lớn hơn (bao gồm Python 3.10) bạn có thể sử dụng kiểu `Union` từ `typing` và đặt trong dấu ngoặc vuông những giá trị được chấp nhận.
+
+In Python 3.10 there's also a **new syntax** where you can put the possible types separated by a vertical bar (`|`).
+
+Trong Python 3.10 cũng có một **cú pháp mới** mà bạn có thể đặt những kiểu giá trị khả thi phân cách bởi một dấu sổ dọc (`|`).
+
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial008b_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial008b.py!}
+ ```
+
+Trong cả hai trường hợp có nghĩa là `item` có thể là một `int` hoặc `str`.
+
+#### Khả năng `None`
+
+Bạn có thể khai báo một giá trị có thể có một kiểu dữ liệu, giống như `str`, nhưng nó cũng có thể là `None`.
+
+Trong Python 3.6 hoặc lớn hơn (bao gồm Python 3.10) bạn có thể khai báo nó bằng các import và sử dụng `Optional` từ mô đun `typing`.
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009.py!}
+```
+
+Sử dụng `Optional[str]` thay cho `str` sẽ cho phép trình soạn thảo giúp bạn phát hiện các lỗi mà bạn có thể gặp như một giá trị luôn là một `str`, trong khi thực tế nó rất có thể là `None`.
+
+`Optional[Something]` là một cách viết ngắn gọn của `Union[Something, None]`, chúng là tương đương nhau.
+
+Điều này cũng có nghĩa là trong Python 3.10, bạn có thể sử dụng `Something | None`:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/python_types/tutorial009_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009.py!}
+ ```
+
+=== "Python 3.8+ alternative"
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial009b.py!}
+ ```
+
+#### Sử dụng `Union` hay `Optional`
+
+If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view:
+
+Nếu bạn đang sử dụng phiên bản Python dưới 3.10, đây là một mẹo từ ý kiến rất "chủ quan" của tôi:
+
+* 🚨 Tránh sử dụng `Optional[SomeType]`
+* Thay vào đó ✨ **sử dụng `Union[SomeType, None]`** ✨.
+
+Cả hai là tương đương và bên dưới chúng giống nhau, nhưng tôi sẽ đễ xuất `Union` thay cho `Optional` vì từ "**tùy chọn**" có vẻ ngầm định giá trị là tùy chọn, và nó thực sự có nghĩa rằng "nó có thể là `None`", do đó nó không phải là tùy chọn và nó vẫn được yêu cầu.
+
+Tôi nghĩ `Union[SomeType, None]` là rõ ràng hơn về ý nghĩa của nó.
+
+Nó chỉ là về các từ và tên. Nhưng những từ đó có thể ảnh hưởng cách bạn và những đồng đội của bạn suy nghĩ về code.
+
+Cho một ví dụ, hãy để ý hàm này:
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009c.py!}
+```
+
+Tham số `name` được định nghĩa là `Optional[str]`, nhưng nó **không phải là tùy chọn**, bạn không thể gọi hàm mà không có tham số:
+
+```Python
+say_hi() # Oh, no, this throws an error! 😱
+```
+
+Tham số `name` **vẫn được yêu cầu** (không phải là *tùy chọn*) vì nó không có giá trị mặc định. Trong khi đó, `name` chấp nhận `None` như là giá trị:
+
+```Python
+say_hi(name=None) # This works, None is valid 🎉
+```
+
+Tin tốt là, khi bạn sử dụng Python 3.10, bạn sẽ không phải lo lắng về điều đó, bạn sẽ có thể sử dụng `|` để định nghĩa hợp của các kiểu dữ liệu một cách đơn giản:
+
+```Python hl_lines="1 4"
+{!../../../docs_src/python_types/tutorial009c_py310.py!}
+```
+
+Và sau đó, bạn sẽ không phải lo rằng những cái tên như `Optional` và `Union`. 😎
+
+
+#### Những kiểu dữ liệu tổng quát
+
+Những kiểu dữ liệu này lấy tham số kiểu dữ liệu trong dấu ngoặc vuông được gọi là **Kiểu dữ liệu tổng quát**, cho ví dụ:
+
+=== "Python 3.10+"
+
+ Bạn có thể sử dụng các kiểu dữ liệu có sẵn như là kiểu dữ liệu tổng quát (với ngoặc vuông và kiểu dữ liệu bên trong):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ Và tương tự với Python 3.6, từ mô đun `typing`:
+
+ * `Union`
+ * `Optional` (tương tự như Python 3.6)
+ * ...và các kiểu dữ liệu khác.
+
+ Trong Python 3.10, thay vì sử dụng `Union` và `Optional`, bạn có thể sử dụng sổ dọc ('|') để khai báo hợp của các kiểu dữ liệu, điều đó tốt hơn và đơn giản hơn nhiều.
+
+=== "Python 3.9+"
+
+ Bạn có thể sử dụng các kiểu dữ liệu có sẵn tương tự như (với ngoặc vuông và kiểu dữ liệu bên trong):
+
+ * `list`
+ * `tuple`
+ * `set`
+ * `dict`
+
+ Và tương tự với Python 3.6, từ mô đun `typing`:
+
+ * `Union`
+ * `Optional`
+ * ...and others.
+
+=== "Python 3.8+"
+
+ * `List`
+ * `Tuple`
+ * `Set`
+ * `Dict`
+ * `Union`
+ * `Optional`
+ * ...và các kiểu khác.
+
+### Lớp như kiểu dữ liệu
+
+Bạn cũng có thể khai báo một lớp như là kiểu dữ liệu của một biến.
+
+Hãy nói rằng bạn muốn có một lớp `Person` với một tên:
+
+```Python hl_lines="1-3"
+{!../../../docs_src/python_types/tutorial010.py!}
+```
+
+Sau đó bạn có thể khai báo một biến có kiểu là `Person`:
+
+```Python hl_lines="6"
+{!../../../docs_src/python_types/tutorial010.py!}
+```
+
+Và lại một lần nữa, bạn có được tất cả sự hỗ trợ từ trình soạn thảo:
+
+
+
+Lưu ý rằng, điều này có nghĩa rằng "`one_person`" là một **thực thể** của lớp `Person`.
+
+Nó không có nghĩa "`one_person`" là một **lớp** gọi là `Person`.
+
+## Pydantic models
+
+Pydantic là một thư viện Python để validate dữ liệu hiệu năng cao.
+
+Bạn có thể khai báo "hình dạng" của dữa liệu như là các lớp với các thuộc tính.
+
+Và mỗi thuộc tính có một kiểu dữ liệu.
+
+Sau đó bạn tạo một thực thể của lớp đó với một vài giá trị và nó sẽ validate các giá trị, chuyển đổi chúng sang kiểu dữ liệu phù hợp (nếu đó là trường hợp) và cho bạn một object với toàn bộ dữ liệu.
+
+Và bạn nhận được tất cả sự hỗ trợ của trình soạn thảo với object kết quả đó.
+
+Một ví dụ từ tài liệu chính thức của Pydantic:
+
+=== "Python 3.10+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python
+ {!> ../../../docs_src/python_types/tutorial011.py!}
+ ```
+
+!!! info
+ Để học nhiều hơn về Pydantic, tham khảo tài liệu của nó.
+
+**FastAPI** được dựa hoàn toàn trên Pydantic.
+
+Bạn sẽ thấy nhiều ví dụ thực tế hơn trong [Hướng dẫn sử dụng](tutorial/index.md){.internal-link target=_blank}.
+
+!!! tip
+ Pydantic có một hành vi đặc biệt khi bạn sử dụng `Optional` hoặc `Union[Something, None]` mà không có giá trị mặc dịnh, bạn có thể đọc nhiều hơn về nó trong tài liệu của Pydantic về Required Optional fields.
+
+
+## Type Hints với Metadata Annotations
+
+Python cũng có một tính năng cho phép đặt **metadata bổ sung** trong những gợi ý kiểu dữ liệu này bằng cách sử dụng `Annotated`.
+
+=== "Python 3.9+"
+
+ Trong Python 3.9, `Annotated` là một phần của thư viện chuẩn, do đó bạn có thể import nó từ `typing`.
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial013_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ Ở phiên bản dưới Python 3.9, bạn import `Annotated` từ `typing_extensions`.
+
+ Nó đã được cài đặt sẵng cùng với **FastAPI**.
+
+ ```Python hl_lines="1 4"
+ {!> ../../../docs_src/python_types/tutorial013.py!}
+ ```
+
+Python bản thân nó không làm bất kì điều gì với `Annotated`. Với các trình soạn thảo và các công cụ khác, kiểu dữ liệu vẫn là `str`.
+
+Nhưng bạn có thể sử dụng `Annotated` để cung cấp cho **FastAPI** metadata bổ sung về cách mà bạn muốn ứng dụng của bạn xử lí.
+
+Điều quan trọng cần nhớ là ***tham số kiểu dữ liệu* đầu tiên** bạn truyền tới `Annotated` là **kiểu giá trị thực sự**. Phần còn lại chỉ là metadata cho các công cụ khác.
+
+Bây giờ, bạn chỉ cần biết rằng `Annotated` tồn tại, và nó là tiêu chuẩn của Python. 😎
+
+
+Sau đó, bạn sẽ thấy sự **mạnh mẽ** mà nó có thể làm.
+
+!!! tip
+ Thực tế, cái này là **tiêu chuẩn của Python**, nghĩa là bạn vẫn sẽ có được **trải nghiệm phát triển tốt nhất có thể** với trình soạn thảo của bạn, với các công cụ bạn sử dụng để phân tích và tái cấu trúc code của bạn, etc. ✨
+
+ Và code của bạn sẽ tương thích với nhiều công cụ và thư viện khác của Python. 🚀
+
+## Các gợi ý kiểu dữ liệu trong **FastAPI**
+
+**FastAPI** lấy các ưu điểm của các gợi ý kiểu dữ liệu để thực hiện một số thứ.
+
+Với **FastAPI**, bạn khai báo các tham số với gợi ý kiểu và bạn có được:
+
+* **Sự hỗ trợ từ các trình soạn thảo**.
+* **Kiểm tra kiểu dữ liệu (type checking)**.
+
+...và **FastAPI** sử dụng các khia báo để:
+
+* **Định nghĩa các yêu cầu**: từ tham số đường dẫn của request, tham số query, headers, bodies, các phụ thuộc (dependencies),...
+* **Chuyển dổi dữ liệu*: từ request sang kiểu dữ liệu được yêu cầu.
+* **Kiểm tra tính đúng đắn của dữ liệu**: tới từ mỗi request:
+ * Sinh **lỗi tự động** để trả về máy khác khi dữ liệu không hợp lệ.
+* **Tài liệu hóa** API sử dụng OpenAPI:
+ * cái mà sau được được sử dụng bởi tài liệu tương tác người dùng.
+
+Điều này có thể nghe trừu tượng. Đừng lo lắng. Bạn sẽ thấy tất cả chúng trong [Hướng dẫn sử dụng](tutorial/index.md){.internal-link target=_blank}.
+
+Điều quan trọng là bằng việc sử dụng các kiểu dữ liệu chuẩn của Python (thay vì thêm các lớp, decorators,...), **FastAPI** sẽ thực hiện nhiều công việc cho bạn.
+
+!!! info
+ Nếu bạn đã đi qua toàn bộ các hướng dẫn và quay trở lại để tìm hiểu nhiều hơn về các kiểu dữ liệu, một tài nguyên tốt như "cheat sheet" từ `mypy`.
diff --git a/docs/vi/docs/tutorial/first-steps.md b/docs/vi/docs/tutorial/first-steps.md
new file mode 100644
index 000000000..712f00852
--- /dev/null
+++ b/docs/vi/docs/tutorial/first-steps.md
@@ -0,0 +1,333 @@
+# Những bước đầu tiên
+
+Tệp tin FastAPI đơn giản nhất có thể trông như này:
+
+```Python
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Sao chép sang một tệp tin `main.py`.
+
+Chạy live server:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+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.
+```
+
+
+
+!!! note
+ Câu lệnh `uvicorn main:app` được giải thích như sau:
+
+ * `main`: tệp tin `main.py` (một Python "mô đun").
+ * `app`: một object được tạo ra bên trong `main.py` với dòng `app = FastAPI()`.
+ * `--reload`: làm server khởi động lại sau mỗi lần thay đổi. Chỉ sử dụng trong môi trường phát triển.
+
+Trong output, có một dòng giống như:
+
+```hl_lines="4"
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+Dòng đó cho thấy URL, nơi mà app của bạn đang được chạy, trong máy local của bạn.
+
+### Kiểm tra
+
+Mở trình duyệt của bạn tại http://127.0.0.1:8000.
+
+Bạn sẽ thấy một JSON response như:
+
+```JSON
+{"message": "Hello World"}
+```
+
+### Tài liệu tương tác API
+
+Bây giờ tới http://127.0.0.1:8000/docs.
+
+Bạn sẽ thấy một tài liệu tương tác API (cung cấp bởi Swagger UI):
+
+
+
+### Phiên bản thay thế của tài liệu API
+
+Và bây giờ tới http://127.0.0.1:8000/redoc.
+
+Bạn sẽ thấy một bản thay thế của tài liệu (cung cấp bởi ReDoc):
+
+
+
+### OpenAPI
+
+**FastAPI** sinh một "schema" với tất cả API của bạn sử dụng tiêu chuẩn **OpenAPI** cho định nghĩa các API.
+
+#### "Schema"
+
+Một "schema" là một định nghĩa hoặc mô tả thứ gì đó. Không phải code triển khai của nó, nhưng chỉ là một bản mô tả trừu tượng.
+
+#### API "schema"
+
+Trong trường hợp này, OpenAPI là một bản mô tả bắt buộc cơ chế định nghĩa API của bạn.
+
+Định nghĩa cấu trúc này bao gồm những đường dẫn API của bạn, các tham số có thể có,...
+
+#### "Cấu trúc" dữ liệu
+
+Thuật ngữ "cấu trúc" (schema) cũng có thể được coi như là hình dạng của dữ liệu, tương tự như một JSON content.
+
+Trong trường hợp đó, nó có nghĩa là các thuộc tính JSON và các kiểu dữ liệu họ có,...
+
+#### OpenAPI và JSON Schema
+
+OpenAPI định nghĩa một cấu trúc API cho API của bạn. Và cấu trúc đó bao gồm các dịnh nghĩa (or "schema") về dữ liệu được gửi đi và nhận về bởi API của bạn, sử dụng **JSON Schema**, một tiêu chuẩn cho cấu trúc dữ liệu JSON.
+
+#### Kiểm tra `openapi.json`
+
+Nếu bạn tò mò về việc cấu trúc OpenAPI nhìn như thế nào thì FastAPI tự động sinh một JSON (schema) với các mô tả cho tất cả API của bạn.
+
+Bạn có thể thấy nó trực tiếp tại: http://127.0.0.1:8000/openapi.json.
+
+Nó sẽ cho thấy một JSON bắt đầu giống như:
+
+```JSON
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+
+
+
+...
+```
+
+#### OpenAPI dùng để làm gì?
+
+Cấu trúc OpenAPI là sức mạnh của tài liệu tương tác.
+
+Và có hàng tá các bản thay thế, tất cả đều dựa trên OpenAPI. Bạn có thể dễ dàng thêm bất kì bản thay thế bào cho ứng dụng của bạn được xây dựng với **FastAPI**.
+
+Bạn cũng có thể sử dụng nó để sinh code tự động, với các client giao viết qua API của bạn. Ví dụ, frontend, mobile hoặc các ứng dụng IoT.
+
+## Tóm lại, từng bước một
+
+### Bước 1: import `FastAPI`
+
+```Python hl_lines="1"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+`FastAPI` là một Python class cung cấp tất cả chức năng cho API của bạn.
+
+!!! note "Chi tiết kĩ thuật"
+ `FastAPI` là một class kế thừa trực tiếp `Starlette`.
+
+ Bạn cũng có thể sử dụng tất cả Starlette chức năng với `FastAPI`.
+
+### Bước 2: Tạo một `FastAPI` "instance"
+
+```Python hl_lines="3"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Biến `app` này là một "instance" của class `FastAPI`.
+
+Đây sẽ là điểm cốt lõi để tạo ra tất cả API của bạn.
+
+`app` này chính là điều được nhắc tới bởi `uvicorn` trong câu lệnh:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Nếu bạn tạo ứng dụng của bạn giống như:
+
+```Python hl_lines="3"
+{!../../../docs_src/first_steps/tutorial002.py!}
+```
+
+Và đặt nó trong một tệp tin `main.py`, sau đó bạn sẽ gọi `uvicorn` giống như:
+
+
+
+```console
+$ uvicorn main:my_awesome_api --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+### Bước 3: tạo một *đường dẫn toán tử*
+
+#### Đường dẫn
+
+"Đường dẫn" ở đây được nhắc tới là phần cuối cùng của URL bắt đầu từ `/`.
+
+Do đó, trong một URL nhìn giống như:
+
+```
+https://example.com/items/foo
+```
+
+...đường dẫn sẽ là:
+
+```
+/items/foo
+```
+
+!!! info
+ Một đường dẫn cũng là một cách gọi chung cho một "endpoint" hoặc một "route".
+
+Trong khi xây dựng một API, "đường dẫn" là các chính để phân tách "mối quan hệ" và "tài nguyên".
+
+#### Toán tử (Operation)
+
+"Toán tử" ở đây được nhắc tới là một trong các "phương thức" HTTP.
+
+Một trong những:
+
+* `POST`
+* `GET`
+* `PUT`
+* `DELETE`
+
+...và một trong những cái còn lại:
+
+* `OPTIONS`
+* `HEAD`
+* `PATCH`
+* `TRACE`
+
+Trong giao thức HTTP, bạn có thể giao tiếp trong mỗi đường dẫn sử dụng một (hoặc nhiều) trong các "phương thức này".
+
+---
+
+Khi xây dựng các API, bạn thường sử dụng cụ thể các phương thức HTTP này để thực hiện một hành động cụ thể.
+
+Thông thường, bạn sử dụng
+
+* `POST`: để tạo dữ liệu.
+* `GET`: để đọc dữ liệu.
+* `PUT`: để cập nhật dữ liệu.
+* `DELETE`: để xóa dữ liệu.
+
+Do đó, trong OpenAPI, mỗi phương thức HTTP được gọi là một "toán tử (operation)".
+
+Chúng ta cũng sẽ gọi chúng là "**các toán tử**".
+
+#### Định nghĩa moojt *decorator cho đường dẫn toán tử*
+
+```Python hl_lines="6"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+`@app.get("/")` nói **FastAPI** rằng hàm bên dưới có trách nhiệm xử lí request tới:
+
+* đường dẫn `/`
+* sử dụng một toán tửget
+
+!!! info Thông tin về "`@decorator`"
+ Cú pháp `@something` trong Python được gọi là một "decorator".
+
+ Bạn đặt nó trên một hàm. Giống như một chiếc mũ xinh xắn (Tôi ddonas đó là lí do mà thuật ngữ này ra đời).
+
+ Một "decorator" lấy một hàm bên dưới và thực hiện một vài thứ với nó.
+
+ Trong trường hợp của chúng ta, decorator này nói **FastAPI** rằng hàm bên dưới ứng với **đường dẫn** `/` và một **toán tử** `get`.
+
+ Nó là một "**decorator đường dẫn toán tử**".
+
+Bạn cũng có thể sử dụng với các toán tử khác:
+
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+
+Và nhiều hơn với các toán tử còn lại:
+
+* `@app.options()`
+* `@app.head()`
+* `@app.patch()`
+* `@app.trace()`
+
+!!! tip
+ Bạn thoải mái sử dụng mỗi toán tử (phương thức HTTP) như bạn mơ ước.
+
+ **FastAPI** không bắt buộc bất kì ý nghĩa cụ thể nào.
+
+ Thông tin ở đây được biểu thị như là một chỉ dẫn, không phải là một yêu cầu bắt buộc.
+
+ Ví dụ, khi sử dụng GraphQL bạn thông thường thực hiện tất cả các hành động chỉ bằng việc sử dụng các toán tử `POST`.
+
+### Step 4: Định nghĩa **hàm cho đường dẫn toán tử**
+
+Đây là "**hàm cho đường dẫn toán tử**":
+
+* **đường dẫn**: là `/`.
+* **toán tử**: là `get`.
+* **hàm**: là hàm bên dưới "decorator" (bên dưới `@app.get("/")`).
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Đây là một hàm Python.
+
+Nó sẽ được gọi bởi **FastAPI** bất cứ khi nào nó nhận một request tới URL "`/`" sử dụng một toán tử `GET`.
+
+Trong trường hợp này, nó là một hàm `async`.
+
+---
+
+Bạn cũng có thể định nghĩa nó như là một hàm thông thường thay cho `async def`:
+
+```Python hl_lines="7"
+{!../../../docs_src/first_steps/tutorial003.py!}
+```
+
+!!! note
+ Nếu bạn không biết sự khác nhau, kiểm tra [Async: *"Trong khi vội vàng?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
+
+### Bước 5: Nội dung trả về
+
+```Python hl_lines="8"
+{!../../../docs_src/first_steps/tutorial001.py!}
+```
+
+Bạn có thể trả về một `dict`, `list`, một trong những giá trị đơn như `str`, `int`,...
+
+Bạn cũng có thể trả về Pydantic model (bạn sẽ thấy nhiều hơn về nó sau).
+
+Có nhiều object và model khác nhau sẽ được tự động chuyển đổi sang JSON (bao gồm cả ORM,...). Thử sử dụng loại ưa thích của bạn, nó có khả năng cao đã được hỗ trợ.
+
+## Tóm lại
+
+* Import `FastAPI`.
+* Tạo một `app` instance.
+* Viết một **decorator cho đường dẫn toán tử** (giống như `@app.get("/")`).
+* Viết một **hàm cho đường dẫn toán tử** (giống như `def root(): ...` ở trên).
+* Chạy server trong môi trường phát triển (giống như `uvicorn main:app --reload`).
diff --git a/docs/vi/docs/tutorial/index.md b/docs/vi/docs/tutorial/index.md
new file mode 100644
index 000000000..e8a93fe40
--- /dev/null
+++ b/docs/vi/docs/tutorial/index.md
@@ -0,0 +1,80 @@
+# Hướng dẫn sử dụng
+
+Hướng dẫn này cho bạn thấy từng bước cách sử dụng **FastAPI** đa số các tính năng của nó.
+
+Mỗi phần được xây dựng từ những phần trước đó, nhưng nó được cấu trúc thành các chủ đề riêng biệt, do đó bạn có thể xem trực tiếp từng phần cụ thể bất kì để giải quyết những API cụ thể mà bạn cần.
+
+Nó cũng được xây dựng để làm việc như một tham chiếu trong tương lai.
+
+Do đó bạn có thể quay lại và tìm chính xác những gì bạn cần.
+
+## Chạy mã
+
+Tất cả các code block có thể được sao chép và sử dụng trực tiếp (chúng thực chất là các tệp tin Python đã được kiểm thử).
+
+Để chạy bất kì ví dụ nào, sao chép code tới tệp tin `main.py`, và bắt đầu `uvicorn` với:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+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.
+```
+
+
+
+**Khuyến khích** bạn viết hoặc sao chép code, sửa và chạy nó ở local.
+
+Sử dụng nó trong trình soạn thảo của bạn thực sự cho bạn thấy những lợi ích của FastAPI, thấy được cách bạn viết code ít hơn, tất cả đều được type check, autocompletion,...
+
+---
+
+## Cài đặt FastAPI
+
+Bước đầu tiên là cài đặt FastAPI.
+
+Với hướng dẫn này, bạn có thể muốn cài đặt nó với tất cả các phụ thuộc và tính năng tùy chọn:
+
+
+
+```console
+$ pip install "fastapi[all]"
+
+---> 100%
+```
+
+
+
+...dó cũng bao gồm `uvicorn`, bạn có thể sử dụng như một server để chạy code của bạn.
+
+!!! note
+ Bạn cũng có thể cài đặt nó từng phần.
+
+ Đây là những gì bạn có thể sẽ làm một lần duy nhất bạn muốn triển khai ứng dụng của bạn lên production:
+
+ ```
+ pip install fastapi
+ ```
+
+ Cũng cài đặt `uvicorn` để làm việc như một server:
+
+ ```
+ pip install "uvicorn[standard]"
+ ```
+
+ Và tương tự với từng phụ thuộc tùy chọn mà bạn muốn sử dụng.
+
+## Hướng dẫn nâng cao
+
+Cũng có một **Hướng dẫn nâng cao** mà bạn có thể đọc nó sau **Hướng dẫn sử dụng**.
+
+**Hướng dẫn sử dụng nâng cao**, xây dựng dựa trên cái này, sử dụng các khái niệm tương tự, và dạy bạn những tính năng mở rộng.
+
+Nhưng bạn nên đọc **Hướng dẫn sử dụng** đầu tiên (những gì bạn đang đọc).
+
+Nó được thiết kế do đó bạn có thể xây dựng một ứng dụng hoàn chỉnh chỉ với **Hướng dẫn sử dụng**, và sau đó mở rộng nó theo các cách khác nhau, phụ thuộc vào những gì bạn cần, sử dụng một vài ý tưởng bổ sung từ **Hướng dẫn sử dụng nâng cao**.
diff --git a/docs/vi/mkdocs.yml b/docs/vi/mkdocs.yml
new file mode 100644
index 000000000..de18856f4
--- /dev/null
+++ b/docs/vi/mkdocs.yml
@@ -0,0 +1 @@
+INHERIT: ../en/mkdocs.yml
diff --git a/docs/yo/docs/index.md b/docs/yo/docs/index.md
new file mode 100644
index 000000000..101e13b6b
--- /dev/null
+++ b/docs/yo/docs/index.md
@@ -0,0 +1,470 @@
+
+
+
+
+ Ìlànà wẹ́ẹ́bù FastAPI, iṣẹ́ gíga, ó rọrùn láti kọ̀, o yára láti kóòdù, ó sì ṣetán fún iṣelọpọ ní lílo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+**Àkọsílẹ̀**: https://fastapi.tiangolo.com
+
+**Orisun Kóòdù**: https://github.com/tiangolo/fastapi
+
+---
+
+FastAPI jẹ́ ìgbàlódé, tí ó yára (iṣẹ-giga), ìlànà wẹ́ẹ́bù fún kikọ àwọn API pẹ̀lú Python 3.8+ èyí tí ó da lori àwọn ìtọ́kasí àmì irúfẹ́ Python.
+
+Àwọn ẹya pàtàkì ni:
+
+* **Ó yára**: Iṣẹ tí ó ga púpọ̀, tí ó wa ni ibamu pẹ̀lú **NodeJS** àti **Go** (ọpẹ si Starlette àti Pydantic). [Ọkan nínú àwọn ìlànà Python ti o yára jùlọ ti o wa](#performance).
+* **Ó yára láti kóòdù**: O mu iyara pọ si láti kọ àwọn ẹya tuntun kóòdù nipasẹ "Igba ìdá ọgọ́rùn-ún" (i.e. 200%) si "ọ̀ọ́dúrún ìdá ọgọ́rùn-ún" (i.e. 300%).
+* **Àìtọ́ kékeré**: O n din aṣiṣe ku bi ọgbon ìdá ọgọ́rùn-ún (i.e. 40%) ti eda eniyan (oṣiṣẹ kóòdù) fa. *
+* **Ọgbọ́n àti ìmọ̀**: Atilẹyin olootu nla. Ìparí nibi gbogbo. Àkókò díẹ̀ nipa wíwá ibi tí ìṣòro kóòdù wà.
+* **Irọrun**: A kọ kí ó le rọrun láti lo àti láti kọ ẹkọ nínú rè. Ó máa fún ọ ní àkókò díẹ̀ látı ka àkọsílẹ.
+* **Ó kúkurú ní kikọ**: Ó dín àtúnkọ àti àtúntò kóòdù kù. Ìkéde àṣàyàn kọ̀ọ̀kan nínú rẹ̀ ní ọ̀pọ̀lọpọ̀ àwọn ìlò. O ṣe iranlọwọ láti má ṣe ní ọ̀pọ̀lọpọ̀ àṣìṣe.
+* **Ó lágbára**: Ó ń ṣe àgbéjáde kóòdù tí ó ṣetán fún ìṣelọ́pọ̀. Pẹ̀lú àkọsílẹ̀ tí ó máa ṣàlàyé ara rẹ̀ fún ẹ ní ìbáṣepọ̀ aládàáṣiṣẹ́ pẹ̀lú rè.
+* **Ajohunše/Ìtọ́kasí**: Ó da lori (àti ibamu ni kikun pẹ̀lú) àwọn ìmọ ajohunše/ìtọ́kasí fún àwọn API: OpenAPI (èyí tí a mọ tẹlẹ si Swagger) àti JSON Schema.
+
+* iṣiro yi da lori àwọn idanwo tí ẹgbẹ ìdàgbàsókè FastAPI ṣe, nígbàtí wọn kọ àwọn ohun elo iṣelọpọ kóòdù pẹ̀lú rẹ.
+
+## Àwọn onígbọ̀wọ́
+
+
+
+{% if sponsors %}
+{% for sponsor in sponsors.gold -%}
+
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+
+
+Àwọn onígbọ̀wọ́ míràn
+
+## Àwọn ero àti èsì
+
+"_[...] Mò ń lo **FastAPI** púpọ̀ ní lẹ́nu àìpẹ́ yìí. [...] Mo n gbero láti lo o pẹ̀lú àwọn ẹgbẹ mi fún gbogbo iṣẹ **ML wa ni Microsoft**. Diẹ nínú wọn ni afikun ti ifilelẹ àwọn ẹya ara ti ọja **Windows** wa pẹ̀lú àwọn ti **Office**._"
+
+Kabir Khan -
Microsoft (ref)
+
+---
+
+"_A gba àwọn ohun èlò ìwé afọwọkọ **FastAPI** tí kò yí padà láti ṣẹ̀dá olùpín **REST** tí a lè béèrè lọ́wọ́ rẹ̀ láti gba **àsọtẹ́lẹ̀**. [fún Ludwig]_"
+
+Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala -
Uber (ref)
+
+---
+
+"_**Netflix** ni inudidun láti kede itusilẹ orisun kóòdù ti ìlànà iṣọkan **iṣakoso Ìṣòro** wa: **Ìfiránṣẹ́**! [a kọ pẹ̀lú **FastAPI**]_"
+
+Kevin Glisson, Marc Vilanova, Forest Monsen -
Netflix (ref)
+
+---
+
+"_Inú mi dùn púpọ̀ nípa **FastAPI**. Ó mú inú ẹnì dùn púpọ̀!_"
+
+
+
+---
+
+"_Ní tòótọ́, ohun tí o kọ dára ó sì tún dán. Ní ọ̀pọ̀lọpọ̀ ọ̀nà, ohun tí mo fẹ́ kí **Hug** jẹ́ nìyẹn - ó wúni lórí gan-an láti rí ẹnìkan tí ó kọ́ nǹkan bí èyí._"
+
+
+
+---
+
+"_Ti o ba n wa láti kọ ọkan **ìlànà igbalode** fún kikọ àwọn REST API, ṣayẹwo **FastAPI** [...] Ó yára, ó rọrùn láti lò, ó sì rọrùn láti kọ́[...]_"
+
+"_A ti yipada si **FastAPI** fún **APIs** wa [...] Mo lérò pé wà á fẹ́ràn rẹ̀ [...]_"
+
+
+
+---
+
+"_Ti ẹnikẹni ba n wa láti kọ iṣelọpọ API pẹ̀lú Python, èmi yóò ṣe'dúró fún **FastAPI**. Ó jẹ́ ohun tí **àgbékalẹ̀ rẹ̀ lẹ́wà**, **ó rọrùn láti lò** àti wipe ó ni **ìwọ̀n gíga**, o tí dí **bọtini paati** nínú alakọkọ API ìdàgbàsókè kikọ fún wa, àti pe o ni ipa lori adaṣiṣẹ àti àwọn iṣẹ gẹ́gẹ́ bíi Onímọ̀-ẹ̀rọ TAC tí órí Íńtánẹ́ẹ̀tì_"
+
+Deon Pillsbury -
Cisco (ref)
+
+---
+
+## **Typer**, FastAPI ti CLIs
+
+
+
+Ti o ba n kọ ohun èlò CLI láti ṣeé lọ nínú ohun èlò lori ebute kọmputa dipo API, ṣayẹwo **Typer**.
+
+**Typer** jẹ́ àbúrò ìyá FastAPI kékeré. Àti pé wọ́n kọ́ láti jẹ́ **FastAPI ti CLIs**. ⌨️ 🚀
+
+## Èròjà
+
+Python 3.8+
+
+FastAPI dúró lórí àwọn èjìká tí àwọn òmíràn:
+
+* Starlette fún àwọn ẹ̀yà ayélujára.
+* Pydantic fún àwọn ẹ̀yà àkójọf'áyẹ̀wò.
+
+## Fifi sórí ẹrọ
+
+
+
+```console
+$ pip install fastapi
+
+---> 100%
+```
+
+
+Iwọ yóò tún nílò olupin ASGI, fún iṣelọpọ bii Uvicorn tabi Hypercorn.
+
+
+
+```console
+$ pip install "uvicorn[standard]"
+
+---> 100%
+```
+
+
+
+## Àpẹẹrẹ
+
+### Ṣẹ̀dá rẹ̀
+
+* Ṣẹ̀dá fáìlì `main.py (èyí tíí ṣe, akọkọ.py)` pẹ̀lú:
+
+```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}
+```
+
+
+Tàbí lò async def
...
+
+Tí kóòdù rẹ̀ bá ń lò `async` / `await`, lò `async def`:
+
+```Python hl_lines="9 14"
+from typing import Union
+
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+async def read_root():
+ return {"Hello": "World"}
+
+
+@app.get("/items/{item_id}")
+async def read_item(item_id: int, q: Union[str, None] = None):
+ return {"item_id": item_id, "q": q}
+```
+
+**Akiyesi**:
+
+Tí o kò bá mọ̀, ṣàyẹ̀wò ibi tí a ti ní _"In a hurry?"_ (i.e. _"Ní kíákíá?"_) nípa `async` and `await` nínú àkọsílẹ̀.
+
+
+
+### Mu ṣiṣẹ
+
+Mú olupin ṣiṣẹ pẹ̀lú:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+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.
+```
+
+
+
+
+Nipa aṣẹ kóòdù náà uvicorn main:app --reload
...
+
+Àṣẹ `uvicorn main:app` ń tọ́ka sí:
+
+* `main`: fáìlì náà 'main.py' (Python "module").
+* `app` jẹ object( i.e. nǹkan) tí a ṣẹ̀dá nínú `main.py` pẹ̀lú ilà `app = FastAPI()`.
+* `--reload`: èyí yóò jẹ́ ki olupin tún bẹ̀rẹ̀ lẹ́hìn àwọn àyípadà kóòdù. Jọ̀wọ́, ṣe èyí fún ìdàgbàsókè kóòdù nìkan, má ṣe é ṣe lori àgbéjáde kóòdù tabi fún iṣelọpọ kóòdù.
+
+
+
+
+### Ṣayẹwo rẹ
+
+Ṣii aṣàwákiri kọ̀ǹpútà rẹ ni http://127.0.0.1:8000/items/5?q=somequery.
+
+Ìwọ yóò sì rí ìdáhùn JSON bíi:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+O tí ṣẹ̀dá API èyí tí yóò:
+
+* Gbà àwọn ìbéèrè HTTP ni àwọn _ipa ọ̀nà_ `/` àti `/items/{item_id}`.
+* Èyí tí àwọn _ipa ọ̀nà_ (i.e. _paths_) méjèèjì gbà àwọn iṣẹ `GET` (a tun mọ si _àwọn ọna_ HTTP).
+* Èyí tí _ipa ọ̀nà_ (i.e. _paths_) `/items/{item_id}` ní _àwọn ohun-ini ipa ọ̀nà_ tí ó yẹ kí ó jẹ́ `int` i.e. `ÒǸKÀ`.
+* Èyí tí _ipa ọ̀nà_ (i.e. _paths_) `/items/{item_id}` ní àṣàyàn `str` _àwọn ohun-ini_ (i.e. _query parameter_) `q`.
+
+### Ìbáṣepọ̀ àkọsílẹ̀ API
+
+Ní báyìí, lọ sí http://127.0.0.1:8000/docs.
+
+Lẹ́yìn náà, iwọ yóò rí ìdáhùn àkọsílẹ̀ API tí ó jẹ́ ìbáṣepọ̀ alaifọwọyi/aládàáṣiṣẹ́ (tí a pèṣè nípaṣẹ̀ Swagger UI):
+
+
+
+### Ìdàkejì àkọsílẹ̀ API
+
+Ní báyìí, lọ sí http://127.0.0.1:8000/redoc.
+
+Wà á rí àwọn àkọsílẹ̀ aládàáṣiṣẹ́ mìíràn (tí a pese nipasẹ ReDoc):
+
+
+
+## Àpẹẹrẹ ìgbésókè mìíràn
+
+Ní báyìí ṣe àtúnṣe fáìlì `main.py` láti gba kókó èsì láti inú ìbéèrè `PUT`.
+
+Ní báyìí, ṣe ìkéde kókó èsì API nínú kóòdù rẹ nipa lílo àwọn ìtọ́kasí àmì irúfẹ́ Python, ọpẹ́ pàtàkìsi sí Pydantic.
+
+```Python hl_lines="4 9-12 25-27"
+from typing import Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ price: float
+ is_offer: Union[bool, None] = None
+
+
+@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}
+
+
+@app.put("/items/{item_id}")
+def update_item(item_id: int, item: Item):
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+Olupin yóò tún ṣe àtúnṣe laifọwọyi/aládàáṣiṣẹ́ (nítorí wípé ó se àfikún `-reload` si àṣẹ kóòdù `uvicorn` lókè).
+
+### Ìbáṣepọ̀ ìgbésókè àkọsílẹ̀ API
+
+Ní báyìí, lọ sí http://127.0.0.1:8000/docs.
+
+* Ìbáṣepọ̀ àkọsílẹ̀ API yóò ṣe imudojuiwọn àkọsílẹ̀ API laifọwọyi, pẹ̀lú kókó èsì ìdáhùn API tuntun:
+
+
+
+* Tẹ bọtini "Gbiyanju rẹ" i.e. "Try it out", yóò gbà ọ́ láàyè láti jẹ́ kí ó tẹ́ àlàyé tí ó nílò kí ó le sọ̀rọ̀ tààrà pẹ̀lú API:
+
+
+
+* Lẹhinna tẹ bọtini "Ṣiṣe" i.e. "Execute", olùmúlò (i.e. user interface) yóò sọrọ pẹ̀lú API rẹ, yóò ṣe afiranṣẹ àwọn èròjà, pàápàá jùlọ yóò gba àwọn àbájáde yóò si ṣafihan wọn loju ìbòjú:
+
+
+
+### Ìdàkejì ìgbésókè àkọsílẹ̀ API
+
+Ní báyìí, lọ sí http://127.0.0.1:8000/redoc.
+
+* Ìdàkejì àkọsílẹ̀ API yóò ṣ'afihan ìbéèrè èròjà/pàrámítà tuntun àti kókó èsì ti API:
+
+
+
+### Àtúnyẹ̀wò
+
+Ni akopọ, ìwọ yóò kéde ni **kete** àwọn iru èròjà/pàrámítà, kókó èsì API, abbl (i.e. àti bẹbẹ lọ), bi àwọn èròjà iṣẹ.
+
+O ṣe ìyẹn pẹ̀lú irúfẹ́ àmì ìtọ́kasí ìgbàlódé Python.
+
+O ò nílò láti kọ́ síńtáàsì tuntun, ìlànà tàbí ọ̀wọ́ kíláàsì kan pàtó, abbl (i.e. àti bẹbẹ lọ).
+
+Ìtọ́kasí **Python 3.8+**
+
+Fún àpẹẹrẹ, fún `int`:
+
+```Python
+item_id: int
+```
+
+tàbí fún àwòṣe `Item` tí ó nira díẹ̀ síi:
+
+```Python
+item: Item
+```
+
+... àti pẹ̀lú ìkéde kan ṣoṣo yẹn ìwọ yóò gbà:
+
+* Atilẹyin olootu, pẹ̀lú:
+ * Pipari.
+ * Àyẹ̀wò irúfẹ́ àmì ìtọ́kasí.
+* Ìfọwọ́sí àkójọf'áyẹ̀wò (i.e. data):
+ * Aṣiṣe alaifọwọyi/aládàáṣiṣẹ́ àti aṣiṣe ti ó hàn kedere nígbàtí àwọn àkójọf'áyẹ̀wò (i.e. data) kò wulo tabi tí kò fẹsẹ̀ múlẹ̀.
+ * Ìfọwọ́sí fún ohun elo JSON tí ó jìn gan-an.
+* Ìyípadà tí input àkójọf'áyẹ̀wò: tí ó wà láti nẹtiwọọki si àkójọf'áyẹ̀wò àti irúfẹ́ àmì ìtọ́kasí Python. Ó ń ka láti:
+ * JSON.
+ * èròjà ọ̀nà tí ò gbé gbà.
+ * èròjà ìbéèrè.
+ * Àwọn Kúkì
+ * Àwọn Àkọlé
+ * Àwọn Fọọmu
+ * Àwọn Fáìlì
+* Ìyípadà èsì àkójọf'áyẹ̀wò: yíyípadà láti àkójọf'áyẹ̀wò àti irúfẹ́ àmì ìtọ́kasí Python si nẹtiwọọki (gẹ́gẹ́ bí JSON):
+ * Yí irúfẹ́ àmì ìtọ́kasí padà (`str`, `int`, `float`, `bool`, `list`, abbl i.e. àti bèbè ló).
+ * Àwọn ohun èlò `datetime`.
+ * Àwọn ohun èlò `UUID`.
+ * Àwọn awoṣẹ́ ibi ìpamọ́ àkójọf'áyẹ̀wò.
+ * ...àti ọ̀pọ̀lọpọ̀ díẹ̀ síi.
+* Ìbáṣepọ̀ àkọsílẹ̀ API aládàáṣiṣẹ́, pẹ̀lú ìdàkejì àgbékalẹ̀-àwọn-olùmúlò (i.e user interfaces) méjì:
+ * Àgbékalẹ̀-olùmúlò Swagger.
+ * ReDoc.
+
+---
+
+Nisinsin yi, tí ó padà sí àpẹẹrẹ ti tẹ́lẹ̀, **FastAPI** yóò:
+
+* Fọwọ́ sí i pé `item_id` wà nínú ọ̀nà ìbéèrè HTTP fún `GET` àti `PUT`.
+* Fọwọ́ sí i pé `item_id` jẹ́ irúfẹ́ àmì ìtọ́kasí `int` fún ìbéèrè HTTP `GET` àti `PUT`.
+ * Tí kìí bá ṣe bẹ, oníbàárà yóò ríi àṣìṣe tí ó wúlò, kedere.
+* Ṣàyẹ̀wò bóyá ìbéèrè àṣàyàn pàrámítà kan wà tí orúkọ rẹ̀ ń jẹ́ `q` (gẹ́gẹ́ bíi `http://127.0.0.1:8000/items/foo?q=somequery`) fún ìbéèrè HTTP `GET`.
+ * Bí wọ́n ṣe kéde pàrámítà `q` pẹ̀lú `= None`, ó jẹ́ àṣàyàn (i.e optional).
+ * Láìsí `None` yóò nílò (gẹ́gẹ́ bí kókó èsì ìbéèrè HTTP ṣe wà pẹ̀lú `PUT`).
+* Fún àwọn ìbéèrè HTTP `PUT` sí `/items/{item_id}`, kà kókó èsì ìbéèrè HTTP gẹ́gẹ́ bí JSON:
+ * Ṣàyẹ̀wò pé ó ní àbùdá tí ó nílò èyí tíí ṣe `name` i.e. `orúkọ` tí ó yẹ kí ó jẹ́ `str`.
+ * Ṣàyẹ̀wò pé ó ní àbùdá tí ó nílò èyí tíí ṣe `price` i.e. `iye` tí ó gbọ́dọ̀ jẹ́ `float`.
+ * Ṣàyẹ̀wò pé ó ní àbùdá àṣàyàn `is_offer`, tí ó yẹ kí ó jẹ́ `bool`, tí ó bá wà níbẹ̀.
+ * Gbogbo èyí yóò tún ṣiṣẹ́ fún àwọn ohun èlò JSON tí ó jìn gidi gan-an.
+* Yìí padà láti àti sí JSON lai fi ọwọ́ yi.
+* Ṣe àkọsílẹ̀ ohun gbogbo pẹ̀lú OpenAPI, èyí tí yóò wà ní lílo nípaṣẹ̀:
+ * Àwọn ètò àkọsílẹ̀ ìbáṣepọ̀.
+ * Aládàáṣiṣẹ́ oníbárà èlètò tíí ṣẹ̀dá kóòdù, fún ọ̀pọ̀lọpọ̀ àwọn èdè.
+* Pese àkọsílẹ̀ òní ìbáṣepọ̀ ti àwọn àgbékalẹ̀ ayélujára méjì tààrà.
+
+---
+
+A ń ṣẹ̀ṣẹ̀ ń mú ẹyẹ bọ́ làpò ní, ṣùgbọ́n ó ti ni òye bí gbogbo rẹ̀ ṣe ń ṣiṣẹ́.
+
+Gbiyanju láti yí ìlà padà pẹ̀lú:
+
+```Python
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+...láti:
+
+```Python
+ ... "item_name": item.name ...
+```
+
+...ṣí:
+
+```Python
+ ... "item_price": item.price ...
+```
+
+.. kí o sì wo bí olóòtú rẹ yóò ṣe parí àwọn àbùdá náà fúnra rẹ̀, yóò sì mọ irúfẹ́ wọn:
+
+
+
+Fún àpẹẹrẹ pípé síi pẹ̀lú àwọn àbùdá mìíràn, wo Ìdánilẹ́kọ̀ọ́ - Ìtọ́sọ́nà Olùmúlò.
+
+**Itaniji gẹ́gẹ́ bí isọ'ye**: ìdánilẹ́kọ̀ọ́ - itọsọna olùmúlò pẹ̀lú:
+
+* Ìkéde àṣàyàn **pàrámítà** láti àwọn oriṣiriṣi ibòmíràn gẹ́gẹ́ bíi: àwọn **àkọlé èsì API**, **kúkì**, **ààyè fọọmu**, àti **fáìlì**.
+* Bíi ó ṣe lé ṣètò **àwọn ìdíwọ́ ìfọwọ́sí** bí `maximum_length` tàbí `regex`.
+* Ó lágbára púpọ̀ ó sì rọrùn láti lo ètò **Àfikún Ìgbẹ́kẹ̀lé Kóòdù**.
+* Ààbò àti ìfọwọ́sowọ́pọ̀, pẹ̀lú àtìlẹ́yìn fún **OAuth2** pẹ̀lú **àmì JWT** àti **HTTP Ipilẹ ìfọwọ́sowọ́pọ̀**.
+* Àwọn ìlànà ìlọsíwájú (ṣùgbọ́n tí ó rọrùn bákan náà) fún ìkéde **àwọn àwòṣe JSON tó jinlẹ̀** (ọpẹ́ pàtàkìsi sí Pydantic).
+* Iṣọpọ **GraphQL** pẹ̀lú Strawberry àti àwọn ohun èlò ìwé kóòdù afọwọkọ mìíràn tí kò yí padà.
+* Ọpọlọpọ àwọn àfikún àwọn ẹ̀yà (ọpẹ́ pàtàkìsi sí Starlette) bí:
+ * **WebSockets**
+ * àwọn ìdánwò tí ó rọrùn púpọ̀ lórí HTTPX àti `pytest`
+ * **CORS**
+ * **Cookie Sessions**
+ * ...àti síwájú síi.
+
+## Ìṣesí
+
+Àwọn àlá TechEmpower fi hàn pé **FastAPI** ń ṣiṣẹ́ lábẹ́ Uvicorn gẹ́gẹ́ bí ọ̀kan lára àwọn ìlànà Python tí ó yára jùlọ tí ó wà, ní ìsàlẹ̀ Starlette àti Uvicorn fúnra wọn (tí FastAPI ń lò fúnra rẹ̀). (*)
+
+Láti ní òye síi nípa rẹ̀, wo abala àwọn Àlá.
+
+## Àṣàyàn Àwọn Àfikún Ìgbẹ́kẹ̀lé Kóòdù
+
+Èyí tí Pydantic ń lò:
+
+* email_validator
- fún ifọwọsi ímeèlì.
+* pydantic-settings
- fún ètò ìsàkóso.
+* pydantic-extra-types
- fún àfikún oríṣi láti lọ pẹ̀lú Pydantic.
+
+Èyí tí Starlette ń lò:
+
+* httpx
- Nílò tí ó bá fẹ́ láti lọ `TestClient`.
+* jinja2
- Nílò tí ó bá fẹ́ láti lọ iṣeto awoṣe aiyipada.
+* python-multipart
- Nílò tí ó bá fẹ́ láti ṣe àtìlẹ́yìn fún "àyẹ̀wò" fọọmu, pẹ̀lú `request.form()`.
+* itsdangerous
- Nílò fún àtìlẹ́yìn `SessionMiddleware`.
+* pyyaml
- Nílò fún àtìlẹ́yìn Starlette's `SchemaGenerator` (ó ṣe ṣe kí ó má nílò rẹ̀ fún FastAPI).
+* ujson
- Nílò tí ó bá fẹ́ láti lọ `UJSONResponse`.
+
+Èyí tí FastAPI / Starlette ń lò:
+
+* uvicorn
- Fún olupin tí yóò sẹ́ àmúyẹ àti tí yóò ṣe ìpèsè fún iṣẹ́ rẹ tàbí ohun èlò rẹ.
+* orjson
- Nílò tí ó bá fẹ́ láti lọ `ORJSONResponse`.
+
+Ó lè fi gbogbo àwọn wọ̀nyí sórí ẹrọ pẹ̀lú `pip install "fastapi[all]"`.
+
+## Iwe-aṣẹ
+
+Iṣẹ́ yìí ni iwe-aṣẹ lábẹ́ àwọn òfin tí iwe-aṣẹ MIT.
diff --git a/docs/yo/mkdocs.yml b/docs/yo/mkdocs.yml
new file mode 100644
index 000000000..de18856f4
--- /dev/null
+++ b/docs/yo/mkdocs.yml
@@ -0,0 +1 @@
+INHERIT: ../en/mkdocs.yml
diff --git a/docs/zh/docs/advanced/generate-clients.md b/docs/zh/docs/advanced/generate-clients.md
new file mode 100644
index 000000000..e222e479c
--- /dev/null
+++ b/docs/zh/docs/advanced/generate-clients.md
@@ -0,0 +1,266 @@
+# 生成客户端
+
+因为 **FastAPI** 是基于OpenAPI规范的,自然您可以使用许多相匹配的工具,包括自动生成API文档 (由 Swagger UI 提供)。
+
+一个不太明显而又特别的优势是,你可以为你的API针对不同的**编程语言**来**生成客户端**(有时候被叫做 **SDKs** )。
+
+## OpenAPI 客户端生成
+
+有许多工具可以从**OpenAPI**生成客户端。
+
+一个常见的工具是 OpenAPI Generator。
+
+如果您正在开发**前端**,一个非常有趣的替代方案是 openapi-typescript-codegen。
+
+## 生成一个 TypeScript 前端客户端
+
+让我们从一个简单的 FastAPI 应用开始:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="7-9 12-13 16-17 21"
+ {!> ../../../docs_src/generate_clients/tutorial001_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9-11 14-15 18 19 23"
+ {!> ../../../docs_src/generate_clients/tutorial001.py!}
+ ```
+
+请注意,*路径操作* 定义了他们所用于请求数据和回应数据的模型,所使用的模型是`Item` 和 `ResponseMessage`。
+
+### API 文档
+
+如果您访问API文档,您将看到它具有在请求中发送和在响应中接收数据的**模式(schemas)**:
+
+
+
+您可以看到这些模式,因为它们是用程序中的模型声明的。
+
+那些信息可以在应用的 **OpenAPI模式** 被找到,然后显示在API文档中(通过Swagger UI)。
+
+OpenAPI中所包含的模型里有相同的信息可以用于 **生成客户端代码**。
+
+### 生成一个TypeScript 客户端
+
+现在我们有了带有模型的应用,我们可以为前端生成客户端代码。
+
+#### 安装 `openapi-typescript-codegen`
+
+您可以使用以下工具在前端代码中安装 `openapi-typescript-codegen`:
+
+
+
+```console
+$ npm install openapi-typescript-codegen --save-dev
+
+---> 100%
+```
+
+
+
+#### 生成客户端代码
+
+要生成客户端代码,您可以使用现在将要安装的命令行应用程序 `openapi`。
+
+因为它安装在本地项目中,所以您可能无法直接使用此命令,但您可以将其放在 `package.json` 文件中。
+
+它可能看起来是这样的:
+
+```JSON hl_lines="7"
+{
+ "name": "frontend-app",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios"
+ },
+ "author": "",
+ "license": "",
+ "devDependencies": {
+ "openapi-typescript-codegen": "^0.20.1",
+ "typescript": "^4.6.2"
+ }
+}
+```
+
+在这里添加 NPM `generate-client` 脚本后,您可以使用以下命令运行它:
+
+
+
+```console
+$ npm run generate-client
+
+frontend-app@1.0.0 generate-client /home/user/code/frontend-app
+> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios
+```
+
+
+
+此命令将在 `./src/client` 中生成代码,并将在其内部使用 `axios`(前端HTTP库)。
+
+### 尝试客户端代码
+
+现在您可以导入并使用客户端代码,它可能看起来像这样,请注意,您可以为这些方法使用自动补全:
+
+
+
+您还将自动补全要发送的数据:
+
+
+
+!!! tip
+ 请注意, `name` 和 `price` 的自动补全,是通过其在`Item`模型(FastAPI)中的定义实现的。
+
+如果发送的数据字段不符,你也会看到编辑器的错误提示:
+
+
+
+响应(response)对象也拥有自动补全:
+
+
+
+## 带有标签的 FastAPI 应用
+
+在许多情况下,你的FastAPI应用程序会更复杂,你可能会使用标签来分隔不同组的*路径操作(path operations)*。
+
+例如,您可以有一个用 `items` 的部分和另一个用于 `users` 的部分,它们可以用标签来分隔:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="21 26 34"
+ {!> ../../../docs_src/generate_clients/tutorial002_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="23 28 36"
+ {!> ../../../docs_src/generate_clients/tutorial002.py!}
+ ```
+
+### 生成带有标签的 TypeScript 客户端
+
+如果您使用标签为FastAPI应用生成客户端,它通常也会根据标签分割客户端代码。
+
+通过这种方式,您将能够为客户端代码进行正确地排序和分组:
+
+
+
+在这个案例中,您有:
+
+* `ItemsService`
+* `UsersService`
+
+### 客户端方法名称
+
+现在生成的方法名像 `createItemItemsPost` 看起来不太简洁:
+
+```TypeScript
+ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
+```
+
+...这是因为客户端生成器为每个 *路径操作* 使用OpenAPI的内部 **操作 ID(operation ID)**。
+
+OpenAPI要求每个操作 ID 在所有 *路径操作* 中都是唯一的,因此 FastAPI 使用**函数名**、**路径**和**HTTP方法/操作**来生成此操作ID,因为这样可以确保这些操作 ID 是唯一的。
+
+但接下来我会告诉你如何改进。 🤓
+
+## 自定义操作ID和更好的方法名
+
+您可以**修改**这些操作ID的**生成**方式,以使其更简洁,并在客户端中具有**更简洁的方法名称**。
+
+在这种情况下,您必须确保每个操作ID在其他方面是**唯一**的。
+
+例如,您可以确保每个*路径操作*都有一个标签,然后根据**标签**和*路径操作***名称**(函数名)来生成操作ID。
+
+### 自定义生成唯一ID函数
+
+FastAPI为每个*路径操作*使用一个**唯一ID**,它用于**操作ID**,也用于任何所需自定义模型的名称,用于请求或响应。
+
+你可以自定义该函数。它接受一个 `APIRoute` 对象作为输入,并输出一个字符串。
+
+例如,以下是一个示例,它使用第一个标签(你可能只有一个标签)和*路径操作*名称(函数名)。
+
+然后,你可以将这个自定义函数作为 `generate_unique_id_function` 参数传递给 **FastAPI**:
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="6-7 10"
+ {!> ../../../docs_src/generate_clients/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="8-9 12"
+ {!> ../../../docs_src/generate_clients/tutorial003.py!}
+ ```
+
+### 使用自定义操作ID生成TypeScript客户端
+
+现在,如果你再次生成客户端,你会发现它具有改善的方法名称:
+
+
+
+正如你所见,现在方法名称中只包含标签和函数名,不再包含URL路径和HTTP操作的信息。
+
+### 预处理用于客户端生成器的OpenAPI规范
+
+生成的代码仍然存在一些**重复的信息**。
+
+我们已经知道该方法与 **items** 相关,因为它在 `ItemsService` 中(从标签中获取),但方法名中仍然有标签名作为前缀。😕
+
+一般情况下对于OpenAPI,我们可能仍然希望保留它,因为这将确保操作ID是**唯一的**。
+
+但对于生成的客户端,我们可以在生成客户端之前**修改** OpenAPI 操作ID,以使方法名称更加美观和**简洁**。
+
+我们可以将 OpenAPI JSON 下载到一个名为`openapi.json`的文件中,然后使用以下脚本**删除此前缀的标签**:
+
+```Python
+{!../../../docs_src/generate_clients/tutorial004.py!}
+```
+
+通过这样做,操作ID将从类似于 `items-get_items` 的名称重命名为 `get_items` ,这样客户端生成器就可以生成更简洁的方法名称。
+
+### 使用预处理的OpenAPI生成TypeScript客户端
+
+现在,由于最终结果保存在文件openapi.json中,你可以修改 package.json 文件以使用此本地文件,例如:
+
+```JSON hl_lines="7"
+{
+ "name": "frontend-app",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios"
+ },
+ "author": "",
+ "license": "",
+ "devDependencies": {
+ "openapi-typescript-codegen": "^0.20.1",
+ "typescript": "^4.6.2"
+ }
+}
+```
+
+生成新的客户端之后,你现在将拥有**清晰的方法名称**,具备**自动补全**、**错误提示**等功能:
+
+
+
+## 优点
+
+当使用自动生成的客户端时,你将获得以下的自动补全功能:
+
+* 方法。
+* 请求体中的数据、查询参数等。
+* 响应数据。
+
+你还将获得针对所有内容的错误提示。
+
+每当你更新后端代码并**重新生成**前端代码时,新的*路径操作*将作为方法可用,旧的方法将被删除,并且其他任何更改将反映在生成的代码中。 🤓
+
+这也意味着如果有任何更改,它将自动**反映**在客户端代码中。如果你**构建**客户端,在使用的数据上存在**不匹配**时,它将报错。
+
+因此,你将在开发周期的早期**检测到许多错误**,而不必等待错误在生产环境中向最终用户展示,然后尝试调试问题所在。 ✨
diff --git a/docs/zh/docs/advanced/settings.md b/docs/zh/docs/advanced/settings.md
index 597e99a77..76070fb7f 100644
--- a/docs/zh/docs/advanced/settings.md
+++ b/docs/zh/docs/advanced/settings.md
@@ -223,13 +223,13 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app
{!> ../../../docs_src/settings/app02_an_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="6 12-13"
{!> ../../../docs_src/settings/app02_an/main.py!}
```
-=== "Python 3.6+ 非注解版本"
+=== "Python 3.8+ 非注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
@@ -239,7 +239,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app
```
!!! tip
- 我们稍后会讨论 `@lru_cache()`。
+ 我们稍后会讨论 `@lru_cache`。
目前,您可以将 `get_settings()` 视为普通函数。
@@ -251,13 +251,13 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app
{!> ../../../docs_src/settings/app02_an_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="17 19-21"
{!> ../../../docs_src/settings/app02_an/main.py!}
```
-=== "Python 3.6+ 非注解版本"
+=== "Python 3.8+ 非注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
@@ -289,7 +289,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app
但是,dotenv 文件实际上不一定要具有确切的文件名。
-Pydantic 支持使用外部库从这些类型的文件中读取。您可以在Pydantic 设置: Dotenv (.env) 支持中阅读更多相关信息。
+Pydantic 支持使用外部库从这些类型的文件中读取。您可以在Pydantic 设置: Dotenv (.env) 支持中阅读更多相关信息。
!!! tip
要使其工作,您需要执行 `pip install python-dotenv`。
@@ -337,7 +337,7 @@ def get_settings():
我们将为每个请求创建该对象,并且将在每个请求中读取 `.env` 文件。 ⚠️
-但是,由于我们在顶部使用了 `@lru_cache()` 装饰器,因此只有在第一次调用它时,才会创建 `Settings` 对象一次。 ✔️
+但是,由于我们在顶部使用了 `@lru_cache` 装饰器,因此只有在第一次调用它时,才会创建 `Settings` 对象一次。 ✔️
=== "Python 3.9+"
@@ -345,13 +345,13 @@ def get_settings():
{!> ../../../docs_src/settings/app03_an_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="1 11"
{!> ../../../docs_src/settings/app03_an/main.py!}
```
-=== "Python 3.6+ 非注解版本"
+=== "Python 3.8+ 非注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
@@ -364,13 +364,13 @@ def get_settings():
#### `lru_cache` 技术细节
-`@lru_cache()` 修改了它所装饰的函数,以返回第一次返回的相同值,而不是再次计算它,每次都执行函数的代码。
+`@lru_cache` 修改了它所装饰的函数,以返回第一次返回的相同值,而不是再次计算它,每次都执行函数的代码。
因此,下面的函数将对每个参数组合执行一次。然后,每个参数组合返回的值将在使用完全相同的参数组合调用函数时再次使用。
例如,如果您有一个函数:
```Python
-@lru_cache()
+@lru_cache
def say_hi(name: str, salutation: str = "Ms."):
return f"Hello {salutation} {name}"
```
@@ -422,7 +422,7 @@ participant execute as Execute function
这样,它的行为几乎就像是一个全局变量。但是由于它使用了依赖项函数,因此我们可以轻松地进行测试时的覆盖。
-`@lru_cache()` 是 `functools` 的一部分,它是 Python 标准库的一部分,您可以在Python 文档中了解有关 `@lru_cache()` 的更多信息。
+`@lru_cache` 是 `functools` 的一部分,它是 Python 标准库的一部分,您可以在Python 文档中了解有关 `@lru_cache` 的更多信息。
## 小结
@@ -430,4 +430,4 @@ participant execute as Execute function
* 通过使用依赖项,您可以简化测试。
* 您可以使用 `.env` 文件。
-* 使用 `@lru_cache()` 可以避免为每个请求重复读取 dotenv 文件,同时允许您在测试时进行覆盖。
+* 使用 `@lru_cache` 可以避免为每个请求重复读取 dotenv 文件,同时允许您在测试时进行覆盖。
diff --git a/docs/zh/docs/advanced/websockets.md b/docs/zh/docs/advanced/websockets.md
index a723487fd..a5cbdd965 100644
--- a/docs/zh/docs/advanced/websockets.md
+++ b/docs/zh/docs/advanced/websockets.md
@@ -118,7 +118,7 @@ $ uvicorn main:app --reload
{!> ../../../docs_src/websockets/tutorial002_an_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="69-70 83"
{!> ../../../docs_src/websockets/tutorial002_an.py!}
@@ -133,7 +133,7 @@ $ uvicorn main:app --reload
{!> ../../../docs_src/websockets/tutorial002_py310.py!}
```
-=== "Python 3.6+ 非带注解版本"
+=== "Python 3.8+ 非带注解版本"
!!! tip
如果可能,请尽量使用 `Annotated` 版本。
@@ -181,7 +181,7 @@ $ uvicorn main:app --reload
{!> ../../../docs_src/websockets/tutorial003_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="81-83"
{!> ../../../docs_src/websockets/tutorial003.py!}
diff --git a/docs/zh/docs/async.md b/docs/zh/docs/async.md
new file mode 100644
index 000000000..59eebd049
--- /dev/null
+++ b/docs/zh/docs/async.md
@@ -0,0 +1,430 @@
+# 并发 async / await
+
+有关路径操作函数的 `async def` 语法以及异步代码、并发和并行的一些背景知识。
+
+## 赶时间吗?
+
+TL;DR:
+
+如果你正在使用第三方库,它们会告诉你使用 `await` 关键字来调用它们,就像这样:
+
+```Python
+results = await some_library()
+```
+
+然后,通过 `async def` 声明你的 *路径操作函数*:
+
+```Python hl_lines="2"
+@app.get('/')
+async def read_results():
+ results = await some_library()
+ return results
+```
+
+!!! note
+ 你只能在被 `async def` 创建的函数内使用 `await`
+
+---
+
+如果你正在使用一个第三方库和某些组件(比如:数据库、API、文件系统...)进行通信,第三方库又不支持使用 `await` (目前大多数数据库三方库都是这样),这种情况你可以像平常那样使用 `def` 声明一个路径操作函数,就像这样:
+
+```Python hl_lines="2"
+@app.get('/')
+def results():
+ results = some_library()
+ return results
+```
+
+---
+
+如果你的应用程序不需要与其他任何东西通信而等待其响应,请使用 `async def`。
+
+---
+
+如果你不清楚,使用 `def` 就好.
+
+---
+
+**注意**:你可以根据需要在路径操作函数中混合使用 `def` 和 `async def`,并使用最适合你的方式去定义每个函数。FastAPI 将为他们做正确的事情。
+
+无论如何,在上述任何情况下,FastAPI 仍将异步工作,速度也非常快。
+
+但是,通过遵循上述步骤,它将能够进行一些性能优化。
+
+## 技术细节
+
+Python 的现代版本支持通过一种叫**"协程"**——使用 `async` 和 `await` 语法的东西来写**”异步代码“**。
+
+让我们在下面的部分中逐一介绍:
+
+* **异步代码**
+* **`async` 和 `await`**
+* **协程**
+
+## 异步代码
+
+异步代码仅仅意味着编程语言 💬 有办法告诉计算机/程序 🤖 在代码中的某个点,它 🤖 将不得不等待在某些地方完成一些事情。让我们假设一些事情被称为 "慢文件"📝.
+
+所以,在等待"慢文件"📝完成的这段时间,计算机可以做一些其他工作。
+
+然后计算机/程序 🤖 每次有机会都会回来,因为它又在等待,或者它 🤖 完成了当前所有的工作。而且它 🤖 将查看它等待的所有任务中是否有已经完成的,做它必须做的任何事情。
+
+接下来,它 🤖 完成第一个任务(比如是我们的"慢文件"📝) 并继续与之相关的一切。
+
+这个"等待其他事情"通常指的是一些相对较慢(与处理器和 RAM 存储器的速度相比)的 I/O 操作,比如说:
+
+* 通过网络发送来自客户端的数据
+* 客户端接收来自网络中的数据
+* 磁盘中要由系统读取并提供给程序的文件的内容
+* 程序提供给系统的要写入磁盘的内容
+* 一个 API 的远程调用
+* 一个数据库操作,直到完成
+* 一个数据库查询,直到返回结果
+* 等等.
+
+这个执行的时间大多是在等待 I/O 操作,因此它们被叫做 "I/O 密集型" 操作。
+
+它被称为"异步"的原因是因为计算机/程序不必与慢任务"同步",去等待任务完成的确切时刻,而在此期间不做任何事情直到能够获取任务结果才继续工作。
+
+相反,作为一个"异步"系统,一旦完成,任务就可以排队等待一段时间(几微秒),等待计算机程序完成它要做的任何事情,然后回来获取结果并继续处理它们。
+
+对于"同步"(与"异步"相反),他们通常也使用"顺序"一词,因为计算机程序在切换到另一个任务之前是按顺序执行所有步骤,即使这些步骤涉及到等待。
+
+### 并发与汉堡
+
+上述异步代码的思想有时也被称为“并发”,它不同于“并行”。
+
+并发和并行都与“不同的事情或多或少同时发生”有关。
+
+但是并发和并行之间的细节是完全不同的。
+
+要了解差异,请想象以下关于汉堡的故事:
+
+### 并发汉堡
+
+你和你的恋人一起去快餐店,你排队在后面,收银员从你前面的人接单。😍
+
+
+
+然后轮到你了,你为你的恋人和你选了两个非常豪华的汉堡。🍔🍔
+
+
+
+收银员对厨房里的厨师说了一些话,让他们知道他们必须为你准备汉堡(尽管他们目前正在为之前的顾客准备汉堡)。
+
+
+
+你付钱了。 💸
+
+收银员给你轮到的号码。
+
+
+
+当你在等待的时候,你和你的恋人一起去挑选一张桌子,然后你们坐下来聊了很长时间(因为汉堡很豪华,需要一些时间来准备)。
+
+当你和你的恋人坐在桌子旁,等待汉堡的时候,你可以用这段时间来欣赏你的恋人是多么的棒、可爱和聪明✨😍✨。
+
+
+
+在等待中和你的恋人交谈时,你会不时地查看柜台上显示的号码,看看是否已经轮到你了。
+
+然后在某个时刻,终于轮到你了。你去柜台拿汉堡然后回到桌子上。
+
+
+
+你们享用了汉堡,整个过程都很开心。✨
+
+
+
+!!! info
+ 漂亮的插画来自 Ketrina Thompson. 🎨
+
+---
+
+在那个故事里,假设你是计算机程序 🤖 。
+
+当你在排队时,你只是闲着😴, 轮到你前不做任何事情(仅排队)。但排队很快,因为收银员只接订单(不准备订单),所以这一切都还好。
+
+然后,当轮到你时,需要你做一些实际性的工作,比如查看菜单,决定你想要什么,让你的恋人选择,支付,检查你是否提供了正确的账单或卡,检查你的收费是否正确,检查订单是否有正确的项目,等等。
+
+此时,即使你仍然没有汉堡,你和收银员的工作也"暂停"了⏸, 因为你必须等待一段时间 🕙 让你的汉堡做好。
+
+但是,当你离开柜台并坐在桌子旁,在轮到你的号码前的这段时间,你可以将焦点切换到 🔀 你的恋人上,并做一些"工作"⏯ 🤓。你可以做一些非常"有成效"的事情,比如和你的恋人调情😍.
+
+之后,收银员 💁 把号码显示在显示屏上,并说到 "汉堡做好了",而当显示的号码是你的号码时,你不会立刻疯狂地跳起来。因为你知道没有人会偷你的汉堡,因为你有你的号码,而其他人又有他们自己的号码。
+
+所以你要等待你的恋人完成故事(完成当前的工作⏯ /正在做的事🤓), 轻轻微笑,说你要吃汉堡⏸.
+
+然后你去柜台🔀, 到现在初始任务已经完成⏯, 拿起汉堡,说声谢谢,然后把它们送到桌上。这就完成了与计数器交互的步骤/任务⏹. 这反过来又产生了一项新任务,即"吃汉堡"🔀 ⏯, 上一个"拿汉堡"的任务已经结束了⏹.
+
+### 并行汉堡
+
+现在让我们假设不是"并发汉堡",而是"并行汉堡"。
+
+你和你的恋人一起去吃并行快餐。
+
+你站在队伍中,同时是厨师的几个收银员(比方说8个)从前面的人那里接单。
+
+你之前的每个人都在等待他们的汉堡准备好后才离开柜台,因为8名收银员都会在下一份订单前马上准备好汉堡。
+
+
+
+然后,终于轮到你了,你为你的恋人和你订购了两个非常精美的汉堡。
+
+你付钱了 💸。
+
+
+
+收银员去厨房。
+
+你站在柜台前 🕙等待着,这样就不会有人在你之前抢走你的汉堡,因为没有轮流的号码。
+
+
+
+当你和你的恋人忙于不让任何人出现在你面前,并且在他们到来的时候拿走你的汉堡时,你无法关注到你的恋人。😞
+
+这是"同步"的工作,你被迫与服务员/厨师 👨🍳"同步"。你在此必须等待 🕙 ,在收银员/厨师 👨🍳 完成汉堡并将它们交给你的确切时间到达之前一直等待,否则其他人可能会拿走它们。
+
+
+
+你经过长时间的等待 🕙 ,收银员/厨师 👨🍳终于带着汉堡回到了柜台。
+
+
+
+你拿着汉堡,和你的情人一起上桌。
+
+你们仅仅是吃了它们,就结束了。⏹
+
+
+
+没有太多的交谈或调情,因为大部分时间 🕙 都在柜台前等待😞。
+
+!!! info
+ 漂亮的插画来自 Ketrina Thompson. 🎨
+
+---
+
+在这个并行汉堡的场景中,你是一个计算机程序 🤖 且有两个处理器(你和你的恋人),都在等待 🕙 ,并投入他们的注意力 ⏯ 在柜台上等待了很长一段时间。
+
+这家快餐店有 8 个处理器(收银员/厨师)。而并发汉堡店可能只有 2 个(一个收银员和一个厨师)。
+
+但最终的体验仍然不是最好的。😞
+
+---
+
+这将是与汉堡的类似故事。🍔
+
+一种更"贴近生活"的例子,想象一家银行。
+
+直到最近,大多数银行都有多个出纳员 👨💼👨💼👨💼👨💼 还有一条长长排队队伍🕙🕙🕙🕙🕙🕙🕙🕙。
+
+所有收银员都是一个接一个的在客户面前做完所有的工作👨💼⏯.
+
+你必须经过 🕙 较长时间排队,否则你就没机会了。
+
+你可不会想带你的恋人 😍 和你一起去银行办事🏦.
+
+### 汉堡结论
+
+在"你与恋人一起吃汉堡"的这个场景中,因为有很多人在等待🕙, 使用并发系统更有意义⏸🔀⏯.
+
+大多数 Web 应用都是这样的。
+
+你的服务器正在等待很多很多用户通过他们不太好的网络发送来的请求。
+
+然后再次等待 🕙 响应回来。
+
+这个"等待" 🕙 是以微秒为单位测量的,但总的来说,最后还是等待很久。
+
+这就是为什么使用异步对于 Web API 很有意义的原因 ⏸🔀⏯。
+
+这种异步机制正是 NodeJS 受到欢迎的原因(尽管 NodeJS 不是并行的),以及 Go 作为编程语言的优势所在。
+
+这与 **FastAPI** 的性能水平相同。
+
+您可以同时拥有并行性和异步性,您可以获得比大多数经过测试的 NodeJS 框架更高的性能,并且与 Go 不相上下, Go 是一种更接近于 C 的编译语言(全部归功于 Starlette)。
+
+### 并发比并行好吗?
+
+不!这不是故事的本意。
+
+并发不同于并行。而是在需要大量等待的特定场景下效果更好。因此,在 Web 应用程序开发中,它通常比并行要好得多,但这并不意味着全部。
+
+因此,为了平衡这一点,想象一下下面的短篇故事:
+
+> 你必须打扫一个又大又脏的房子。
+
+*是的,这就是完整的故事。*
+
+---
+
+在任何地方, 都不需要等待 🕙 ,只需要在房子的多个地方做着很多工作。
+
+你可以像汉堡的例子那样轮流执行,先是客厅,然后是厨房,但因为你不需要等待 🕙 ,对于任何事情都是清洁,清洁,还是清洁,轮流不会影响任何事情。
+
+无论是否轮流执行(并发),都需要相同的时间来完成,而你也会完成相同的工作量。
+
+但在这种情况下,如果你能带上 8 名前收银员/厨师,现在是清洁工一起清扫,他们中的每一个人(加上你)都能占据房子的一个区域来清扫,你就可以在额外的帮助下并行的更快地完成所有工作。
+
+在这个场景中,每个清洁工(包括您)都将是一个处理器,完成这个工作的一部分。
+
+由于大多数执行时间是由实际工作(而不是等待)占用的,并且计算机中的工作是由 CPU 完成的,所以他们称这些问题为"CPU 密集型"。
+
+---
+
+CPU 密集型操作的常见示例是需要复杂的数学处理。
+
+例如:
+
+* **音频**或**图像**处理;
+* **计算机视觉**: 一幅图像由数百万像素组成,每个像素有3种颜色值,处理通常需要同时对这些像素进行计算;
+* **机器学习**: 它通常需要大量的"矩阵"和"向量"乘法。想象一个包含数字的巨大电子表格,并同时将所有数字相乘;
+* **深度学习**: 这是机器学习的一个子领域,同样适用。只是没有一个数字的电子表格可以相乘,而是一个庞大的数字集合,在很多情况下,你需要使用一个特殊的处理器来构建和使用这些模型。
+
+### 并发 + 并行: Web + 机器学习
+
+使用 **FastAPI**,您可以利用 Web 开发中常见的并发机制的优势(NodeJS 的主要吸引力)。
+
+并且,您也可以利用并行和多进程(让多个进程并行运行)的优点来处理与机器学习系统中类似的 **CPU 密集型** 工作。
+
+这一点,再加上 Python 是**数据科学**、机器学习(尤其是深度学习)的主要语言这一简单事实,使得 **FastAPI** 与数据科学/机器学习 Web API 和应用程序(以及其他许多应用程序)非常匹配。
+
+了解如何在生产环境中实现这种并行性,可查看此文 [Deployment](deployment/index.md){.internal-link target=_blank}。
+
+## `async` 和 `await`
+
+现代版本的 Python 有一种非常直观的方式来定义异步代码。这使它看起来就像正常的"顺序"代码,并在适当的时候"等待"。
+
+当有一个操作需要等待才能给出结果,且支持这个新的 Python 特性时,您可以编写如下代码:
+
+```Python
+burgers = await get_burgers(2)
+```
+
+这里的关键是 `await`。它告诉 Python 它必须等待 ⏸ `get_burgers(2)` 完成它的工作 🕙 ,然后将结果存储在 `burgers` 中。这样,Python 就会知道此时它可以去做其他事情 🔀 ⏯ (比如接收另一个请求)。
+
+要使 `await` 工作,它必须位于支持这种异步机制的函数内。因此,只需使用 `async def` 声明它:
+
+```Python hl_lines="1"
+async def get_burgers(number: int):
+ # Do some asynchronous stuff to create the burgers
+ return burgers
+```
+
+...而不是 `def`:
+
+```Python hl_lines="2"
+# This is not asynchronous
+def get_sequential_burgers(number: int):
+ # Do some sequential stuff to create the burgers
+ return burgers
+```
+
+使用 `async def`,Python 就知道在该函数中,它将遇上 `await`,并且它可以"暂停" ⏸ 执行该函数,直至执行其他操作 🔀 后回来。
+
+当你想调用一个 `async def` 函数时,你必须"等待"它。因此,这不会起作用:
+
+```Python
+# This won't work, because get_burgers was defined with: async def
+burgers = get_burgers(2)
+```
+
+---
+
+因此,如果您使用的库告诉您可以使用 `await` 调用它,则需要使用 `async def` 创建路径操作函数 ,如:
+
+```Python hl_lines="2-3"
+@app.get('/burgers')
+async def read_burgers():
+ burgers = await get_burgers(2)
+ return burgers
+```
+
+### 更多技术细节
+
+您可能已经注意到,`await` 只能在 `async def` 定义的函数内部使用。
+
+但与此同时,必须"等待"通过 `async def` 定义的函数。因此,带 `async def` 的函数也只能在 `async def` 定义的函数内部调用。
+
+那么,这关于先有鸡还是先有蛋的问题,如何调用第一个 `async` 函数?
+
+如果您使用 **FastAPI**,你不必担心这一点,因为"第一个"函数将是你的路径操作函数,FastAPI 将知道如何做正确的事情。
+
+但如果您想在没有 FastAPI 的情况下使用 `async` / `await`,则可以这样做。
+
+### 编写自己的异步代码
+
+Starlette (和 **FastAPI**) 是基于 AnyIO 实现的,这使得它们可以兼容 Python 的标准库 asyncio 和 Trio。
+
+特别是,你可以直接使用 AnyIO 来处理高级的并发用例,这些用例需要在自己的代码中使用更高级的模式。
+
+即使您没有使用 **FastAPI**,您也可以使用 AnyIO 编写自己的异步程序,使其拥有较高的兼容性并获得一些好处(例如, 结构化并发)。
+
+### 其他形式的异步代码
+
+这种使用 `async` 和 `await` 的风格在语言中相对较新。
+
+但它使处理异步代码变得容易很多。
+
+这种相同的语法(或几乎相同)最近也包含在现代版本的 JavaScript 中(在浏览器和 NodeJS 中)。
+
+但在此之前,处理异步代码非常复杂和困难。
+
+在以前版本的 Python,你可以使用多线程或者 Gevent。但代码的理解、调试和思考都要复杂许多。
+
+在以前版本的 NodeJS / 浏览器 JavaScript 中,你会使用"回调",因此也可能导致回调地狱。
+
+## 协程
+
+**协程**只是 `async def` 函数返回的一个非常奇特的东西的称呼。Python 知道它有点像一个函数,它可以启动,也会在某个时刻结束,而且它可能会在内部暂停 ⏸ ,只要内部有一个 `await`。
+
+通过使用 `async` 和 `await` 的异步代码的所有功能大多数被概括为"协程"。它可以与 Go 的主要关键特性 "Goroutines" 相媲美。
+
+## 结论
+
+让我们再来回顾下上文所说的:
+
+> Python 的现代版本可以通过使用 `async` 和 `await` 语法创建**协程**,并用于支持**异步代码**。
+
+现在应该能明白其含义了。✨
+
+所有这些使得 FastAPI(通过 Starlette)如此强大,也是它拥有如此令人印象深刻的性能的原因。
+
+## 非常技术性的细节
+
+!!! warning
+ 你可以跳过这里。
+
+ 这些都是 FastAPI 如何在内部工作的技术细节。
+
+ 如果您有相当多的技术知识(协程、线程、阻塞等),并且对 FastAPI 如何处理 `async def` 与常规 `def` 感到好奇,请继续。
+
+### 路径操作函数
+
+当你使用 `def` 而不是 `async def` 来声明一个*路径操作函数*时,它运行在外部的线程池中并等待其结果,而不是直接调用(因为它会阻塞服务器)。
+
+如果您使用过另一个不以上述方式工作的异步框架,并且您习惯于用普通的 `def` 定义普通的仅计算路径操作函数,以获得微小的性能增益(大约100纳秒),请注意,在 FastAPI 中,效果将完全相反。在这些情况下,最好使用 `async def`,除非路径操作函数内使用执行阻塞 I/O 的代码。
+
+在这两种情况下,与您之前的框架相比,**FastAPI** 可能[仍然很快](/#performance){.internal-link target=_blank}。
+
+### 依赖
+
+这同样适用于[依赖](./tutorial/dependencies/index.md){.internal-link target=_blank}。如果一个依赖是标准的 `def` 函数而不是 `async def`,它将被运行在外部线程池中。
+
+### 子依赖
+
+你可以拥有多个相互依赖的依赖以及[子依赖](./tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (作为函数的参数),它们中的一些可能是通过 `async def` 声明,也可能是通过 `def` 声明。它们仍然可以正常工作,这些通过 `def` 声明的函数将会在外部线程中调用(来自线程池),而不是"被等待"。
+
+### 其他函数
+
+您可直接调用通过 `def` 或 `async def` 创建的任何其他函数,FastAPI 不会影响您调用它们的方式。
+
+这与 FastAPI 为您调用*路径操作函数*和依赖项的逻辑相反。
+
+如果你的函数是通过 `def` 声明的,它将被直接调用(在代码中编写的地方),而不会在线程池中,如果这个函数通过 `async def` 声明,当在代码中调用时,你就应该使用 `await` 等待函数的结果。
+
+---
+
+再次提醒,这些是非常技术性的细节,如果你来搜索它可能对你有用。
+
+否则,您最好应该遵守的指导原则赶时间吗?.
diff --git a/docs/zh/docs/deployment/versions.md b/docs/zh/docs/deployment/versions.md
new file mode 100644
index 000000000..75b870139
--- /dev/null
+++ b/docs/zh/docs/deployment/versions.md
@@ -0,0 +1,87 @@
+# 关于 FastAPI 版本
+
+**FastAPI** 已在许多应用程序和系统的生产环境中使用。 并且测试覆盖率保持在100%。 但其开发进度仍在快速推进。
+
+经常添加新功能,定期修复错误,并且代码仍在持续改进。
+
+这就是为什么当前版本仍然是`0.x.x`,这反映出每个版本都可能有Breaking changes。 这遵循语义版本控制的约定。
+
+你现在就可以使用 **FastAPI** 创建生产环境应用程序(你可能已经这样做了一段时间),你只需确保使用的版本可以与其余代码正确配合即可。
+
+## 固定你的 `fastapi` 版本
+
+你应该做的第一件事是将你正在使用的 **FastAPI** 版本“固定”到你知道适用于你的应用程序的特定最新版本。
+
+例如,假设你在应用程序中使用版本`0.45.0`。
+
+如果你使用`requirements.txt`文件,你可以使用以下命令指定版本:
+
+````txt
+fastapi==0.45.0
+````
+
+这意味着你将使用版本`0.45.0`。
+
+或者你也可以将其固定为:
+
+````txt
+fastapi>=0.45.0,<0.46.0
+````
+
+这意味着你将使用`0.45.0`或更高版本,但低于`0.46.0`,例如,版本`0.45.2`仍会被接受。
+
+如果你使用任何其他工具来管理你的安装,例如 Poetry、Pipenv 或其他工具,它们都有一种定义包的特定版本的方法。
+
+## 可用版本
+
+你可以在[发行说明](../release-notes.md){.internal-link target=_blank}中查看可用版本(例如查看当前最新版本)。
+
+## 关于版本
+
+遵循语义版本控制约定,任何低于`1.0.0`的版本都可能会添加 breaking changes。
+
+FastAPI 还遵循这样的约定:任何`PATCH`版本更改都是为了bug修复和non-breaking changes。
+
+!!! tip
+ "PATCH"是最后一个数字,例如,在`0.2.3`中,PATCH版本是`3`。
+
+因此,你应该能够固定到如下版本:
+
+```txt
+fastapi>=0.45.0,<0.46.0
+```
+
+"MINOR"版本中会添加breaking changes和新功能。
+
+!!! tip
+ "MINOR"是中间的数字,例如,在`0.2.3`中,MINOR版本是`2`。
+
+## 升级FastAPI版本
+
+你应该为你的应用程序添加测试。
+
+使用 **FastAPI** 编写测试非常简单(感谢 Starlette),请参考文档:[测试](../tutorial/testing.md){.internal-link target=_blank}
+
+添加测试后,你可以将 **FastAPI** 版本升级到更新版本,并通过运行测试来确保所有代码都能正常工作。
+
+如果一切正常,或者在进行必要的更改之后,并且所有测试都通过了,那么你可以将`fastapi`固定到新的版本。
+
+## 关于Starlette
+
+你不应该固定`starlette`的版本。
+
+不同版本的 **FastAPI** 将使用特定的较新版本的 Starlette。
+
+因此,**FastAPI** 自己可以使用正确的 Starlette 版本。
+
+## 关于 Pydantic
+
+Pydantic 包含针对 **FastAPI** 的测试及其自己的测试,因此 Pydantic 的新版本(`1.0.0`以上)始终与 FastAPI 兼容。
+
+你可以将 Pydantic 固定到适合你的`1.0.0`以上和`2.0.0`以下的任何版本。
+
+例如:
+
+````txt
+pydantic>=1.2.0,<2.0.0
+````
diff --git a/docs/zh/docs/help-fastapi.md b/docs/zh/docs/help-fastapi.md
index 2a99950e3..9b70d115a 100644
--- a/docs/zh/docs/help-fastapi.md
+++ b/docs/zh/docs/help-fastapi.md
@@ -114,8 +114,6 @@
聊天室仅供闲聊。
-我们之前还使用过 Gitter chat,但它不支持频道等高级功能,聊天也比较麻烦,所以现在推荐使用 Discord。
-
### 别在聊天室里提问
注意,聊天室更倾向于“闲聊”,经常有人会提出一些笼统得让人难以回答的问题,所以在这里提问一般没人回答。
diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md
index 1de2a8d36..d776e5813 100644
--- a/docs/zh/docs/index.md
+++ b/docs/zh/docs/index.md
@@ -24,7 +24,7 @@
---
-FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.6+ 并基于标准的 Python 类型提示。
+FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.8+ 并基于标准的 Python 类型提示。
关键特性:
@@ -107,7 +107,7 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框
## 依赖
-Python 3.6 及更高版本
+Python 3.8 及更高版本
FastAPI 站在以下巨人的肩膀之上:
@@ -323,7 +323,7 @@ def update_item(item_id: int, item: Item):
你不需要去学习新的语法、了解特定库的方法或类,等等。
-只需要使用标准的 **Python 3.6 及更高版本**。
+只需要使用标准的 **Python 3.8 及更高版本**。
举个例子,比如声明 `int` 类型:
diff --git a/docs/zh/docs/tutorial/background-tasks.md b/docs/zh/docs/tutorial/background-tasks.md
new file mode 100644
index 000000000..94b75d4fd
--- /dev/null
+++ b/docs/zh/docs/tutorial/background-tasks.md
@@ -0,0 +1,126 @@
+# 后台任务
+
+你可以定义在返回响应后运行的后台任务。
+
+这对需要在请求之后执行的操作很有用,但客户端不必在接收响应之前等待操作完成。
+
+包括这些例子:
+
+* 执行操作后发送的电子邮件通知:
+ * 由于连接到电子邮件服务器并发送电子邮件往往很“慢”(几秒钟),您可以立即返回响应并在后台发送电子邮件通知。
+* 处理数据:
+ * 例如,假设您收到的文件必须经过一个缓慢的过程,您可以返回一个"Accepted"(HTTP 202)响应并在后台处理它。
+
+## 使用 `BackgroundTasks`
+
+首先导入 `BackgroundTasks` 并在 *路径操作函数* 中使用类型声明 `BackgroundTasks` 定义一个参数:
+
+```Python hl_lines="1 13"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+**FastAPI** 会创建一个 `BackgroundTasks` 类型的对象并作为该参数传入。
+
+## 创建一个任务函数
+
+创建要作为后台任务运行的函数。
+
+它只是一个可以接收参数的标准函数。
+
+它可以是 `async def` 或普通的 `def` 函数,**FastAPI** 知道如何正确处理。
+
+在这种情况下,任务函数将写入一个文件(模拟发送电子邮件)。
+
+由于写操作不使用 `async` 和 `await`,我们用普通的 `def` 定义函数:
+
+```Python hl_lines="6-9"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+## 添加后台任务
+
+在你的 *路径操作函数* 里,用 `.add_task()` 方法将任务函数传到 *后台任务* 对象中:
+
+```Python hl_lines="14"
+{!../../../docs_src/background_tasks/tutorial001.py!}
+```
+
+`.add_task()` 接收以下参数:
+
+* 在后台运行的任务函数(`write_notification`)。
+* 应按顺序传递给任务函数的任意参数序列(`email`)。
+* 应传递给任务函数的任意关键字参数(`message="some notification"`)。
+
+## 依赖注入
+
+使用 `BackgroundTasks` 也适用于依赖注入系统,你可以在多个级别声明 `BackgroundTasks` 类型的参数:在 *路径操作函数* 里,在依赖中(可依赖),在子依赖中,等等。
+
+**FastAPI** 知道在每种情况下该做什么以及如何复用同一对象,因此所有后台任务被合并在一起并且随后在后台运行:
+
+=== "Python 3.10+"
+
+ ```Python hl_lines="13 15 22 25"
+ {!> ../../../docs_src/background_tasks/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="13 15 22 25"
+ {!> ../../../docs_src/background_tasks/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="14 16 23 26"
+ {!> ../../../docs_src/background_tasks/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ 没Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="11 13 20 23"
+ {!> ../../../docs_src/background_tasks/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.8+ 没Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="13 15 22 25"
+ {!> ../../../docs_src/background_tasks/tutorial002.py!}
+ ```
+
+该示例中,信息会在响应发出 *之后* 被写到 `log.txt` 文件。
+
+如果请求中有查询,它将在后台任务中写入日志。
+
+然后另一个在 *路径操作函数* 生成的后台任务会使用路径参数 `email` 写入一条信息。
+
+## 技术细节
+
+`BackgroundTasks` 类直接来自 `starlette.background`。
+
+它被直接导入/包含到FastAPI以便你可以从 `fastapi` 导入,并避免意外从 `starlette.background` 导入备用的 `BackgroundTask` (后面没有 `s`)。
+
+通过仅使用 `BackgroundTasks` (而不是 `BackgroundTask`),使得能将它作为 *路径操作函数* 的参数 ,并让**FastAPI**为您处理其余部分, 就像直接使用 `Request` 对象。
+
+在FastAPI中仍然可以单独使用 `BackgroundTask`,但您必须在代码中创建对象,并返回包含它的Starlette `Response`。
+
+更多细节查看 Starlette's official docs for Background Tasks.
+
+## 告诫
+
+如果您需要执行繁重的后台计算,并且不一定需要由同一进程运行(例如,您不需要共享内存、变量等),那么使用其他更大的工具(如 Celery)可能更好。
+
+它们往往需要更复杂的配置,即消息/作业队列管理器,如RabbitMQ或Redis,但它们允许您在多个进程中运行后台任务,甚至是在多个服务器中。
+
+要查看示例,查阅 [Project Generators](../project-generation.md){.internal-link target=_blank},它们都包括已经配置的Celery。
+
+但是,如果您需要从同一个**FastAPI**应用程序访问变量和对象,或者您需要执行小型后台任务(如发送电子邮件通知),您只需使用 `BackgroundTasks` 即可。
+
+## 回顾
+
+导入并使用 `BackgroundTasks` 通过 *路径操作函数* 中的参数和依赖项来添加后台任务。
diff --git a/docs/zh/docs/tutorial/body-fields.md b/docs/zh/docs/tutorial/body-fields.md
index 053cae71c..fb6c6d9b6 100644
--- a/docs/zh/docs/tutorial/body-fields.md
+++ b/docs/zh/docs/tutorial/body-fields.md
@@ -6,9 +6,41 @@
首先,你必须导入它:
-```Python hl_lines="2"
-{!../../../docs_src/body_fields/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body_fields/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body_fields/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="2"
+ {!> ../../../docs_src/body_fields/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body_fields/tutorial001.py!}
+ ```
!!! warning
注意,`Field` 是直接从 `pydantic` 导入的,而不是像其他的(`Query`,`Path`,`Body` 等)都从 `fastapi` 导入。
@@ -17,9 +49,41 @@
然后,你可以对模型属性使用 `Field`:
-```Python hl_lines="9-10"
-{!../../../docs_src/body_fields/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="11-14"
+ {!> ../../../docs_src/body_fields/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11-14"
+ {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="12-15"
+ {!> ../../../docs_src/body_fields/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="9-12"
+ {!> ../../../docs_src/body_fields/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="11-14"
+ {!> ../../../docs_src/body_fields/tutorial001.py!}
+ ```
`Field` 的工作方式和 `Query`、`Path` 和 `Body` 相同,包括它们的参数等等也完全相同。
diff --git a/docs/zh/docs/tutorial/body-multiple-params.md b/docs/zh/docs/tutorial/body-multiple-params.md
index 34fa5b638..c93ef2f5c 100644
--- a/docs/zh/docs/tutorial/body-multiple-params.md
+++ b/docs/zh/docs/tutorial/body-multiple-params.md
@@ -8,9 +8,41 @@
你还可以通过将默认值设置为 `None` 来将请求体参数声明为可选参数:
-```Python hl_lines="17-19"
-{!../../../docs_src/body_multiple_params/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="18-20"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-20"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="19-21"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="17-19"
+ {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="19-21"
+ {!> ../../../docs_src/body_multiple_params/tutorial001.py!}
+ ```
!!! note
请注意,在这种情况下,将从请求体获取的 `item` 是可选的。因为它的默认值为 `None`。
@@ -30,9 +62,17 @@
但是你也可以声明多个请求体参数,例如 `item` 和 `user`:
-```Python hl_lines="20"
-{!../../../docs_src/body_multiple_params/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/body_multiple_params/tutorial002.py!}
+ ```
在这种情况下,**FastAPI** 将注意到该函数中有多个请求体参数(两个 Pydantic 模型参数)。
@@ -72,9 +112,41 @@
但是你可以使用 `Body` 指示 **FastAPI** 将其作为请求体的另一个键进行处理。
-```Python hl_lines="22"
-{!../../../docs_src/body_multiple_params/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="23"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="23"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/body_multiple_params/tutorial003.py!}
+ ```
在这种情况下,**FastAPI** 将期望像这样的请求体:
@@ -109,9 +181,41 @@ q: str = None
比如:
-```Python hl_lines="25"
-{!../../../docs_src/body_multiple_params/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="28"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="25"
+ {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="27"
+ {!> ../../../docs_src/body_multiple_params/tutorial004.py!}
+ ```
!!! info
`Body` 同样具有与 `Query`、`Path` 以及其他后面将看到的类完全相同的额外校验和元数据参数。
@@ -131,9 +235,41 @@ item: Item = Body(embed=True)
比如:
-```Python hl_lines="15"
-{!../../../docs_src/body_multiple_params/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="17"
+ {!> ../../../docs_src/body_multiple_params/tutorial005.py!}
+ ```
在这种情况下,**FastAPI** 将期望像这样的请求体:
diff --git a/docs/zh/docs/tutorial/body-nested-models.md b/docs/zh/docs/tutorial/body-nested-models.md
index 7649ee6fe..c65308bef 100644
--- a/docs/zh/docs/tutorial/body-nested-models.md
+++ b/docs/zh/docs/tutorial/body-nested-models.md
@@ -6,9 +6,17 @@
你可以将一个属性定义为拥有子元素的类型。例如 Python `list`:
-```Python hl_lines="12"
-{!../../../docs_src/body_nested_models/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/body_nested_models/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/body_nested_models/tutorial001.py!}
+ ```
这将使 `tags` 成为一个由元素组成的列表。不过它没有声明每个元素的类型。
@@ -21,7 +29,7 @@
首先,从 Python 的标准库 `typing` 模块中导入 `List`:
```Python hl_lines="1"
-{!../../../docs_src/body_nested_models/tutorial002.py!}
+{!> ../../../docs_src/body_nested_models/tutorial002.py!}
```
### 声明具有子类型的 List
@@ -43,9 +51,23 @@ my_list: List[str]
因此,在我们的示例中,我们可以将 `tags` 明确地指定为一个「字符串列表」:
-```Python hl_lines="14"
-{!../../../docs_src/body_nested_models/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/body_nested_models/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/body_nested_models/tutorial002_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/body_nested_models/tutorial002.py!}
+ ```
## Set 类型
@@ -55,9 +77,23 @@ Python 具有一种特殊的数据类型来保存一组唯一的元素,即 `se
然后我们可以导入 `Set` 并将 `tag` 声明为一个由 `str` 组成的 `set`:
-```Python hl_lines="1 14"
-{!../../../docs_src/body_nested_models/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/body_nested_models/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="14"
+ {!> ../../../docs_src/body_nested_models/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 14"
+ {!> ../../../docs_src/body_nested_models/tutorial003.py!}
+ ```
这样,即使你收到带有重复数据的请求,这些数据也会被转换为一组唯一项。
@@ -79,17 +115,45 @@ Pydantic 模型的每个属性都具有类型。
例如,我们可以定义一个 `Image` 模型:
-```Python hl_lines="9 10 11"
-{!../../../docs_src/body_nested_models/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7-9"
+ {!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9-11"
+ {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9-11"
+ {!> ../../../docs_src/body_nested_models/tutorial004.py!}
+ ```
### 将子模型用作类型
然后我们可以将其用作一个属性的类型:
-```Python hl_lines="20"
-{!../../../docs_src/body_nested_models/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_nested_models/tutorial004.py!}
+ ```
这意味着 **FastAPI** 将期望类似于以下内容的请求体:
@@ -122,9 +186,23 @@ Pydantic 模型的每个属性都具有类型。
例如,在 `Image` 模型中我们有一个 `url` 字段,我们可以把它声明为 Pydantic 的 `HttpUrl`,而不是 `str`:
-```Python hl_lines="4 10"
-{!../../../docs_src/body_nested_models/tutorial005.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="2 8"
+ {!> ../../../docs_src/body_nested_models/tutorial005_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="4 10"
+ {!> ../../../docs_src/body_nested_models/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="4 10"
+ {!> ../../../docs_src/body_nested_models/tutorial005.py!}
+ ```
该字符串将被检查是否为有效的 URL,并在 JSON Schema / OpenAPI 文档中进行记录。
@@ -132,9 +210,23 @@ Pydantic 模型的每个属性都具有类型。
你还可以将 Pydantic 模型用作 `list`、`set` 等的子类型:
-```Python hl_lines="20"
-{!../../../docs_src/body_nested_models/tutorial006.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body_nested_models/tutorial006_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_nested_models/tutorial006_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="20"
+ {!> ../../../docs_src/body_nested_models/tutorial006.py!}
+ ```
这将期望(转换,校验,记录文档等)下面这样的 JSON 请求体:
@@ -169,9 +261,23 @@ Pydantic 模型的每个属性都具有类型。
你可以定义任意深度的嵌套模型:
-```Python hl_lines="9 14 20 23 27"
-{!../../../docs_src/body_nested_models/tutorial007.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7 12 18 21 25"
+ {!> ../../../docs_src/body_nested_models/tutorial007_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9 14 20 23 27"
+ {!> ../../../docs_src/body_nested_models/tutorial007_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9 14 20 23 27"
+ {!> ../../../docs_src/body_nested_models/tutorial007.py!}
+ ```
!!! info
请注意 `Offer` 拥有一组 `Item` 而反过来 `Item` 又是一个可选的 `Image` 列表是如何发生的。
@@ -186,9 +292,17 @@ images: List[Image]
例如:
-```Python hl_lines="15"
-{!../../../docs_src/body_nested_models/tutorial008.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="13"
+ {!> ../../../docs_src/body_nested_models/tutorial008_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="15"
+ {!> ../../../docs_src/body_nested_models/tutorial008.py!}
+ ```
## 无处不在的编辑器支持
@@ -218,9 +332,17 @@ images: List[Image]
在下面的例子中,你将接受任意键为 `int` 类型并且值为 `float` 类型的 `dict`:
-```Python hl_lines="15"
-{!../../../docs_src/body_nested_models/tutorial009.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/body_nested_models/tutorial009_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/body_nested_models/tutorial009.py!}
+ ```
!!! tip
请记住 JSON 仅支持将 `str` 作为键。
diff --git a/docs/zh/docs/tutorial/body.md b/docs/zh/docs/tutorial/body.md
index f80ab5bf5..5cf53c0c2 100644
--- a/docs/zh/docs/tutorial/body.md
+++ b/docs/zh/docs/tutorial/body.md
@@ -17,9 +17,17 @@
首先,你需要从 `pydantic` 中导入 `BaseModel`:
-```Python hl_lines="2"
-{!../../../docs_src/body/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="2"
+ {!> ../../../docs_src/body/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="4"
+ {!> ../../../docs_src/body/tutorial001.py!}
+ ```
## 创建数据模型
@@ -27,9 +35,17 @@
使用标准的 Python 类型来声明所有属性:
-```Python hl_lines="5-9"
-{!../../../docs_src/body/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="5-9"
+ {!> ../../../docs_src/body/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="7-11"
+ {!> ../../../docs_src/body/tutorial001.py!}
+ ```
和声明查询参数时一样,当一个模型属性具有默认值时,它不是必需的。否则它是一个必需属性。将默认值设为 `None` 可使其成为可选属性。
@@ -57,9 +73,17 @@
使用与声明路径和查询参数的相同方式声明请求体,即可将其添加到「路径操作」中:
-```Python hl_lines="16"
-{!../../../docs_src/body/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/body/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body/tutorial001.py!}
+ ```
...并且将它的类型声明为你创建的 `Item` 模型。
@@ -112,9 +136,17 @@ Pydantic 本身甚至也进行了一些更改以支持此功能。
在函数内部,你可以直接访问模型对象的所有属性:
-```Python hl_lines="19"
-{!../../../docs_src/body/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="19"
+ {!> ../../../docs_src/body/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="21"
+ {!> ../../../docs_src/body/tutorial002.py!}
+ ```
## 请求体 + 路径参数
@@ -122,9 +154,17 @@ Pydantic 本身甚至也进行了一些更改以支持此功能。
**FastAPI** 将识别出与路径参数匹配的函数参数应**从路径中获取**,而声明为 Pydantic 模型的函数参数应**从请求体中获取**。
-```Python hl_lines="15-16"
-{!../../../docs_src/body/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="15-16"
+ {!> ../../../docs_src/body/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="17-18"
+ {!> ../../../docs_src/body/tutorial003.py!}
+ ```
## 请求体 + 路径参数 + 查询参数
@@ -132,9 +172,17 @@ Pydantic 本身甚至也进行了一些更改以支持此功能。
**FastAPI** 会识别它们中的每一个,并从正确的位置获取数据。
-```Python hl_lines="16"
-{!../../../docs_src/body/tutorial004.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="16"
+ {!> ../../../docs_src/body/tutorial004_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/body/tutorial004.py!}
+ ```
函数参数将依次按如下规则进行识别:
diff --git a/docs/zh/docs/tutorial/cookie-params.md b/docs/zh/docs/tutorial/cookie-params.md
index d67daf0f9..f115f9677 100644
--- a/docs/zh/docs/tutorial/cookie-params.md
+++ b/docs/zh/docs/tutorial/cookie-params.md
@@ -6,9 +6,41 @@
首先,导入 `Cookie`:
-```Python hl_lines="3"
-{!../../../docs_src/cookie_params/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/cookie_params/tutorial001.py!}
+ ```
## 声明 `Cookie` 参数
@@ -17,9 +49,41 @@
第一个值是参数的默认值,同时也可以传递所有验证参数或注释参数,来校验参数:
-```Python hl_lines="9"
-{!../../../docs_src/cookie_params/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/cookie_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/cookie_params/tutorial001.py!}
+ ```
!!! note "技术细节"
`Cookie` 、`Path` 、`Query`是兄弟类,它们都继承自公共的 `Param` 类
diff --git a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
index f404820df..1866da298 100644
--- a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -12,7 +12,7 @@
{!> ../../../docs_src/dependencies/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/dependencies/tutorial001.py!}
@@ -85,7 +85,7 @@ fluffy = Cat(name="Mr Fluffy")
{!> ../../../docs_src/dependencies/tutorial002_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="11-15"
{!> ../../../docs_src/dependencies/tutorial002.py!}
diff --git a/docs/zh/docs/tutorial/encoder.md b/docs/zh/docs/tutorial/encoder.md
index 76ed846ce..859ebc2e8 100644
--- a/docs/zh/docs/tutorial/encoder.md
+++ b/docs/zh/docs/tutorial/encoder.md
@@ -26,7 +26,7 @@
{!> ../../../docs_src/encoder/tutorial001_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="5 22"
{!> ../../../docs_src/encoder/tutorial001.py!}
diff --git a/docs/zh/docs/tutorial/extra-data-types.md b/docs/zh/docs/tutorial/extra-data-types.md
index ac3e07654..a74efa61b 100644
--- a/docs/zh/docs/tutorial/extra-data-types.md
+++ b/docs/zh/docs/tutorial/extra-data-types.md
@@ -55,12 +55,76 @@
下面是一个*路径操作*的示例,其中的参数使用了上面的一些类型。
-```Python hl_lines="1 3 12-16"
-{!../../../docs_src/extra_data_types/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 3 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 3 13-17"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="1 2 11-15"
+ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="1 2 12-16"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
注意,函数内的参数有原生的数据类型,你可以,例如,执行正常的日期操作,如:
-```Python hl_lines="18-19"
-{!../../../docs_src/extra_data_types/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="19-20"
+ {!> ../../../docs_src/extra_data_types/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="17-18"
+ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="18-19"
+ {!> ../../../docs_src/extra_data_types/tutorial001.py!}
+ ```
diff --git a/docs/zh/docs/tutorial/extra-models.md b/docs/zh/docs/tutorial/extra-models.md
index 1fbe77be8..06427a73d 100644
--- a/docs/zh/docs/tutorial/extra-models.md
+++ b/docs/zh/docs/tutorial/extra-models.md
@@ -17,9 +17,17 @@
下面是应该如何根据它们的密码字段以及使用位置去定义模型的大概思路:
-```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
-{!../../../docs_src/extra_models/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
+ {!> ../../../docs_src/extra_models/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
+ {!> ../../../docs_src/extra_models/tutorial001.py!}
+ ```
### 关于 `**user_in.dict()`
@@ -150,9 +158,17 @@ UserInDB(
这样,我们可以仅声明模型之间的差异部分(具有明文的 `password`、具有 `hashed_password` 以及不包括密码)。
-```Python hl_lines="9 15-16 19-20 23-24"
-{!../../../docs_src/extra_models/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7 13-14 17-18 21-22"
+ {!> ../../../docs_src/extra_models/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9 15-16 19-20 23-24"
+ {!> ../../../docs_src/extra_models/tutorial002.py!}
+ ```
## `Union` 或者 `anyOf`
@@ -166,9 +182,17 @@ UserInDB(
!!! note
定义一个 `Union` 类型时,首先包括最详细的类型,然后是不太详细的类型。在下面的示例中,更详细的 `PlaneItem` 位于 `Union[PlaneItem,CarItem]` 中的 `CarItem` 之前。
-```Python hl_lines="1 14-15 18-20 33"
-{!../../../docs_src/extra_models/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="1 14-15 18-20 33"
+ {!> ../../../docs_src/extra_models/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 14-15 18-20 33"
+ {!> ../../../docs_src/extra_models/tutorial003.py!}
+ ```
## 模型列表
@@ -176,9 +200,17 @@ UserInDB(
为此,请使用标准的 Python `typing.List`:
-```Python hl_lines="1 20"
-{!../../../docs_src/extra_models/tutorial004.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="18"
+ {!> ../../../docs_src/extra_models/tutorial004_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 20"
+ {!> ../../../docs_src/extra_models/tutorial004.py!}
+ ```
## 任意 `dict` 构成的响应
@@ -188,9 +220,17 @@ UserInDB(
在这种情况下,你可以使用 `typing.Dict`:
-```Python hl_lines="1 8"
-{!../../../docs_src/extra_models/tutorial005.py!}
-```
+=== "Python 3.9+"
+
+ ```Python hl_lines="6"
+ {!> ../../../docs_src/extra_models/tutorial005_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="1 8"
+ {!> ../../../docs_src/extra_models/tutorial005.py!}
+ ```
## 总结
diff --git a/docs/zh/docs/tutorial/handling-errors.md b/docs/zh/docs/tutorial/handling-errors.md
index 9b066bc2c..a0d66e557 100644
--- a/docs/zh/docs/tutorial/handling-errors.md
+++ b/docs/zh/docs/tutorial/handling-errors.md
@@ -145,7 +145,7 @@
```
-访问 `/items/foo`,可以看到以下内容替换了默认 JSON 错误信息:
+访问 `/items/foo`,可以看到默认的 JSON 错误信息:
```JSON
{
@@ -163,7 +163,7 @@
```
-以下是文本格式的错误信息:
+被替换为了以下文本格式的错误信息:
```
1 validation error
diff --git a/docs/zh/docs/tutorial/header-params.md b/docs/zh/docs/tutorial/header-params.md
index c4b1c38ce..2701167b3 100644
--- a/docs/zh/docs/tutorial/header-params.md
+++ b/docs/zh/docs/tutorial/header-params.md
@@ -6,9 +6,41 @@
首先导入 `Header`:
-```Python hl_lines="3"
-{!../../../docs_src/header_params/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/header_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```
## 声明 `Header` 参数
@@ -16,9 +48,41 @@
第一个值是默认值,你可以传递所有的额外验证或注释参数:
-```Python hl_lines="9"
-{!../../../docs_src/header_params/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial001.py!}
+ ```
!!! note "技术细节"
`Header` 是 `Path`, `Query` 和 `Cookie` 的兄弟类型。它也继承自通用的 `Param` 类.
@@ -44,9 +108,41 @@
如果出于某些原因,你需要禁用下划线到连字符的自动转换,设置`Header`的参数 `convert_underscores` 为 `False`:
-```Python hl_lines="10"
-{!../../../docs_src/header_params/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial002_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/header_params/tutorial002_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="12"
+ {!> ../../../docs_src/header_params/tutorial002_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/header_params/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial002.py!}
+ ```
!!! warning
在设置 `convert_underscores` 为 `False` 之前,请记住,一些HTTP代理和服务器不允许使用带有下划线的headers。
@@ -62,9 +158,50 @@
比如, 为了声明一个 `X-Token` header 可以出现多次,你可以这样写:
-```Python hl_lines="9"
-{!../../../docs_src/header_params/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/header_params/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ Prefer to use the `Annotated` version if possible.
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/header_params/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.9+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003_py39.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/header_params/tutorial003.py!}
+ ```
如果你与*路径操作*通信时发送两个HTTP headers,就像:
diff --git a/docs/zh/docs/tutorial/path-params-numeric-validations.md b/docs/zh/docs/tutorial/path-params-numeric-validations.md
index 13512a08e..9b41ad7cf 100644
--- a/docs/zh/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/zh/docs/tutorial/path-params-numeric-validations.md
@@ -6,9 +6,41 @@
首先,从 `fastapi` 导入 `Path`:
-```Python hl_lines="1"
-{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="1 3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="3-4"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="1"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="3"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
## 声明元数据
@@ -16,9 +48,41 @@
例如,要声明路径参数 `item_id`的 `title` 元数据值,你可以输入:
-```Python hl_lines="8"
-{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="11"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="8"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="10"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!}
+ ```
!!! note
路径参数总是必需的,因为它必须是路径的一部分。
@@ -43,9 +107,14 @@
因此,你可以将函数声明为:
-```Python hl_lines="7"
-{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
-```
+=== "Python 3.8 non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/path_params_numeric_validations/tutorial002.py!}
+ ```
## 按需对参数排序的技巧
diff --git a/docs/zh/docs/tutorial/query-params-str-validations.md b/docs/zh/docs/tutorial/query-params-str-validations.md
index 070074839..39253eb0d 100644
--- a/docs/zh/docs/tutorial/query-params-str-validations.md
+++ b/docs/zh/docs/tutorial/query-params-str-validations.md
@@ -4,9 +4,17 @@
让我们以下面的应用程序为例:
-```Python hl_lines="7"
-{!../../../docs_src/query_params_str_validations/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="7"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9"
+ {!> ../../../docs_src/query_params_str_validations/tutorial001.py!}
+ ```
查询参数 `q` 的类型为 `str`,默认值为 `None`,因此它是可选的。
diff --git a/docs/zh/docs/tutorial/request-files.md b/docs/zh/docs/tutorial/request-files.md
index 03474907e..2c48f33ca 100644
--- a/docs/zh/docs/tutorial/request-files.md
+++ b/docs/zh/docs/tutorial/request-files.md
@@ -130,7 +130,7 @@ contents = myfile.file.read()
{!> ../../../docs_src/request_files/tutorial001_02_py310.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9 17"
{!> ../../../docs_src/request_files/tutorial001_02.py!}
@@ -158,7 +158,7 @@ FastAPI 支持同时上传多个文件。
{!> ../../../docs_src/request_files/tutorial002_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="10 15"
{!> ../../../docs_src/request_files/tutorial002.py!}
@@ -183,7 +183,7 @@ FastAPI 支持同时上传多个文件。
{!> ../../../docs_src/request_files/tutorial003_py39.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="18"
{!> ../../../docs_src/request_files/tutorial003.py!}
diff --git a/docs/zh/docs/tutorial/response-model.md b/docs/zh/docs/tutorial/response-model.md
index ea3d0666d..e731b6989 100644
--- a/docs/zh/docs/tutorial/response-model.md
+++ b/docs/zh/docs/tutorial/response-model.md
@@ -8,9 +8,23 @@
* `@app.delete()`
* 等等。
-```Python hl_lines="17"
-{!../../../docs_src/response_model/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="17 22 24-27"
+ {!> ../../../docs_src/response_model/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="17 22 24-27"
+ {!> ../../../docs_src/response_model/tutorial001_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="17 22 24-27"
+ {!> ../../../docs_src/response_model/tutorial001.py!}
+ ```
!!! note
注意,`response_model`是「装饰器」方法(`get`,`post` 等)的一个参数。不像之前的所有参数和请求体,它不属于*路径操作函数*。
@@ -58,21 +72,45 @@ FastAPI 将使用此 `response_model` 来:
相反,我们可以创建一个有明文密码的输入模型和一个没有明文密码的输出模型:
-```Python hl_lines="9 11 16"
-{!../../../docs_src/response_model/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="9 11 16"
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="9 11 16"
+ {!> ../../../docs_src/response_model/tutorial003.py!}
+ ```
这样,即便我们的*路径操作函数*将会返回包含密码的相同输入用户:
-```Python hl_lines="24"
-{!../../../docs_src/response_model/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="24"
+ {!> ../../../docs_src/response_model/tutorial003.py!}
+ ```
...我们已经将 `response_model` 声明为了不包含密码的 `UserOut` 模型:
-```Python hl_lines="22"
-{!../../../docs_src/response_model/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/response_model/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="22"
+ {!> ../../../docs_src/response_model/tutorial003.py!}
+ ```
因此,**FastAPI** 将会负责过滤掉未在输出模型中声明的所有数据(使用 Pydantic)。
diff --git a/docs/zh/docs/tutorial/schema-extra-example.md b/docs/zh/docs/tutorial/schema-extra-example.md
index 8f5fbfe70..ebc04da8b 100644
--- a/docs/zh/docs/tutorial/schema-extra-example.md
+++ b/docs/zh/docs/tutorial/schema-extra-example.md
@@ -10,9 +10,17 @@
您可以使用 `Config` 和 `schema_extra` 为Pydantic模型声明一个示例,如Pydantic 文档:定制 Schema 中所述:
-```Python hl_lines="15-23"
-{!../../../docs_src/schema_extra_example/tutorial001.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="13-21"
+ {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="15-23"
+ {!> ../../../docs_src/schema_extra_example/tutorial001.py!}
+ ```
这些额外的信息将按原样添加到输出的JSON模式中。
@@ -20,9 +28,17 @@
在 `Field`, `Path`, `Query`, `Body` 和其他你之后将会看到的工厂函数,你可以为JSON 模式声明额外信息,你也可以通过给工厂函数传递其他的任意参数来给JSON 模式声明额外信息,比如增加 `example`:
-```Python hl_lines="4 10-13"
-{!../../../docs_src/schema_extra_example/tutorial002.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="2 8-11"
+ {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="4 10-13"
+ {!> ../../../docs_src/schema_extra_example/tutorial002.py!}
+ ```
!!! warning
请记住,传递的那些额外参数不会添加任何验证,只会添加注释,用于文档的目的。
@@ -33,9 +49,41 @@
比如,你可以将请求体的一个 `example` 传递给 `Body`:
-```Python hl_lines="20-25"
-{!../../../docs_src/schema_extra_example/tutorial003.py!}
-```
+=== "Python 3.10+"
+
+ ```Python hl_lines="22-27"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_an_py310.py!}
+ ```
+
+=== "Python 3.9+"
+
+ ```Python hl_lines="22-27"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python hl_lines="23-28"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_an.py!}
+ ```
+
+=== "Python 3.10+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="18-23"
+ {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python hl_lines="20-25"
+ {!> ../../../docs_src/schema_extra_example/tutorial003.py!}
+ ```
## 文档 UI 中的例子
diff --git a/docs/zh/docs/tutorial/security/first-steps.md b/docs/zh/docs/tutorial/security/first-steps.md
index 86c3320ce..dda956417 100644
--- a/docs/zh/docs/tutorial/security/first-steps.md
+++ b/docs/zh/docs/tutorial/security/first-steps.md
@@ -20,9 +20,26 @@
把下面的示例代码复制到 `main.py`:
-```Python
-{!../../../docs_src/security/tutorial001.py!}
-```
+=== "Python 3.9+"
+
+ ```Python
+ {!> ../../../docs_src/security/tutorial001_an_py39.py!}
+ ```
+
+=== "Python 3.8+"
+
+ ```Python
+ {!> ../../../docs_src/security/tutorial001_an.py!}
+ ```
+
+=== "Python 3.8+ non-Annotated"
+
+ !!! tip
+ 尽可能选择使用 `Annotated` 的版本。
+
+ ```Python
+ {!> ../../../docs_src/security/tutorial001.py!}
+ ```
## 运行
diff --git a/docs/zh/docs/tutorial/security/simple-oauth2.md b/docs/zh/docs/tutorial/security/simple-oauth2.md
index 276f3d63b..c7f46177f 100644
--- a/docs/zh/docs/tutorial/security/simple-oauth2.md
+++ b/docs/zh/docs/tutorial/security/simple-oauth2.md
@@ -1,94 +1,98 @@
-# 使用密码和 Bearer 的简单 OAuth2
+# OAuth2 实现简单的 Password 和 Bearer 验证
-现在让我们接着上一章继续开发,并添加缺少的部分以实现一个完整的安全性流程。
+本章添加上一章示例中欠缺的部分,实现完整的安全流。
## 获取 `username` 和 `password`
-我们将使用 **FastAPI** 的安全性实用工具来获取 `username` 和 `password`。
+首先,使用 **FastAPI** 安全工具获取 `username` 和 `password`。
-OAuth2 规定在使用(我们打算用的)「password 流程」时,客户端/用户必须将 `username` 和 `password` 字段作为表单数据发送。
+OAuth2 规范要求使用**密码流**时,客户端或用户必须以表单数据形式发送 `username` 和 `password` 字段。
-而且规范明确了字段必须这样命名。因此 `user-name` 或 `email` 是行不通的。
+并且,这两个字段必须命名为 `username` 和 `password` ,不能使用 `user-name` 或 `email` 等其它名称。
-不过不用担心,你可以在前端按照你的想法将它展示给最终用户。
+不过也不用担心,前端仍可以显示终端用户所需的名称。
-而且你的数据库模型也可以使用你想用的任何其他名称。
+数据库模型也可以使用所需的名称。
-但是对于登录*路径操作*,我们需要使用这些名称来与规范兼容(以具备例如使用集成的 API 文档系统的能力)。
+但对于登录*路径操作*,则要使用兼容规范的 `username` 和 `password`,(例如,实现与 API 文档集成)。
-规范还写明了 `username` 和 `password` 必须作为表单数据发送(因此,此处不能使用 JSON)。
+该规范要求必须以表单数据形式发送 `username` 和 `password`,因此,不能使用 JSON 对象。
-### `scope`
+### `Scope`(作用域)
-规范还提到客户端可以发送另一个表单字段「`scope`」。
+OAuth2 还支持客户端发送**`scope`**表单字段。
-这个表单字段的名称为 `scope`(单数形式),但实际上它是一个由空格分隔的「作用域」组成的长字符串。
+虽然表单字段的名称是 `scope`(单数),但实际上,它是以空格分隔的,由多个**scope**组成的长字符串。
-每个「作用域」只是一个字符串(中间没有空格)。
+**作用域**只是不带空格的字符串。
-它们通常用于声明特定的安全权限,例如:
+常用于声明指定安全权限,例如:
-* `users:read` 或者 `users:write` 是常见的例子。
-* Facebook / Instagram 使用 `instagram_basic`。
-* Google 使用了 `https://www.googleapis.com/auth/drive` 。
+* 常见用例为,`users:read` 或 `users:write`
+* 脸书和 Instagram 使用 `instagram_basic`
+* 谷歌使用 `https://www.googleapis.com/auth/drive`
-!!! info
- 在 OAuth2 中「作用域」只是一个声明所需特定权限的字符串。
+!!! info "说明"
- 它有没有 `:` 这样的其他字符或者是不是 URL 都没有关系。
+ OAuth2 中,**作用域**只是声明指定权限的字符串。
- 这些细节是具体的实现。
+ 是否使用冒号 `:` 等符号,或是不是 URL 并不重要。
- 对 OAuth2 来说它们就只是字符串而已。
+ 这些细节只是特定的实现方式。
+
+ 对 OAuth2 来说,都只是字符串而已。
## 获取 `username` 和 `password` 的代码
-现在,让我们使用 **FastAPI** 提供的实用工具来处理此问题。
+接下来,使用 **FastAPI** 工具获取用户名与密码。
### `OAuth2PasswordRequestForm`
-首先,导入 `OAuth2PasswordRequestForm`,然后在 `token` 的*路径操作*中通过 `Depends` 将其作为依赖项使用。
+首先,导入 `OAuth2PasswordRequestForm`,然后,在 `/token` *路径操作* 中,用 `Depends` 把该类作为依赖项。
```Python hl_lines="4 76"
{!../../../docs_src/security/tutorial003.py!}
```
-`OAuth2PasswordRequestForm` 是一个类依赖项,声明了如下的请求表单:
+`OAuth2PasswordRequestForm` 是用以下几项内容声明表单请求体的类依赖项:
+
+* `username`
+* `password`
+* 可选的 `scope` 字段,由多个空格分隔的字符串组成的长字符串
+* 可选的 `grant_type`
-* `username`。
-* `password`。
-* 一个可选的 `scope` 字段,是一个由空格分隔的字符串组成的大字符串。
-* 一个可选的 `grant_type`.
+!!! tip "提示"
-!!! tip
- OAuth2 规范实际上*要求* `grant_type` 字段使用一个固定的值 `password`,但是 `OAuth2PasswordRequestForm` 没有作强制约束。
+ 实际上,OAuth2 规范*要求* `grant_type` 字段使用固定值 `password`,但 `OAuth2PasswordRequestForm` 没有作强制约束。
- 如果你需要强制要求这一点,请使用 `OAuth2PasswordRequestFormStrict` 而不是 `OAuth2PasswordRequestForm`。
+ 如需强制使用固定值 `password`,则不要用 `OAuth2PasswordRequestForm`,而是用 `OAuth2PasswordRequestFormStrict`。
-* 一个可选的 `client_id`(我们的示例不需要它)。
-* 一个可选的 `client_secret`(我们的示例不需要它)。
+* 可选的 `client_id`(本例未使用)
+* 可选的 `client_secret`(本例未使用)
-!!! info
- `OAuth2PasswordRequestForm` 并不像 `OAuth2PasswordBearer` 一样是 FastAPI 的一个特殊的类。
+!!! info "说明"
- `OAuth2PasswordBearer` 使得 **FastAPI** 明白它是一个安全方案。所以它得以通过这种方式添加到 OpenAPI 中。
+ `OAuth2PasswordRequestForm` 与 `OAuth2PasswordBearer` 一样,都不是 FastAPI 的特殊类。
- 但 `OAuth2PasswordRequestForm` 只是一个你可以自己编写的类依赖项,或者你也可以直接声明 `Form` 参数。
+ **FastAPI** 把 `OAuth2PasswordBearer` 识别为安全方案。因此,可以通过这种方式把它添加至 OpenAPI。
- 但是由于这是一种常见的使用场景,因此 FastAPI 出于简便直接提供了它。
+ 但 `OAuth2PasswordRequestForm` 只是可以自行编写的类依赖项,也可以直接声明 `Form` 参数。
+
+ 但由于这种用例很常见,FastAPI 为了简便,就直接提供了对它的支持。
### 使用表单数据
-!!! tip
- 类依赖项 `OAuth2PasswordRequestForm` 的实例不会有用空格分隔的长字符串属性 `scope`,而是具有一个 `scopes` 属性,该属性将包含实际被发送的每个作用域字符串组成的列表。
+!!! tip "提示"
+
+ `OAuth2PasswordRequestForm` 类依赖项的实例没有以空格分隔的长字符串属性 `scope`,但它支持 `scopes` 属性,由已发送的 scope 字符串列表组成。
- 在此示例中我们没有使用 `scopes`,但如果你需要的话可以使用该功能。
+ 本例没有使用 `scopes`,但开发者也可以根据需要使用该属性。
-现在,使用表单字段中的 `username` 从(伪)数据库中获取用户数据。
+现在,即可使用表单字段 `username`,从(伪)数据库中获取用户数据。
-如果没有这个用户,我们将返回一个错误消息,提示「用户名或密码错误」。
+如果不存在指定用户,则返回错误消息,提示**用户名或密码错误**。
-对于这个错误,我们使用 `HTTPException` 异常:
+本例使用 `HTTPException` 异常显示此错误:
```Python hl_lines="3 77-79"
{!../../../docs_src/security/tutorial003.py!}
@@ -96,27 +100,27 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
### 校验密码
-目前我们已经从数据库中获取了用户数据,但尚未校验密码。
+至此,我们已经从数据库中获取了用户数据,但尚未校验密码。
-让我们首先将这些数据放入 Pydantic `UserInDB` 模型中。
+接下来,首先将数据放入 Pydantic 的 `UserInDB` 模型。
-永远不要保存明文密码,因此,我们将使用(伪)哈希密码系统。
+注意:永远不要保存明文密码,本例暂时先使用(伪)哈希密码系统。
-如果密码不匹配,我们将返回同一个错误。
+如果密码不匹配,则返回与上面相同的错误。
-#### 哈希密码
+#### 密码哈希
-「哈希」的意思是:将某些内容(在本例中为密码)转换为看起来像乱码的字节序列(只是一个字符串)。
+**哈希**是指,将指定内容(本例中为密码)转换为形似乱码的字节序列(其实就是字符串)。
-每次你传入完全相同的内容(完全相同的密码)时,你都会得到完全相同的乱码。
+每次传入完全相同的内容(比如,完全相同的密码)时,得到的都是完全相同的乱码。
-但是你不能从乱码转换回密码。
+但这个乱码无法转换回传入的密码。
-##### 为什么使用哈希密码
+##### 为什么使用密码哈希
-如果你的数据库被盗,小偷将无法获得用户的明文密码,只有哈希值。
+原因很简单,假如数据库被盗,窃贼无法获取用户的明文密码,得到的只是哈希值。
-因此,小偷将无法尝试在另一个系统中使用这些相同的密码(由于许多用户在任何地方都使用相同的密码,因此这很危险)。
+这样一来,窃贼就无法在其它应用中使用窃取的密码,要知道,很多用户在所有系统中都使用相同的密码,风险超大。
```Python hl_lines="80-83"
{!../../../docs_src/security/tutorial003.py!}
@@ -124,9 +128,9 @@ OAuth2 规定在使用(我们打算用的)「password 流程」时,客户
#### 关于 `**user_dict`
-`UserInDB(**user_dict)` 表示:
+`UserInDB(**user_dict)` 是指:
-*直接将 `user_dict` 的键和值作为关键字参数传递,等同于:*
+*直接把 `user_dict` 的键与值当作关键字参数传递,等效于:*
```Python
UserInDB(
@@ -138,75 +142,79 @@ UserInDB(
)
```
-!!! info
- 有关 `user_dict` 的更完整说明,请参阅[**额外的模型**文档](../extra-models.md#about-user_indict){.internal-link target=_blank}。
+!!! info "说明"
-## 返回令牌
+ `user_dict` 的说明,详见[**更多模型**一章](../extra-models.md#about-user_indict){.internal-link target=_blank}。
-`token` 端点的响应必须是一个 JSON 对象。
+## 返回 Token
-它应该有一个 `token_type`。在我们的例子中,由于我们使用的是「Bearer」令牌,因此令牌类型应为「`bearer`」。
+`token` 端点的响应必须是 JSON 对象。
-并且还应该有一个 `access_token` 字段,它是一个包含我们的访问令牌的字符串。
+响应返回的内容应该包含 `token_type`。本例中用的是**Bearer**Token,因此, Token 类型应为**`bearer`**。
-对于这个简单的示例,我们将极其不安全地返回相同的 `username` 作为令牌。
+返回内容还应包含 `access_token` 字段,它是包含权限 Token 的字符串。
-!!! tip
- 在下一章中,你将看到一个真实的安全实现,使用了哈希密码和 JWT 令牌。
+本例只是简单的演示,返回的 Token 就是 `username`,但这种方式极不安全。
- 但现在,让我们仅关注我们需要的特定细节。
+!!! tip "提示"
+
+ 下一章介绍使用哈希密码和 JWT Token 的真正安全机制。
+
+ 但现在,仅关注所需的特定细节。
```Python hl_lines="85"
{!../../../docs_src/security/tutorial003.py!}
```
-!!! tip
- 根据规范,你应该像本示例一样,返回一个带有 `access_token` 和 `token_type` 的 JSON。
+!!! tip "提示"
- 这是你必须在代码中自行完成的工作,并且要确保使用了这些 JSON 字段。
+ 按规范的要求,应像本示例一样,返回带有 `access_token` 和 `token_type` 的 JSON 对象。
- 这几乎是唯一的你需要自己记住并正确地执行以符合规范的事情。
+ 这是开发者必须在代码中自行完成的工作,并且要确保使用这些 JSON 的键。
- 其余的,**FastAPI** 都会为你处理。
+ 这几乎是唯一需要开发者牢记在心,并按规范要求正确执行的事。
+
+ **FastAPI** 则负责处理其它的工作。
## 更新依赖项
-现在我们将更新我们的依赖项。
+接下来,更新依赖项。
-我们想要仅当此用户处于启用状态时才能获取 `current_user`。
+使之仅在当前用户为激活状态时,才能获取 `current_user`。
-因此,我们创建了一个额外的依赖项 `get_current_active_user`,而该依赖项又以 `get_current_user` 作为依赖项。
+为此,要再创建一个依赖项 `get_current_active_user`,此依赖项以 `get_current_user` 依赖项为基础。
-如果用户不存在或处于未启用状态,则这两个依赖项都将仅返回 HTTP 错误。
+如果用户不存在,或状态为未激活,这两个依赖项都会返回 HTTP 错误。
-因此,在我们的端点中,只有当用户存在,身份认证通过且处于启用状态时,我们才能获得该用户:
+因此,在端点中,只有当用户存在、通过身份验证、且状态为激活时,才能获得该用户:
```Python hl_lines="58-67 69-72 90"
{!../../../docs_src/security/tutorial003.py!}
```
-!!! info
- 我们在此处返回的值为 `Bearer` 的额外响应头 `WWW-Authenticate` 也是规范的一部分。
+!!! info "说明"
+
+ 此处返回值为 `Bearer` 的响应头 `WWW-Authenticate` 也是规范的一部分。
- 任何的 401「未认证」HTTP(错误)状态码都应该返回 `WWW-Authenticate` 响应头。
+ 任何 401**UNAUTHORIZED**HTTP(错误)状态码都应返回 `WWW-Authenticate` 响应头。
- 对于 bearer 令牌(我们的例子),该响应头的值应为 `Bearer`。
+ 本例中,因为使用的是 Bearer Token,该响应头的值应为 `Bearer`。
- 实际上你可以忽略这个额外的响应头,不会有什么问题。
+ 实际上,忽略这个附加响应头,也不会有什么问题。
- 但此处提供了它以符合规范。
+ 之所以在此提供这个附加响应头,是为了符合规范的要求。
- 而且,(现在或将来)可能会有工具期望得到并使用它,然后对你或你的用户有用处。
+ 说不定什么时候,就有工具用得上它,而且,开发者或用户也可能用得上。
- 这就是遵循标准的好处...
+ 这就是遵循标准的好处……
## 实际效果
-打开交互式文档:http://127.0.0.1:8000/docs。
+打开 API 文档:http://127.0.0.1:8000/docs。
-### 身份认证
+### 身份验证
-点击「Authorize」按钮。
+点击**Authorize**按钮。
使用以下凭证:
@@ -216,15 +224,15 @@ UserInDB(
-在系统中进行身份认证后,你将看到:
+通过身份验证后,显示下图所示的内容:
-### 获取本人的用户数据
+### 获取当前用户数据
-现在执行 `/users/me` 路径的 `GET` 操作。
+使用 `/users/me` 路径的 `GET` 操作。
-你将获得你的用户数据,如:
+可以提取如下当前用户数据:
```JSON
{
@@ -238,7 +246,7 @@ UserInDB(
-如果你点击锁定图标并注销,然后再次尝试同一操作,则会得到 HTTP 401 错误:
+点击小锁图标,注销后,再执行同样的操作,则会得到 HTTP 401 错误:
```JSON
{
@@ -246,17 +254,17 @@ UserInDB(
}
```
-### 未启用的用户
+### 未激活用户
-现在尝试使用未启用的用户,并通过以下方式进行身份认证:
+测试未激活用户,输入以下信息,进行身份验证:
用户名:`alice`
密码:`secret2`
-然后尝试执行 `/users/me` 路径的 `GET` 操作。
+然后,执行 `/users/me` 路径的 `GET` 操作。
-你将得到一个「未启用的用户」错误,如:
+显示下列**未激活用户**错误信息:
```JSON
{
@@ -264,12 +272,12 @@ UserInDB(
}
```
-## 总结
+## 小结
-现在你掌握了为你的 API 实现一个基于 `username` 和 `password` 的完整安全系统的工具。
+使用本章的工具实现基于 `username` 和 `password` 的完整 API 安全系统。
-使用这些工具,你可以使安全系统与任何数据库以及任何用户或数据模型兼容。
+这些工具让安全系统兼容任何数据库、用户及数据模型。
-唯一缺少的细节是它实际上还并不「安全」。
+唯一欠缺的是,它仍然不是真的**安全**。
-在下一章中,你将看到如何使用一个安全的哈希密码库和 JWT 令牌。
+下一章,介绍使用密码哈希支持库与 JWT 令牌实现真正的安全机制。
diff --git a/docs/zh/docs/tutorial/sql-databases.md b/docs/zh/docs/tutorial/sql-databases.md
index 482588f94..8b09dc677 100644
--- a/docs/zh/docs/tutorial/sql-databases.md
+++ b/docs/zh/docs/tutorial/sql-databases.md
@@ -258,7 +258,7 @@ connect_args={"check_same_thread": False}
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="3 6-8 11-12 23-24 27-28"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
@@ -302,7 +302,7 @@ name: str
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="15-17 31-34"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
@@ -331,7 +331,7 @@ name: str
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="15 19-20 31 36-37"
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
@@ -471,7 +471,7 @@ current_user.items
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="9"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
@@ -505,7 +505,7 @@ current_user.items
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="15-20"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
@@ -530,7 +530,7 @@ current_user.items
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="24 32 38 47 53"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
@@ -551,7 +551,7 @@ current_user.items
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="23-28 31-34 37-42 45-49 52-55"
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
@@ -650,7 +650,7 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
{!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python
{!> ../../../docs_src/sql_databases/sql_app/schemas.py!}
@@ -670,7 +670,7 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
{!> ../../../docs_src/sql_databases/sql_app_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python
{!> ../../../docs_src/sql_databases/sql_app/main.py!}
@@ -729,7 +729,7 @@ $ uvicorn sql_app.main:app --reload
{!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python hl_lines="14-22"
{!> ../../../docs_src/sql_databases/sql_app/alt_main.py!}
diff --git a/docs/zh/docs/tutorial/testing.md b/docs/zh/docs/tutorial/testing.md
index 41f01f8d8..77fff7596 100644
--- a/docs/zh/docs/tutorial/testing.md
+++ b/docs/zh/docs/tutorial/testing.md
@@ -122,7 +122,7 @@
{!> ../../../docs_src/app_testing/app_b_an_py39/main.py!}
```
-=== "Python 3.6+"
+=== "Python 3.8+"
```Python
{!> ../../../docs_src/app_testing/app_b_an/main.py!}
@@ -137,7 +137,7 @@
{!> ../../../docs_src/app_testing/app_b_py310/main.py!}
```
-=== "Python 3.6+ non-Annotated"
+=== "Python 3.8+ non-Annotated"
!!! tip
Prefer to use the `Annotated` version if possible.
diff --git a/docs_src/extending_openapi/tutorial003.py b/docs_src/configure_swagger_ui/tutorial001.py
similarity index 100%
rename from docs_src/extending_openapi/tutorial003.py
rename to docs_src/configure_swagger_ui/tutorial001.py
diff --git a/docs_src/extending_openapi/tutorial004.py b/docs_src/configure_swagger_ui/tutorial002.py
similarity index 100%
rename from docs_src/extending_openapi/tutorial004.py
rename to docs_src/configure_swagger_ui/tutorial002.py
diff --git a/docs_src/extending_openapi/tutorial005.py b/docs_src/configure_swagger_ui/tutorial003.py
similarity index 100%
rename from docs_src/extending_openapi/tutorial005.py
rename to docs_src/configure_swagger_ui/tutorial003.py
diff --git a/docs_src/custom_docs_ui/tutorial001.py b/docs_src/custom_docs_ui/tutorial001.py
new file mode 100644
index 000000000..4384433e3
--- /dev/null
+++ b/docs_src/custom_docs_ui/tutorial001.py
@@ -0,0 +1,38 @@
+from fastapi import FastAPI
+from fastapi.openapi.docs import (
+ get_redoc_html,
+ get_swagger_ui_html,
+ get_swagger_ui_oauth2_redirect_html,
+)
+
+app = FastAPI(docs_url=None, redoc_url=None)
+
+
+@app.get("/docs", include_in_schema=False)
+async def custom_swagger_ui_html():
+ return get_swagger_ui_html(
+ openapi_url=app.openapi_url,
+ title=app.title + " - Swagger UI",
+ oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
+ swagger_js_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js",
+ swagger_css_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css",
+ )
+
+
+@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
+async def swagger_ui_redirect():
+ return get_swagger_ui_oauth2_redirect_html()
+
+
+@app.get("/redoc", include_in_schema=False)
+async def redoc_html():
+ return get_redoc_html(
+ openapi_url=app.openapi_url,
+ title=app.title + " - ReDoc",
+ redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js",
+ )
+
+
+@app.get("/users/{username}")
+async def read_user(username: str):
+ return {"message": f"Hello {username}"}
diff --git a/docs_src/extending_openapi/tutorial002.py b/docs_src/custom_docs_ui/tutorial002.py
similarity index 100%
rename from docs_src/extending_openapi/tutorial002.py
rename to docs_src/custom_docs_ui/tutorial002.py
diff --git a/docs_src/dependencies/tutorial008b.py b/docs_src/dependencies/tutorial008b.py
new file mode 100644
index 000000000..163e96600
--- /dev/null
+++ b/docs_src/dependencies/tutorial008b.py
@@ -0,0 +1,30 @@
+from fastapi import Depends, FastAPI, HTTPException
+
+app = FastAPI()
+
+
+data = {
+ "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
+ "portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
+}
+
+
+class OwnerError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except OwnerError as e:
+ raise HTTPException(status_code=400, detail=f"Owner error: {e}")
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: str = Depends(get_username)):
+ if item_id not in data:
+ raise HTTPException(status_code=404, detail="Item not found")
+ item = data[item_id]
+ if item["owner"] != username:
+ raise OwnerError(username)
+ return item
diff --git a/docs_src/dependencies/tutorial008b_an.py b/docs_src/dependencies/tutorial008b_an.py
new file mode 100644
index 000000000..84d8f12c1
--- /dev/null
+++ b/docs_src/dependencies/tutorial008b_an.py
@@ -0,0 +1,31 @@
+from fastapi import Depends, FastAPI, HTTPException
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+data = {
+ "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
+ "portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
+}
+
+
+class OwnerError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except OwnerError as e:
+ raise HTTPException(status_code=400, detail=f"Owner error: {e}")
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
+ if item_id not in data:
+ raise HTTPException(status_code=404, detail="Item not found")
+ item = data[item_id]
+ if item["owner"] != username:
+ raise OwnerError(username)
+ return item
diff --git a/docs_src/dependencies/tutorial008b_an_py39.py b/docs_src/dependencies/tutorial008b_an_py39.py
new file mode 100644
index 000000000..3b8434c81
--- /dev/null
+++ b/docs_src/dependencies/tutorial008b_an_py39.py
@@ -0,0 +1,32 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, HTTPException
+
+app = FastAPI()
+
+
+data = {
+ "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
+ "portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
+}
+
+
+class OwnerError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except OwnerError as e:
+ raise HTTPException(status_code=400, detail=f"Owner error: {e}")
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
+ if item_id not in data:
+ raise HTTPException(status_code=404, detail="Item not found")
+ item = data[item_id]
+ if item["owner"] != username:
+ raise OwnerError(username)
+ return item
diff --git a/docs_src/generate_clients/tutorial004.js b/docs_src/generate_clients/tutorial004.js
new file mode 100644
index 000000000..18dc38267
--- /dev/null
+++ b/docs_src/generate_clients/tutorial004.js
@@ -0,0 +1,29 @@
+import * as fs from "fs";
+
+const filePath = "./openapi.json";
+
+fs.readFile(filePath, (err, data) => {
+ const openapiContent = JSON.parse(data);
+ if (err) throw err;
+
+ const paths = openapiContent.paths;
+
+ Object.keys(paths).forEach((pathKey) => {
+ const pathData = paths[pathKey];
+ Object.keys(pathData).forEach((method) => {
+ const operation = pathData[method];
+ if (operation.tags && operation.tags.length > 0) {
+ const tag = operation.tags[0];
+ const operationId = operation.operationId;
+ const toRemove = `${tag}-`;
+ if (operationId.startsWith(toRemove)) {
+ const newOperationId = operationId.substring(toRemove.length);
+ operation.operationId = newOperationId;
+ }
+ }
+ });
+ });
+ fs.writeFile(filePath, JSON.stringify(openapiContent, null, 2), (err) => {
+ if (err) throw err;
+ });
+});
diff --git a/docs_src/header_params/tutorial002_an.py b/docs_src/header_params/tutorial002_an.py
index 65d972d46..82fe49ba2 100644
--- a/docs_src/header_params/tutorial002_an.py
+++ b/docs_src/header_params/tutorial002_an.py
@@ -10,6 +10,6 @@ app = FastAPI()
async def read_items(
strange_header: Annotated[
Union[str, None], Header(convert_underscores=False)
- ] = None
+ ] = None,
):
return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial002_an_py39.py b/docs_src/header_params/tutorial002_an_py39.py
index 7f6a99f9c..008e4b6e1 100644
--- a/docs_src/header_params/tutorial002_an_py39.py
+++ b/docs_src/header_params/tutorial002_an_py39.py
@@ -9,6 +9,6 @@ app = FastAPI()
async def read_items(
strange_header: Annotated[
Union[str, None], Header(convert_underscores=False)
- ] = None
+ ] = None,
):
return {"strange_header": strange_header}
diff --git a/docs_src/openapi_webhooks/tutorial001.py b/docs_src/openapi_webhooks/tutorial001.py
index 5016f5b00..55822bb48 100644
--- a/docs_src/openapi_webhooks/tutorial001.py
+++ b/docs_src/openapi_webhooks/tutorial001.py
@@ -8,7 +8,7 @@ app = FastAPI()
class Subscription(BaseModel):
username: str
- montly_fee: float
+ monthly_fee: float
start_date: datetime
diff --git a/docs_src/python_types/tutorial011.py b/docs_src/python_types/tutorial011.py
index c8634cbff..297a84db6 100644
--- a/docs_src/python_types/tutorial011.py
+++ b/docs_src/python_types/tutorial011.py
@@ -6,7 +6,7 @@ from pydantic import BaseModel
class User(BaseModel):
id: int
- name = "John Doe"
+ name: str = "John Doe"
signup_ts: Union[datetime, None] = None
friends: List[int] = []
diff --git a/docs_src/python_types/tutorial011_py310.py b/docs_src/python_types/tutorial011_py310.py
index 7f173880f..842760c60 100644
--- a/docs_src/python_types/tutorial011_py310.py
+++ b/docs_src/python_types/tutorial011_py310.py
@@ -5,7 +5,7 @@ from pydantic import BaseModel
class User(BaseModel):
id: int
- name = "John Doe"
+ name: str = "John Doe"
signup_ts: datetime | None = None
friends: list[int] = []
diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py
index 468496f51..4eb40b405 100644
--- a/docs_src/python_types/tutorial011_py39.py
+++ b/docs_src/python_types/tutorial011_py39.py
@@ -6,7 +6,7 @@ from pydantic import BaseModel
class User(BaseModel):
id: int
- name = "John Doe"
+ name: str = "John Doe"
signup_ts: Union[datetime, None] = None
friends: list[int] = []
diff --git a/docs_src/query_params_str_validations/tutorial004.py b/docs_src/query_params_str_validations/tutorial004.py
index 3639b6c38..64a647a16 100644
--- a/docs_src/query_params_str_validations/tutorial004.py
+++ b/docs_src/query_params_str_validations/tutorial004.py
@@ -9,7 +9,7 @@ app = FastAPI()
async def read_items(
q: Union[str, None] = Query(
default=None, min_length=3, max_length=50, pattern="^fixedquery$"
- )
+ ),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial004_an.py b/docs_src/query_params_str_validations/tutorial004_an.py
index 24698c7b3..c75d45d63 100644
--- a/docs_src/query_params_str_validations/tutorial004_an.py
+++ b/docs_src/query_params_str_validations/tutorial004_an.py
@@ -10,7 +10,7 @@ app = FastAPI()
async def read_items(
q: Annotated[
Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$")
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial004_an_py310.py b/docs_src/query_params_str_validations/tutorial004_an_py310.py
index b7b629ee8..20cf1988f 100644
--- a/docs_src/query_params_str_validations/tutorial004_an_py310.py
+++ b/docs_src/query_params_str_validations/tutorial004_an_py310.py
@@ -9,7 +9,7 @@ app = FastAPI()
async def read_items(
q: Annotated[
str | None, Query(min_length=3, max_length=50, pattern="^fixedquery$")
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py b/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py
index 8fd375b3d..21e0d3eb8 100644
--- a/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py
+++ b/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py
@@ -9,7 +9,7 @@ app = FastAPI()
async def read_items(
q: Annotated[
str | None, Query(min_length=3, max_length=50, regex="^fixedquery$")
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial004_an_py39.py b/docs_src/query_params_str_validations/tutorial004_an_py39.py
index 8e9a6fc32..de27097b3 100644
--- a/docs_src/query_params_str_validations/tutorial004_an_py39.py
+++ b/docs_src/query_params_str_validations/tutorial004_an_py39.py
@@ -9,7 +9,7 @@ app = FastAPI()
async def read_items(
q: Annotated[
Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$")
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial004_py310.py b/docs_src/query_params_str_validations/tutorial004_py310.py
index f80798bcb..7801e7500 100644
--- a/docs_src/query_params_str_validations/tutorial004_py310.py
+++ b/docs_src/query_params_str_validations/tutorial004_py310.py
@@ -5,8 +5,9 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: str
- | None = Query(default=None, min_length=3, max_length=50, pattern="^fixedquery$")
+ q: str | None = Query(
+ default=None, min_length=3, max_length=50, pattern="^fixedquery$"
+ ),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial008.py b/docs_src/query_params_str_validations/tutorial008.py
index d112a9ab8..e3e0b50aa 100644
--- a/docs_src/query_params_str_validations/tutorial008.py
+++ b/docs_src/query_params_str_validations/tutorial008.py
@@ -12,7 +12,7 @@ async def read_items(
title="Query string",
description="Query string for the items to search in the database that have a good match",
min_length=3,
- )
+ ),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial008_an.py b/docs_src/query_params_str_validations/tutorial008_an.py
index 5699f1e88..01606a920 100644
--- a/docs_src/query_params_str_validations/tutorial008_an.py
+++ b/docs_src/query_params_str_validations/tutorial008_an.py
@@ -15,7 +15,7 @@ async def read_items(
description="Query string for the items to search in the database that have a good match",
min_length=3,
),
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial008_an_py310.py b/docs_src/query_params_str_validations/tutorial008_an_py310.py
index 4aaadf8b4..44b3082b6 100644
--- a/docs_src/query_params_str_validations/tutorial008_an_py310.py
+++ b/docs_src/query_params_str_validations/tutorial008_an_py310.py
@@ -14,7 +14,7 @@ async def read_items(
description="Query string for the items to search in the database that have a good match",
min_length=3,
),
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial008_an_py39.py b/docs_src/query_params_str_validations/tutorial008_an_py39.py
index 1c3b36176..f3f2f2c0e 100644
--- a/docs_src/query_params_str_validations/tutorial008_an_py39.py
+++ b/docs_src/query_params_str_validations/tutorial008_an_py39.py
@@ -14,7 +14,7 @@ async def read_items(
description="Query string for the items to search in the database that have a good match",
min_length=3,
),
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial008_py310.py b/docs_src/query_params_str_validations/tutorial008_py310.py
index 489f631d5..574385272 100644
--- a/docs_src/query_params_str_validations/tutorial008_py310.py
+++ b/docs_src/query_params_str_validations/tutorial008_py310.py
@@ -5,13 +5,12 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: str
- | None = Query(
+ q: str | None = Query(
default=None,
title="Query string",
description="Query string for the items to search in the database that have a good match",
min_length=3,
- )
+ ),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial010.py b/docs_src/query_params_str_validations/tutorial010.py
index 3314f8b6d..ff29176fe 100644
--- a/docs_src/query_params_str_validations/tutorial010.py
+++ b/docs_src/query_params_str_validations/tutorial010.py
@@ -16,7 +16,7 @@ async def read_items(
max_length=50,
pattern="^fixedquery$",
deprecated=True,
- )
+ ),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial010_an.py b/docs_src/query_params_str_validations/tutorial010_an.py
index c5df00897..ed343230f 100644
--- a/docs_src/query_params_str_validations/tutorial010_an.py
+++ b/docs_src/query_params_str_validations/tutorial010_an.py
@@ -19,7 +19,7 @@ async def read_items(
pattern="^fixedquery$",
deprecated=True,
),
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial010_an_py310.py b/docs_src/query_params_str_validations/tutorial010_an_py310.py
index a8e8c099b..775095bda 100644
--- a/docs_src/query_params_str_validations/tutorial010_an_py310.py
+++ b/docs_src/query_params_str_validations/tutorial010_an_py310.py
@@ -18,7 +18,7 @@ async def read_items(
pattern="^fixedquery$",
deprecated=True,
),
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial010_an_py39.py b/docs_src/query_params_str_validations/tutorial010_an_py39.py
index 955880dd6..b126c116f 100644
--- a/docs_src/query_params_str_validations/tutorial010_an_py39.py
+++ b/docs_src/query_params_str_validations/tutorial010_an_py39.py
@@ -18,7 +18,7 @@ async def read_items(
pattern="^fixedquery$",
deprecated=True,
),
- ] = None
+ ] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial010_py310.py b/docs_src/query_params_str_validations/tutorial010_py310.py
index 9ea7b3c49..530e6cf5b 100644
--- a/docs_src/query_params_str_validations/tutorial010_py310.py
+++ b/docs_src/query_params_str_validations/tutorial010_py310.py
@@ -5,8 +5,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: str
- | None = Query(
+ q: str | None = Query(
default=None,
alias="item-query",
title="Query string",
@@ -15,7 +14,7 @@ async def read_items(
max_length=50,
pattern="^fixedquery$",
deprecated=True,
- )
+ ),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/schema_extra_example/tutorial005.py b/docs_src/schema_extra_example/tutorial005.py
new file mode 100644
index 000000000..b8217c27e
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial005.py
@@ -0,0 +1,51 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Item = Body(
+ openapi_examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial005_an.py b/docs_src/schema_extra_example/tutorial005_an.py
new file mode 100644
index 000000000..4b2d9c662
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial005_an.py
@@ -0,0 +1,55 @@
+from typing import Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ openapi_examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial005_an_py310.py b/docs_src/schema_extra_example/tutorial005_an_py310.py
new file mode 100644
index 000000000..64dc2cf90
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial005_an_py310.py
@@ -0,0 +1,54 @@
+from typing import Annotated
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ openapi_examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial005_an_py39.py b/docs_src/schema_extra_example/tutorial005_an_py39.py
new file mode 100644
index 000000000..edeb1affc
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial005_an_py39.py
@@ -0,0 +1,54 @@
+from typing import Annotated, Union
+
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+ price: float
+ tax: Union[float, None] = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Annotated[
+ Item,
+ Body(
+ openapi_examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+ ],
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/schema_extra_example/tutorial005_py310.py b/docs_src/schema_extra_example/tutorial005_py310.py
new file mode 100644
index 000000000..eef973343
--- /dev/null
+++ b/docs_src/schema_extra_example/tutorial005_py310.py
@@ -0,0 +1,49 @@
+from fastapi import Body, FastAPI
+from pydantic import BaseModel
+
+app = FastAPI()
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+ price: float
+ tax: float | None = None
+
+
+@app.put("/items/{item_id}")
+async def update_item(
+ *,
+ item_id: int,
+ item: Item = Body(
+ openapi_examples={
+ "normal": {
+ "summary": "A normal example",
+ "description": "A **normal** item works correctly.",
+ "value": {
+ "name": "Foo",
+ "description": "A very nice Item",
+ "price": 35.4,
+ "tax": 3.2,
+ },
+ },
+ "converted": {
+ "summary": "An example with converted data",
+ "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
+ "value": {
+ "name": "Bar",
+ "price": "35.4",
+ },
+ },
+ "invalid": {
+ "summary": "Invalid data is rejected with an error",
+ "value": {
+ "name": "Baz",
+ "price": "thirty five point four",
+ },
+ },
+ },
+ ),
+):
+ results = {"item_id": item_id, "item": item}
+ return results
diff --git a/docs_src/separate_openapi_schemas/tutorial001.py b/docs_src/separate_openapi_schemas/tutorial001.py
new file mode 100644
index 000000000..415eef8e2
--- /dev/null
+++ b/docs_src/separate_openapi_schemas/tutorial001.py
@@ -0,0 +1,28 @@
+from typing import List, Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+
+
+app = FastAPI()
+
+
+@app.post("/items/")
+def create_item(item: Item):
+ return item
+
+
+@app.get("/items/")
+def read_items() -> List[Item]:
+ return [
+ Item(
+ name="Portal Gun",
+ description="Device to travel through the multi-rick-verse",
+ ),
+ Item(name="Plumbus"),
+ ]
diff --git a/docs_src/separate_openapi_schemas/tutorial001_py310.py b/docs_src/separate_openapi_schemas/tutorial001_py310.py
new file mode 100644
index 000000000..289cb54ed
--- /dev/null
+++ b/docs_src/separate_openapi_schemas/tutorial001_py310.py
@@ -0,0 +1,26 @@
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+
+app = FastAPI()
+
+
+@app.post("/items/")
+def create_item(item: Item):
+ return item
+
+
+@app.get("/items/")
+def read_items() -> list[Item]:
+ return [
+ Item(
+ name="Portal Gun",
+ description="Device to travel through the multi-rick-verse",
+ ),
+ Item(name="Plumbus"),
+ ]
diff --git a/docs_src/separate_openapi_schemas/tutorial001_py39.py b/docs_src/separate_openapi_schemas/tutorial001_py39.py
new file mode 100644
index 000000000..63cffd1e3
--- /dev/null
+++ b/docs_src/separate_openapi_schemas/tutorial001_py39.py
@@ -0,0 +1,28 @@
+from typing import Optional
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+
+class Item(BaseModel):
+ name: str
+ description: Optional[str] = None
+
+
+app = FastAPI()
+
+
+@app.post("/items/")
+def create_item(item: Item):
+ return item
+
+
+@app.get("/items/")
+def read_items() -> list[Item]:
+ return [
+ Item(
+ name="Portal Gun",
+ description="Device to travel through the multi-rick-verse",
+ ),
+ Item(name="Plumbus"),
+ ]
diff --git a/docs_src/separate_openapi_schemas/tutorial002.py b/docs_src/separate_openapi_schemas/tutorial002.py
new file mode 100644
index 000000000..7df93783b
--- /dev/null
+++ b/docs_src/separate_openapi_schemas/tutorial002.py
@@ -0,0 +1,28 @@
+from typing import List, Union
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+
+class Item(BaseModel):
+ name: str
+ description: Union[str, None] = None
+
+
+app = FastAPI(separate_input_output_schemas=False)
+
+
+@app.post("/items/")
+def create_item(item: Item):
+ return item
+
+
+@app.get("/items/")
+def read_items() -> List[Item]:
+ return [
+ Item(
+ name="Portal Gun",
+ description="Device to travel through the multi-rick-verse",
+ ),
+ Item(name="Plumbus"),
+ ]
diff --git a/docs_src/separate_openapi_schemas/tutorial002_py310.py b/docs_src/separate_openapi_schemas/tutorial002_py310.py
new file mode 100644
index 000000000..5db210872
--- /dev/null
+++ b/docs_src/separate_openapi_schemas/tutorial002_py310.py
@@ -0,0 +1,26 @@
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+
+class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+
+app = FastAPI(separate_input_output_schemas=False)
+
+
+@app.post("/items/")
+def create_item(item: Item):
+ return item
+
+
+@app.get("/items/")
+def read_items() -> list[Item]:
+ return [
+ Item(
+ name="Portal Gun",
+ description="Device to travel through the multi-rick-verse",
+ ),
+ Item(name="Plumbus"),
+ ]
diff --git a/docs_src/separate_openapi_schemas/tutorial002_py39.py b/docs_src/separate_openapi_schemas/tutorial002_py39.py
new file mode 100644
index 000000000..50d997d92
--- /dev/null
+++ b/docs_src/separate_openapi_schemas/tutorial002_py39.py
@@ -0,0 +1,28 @@
+from typing import Optional
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+
+
+class Item(BaseModel):
+ name: str
+ description: Optional[str] = None
+
+
+app = FastAPI(separate_input_output_schemas=False)
+
+
+@app.post("/items/")
+def create_item(item: Item):
+ return item
+
+
+@app.get("/items/")
+def read_items() -> list[Item]:
+ return [
+ Item(
+ name="Portal Gun",
+ description="Device to travel through the multi-rick-verse",
+ ),
+ Item(name="Plumbus"),
+ ]
diff --git a/docs_src/settings/app02/main.py b/docs_src/settings/app02/main.py
index 163aa2614..941f82e6b 100644
--- a/docs_src/settings/app02/main.py
+++ b/docs_src/settings/app02/main.py
@@ -7,7 +7,7 @@ from .config import Settings
app = FastAPI()
-@lru_cache()
+@lru_cache
def get_settings():
return Settings()
diff --git a/docs_src/settings/app02_an/main.py b/docs_src/settings/app02_an/main.py
index cb679202d..3a578cc33 100644
--- a/docs_src/settings/app02_an/main.py
+++ b/docs_src/settings/app02_an/main.py
@@ -8,7 +8,7 @@ from .config import Settings
app = FastAPI()
-@lru_cache()
+@lru_cache
def get_settings():
return Settings()
diff --git a/docs_src/settings/app02_an_py39/main.py b/docs_src/settings/app02_an_py39/main.py
index 61be74fcb..6d5db12a8 100644
--- a/docs_src/settings/app02_an_py39/main.py
+++ b/docs_src/settings/app02_an_py39/main.py
@@ -8,7 +8,7 @@ from .config import Settings
app = FastAPI()
-@lru_cache()
+@lru_cache
def get_settings():
return Settings()
diff --git a/docs_src/settings/app03/main.py b/docs_src/settings/app03/main.py
index 69bc8c6e0..ea64a5709 100644
--- a/docs_src/settings/app03/main.py
+++ b/docs_src/settings/app03/main.py
@@ -7,7 +7,7 @@ from . import config
app = FastAPI()
-@lru_cache()
+@lru_cache
def get_settings():
return config.Settings()
diff --git a/docs_src/settings/app03_an/main.py b/docs_src/settings/app03_an/main.py
index c33b98f47..2f64b9cd1 100644
--- a/docs_src/settings/app03_an/main.py
+++ b/docs_src/settings/app03_an/main.py
@@ -8,7 +8,7 @@ from . import config
app = FastAPI()
-@lru_cache()
+@lru_cache
def get_settings():
return config.Settings()
diff --git a/docs_src/settings/app03_an_py39/main.py b/docs_src/settings/app03_an_py39/main.py
index b89c6b6cf..62f347639 100644
--- a/docs_src/settings/app03_an_py39/main.py
+++ b/docs_src/settings/app03_an_py39/main.py
@@ -8,7 +8,7 @@ from . import config
app = FastAPI()
-@lru_cache()
+@lru_cache
def get_settings():
return config.Settings()
diff --git a/docs_src/templates/tutorial001.py b/docs_src/templates/tutorial001.py
index 245e7110b..81ccc8d4d 100644
--- a/docs_src/templates/tutorial001.py
+++ b/docs_src/templates/tutorial001.py
@@ -13,4 +13,6 @@ templates = Jinja2Templates(directory="templates")
@app.get("/items/{id}", response_class=HTMLResponse)
async def read_item(request: Request, id: str):
- return templates.TemplateResponse("item.html", {"request": request, "id": id})
+ return templates.TemplateResponse(
+ request=request, name="item.html", context={"id": id}
+ )
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index e9c3abe01..02ac83b5e 100644
--- a/fastapi/__init__.py
+++ b/fastapi/__init__.py
@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
-__version__ = "0.100.0"
+__version__ = "0.108.0"
from starlette import status as status
diff --git a/fastapi/_compat.py b/fastapi/_compat.py
index 01b1bcfb9..bf5861bed 100644
--- a/fastapi/_compat.py
+++ b/fastapi/_compat.py
@@ -56,12 +56,17 @@ if PYDANTIC_V2:
from pydantic.json_schema import GenerateJsonSchema as GenerateJsonSchema
from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue
from pydantic_core import CoreSchema as CoreSchema
- from pydantic_core import MultiHostUrl as MultiHostUrl
from pydantic_core import PydanticUndefined, PydanticUndefinedType
from pydantic_core import Url as Url
- from pydantic_core.core_schema import (
- general_plain_validator_function as general_plain_validator_function,
- )
+
+ try:
+ from pydantic_core.core_schema import (
+ with_info_plain_validator_function as with_info_plain_validator_function,
+ )
+ except ImportError: # pragma: no cover
+ from pydantic_core.core_schema import (
+ general_plain_validator_function as with_info_plain_validator_function, # noqa: F401
+ )
Required = PydanticUndefined
Undefined = PydanticUndefined
@@ -182,15 +187,19 @@ if PYDANTIC_V2:
field_mapping: Dict[
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
],
+ separate_input_output_schemas: bool = True,
) -> Dict[str, Any]:
+ override_mode: Union[Literal["validation"], None] = (
+ None if separate_input_output_schemas else "validation"
+ )
# This expects that GenerateJsonSchema was already used to generate the definitions
- json_schema = field_mapping[(field, field.mode)]
+ json_schema = field_mapping[(field, override_mode or field.mode)]
if "$ref" not in json_schema:
# TODO remove when deprecating Pydantic v1
# Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207
- json_schema[
- "title"
- ] = field.field_info.title or field.alias.title().replace("_", " ")
+ json_schema["title"] = (
+ field.field_info.title or field.alias.title().replace("_", " ")
+ )
return json_schema
def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
@@ -201,14 +210,19 @@ if PYDANTIC_V2:
fields: List[ModelField],
schema_generator: GenerateJsonSchema,
model_name_map: ModelNameMap,
+ separate_input_output_schemas: bool = True,
) -> Tuple[
Dict[
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
],
Dict[str, Dict[str, Any]],
]:
+ override_mode: Union[Literal["validation"], None] = (
+ None if separate_input_output_schemas else "validation"
+ )
inputs = [
- (field, field.mode, field._type_adapter.core_schema) for field in fields
+ (field, override_mode or field.mode, field._type_adapter.core_schema)
+ for field in fields
]
field_mapping, definitions = schema_generator.generate_definitions(
inputs=inputs
@@ -249,7 +263,12 @@ if PYDANTIC_V2:
return is_bytes_sequence_annotation(field.type_)
def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
- return type(field_info).from_annotation(annotation)
+ cls = type(field_info)
+ merged_field_info = cls.from_annotation(annotation)
+ new_field_info = copy(field_info)
+ new_field_info.metadata = merged_field_info.metadata
+ new_field_info.annotation = merged_field_info.annotation
+ return new_field_info
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
origin_type = (
@@ -308,9 +327,6 @@ else:
from pydantic.fields import ( # type: ignore[no-redef, attr-defined]
UndefinedType as UndefinedType, # noqa: F401
)
- from pydantic.networks import ( # type: ignore[no-redef]
- MultiHostDsn as MultiHostUrl, # noqa: F401
- )
from pydantic.schema import (
field_schema,
get_flat_models_from_fields,
@@ -354,7 +370,7 @@ else:
class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef]
pass
- def general_plain_validator_function( # type: ignore[misc]
+ def with_info_plain_validator_function( # type: ignore[misc]
function: Callable[..., Any],
*,
ref: Union[str, None] = None,
@@ -447,6 +463,7 @@ else:
field_mapping: Dict[
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
],
+ separate_input_output_schemas: bool = True,
) -> Dict[str, Any]:
# This expects that GenerateJsonSchema was already used to generate the definitions
return field_schema( # type: ignore[no-any-return]
@@ -462,6 +479,7 @@ else:
fields: List[ModelField],
schema_generator: GenerateJsonSchema,
model_name_map: ModelNameMap,
+ separate_input_output_schemas: bool = True,
) -> Tuple[
Dict[
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
diff --git a/fastapi/applications.py b/fastapi/applications.py
index e32cfa03d..597c60a56 100644
--- a/fastapi/applications.py
+++ b/fastapi/applications.py
@@ -22,7 +22,6 @@ from fastapi.exception_handlers import (
)
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
from fastapi.logger import logger
-from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware
from fastapi.openapi.docs import (
get_redoc_html,
get_swagger_ui_html,
@@ -37,62 +36,789 @@ from starlette.datastructures import State
from starlette.exceptions import HTTPException
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
-from starlette.middleware.errors import ServerErrorMiddleware
-from starlette.middleware.exceptions import ExceptionMiddleware
from starlette.requests import Request
from starlette.responses import HTMLResponse, JSONResponse, Response
from starlette.routing import BaseRoute
from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
+from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined]
AppType = TypeVar("AppType", bound="FastAPI")
class FastAPI(Starlette):
+ """
+ `FastAPI` app class, the main entrypoint to use FastAPI.
+
+ Read more in the
+ [FastAPI docs for First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+ ```
+ """
+
def __init__(
self: AppType,
*,
- debug: bool = False,
- routes: Optional[List[BaseRoute]] = None,
- title: str = "FastAPI",
- summary: Optional[str] = None,
- description: str = "",
- version: str = "0.1.0",
- openapi_url: Optional[str] = "/openapi.json",
- openapi_tags: Optional[List[Dict[str, Any]]] = None,
- servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- default_response_class: Type[Response] = Default(JSONResponse),
- redirect_slashes: bool = True,
- docs_url: Optional[str] = "/docs",
- redoc_url: Optional[str] = "/redoc",
- swagger_ui_oauth2_redirect_url: Optional[str] = "/docs/oauth2-redirect",
- swagger_ui_init_oauth: Optional[Dict[str, Any]] = None,
- middleware: Optional[Sequence[Middleware]] = None,
- exception_handlers: Optional[
- Dict[
- Union[int, Type[Exception]],
- Callable[[Request, Any], Coroutine[Any, Any, Response]],
- ]
- ] = None,
- on_startup: Optional[Sequence[Callable[[], Any]]] = None,
- on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
- lifespan: Optional[Lifespan[AppType]] = None,
- terms_of_service: Optional[str] = None,
- contact: Optional[Dict[str, Union[str, Any]]] = None,
- license_info: Optional[Dict[str, Union[str, Any]]] = None,
- openapi_prefix: str = "",
- root_path: str = "",
- root_path_in_servers: bool = True,
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- webhooks: Optional[routing.APIRouter] = None,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- swagger_ui_parameters: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
- **extra: Any,
+ debug: Annotated[
+ bool,
+ Doc(
+ """
+ Boolean indicating if debug tracebacks should be returned on server
+ errors.
+
+ Read more in the
+ [Starlette docs for Applications](https://www.starlette.io/applications/#instantiating-the-application).
+ """
+ ),
+ ] = False,
+ routes: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ **Note**: you probably shouldn't use this parameter, it is inherited
+ from Starlette and supported for compatibility.
+
+ ---
+
+ A list of routes to serve incoming HTTP and WebSocket requests.
+ """
+ ),
+ deprecated(
+ """
+ You normally wouldn't use this parameter with FastAPI, it is inherited
+ from Starlette and supported for compatibility.
+
+ In FastAPI, you normally would use the *path operation methods*,
+ like `app.get()`, `app.post()`, etc.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The title of the API.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(title="ChimichangApp")
+ ```
+ """
+ ),
+ ] = "FastAPI",
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A short summary of the API.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(summary="Deadpond's favorite app. Nuff said.")
+ ```
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ str,
+ Doc(
+ '''
+ A description of the API. Supports Markdown (using
+ [CommonMark syntax](https://commonmark.org/)).
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(
+ description="""
+ ChimichangApp API helps you do awesome stuff. 🚀
+
+ ## Items
+
+ You can **read items**.
+
+ ## Users
+
+ You will be able to:
+
+ * **Create users** (_not implemented_).
+ * **Read users** (_not implemented_).
+
+ """
+ )
+ ```
+ '''
+ ),
+ ] = "",
+ version: Annotated[
+ str,
+ Doc(
+ """
+ The version of the API.
+
+ **Note** This is the version of your application, not the version of
+ the OpenAPI specification nor the version of FastAPI being used.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(version="0.0.1")
+ ```
+ """
+ ),
+ ] = "0.1.0",
+ openapi_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The URL where the OpenAPI schema will be served from.
+
+ If you set it to `None`, no OpenAPI schema will be served publicly, and
+ the default automatic endpoints `/docs` and `/redoc` will also be
+ disabled.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#openapi-url).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(openapi_url="/api/v1/openapi.json")
+ ```
+ """
+ ),
+ ] = "/openapi.json",
+ openapi_tags: Annotated[
+ Optional[List[Dict[str, Any]]],
+ Doc(
+ """
+ A list of tags used by OpenAPI, these are the same `tags` you can set
+ in the *path operations*, like:
+
+ * `@app.get("/users/", tags=["users"])`
+ * `@app.get("/items/", tags=["items"])`
+
+ The order of the tags can be used to specify the order shown in
+ tools like Swagger UI, used in the automatic path `/docs`.
+
+ It's not required to specify all the tags used.
+
+ The tags that are not declared MAY be organized randomly or based
+ on the tools' logic. Each tag name in the list MUST be unique.
+
+ The value of each item is a `dict` containing:
+
+ * `name`: The name of the tag.
+ * `description`: A short description of the tag.
+ [CommonMark syntax](https://commonmark.org/) MAY be used for rich
+ text representation.
+ * `externalDocs`: Additional external documentation for this tag. If
+ provided, it would contain a `dict` with:
+ * `description`: A short description of the target documentation.
+ [CommonMark syntax](https://commonmark.org/) MAY be used for
+ rich text representation.
+ * `url`: The URL for the target documentation. Value MUST be in
+ the form of a URL.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-tags).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ tags_metadata = [
+ {
+ "name": "users",
+ "description": "Operations with users. The **login** logic is also here.",
+ },
+ {
+ "name": "items",
+ "description": "Manage items. So _fancy_ they have their own docs.",
+ "externalDocs": {
+ "description": "Items external docs",
+ "url": "https://fastapi.tiangolo.com/",
+ },
+ },
+ ]
+
+ app = FastAPI(openapi_tags=tags_metadata)
+ ```
+ """
+ ),
+ ] = None,
+ servers: Annotated[
+ Optional[List[Dict[str, Union[str, Any]]]],
+ Doc(
+ """
+ A `list` of `dict`s with connectivity information to a target server.
+
+ You would use it, for example, if your application is served from
+ different domains and you want to use the same Swagger UI in the
+ browser to interact with each of them (instead of having multiple
+ browser tabs open). Or if you want to leave fixed the possible URLs.
+
+ If the servers `list` is not provided, or is an empty `list`, the
+ default value would be a a `dict` with a `url` value of `/`.
+
+ Each item in the `list` is a `dict` containing:
+
+ * `url`: A URL to the target host. This URL supports Server Variables
+ and MAY be relative, to indicate that the host location is relative
+ to the location where the OpenAPI document is being served. Variable
+ substitutions will be made when a variable is named in `{`brackets`}`.
+ * `description`: An optional string describing the host designated by
+ the URL. [CommonMark syntax](https://commonmark.org/) MAY be used for
+ rich text representation.
+ * `variables`: A `dict` between a variable name and its value. The value
+ is used for substitution in the server's URL template.
+
+ Read more in the
+ [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(
+ servers=[
+ {"url": "https://stag.example.com", "description": "Staging environment"},
+ {"url": "https://prod.example.com", "description": "Production environment"},
+ ]
+ )
+ ```
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of global dependencies, they will be applied to each
+ *path operation*, including in sub-routers.
+
+ Read more about it in the
+ [FastAPI docs for Global Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/global-dependencies/).
+
+ **Example**
+
+ ```python
+ from fastapi import Depends, FastAPI
+
+ from .dependencies import func_dep_1, func_dep_2
+
+ app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)])
+ ```
+ """
+ ),
+ ] = None,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ The default response class to be used.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+ from fastapi.responses import ORJSONResponse
+
+ app = FastAPI(default_response_class=ORJSONResponse)
+ ```
+ """
+ ),
+ ] = Default(JSONResponse),
+ redirect_slashes: Annotated[
+ bool,
+ Doc(
+ """
+ Whether to detect and redirect slashes in URLs when the client doesn't
+ use the same format.
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(redirect_slashes=True) # the default
+
+ @app.get("/items/")
+ async def read_items():
+ return [{"item_id": "Foo"}]
+ ```
+
+ With this app, if a client goes to `/items` (without a trailing slash),
+ they will be automatically redirected with an HTTP status code of 307
+ to `/items/`.
+ """
+ ),
+ ] = True,
+ docs_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The path to the automatic interactive API documentation.
+ It is handled in the browser by Swagger UI.
+
+ The default URL is `/docs`. You can disable it by setting it to `None`.
+
+ If `openapi_url` is set to `None`, this will be automatically disabled.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(docs_url="/documentation", redoc_url=None)
+ ```
+ """
+ ),
+ ] = "/docs",
+ redoc_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The path to the alternative automatic interactive API documentation
+ provided by ReDoc.
+
+ The default URL is `/redoc`. You can disable it by setting it to `None`.
+
+ If `openapi_url` is set to `None`, this will be automatically disabled.
+
+ Read more in the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(docs_url="/documentation", redoc_url="redocumentation")
+ ```
+ """
+ ),
+ ] = "/redoc",
+ swagger_ui_oauth2_redirect_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The OAuth2 redirect endpoint for the Swagger UI.
+
+ By default it is `/docs/oauth2-redirect`.
+
+ This is only used if you use OAuth2 (with the "Authorize" button)
+ with Swagger UI.
+ """
+ ),
+ ] = "/docs/oauth2-redirect",
+ swagger_ui_init_oauth: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ OAuth2 configuration for the Swagger UI, by default shown at `/docs`.
+
+ Read more about the available configuration options in the
+ [Swagger UI docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/).
+ """
+ ),
+ ] = None,
+ middleware: Annotated[
+ Optional[Sequence[Middleware]],
+ Doc(
+ """
+ List of middleware to be added when creating the application.
+
+ In FastAPI you would normally do this with `app.add_middleware()`
+ instead.
+
+ Read more in the
+ [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/).
+ """
+ ),
+ ] = None,
+ exception_handlers: Annotated[
+ Optional[
+ Dict[
+ Union[int, Type[Exception]],
+ Callable[[Request, Any], Coroutine[Any, Any, Response]],
+ ]
+ ],
+ Doc(
+ """
+ A dictionary with handlers for exceptions.
+
+ In FastAPI, you would normally use the decorator
+ `@app.exception_handler()`.
+
+ Read more in the
+ [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
+ """
+ ),
+ ] = None,
+ on_startup: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of startup event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ on_shutdown: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of shutdown event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ lifespan: Annotated[
+ Optional[Lifespan[AppType]],
+ Doc(
+ """
+ A `Lifespan` context manager handler. This replaces `startup` and
+ `shutdown` functions with a single context manager.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ terms_of_service: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A URL to the Terms of Service for your API.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more at the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ app = FastAPI(terms_of_service="http://example.com/terms/")
+ ```
+ """
+ ),
+ ] = None,
+ contact: Annotated[
+ Optional[Dict[str, Union[str, Any]]],
+ Doc(
+ """
+ A dictionary with the contact information for the exposed API.
+
+ It can contain several fields.
+
+ * `name`: (`str`) The name of the contact person/organization.
+ * `url`: (`str`) A URL pointing to the contact information. MUST be in
+ the format of a URL.
+ * `email`: (`str`) The email address of the contact person/organization.
+ MUST be in the format of an email address.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more at the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ app = FastAPI(
+ contact={
+ "name": "Deadpoolio the Amazing",
+ "url": "http://x-force.example.com/contact/",
+ "email": "dp@x-force.example.com",
+ }
+ )
+ ```
+ """
+ ),
+ ] = None,
+ license_info: Annotated[
+ Optional[Dict[str, Union[str, Any]]],
+ Doc(
+ """
+ A dictionary with the license information for the exposed API.
+
+ It can contain several fields.
+
+ * `name`: (`str`) **REQUIRED** (if a `license_info` is set). The
+ license name used for the API.
+ * `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression
+ for the API. The `identifier` field is mutually exclusive of the `url`
+ field. Available since OpenAPI 3.1.0, FastAPI 0.99.0.
+ * `url`: (`str`) A URL to the license used for the API. This MUST be
+ the format of a URL.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more at the
+ [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api).
+
+ **Example**
+
+ ```python
+ app = FastAPI(
+ license_info={
+ "name": "Apache 2.0",
+ "url": "https://www.apache.org/licenses/LICENSE-2.0.html",
+ }
+ )
+ ```
+ """
+ ),
+ ] = None,
+ openapi_prefix: Annotated[
+ str,
+ Doc(
+ """
+ A URL prefix for the OpenAPI URL.
+ """
+ ),
+ deprecated(
+ """
+ "openapi_prefix" has been deprecated in favor of "root_path", which
+ follows more closely the ASGI standard, is simpler, and more
+ automatic.
+ """
+ ),
+ ] = "",
+ root_path: Annotated[
+ str,
+ Doc(
+ """
+ A path prefix handled by a proxy that is not seen by the application
+ but is seen by external clients, which affects things like Swagger UI.
+
+ Read more about it at the
+ [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(root_path="/api/v1")
+ ```
+ """
+ ),
+ ] = "",
+ root_path_in_servers: Annotated[
+ bool,
+ Doc(
+ """
+ To disable automatically generating the URLs in the `servers` field
+ in the autogenerated OpenAPI using the `root_path`.
+
+ Read more about it in the
+ [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#disable-automatic-server-from-root_path).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI(root_path_in_servers=False)
+ ```
+ """
+ ),
+ ] = True,
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ OpenAPI callbacks that should apply to all *path operations*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ webhooks: Annotated[
+ Optional[routing.APIRouter],
+ Doc(
+ """
+ Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't
+ depend on specific *path operations*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ **Note**: This is available since OpenAPI 3.1.0, FastAPI 0.99.0.
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all *path operations* as deprecated. You probably don't need it,
+ but it's available.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) all the *path operations* in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ swagger_ui_parameters: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Parameters to configure Swagger UI, the autogenerated interactive API
+ documentation (by default at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs about how to Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ separate_input_output_schemas: Annotated[
+ bool,
+ Doc(
+ """
+ Whether to generate separate OpenAPI schemas for request body and
+ response body when the results would be more precise.
+
+ This is particularly useful when automatically generating clients.
+
+ For example, if you have a model like:
+
+ ```python
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ tags: list[str] = []
+ ```
+
+ When `Item` is used for input, a request body, `tags` is not required,
+ the client doesn't have to provide it.
+
+ But when using `Item` for output, for a response body, `tags` is always
+ available because it has a default value, even if it's just an empty
+ list. So, the client should be able to always expect it.
+
+ In this case, there would be two different schemas, one for input and
+ another one for output.
+ """
+ ),
+ ] = True,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Extra keyword arguments to be stored in the app, not used by FastAPI
+ anywhere.
+ """
+ ),
+ ],
) -> None:
self.debug = debug
self.title = title
@@ -111,8 +837,39 @@ class FastAPI(Starlette):
self.swagger_ui_init_oauth = swagger_ui_init_oauth
self.swagger_ui_parameters = swagger_ui_parameters
self.servers = servers or []
+ self.separate_input_output_schemas = separate_input_output_schemas
self.extra = extra
- self.openapi_version = "3.1.0"
+ self.openapi_version: Annotated[
+ str,
+ Doc(
+ """
+ The version string of OpenAPI.
+
+ FastAPI will generate OpenAPI version 3.1.0, and will output that as
+ the OpenAPI version. But some tools, even though they might be
+ compatible with OpenAPI 3.1.0, might not recognize it as a valid.
+
+ So you could override this value to trick those tools into using
+ the generated OpenAPI. Have in mind that this is a hack. But if you
+ avoid using features added in OpenAPI 3.1.0, it might work for your
+ use case.
+
+ This is not passed as a parameter to the `FastAPI` class to avoid
+ giving the false idea that FastAPI would generate a different OpenAPI
+ schema. It is only available as an attribute.
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ app.openapi_version = "3.0.2"
+ ```
+ """
+ ),
+ ] = "3.1.0"
self.openapi_schema: Optional[Dict[str, Any]] = None
if self.openapi_url:
assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'"
@@ -125,10 +882,53 @@ class FastAPI(Starlette):
"automatic. Check the docs at "
"https://fastapi.tiangolo.com/advanced/sub-applications/"
)
- self.webhooks = webhooks or routing.APIRouter()
+ self.webhooks: Annotated[
+ routing.APIRouter,
+ Doc(
+ """
+ The `app.webhooks` attribute is an `APIRouter` with the *path
+ operations* that will be used just for documentation of webhooks.
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/).
+ """
+ ),
+ ] = webhooks or routing.APIRouter()
self.root_path = root_path or openapi_prefix
- self.state: State = State()
- self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
+ self.state: Annotated[
+ State,
+ Doc(
+ """
+ A state object for the application. This is the same object for the
+ entire application, it doesn't change from request to request.
+
+ You normally woudln't use this in FastAPI, for most of the cases you
+ would instead use FastAPI dependencies.
+
+ This is simply inherited from Starlette.
+
+ Read more about it in the
+ [Starlette docs for Applications](https://www.starlette.io/applications/#storing-state-on-the-app-instance).
+ """
+ ),
+ ] = State()
+ self.dependency_overrides: Annotated[
+ Dict[Callable[..., Any], Callable[..., Any]],
+ Doc(
+ """
+ A dictionary with overrides for the dependencies.
+
+ Each key is the original dependency callable, and the value is the
+ actual dependency that should be called.
+
+ This is for testing, to replace expensive dependencies with testing
+ versions.
+
+ Read more about it in the
+ [FastAPI docs for Testing Dependencies with Overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/).
+ """
+ ),
+ ] = {}
self.router: routing.APIRouter = routing.APIRouter(
routes=routes,
redirect_slashes=redirect_slashes,
@@ -146,7 +946,7 @@ class FastAPI(Starlette):
)
self.exception_handlers: Dict[
Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]]
- ] = ({} if exception_handlers is None else dict(exception_handlers))
+ ] = {} if exception_handlers is None else dict(exception_handlers)
self.exception_handlers.setdefault(HTTPException, http_exception_handler)
self.exception_handlers.setdefault(
RequestValidationError, request_validation_exception_handler
@@ -163,56 +963,20 @@ class FastAPI(Starlette):
self.middleware_stack: Union[ASGIApp, None] = None
self.setup()
- def build_middleware_stack(self) -> ASGIApp:
- # Duplicate/override from Starlette to add AsyncExitStackMiddleware
- # inside of ExceptionMiddleware, inside of custom user middlewares
- debug = self.debug
- error_handler = None
- exception_handlers = {}
-
- for key, value in self.exception_handlers.items():
- if key in (500, Exception):
- error_handler = value
- else:
- exception_handlers[key] = value
-
- middleware = (
- [Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)]
- + self.user_middleware
- + [
- Middleware(
- ExceptionMiddleware, handlers=exception_handlers, debug=debug
- ),
- # Add FastAPI-specific AsyncExitStackMiddleware for dependencies with
- # contextvars.
- # This needs to happen after user middlewares because those create a
- # new contextvars context copy by using a new AnyIO task group.
- # The initial part of dependencies with yield is executed in the
- # FastAPI code, inside all the middlewares, but the teardown part
- # (after yield) is executed in the AsyncExitStack in this middleware,
- # if the AsyncExitStack lived outside of the custom middlewares and
- # contextvars were set in a dependency with yield in that internal
- # contextvars context, the values would not be available in the
- # outside context of the AsyncExitStack.
- # By putting the middleware and the AsyncExitStack here, inside all
- # user middlewares, the code before and after yield in dependencies
- # with yield is executed in the same contextvars context, so all values
- # set in contextvars before yield is still available after yield as
- # would be expected.
- # Additionally, by having this AsyncExitStack here, after the
- # ExceptionMiddleware, now dependencies can catch handled exceptions,
- # e.g. HTTPException, to customize the teardown code (e.g. DB session
- # rollback).
- Middleware(AsyncExitStackMiddleware),
- ]
- )
+ def openapi(self) -> Dict[str, Any]:
+ """
+ Generate the OpenAPI schema of the application. This is called by FastAPI
+ internally.
- app = self.router
- for cls, options in reversed(middleware):
- app = cls(app=app, **options)
- return app
+ The first time it is called it stores the result in the attribute
+ `app.openapi_schema`, and next times it is called, it just returns that same
+ result. To avoid the cost of generating the schema every time.
- def openapi(self) -> Dict[str, Any]:
+ If you need to modify the generated OpenAPI schema, you could modify it.
+
+ Read more in the
+ [FastAPI docs for OpenAPI](https://fastapi.tiangolo.com/how-to/extending-openapi/).
+ """
if not self.openapi_schema:
self.openapi_schema = get_openapi(
title=self.title,
@@ -227,6 +991,7 @@ class FastAPI(Starlette):
webhooks=self.webhooks.routes,
tags=self.openapi_tags,
servers=self.servers,
+ separate_input_output_schemas=self.separate_input_output_schemas,
)
return self.openapi_schema
@@ -424,11 +1189,58 @@ class FastAPI(Starlette):
def websocket(
self,
- path: str,
- name: Optional[str] = None,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ WebSocket path.
+ """
+ ),
+ ],
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A name for the WebSocket. Only used internally.
+ """
+ ),
+ ] = None,
*,
- dependencies: Optional[Sequence[Depends]] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be used for this
+ WebSocket.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+ """
+ ),
+ ] = None,
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Decorate a WebSocket function.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI, WebSocket
+
+ app = FastAPI()
+
+ @app.websocket("/ws")
+ async def websocket_endpoint(websocket: WebSocket):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(f"Message text was: {data}")
+ ```
+ """
+
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.add_api_websocket_route(
path,
@@ -442,64 +1254,558 @@ class FastAPI(Starlette):
def include_router(
self,
- router: routing.APIRouter,
+ router: Annotated[routing.APIRouter, Doc("The `APIRouter` to include.")],
*,
- prefix: str = "",
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- default_response_class: Type[Response] = Default(JSONResponse),
- callbacks: Optional[List[BaseRoute]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
- ) -> None:
- self.router.include_router(
- router,
- prefix=prefix,
- tags=tags,
- dependencies=dependencies,
- responses=responses,
- deprecated=deprecated,
- include_in_schema=include_in_schema,
- default_response_class=default_response_class,
- callbacks=callbacks,
- generate_unique_id_function=generate_unique_id_function,
- )
+ prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to all the *path operations* in this
+ router.
- def get(
- self,
- path: str,
- *,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
- ) -> Callable[[DecoratedCallable], DecoratedCallable]:
- return self.router.get(
- path,
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to all the
+ *path operations* in this router.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+
+ **Example**
+
+ ```python
+ from fastapi import Depends, FastAPI
+
+ from .dependencies import get_token_header
+ from .internal import admin
+
+ app = FastAPI()
+
+ app.include_router(
+ admin.router,
+ dependencies=[Depends(get_token_header)],
+ )
+ ```
+ """
+ ),
+ ] = None,
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all the *path operations* in this router as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ from .internal import old_api
+
+ app = FastAPI()
+
+ app.include_router(
+ old_api.router,
+ deprecated=True,
+ )
+ ```
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include (or not) all the *path operations* in this router in the
+ generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+
+ from .internal import old_api
+
+ app = FastAPI()
+
+ app.include_router(
+ old_api.router,
+ include_in_schema=False,
+ )
+ ```
+ """
+ ),
+ ] = True,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Default response class to be used for the *path operations* in this
+ router.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+
+ **Example**
+
+ ```python
+ from fastapi import FastAPI
+ from fastapi.responses import ORJSONResponse
+
+ from .internal import old_api
+
+ app = FastAPI()
+
+ app.include_router(
+ old_api.router,
+ default_response_class=ORJSONResponse,
+ )
+ ```
+ """
+ ),
+ ] = Default(JSONResponse),
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> None:
+ """
+ Include an `APIRouter` in the same app.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ from .users import users_router
+
+ app = FastAPI()
+
+ app.include_router(users_router)
+ ```
+ """
+ self.router.include_router(
+ router,
+ prefix=prefix,
+ tags=tags,
+ dependencies=dependencies,
+ responses=responses,
+ deprecated=deprecated,
+ include_in_schema=include_in_schema,
+ default_response_class=default_response_class,
+ callbacks=callbacks,
+ generate_unique_id_function=generate_unique_id_function,
+ )
+
+ def get(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
+ ) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP GET operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.get("/items/")
+ def read_items():
+ return [{"name": "Empanada"}, {"name": "Arepa"}]
+ ```
+ """
+ return self.router.get(
+ path,
response_model=response_model,
status_code=status_code,
tags=tags,
@@ -526,33 +1832,356 @@ class FastAPI(Starlette):
def put(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PUT operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+
+ @app.put("/items/{item_id}")
+ def replace_item(item_id: str, item: Item):
+ return {"message": "Item replaced", "id": item_id}
+ ```
+ """
return self.router.put(
path,
response_model=response_model,
@@ -581,33 +2210,356 @@ class FastAPI(Starlette):
def post(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP POST operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+
+ @app.post("/items/")
+ def create_item(item: Item):
+ return {"message": "Item created"}
+ ```
+ """
return self.router.post(
path,
response_model=response_model,
@@ -636,33 +2588,351 @@ class FastAPI(Starlette):
def delete(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP DELETE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.delete("/items/{item_id}")
+ def delete_item(item_id: str):
+ return {"message": "Item deleted"}
+ ```
+ """
return self.router.delete(
path,
response_model=response_model,
@@ -691,33 +2961,351 @@ class FastAPI(Starlette):
def options(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP OPTIONS operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.options("/items/")
+ def get_item_options():
+ return {"additions": ["Aji", "Guacamole"]}
+ ```
+ """
return self.router.options(
path,
response_model=response_model,
@@ -744,35 +3332,353 @@ class FastAPI(Starlette):
generate_unique_id_function=generate_unique_id_function,
)
- def head(
- self,
- path: str,
- *,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
+ def head(
+ self,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
+ *,
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP HEAD operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI, Response
+
+ app = FastAPI()
+
+ @app.head("/items/", status_code=204)
+ def get_items_headers(response: Response):
+ response.headers["X-Cat-Dog"] = "Alone in the world"
+ ```
+ """
return self.router.head(
path,
response_model=response_model,
@@ -801,33 +3707,356 @@ class FastAPI(Starlette):
def patch(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PATCH operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+
+ @app.patch("/items/")
+ def update_item(item: Item):
+ return {"message": "Item updated in place"}
+ ```
+ """
return self.router.patch(
path,
response_model=response_model,
@@ -856,33 +4085,351 @@ class FastAPI(Starlette):
def trace(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[routing.APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[routing.APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP TRACE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI
+
+ app = FastAPI()
+
+ @app.put("/items/{item_id}")
+ def trace_item(item_id: str):
+ return None
+ ```
+ """
return self.router.trace(
path,
response_model=response_model,
@@ -918,14 +4465,72 @@ class FastAPI(Starlette):
return decorator
+ @deprecated(
+ """
+ on_event is deprecated, use lifespan event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ )
def on_event(
- self, event_type: str
+ self,
+ event_type: Annotated[
+ str,
+ Doc(
+ """
+ The type of event. `startup` or `shutdown`.
+ """
+ ),
+ ],
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add an event handler for the application.
+
+ `on_event` is deprecated, use `lifespan` event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated).
+ """
return self.router.on_event(event_type)
def middleware(
- self, middleware_type: str
+ self,
+ middleware_type: Annotated[
+ str,
+ Doc(
+ """
+ The type of middleware. Currently only supports `http`.
+ """
+ ),
+ ],
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a middleware to the application.
+
+ Read more about it in the
+ [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/).
+
+ ## Example
+
+ ```python
+ import time
+
+ from fastapi import FastAPI, Request
+
+ app = FastAPI()
+
+
+ @app.middleware("http")
+ async def add_process_time_header(request: Request, call_next):
+ start_time = time.time()
+ response = await call_next(request)
+ process_time = time.time() - start_time
+ response.headers["X-Process-Time"] = str(process_time)
+ return response
+ ```
+ """
+
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.add_middleware(BaseHTTPMiddleware, dispatch=func)
return func
@@ -933,8 +4538,46 @@ class FastAPI(Starlette):
return decorator
def exception_handler(
- self, exc_class_or_status_code: Union[int, Type[Exception]]
+ self,
+ exc_class_or_status_code: Annotated[
+ Union[int, Type[Exception]],
+ Doc(
+ """
+ The Exception class this would handle, or a status code.
+ """
+ ),
+ ],
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add an exception handler to the app.
+
+ Read more about it in the
+ [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI, Request
+ from fastapi.responses import JSONResponse
+
+
+ class UnicornException(Exception):
+ def __init__(self, name: str):
+ self.name = name
+
+
+ app = FastAPI()
+
+
+ @app.exception_handler(UnicornException)
+ async def unicorn_exception_handler(request: Request, exc: UnicornException):
+ return JSONResponse(
+ status_code=418,
+ content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
+ )
+ ```
+ """
+
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.add_exception_handler(exc_class_or_status_code, func)
return func
diff --git a/fastapi/background.py b/fastapi/background.py
index dd3bbe249..35ab1b227 100644
--- a/fastapi/background.py
+++ b/fastapi/background.py
@@ -1 +1,59 @@
-from starlette.background import BackgroundTasks as BackgroundTasks # noqa
+from typing import Any, Callable
+
+from starlette.background import BackgroundTasks as StarletteBackgroundTasks
+from typing_extensions import Annotated, Doc, ParamSpec # type: ignore [attr-defined]
+
+P = ParamSpec("P")
+
+
+class BackgroundTasks(StarletteBackgroundTasks):
+ """
+ A collection of background tasks that will be called after a response has been
+ sent to the client.
+
+ Read more about it in the
+ [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
+
+ ## Example
+
+ ```python
+ from fastapi import BackgroundTasks, FastAPI
+
+ app = FastAPI()
+
+
+ def write_notification(email: str, message=""):
+ with open("log.txt", mode="w") as email_file:
+ content = f"notification for {email}: {message}"
+ email_file.write(content)
+
+
+ @app.post("/send-notification/{email}")
+ async def send_notification(email: str, background_tasks: BackgroundTasks):
+ background_tasks.add_task(write_notification, email, message="some notification")
+ return {"message": "Notification sent in the background"}
+ ```
+ """
+
+ def add_task(
+ self,
+ func: Annotated[
+ Callable[P, Any],
+ Doc(
+ """
+ The function to call after the response is sent.
+
+ It can be a regular `def` function or an `async def` function.
+ """
+ ),
+ ],
+ *args: P.args,
+ **kwargs: P.kwargs,
+ ) -> None:
+ """
+ Add a function to be called in the background after the response is sent.
+
+ Read more about it in the
+ [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).
+ """
+ return super().add_task(func, *args, **kwargs)
diff --git a/fastapi/concurrency.py b/fastapi/concurrency.py
index 31b878d5d..894bd3ed1 100644
--- a/fastapi/concurrency.py
+++ b/fastapi/concurrency.py
@@ -1,4 +1,3 @@
-from contextlib import AsyncExitStack as AsyncExitStack # noqa
from contextlib import asynccontextmanager as asynccontextmanager
from typing import AsyncGenerator, ContextManager, TypeVar
@@ -19,7 +18,7 @@ async def contextmanager_in_threadpool(
) -> AsyncGenerator[_T, None]:
# blocking __exit__ from running waiting on a free thread
# can create race conditions/deadlocks if the context manager itself
- # has it's own internal pool (e.g. a database connection pool)
+ # has its own internal pool (e.g. a database connection pool)
# to avoid this we let __exit__ run without a capacity limit
# since we're creating a new limiter for each call, any non-zero limit
# works (1 is arbitrary)
diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py
index 3c96c56c7..ce03e3ce4 100644
--- a/fastapi/datastructures.py
+++ b/fastapi/datastructures.py
@@ -1,11 +1,21 @@
-from typing import Any, Callable, Dict, Iterable, Type, TypeVar, cast
+from typing import (
+ Any,
+ BinaryIO,
+ Callable,
+ Dict,
+ Iterable,
+ Optional,
+ Type,
+ TypeVar,
+ cast,
+)
from fastapi._compat import (
PYDANTIC_V2,
CoreSchema,
GetJsonSchemaHandler,
JsonSchemaValue,
- general_plain_validator_function,
+ with_info_plain_validator_function,
)
from starlette.datastructures import URL as URL # noqa: F401
from starlette.datastructures import Address as Address # noqa: F401
@@ -14,9 +24,120 @@ from starlette.datastructures import Headers as Headers # noqa: F401
from starlette.datastructures import QueryParams as QueryParams # noqa: F401
from starlette.datastructures import State as State # noqa: F401
from starlette.datastructures import UploadFile as StarletteUploadFile
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
class UploadFile(StarletteUploadFile):
+ """
+ A file uploaded in a request.
+
+ Define it as a *path operation function* (or dependency) parameter.
+
+ If you are using a regular `def` function, you can use the `upload_file.file`
+ attribute to access the raw standard Python file (blocking, not async), useful and
+ needed for non-async code.
+
+ Read more about it in the
+ [FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import FastAPI, File, UploadFile
+
+ app = FastAPI()
+
+
+ @app.post("/files/")
+ async def create_file(file: Annotated[bytes, File()]):
+ return {"file_size": len(file)}
+
+
+ @app.post("/uploadfile/")
+ async def create_upload_file(file: UploadFile):
+ return {"filename": file.filename}
+ ```
+ """
+
+ file: Annotated[
+ BinaryIO,
+ Doc("The standard Python file object (non-async)."),
+ ]
+ filename: Annotated[Optional[str], Doc("The original file name.")]
+ size: Annotated[Optional[int], Doc("The size of the file in bytes.")]
+ headers: Annotated[Headers, Doc("The headers of the request.")]
+ content_type: Annotated[
+ Optional[str], Doc("The content type of the request, from the headers.")
+ ]
+
+ async def write(
+ self,
+ data: Annotated[
+ bytes,
+ Doc(
+ """
+ The bytes to write to the file.
+ """
+ ),
+ ],
+ ) -> None:
+ """
+ Write some bytes to the file.
+
+ You normally wouldn't use this from a file you read in a request.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().write(data)
+
+ async def read(
+ self,
+ size: Annotated[
+ int,
+ Doc(
+ """
+ The number of bytes to read from the file.
+ """
+ ),
+ ] = -1,
+ ) -> bytes:
+ """
+ Read some bytes from the file.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().read(size)
+
+ async def seek(
+ self,
+ offset: Annotated[
+ int,
+ Doc(
+ """
+ The position in bytes to seek to in the file.
+ """
+ ),
+ ],
+ ) -> None:
+ """
+ Move to a position in the file.
+
+ Any next read or write will be done from that position.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().seek(offset)
+
+ async def close(self) -> None:
+ """
+ Close the file.
+
+ To be awaitable, compatible with async, this is run in threadpool.
+ """
+ return await super().close()
+
@classmethod
def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]:
yield cls.validate
@@ -49,7 +170,7 @@ class UploadFile(StarletteUploadFile):
def __get_pydantic_core_schema__(
cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
) -> CoreSchema:
- return general_plain_validator_function(cls._validate)
+ return with_info_plain_validator_function(cls._validate)
class DefaultPlaceholder:
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index e2915268c..b73473484 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -1,5 +1,5 @@
import inspect
-from contextlib import contextmanager
+from contextlib import AsyncExitStack, contextmanager
from copy import deepcopy
from typing import (
Any,
@@ -44,8 +44,8 @@ from fastapi._compat import (
serialize_sequence_value,
value_is_sequence,
)
+from fastapi.background import BackgroundTasks
from fastapi.concurrency import (
- AsyncExitStack,
asynccontextmanager,
contextmanager_in_threadpool,
)
@@ -56,7 +56,7 @@ from fastapi.security.oauth2 import OAuth2, SecurityScopes
from fastapi.security.open_id_connect_url import OpenIdConnect
from fastapi.utils import create_response_field, get_path_param_names
from pydantic.fields import FieldInfo
-from starlette.background import BackgroundTasks
+from starlette.background import BackgroundTasks as StarletteBackgroundTasks
from starlette.concurrency import run_in_threadpool
from starlette.datastructures import FormData, Headers, QueryParams, UploadFile
from starlette.requests import HTTPConnection, Request
@@ -305,7 +305,7 @@ def add_non_field_param_to_dependency(
elif lenient_issubclass(type_annotation, Response):
dependant.response_param_name = param_name
return True
- elif lenient_issubclass(type_annotation, BackgroundTasks):
+ elif lenient_issubclass(type_annotation, StarletteBackgroundTasks):
dependant.background_tasks_param_name = param_name
return True
elif lenient_issubclass(type_annotation, SecurityScopes):
@@ -324,10 +324,11 @@ def analyze_param(
field_info = None
depends = None
type_annotation: Any = Any
- if (
- annotation is not inspect.Signature.empty
- and get_origin(annotation) is Annotated
- ):
+ use_annotation: Any = Any
+ if annotation is not inspect.Signature.empty:
+ use_annotation = annotation
+ type_annotation = annotation
+ if get_origin(use_annotation) is Annotated:
annotated_args = get_args(annotation)
type_annotation = annotated_args[0]
fastapi_annotations = [
@@ -335,14 +336,21 @@ def analyze_param(
for arg in annotated_args[1:]
if isinstance(arg, (FieldInfo, params.Depends))
]
- assert (
- len(fastapi_annotations) <= 1
- ), f"Cannot specify multiple `Annotated` FastAPI arguments for {param_name!r}"
- fastapi_annotation = next(iter(fastapi_annotations), None)
+ fastapi_specific_annotations = [
+ arg
+ for arg in fastapi_annotations
+ if isinstance(arg, (params.Param, params.Body, params.Depends))
+ ]
+ if fastapi_specific_annotations:
+ fastapi_annotation: Union[
+ FieldInfo, params.Depends, None
+ ] = fastapi_specific_annotations[-1]
+ else:
+ fastapi_annotation = None
if isinstance(fastapi_annotation, FieldInfo):
# Copy `field_info` because we mutate `field_info.default` below.
field_info = copy_field_info(
- field_info=fastapi_annotation, annotation=annotation
+ field_info=fastapi_annotation, annotation=use_annotation
)
assert field_info.default is Undefined or field_info.default is Required, (
f"`{field_info.__class__.__name__}` default value cannot be set in"
@@ -355,8 +363,6 @@ def analyze_param(
field_info.default = Required
elif isinstance(fastapi_annotation, params.Depends):
depends = fastapi_annotation
- elif annotation is not inspect.Signature.empty:
- type_annotation = annotation
if isinstance(value, params.Depends):
assert depends is None, (
@@ -382,7 +388,14 @@ def analyze_param(
if lenient_issubclass(
type_annotation,
- (Request, WebSocket, HTTPConnection, Response, BackgroundTasks, SecurityScopes),
+ (
+ Request,
+ WebSocket,
+ HTTPConnection,
+ Response,
+ StarletteBackgroundTasks,
+ SecurityScopes,
+ ),
):
assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}"
assert (
@@ -394,15 +407,15 @@ def analyze_param(
# We might check here that `default_value is Required`, but the fact is that the same
# parameter might sometimes be a path parameter and sometimes not. See
# `tests/test_infer_param_optionality.py` for an example.
- field_info = params.Path(annotation=type_annotation)
+ field_info = params.Path(annotation=use_annotation)
elif is_uploadfile_or_nonable_uploadfile_annotation(
type_annotation
) or is_uploadfile_sequence_annotation(type_annotation):
- field_info = params.File(annotation=type_annotation, default=default_value)
+ field_info = params.File(annotation=use_annotation, default=default_value)
elif not field_annotation_is_scalar(annotation=type_annotation):
- field_info = params.Body(annotation=type_annotation, default=default_value)
+ field_info = params.Body(annotation=use_annotation, default=default_value)
else:
- field_info = params.Query(annotation=type_annotation, default=default_value)
+ field_info = params.Query(annotation=use_annotation, default=default_value)
field = None
if field_info is not None:
@@ -416,8 +429,8 @@ def analyze_param(
and getattr(field_info, "in_", None) is None
):
field_info.in_ = params.ParamTypes.query
- use_annotation = get_annotation_from_field_info(
- type_annotation,
+ use_annotation_from_field_info = get_annotation_from_field_info(
+ use_annotation,
field_info,
param_name,
)
@@ -428,7 +441,7 @@ def analyze_param(
field_info.alias = alias
field = create_response_field(
name=param_name,
- type_=use_annotation,
+ type_=use_annotation_from_field_info,
default=field_info.default,
alias=alias,
required=field_info.default in (Required, Undefined),
@@ -458,16 +471,17 @@ def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool:
def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
- field_info = cast(params.Param, field.field_info)
- if field_info.in_ == params.ParamTypes.path:
+ field_info = field.field_info
+ field_info_in = getattr(field_info, "in_", None)
+ if field_info_in == params.ParamTypes.path:
dependant.path_params.append(field)
- elif field_info.in_ == params.ParamTypes.query:
+ elif field_info_in == params.ParamTypes.query:
dependant.query_params.append(field)
- elif field_info.in_ == params.ParamTypes.header:
+ elif field_info_in == params.ParamTypes.header:
dependant.header_params.append(field)
else:
assert (
- field_info.in_ == params.ParamTypes.cookie
+ field_info_in == params.ParamTypes.cookie
), f"non-body parameters must be in path, query, header or cookie: {field.name}"
dependant.cookie_params.append(field)
@@ -510,14 +524,15 @@ async def solve_dependencies(
request: Union[Request, WebSocket],
dependant: Dependant,
body: Optional[Union[Dict[str, Any], FormData]] = None,
- background_tasks: Optional[BackgroundTasks] = None,
+ background_tasks: Optional[StarletteBackgroundTasks] = None,
response: Optional[Response] = None,
dependency_overrides_provider: Optional[Any] = None,
dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
+ async_exit_stack: AsyncExitStack,
) -> Tuple[
Dict[str, Any],
List[Any],
- Optional[BackgroundTasks],
+ Optional[StarletteBackgroundTasks],
Response,
Dict[Tuple[Callable[..., Any], Tuple[str]], Any],
]:
@@ -560,6 +575,7 @@ async def solve_dependencies(
response=response,
dependency_overrides_provider=dependency_overrides_provider,
dependency_cache=dependency_cache,
+ async_exit_stack=async_exit_stack,
)
(
sub_values,
@@ -575,10 +591,8 @@ async def solve_dependencies(
if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
solved = dependency_cache[sub_dependant.cache_key]
elif is_gen_callable(call) or is_async_gen_callable(call):
- stack = request.scope.get("fastapi_astack")
- assert isinstance(stack, AsyncExitStack)
solved = await solve_generator(
- call=call, stack=stack, sub_values=sub_values
+ call=call, stack=async_exit_stack, sub_values=sub_values
)
elif is_coroutine_callable(call):
solved = await call(**sub_values)
diff --git a/fastapi/encoders.py b/fastapi/encoders.py
index b542749f2..e50171393 100644
--- a/fastapi/encoders.py
+++ b/fastapi/encoders.py
@@ -20,10 +20,11 @@ from uuid import UUID
from fastapi.types import IncEx
from pydantic import BaseModel
from pydantic.color import Color
-from pydantic.networks import NameEmail
+from pydantic.networks import AnyUrl, NameEmail
from pydantic.types import SecretBytes, SecretStr
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
-from ._compat import PYDANTIC_V2, MultiHostUrl, Url, _model_dump
+from ._compat import PYDANTIC_V2, Url, _model_dump
# Taken from Pydantic v1 as is
@@ -80,7 +81,7 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
set: list,
UUID: str,
Url: str,
- MultiHostUrl: str,
+ AnyUrl: str,
}
@@ -99,16 +100,107 @@ encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)
def jsonable_encoder(
- obj: Any,
- include: Optional[IncEx] = None,
- exclude: Optional[IncEx] = None,
- by_alias: bool = True,
- exclude_unset: bool = False,
- exclude_defaults: bool = False,
- exclude_none: bool = False,
- custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None,
- sqlalchemy_safe: bool = True,
+ obj: Annotated[
+ Any,
+ Doc(
+ """
+ The input object to convert to JSON.
+ """
+ ),
+ ],
+ include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Pydantic's `include` parameter, passed to Pydantic models to set the
+ fields to include.
+ """
+ ),
+ ] = None,
+ exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Pydantic's `exclude` parameter, passed to Pydantic models to set the
+ fields to exclude.
+ """
+ ),
+ ] = None,
+ by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `by_alias` parameter, passed to Pydantic models to define if
+ the output should use the alias names (when provided) or the Python
+ attribute names. In an API, if you set an alias, it's probably because you
+ want to use it in the result, so you probably want to leave this set to
+ `True`.
+ """
+ ),
+ ] = True,
+ exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `exclude_unset` parameter, passed to Pydantic models to define
+ if it should exclude from the output the fields that were not explicitly
+ set (and that only had their default values).
+ """
+ ),
+ ] = False,
+ exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define
+ if it should exclude from the output the fields that had the same default
+ value, even when they were explicitly set.
+ """
+ ),
+ ] = False,
+ exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Pydantic's `exclude_none` parameter, passed to Pydantic models to define
+ if it should exclude from the output any fields that have a `None` value.
+ """
+ ),
+ ] = False,
+ custom_encoder: Annotated[
+ Optional[Dict[Any, Callable[[Any], Any]]],
+ Doc(
+ """
+ Pydantic's `custom_encoder` parameter, passed to Pydantic models to define
+ a custom encoder.
+ """
+ ),
+ ] = None,
+ sqlalchemy_safe: Annotated[
+ bool,
+ Doc(
+ """
+ Exclude from the output any fields that start with the name `_sa`.
+
+ This is mainly a hack for compatibility with SQLAlchemy objects, they
+ store internal SQLAlchemy-specific state in attributes named with `_sa`,
+ and those objects can't (and shouldn't be) serialized to JSON.
+ """
+ ),
+ ] = True,
) -> Any:
+ """
+ Convert any object to something that can be encoded in JSON.
+
+ This is used internally by FastAPI to make sure anything you return can be
+ encoded as JSON before it is sent to the client.
+
+ You can also use it yourself, for example to convert objects before saving them
+ in a database that supports only JSON.
+
+ Read more about it in the
+ [FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/).
+ """
custom_encoder = custom_encoder or {}
if custom_encoder:
if type(obj) in custom_encoder:
diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py
index c1692f396..680d288e4 100644
--- a/fastapi/exceptions.py
+++ b/fastapi/exceptions.py
@@ -1,20 +1,141 @@
-from typing import Any, Dict, Optional, Sequence, Type
+from typing import Any, Dict, Optional, Sequence, Type, Union
from pydantic import BaseModel, create_model
from starlette.exceptions import HTTPException as StarletteHTTPException
-from starlette.exceptions import WebSocketException as WebSocketException # noqa: F401
+from starlette.exceptions import WebSocketException as StarletteWebSocketException
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
class HTTPException(StarletteHTTPException):
+ """
+ An HTTP exception you can raise in your own code to show errors to the client.
+
+ This is for client errors, invalid authentication, invalid data, etc. Not for server
+ errors in your code.
+
+ Read more about it in the
+ [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).
+
+ ## Example
+
+ ```python
+ from fastapi import FastAPI, HTTPException
+
+ app = FastAPI()
+
+ items = {"foo": "The Foo Wrestlers"}
+
+
+ @app.get("/items/{item_id}")
+ async def read_item(item_id: str):
+ if item_id not in items:
+ raise HTTPException(status_code=404, detail="Item not found")
+ return {"item": items[item_id]}
+ ```
+ """
+
def __init__(
self,
- status_code: int,
- detail: Any = None,
- headers: Optional[Dict[str, str]] = None,
+ status_code: Annotated[
+ int,
+ Doc(
+ """
+ HTTP status code to send to the client.
+ """
+ ),
+ ],
+ detail: Annotated[
+ Any,
+ Doc(
+ """
+ Any data to be sent to the client in the `detail` key of the JSON
+ response.
+ """
+ ),
+ ] = None,
+ headers: Annotated[
+ Optional[Dict[str, str]],
+ Doc(
+ """
+ Any headers to send to the client in the response.
+ """
+ ),
+ ] = None,
) -> None:
super().__init__(status_code=status_code, detail=detail, headers=headers)
+class WebSocketException(StarletteWebSocketException):
+ """
+ A WebSocket exception you can raise in your own code to show errors to the client.
+
+ This is for client errors, invalid authentication, invalid data, etc. Not for server
+ errors in your code.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import (
+ Cookie,
+ FastAPI,
+ WebSocket,
+ WebSocketException,
+ status,
+ )
+
+ app = FastAPI()
+
+ @app.websocket("/items/{item_id}/ws")
+ async def websocket_endpoint(
+ *,
+ websocket: WebSocket,
+ session: Annotated[str | None, Cookie()] = None,
+ item_id: str,
+ ):
+ if session is None:
+ raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(f"Session cookie is: {session}")
+ await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}")
+ ```
+ """
+
+ def __init__(
+ self,
+ code: Annotated[
+ int,
+ Doc(
+ """
+ A closing code from the
+ [valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1).
+ """
+ ),
+ ],
+ reason: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ The reason to close the WebSocket connection.
+
+ It is UTF-8-encoded data. The interpretation of the reason is up to the
+ application, it is not specified by the WebSocket specification.
+
+ It could contain text that could be human-readable or interpretable
+ by the client code, etc.
+ """
+ ),
+ ] = None,
+ ) -> None:
+ super().__init__(code=code, reason=reason)
+
+
RequestErrorModel: Type[BaseModel] = create_model("Request")
WebSocketErrorModel: Type[BaseModel] = create_model("WebSocket")
@@ -47,3 +168,9 @@ class ResponseValidationError(ValidationException):
def __init__(self, errors: Sequence[Any], *, body: Any = None) -> None:
super().__init__(errors)
self.body = body
+
+ def __str__(self) -> str:
+ message = f"{len(self._errors)} validation errors:\n"
+ for err in self._errors:
+ message += f" {err}\n"
+ return message
diff --git a/fastapi/middleware/asyncexitstack.py b/fastapi/middleware/asyncexitstack.py
deleted file mode 100644
index 30a0ae626..000000000
--- a/fastapi/middleware/asyncexitstack.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from typing import Optional
-
-from fastapi.concurrency import AsyncExitStack
-from starlette.types import ASGIApp, Receive, Scope, Send
-
-
-class AsyncExitStackMiddleware:
- def __init__(self, app: ASGIApp, context_name: str = "fastapi_astack") -> None:
- self.app = app
- self.context_name = context_name
-
- async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
- dependency_exception: Optional[Exception] = None
- async with AsyncExitStack() as stack:
- scope[self.context_name] = stack
- try:
- await self.app(scope, receive, send)
- except Exception as e:
- dependency_exception = e
- raise e
- if dependency_exception:
- # This exception was possibly handled by the dependency but it should
- # still bubble up so that the ServerErrorMiddleware can return a 500
- # or the ExceptionMiddleware can catch and handle any other exceptions
- raise dependency_exception
diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py
index 81f67dcc5..69473d19c 100644
--- a/fastapi/openapi/docs.py
+++ b/fastapi/openapi/docs.py
@@ -3,8 +3,18 @@ from typing import Any, Dict, Optional
from fastapi.encoders import jsonable_encoder
from starlette.responses import HTMLResponse
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
-swagger_ui_default_parameters = {
+swagger_ui_default_parameters: Annotated[
+ Dict[str, Any],
+ Doc(
+ """
+ Default configurations for Swagger UI.
+
+ You can use it as a template to add any other configurations needed.
+ """
+ ),
+] = {
"dom_id": "#swagger-ui",
"layout": "BaseLayout",
"deepLinking": True,
@@ -15,15 +25,91 @@ swagger_ui_default_parameters = {
def get_swagger_ui_html(
*,
- openapi_url: str,
- title: str,
- swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
- swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
- swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
- oauth2_redirect_url: Optional[str] = None,
- init_oauth: Optional[Dict[str, Any]] = None,
- swagger_ui_parameters: Optional[Dict[str, Any]] = None,
+ openapi_url: Annotated[
+ str,
+ Doc(
+ """
+ The OpenAPI URL that Swagger UI should load and use.
+
+ This is normally done automatically by FastAPI using the default URL
+ `/openapi.json`.
+ """
+ ),
+ ],
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The HTML `` content, normally shown in the browser tab.
+ """
+ ),
+ ],
+ swagger_js_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the Swagger UI JavaScript.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js",
+ swagger_css_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the Swagger UI CSS.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css",
+ swagger_favicon_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL of the favicon to use. It is normally shown in the browser tab.
+ """
+ ),
+ ] = "https://fastapi.tiangolo.com/img/favicon.png",
+ oauth2_redirect_url: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The OAuth2 redirect URL, it is normally automatically handled by FastAPI.
+ """
+ ),
+ ] = None,
+ init_oauth: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ A dictionary with Swagger UI OAuth2 initialization configurations.
+ """
+ ),
+ ] = None,
+ swagger_ui_parameters: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Configuration parameters for Swagger UI.
+
+ It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters].
+ """
+ ),
+ ] = None,
) -> HTMLResponse:
+ """
+ Generate and return the HTML that loads Swagger UI for the interactive
+ API docs (normally served at `/docs`).
+
+ You would only call this function yourself if you needed to override some parts,
+ for example the URLs to use to load Swagger UI's JavaScript and CSS.
+
+ Read more about it in the
+ [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/)
+ and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
+ """
current_swagger_ui_parameters = swagger_ui_default_parameters.copy()
if swagger_ui_parameters:
current_swagger_ui_parameters.update(swagger_ui_parameters)
@@ -74,12 +160,62 @@ def get_swagger_ui_html(
def get_redoc_html(
*,
- openapi_url: str,
- title: str,
- redoc_js_url: str = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
- redoc_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png",
- with_google_fonts: bool = True,
+ openapi_url: Annotated[
+ str,
+ Doc(
+ """
+ The OpenAPI URL that ReDoc should load and use.
+
+ This is normally done automatically by FastAPI using the default URL
+ `/openapi.json`.
+ """
+ ),
+ ],
+ title: Annotated[
+ str,
+ Doc(
+ """
+ The HTML `` content, normally shown in the browser tab.
+ """
+ ),
+ ],
+ redoc_js_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL to use to load the ReDoc JavaScript.
+
+ It is normally set to a CDN URL.
+ """
+ ),
+ ] = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
+ redoc_favicon_url: Annotated[
+ str,
+ Doc(
+ """
+ The URL of the favicon to use. It is normally shown in the browser tab.
+ """
+ ),
+ ] = "https://fastapi.tiangolo.com/img/favicon.png",
+ with_google_fonts: Annotated[
+ bool,
+ Doc(
+ """
+ Load and use Google Fonts.
+ """
+ ),
+ ] = True,
) -> HTMLResponse:
+ """
+ Generate and return the HTML response that loads ReDoc for the alternative
+ API docs (normally served at `/redoc`).
+
+ You would only call this function yourself if you needed to override some parts,
+ for example the URLs to use to load ReDoc's JavaScript and CSS.
+
+ Read more about it in the
+ [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).
+ """
html = f"""
@@ -118,6 +254,11 @@ def get_redoc_html(
def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse:
+ """
+ Generate the HTML response with the OAuth2 redirection for Swagger UI.
+
+ You normally don't need to use or change this.
+ """
# copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html
html = """
diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py
index 2268dd229..5f3bdbb20 100644
--- a/fastapi/openapi/models.py
+++ b/fastapi/openapi/models.py
@@ -7,11 +7,11 @@ from fastapi._compat import (
GetJsonSchemaHandler,
JsonSchemaValue,
_model_rebuild,
- general_plain_validator_function,
+ with_info_plain_validator_function,
)
from fastapi.logger import logger
from pydantic import AnyUrl, BaseModel, Field
-from typing_extensions import Annotated, Literal
+from typing_extensions import Annotated, Literal, TypedDict
from typing_extensions import deprecated as typing_deprecated
try:
@@ -52,7 +52,7 @@ except ImportError: # pragma: no cover
def __get_pydantic_core_schema__(
cls, source: Type[Any], handler: Callable[[Any], CoreSchema]
) -> CoreSchema:
- return general_plain_validator_function(cls._validate)
+ return with_info_plain_validator_function(cls._validate)
class Contact(BaseModel):
@@ -267,14 +267,14 @@ class Schema(BaseModel):
SchemaOrBool = Union[Schema, bool]
-class Example(BaseModel):
- summary: Optional[str] = None
- description: Optional[str] = None
- value: Optional[Any] = None
- externalValue: Optional[AnyUrl] = None
+class Example(TypedDict, total=False):
+ summary: Optional[str]
+ description: Optional[str]
+ value: Optional[Any]
+ externalValue: Optional[AnyUrl]
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
+ if PYDANTIC_V2: # type: ignore [misc]
+ __pydantic_config__ = {"extra": "allow"}
else:
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
index e295361e6..5bfb5acef 100644
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -95,6 +95,7 @@ def get_openapi_operation_parameters(
field_mapping: Dict[
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
],
+ separate_input_output_schemas: bool = True,
) -> List[Dict[str, Any]]:
parameters = []
for param in all_route_params:
@@ -107,6 +108,7 @@ def get_openapi_operation_parameters(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
parameter = {
"name": param.alias,
@@ -116,7 +118,9 @@ def get_openapi_operation_parameters(
}
if field_info.description:
parameter["description"] = field_info.description
- if field_info.example != Undefined:
+ if field_info.openapi_examples:
+ parameter["examples"] = jsonable_encoder(field_info.openapi_examples)
+ elif field_info.example != Undefined:
parameter["example"] = jsonable_encoder(field_info.example)
if field_info.deprecated:
parameter["deprecated"] = field_info.deprecated
@@ -132,6 +136,7 @@ def get_openapi_operation_request_body(
field_mapping: Dict[
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
],
+ separate_input_output_schemas: bool = True,
) -> Optional[Dict[str, Any]]:
if not body_field:
return None
@@ -141,6 +146,7 @@ def get_openapi_operation_request_body(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
field_info = cast(Body, body_field.field_info)
request_media_type = field_info.media_type
@@ -149,7 +155,11 @@ def get_openapi_operation_request_body(
if required:
request_body_oai["required"] = required
request_media_content: Dict[str, Any] = {"schema": body_schema}
- if field_info.example != Undefined:
+ if field_info.openapi_examples:
+ request_media_content["examples"] = jsonable_encoder(
+ field_info.openapi_examples
+ )
+ elif field_info.example != Undefined:
request_media_content["example"] = jsonable_encoder(field_info.example)
request_body_oai["content"] = {request_media_type: request_media_content}
return request_body_oai
@@ -211,6 +221,7 @@ def get_openapi_path(
field_mapping: Dict[
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
],
+ separate_input_output_schemas: bool = True,
) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
path = {}
security_schemes: Dict[str, Any] = {}
@@ -242,6 +253,7 @@ def get_openapi_path(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
parameters.extend(operation_parameters)
if parameters:
@@ -263,6 +275,7 @@ def get_openapi_path(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
if request_body_oai:
operation["requestBody"] = request_body_oai
@@ -280,6 +293,7 @@ def get_openapi_path(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
callbacks[callback.name] = {callback.path: cb_path}
operation["callbacks"] = callbacks
@@ -310,6 +324,7 @@ def get_openapi_path(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
else:
response_schema = {}
@@ -343,6 +358,7 @@ def get_openapi_path(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
media_type = route_response_media_type or "application/json"
additional_schema = (
@@ -433,6 +449,7 @@ def get_openapi(
terms_of_service: Optional[str] = None,
contact: Optional[Dict[str, Union[str, Any]]] = None,
license_info: Optional[Dict[str, Union[str, Any]]] = None,
+ separate_input_output_schemas: bool = True,
) -> Dict[str, Any]:
info: Dict[str, Any] = {"title": title, "version": version}
if summary:
@@ -459,6 +476,7 @@ def get_openapi(
fields=all_fields,
schema_generator=schema_generator,
model_name_map=model_name_map,
+ separate_input_output_schemas=separate_input_output_schemas,
)
for route in routes or []:
if isinstance(route, routing.APIRoute):
@@ -468,6 +486,7 @@ def get_openapi(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
if result:
path, security_schemes, path_definitions = result
@@ -487,6 +506,7 @@ def get_openapi(
schema_generator=schema_generator,
model_name_map=model_name_map,
field_mapping=field_mapping,
+ separate_input_output_schemas=separate_input_output_schemas,
)
if result:
path, security_schemes, path_definitions = result
diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py
index a43afaf31..3f6dbc959 100644
--- a/fastapi/param_functions.py
+++ b/fastapi/param_functions.py
@@ -2,43 +2,219 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Union
from fastapi import params
from fastapi._compat import Undefined
-from typing_extensions import Annotated, deprecated
+from fastapi.openapi.models import Example
+from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined]
_Unset: Any = Undefined
def Path( # noqa: N802
- default: Any = ...,
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = ...,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
# TODO: update when deprecating Pydantic v1, import these types
# validation_alias: str | AliasPath | AliasChoices | None
- validation_alias: Union[str, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
regex: Annotated[
Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[List[Any]] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
example: Annotated[
Optional[Any],
deprecated(
@@ -46,11 +222,87 @@ def Path( # noqa: N802
"although still supported. Use examples instead."
),
] = _Unset,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- json_schema_extra: Union[Dict[str, Any], None] = None,
- **extra: Any,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
) -> Any:
+ """
+ Declare a path parameter for a *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/).
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import FastAPI, Path
+
+ app = FastAPI()
+
+
+ @app.get("/items/{item_id}")
+ async def read_items(
+ item_id: Annotated[int, Path(title="The ID of the item to get")],
+ ):
+ return {"item_id": item_id}
+ ```
+ """
return params.Path(
default=default,
default_factory=default_factory,
@@ -76,6 +328,7 @@ def Path( # noqa: N802
decimal_places=decimal_places,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
@@ -84,37 +337,209 @@ def Path( # noqa: N802
def Query( # noqa: N802
- default: Any = Undefined,
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
# TODO: update when deprecating Pydantic v1, import these types
# validation_alias: str | AliasPath | AliasChoices | None
- validation_alias: Union[str, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
regex: Annotated[
Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[List[Any]] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
example: Annotated[
Optional[Any],
deprecated(
@@ -122,10 +547,65 @@ def Query( # noqa: N802
"although still supported. Use examples instead."
),
] = _Unset,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- json_schema_extra: Union[Dict[str, Any], None] = None,
- **extra: Any,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
) -> Any:
return params.Query(
default=default,
@@ -152,6 +632,7 @@ def Query( # noqa: N802
decimal_places=decimal_places,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
@@ -160,38 +641,220 @@ def Query( # noqa: N802
def Header( # noqa: N802
- default: Any = Undefined,
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
# TODO: update when deprecating Pydantic v1, import these types
# validation_alias: str | AliasPath | AliasChoices | None
- validation_alias: Union[str, None] = None,
- serialization_alias: Union[str, None] = None,
- convert_underscores: bool = True,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ convert_underscores: Annotated[
+ bool,
+ Doc(
+ """
+ Automatically convert underscores to hyphens in the parameter field name.
+
+ Read more about it in the
+ [FastAPI docs for Header Parameters](https://fastapi.tiangolo.com/tutorial/header-params/#automatic-conversion)
+ """
+ ),
+ ] = True,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
regex: Annotated[
Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[List[Any]] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
example: Annotated[
Optional[Any],
deprecated(
@@ -199,10 +862,65 @@ def Header( # noqa: N802
"although still supported. Use examples instead."
),
] = _Unset,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- json_schema_extra: Union[Dict[str, Any], None] = None,
- **extra: Any,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
) -> Any:
return params.Header(
default=default,
@@ -230,6 +948,7 @@ def Header( # noqa: N802
decimal_places=decimal_places,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
@@ -238,37 +957,209 @@ def Header( # noqa: N802
def Cookie( # noqa: N802
- default: Any = Undefined,
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
# TODO: update when deprecating Pydantic v1, import these types
# validation_alias: str | AliasPath | AliasChoices | None
- validation_alias: Union[str, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
regex: Annotated[
Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[List[Any]] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
example: Annotated[
Optional[Any],
deprecated(
@@ -276,10 +1167,65 @@ def Cookie( # noqa: N802
"although still supported. Use examples instead."
),
] = _Unset,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- json_schema_extra: Union[Dict[str, Any], None] = None,
- **extra: Any,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
) -> Any:
return params.Cookie(
default=default,
@@ -306,6 +1252,7 @@ def Cookie( # noqa: N802
decimal_places=decimal_places,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
@@ -314,39 +1261,232 @@ def Cookie( # noqa: N802
def Body( # noqa: N802
- default: Any = Undefined,
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- embed: bool = False,
- media_type: str = "application/json",
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ embed: Annotated[
+ bool,
+ Doc(
+ """
+ When `embed` is `True`, the parameter will be expected in a JSON body as a
+ key instead of being the JSON body itself.
+
+ This happens automatically when more than one `Body` parameter is declared.
+
+ Read more about it in the
+ [FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter).
+ """
+ ),
+ ] = False,
+ media_type: Annotated[
+ str,
+ Doc(
+ """
+ The media type of this parameter field. Changing it would affect the
+ generated OpenAPI, but currently it doesn't affect the parsing of the data.
+ """
+ ),
+ ] = "application/json",
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
# TODO: update when deprecating Pydantic v1, import these types
# validation_alias: str | AliasPath | AliasChoices | None
- validation_alias: Union[str, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
regex: Annotated[
Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[List[Any]] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
example: Annotated[
Optional[Any],
deprecated(
@@ -354,10 +1494,65 @@ def Body( # noqa: N802
"although still supported. Use examples instead."
),
] = _Unset,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- json_schema_extra: Union[Dict[str, Any], None] = None,
- **extra: Any,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
) -> Any:
return params.Body(
default=default,
@@ -386,6 +1581,7 @@ def Body( # noqa: N802
decimal_places=decimal_places,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
@@ -394,38 +1590,218 @@ def Body( # noqa: N802
def Form( # noqa: N802
- default: Any = Undefined,
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- media_type: str = "application/x-www-form-urlencoded",
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ media_type: Annotated[
+ str,
+ Doc(
+ """
+ The media type of this parameter field. Changing it would affect the
+ generated OpenAPI, but currently it doesn't affect the parsing of the data.
+ """
+ ),
+ ] = "application/x-www-form-urlencoded",
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
# TODO: update when deprecating Pydantic v1, import these types
# validation_alias: str | AliasPath | AliasChoices | None
- validation_alias: Union[str, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
regex: Annotated[
Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[List[Any]] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
example: Annotated[
Optional[Any],
deprecated(
@@ -433,10 +1809,65 @@ def Form( # noqa: N802
"although still supported. Use examples instead."
),
] = _Unset,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- json_schema_extra: Union[Dict[str, Any], None] = None,
- **extra: Any,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
) -> Any:
return params.Form(
default=default,
@@ -464,6 +1895,7 @@ def Form( # noqa: N802
decimal_places=decimal_places,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
@@ -472,38 +1904,218 @@ def Form( # noqa: N802
def File( # noqa: N802
- default: Any = Undefined,
+ default: Annotated[
+ Any,
+ Doc(
+ """
+ Default value if the parameter field is not set.
+ """
+ ),
+ ] = Undefined,
*,
- default_factory: Union[Callable[[], Any], None] = _Unset,
- media_type: str = "multipart/form-data",
- alias: Optional[str] = None,
- alias_priority: Union[int, None] = _Unset,
+ default_factory: Annotated[
+ Union[Callable[[], Any], None],
+ Doc(
+ """
+ A callable to generate the default value.
+
+ This doesn't affect `Path` parameters as the value is always required.
+ The parameter is available only for compatibility.
+ """
+ ),
+ ] = _Unset,
+ media_type: Annotated[
+ str,
+ Doc(
+ """
+ The media type of this parameter field. Changing it would affect the
+ generated OpenAPI, but currently it doesn't affect the parsing of the data.
+ """
+ ),
+ ] = "multipart/form-data",
+ alias: Annotated[
+ Optional[str],
+ Doc(
+ """
+ An alternative name for the parameter field.
+
+ This will be used to extract the data and for the generated OpenAPI.
+ It is particularly useful when you can't use the name you want because it
+ is a Python reserved keyword or similar.
+ """
+ ),
+ ] = None,
+ alias_priority: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Priority of the alias. This affects whether an alias generator is used.
+ """
+ ),
+ ] = _Unset,
# TODO: update when deprecating Pydantic v1, import these types
# validation_alias: str | AliasPath | AliasChoices | None
- validation_alias: Union[str, None] = None,
- serialization_alias: Union[str, None] = None,
- title: Optional[str] = None,
- description: Optional[str] = None,
- gt: Optional[float] = None,
- ge: Optional[float] = None,
- lt: Optional[float] = None,
- le: Optional[float] = None,
- min_length: Optional[int] = None,
- max_length: Optional[int] = None,
- pattern: Optional[str] = None,
+ validation_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Whitelist' validation step. The parameter field will be the single one
+ allowed by the alias or set of aliases defined.
+ """
+ ),
+ ] = None,
+ serialization_alias: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ 'Blacklist' validation step. The vanilla parameter field will be the
+ single one of the alias' or set of aliases' fields and all the other
+ fields will be ignored at serialization time.
+ """
+ ),
+ ] = None,
+ title: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable title.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Human-readable description.
+ """
+ ),
+ ] = None,
+ gt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than. If set, value must be greater than this. Only applicable to
+ numbers.
+ """
+ ),
+ ] = None,
+ ge: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Greater than or equal. If set, value must be greater than or equal to
+ this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ lt: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than. If set, value must be less than this. Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ le: Annotated[
+ Optional[float],
+ Doc(
+ """
+ Less than or equal. If set, value must be less than or equal to this.
+ Only applicable to numbers.
+ """
+ ),
+ ] = None,
+ min_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Minimum length for strings.
+ """
+ ),
+ ] = None,
+ max_length: Annotated[
+ Optional[int],
+ Doc(
+ """
+ Maximum length for strings.
+ """
+ ),
+ ] = None,
+ pattern: Annotated[
+ Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
+ ] = None,
regex: Annotated[
Optional[str],
+ Doc(
+ """
+ RegEx pattern for strings.
+ """
+ ),
deprecated(
"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead."
),
] = None,
- discriminator: Union[str, None] = None,
- strict: Union[bool, None] = _Unset,
- multiple_of: Union[float, None] = _Unset,
- allow_inf_nan: Union[bool, None] = _Unset,
- max_digits: Union[int, None] = _Unset,
- decimal_places: Union[int, None] = _Unset,
- examples: Optional[List[Any]] = None,
+ discriminator: Annotated[
+ Union[str, None],
+ Doc(
+ """
+ Parameter field name for discriminating the type in a tagged union.
+ """
+ ),
+ ] = None,
+ strict: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ If `True`, strict validation is applied to the field.
+ """
+ ),
+ ] = _Unset,
+ multiple_of: Annotated[
+ Union[float, None],
+ Doc(
+ """
+ Value must be a multiple of this. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ allow_inf_nan: Annotated[
+ Union[bool, None],
+ Doc(
+ """
+ Allow `inf`, `-inf`, `nan`. Only applicable to numbers.
+ """
+ ),
+ ] = _Unset,
+ max_digits: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of allow digits for strings.
+ """
+ ),
+ ] = _Unset,
+ decimal_places: Annotated[
+ Union[int, None],
+ Doc(
+ """
+ Maximum number of decimal places allowed for numbers.
+ """
+ ),
+ ] = _Unset,
+ examples: Annotated[
+ Optional[List[Any]],
+ Doc(
+ """
+ Example values for this field.
+ """
+ ),
+ ] = None,
example: Annotated[
Optional[Any],
deprecated(
@@ -511,10 +2123,65 @@ def File( # noqa: N802
"although still supported. Use examples instead."
),
] = _Unset,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- json_schema_extra: Union[Dict[str, Any], None] = None,
- **extra: Any,
+ openapi_examples: Annotated[
+ Optional[Dict[str, Example]],
+ Doc(
+ """
+ OpenAPI-specific examples.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Swagger UI (that provides the `/docs` interface) has better support for the
+ OpenAPI-specific examples than the JSON Schema `examples`, that's the main
+ use case for this.
+
+ Read more about it in the
+ [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this parameter field as deprecated.
+
+ It will affect the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) this parameter field in the generated OpenAPI.
+ You probably don't need it, but it's available.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ json_schema_extra: Annotated[
+ Union[Dict[str, Any], None],
+ Doc(
+ """
+ Any additional JSON schema data.
+ """
+ ),
+ ] = None,
+ **extra: Annotated[
+ Any,
+ Doc(
+ """
+ Include extra fields used by the JSON Schema.
+ """
+ ),
+ deprecated(
+ """
+ The `extra` kwargs is deprecated. Use `json_schema_extra` instead.
+ """
+ ),
+ ],
) -> Any:
return params.File(
default=default,
@@ -542,6 +2209,7 @@ def File( # noqa: N802
decimal_places=decimal_places,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
deprecated=deprecated,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
@@ -550,15 +2218,143 @@ def File( # noqa: N802
def Depends( # noqa: N802
- dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True
+ dependency: Annotated[
+ Optional[Callable[..., Any]],
+ Doc(
+ """
+ A "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you, just pass the object
+ directly.
+ """
+ ),
+ ] = None,
+ *,
+ use_cache: Annotated[
+ bool,
+ Doc(
+ """
+ By default, after a dependency is called the first time in a request, if
+ the dependency is declared again for the rest of the request (for example
+ if the dependency is needed by several dependencies), the value will be
+ re-used for the rest of the request.
+
+ Set `use_cache` to `False` to disable this behavior and ensure the
+ dependency is called again (if declared more than once) in the same request.
+ """
+ ),
+ ] = True,
) -> Any:
+ """
+ Declare a FastAPI dependency.
+
+ It takes a single "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/).
+
+ **Example**
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+
+ app = FastAPI()
+
+
+ async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
+ return {"q": q, "skip": skip, "limit": limit}
+
+
+ @app.get("/items/")
+ async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
+ return commons
+ ```
+ """
return params.Depends(dependency=dependency, use_cache=use_cache)
def Security( # noqa: N802
- dependency: Optional[Callable[..., Any]] = None,
+ dependency: Annotated[
+ Optional[Callable[..., Any]],
+ Doc(
+ """
+ A "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you, just pass the object
+ directly.
+ """
+ ),
+ ] = None,
*,
- scopes: Optional[Sequence[str]] = None,
- use_cache: bool = True,
+ scopes: Annotated[
+ Optional[Sequence[str]],
+ Doc(
+ """
+ OAuth2 scopes required for the *path operation* that uses this Security
+ dependency.
+
+ The term "scope" comes from the OAuth2 specification, it seems to be
+ intentionaly vague and interpretable. It normally refers to permissions,
+ in cases to roles.
+
+ These scopes are integrated with OpenAPI (and the API docs at `/docs`).
+ So they are visible in the OpenAPI specification.
+ )
+ """
+ ),
+ ] = None,
+ use_cache: Annotated[
+ bool,
+ Doc(
+ """
+ By default, after a dependency is called the first time in a request, if
+ the dependency is declared again for the rest of the request (for example
+ if the dependency is needed by several dependencies), the value will be
+ re-used for the rest of the request.
+
+ Set `use_cache` to `False` to disable this behavior and ensure the
+ dependency is called again (if declared more than once) in the same request.
+ """
+ ),
+ ] = True,
) -> Any:
+ """
+ Declare a FastAPI Security dependency.
+
+ The only difference with a regular dependency is that it can declare OAuth2
+ scopes that will be integrated with OpenAPI and the automatic UI docs (by default
+ at `/docs`).
+
+ It takes a single "dependable" callable (like a function).
+
+ Don't call it directly, FastAPI will call it for you.
+
+ Read more about it in the
+ [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/) and
+ in the
+ [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).
+
+ **Example**
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+
+ from .db import User
+ from .security import get_current_active_user
+
+ app = FastAPI()
+
+ @app.get("/users/me/items/")
+ async def read_own_items(
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+ ):
+ return [{"item_id": "Foo", "owner": current_user.username}]
+ ```
+ """
return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache)
diff --git a/fastapi/params.py b/fastapi/params.py
index 30af5713e..b40944dba 100644
--- a/fastapi/params.py
+++ b/fastapi/params.py
@@ -2,6 +2,7 @@ import warnings
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
+from fastapi.openapi.models import Example
from pydantic.fields import FieldInfo
from typing_extensions import Annotated, deprecated
@@ -61,6 +62,7 @@ class Param(FieldInfo):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -69,12 +71,13 @@ class Param(FieldInfo):
self.deprecated = deprecated
if example is not _Unset:
warnings.warn(
- "`example` has been depreacated, please use `examples` instead",
+ "`example` has been deprecated, please use `examples` instead",
category=DeprecationWarning,
stacklevel=4,
)
self.example = example
self.include_in_schema = include_in_schema
+ self.openapi_examples = openapi_examples
kwargs = dict(
default=default,
default_factory=default_factory,
@@ -98,7 +101,7 @@ class Param(FieldInfo):
kwargs["examples"] = examples
if regex is not None:
warnings.warn(
- "`regex` has been depreacated, please use `pattern` instead",
+ "`regex` has been deprecated, please use `pattern` instead",
category=DeprecationWarning,
stacklevel=4,
)
@@ -170,6 +173,7 @@ class Path(Param):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -204,6 +208,7 @@ class Path(Param):
deprecated=deprecated,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
@@ -254,6 +259,7 @@ class Query(Param):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -286,6 +292,7 @@ class Query(Param):
deprecated=deprecated,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
@@ -337,6 +344,7 @@ class Header(Param):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -370,6 +378,7 @@ class Header(Param):
deprecated=deprecated,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
@@ -420,6 +429,7 @@ class Cookie(Param):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -452,6 +462,7 @@ class Cookie(Param):
deprecated=deprecated,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
@@ -502,6 +513,7 @@ class Body(FieldInfo):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -512,12 +524,13 @@ class Body(FieldInfo):
self.deprecated = deprecated
if example is not _Unset:
warnings.warn(
- "`example` has been depreacated, please use `examples` instead",
+ "`example` has been deprecated, please use `examples` instead",
category=DeprecationWarning,
stacklevel=4,
)
self.example = example
self.include_in_schema = include_in_schema
+ self.openapi_examples = openapi_examples
kwargs = dict(
default=default,
default_factory=default_factory,
@@ -613,6 +626,7 @@ class Form(Body):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -647,6 +661,7 @@ class Form(Body):
deprecated=deprecated,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
@@ -696,6 +711,7 @@ class File(Form):
"although still supported. Use examples instead."
),
] = _Unset,
+ openapi_examples: Optional[Dict[str, Example]] = None,
deprecated: Optional[bool] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
@@ -729,6 +745,7 @@ class File(Form):
deprecated=deprecated,
example=example,
examples=examples,
+ openapi_examples=openapi_examples,
include_in_schema=include_in_schema,
json_schema_extra=json_schema_extra,
**extra,
diff --git a/fastapi/responses.py b/fastapi/responses.py
index c0a13b755..6c8db6f33 100644
--- a/fastapi/responses.py
+++ b/fastapi/responses.py
@@ -21,12 +21,26 @@ except ImportError: # pragma: nocover
class UJSONResponse(JSONResponse):
+ """
+ JSON response using the high-performance ujson library to serialize data to JSON.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
+ """
+
def render(self, content: Any) -> bytes:
assert ujson is not None, "ujson must be installed to use UJSONResponse"
return ujson.dumps(content, ensure_ascii=False).encode("utf-8")
class ORJSONResponse(JSONResponse):
+ """
+ JSON response using the high-performance orjson library to serialize data to JSON.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).
+ """
+
def render(self, content: Any) -> bytes:
assert orjson is not None, "orjson must be installed to use ORJSONResponse"
return orjson.dumps(
diff --git a/fastapi/routing.py b/fastapi/routing.py
index d8ff0579c..589ecca2a 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -69,6 +69,7 @@ from starlette.routing import (
from starlette.routing import Mount as Mount # noqa
from starlette.types import ASGIApp, Lifespan, Scope
from starlette.websockets import WebSocket
+from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined]
def _prepare_response_content(
@@ -83,7 +84,7 @@ def _prepare_response_content(
if read_with_orm_mode:
# Let from_orm extract the data from this model instead of converting
# it now to a dict.
- # Otherwise there's no way to extract lazy data that requires attribute
+ # Otherwise, there's no way to extract lazy data that requires attribute
# access instead of dict iteration, e.g. lazy relationships.
return res
return _model_dump(
@@ -215,95 +216,124 @@ def get_request_handler(
actual_response_class = response_class
async def app(request: Request) -> Response:
- try:
- body: Any = None
- if body_field:
- if is_body_form:
- body = await request.form()
- stack = request.scope.get("fastapi_astack")
- assert isinstance(stack, AsyncExitStack)
- stack.push_async_callback(body.close)
+ exception_to_reraise: Optional[Exception] = None
+ response: Union[Response, None] = None
+ async with AsyncExitStack() as async_exit_stack:
+ # TODO: remove this scope later, after a few releases
+ # This scope fastapi_astack is no longer used by FastAPI, kept for
+ # compatibility, just in case
+ request.scope["fastapi_astack"] = async_exit_stack
+ try:
+ body: Any = None
+ if body_field:
+ if is_body_form:
+ body = await request.form()
+ async_exit_stack.push_async_callback(body.close)
+ else:
+ body_bytes = await request.body()
+ if body_bytes:
+ json_body: Any = Undefined
+ content_type_value = request.headers.get("content-type")
+ if not content_type_value:
+ json_body = await request.json()
+ else:
+ message = email.message.Message()
+ message["content-type"] = content_type_value
+ if message.get_content_maintype() == "application":
+ subtype = message.get_content_subtype()
+ if subtype == "json" or subtype.endswith("+json"):
+ json_body = await request.json()
+ if json_body != Undefined:
+ body = json_body
+ else:
+ body = body_bytes
+ except json.JSONDecodeError as e:
+ validation_error = RequestValidationError(
+ [
+ {
+ "type": "json_invalid",
+ "loc": ("body", e.pos),
+ "msg": "JSON decode error",
+ "input": {},
+ "ctx": {"error": e.msg},
+ }
+ ],
+ body=e.doc,
+ )
+ exception_to_reraise = validation_error
+ raise validation_error from e
+ except HTTPException as e:
+ exception_to_reraise = e
+ raise
+ except Exception as e:
+ http_error = HTTPException(
+ status_code=400, detail="There was an error parsing the body"
+ )
+ exception_to_reraise = http_error
+ raise http_error from e
+ try:
+ solved_result = await solve_dependencies(
+ request=request,
+ dependant=dependant,
+ body=body,
+ dependency_overrides_provider=dependency_overrides_provider,
+ async_exit_stack=async_exit_stack,
+ )
+ values, errors, background_tasks, sub_response, _ = solved_result
+ except Exception as e:
+ exception_to_reraise = e
+ raise e
+ if errors:
+ validation_error = RequestValidationError(
+ _normalize_errors(errors), body=body
+ )
+ exception_to_reraise = validation_error
+ raise validation_error
+ else:
+ try:
+ raw_response = await run_endpoint_function(
+ dependant=dependant, values=values, is_coroutine=is_coroutine
+ )
+ except Exception as e:
+ exception_to_reraise = e
+ raise e
+ if isinstance(raw_response, Response):
+ if raw_response.background is None:
+ raw_response.background = background_tasks
+ response = raw_response
else:
- body_bytes = await request.body()
- if body_bytes:
- json_body: Any = Undefined
- content_type_value = request.headers.get("content-type")
- if not content_type_value:
- json_body = await request.json()
- else:
- message = email.message.Message()
- message["content-type"] = content_type_value
- if message.get_content_maintype() == "application":
- subtype = message.get_content_subtype()
- if subtype == "json" or subtype.endswith("+json"):
- json_body = await request.json()
- if json_body != Undefined:
- body = json_body
- else:
- body = body_bytes
- except json.JSONDecodeError as e:
- raise RequestValidationError(
- [
- {
- "type": "json_invalid",
- "loc": ("body", e.pos),
- "msg": "JSON decode error",
- "input": {},
- "ctx": {"error": e.msg},
- }
- ],
- body=e.doc,
- ) from e
- except HTTPException:
- raise
- except Exception as e:
- raise HTTPException(
- status_code=400, detail="There was an error parsing the body"
- ) from e
- solved_result = await solve_dependencies(
- request=request,
- dependant=dependant,
- body=body,
- dependency_overrides_provider=dependency_overrides_provider,
- )
- values, errors, background_tasks, sub_response, _ = solved_result
- if errors:
- raise RequestValidationError(_normalize_errors(errors), body=body)
- else:
- raw_response = await run_endpoint_function(
- dependant=dependant, values=values, is_coroutine=is_coroutine
- )
-
- if isinstance(raw_response, Response):
- if raw_response.background is None:
- raw_response.background = background_tasks
- return raw_response
- response_args: Dict[str, Any] = {"background": background_tasks}
- # If status_code was set, use it, otherwise use the default from the
- # response class, in the case of redirect it's 307
- current_status_code = (
- status_code if status_code else sub_response.status_code
- )
- if current_status_code is not None:
- response_args["status_code"] = current_status_code
- if sub_response.status_code:
- response_args["status_code"] = sub_response.status_code
- content = await serialize_response(
- field=response_field,
- response_content=raw_response,
- include=response_model_include,
- exclude=response_model_exclude,
- by_alias=response_model_by_alias,
- exclude_unset=response_model_exclude_unset,
- exclude_defaults=response_model_exclude_defaults,
- exclude_none=response_model_exclude_none,
- is_coroutine=is_coroutine,
- )
- response = actual_response_class(content, **response_args)
- if not is_body_allowed_for_status_code(response.status_code):
- response.body = b""
- response.headers.raw.extend(sub_response.headers.raw)
- return response
+ response_args: Dict[str, Any] = {"background": background_tasks}
+ # If status_code was set, use it, otherwise use the default from the
+ # response class, in the case of redirect it's 307
+ current_status_code = (
+ status_code if status_code else sub_response.status_code
+ )
+ if current_status_code is not None:
+ response_args["status_code"] = current_status_code
+ if sub_response.status_code:
+ response_args["status_code"] = sub_response.status_code
+ content = await serialize_response(
+ field=response_field,
+ response_content=raw_response,
+ include=response_model_include,
+ exclude=response_model_exclude,
+ by_alias=response_model_by_alias,
+ exclude_unset=response_model_exclude_unset,
+ exclude_defaults=response_model_exclude_defaults,
+ exclude_none=response_model_exclude_none,
+ is_coroutine=is_coroutine,
+ )
+ response = actual_response_class(content, **response_args)
+ if not is_body_allowed_for_status_code(response.status_code):
+ response.body = b""
+ response.headers.raw.extend(sub_response.headers.raw)
+ # This exception was possibly handled by the dependency but it should
+ # still bubble up so that the ServerErrorMiddleware can return a 500
+ # or the ExceptionMiddleware can catch and handle any other exceptions
+ if exception_to_reraise:
+ raise exception_to_reraise
+ assert response is not None, "An error occurred while generating the request"
+ return response
return app
@@ -312,16 +342,22 @@ def get_websocket_app(
dependant: Dependant, dependency_overrides_provider: Optional[Any] = None
) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
async def app(websocket: WebSocket) -> None:
- solved_result = await solve_dependencies(
- request=websocket,
- dependant=dependant,
- dependency_overrides_provider=dependency_overrides_provider,
- )
- values, errors, _, _2, _3 = solved_result
- if errors:
- raise WebSocketRequestValidationError(_normalize_errors(errors))
- assert dependant.call is not None, "dependant.call must be a function"
- await dependant.call(**values)
+ async with AsyncExitStack() as async_exit_stack:
+ # TODO: remove this scope later, after a few releases
+ # This scope fastapi_astack is no longer used by FastAPI, kept for
+ # compatibility, just in case
+ websocket.scope["fastapi_astack"] = async_exit_stack
+ solved_result = await solve_dependencies(
+ request=websocket,
+ dependant=dependant,
+ dependency_overrides_provider=dependency_overrides_provider,
+ async_exit_stack=async_exit_stack,
+ )
+ values, errors, _, _2, _3 = solved_result
+ if errors:
+ raise WebSocketRequestValidationError(_normalize_errors(errors))
+ assert dependant.call is not None, "dependant.call must be a function"
+ await dependant.call(**values)
return app
@@ -448,9 +484,7 @@ class APIRoute(routing.Route):
self.response_field = create_response_field(
name=response_name,
type_=self.response_model,
- # TODO: This should actually set mode='serialization', just, that changes the schemas
- # mode="serialization",
- mode="validation",
+ mode="serialization",
)
# Create a clone of the field, so that a Pydantic submodel is not returned
# as is just because it's an instance of a subclass of a more limited class
@@ -458,7 +492,7 @@ class APIRoute(routing.Route):
# that doesn't have the hashed_password. But because it's a subclass, it
# would pass the validation and be returned as is.
# By being a new field, no inheritance will be passed as is. A new model
- # will be always created.
+ # will always be created.
# TODO: remove when deprecating Pydantic v1
self.secure_cloned_response_field: Optional[
ModelField
@@ -521,30 +555,246 @@ class APIRoute(routing.Route):
class APIRouter(routing.Router):
+ """
+ `APIRouter` class, used to group *path operations*, for example to structure
+ an app in multiple files. It would then be included in the `FastAPI` app, or
+ in another `APIRouter` (ultimately included in the app).
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+
+ @router.get("/users/", tags=["users"])
+ async def read_users():
+ return [{"username": "Rick"}, {"username": "Morty"}]
+
+
+ app.include_router(router)
+ ```
+ """
+
def __init__(
self,
*,
- prefix: str = "",
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- default_response_class: Type[Response] = Default(JSONResponse),
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- routes: Optional[List[routing.BaseRoute]] = None,
- redirect_slashes: bool = True,
- default: Optional[ASGIApp] = None,
- dependency_overrides_provider: Optional[Any] = None,
- route_class: Type[APIRoute] = APIRoute,
- on_startup: Optional[Sequence[Callable[[], Any]]] = None,
- on_shutdown: Optional[Sequence[Callable[[], Any]]] = None,
+ prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to all the *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to all the
+ *path operations* in this router.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ The default response class to be used.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+ """
+ ),
+ ] = Default(JSONResponse),
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ OpenAPI callbacks that should apply to all *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ routes: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ **Note**: you probably shouldn't use this parameter, it is inherited
+ from Starlette and supported for compatibility.
+
+ ---
+
+ A list of routes to serve incoming HTTP and WebSocket requests.
+ """
+ ),
+ deprecated(
+ """
+ You normally wouldn't use this parameter with FastAPI, it is inherited
+ from Starlette and supported for compatibility.
+
+ In FastAPI, you normally would use the *path operation methods*,
+ like `router.get()`, `router.post()`, etc.
+ """
+ ),
+ ] = None,
+ redirect_slashes: Annotated[
+ bool,
+ Doc(
+ """
+ Whether to detect and redirect slashes in URLs when the client doesn't
+ use the same format.
+ """
+ ),
+ ] = True,
+ default: Annotated[
+ Optional[ASGIApp],
+ Doc(
+ """
+ Default function handler for this router. Used to handle
+ 404 Not Found errors.
+ """
+ ),
+ ] = None,
+ dependency_overrides_provider: Annotated[
+ Optional[Any],
+ Doc(
+ """
+ Only used internally by FastAPI to handle dependency overrides.
+
+ You shouldn't need to use it. It normally points to the `FastAPI` app
+ object.
+ """
+ ),
+ ] = None,
+ route_class: Annotated[
+ Type[APIRoute],
+ Doc(
+ """
+ Custom route (*path operation*) class to be used by this router.
+
+ Read more about it in the
+ [FastAPI docs for Custom Request and APIRoute class](https://fastapi.tiangolo.com/how-to/custom-request-and-route/#custom-apiroute-class-in-a-router).
+ """
+ ),
+ ] = APIRoute,
+ on_startup: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of startup event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ on_shutdown: Annotated[
+ Optional[Sequence[Callable[[], Any]]],
+ Doc(
+ """
+ A list of shutdown event handler functions.
+
+ You should instead use the `lifespan` handlers.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
# the generic to Lifespan[AppType] is the type of the top level application
# which the router cannot know statically, so we use typing.Any
- lifespan: Optional[Lifespan[Any]] = None,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ lifespan: Annotated[
+ Optional[Lifespan[Any]],
+ Doc(
+ """
+ A `Lifespan` context manager handler. This replaces `startup` and
+ `shutdown` functions with a single context manager.
+
+ Read more in the
+ [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all *path operations* in this router as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ To include (or not) all the *path operations* in this router in the
+ generated OpenAPI.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> None:
super().__init__(
routes=routes,
@@ -757,11 +1007,63 @@ class APIRouter(routing.Router):
def websocket(
self,
- path: str,
- name: Optional[str] = None,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ WebSocket path.
+ """
+ ),
+ ],
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A name for the WebSocket. Only used internally.
+ """
+ ),
+ ] = None,
*,
- dependencies: Optional[Sequence[params.Depends]] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be used for this
+ WebSocket.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+ """
+ ),
+ ] = None,
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Decorate a WebSocket function.
+
+ Read more about it in the
+ [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).
+
+ **Example**
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI, WebSocket
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.websocket("/ws")
+ async def websocket_endpoint(websocket: WebSocket):
+ await websocket.accept()
+ while True:
+ data = await websocket.receive_text()
+ await websocket.send_text(f"Message text was: {data}")
+
+ app.include_router(router)
+ ```
+ """
+
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.add_api_websocket_route(
path, func, name=name, dependencies=dependencies
@@ -781,20 +1083,139 @@ class APIRouter(routing.Router):
def include_router(
self,
- router: "APIRouter",
+ router: Annotated["APIRouter", Doc("The `APIRouter` to include.")],
*,
- prefix: str = "",
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- default_response_class: Type[Response] = Default(JSONResponse),
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- deprecated: Optional[bool] = None,
- include_in_schema: bool = True,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "",
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to all the *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to all the
+ *path operations* in this router.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ default_response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ The default response class to be used.
+
+ Read more in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
+ """
+ ),
+ ] = Default(JSONResponse),
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses to be shown in OpenAPI.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
+
+ And in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ OpenAPI callbacks that should apply to all *path operations* in this
+ router.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark all *path operations* in this router as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include (or not) all the *path operations* in this router in the
+ generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = True,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> None:
+ """
+ Include another `APIRouter` in the same current `APIRouter`.
+
+ Read more about it in the
+ [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ internal_router = APIRouter()
+ users_router = APIRouter()
+
+ @users_router.get("/users/")
+ def read_users():
+ return [{"name": "Rick"}, {"name": "Morty"}]
+
+ internal_router.include_router(users_router)
+ app.include_router(internal_router)
+ ```
+ """
if prefix:
assert prefix.startswith("/"), "A path prefix must start with '/'"
assert not prefix.endswith(
@@ -902,33 +1323,354 @@ class APIRouter(routing.Router):
def get(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP GET operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.get("/items/")
+ def read_items():
+ return [{"name": "Empanada"}, {"name": "Arepa"}]
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -958,33 +1700,359 @@ class APIRouter(routing.Router):
def put(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PUT operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.put("/items/{item_id}")
+ def replace_item(item_id: str, item: Item):
+ return {"message": "Item replaced", "id": item_id}
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -1014,33 +2082,359 @@ class APIRouter(routing.Router):
def post(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP POST operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.post("/items/")
+ def create_item(item: Item):
+ return {"message": "Item created"}
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -1070,33 +2464,354 @@ class APIRouter(routing.Router):
def delete(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP DELETE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.delete("/items/{item_id}")
+ def delete_item(item_id: str):
+ return {"message": "Item deleted"}
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -1126,33 +2841,354 @@ class APIRouter(routing.Router):
def options(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP OPTIONS operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.options("/items/")
+ def get_item_options():
+ return {"additions": ["Aji", "Guacamole"]}
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -1182,33 +3218,359 @@ class APIRouter(routing.Router):
def head(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP HEAD operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.head("/items/", status_code=204)
+ def get_items_headers(response: Response):
+ response.headers["X-Cat-Dog"] = "Alone in the world"
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -1238,33 +3600,359 @@ class APIRouter(routing.Router):
def patch(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP PATCH operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.patch("/items/")
+ def update_item(item: Item):
+ return {"message": "Item updated in place"}
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -1294,33 +3982,359 @@ class APIRouter(routing.Router):
def trace(
self,
- path: str,
+ path: Annotated[
+ str,
+ Doc(
+ """
+ The URL path to be used for this *path operation*.
+
+ For example, in `http://example.com/items`, the path is `/items`.
+ """
+ ),
+ ],
*,
- response_model: Any = Default(None),
- status_code: Optional[int] = None,
- tags: Optional[List[Union[str, Enum]]] = None,
- dependencies: Optional[Sequence[params.Depends]] = None,
- summary: Optional[str] = None,
- description: Optional[str] = None,
- response_description: str = "Successful Response",
- responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
- deprecated: Optional[bool] = None,
- operation_id: Optional[str] = None,
- response_model_include: Optional[IncEx] = None,
- response_model_exclude: Optional[IncEx] = None,
- response_model_by_alias: bool = True,
- response_model_exclude_unset: bool = False,
- response_model_exclude_defaults: bool = False,
- response_model_exclude_none: bool = False,
- include_in_schema: bool = True,
- response_class: Type[Response] = Default(JSONResponse),
- name: Optional[str] = None,
- callbacks: Optional[List[BaseRoute]] = None,
- openapi_extra: Optional[Dict[str, Any]] = None,
- generate_unique_id_function: Callable[[APIRoute], str] = Default(
- generate_unique_id
- ),
+ response_model: Annotated[
+ Any,
+ Doc(
+ """
+ The type to use for the response.
+
+ It could be any valid Pydantic *field* type. So, it doesn't have to
+ be a Pydantic model, it could be other things, like a `list`, `dict`,
+ etc.
+
+ It will be used for:
+
+ * Documentation: the generated OpenAPI (and the UI at `/docs`) will
+ show it as the response (JSON Schema).
+ * Serialization: you could return an arbitrary object and the
+ `response_model` would be used to serialize that object into the
+ corresponding JSON.
+ * Filtering: the JSON sent to the client will only contain the data
+ (fields) defined in the `response_model`. If you returned an object
+ that contains an attribute `password` but the `response_model` does
+ not include that field, the JSON sent to the client would not have
+ that `password`.
+ * Validation: whatever you return will be serialized with the
+ `response_model`, converting any data as necessary to generate the
+ corresponding JSON. But if the data in the object returned is not
+ valid, that would mean a violation of the contract with the client,
+ so it's an error from the API developer. So, FastAPI will raise an
+ error and return a 500 error code (Internal Server Error).
+
+ Read more about it in the
+ [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).
+ """
+ ),
+ ] = Default(None),
+ status_code: Annotated[
+ Optional[int],
+ Doc(
+ """
+ The default status code to be used for the response.
+
+ You could override the status code by returning a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).
+ """
+ ),
+ ] = None,
+ tags: Annotated[
+ Optional[List[Union[str, Enum]]],
+ Doc(
+ """
+ A list of tags to be applied to the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags).
+ """
+ ),
+ ] = None,
+ dependencies: Annotated[
+ Optional[Sequence[params.Depends]],
+ Doc(
+ """
+ A list of dependencies (using `Depends()`) to be applied to the
+ *path operation*.
+
+ Read more about it in the
+ [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/).
+ """
+ ),
+ ] = None,
+ summary: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A summary for the *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ A description for the *path operation*.
+
+ If not provided, it will be extracted automatically from the docstring
+ of the *path operation function*.
+
+ It can contain Markdown.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
+ """
+ ),
+ ] = None,
+ response_description: Annotated[
+ str,
+ Doc(
+ """
+ The description for the default response.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = "Successful Response",
+ responses: Annotated[
+ Optional[Dict[Union[int, str], Dict[str, Any]]],
+ Doc(
+ """
+ Additional responses that could be returned by this *path operation*.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ deprecated: Annotated[
+ Optional[bool],
+ Doc(
+ """
+ Mark this *path operation* as deprecated.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ operation_id: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Custom operation ID to be used by this *path operation*.
+
+ By default, it is generated automatically.
+
+ If you provide a custom operation ID, you need to make sure it is
+ unique for the whole API.
+
+ You can customize the
+ operation ID generation with the parameter
+ `generate_unique_id_function` in the `FastAPI` class.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = None,
+ response_model_include: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to include only certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_exclude: Annotated[
+ Optional[IncEx],
+ Doc(
+ """
+ Configuration passed to Pydantic to exclude certain fields in the
+ response data.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = None,
+ response_model_by_alias: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response model
+ should be serialized by alias when an alias is used.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude).
+ """
+ ),
+ ] = True,
+ response_model_exclude_unset: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that were not set and
+ have their default values. This is different from
+ `response_model_exclude_defaults` in that if the fields are set,
+ they will be included in the response, even if the value is the same
+ as the default.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_defaults: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data
+ should have all the fields, including the ones that have the same value
+ as the default. This is different from `response_model_exclude_unset`
+ in that if the fields are set but contain the same default values,
+ they will be excluded from the response.
+
+ When `True`, default values are omitted from the response.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter).
+ """
+ ),
+ ] = False,
+ response_model_exclude_none: Annotated[
+ bool,
+ Doc(
+ """
+ Configuration passed to Pydantic to define if the response data should
+ exclude fields set to `None`.
+
+ This is much simpler (less smart) than `response_model_exclude_unset`
+ and `response_model_exclude_defaults`. You probably want to use one of
+ those two instead of this one, as those allow returning `None` values
+ when it makes sense.
+
+ Read more about it in the
+ [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none).
+ """
+ ),
+ ] = False,
+ include_in_schema: Annotated[
+ bool,
+ Doc(
+ """
+ Include this *path operation* in the generated OpenAPI schema.
+
+ This affects the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi).
+ """
+ ),
+ ] = True,
+ response_class: Annotated[
+ Type[Response],
+ Doc(
+ """
+ Response class to be used for this *path operation*.
+
+ This will not be used if you return a response directly.
+
+ Read more about it in the
+ [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse).
+ """
+ ),
+ ] = Default(JSONResponse),
+ name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Name for this *path operation*. Only used internally.
+ """
+ ),
+ ] = None,
+ callbacks: Annotated[
+ Optional[List[BaseRoute]],
+ Doc(
+ """
+ List of *path operations* that will be used as OpenAPI callbacks.
+
+ This is only for OpenAPI documentation, the callbacks won't be used
+ directly.
+
+ It will be added to the generated OpenAPI (e.g. visible at `/docs`).
+
+ Read more about it in the
+ [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
+ """
+ ),
+ ] = None,
+ openapi_extra: Annotated[
+ Optional[Dict[str, Any]],
+ Doc(
+ """
+ Extra metadata to be included in the OpenAPI schema for this *path
+ operation*.
+
+ Read more about it in the
+ [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema).
+ """
+ ),
+ ] = None,
+ generate_unique_id_function: Annotated[
+ Callable[[APIRoute], str],
+ Doc(
+ """
+ Customize the function used to generate unique IDs for the *path
+ operations* shown in the generated OpenAPI.
+
+ This is particularly useful when automatically generating clients or
+ SDKs for your API.
+
+ Read more about it in the
+ [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
+ """
+ ),
+ ] = Default(generate_unique_id),
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add a *path operation* using an HTTP TRACE operation.
+
+ ## Example
+
+ ```python
+ from fastapi import APIRouter, FastAPI
+ from pydantic import BaseModel
+
+ class Item(BaseModel):
+ name: str
+ description: str | None = None
+
+ app = FastAPI()
+ router = APIRouter()
+
+ @router.put("/items/{item_id}")
+ def trace_item(item_id: str):
+ return None
+
+ app.include_router(router)
+ ```
+ """
return self.api_route(
path=path,
response_model=response_model,
@@ -1348,9 +4362,34 @@ class APIRouter(routing.Router):
generate_unique_id_function=generate_unique_id_function,
)
+ @deprecated(
+ """
+ on_event is deprecated, use lifespan event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/).
+ """
+ )
def on_event(
- self, event_type: str
+ self,
+ event_type: Annotated[
+ str,
+ Doc(
+ """
+ The type of event. `startup` or `shutdown`.
+ """
+ ),
+ ],
) -> Callable[[DecoratedCallable], DecoratedCallable]:
+ """
+ Add an event handler for the router.
+
+ `on_event` is deprecated, use `lifespan` event handlers instead.
+
+ Read more about it in the
+ [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated).
+ """
+
def decorator(func: DecoratedCallable) -> DecoratedCallable:
self.add_event_handler(event_type, func)
return func
diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py
index 8b2c5c080..b1a6b4f94 100644
--- a/fastapi/security/api_key.py
+++ b/fastapi/security/api_key.py
@@ -5,6 +5,7 @@ from fastapi.security.base import SecurityBase
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
class APIKeyBase(SecurityBase):
@@ -12,13 +13,83 @@ class APIKeyBase(SecurityBase):
class APIKeyQuery(APIKeyBase):
+ """
+ API key authentication using a query parameter.
+
+ This defines the name of the query parameter that should be provided in the request
+ with the API key and integrates that into the OpenAPI documentation. It extracts
+ the key value sent in the query parameter automatically and provides it as the
+ dependency result. But it doesn't define how to send that API key to the client.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be a string containing the key value.
+
+ ## Example
+
+ ```python
+ from fastapi import Depends, FastAPI
+ from fastapi.security import APIKeyQuery
+
+ app = FastAPI()
+
+ query_scheme = APIKeyQuery(name="api_key")
+
+
+ @app.get("/items/")
+ async def read_items(api_key: str = Depends(query_scheme)):
+ return {"api_key": api_key}
+ ```
+ """
+
def __init__(
self,
*,
- name: str,
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ name: Annotated[
+ str,
+ Doc("Query parameter name."),
+ ],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the query parameter is not provided, `APIKeyQuery` will
+ automatically cancel the request and sebd the client an error.
+
+ If `auto_error` is set to `False`, when the query parameter is not
+ available, instead of erroring out, the dependency result will be
+ `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in a query
+ parameter or in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
):
self.model: APIKey = APIKey(
**{"in": APIKeyIn.query}, # type: ignore[arg-type]
@@ -41,13 +112,79 @@ class APIKeyQuery(APIKeyBase):
class APIKeyHeader(APIKeyBase):
+ """
+ API key authentication using a header.
+
+ This defines the name of the header that should be provided in the request with
+ the API key and integrates that into the OpenAPI documentation. It extracts
+ the key value sent in the header automatically and provides it as the dependency
+ result. But it doesn't define how to send that key to the client.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be a string containing the key value.
+
+ ## Example
+
+ ```python
+ from fastapi import Depends, FastAPI
+ from fastapi.security import APIKeyHeader
+
+ app = FastAPI()
+
+ header_scheme = APIKeyHeader(name="x-key")
+
+
+ @app.get("/items/")
+ async def read_items(key: str = Depends(header_scheme)):
+ return {"key": key}
+ ```
+ """
+
def __init__(
self,
*,
- name: str,
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ name: Annotated[str, Doc("Header name.")],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the header is not provided, `APIKeyHeader` will
+ automatically cancel the request and send the client an error.
+
+ If `auto_error` is set to `False`, when the header is not available,
+ instead of erroring out, the dependency result will be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in a header or
+ in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
):
self.model: APIKey = APIKey(
**{"in": APIKeyIn.header}, # type: ignore[arg-type]
@@ -70,13 +207,79 @@ class APIKeyHeader(APIKeyBase):
class APIKeyCookie(APIKeyBase):
+ """
+ API key authentication using a cookie.
+
+ This defines the name of the cookie that should be provided in the request with
+ the API key and integrates that into the OpenAPI documentation. It extracts
+ the key value sent in the cookie automatically and provides it as the dependency
+ result. But it doesn't define how to set that cookie.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be a string containing the key value.
+
+ ## Example
+
+ ```python
+ from fastapi import Depends, FastAPI
+ from fastapi.security import APIKeyCookie
+
+ app = FastAPI()
+
+ cookie_scheme = APIKeyCookie(name="session")
+
+
+ @app.get("/items/")
+ async def read_items(session: str = Depends(cookie_scheme)):
+ return {"session": session}
+ ```
+ """
+
def __init__(
self,
*,
- name: str,
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ name: Annotated[str, Doc("Cookie name.")],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the cookie is not provided, `APIKeyCookie` will
+ automatically cancel the request and send the client an error.
+
+ If `auto_error` is set to `False`, when the cookie is not available,
+ instead of erroring out, the dependency result will be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in a cookie or
+ in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
):
self.model: APIKey = APIKey(
**{"in": APIKeyIn.cookie}, # type: ignore[arg-type]
diff --git a/fastapi/security/http.py b/fastapi/security/http.py
index 8fc0aafd9..738455de3 100644
--- a/fastapi/security/http.py
+++ b/fastapi/security/http.py
@@ -10,16 +10,60 @@ from fastapi.security.utils import get_authorization_scheme_param
from pydantic import BaseModel
from starlette.requests import Request
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
class HTTPBasicCredentials(BaseModel):
- username: str
- password: str
+ """
+ The HTTP Basic credendials given as the result of using `HTTPBasic` in a
+ dependency.
+
+ Read more about it in the
+ [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).
+ """
+
+ username: Annotated[str, Doc("The HTTP Basic username.")]
+ password: Annotated[str, Doc("The HTTP Basic password.")]
class HTTPAuthorizationCredentials(BaseModel):
- scheme: str
- credentials: str
+ """
+ The HTTP authorization credentials in the result of using `HTTPBearer` or
+ `HTTPDigest` in a dependency.
+
+ The HTTP authorization header value is split by the first space.
+
+ The first part is the `scheme`, the second part is the `credentials`.
+
+ For example, in an HTTP Bearer token scheme, the client will send a header
+ like:
+
+ ```
+ Authorization: Bearer deadbeef12346
+ ```
+
+ In this case:
+
+ * `scheme` will have the value `"Bearer"`
+ * `credentials` will have the value `"deadbeef12346"`
+ """
+
+ scheme: Annotated[
+ str,
+ Doc(
+ """
+ The HTTP authorization scheme extracted from the header value.
+ """
+ ),
+ ]
+ credentials: Annotated[
+ str,
+ Doc(
+ """
+ The HTTP authorization credentials extracted from the header value.
+ """
+ ),
+ ]
class HTTPBase(SecurityBase):
@@ -51,13 +95,89 @@ class HTTPBase(SecurityBase):
class HTTPBasic(HTTPBase):
+ """
+ HTTP Basic authentication.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be an `HTTPBasicCredentials` object containing the
+ `username` and the `password`.
+
+ Read more about it in the
+ [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import HTTPBasic, HTTPBasicCredentials
+
+ app = FastAPI()
+
+ security = HTTPBasic()
+
+
+ @app.get("/users/me")
+ def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):
+ return {"username": credentials.username, "password": credentials.password}
+ ```
+ """
+
def __init__(
self,
*,
- scheme_name: Optional[str] = None,
- realm: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ realm: Annotated[
+ Optional[str],
+ Doc(
+ """
+ HTTP Basic authentication realm.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the HTTP Basic authentication is not provided (a
+ header), `HTTPBasic` will automatically cancel the request and send the
+ client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Basic authentication
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in HTTP Basic
+ authentication or in an HTTP Bearer token).
+ """
+ ),
+ ] = True,
):
self.model = HTTPBaseModel(scheme="basic", description=description)
self.scheme_name = scheme_name or self.__class__.__name__
@@ -90,7 +210,7 @@ class HTTPBasic(HTTPBase):
try:
data = b64decode(param).decode("ascii")
except (ValueError, UnicodeDecodeError, binascii.Error):
- raise invalid_user_credentials_exc
+ raise invalid_user_credentials_exc # noqa: B904
username, separator, password = data.partition(":")
if not separator:
raise invalid_user_credentials_exc
@@ -98,13 +218,81 @@ class HTTPBasic(HTTPBase):
class HTTPBearer(HTTPBase):
+ """
+ HTTP Bearer token authentication.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be an `HTTPAuthorizationCredentials` object containing
+ the `scheme` and the `credentials`.
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
+
+ app = FastAPI()
+
+ security = HTTPBearer()
+
+
+ @app.get("/users/me")
+ def read_current_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]
+ ):
+ return {"scheme": credentials.scheme, "credentials": credentials.credentials}
+ ```
+ """
+
def __init__(
self,
*,
- bearerFormat: Optional[str] = None,
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ bearerFormat: Annotated[Optional[str], Doc("Bearer token format.")] = None,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the HTTP Bearer token not provided (in an
+ `Authorization` header), `HTTPBearer` will automatically cancel the
+ request and send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Bearer token
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in an HTTP
+ Bearer token or in a cookie).
+ """
+ ),
+ ] = True,
):
self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description)
self.scheme_name = scheme_name or self.__class__.__name__
@@ -134,12 +322,79 @@ class HTTPBearer(HTTPBase):
class HTTPDigest(HTTPBase):
+ """
+ HTTP Digest authentication.
+
+ ## Usage
+
+ Create an instance object and use that object as the dependency in `Depends()`.
+
+ The dependency result will be an `HTTPAuthorizationCredentials` object containing
+ the `scheme` and the `credentials`.
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest
+
+ app = FastAPI()
+
+ security = HTTPDigest()
+
+
+ @app.get("/users/me")
+ def read_current_user(
+ credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]
+ ):
+ return {"scheme": credentials.scheme, "credentials": credentials.credentials}
+ ```
+ """
+
def __init__(
self,
*,
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if the HTTP Digest not provided, `HTTPDigest` will
+ automatically cancel the request and send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Digest is not
+ available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, in HTTP
+ Digest or in a cookie).
+ """
+ ),
+ ] = True,
):
self.model = HTTPBaseModel(scheme="digest", description=description)
self.scheme_name = scheme_name or self.__class__.__name__
diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py
index e4c4357e7..9281dfb64 100644
--- a/fastapi/security/oauth2.py
+++ b/fastapi/security/oauth2.py
@@ -10,51 +10,136 @@ from starlette.requests import Request
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
# TODO: import from typing when deprecating Python 3.9
-from typing_extensions import Annotated
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
class OAuth2PasswordRequestForm:
"""
- This is a dependency class, use it like:
+ This is a dependency class to collect the `username` and `password` as form data
+ for an OAuth2 password flow.
- @app.post("/login")
- def login(form_data: OAuth2PasswordRequestForm = Depends()):
- data = form_data.parse()
- print(data.username)
- print(data.password)
- for scope in data.scopes:
- print(scope)
- if data.client_id:
- print(data.client_id)
- if data.client_secret:
- print(data.client_secret)
- return data
+ The OAuth2 specification dictates that for a password flow the data should be
+ collected using form data (instead of JSON) and that it should have the specific
+ fields `username` and `password`.
+ All the initialization parameters are extracted from the request.
- It creates the following Form request parameters in your endpoint:
+ Read more about it in the
+ [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
- grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".
- Nevertheless, this dependency class is permissive and allows not passing it. If you want to enforce it,
- use instead the OAuth2PasswordRequestFormStrict dependency.
- username: username string. The OAuth2 spec requires the exact field name "username".
- password: password string. The OAuth2 spec requires the exact field name "password".
- scope: Optional string. Several scopes (each one a string) separated by spaces. E.g.
- "items:read items:write users:read profile openid"
- client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
- using HTTP Basic auth, as: client_id:client_secret
- client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
- using HTTP Basic auth, as: client_id:client_secret
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import OAuth2PasswordRequestForm
+
+ app = FastAPI()
+
+
+ @app.post("/login")
+ def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
+ data = {}
+ data["scopes"] = []
+ for scope in form_data.scopes:
+ data["scopes"].append(scope)
+ if form_data.client_id:
+ data["client_id"] = form_data.client_id
+ if form_data.client_secret:
+ data["client_secret"] = form_data.client_secret
+ return data
+ ```
+
+ Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
+ You could have custom internal logic to separate it by colon caracters (`:`) or
+ similar, and get the two parts `items` and `read`. Many applications do that to
+ group and organize permisions, you could do it as well in your application, just
+ know that that it is application specific, it's not part of the specification.
"""
def __init__(
self,
*,
- grant_type: Annotated[Union[str, None], Form(pattern="password")] = None,
- username: Annotated[str, Form()],
- password: Annotated[str, Form()],
- scope: Annotated[str, Form()] = "",
- client_id: Annotated[Union[str, None], Form()] = None,
- client_secret: Annotated[Union[str, None], Form()] = None,
+ grant_type: Annotated[
+ Union[str, None],
+ Form(pattern="password"),
+ Doc(
+ """
+ The OAuth2 spec says it is required and MUST be the fixed string
+ "password". Nevertheless, this dependency class is permissive and
+ allows not passing it. If you want to enforce it, use instead the
+ `OAuth2PasswordRequestFormStrict` dependency.
+ """
+ ),
+ ] = None,
+ username: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `username` string. The OAuth2 spec requires the exact field name
+ `username`.
+ """
+ ),
+ ],
+ password: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `password` string. The OAuth2 spec requires the exact field name
+ `password".
+ """
+ ),
+ ],
+ scope: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ A single string with actually several scopes separated by spaces. Each
+ scope is also a string.
+
+ For example, a single string with:
+
+ ```python
+ "items:read items:write users:read profile openid"
+ ````
+
+ would represent the scopes:
+
+ * `items:read`
+ * `items:write`
+ * `users:read`
+ * `profile`
+ * `openid`
+ """
+ ),
+ ] = "",
+ client_id: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_id`, it can be sent as part of the form fields.
+ But the OAuth2 specification recommends sending the `client_id` and
+ `client_secret` (if any) using HTTP Basic auth.
+ """
+ ),
+ ] = None,
+ client_secret: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_password` (and a `client_id`), they can be sent
+ as part of the form fields. But the OAuth2 specification recommends
+ sending the `client_id` and `client_secret` (if any) using HTTP Basic
+ auth.
+ """
+ ),
+ ] = None,
):
self.grant_type = grant_type
self.username = username
@@ -66,23 +151,54 @@ class OAuth2PasswordRequestForm:
class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
"""
- This is a dependency class, use it like:
+ This is a dependency class to collect the `username` and `password` as form data
+ for an OAuth2 password flow.
+
+ The OAuth2 specification dictates that for a password flow the data should be
+ collected using form data (instead of JSON) and that it should have the specific
+ fields `username` and `password`.
+
+ All the initialization parameters are extracted from the request.
+
+ The only difference between `OAuth2PasswordRequestFormStrict` and
+ `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the
+ client to send the form field `grant_type` with the value `"password"`, which
+ is required in the OAuth2 specification (it seems that for no particular reason),
+ while for `OAuth2PasswordRequestForm` `grant_type` is optional.
+
+ Read more about it in the
+ [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
+
+ ## Example
+
+ ```python
+ from typing import Annotated
+
+ from fastapi import Depends, FastAPI
+ from fastapi.security import OAuth2PasswordRequestForm
- @app.post("/login")
- def login(form_data: OAuth2PasswordRequestFormStrict = Depends()):
- data = form_data.parse()
- print(data.username)
- print(data.password)
- for scope in data.scopes:
- print(scope)
- if data.client_id:
- print(data.client_id)
- if data.client_secret:
- print(data.client_secret)
- return data
+ app = FastAPI()
- It creates the following Form request parameters in your endpoint:
+ @app.post("/login")
+ def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]):
+ data = {}
+ data["scopes"] = []
+ for scope in form_data.scopes:
+ data["scopes"].append(scope)
+ if form_data.client_id:
+ data["client_id"] = form_data.client_id
+ if form_data.client_secret:
+ data["client_secret"] = form_data.client_secret
+ return data
+ ```
+
+ Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
+ You could have custom internal logic to separate it by colon caracters (`:`) or
+ similar, and get the two parts `items` and `read`. Many applications do that to
+ group and organize permisions, you could do it as well in your application, just
+ know that that it is application specific, it's not part of the specification.
+
grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".
This dependency is strict about it. If you want to be permissive, use instead the
@@ -99,12 +215,85 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
def __init__(
self,
- grant_type: Annotated[str, Form(pattern="password")],
- username: Annotated[str, Form()],
- password: Annotated[str, Form()],
- scope: Annotated[str, Form()] = "",
- client_id: Annotated[Union[str, None], Form()] = None,
- client_secret: Annotated[Union[str, None], Form()] = None,
+ grant_type: Annotated[
+ str,
+ Form(pattern="password"),
+ Doc(
+ """
+ The OAuth2 spec says it is required and MUST be the fixed string
+ "password". This dependency is strict about it. If you want to be
+ permissive, use instead the `OAuth2PasswordRequestForm` dependency
+ class.
+ """
+ ),
+ ],
+ username: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `username` string. The OAuth2 spec requires the exact field name
+ `username`.
+ """
+ ),
+ ],
+ password: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ `password` string. The OAuth2 spec requires the exact field name
+ `password".
+ """
+ ),
+ ],
+ scope: Annotated[
+ str,
+ Form(),
+ Doc(
+ """
+ A single string with actually several scopes separated by spaces. Each
+ scope is also a string.
+
+ For example, a single string with:
+
+ ```python
+ "items:read items:write users:read profile openid"
+ ````
+
+ would represent the scopes:
+
+ * `items:read`
+ * `items:write`
+ * `users:read`
+ * `profile`
+ * `openid`
+ """
+ ),
+ ] = "",
+ client_id: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_id`, it can be sent as part of the form fields.
+ But the OAuth2 specification recommends sending the `client_id` and
+ `client_secret` (if any) using HTTP Basic auth.
+ """
+ ),
+ ] = None,
+ client_secret: Annotated[
+ Union[str, None],
+ Form(),
+ Doc(
+ """
+ If there's a `client_password` (and a `client_id`), they can be sent
+ as part of the form fields. But the OAuth2 specification recommends
+ sending the `client_id` and `client_secret` (if any) using HTTP Basic
+ auth.
+ """
+ ),
+ ] = None,
):
super().__init__(
grant_type=grant_type,
@@ -117,13 +306,69 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
class OAuth2(SecurityBase):
+ """
+ This is the base class for OAuth2 authentication, an instance of it would be used
+ as a dependency. All other OAuth2 classes inherit from it and customize it for
+ each OAuth2 flow.
+
+ You normally would not create a new class inheriting from it but use one of the
+ existing subclasses, and maybe compose them if you want to support multiple flows.
+
+ Read more about it in the
+ [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/).
+ """
+
def __init__(
self,
*,
- flows: Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]] = OAuthFlowsModel(),
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ flows: Annotated[
+ Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]],
+ Doc(
+ """
+ The dictionary of OAuth2 flows.
+ """
+ ),
+ ] = OAuthFlowsModel(),
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Auhtorization header is provided, required for
+ OAuth2 authentication, it will automatically cancel the request and
+ send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OAuth2
+ or in a cookie).
+ """
+ ),
+ ] = True,
):
self.model = OAuth2Model(
flows=cast(OAuthFlowsModel, flows), description=description
@@ -144,13 +389,74 @@ class OAuth2(SecurityBase):
class OAuth2PasswordBearer(OAuth2):
+ """
+ OAuth2 flow for authentication using a bearer token obtained with a password.
+ An instance of it would be used as a dependency.
+
+ Read more about it in the
+ [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
+ """
+
def __init__(
self,
- tokenUrl: str,
- scheme_name: Optional[str] = None,
- scopes: Optional[Dict[str, str]] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ tokenUrl: Annotated[
+ str,
+ Doc(
+ """
+ The URL to obtain the OAuth2 token. This would be the *path operation*
+ that has `OAuth2PasswordRequestForm` as a dependency.
+ """
+ ),
+ ],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ scopes: Annotated[
+ Optional[Dict[str, str]],
+ Doc(
+ """
+ The OAuth2 scopes that would be required by the *path operations* that
+ use this dependency.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Auhtorization header is provided, required for
+ OAuth2 authentication, it will automatically cancel the request and
+ send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OAuth2
+ or in a cookie).
+ """
+ ),
+ ] = True,
):
if not scopes:
scopes = {}
@@ -180,15 +486,79 @@ class OAuth2PasswordBearer(OAuth2):
class OAuth2AuthorizationCodeBearer(OAuth2):
+ """
+ OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code
+ flow. An instance of it would be used as a dependency.
+ """
+
def __init__(
self,
authorizationUrl: str,
- tokenUrl: str,
- refreshUrl: Optional[str] = None,
- scheme_name: Optional[str] = None,
- scopes: Optional[Dict[str, str]] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ tokenUrl: Annotated[
+ str,
+ Doc(
+ """
+ The URL to obtain the OAuth2 token.
+ """
+ ),
+ ],
+ refreshUrl: Annotated[
+ Optional[str],
+ Doc(
+ """
+ The URL to refresh the token and obtain a new one.
+ """
+ ),
+ ] = None,
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ scopes: Annotated[
+ Optional[Dict[str, str]],
+ Doc(
+ """
+ The OAuth2 scopes that would be required by the *path operations* that
+ use this dependency.
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Auhtorization header is provided, required for
+ OAuth2 authentication, it will automatically cancel the request and
+ send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OAuth2
+ or in a cookie).
+ """
+ ),
+ ] = True,
):
if not scopes:
scopes = {}
@@ -226,6 +596,43 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
class SecurityScopes:
- def __init__(self, scopes: Optional[List[str]] = None):
- self.scopes = scopes or []
- self.scope_str = " ".join(self.scopes)
+ """
+ This is a special class that you can define in a parameter in a dependency to
+ obtain the OAuth2 scopes required by all the dependencies in the same chain.
+
+ This way, multiple dependencies can have different scopes, even when used in the
+ same *path operation*. And with this, you can access all the scopes required in
+ all those dependencies in a single place.
+
+ Read more about it in the
+ [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).
+ """
+
+ def __init__(
+ self,
+ scopes: Annotated[
+ Optional[List[str]],
+ Doc(
+ """
+ This will be filled by FastAPI.
+ """
+ ),
+ ] = None,
+ ):
+ self.scopes: Annotated[
+ List[str],
+ Doc(
+ """
+ The list of all the scopes required by dependencies.
+ """
+ ),
+ ] = scopes or []
+ self.scope_str: Annotated[
+ str,
+ Doc(
+ """
+ All the scopes required by all the dependencies in a single string
+ separated by spaces, as defined in the OAuth2 specification.
+ """
+ ),
+ ] = " ".join(self.scopes)
diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py
index 4e65f1f6c..c612b475d 100644
--- a/fastapi/security/open_id_connect_url.py
+++ b/fastapi/security/open_id_connect_url.py
@@ -5,16 +5,66 @@ from fastapi.security.base import SecurityBase
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
+from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
class OpenIdConnect(SecurityBase):
+ """
+ OpenID Connect authentication class. An instance of it would be used as a
+ dependency.
+ """
+
def __init__(
self,
*,
- openIdConnectUrl: str,
- scheme_name: Optional[str] = None,
- description: Optional[str] = None,
- auto_error: bool = True,
+ openIdConnectUrl: Annotated[
+ str,
+ Doc(
+ """
+ The OpenID Connect URL.
+ """
+ ),
+ ],
+ scheme_name: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme name.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ description: Annotated[
+ Optional[str],
+ Doc(
+ """
+ Security scheme description.
+
+ It will be included in the generated OpenAPI (e.g. visible at `/docs`).
+ """
+ ),
+ ] = None,
+ auto_error: Annotated[
+ bool,
+ Doc(
+ """
+ By default, if no HTTP Auhtorization header is provided, required for
+ OpenID Connect authentication, it will automatically cancel the request
+ and send the client an error.
+
+ If `auto_error` is set to `False`, when the HTTP Authorization header
+ is not available, instead of erroring out, the dependency result will
+ be `None`.
+
+ This is useful when you want to have optional authentication.
+
+ It is also useful when you want to have authentication that can be
+ provided in one of multiple optional ways (for example, with OpenID
+ Connect or in a cookie).
+ """
+ ),
+ ] = True,
):
self.model = OpenIdConnectModel(
openIdConnectUrl=openIdConnectUrl, description=description
diff --git a/fastapi/types.py b/fastapi/types.py
index 7adf565a7..3205654c7 100644
--- a/fastapi/types.py
+++ b/fastapi/types.py
@@ -6,6 +6,5 @@ from pydantic import BaseModel
DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
UnionType = getattr(types, "UnionType", Union)
-NoneType = getattr(types, "UnionType", None)
ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
diff --git a/fastapi/utils.py b/fastapi/utils.py
index 267d64ce8..f8463dda2 100644
--- a/fastapi/utils.py
+++ b/fastapi/utils.py
@@ -117,7 +117,7 @@ def create_cloned_field(
if PYDANTIC_V2:
return field
# cloned_types caches already cloned types to support recursive models and improve
- # performance by avoiding unecessary cloning
+ # performance by avoiding unnecessary cloning
if cloned_types is None:
cloned_types = _CLONED_TYPES_CACHE
@@ -152,7 +152,8 @@ def create_cloned_field(
]
if field.key_field: # type: ignore[attr-defined]
new_field.key_field = create_cloned_field( # type: ignore[attr-defined]
- field.key_field, cloned_types=cloned_types # type: ignore[attr-defined]
+ field.key_field, # type: ignore[attr-defined]
+ cloned_types=cloned_types,
)
new_field.validators = field.validators # type: ignore[attr-defined]
new_field.pre_validators = field.pre_validators # type: ignore[attr-defined]
diff --git a/pyproject.toml b/pyproject.toml
index f0917578f..38728d99e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
name = "fastapi"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
readme = "README.md"
-requires-python = ">=3.7"
+requires-python = ">=3.8"
license = "MIT"
authors = [
{ name = "Sebastián Ramírez", email = "tiangolo@gmail.com" },
@@ -32,7 +32,6 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3 :: Only",
- "Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
@@ -41,9 +40,9 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [
- "starlette>=0.27.0,<0.28.0",
- "pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,<3.0.0",
- "typing-extensions>=4.5.0",
+ "starlette>=0.29.0,<0.33.0",
+ "pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0",
+ "typing-extensions>=4.8.0",
]
dynamic = ["version"]
@@ -83,6 +82,12 @@ module = "fastapi.tests.*"
ignore_missing_imports = true
check_untyped_defs = true
+[[tool.mypy.overrides]]
+module = "docs_src.*"
+disallow_incomplete_defs = false
+disallow_untyped_defs = false
+disallow_untyped_calls = false
+
[tool.pytest.ini_options]
addopts = [
"--strict-config",
@@ -129,11 +134,13 @@ select = [
"I", # isort
"C", # flake8-comprehensions
"B", # flake8-bugbear
+ "UP", # pyupgrade
]
ignore = [
"E501", # line too long, handled by black
"B008", # do not perform function calls in argument defaults
"C901", # too complex
+ "W191", # indentation contains tabs
]
[tool.ruff.per-file-ignores]
@@ -153,6 +160,25 @@ ignore = [
"docs_src/query_params_str_validations/tutorial012_an_py39.py" = ["B006"]
"docs_src/query_params_str_validations/tutorial013_an.py" = ["B006"]
"docs_src/query_params_str_validations/tutorial013_an_py39.py" = ["B006"]
+"docs_src/security/tutorial004.py" = ["B904"]
+"docs_src/security/tutorial004_an.py" = ["B904"]
+"docs_src/security/tutorial004_an_py310.py" = ["B904"]
+"docs_src/security/tutorial004_an_py39.py" = ["B904"]
+"docs_src/security/tutorial004_py310.py" = ["B904"]
+"docs_src/security/tutorial005.py" = ["B904"]
+"docs_src/security/tutorial005_an.py" = ["B904"]
+"docs_src/security/tutorial005_an_py310.py" = ["B904"]
+"docs_src/security/tutorial005_an_py39.py" = ["B904"]
+"docs_src/security/tutorial005_py310.py" = ["B904"]
+"docs_src/security/tutorial005_py39.py" = ["B904"]
+"docs_src/dependencies/tutorial008b.py" = ["B904"]
+"docs_src/dependencies/tutorial008b_an.py" = ["B904"]
+"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"]
+
[tool.ruff.isort]
known-third-party = ["fastapi", "pydantic", "starlette"]
+
+[tool.ruff.pyupgrade]
+# Preserve types, even if a file imports `from __future__ import annotations`.
+keep-runtime-typing = true
diff --git a/requirements-docs-tests.txt b/requirements-docs-tests.txt
new file mode 100644
index 000000000..b82df4933
--- /dev/null
+++ b/requirements-docs-tests.txt
@@ -0,0 +1,2 @@
+# For mkdocstrings and tests
+httpx >=0.23.0,<0.25.0
diff --git a/requirements-docs.txt b/requirements-docs.txt
index df60ca4df..28408a9f1 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -1,14 +1,19 @@
-e .
-mkdocs==1.4.3
-mkdocs-material==9.1.17
+-r requirements-docs-tests.txt
+mkdocs-material==9.4.7
mdx-include >=1.4.1,<2.0.0
mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0
+mkdocs-redirects>=1.2.1,<1.3.0
typer-cli >=0.0.13,<0.0.14
typer[all] >=0.6.1,<0.8.0
pyyaml >=5.3.1,<7.0.0
# For Material for MkDocs, Chinese search
jieba==0.42.1
# For image processing by Material for MkDocs
-pillow==9.5.0
+pillow==10.1.0
# For image processing by Material for MkDocs
cairosvg==2.7.0
+mkdocstrings[python]==0.23.0
+griffe-typingdoc==0.2.2
+# For griffe, it formats with black
+black==23.3.0
diff --git a/requirements-tests.txt b/requirements-tests.txt
index abefac685..e1a976c13 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -1,17 +1,15 @@
-e .
+-r requirements-docs-tests.txt
pydantic-settings >=2.0.0
pytest >=7.1.3,<8.0.0
coverage[toml] >= 6.5.0,< 8.0
-mypy ==1.4.0
-ruff ==0.0.275
-black == 23.3.0
-httpx >=0.23.0,<0.25.0
+mypy ==1.4.1
+ruff ==0.1.2
email_validator >=1.1.1,<3.0.0
dirty-equals ==0.6.0
# TODO: once removing databases from tutorial, upgrade SQLAlchemy
# probably when including SQLModel
sqlalchemy >=1.3.18,<1.4.43
-peewee >=3.13.3,<4.0.0
databases[sqlite] >=0.3.2,<0.7.0
orjson >=3.2.1,<4.0.0
ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0
diff --git a/requirements.txt b/requirements.txt
index 7e746016a..ef25ec483 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,5 @@
-r requirements-docs.txt
uvicorn[standard] >=0.12.0,<0.23.0
pre-commit >=2.17.0,<4.0.0
+# For generating screenshots
+playwright
diff --git a/scripts/docs.py b/scripts/docs.py
index 968dd9a3d..73e1900ad 100644
--- a/scripts/docs.py
+++ b/scripts/docs.py
@@ -36,7 +36,7 @@ site_path = Path("site").absolute()
build_site_path = Path("site_build").absolute()
-@lru_cache()
+@lru_cache
def is_mkdocs_insiders() -> bool:
version = metadata.version("mkdocs-material")
return "insiders" in version
@@ -104,7 +104,7 @@ def new_lang(lang: str = typer.Argument(..., callback=lang_callback)):
def build_lang(
lang: str = typer.Argument(
..., callback=lang_callback, autocompletion=complete_existing_lang
- )
+ ),
) -> None:
"""
Build the docs for a language.
@@ -153,17 +153,21 @@ index_sponsors_template = """
def generate_readme_content() -> str:
en_index = en_docs_path / "docs" / "index.md"
content = en_index.read_text("utf-8")
+ match_pre = re.search(r"\n\n", content)
match_start = re.search(r"", content)
match_end = re.search(r"", content)
sponsors_data_path = en_docs_path / "data" / "sponsors.yml"
sponsors = mkdocs.utils.yaml_load(sponsors_data_path.read_text(encoding="utf-8"))
if not (match_start and match_end):
raise RuntimeError("Couldn't auto-generate sponsors section")
+ if not match_pre:
+ raise RuntimeError("Couldn't find pre section (