-
+
@@ -46,23 +46,22 @@ The key features are:
-
+
-
-
-
-
-
+
-
+
+
-
+
+
+
@@ -149,7 +148,7 @@ $ pip install "fastapi[standard]"
### Create it
-* Create a file `main.py` with:
+Create a file `main.py` with:
```Python
from typing import Union
@@ -459,7 +458,7 @@ FastAPI depends on Pydantic and Starlette.
### `standard` Dependencies
-When you install FastAPI with `pip install "fastapi[standard]"` it comes the `standard` group of optional dependencies:
+When you install FastAPI with `pip install "fastapi[standard]"` it comes with the `standard` group of optional dependencies:
Used by Pydantic:
diff --git a/docs/az/docs/index.md b/docs/az/docs/index.md
index ad78d7d06..fbbbce130 100644
--- a/docs/az/docs/index.md
+++ b/docs/az/docs/index.md
@@ -6,7 +6,7 @@
+
+```console
+// এখনো আমরা এনভায়রনমেন্ট ভেরিয়েবল সেট করিনি
+$ python main.py
+
+// যেহেতু env var সেট করা হয়নি, তাই আমরা ডিফল্ট ভ্যালু পাচ্ছি
+
+Hello World from Python
+
+// কিন্তু আমরা প্রথমে যদি একটা এনভায়রনমেন্ট ভারিয়েবল তৈরি করে নেই
+$ export MY_NAME="Wade Wilson"
+
+// এবং তারপর আবার প্রোগ্রাটিকে কল করি
+$ python main.py
+
+// এখন এটি এনভায়রনমেন্ট ভেরিয়েবল রিড করতে পারবে
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+//// tab | উইন্ডোজ পাওয়ারশেল
+
+
+
+```console
+// এখনো আমরা এনভায়রনমেন্ট ভেরিয়েবল সেট করিনি
+$ python main.py
+
+// যেহেতু env var সেট করা হয়নি, তাই আমরা ডিফল্ট ভ্যালু পাচ্ছি
+
+Hello World from Python
+
+// কিন্তু আমরা প্রথমে যদি একটা এনভায়রনমেন্ট ভারিয়েবল তৈরি করে নেই
+$ $Env:MY_NAME = "Wade Wilson"
+
+// এবং তারপর আবার প্রোগ্রাটিকে কল করি
+$ python main.py
+
+// এখন এটি এনভায়রনমেন্ট ভেরিয়েবল রিড করতে পারবে
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+যেহেতু এনভায়রনমেন্ট ভেরিয়েবলস কোডের বাইরে সেট করা যায়, কিন্তু পরবর্তীতে কোড দ্বারা রিড করা যায়, এবং বাকি ফাইলগুলোর সাথে রাখতে (`git` এ কমিট) হয় না, তাই কনফিগারেশনস বা **সেটিংস** এর জন্য এগুলো সাধারণত ব্যবহৃত হয়ে থাকে।
+
+আপনি একটি এনভায়রনমেন্ট ভেরিয়েবল শুধুমাত্র একটি **নির্দিষ্ট প্রোগ্রাম ইনভোকেশনের** জন্যও তৈরি করতে পারেন, যা শুধুমাত্র সেই প্রোগ্রামের জন্যই এভেইলেবল থাকবে এবং শুধুমাত্র তার চলাকালীন সময় পর্যন্তই সক্রিয় থাকবে।
+
+এটি করতে, প্রোগ্রামটি রান করার ঠিক আগেই, একই লাইনে এনভায়রনমেন্ট ভেরিয়েবল তৈরি করুন:
+
+
+
+```console
+// প্রোগ্রামটি কল করার সময় একই লাইনে MY_NAME এনভায়রনমেন্ট ভেরিয়েবল তৈরি করুন
+$ MY_NAME="Wade Wilson" python main.py
+
+// এখন এটি এনভায়রনমেন্ট ভ্যরিয়েবলটিকে রিড করতে পারবে
+
+Hello Wade Wilson from Python
+
+// পরবর্তীতে এনভায়রনমেন্ট ভেরিয়েবলটিকে আর ব্যবহার করা যাচ্ছে না
+$ python main.py
+
+Hello World from Python
+```
+
+
+
+/// tip
+
+এটি নিয়ে আরো বিস্তারিত পড়তে পারেন এখানে The Twelve-Factor App: Config।
+
+///
+
+## টাইপস এবং ভ্যালিডেশন
+
+এই এনভায়রনমেন্ট ভেরিয়েবলগুলো শুধুমাত্র **টেক্সট স্ট্রিংস** হ্যান্ডেল করতে পারে, যেহেতু এগুলো পাইথনের বাইরে অবস্থিত এবং অন্যান্য প্রোগ্রাম এবং সিস্টেমের বাকি অংশের (এমনকি বিভিন্ন অপারেটিং সিস্টেম যেমন লিনাক্স, উইন্ডোজ, ম্যাকওএস) সাথে সামঞ্জস্যপূর্ণ হতে হয়।
+
+এর অর্থ হচ্ছে পাইথনে এনভায়রনমেন্ট ভেরিয়েবল থেকে রিড করা **যেকোনো ভ্যালু** একটি `str` হবে, এবং অন্য কোনো টাইপে কনভার্সন বা যেকোনো ভেলিডেশন কোডে আলাদাভাবে করতে হবে।
+
+এনভায়রনমেন্ট ভেরিয়েবল ব্যবহার করে **এপ্লিকেশন সেটিংস** হ্যান্ডেল করা নিয়ে আরো বিস্তারিত জানা যাবে [Advanced User Guide - Settings and Environment Variables](./advanced/settings.md){.internal-link target=_blank}.
+
+## `PATH` এনভায়রনমেন্ট ভেরিয়েবল
+
+**`PATH`** নামে একটি **বিশেষ** এনভায়রনমেন্ট ভেরিয়েবল রয়েছে, যেটি প্রোগ্রাম রান করার জন্য অপারেটিং সিস্টেমস (লিনাক্স, ম্যাকওএস, উইন্ডোজ) দ্বারা ব্যবহৃত হয়।
+
+`PATH` ভেরিয়েবল এর ভ্যালু হচ্ছে একটি বিশাল স্ট্রিং যা ডিরেক্টরিকে কোলন `:` দিয়ে আলাদা করার মাধ্যমে লিনাক্সে ও ম্যাকওএস এ, এবং সেমিকোলন `;` এর মাধ্যমে উইন্ডোজ এ তৈরি করা থাকে।
+
+উদাহরণস্বরূপ, `PATH` ভেরিয়েবল নিচের মতো দেখতে হতে পারেঃ
+
+//// tab | লিনাক্স, ম্যাকওএস
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+তারমানে হলো সিস্টেম প্রোগ্রামগুলোকে নিচের ডিরেক্টরিগুলোতে খুঁজবেঃ
+
+* `/usr/local/bin`
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | উইন্ডোজ
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
+```
+
+তারমানে হলো সিস্টেম প্রোগ্রামগুলোকে নিচের ডিরেক্টরিগুলোতে খুঁজবেঃ
+
+* `C:\Program Files\Python312\Scripts`
+* `C:\Program Files\Python312`
+* `C:\Windows\System32`
+
+////
+
+যখন আপনি টার্মিনালে কোনো **কমান্ড** লিখবেন, অপারেটিং সিস্টেম **প্রত্যেকটি ডিরেক্টরিতে** প্রোগ্রামটি **খুঁজবে** যেগুলো `PATH` এনভায়রনমেন্ট ভেরিয়েবল এ লিস্ট করা আছে।
+
+উদাহরণস্বরূপ, যখন আপনি টার্মিনালে `python` টাইপ করবেন, অপারেটিং সিস্টেম এই লিস্ট এর **প্রথম ডিরেক্টরিতে** `python` নামের একটি প্রোগ্রাম খুঁজবে।
+
+যদি এটি খুঁজে পায়, তাহলে এটি প্রোগ্রামটিকে ব্যবহার করবে। অন্যথায় এটি **অন্যান্য ডিরেক্টরিগুলোতে** এটিকে খুঁজতে থাকবে।
+
+### পাইথন ইনস্টল এবং `PATH` আপডেট
+
+যখন আপনি পাইথন ইনস্টল করেন, আপনি `PATH` এনভায়রনমেন্ট ভেরিয়েবল আপডেট করতে চান কিনা সেটা জিজ্ঞেস করা হতে পারে।
+
+//// tab | লিনাক্স, ম্যাকওএস
+
+ধরা যাক আপনি পাইথন ইনস্টল করলেন এবং এটি `/opt/custompython/bin` ডিরেক্টরিতে ইনস্টল হচ্ছে।
+
+যদি আপনি "Yes" সিলেক্ট করে `PATH` এনভায়রনমেন্ট ভেরিয়েবল আপডেট করতে চান, তাহলে ইনস্টলার `/opt/custompython/bin` কে `PATH` এনভায়রনমেন্ট ভেরিয়েবল এ এড করে দিবে।
+
+এটা দেখতে এমনটা হতে পারেঃ
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
+```
+
+এইভাবে, আপনি যখন টার্মিনালে `python` টাইপ করেন, সিস্টেম পাইথন প্রোগ্রামটিকে `/opt/custompython/bin` (সর্বশেষ ডিরেক্টরি) তে খুঁজে পাবে এবং এটাকে ব্যবহার করবে।
+
+////
+
+//// tab | উইন্ডোজ
+
+ধরা যাক আপনি পাইথন ইনস্টল করলেন এবং এটি `C:\opt\custompython\bin` ডিরেক্টরিতে ইনস্টল হচ্ছে।
+
+যদি আপনি "Yes" সিলেক্ট করে `PATH` এনভায়রনমেন্ট ভেরিয়েবল আপডেট করতে চান, তাহলে ইনস্টলার `C:\opt\custompython\bin` কে `PATH` এনভায়রনমেন্ট ভেরিয়েবল এ এড করে দিবে।
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
+```
+
+এইভাবে, আপনি যখন টার্মিনালে `python` টাইপ করেন, সিস্টেম পাইথন প্রোগ্রামটিকে `C:\opt\custompython\bin` (সর্বশেষ ডিরেক্টরি) তে খুঁজে পাবে এবং এটাকে ব্যবহার করবে।
+
+////
+
+তাই, আপনি যদি টাইপ করেনঃ
+
+
+
+```console
+$ python
+```
+
+
+
+//// tab | লিনাক্স, ম্যাকওএস
+
+সিস্টেম `python` প্রোগ্রামকে `/opt/custompython/bin` এ **খুঁজে পাবে** এবং এটাকে রান করবে।
+
+এটা মোটামুটিভাবে নিচের মতো করে লেখার সমান হবেঃ
+
+
+
+////
+
+এই তথ্যগুলো [ভার্চুয়াল এনভায়রনমেন্টস](virtual-environments.md){.internal-link target=_blank} শেখার ক্ষেত্রে সহায়ক হবে।
+
+## উপসংহার
+
+এর মাধ্যমে আপনি **এনভায়রনমেন্ট ভেরিয়েবলস** কি এবং এটিকে পাইথনে কিভাবে ব্যবহার করতে হয় তার সম্পর্কে বেসিক ধারনা পেলেন।
+
+চাইলে এই সম্পর্কে আরো বিস্তারিত পড়তে পারেন Wikipedia for Environment Variable এ।
+
+অনেক ক্ষেত্রে, দেখা মাত্রই এনভায়রনমেন্ট ভেরিয়েবল কীভাবে প্রয়োজন হবে তা স্পষ্ট হয় না। কিন্তু ডেভেলপমেন্টের সময় আপনি নানা রকম পরিস্থিতিতে এগুলোর সম্মুখীন হবেন, তাই এগুলো সম্পর্কে জেনে রাখা ভালো।
+
+উদাহরণস্বরূপ, আপনার এই ইনফরমেশনটি পরবর্তী, [ভার্চুয়াল এনভায়রনমেন্টস](virtual-environments.md) অংশে দরকার হবে।
diff --git a/docs/bn/docs/index.md b/docs/bn/docs/index.md
index 678ac9ca9..74ee230a1 100644
--- a/docs/bn/docs/index.md
+++ b/docs/bn/docs/index.md
@@ -5,15 +5,18 @@
FastAPI উচ্চক্ষমতা সম্পন্ন, সহজে শেখার এবং দ্রুত কোড করে প্রোডাকশনের জন্য ফ্রামওয়ার্ক।
-
-Das erstellt ein Verzeichnis `./env/` mit den Python-Binärdateien und Sie können dann Packages in dieser lokalen Umgebung installieren.
-
-### Umgebung aktivieren
-
-Aktivieren Sie die neue Umgebung mit:
-
-//// tab | Linux, macOS
-
-
-
-////
-
-Wenn die `pip` Binärdatei unter `env/bin/pip` angezeigt wird, hat es funktioniert. 🎉
-
-Stellen Sie sicher, dass Sie über die neueste Version von pip in Ihrer lokalen Umgebung verfügen, um Fehler bei den nächsten Schritten zu vermeiden:
-
-
-
-/// tip | Tipp
-
-Aktivieren Sie jedes Mal, wenn Sie ein neues Package mit `pip` in dieser Umgebung installieren, die Umgebung erneut.
-
-Dadurch wird sichergestellt, dass Sie, wenn Sie ein von diesem Package installiertes Terminalprogramm verwenden, das Programm aus Ihrer lokalen Umgebung verwenden und kein anderes, das global installiert sein könnte.
-
-///
-
-### Benötigtes mit pip installieren
-
-Nachdem Sie die Umgebung wie oben beschrieben aktiviert haben:
-
-
-
-Das installiert alle Abhängigkeiten und Ihr lokales FastAPI in Ihrer lokalen Umgebung.
-
-#### Das lokale FastAPI verwenden
-
-Wenn Sie eine Python-Datei erstellen, die FastAPI importiert und verwendet, und diese mit dem Python aus Ihrer lokalen Umgebung ausführen, wird Ihr geklonter lokaler FastAPI-Quellcode verwendet.
-
-Und wenn Sie diesen lokalen FastAPI-Quellcode aktualisieren und dann die Python-Datei erneut ausführen, wird die neue Version von FastAPI verwendet, die Sie gerade bearbeitet haben.
-
-Auf diese Weise müssen Sie Ihre lokale Version nicht „installieren“, um jede Änderung testen zu können.
-
-/// note | Technische Details
-
-Das geschieht nur, wenn Sie die Installation mit der enthaltenen `requirements.txt` durchführen, anstatt `pip install fastapi` direkt auszuführen.
-
-Das liegt daran, dass in der Datei `requirements.txt` die lokale Version von FastAPI mit der Option `-e` für die Installation im „editierbaren“ Modus markiert ist.
-
-///
-
-### Den Code formatieren
-
-Es gibt ein Skript, das, wenn Sie es ausführen, Ihren gesamten Code formatiert und bereinigt:
-
-
-
-```console
-$ bash scripts/format.sh
-```
-
-
-
-Es sortiert auch alle Ihre Importe automatisch.
-
-Damit es sie richtig sortiert, muss FastAPI lokal in Ihrer Umgebung installiert sein, mit dem Befehl vom obigen Abschnitt, welcher `-e` verwendet.
-
-## Dokumentation
-
-Stellen Sie zunächst sicher, dass Sie Ihre Umgebung wie oben beschrieben einrichten, was alles Benötigte installiert.
-
-### Dokumentation live
-
-Während der lokalen Entwicklung gibt es ein Skript, das die Site erstellt, auf Änderungen prüft und direkt neu lädt (Live Reload):
-
-
-
-Das stellt die Dokumentation unter `http://127.0.0.1:8008` bereit.
-
-Auf diese Weise können Sie die Dokumentation/Quelldateien bearbeiten und die Änderungen live sehen.
-
-/// tip | Tipp
-
-Alternativ können Sie die Schritte des Skripts auch manuell ausführen.
-
-Gehen Sie in das Verzeichnis für die entsprechende Sprache. Das für die englischsprachige Hauptdokumentation befindet sich unter `docs/en/`:
-
-```console
-$ cd docs/en/
-```
-
-Führen Sie dann `mkdocs` in diesem Verzeichnis aus:
-
-```console
-$ mkdocs serve --dev-addr 8008
-```
-
-///
-
-#### Typer-CLI (optional)
-
-Die Anleitung hier zeigt Ihnen, wie Sie das Skript unter `./scripts/docs.py` direkt mit dem `python` Programm verwenden.
-
-Sie können aber auch Typer CLI verwenden und erhalten dann Autovervollständigung für Kommandos in Ihrem Terminal, nach dem Sie dessen Vervollständigung installiert haben.
-
-Wenn Sie Typer CLI installieren, können Sie die Vervollständigung installieren mit:
-
-
-
-```console
-$ typer --install-completion
-
-zsh completion installed in /home/user/.bashrc.
-Completion will take effect once you restart the terminal.
-```
-
-
-
-### Dokumentationsstruktur
-
-Die Dokumentation verwendet MkDocs.
-
-Und es gibt zusätzliche Tools/Skripte für Übersetzungen, in `./scripts/docs.py`.
-
-/// tip | Tipp
-
-Sie müssen sich den Code in `./scripts/docs.py` nicht anschauen, verwenden Sie ihn einfach in der Kommandozeile.
-
-///
-
-Die gesamte Dokumentation befindet sich im Markdown-Format im Verzeichnis `./docs/en/`.
-
-Viele der Tutorials enthalten Codeblöcke.
-
-In den meisten Fällen handelt es sich bei diesen Codeblöcken um vollständige Anwendungen, die unverändert ausgeführt werden können.
-
-Tatsächlich sind diese Codeblöcke nicht Teil des Markdowns, sondern Python-Dateien im Verzeichnis `./docs_src/`.
-
-Und diese Python-Dateien werden beim Generieren der Site in die Dokumentation eingefügt.
-
-### Dokumentation für Tests
-
-Tatsächlich arbeiten die meisten Tests mit den Beispielquelldateien in der Dokumentation.
-
-Dadurch wird sichergestellt, dass:
-
-* Die Dokumentation aktuell ist.
-* Die Dokumentationsbeispiele ohne Änderung ausgeführt werden können.
-* Die meisten Funktionalitäten durch die Dokumentation abgedeckt werden, sichergestellt durch die Testabdeckung.
-
-#### Gleichzeitig Apps und Dokumentation
-
-Wenn Sie die Beispiele ausführen, mit z. B.:
-
-
-
-```console
-$ uvicorn tutorial001:app --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-wird das, da Uvicorn standardmäßig den Port `8000` verwendet, mit der Dokumentation auf dem Port `8008` nicht in Konflikt geraten.
-
-### Übersetzungen
-
-Hilfe bei Übersetzungen wird SEHR geschätzt! Und es kann nicht getan werden, ohne die Hilfe der Gemeinschaft. 🌎 🚀
-
-Hier sind die Schritte, die Ihnen bei Übersetzungen helfen.
-
-#### Tipps und Richtlinien
-
-* Schauen Sie nach aktuellen Pull Requests für Ihre Sprache. Sie können die Pull Requests nach dem Label für Ihre Sprache filtern. Für Spanisch lautet das Label beispielsweise `lang-es`.
-
-* Sehen Sie diese Pull Requests durch (Review), schlagen Sie Änderungen vor, oder segnen Sie sie ab (Approval). Bei den Sprachen, die ich nicht spreche, warte ich, bis mehrere andere die Übersetzung durchgesehen haben, bevor ich den Pull Request merge.
-
-/// tip | Tipp
-
-Sie können Kommentare mit Änderungsvorschlägen zu vorhandenen Pull Requests hinzufügen.
-
-Schauen Sie sich die Dokumentation an, wie man ein Review zu einem Pull Request hinzufügt, welches den PR absegnet oder Änderungen vorschlägt.
-
-///
-
-* Überprüfen Sie, ob es eine GitHub-Diskussion gibt, die Übersetzungen für Ihre Sprache koordiniert. Sie können sie abonnieren, und wenn ein neuer Pull Request zum Review vorliegt, wird der Diskussion automatisch ein Kommentar hinzugefügt.
-
-* Wenn Sie Seiten übersetzen, fügen Sie einen einzelnen Pull Request pro übersetzter Seite hinzu. Dadurch wird es für andere viel einfacher, ihn zu durchzusehen.
-
-* Um den Zwei-Buchstaben-Code für die Sprache zu finden, die Sie übersetzen möchten, schauen Sie sich die Tabelle List of ISO 639-1 codes an.
-
-#### Vorhandene Sprache
-
-Angenommen, Sie möchten eine Seite für eine Sprache übersetzen, die bereits Übersetzungen für einige Seiten hat, beispielsweise für Spanisch.
-
-Im Spanischen lautet der Zwei-Buchstaben-Code `es`. Das Verzeichnis für spanische Übersetzungen befindet sich also unter `docs/es/`.
-
-/// tip | Tipp
-
-Die Haupt („offizielle“) Sprache ist Englisch und befindet sich unter `docs/en/`.
-
-///
-
-Führen Sie nun den Live-Server für die Dokumentation auf Spanisch aus:
-
-
-
-```console
-// Verwenden Sie das Kommando „live“ und fügen Sie den Sprach-Code als Argument hinten an
-$ python ./scripts/docs.py live es
-
-[INFO] Serving on http://127.0.0.1:8008
-[INFO] Start watching changes
-[INFO] Start detecting changes
-```
-
-
-
-/// tip | Tipp
-
-Alternativ können Sie die Schritte des Skripts auch manuell ausführen.
-
-Gehen Sie in das Sprachverzeichnis, für die spanischen Übersetzungen ist das `docs/es/`:
-
-```console
-$ cd docs/es/
-```
-
-Dann führen Sie in dem Verzeichnis `mkdocs` aus:
-
-```console
-$ mkdocs serve --dev-addr 8008
-```
-
-///
-
-Jetzt können Sie auf http://127.0.0.1:8008 gehen und Ihre Änderungen live sehen.
-
-Sie werden sehen, dass jede Sprache alle Seiten hat. Einige Seiten sind jedoch nicht übersetzt und haben oben eine Info-Box, dass die Übersetzung noch fehlt.
-
-Nehmen wir nun an, Sie möchten eine Übersetzung für den Abschnitt [Features](features.md){.internal-link target=_blank} hinzufügen.
-
-* Kopieren Sie die Datei:
-
-```
-docs/en/docs/features.md
-```
-
-* Fügen Sie sie an genau derselben Stelle ein, jedoch für die Sprache, die Sie übersetzen möchten, z. B.:
-
-```
-docs/es/docs/features.md
-```
-
-/// tip | Tipp
-
-Beachten Sie, dass die einzige Änderung in Pfad und Dateiname der Sprachcode ist, von `en` zu `es`.
-
-///
-
-Wenn Sie in Ihrem Browser nachsehen, werden Sie feststellen, dass die Dokumentation jetzt Ihren neuen Abschnitt anzeigt (die Info-Box oben ist verschwunden). 🎉
-
-Jetzt können Sie alles übersetzen und beim Speichern sehen, wie es aussieht.
-
-#### Neue Sprache
-
-Nehmen wir an, Sie möchten Übersetzungen für eine Sprache hinzufügen, die noch nicht übersetzt ist, nicht einmal einige Seiten.
-
-Angenommen, Sie möchten Übersetzungen für Kreolisch hinzufügen, diese sind jedoch noch nicht in den Dokumenten enthalten.
-
-Wenn Sie den Link von oben überprüfen, lautet der Sprachcode für Kreolisch `ht`.
-
-Der nächste Schritt besteht darin, das Skript auszuführen, um ein neues Übersetzungsverzeichnis zu erstellen:
-
-
-
-```console
-// Verwenden Sie das Kommando new-lang und fügen Sie den Sprach-Code als Argument hinten an
-$ python ./scripts/docs.py new-lang ht
-
-Successfully initialized: docs/ht
-```
-
-
-
-Jetzt können Sie in Ihrem Code-Editor das neu erstellte Verzeichnis `docs/ht/` sehen.
-
-Obiges Kommando hat eine Datei `docs/ht/mkdocs.yml` mit einer Minimal-Konfiguration erstellt, die alles von der `en`-Version erbt:
-
-```yaml
-INHERIT: ../en/mkdocs.yml
-```
-
-/// tip | Tipp
-
-Sie können diese Datei mit diesem Inhalt auch einfach manuell erstellen.
-
-///
-
-Das Kommando hat auch eine Dummy-Datei `docs/ht/index.md` für die Hauptseite erstellt. Sie können mit der Übersetzung dieser Datei beginnen.
-
-Sie können nun mit den obigen Instruktionen für eine „vorhandene Sprache“ fortfahren.
-
-Fügen Sie dem ersten Pull Request beide Dateien `docs/ht/mkdocs.yml` und `docs/ht/index.md` bei. 🎉
-
-#### Vorschau des Ergebnisses
-
-Wie bereits oben erwähnt, können Sie `./scripts/docs.py` mit dem Befehl `live` verwenden, um eine Vorschau der Ergebnisse anzuzeigen (oder `mkdocs serve`).
-
-Sobald Sie fertig sind, können Sie auch alles so testen, wie es online aussehen würde, einschließlich aller anderen Sprachen.
-
-Bauen Sie dazu zunächst die gesamte Dokumentation:
-
-
-
-```console
-// Verwenden Sie das Kommando „build-all“, das wird ein wenig dauern
-$ python ./scripts/docs.py build-all
-
-Building docs for: en
-Building docs for: es
-Successfully built docs for: es
-```
-
-
-
-Dadurch werden alle diese unabhängigen MkDocs-Sites für jede Sprache erstellt, kombiniert und das endgültige Resultat unter `./site/` gespeichert.
-
-Dieses können Sie dann mit dem Befehl `serve` bereitstellen:
-
-
-
-```console
-// Verwenden Sie das Kommando „serve“ nachdem Sie „build-all“ ausgeführt haben.
-$ python ./scripts/docs.py serve
-
-Warning: this is a very simple server. For development, use mkdocs serve instead.
-This is here only to preview a site with translations already built.
-Make sure you run the build-all command first.
-Serving at: http://127.0.0.1:8008
-```
-
-
-
-#### Übersetzungsspezifische Tipps und Richtlinien
-
-* Übersetzen Sie nur die Markdown-Dokumente (`.md`). Übersetzen Sie nicht die Codebeispiele unter `./docs_src`.
-
-* In Codeblöcken innerhalb des Markdown-Dokuments, übersetzen Sie Kommentare (`# ein Kommentar`), aber lassen Sie den Rest unverändert.
-
-* Ändern Sie nichts, was in "``" (Inline-Code) eingeschlossen ist.
-
-* In Zeilen, die mit `===` oder `!!!` beginnen, übersetzen Sie nur den ` "... Text ..."`-Teil. Lassen Sie den Rest unverändert.
-
-* Sie können Info-Boxen wie `!!! warning` mit beispielsweise `!!! warning "Achtung"` übersetzen. Aber ändern Sie nicht das Wort direkt nach dem `!!!`, es bestimmt die Farbe der Info-Box.
-
-* Ändern Sie nicht die Pfade in Links zu Bildern, Codedateien, Markdown Dokumenten.
-
-* Wenn ein Markdown-Dokument übersetzt ist, ändern sich allerdings unter Umständen die `#hash-teile` in Links zu dessen Überschriften. Aktualisieren Sie diese Links, wenn möglich.
- * Suchen Sie im übersetzten Dokument nach solchen Links mit dem Regex `#[^# ]`.
- * Suchen Sie in allen bereits in ihre Sprache übersetzen Dokumenten nach `ihr-ubersetztes-dokument.md`. VS Code hat beispielsweise eine Option „Bearbeiten“ -> „In Dateien suchen“.
- * Übersetzen Sie bei der Übersetzung eines Dokuments nicht „im Voraus“ `#hash-teile`, die zu Überschriften in noch nicht übersetzten Dokumenten verlinken.
-
-## Tests
-
-Es gibt ein Skript, das Sie lokal ausführen können, um den gesamten Code zu testen und Code Coverage Reporte in HTML zu generieren:
-
-
-
-Dieses Kommando generiert ein Verzeichnis `./htmlcov/`. Wenn Sie die Datei `./htmlcov/index.html` in Ihrem Browser öffnen, können Sie interaktiv die Codebereiche erkunden, die von den Tests abgedeckt werden, und feststellen, ob Bereiche fehlen.
diff --git a/docs/de/docs/deployment/concepts.md b/docs/de/docs/deployment/concepts.md
index 97ad854e2..907598e54 100644
--- a/docs/de/docs/deployment/concepts.md
+++ b/docs/de/docs/deployment/concepts.md
@@ -216,7 +216,7 @@ Dieser Manager-Prozess wäre wahrscheinlich derjenige, welcher der IP am **Port*
Diese Workerprozesse würden Ihre Anwendung ausführen, sie würden die Hauptberechnungen durchführen, um einen **Request** entgegenzunehmen und eine **Response** zurückzugeben, und sie würden alles, was Sie in Variablen einfügen, in den RAM laden.
-
+
Und natürlich würden auf derselben Maschine neben Ihrer Anwendung wahrscheinlich auch **andere Prozesse** laufen.
diff --git a/docs/de/docs/deployment/https.md b/docs/de/docs/deployment/https.md
index 630582995..a216f44af 100644
--- a/docs/de/docs/deployment/https.md
+++ b/docs/de/docs/deployment/https.md
@@ -85,7 +85,7 @@ Zuerst würde der Browser mithilfe der **DNS-Server** herausfinden, welches die
Die DNS-Server geben dem Browser eine bestimmte **IP-Adresse** zurück. Das wäre die von Ihrem Server verwendete öffentliche IP-Adresse, die Sie in den DNS-Servern konfiguriert haben.
-
+
### TLS-Handshake-Start
@@ -93,7 +93,7 @@ Der Browser kommuniziert dann mit dieser IP-Adresse über **Port 443** (den HTTP
Der erste Teil der Kommunikation besteht lediglich darin, die Verbindung zwischen dem Client und dem Server herzustellen und die zu verwendenden kryptografischen Schlüssel usw. zu vereinbaren.
-
+
Diese Interaktion zwischen dem Client und dem Server zum Aufbau der TLS-Verbindung wird als **TLS-Handshake** bezeichnet.
@@ -111,7 +111,7 @@ Mithilfe der oben beschriebenen **SNI-Erweiterung** würde der TLS-Terminierungs
In diesem Fall würde er das Zertifikat für `someapp.example.com` verwenden.
-
+
Der Client **vertraut** bereits der Entität, die das TLS-Zertifikat generiert hat (in diesem Fall Let's Encrypt, aber wir werden später mehr darüber erfahren), sodass er **verifizieren** kann, dass das Zertifikat gültig ist.
@@ -133,19 +133,19 @@ Da Client und Server (sprich, der Browser und der TLS-Terminierungsproxy) nun ü
Der Client sendet also einen **HTTPS-Request**. Das ist einfach ein HTTP-Request über eine verschlüsselte TLS-Verbindung.
-
+
### Den Request entschlüsseln
Der TLS-Terminierungsproxy würde die vereinbarte Verschlüsselung zum **Entschlüsseln des Requests** verwenden und den **einfachen (entschlüsselten) HTTP-Request** an den Prozess weiterleiten, der die Anwendung ausführt (z. B. einen Prozess, bei dem Uvicorn die FastAPI-Anwendung ausführt).
-
+
### HTTP-Response
Die Anwendung würde den Request verarbeiten und eine **einfache (unverschlüsselte) HTTP-Response** an den TLS-Terminierungsproxy senden.
-
+
### HTTPS-Response
@@ -153,7 +153,7 @@ Der TLS-Terminierungsproxy würde dann die Response mithilfe der zuvor vereinbar
Als Nächstes überprüft der Browser, ob die Response gültig und mit dem richtigen kryptografischen Schlüssel usw. verschlüsselt ist. Anschließend **entschlüsselt er die Response** und verarbeitet sie.
-
+
Der Client (Browser) weiß, dass die Response vom richtigen Server kommt, da dieser die Kryptografie verwendet, die zuvor mit dem **HTTPS-Zertifikat** vereinbart wurde.
@@ -163,7 +163,7 @@ Auf demselben Server (oder denselben Servern) könnten sich **mehrere Anwendunge
Nur ein Prozess kann diese spezifische IP und den Port verarbeiten (in unserem Beispiel der TLS-Terminierungsproxy), aber die anderen Anwendungen/Prozesse können auch auf dem/den Server(n) ausgeführt werden, solange sie nicht versuchen, dieselbe **Kombination aus öffentlicher IP und Port** zu verwenden.
-
+
Auf diese Weise könnte der TLS-Terminierungsproxy HTTPS und Zertifikate für **mehrere Domains**, für mehrere Anwendungen, verarbeiten und die Requests dann jeweils an die richtige Anwendung weiterleiten.
@@ -173,7 +173,7 @@ Irgendwann in der Zukunft würde jedes Zertifikat **ablaufen** (etwa 3 Monate na
Und dann gäbe es ein anderes Programm (in manchen Fällen ist es ein anderes Programm, in manchen Fällen ist es derselbe TLS-Terminierungsproxy), das mit Let's Encrypt kommuniziert und das/die Zertifikat(e) erneuert.
-
+
Die **TLS-Zertifikate** sind **einem Domainnamen zugeordnet**, nicht einer IP-Adresse.
diff --git a/docs/de/docs/how-to/conditional-openapi.md b/docs/de/docs/how-to/conditional-openapi.md
index a0a4983bb..50ae11f90 100644
--- a/docs/de/docs/how-to/conditional-openapi.md
+++ b/docs/de/docs/how-to/conditional-openapi.md
@@ -29,9 +29,7 @@ Sie können problemlos dieselben Pydantic-Einstellungen verwenden, um Ihre gener
Zum Beispiel:
-```Python hl_lines="6 11"
-{!../../docs_src/conditional_openapi/tutorial001.py!}
-```
+{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *}
Hier deklarieren wir die Einstellung `openapi_url` mit dem gleichen Defaultwert `"/openapi.json"`.
diff --git a/docs/de/docs/how-to/custom-docs-ui-assets.md b/docs/de/docs/how-to/custom-docs-ui-assets.md
index a292be69b..f68902b99 100644
--- a/docs/de/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/de/docs/how-to/custom-docs-ui-assets.md
@@ -18,9 +18,7 @@ Der erste Schritt besteht darin, die automatischen Dokumentationen zu deaktivier
Um diese zu deaktivieren, setzen Sie deren URLs beim Erstellen Ihrer `FastAPI`-App auf `None`:
-```Python hl_lines="8"
-{!../../docs_src/custom_docs_ui/tutorial001.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *}
### Die benutzerdefinierten Dokumentationen hinzufügen
@@ -36,9 +34,7 @@ Sie können die internen Funktionen von FastAPI wiederverwenden, um die HTML-Sei
Und genau so für ReDoc ...
-```Python hl_lines="2-6 11-19 22-24 27-33"
-{!../../docs_src/custom_docs_ui/tutorial001.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *}
/// tip | Tipp
@@ -54,9 +50,7 @@ Swagger UI erledigt das hinter den Kulissen für Sie, benötigt aber diesen „U
Um nun testen zu können, ob alles funktioniert, erstellen Sie eine *Pfadoperation*:
-```Python hl_lines="36-38"
-{!../../docs_src/custom_docs_ui/tutorial001.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *}
### Es ausprobieren
@@ -104,7 +98,7 @@ Sie können wahrscheinlich mit der rechten Maustaste auf jeden Link klicken und
Und **ReDoc** verwendet diese Datei:
-* `redoc.standalone.js`
+* `redoc.standalone.js`
Danach könnte Ihre Dateistruktur wie folgt aussehen:
@@ -124,9 +118,7 @@ Danach könnte Ihre Dateistruktur wie folgt aussehen:
* Importieren Sie `StaticFiles`.
* „Mounten“ Sie eine `StaticFiles()`-Instanz in einem bestimmten Pfad.
-```Python hl_lines="7 11"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *}
### Die statischen Dateien testen
@@ -137,14 +129,8 @@ Sie sollten eine sehr lange JavaScript-Datei für **ReDoc** sehen.
Sie könnte beginnen mit etwas wie:
```JavaScript
-/*!
- * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
- * -------------------------------------------------------------
- * Version: "2.0.0-rc.18"
- * Repo: https://github.com/Redocly/redoc
- */
-!function(e,t){"object"==typeof exports&&"object"==typeof m
-
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
```
@@ -158,9 +144,7 @@ Wie bei der Verwendung eines benutzerdefinierten CDN besteht der erste Schritt d
Um diese zu deaktivieren, setzen Sie deren URLs beim Erstellen Ihrer `FastAPI`-App auf `None`:
-```Python hl_lines="9"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *}
### Die benutzerdefinierten Dokumentationen, mit statischen Dateien, hinzufügen
@@ -176,9 +160,7 @@ Auch hier können Sie die internen Funktionen von FastAPI wiederverwenden, um di
Und genau so für ReDoc ...
-```Python hl_lines="2-6 14-22 25-27 30-36"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *}
/// tip | Tipp
@@ -194,9 +176,7 @@ Swagger UI erledigt das hinter den Kulissen für Sie, benötigt aber diesen „U
Um nun testen zu können, ob alles funktioniert, erstellen Sie eine *Pfadoperation*:
-```Python hl_lines="39-41"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *}
### Benutzeroberfläche, mit statischen Dateien, testen
diff --git a/docs/de/docs/how-to/custom-request-and-route.md b/docs/de/docs/how-to/custom-request-and-route.md
index ef71d96dc..3e6f709b6 100644
--- a/docs/de/docs/how-to/custom-request-and-route.md
+++ b/docs/de/docs/how-to/custom-request-and-route.md
@@ -42,9 +42,7 @@ Wenn der Header kein `gzip` enthält, wird nicht versucht, den Body zu dekomprim
Auf diese Weise kann dieselbe Routenklasse gzip-komprimierte oder unkomprimierte Requests verarbeiten.
-```Python hl_lines="8-15"
-{!../../docs_src/custom_request_and_route/tutorial001.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial001.py hl[8:15] *}
### Eine benutzerdefinierte `GzipRoute`-Klasse erstellen
@@ -56,9 +54,7 @@ Diese Methode gibt eine Funktion zurück. Und diese Funktion empfängt einen Req
Hier verwenden wir sie, um aus dem ursprünglichen Request einen `GzipRequest` zu erstellen.
-```Python hl_lines="18-26"
-{!../../docs_src/custom_request_and_route/tutorial001.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial001.py hl[18:26] *}
/// note | Technische Details
@@ -96,26 +92,18 @@ Wir können denselben Ansatz auch verwenden, um in einem Exceptionhandler auf de
Alles, was wir tun müssen, ist, den Request innerhalb eines `try`/`except`-Blocks zu handhaben:
-```Python hl_lines="13 15"
-{!../../docs_src/custom_request_and_route/tutorial002.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial002.py hl[13,15] *}
Wenn eine Exception auftritt, befindet sich die `Request`-Instanz weiterhin im Gültigkeitsbereich, sodass wir den Requestbody lesen und bei der Fehlerbehandlung verwenden können:
-```Python hl_lines="16-18"
-{!../../docs_src/custom_request_and_route/tutorial002.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial002.py hl[16:18] *}
## Benutzerdefinierte `APIRoute`-Klasse in einem Router
Sie können auch den Parameter `route_class` eines `APIRouter` festlegen:
-```Python hl_lines="26"
-{!../../docs_src/custom_request_and_route/tutorial003.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial003.py hl[26] *}
In diesem Beispiel verwenden die *Pfadoperationen* unter dem `router` die benutzerdefinierte `TimedRoute`-Klasse und haben in der Response einen zusätzlichen `X-Response-Time`-Header mit der Zeit, die zum Generieren der Response benötigt wurde:
-```Python hl_lines="13-20"
-{!../../docs_src/custom_request_and_route/tutorial003.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial003.py hl[13:20] *}
diff --git a/docs/de/docs/how-to/extending-openapi.md b/docs/de/docs/how-to/extending-openapi.md
index c895fb860..3b1459364 100644
--- a/docs/de/docs/how-to/extending-openapi.md
+++ b/docs/de/docs/how-to/extending-openapi.md
@@ -43,25 +43,19 @@ Fügen wir beispielsweise Strawberry-Dokumentation.
diff --git a/docs/de/docs/how-to/separate-openapi-schemas.md b/docs/de/docs/how-to/separate-openapi-schemas.md
index 974341dd2..4f6911e79 100644
--- a/docs/de/docs/how-to/separate-openapi-schemas.md
+++ b/docs/de/docs/how-to/separate-openapi-schemas.md
@@ -10,123 +10,13 @@ Sehen wir uns an, wie das funktioniert und wie Sie es bei Bedarf ändern können
Nehmen wir an, Sie haben ein Pydantic-Modell mit Defaultwerten wie dieses:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-7]!}
-
-# Code unterhalb weggelassen 👇
-```
-
-
-👀 Vollständige Dateivorschau
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-9]!}
-
-# Code unterhalb weggelassen 👇
-```
-
-
-👀 Vollständige Dateivorschau
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-9]!}
-
-# Code unterhalb weggelassen 👇
-```
-
-
-👀 Vollständige Dateivorschau
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
-```
-
-
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
### Modell für Eingabe
Wenn Sie dieses Modell wie hier als Eingabe verwenden:
-//// tab | Python 3.10+
-
-```Python hl_lines="14"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-15]!}
-
-# Code unterhalb weggelassen 👇
-```
-
-
-👀 Vollständige Dateivorschau
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="16"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-17]!}
-
-# Code unterhalb weggelassen 👇
-```
-
-
-👀 Vollständige Dateivorschau
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="16"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-17]!}
-
-# Code unterhalb weggelassen 👇
-```
-
-
-👀 Vollständige Dateivorschau
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
-```
-
-
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
... dann ist das Feld `description` **nicht erforderlich**. Weil es den Defaultwert `None` hat.
@@ -142,29 +32,7 @@ Sie können überprüfen, dass das Feld `description` in der Dokumentation kein
Wenn Sie jedoch dasselbe Modell als Ausgabe verwenden, wie hier:
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="21"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="21"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
... dann, weil `description` einen Defaultwert hat, wird es, wenn Sie für dieses Feld **nichts zurückgeben**, immer noch diesen **Defaultwert** haben.
@@ -223,29 +91,7 @@ Unterstützung für `separate_input_output_schemas` wurde in FastAPI `0.102.0` h
///
-//// tab | Python 3.10+
-
-```Python hl_lines="10"
-{!> ../../docs_src/separate_openapi_schemas/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="12"
-{!> ../../docs_src/separate_openapi_schemas/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="12"
-{!> ../../docs_src/separate_openapi_schemas/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
### Gleiches Schema für Eingabe- und Ausgabemodelle in der Dokumentation
diff --git a/docs/de/docs/index.md b/docs/de/docs/index.md
index 411c8e969..d239f0815 100644
--- a/docs/de/docs/index.md
+++ b/docs/de/docs/index.md
@@ -12,7 +12,7 @@
-
-```console
-$ typer --install-completion
-
-zsh completion installed in /home/user/.bashrc.
-Completion will take effect once you restart the terminal.
-```
-
-
-
-### 📱 & 🩺 🎏 🕰
-
-🚥 👆 🏃 🖼 ⏮️, ✅:
-
-
-
-```console
-$ uvicorn tutorial001:app --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-```console
-// Use the command "live" and pass the language code as a CLI argument
-$ python ./scripts/docs.py live es
-
-[INFO] Serving on http://127.0.0.1:8008
-[INFO] Start watching changes
-[INFO] Start detecting changes
-```
-
-
-
-```console
-// Use the command new-lang, pass the language code as a CLI argument
-$ python ./scripts/docs.py new-lang ht
-
-Successfully initialized: docs/ht
-Updating ht
-Updating en
-```
-
-
-
-```console
-// Use the command "build-all", this will take a bit
-$ python ./scripts/docs.py build-all
-
-Updating es
-Updating en
-Building docs for: en
-Building docs for: es
-Successfully built docs for: es
-Copying en index.md to README.md
-```
-
-
-
-```console
-// Use the command "serve" after running "build-all"
-$ python ./scripts/docs.py serve
-
-Warning: this is a very simple server. For development, use mkdocs serve instead.
-This is here only to preview a site with translations already built.
-Make sure you run the build-all command first.
-Serving at: http://127.0.0.1:8008
-```
-
-
```console
-$ fastapi run main.py
-INFO Using path main.py
-INFO Resolved absolute path /home/user/code/awesomeapp/main.py
-INFO Searching for package file structure from directories with __init__.py files
-INFO Importing from /home/user/code/awesomeapp
-
- ╭─ Python module file ─╮
- │ │
- │ 🐍 main.py │
- │ │
- ╰──────────────────────╯
-
-INFO Importing module main
-INFO Found importable FastAPI app
-
- ╭─ Importable FastAPI app ─╮
- │ │
- │ from main import app │
- │ │
- ╰──────────────────────────╯
-
-INFO Using import string main:app
-
- ╭─────────── FastAPI CLI - Production mode ───────────╮
- │ │
- │ Serving at: http://0.0.0.0:8000 │
- │ │
- │ API docs: http://0.0.0.0:8000/docs │
- │ │
- │ Running in production mode, for development use: │
- │ │
- │ fastapi dev │
- │ │
- ╰─────────────────────────────────────────────────────╯
-
-INFO: Started server process [2306215]
-INFO: Waiting for application startup.
-INFO: Application startup complete.
-INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
+$ fastapi run main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories
+ with __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with
+ the following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Started server process [2306215]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Uvicorn running on http://0.0.0.0:8000(Press CTRL+C
+ to quit)
```
diff --git a/docs/en/docs/deployment/server-workers.md b/docs/en/docs/deployment/server-workers.md
index 622c10a30..5d6b0d00a 100644
--- a/docs/en/docs/deployment/server-workers.md
+++ b/docs/en/docs/deployment/server-workers.md
@@ -36,56 +36,43 @@ If you use the `fastapi` command:
```console
-$
fastapi run --workers 4 main.py
-INFO Using path main.py
-INFO Resolved absolute path /home/user/code/awesomeapp/main.py
-INFO Searching for package file structure from directories with __init__.py files
-INFO Importing from /home/user/code/awesomeapp
-
- ╭─ Python module file ─╮
- │ │
- │ 🐍 main.py │
- │ │
- ╰──────────────────────╯
-
-INFO Importing module main
-INFO Found importable FastAPI app
-
- ╭─ Importable FastAPI app ─╮
- │ │
- │ from main import app │
- │ │
- ╰──────────────────────────╯
-
-INFO Using import string main:app
-
- ╭─────────── FastAPI CLI - Production mode ───────────╮
- │ │
- │ Serving at: http://0.0.0.0:8000 │
- │ │
- │ API docs: http://0.0.0.0:8000/docs │
- │ │
- │ Running in production mode, for development use: │
- │ │
- │ fastapi dev │
- │ │
- ╰─────────────────────────────────────────────────────╯
-
-INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
-INFO: Started parent process [27365]
-INFO: Started server process [27368]
-INFO: 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.
-
+$ fastapi run --workers 4 main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Uvicorn running on http://0.0.0.0:8000(Press CTRL+C to
+ quit)
+ INFO Started parent process [27365]
+ INFO Started server process [27368]
+ INFO Started server process [27369]
+ INFO Started server process [27370]
+ INFO Started server process [27367]
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
```
diff --git a/docs/en/docs/external-links.md b/docs/en/docs/external-links.md
index 5a3b8ee33..3ed04e5c5 100644
--- a/docs/en/docs/external-links.md
+++ b/docs/en/docs/external-links.md
@@ -28,9 +28,12 @@ If you have an article, project, tool, or anything related to **FastAPI** that i
{% endfor %}
{% endfor %}
-## Projects
+## GitHub Repositories
-Latest GitHub projects with the topic `fastapi`:
+Most starred GitHub repositories with the topic `fastapi`:
-
-
+{% for repo in topic_repos %}
+
+★ {{repo.stars}} - {{repo.name}} by @{{repo.owner_login}}.
+
+{% endfor %}
diff --git a/docs/en/docs/fastapi-cli.md b/docs/en/docs/fastapi-cli.md
index e27bebcb4..654d2fe91 100644
--- a/docs/en/docs/fastapi-cli.md
+++ b/docs/en/docs/fastapi-cli.md
@@ -9,47 +9,39 @@ To run your FastAPI app for development, you can use the `fastapi dev` command:
```console
-$ fastapi dev main.py
-INFO Using path main.py
-INFO Resolved absolute path /home/user/code/awesomeapp/main.py
-INFO Searching for package file structure from directories with __init__.py files
-INFO Importing from /home/user/code/awesomeapp
-
- ╭─ Python module file ─╮
- │ │
- │ 🐍 main.py │
- │ │
- ╰──────────────────────╯
-
-INFO Importing module main
-INFO Found importable FastAPI app
-
- ╭─ Importable FastAPI app ─╮
- │ │
- │ from main import app │
- │ │
- ╰──────────────────────────╯
-
-INFO Using import string main:app
-
- ╭────────── FastAPI CLI - Development mode ───────────╮
- │ │
- │ Serving at: http://127.0.0.1:8000 │
- │ │
- │ API docs: http://127.0.0.1:8000/docs │
- │ │
- │ Running in development mode, for production use: │
- │ │
- │ fastapi run │
- │ │
- ╰─────────────────────────────────────────────────────╯
-
-INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-INFO: Started reloader process [2265862] using WatchFiles
-INFO: Started server process [2265873]
-INFO: Waiting for application startup.
-INFO: Application startup complete.
+$ fastapi dev main.py
+
+ FastAPI Starting development server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://127.0.0.1:8000
+ server Documentation at http://127.0.0.1:8000/docs
+
+ tip Running in development mode, for production use:
+ fastapi run
+
+ Logs:
+
+ INFO Will watch for changes in these directories:
+ ['/home/user/code/awesomeapp']
+ INFO Uvicorn running on http://127.0.0.1:8000(Press CTRL+C to
+ quit)
+ INFO Started reloader process [383138] using WatchFiles
+ INFO Started server process [383153]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
```
diff --git a/docs/en/docs/fastapi-people.md b/docs/en/docs/fastapi-people.md
index bf7954449..f2ca26013 100644
--- a/docs/en/docs/fastapi-people.md
+++ b/docs/en/docs/fastapi-people.md
@@ -13,15 +13,13 @@ Hey! 👋
This is me:
-{% if people %}
-{% endif %}
I'm the creator of **FastAPI**. You can read more about that in [Help FastAPI - Get Help - Connect with the author](help-fastapi.md#connect-with-the-author){.internal-link target=_blank}.
@@ -49,9 +47,11 @@ This is the current list of team members. 😎
They have different levels of involvement and permissions, they can perform [repository management tasks](./management-tasks.md){.internal-link target=_blank} and together we [manage the FastAPI repository](./management.md){.internal-link target=_blank}.
@@ -84,57 +84,73 @@ You can see the **FastAPI Experts** for:
These are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} during the last month. 🤓
-{% if people %}
+
{% for user in people.last_month_experts[:10] %}
+{% if user.login not in skip_users %}
+
-{% endif %}
### FastAPI Experts - 3 Months
These are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} during the last 3 months. 😎
-{% if people %}
+
{% for user in people.three_months_experts[:10] %}
+{% if user.login not in skip_users %}
+
-{% endif %}
### FastAPI Experts - 6 Months
These are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} during the last 6 months. 🧐
-{% if people %}
+
{% for user in people.six_months_experts[:10] %}
+{% if user.login not in skip_users %}
+
-{% endif %}
### FastAPI Experts - 1 Year
These are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} during the last year. 🧑🔬
-{% if people %}
+
{% for user in people.one_year_experts[:20] %}
+{% if user.login not in skip_users %}
+
-{% endif %}
### FastAPI Experts - All Time
@@ -142,15 +158,19 @@ Here are the all time **FastAPI Experts**. 🤓🤯
These are the users that have [helped others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} through *all time*. 🧙
-{% if people %}
+
{% for user in people.experts[:50] %}
+{% if user.login not in skip_users %}
+
-{% endif %}
## Top Contributors
@@ -158,19 +178,43 @@ Here are the **Top Contributors**. 👷
These users have [created the most Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank} that have been *merged*.
-They have contributed source code, documentation, translations, etc. 📦
+They have contributed source code, documentation, etc. 📦
-{% if people %}
-{% for user in people.top_contributors[:50] %}
+
+{% for user in (contributors.values() | list)[:50] %}
+
+{% if user.login not in skip_users %}
+
+There are hundreds of other contributors, you can see them all in the FastAPI GitHub Contributors page. 👷
+
+## Top Translators
+
+These are the **Top Translators**. 🌐
+
+These users have created the most Pull Requests with [translations to other languages](contributing.md#translations){.internal-link target=_blank} that have been *merged*.
+
+
+
+{% for user in (translators.values() | list)[:50] %}
+
+{% if user.login not in skip_users %}
+
+
+
{% endif %}
-There are many other contributors (more than a hundred), you can see them all in the FastAPI GitHub Contributors page. 👷
+{% endfor %}
+
+
## Top Translation Reviewers
@@ -178,15 +222,18 @@ These users are the **Top Translation Reviewers**. 🕵️
I only speak a few languages (and not very well 😅). So, the reviewers are the ones that have the [**power to approve translations**](contributing.md#translations){.internal-link target=_blank} of the documentation. Without them, there wouldn't be documentation in several other languages.
-{% if people %}
-{% for user in people.top_translations_reviewers[:50] %}
+{% for user in (translation_reviewers.values() | list)[:50] %}
+
+{% if user.login not in skip_users %}
diff --git a/docs/es/docs/advanced/additional-responses.md b/docs/es/docs/advanced/additional-responses.md
new file mode 100644
index 000000000..7788bccd9
--- /dev/null
+++ b/docs/es/docs/advanced/additional-responses.md
@@ -0,0 +1,247 @@
+# Responses Adicionales en OpenAPI
+
+/// warning | Advertencia
+
+Este es un tema bastante avanzado.
+
+Si estás comenzando con **FastAPI**, puede que no lo necesites.
+
+///
+
+Puedes declarar responses adicionales, con códigos de estado adicionales, media types, descripciones, etc.
+
+Esos responses adicionales se incluirán en el esquema de OpenAPI, por lo que también aparecerán en la documentación de la API.
+
+Pero para esos responses adicionales tienes que asegurarte de devolver un `Response` como `JSONResponse` directamente, con tu código de estado y contenido.
+
+## Response Adicional con `model`
+
+Puedes pasar a tus *decoradores de path operation* un parámetro `responses`.
+
+Recibe un `dict`: las claves son los códigos de estado para cada response (como `200`), y los valores son otros `dict`s con la información para cada uno de ellos.
+
+Cada uno de esos `dict`s de response puede tener una clave `model`, conteniendo un modelo de Pydantic, así como `response_model`.
+
+**FastAPI** tomará ese modelo, generará su JSON Schema y lo incluirá en el lugar correcto en OpenAPI.
+
+Por ejemplo, para declarar otro response con un código de estado `404` y un modelo Pydantic `Message`, puedes escribir:
+
+{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *}
+
+/// note | Nota
+
+Ten en cuenta que debes devolver el `JSONResponse` directamente.
+
+///
+
+/// info | Información
+
+La clave `model` no es parte de OpenAPI.
+
+**FastAPI** tomará el modelo de Pydantic de allí, generará el JSON Schema y lo colocará en el lugar correcto.
+
+El lugar correcto es:
+
+* En la clave `content`, que tiene como valor otro objeto JSON (`dict`) que contiene:
+ * Una clave con el media type, por ejemplo, `application/json`, que contiene como valor otro objeto JSON, que contiene:
+ * Una clave `schema`, que tiene como valor el JSON Schema del modelo, aquí es el lugar correcto.
+ * **FastAPI** agrega una referencia aquí a los JSON Schemas globales en otro lugar de tu OpenAPI en lugar de incluirlo directamente. De este modo, otras aplicaciones y clientes pueden usar esos JSON Schemas directamente, proporcionar mejores herramientas de generación de código, etc.
+
+///
+
+Los responses generadas en el OpenAPI para esta *path operation* serán:
+
+```JSON hl_lines="3-12"
+{
+ "responses": {
+ "404": {
+ "description": "Additional Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Message"
+ }
+ }
+ }
+ },
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/Item"
+ }
+ }
+ }
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+Los esquemas se referencian a otro lugar dentro del esquema de OpenAPI:
+
+```JSON hl_lines="4-16"
+{
+ "components": {
+ "schemas": {
+ "Message": {
+ "title": "Message",
+ "required": [
+ "message"
+ ],
+ "type": "object",
+ "properties": {
+ "message": {
+ "title": "Message",
+ "type": "string"
+ }
+ }
+ },
+ "Item": {
+ "title": "Item",
+ "required": [
+ "id",
+ "value"
+ ],
+ "type": "object",
+ "properties": {
+ "id": {
+ "title": "Id",
+ "type": "string"
+ },
+ "value": {
+ "title": "Value",
+ "type": "string"
+ }
+ }
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": [
+ "loc",
+ "msg",
+ "type"
+ ],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "msg": {
+ "title": "Message",
+ "type": "string"
+ },
+ "type": {
+ "title": "Error Type",
+ "type": "string"
+ }
+ }
+ },
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+## Media types adicionales para el response principal
+
+Puedes usar este mismo parámetro `responses` para agregar diferentes media type para el mismo response principal.
+
+Por ejemplo, puedes agregar un media type adicional de `image/png`, declarando que tu *path operation* puede devolver un objeto JSON (con media type `application/json`) o una imagen PNG:
+
+{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *}
+
+/// note | Nota
+
+Nota que debes devolver la imagen usando un `FileResponse` directamente.
+
+///
+
+/// info | Información
+
+A menos que especifiques un media type diferente explícitamente en tu parámetro `responses`, FastAPI asumirá que el response tiene el mismo media type que la clase de response principal (por defecto `application/json`).
+
+Pero si has especificado una clase de response personalizada con `None` como su media type, FastAPI usará `application/json` para cualquier response adicional que tenga un modelo asociado.
+
+///
+
+## Combinando información
+
+También puedes combinar información de response de múltiples lugares, incluyendo los parámetros `response_model`, `status_code`, y `responses`.
+
+Puedes declarar un `response_model`, usando el código de estado predeterminado `200` (o uno personalizado si lo necesitas), y luego declarar información adicional para ese mismo response en `responses`, directamente en el esquema de OpenAPI.
+
+**FastAPI** manterá la información adicional de `responses` y la combinará con el JSON Schema de tu modelo.
+
+Por ejemplo, puedes declarar un response con un código de estado `404` que usa un modelo Pydantic y tiene una `description` personalizada.
+
+Y un response con un código de estado `200` que usa tu `response_model`, pero incluye un `example` personalizado:
+
+{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *}
+
+Todo se combinará e incluirá en tu OpenAPI, y se mostrará en la documentación de la API:
+
+
+
+## Combina responses predefinidos y personalizados
+
+Es posible que desees tener algunos responses predefinidos que se apliquen a muchas *path operations*, pero que quieras combinarlos con responses personalizados necesarios por cada *path operation*.
+
+Para esos casos, puedes usar la técnica de Python de "desempaquetar" un `dict` con `**dict_to_unpack`:
+
+```Python
+old_dict = {
+ "old key": "old value",
+ "second old key": "second old value",
+}
+new_dict = {**old_dict, "new key": "new value"}
+```
+
+Aquí, `new_dict` contendrá todos los pares clave-valor de `old_dict` más el nuevo par clave-valor:
+
+```Python
+{
+ "old key": "old value",
+ "second old key": "second old value",
+ "new key": "new value",
+}
+```
+
+Puedes usar esa técnica para reutilizar algunos responses predefinidos en tus *path operations* y combinarlos con otros personalizados adicionales.
+
+Por ejemplo:
+
+{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *}
+
+## Más información sobre responses OpenAPI
+
+Para ver exactamente qué puedes incluir en los responses, puedes revisar estas secciones en la especificación OpenAPI:
+
+* Objeto de Responses de OpenAPI, incluye el `Response Object`.
+* Objeto de Response de OpenAPI, puedes incluir cualquier cosa de esto directamente en cada response dentro de tu parámetro `responses`. Incluyendo `description`, `headers`, `content` (dentro de este es que declaras diferentes media types y JSON Schemas), y `links`.
diff --git a/docs/es/docs/advanced/additional-status-codes.md b/docs/es/docs/advanced/additional-status-codes.md
index 4a0625c25..df7737aac 100644
--- a/docs/es/docs/advanced/additional-status-codes.md
+++ b/docs/es/docs/advanced/additional-status-codes.md
@@ -1,43 +1,41 @@
-# Códigos de estado adicionales
+# Códigos de Estado Adicionales
-Por defecto, **FastAPI** devolverá las respuestas utilizando una `JSONResponse`, poniendo el contenido que devuelves en tu *operación de path* dentro de esa `JSONResponse`.
+Por defecto, **FastAPI** devolverá los responses usando un `JSONResponse`, colocando el contenido que devuelves desde tu *path operation* dentro de ese `JSONResponse`.
-Utilizará el código de estado por defecto, o el que hayas asignado en tu *operación de path*.
+Usará el código de estado por defecto o el que configures en tu *path operation*.
## Códigos de estado adicionales
-Si quieres devolver códigos de estado adicionales además del principal, puedes hacerlo devolviendo directamente una `Response`, como una `JSONResponse`, y asignar directamente el código de estado adicional.
+Si quieres devolver códigos de estado adicionales aparte del principal, puedes hacerlo devolviendo un `Response` directamente, como un `JSONResponse`, y configurando el código de estado adicional directamente.
-Por ejemplo, digamos que quieres tener una *operación de path* que permita actualizar ítems y devolver códigos de estado HTTP 200 "OK" cuando sea exitosa.
+Por ejemplo, supongamos que quieres tener una *path operation* que permita actualizar elementos, y devuelva códigos de estado HTTP de 200 "OK" cuando sea exitoso.
-Pero también quieres que acepte nuevos ítems. Cuando los ítems no existan anteriormente, serán creados y devolverá un código de estado HTTP 201 "Created".
+Pero también quieres que acepte nuevos elementos. Y cuando los elementos no existían antes, los crea y devuelve un código de estado HTTP de 201 "Created".
-Para conseguir esto importa `JSONResponse` y devuelve ahí directamente tu contenido, asignando el `status_code` que quieras:
+Para lograr eso, importa `JSONResponse`, y devuelve tu contenido allí directamente, configurando el `status_code` que deseas:
-```Python hl_lines="4 25"
-{!../../docs_src/additional_status_codes/tutorial001.py!}
-```
+{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
/// warning | Advertencia
-Cuando devuelves directamente una `Response`, como en los ejemplos anteriores, será devuelta directamente.
+Cuando devuelves un `Response` directamente, como en el ejemplo anterior, se devuelve directamente.
-No será serializado con el modelo, etc.
+No se serializará con un modelo, etc.
-Asegúrate de que la respuesta tenga los datos que quieras, y que los valores sean JSON válidos (si estás usando `JSONResponse`).
+Asegúrate de que tenga los datos que deseas que tenga y que los valores sean JSON válidos (si estás usando `JSONResponse`).
///
/// note | Detalles Técnicos
-También podrías utilizar `from starlette.responses import JSONResponse`.
+También podrías usar `from starlette.responses import JSONResponse`.
-**FastAPI** provee las mismas `starlette.responses` que `fastapi.responses` simplemente como una convención para ti, el desarrollador. Pero la mayoría de las respuestas disponibles vienen directamente de Starlette. Lo mismo con `status`.
+**FastAPI** proporciona los mismos `starlette.responses` que `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles provienen directamente de Starlette. Lo mismo con `status`.
///
## OpenAPI y documentación de API
-Si quieres devolver códigos de estado y respuestas adicionales directamente, estas no estarán incluidas en el schema de OpenAPI (documentación de API), porque FastAPI no tiene una manera de conocer de antemano lo que vas a devolver.
+Si devuelves códigos de estado adicionales y responses directamente, no se incluirán en el esquema de OpenAPI (la documentación de la API), porque FastAPI no tiene una forma de saber de antemano qué vas a devolver.
-Pero puedes documentar eso en tu código usando [Respuestas Adicionales](additional-responses.md){.internal-link target=_blank}.
+Pero puedes documentarlo en tu código, usando: [Responses Adicionales](additional-responses.md){.internal-link target=_blank}.
diff --git a/docs/es/docs/advanced/advanced-dependencies.md b/docs/es/docs/advanced/advanced-dependencies.md
new file mode 100644
index 000000000..dd3c63a37
--- /dev/null
+++ b/docs/es/docs/advanced/advanced-dependencies.md
@@ -0,0 +1,65 @@
+# Dependencias Avanzadas
+
+## Dependencias con parámetros
+
+Todas las dependencias que hemos visto son una función o clase fija.
+
+Pero podría haber casos en los que quieras poder establecer parámetros en la dependencia, sin tener que declarar muchas funciones o clases diferentes.
+
+Imaginemos que queremos tener una dependencia que revise si el parámetro de query `q` contiene algún contenido fijo.
+
+Pero queremos poder parametrizar ese contenido fijo.
+
+## Una *instance* "callable"
+
+En Python hay una forma de hacer que una instance de una clase sea un "callable".
+
+No la clase en sí (que ya es un callable), sino una instance de esa clase.
+
+Para hacer eso, declaramos un método `__call__`:
+
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
+
+En este caso, este `__call__` es lo que **FastAPI** usará para comprobar parámetros adicionales y sub-dependencias, y es lo que llamará para pasar un valor al parámetro en tu *path operation function* más adelante.
+
+## Parametrizar la instance
+
+Y ahora, podemos usar `__init__` para declarar los parámetros de la instance que podemos usar para "parametrizar" la dependencia:
+
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
+
+En este caso, **FastAPI** nunca tocará ni se preocupará por `__init__`, lo usaremos directamente en nuestro código.
+
+## Crear una instance
+
+Podríamos crear una instance de esta clase con:
+
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
+
+Y de esa manera podemos "parametrizar" nuestra dependencia, que ahora tiene `"bar"` dentro de ella, como el atributo `checker.fixed_content`.
+
+## Usar la instance como una dependencia
+
+Luego, podríamos usar este `checker` en un `Depends(checker)`, en lugar de `Depends(FixedContentQueryChecker)`, porque la dependencia es la instance, `checker`, no la clase en sí.
+
+Y al resolver la dependencia, **FastAPI** llamará a este `checker` así:
+
+```Python
+checker(q="somequery")
+```
+
+...y pasará lo que eso retorne como el valor de la dependencia en nuestra *path operation function* como el parámetro `fixed_content_included`:
+
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
+
+/// tip | Consejo
+
+Todo esto podría parecer complicado. Y puede que no esté muy claro cómo es útil aún.
+
+Estos ejemplos son intencionalmente simples, pero muestran cómo funciona todo.
+
+En los capítulos sobre seguridad, hay funciones utilitarias que se implementan de esta misma manera.
+
+Si entendiste todo esto, ya sabes cómo funcionan por debajo esas herramientas de utilidad para seguridad.
+
+///
diff --git a/docs/es/docs/advanced/async-tests.md b/docs/es/docs/advanced/async-tests.md
new file mode 100644
index 000000000..f89db1533
--- /dev/null
+++ b/docs/es/docs/advanced/async-tests.md
@@ -0,0 +1,99 @@
+# Tests Asíncronos
+
+Ya has visto cómo probar tus aplicaciones de **FastAPI** usando el `TestClient` proporcionado. Hasta ahora, solo has visto cómo escribir tests sincrónicos, sin usar funciones `async`.
+
+Poder usar funciones asíncronas en tus tests puede ser útil, por ejemplo, cuando consultas tu base de datos de forma asíncrona. Imagina que quieres probar el envío de requests a tu aplicación FastAPI y luego verificar que tu backend escribió exitosamente los datos correctos en la base de datos, mientras usas un paquete de base de datos asíncrono.
+
+Veamos cómo podemos hacer que esto funcione.
+
+## pytest.mark.anyio
+
+Si queremos llamar funciones asíncronas en nuestros tests, nuestras funciones de test tienen que ser asíncronas. AnyIO proporciona un plugin útil para esto, que nos permite especificar que algunas funciones de test deben ser llamadas de manera asíncrona.
+
+## HTTPX
+
+Incluso si tu aplicación de **FastAPI** usa funciones `def` normales en lugar de `async def`, sigue siendo una aplicación `async` por debajo.
+
+El `TestClient` hace algo de magia interna para llamar a la aplicación FastAPI asíncrona en tus funciones de test `def` normales, usando pytest estándar. Pero esa magia ya no funciona cuando lo usamos dentro de funciones asíncronas. Al ejecutar nuestros tests de manera asíncrona, ya no podemos usar el `TestClient` dentro de nuestras funciones de test.
+
+El `TestClient` está basado en HTTPX, y afortunadamente, podemos usarlo directamente para probar la API.
+
+## Ejemplo
+
+Para un ejemplo simple, consideremos una estructura de archivos similar a la descrita en [Aplicaciones Más Grandes](../tutorial/bigger-applications.md){.internal-link target=_blank} y [Testing](../tutorial/testing.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+El archivo `main.py` tendría:
+
+{* ../../docs_src/async_tests/main.py *}
+
+El archivo `test_main.py` tendría los tests para `main.py`, podría verse así ahora:
+
+{* ../../docs_src/async_tests/test_main.py *}
+
+## Ejecútalo
+
+Puedes ejecutar tus tests como de costumbre vía:
+
+
+
+```console
+$ pytest
+
+---> 100%
+```
+
+
+
+## En Detalle
+
+El marcador `@pytest.mark.anyio` le dice a pytest que esta función de test debe ser llamada asíncronamente:
+
+{* ../../docs_src/async_tests/test_main.py hl[7] *}
+
+/// tip | Consejo
+
+Note que la función de test ahora es `async def` en lugar de solo `def` como antes al usar el `TestClient`.
+
+///
+
+Luego podemos crear un `AsyncClient` con la app y enviar requests asíncronos a ella, usando `await`.
+
+{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
+
+Esto es equivalente a:
+
+```Python
+response = client.get('/')
+```
+
+...que usábamos para hacer nuestros requests con el `TestClient`.
+
+/// tip | Consejo
+
+Nota que estamos usando async/await con el nuevo `AsyncClient`: el request es asíncrono.
+
+///
+
+/// warning | Advertencia
+
+Si tu aplicación depende de eventos de lifespan, el `AsyncClient` no activará estos eventos. Para asegurarte de que se activen, usa `LifespanManager` de florimondmanca/asgi-lifespan.
+
+///
+
+## Otras Llamadas a Funciones Asíncronas
+
+Al ser la función de test asíncrona, ahora también puedes llamar (y `await`) otras funciones `async` además de enviar requests a tu aplicación FastAPI en tus tests, exactamente como las llamarías en cualquier otro lugar de tu código.
+
+/// tip | Consejo
+
+Si encuentras un `RuntimeError: Task attached to a different loop` al integrar llamadas a funciones asíncronas en tus tests (por ejemplo, cuando usas MotorClient de MongoDB), recuerda crear instances de objetos que necesiten un loop de eventos solo dentro de funciones async, por ejemplo, en un callback `'@app.on_event("startup")`.
+
+///
diff --git a/docs/es/docs/advanced/behind-a-proxy.md b/docs/es/docs/advanced/behind-a-proxy.md
new file mode 100644
index 000000000..8c590cbe8
--- /dev/null
+++ b/docs/es/docs/advanced/behind-a-proxy.md
@@ -0,0 +1,361 @@
+# Detrás de un Proxy
+
+En algunas situaciones, podrías necesitar usar un **proxy** como Traefik o Nginx con una configuración que añade un prefijo de path extra que no es visto por tu aplicación.
+
+En estos casos, puedes usar `root_path` para configurar tu aplicación.
+
+El `root_path` es un mecanismo proporcionado por la especificación ASGI (en la que está construido FastAPI, a través de Starlette).
+
+El `root_path` se usa para manejar estos casos específicos.
+
+Y también se usa internamente al montar subaplicaciones.
+
+## Proxy con un prefijo de path eliminado
+
+Tener un proxy con un prefijo de path eliminado, en este caso, significa que podrías declarar un path en `/app` en tu código, pero luego añades una capa encima (el proxy) que situaría tu aplicación **FastAPI** bajo un path como `/api/v1`.
+
+En este caso, el path original `/app` realmente sería servido en `/api/v1/app`.
+
+Aunque todo tu código esté escrito asumiendo que solo existe `/app`.
+
+{* ../../docs_src/behind_a_proxy/tutorial001.py hl[6] *}
+
+Y el proxy estaría **"eliminando"** el **prefijo del path** sobre la marcha antes de transmitir el request al servidor de aplicaciones (probablemente Uvicorn a través de FastAPI CLI), manteniendo a tu aplicación convencida de que está siendo servida en `/app`, así que no tienes que actualizar todo tu código para incluir el prefijo `/api/v1`.
+
+Hasta aquí, todo funcionaría normalmente.
+
+Pero luego, cuando abres la UI integrada de los docs (el frontend), esperaría obtener el esquema de OpenAPI en `/openapi.json`, en lugar de `/api/v1/openapi.json`.
+
+Entonces, el frontend (que se ejecuta en el navegador) trataría de alcanzar `/openapi.json` y no podría obtener el esquema de OpenAPI.
+
+Porque tenemos un proxy con un prefijo de path de `/api/v1` para nuestra aplicación, el frontend necesita obtener el esquema de OpenAPI en `/api/v1/openapi.json`.
+
+```mermaid
+graph LR
+
+browser("Navegador")
+proxy["Proxy en http://0.0.0.0:9999/api/v1/app"]
+server["Servidor en http://127.0.0.1:8000/app"]
+
+browser --> proxy
+proxy --> server
+```
+
+/// tip | Consejo
+
+La IP `0.0.0.0` se usa comúnmente para indicar que el programa escucha en todas las IPs disponibles en esa máquina/servidor.
+
+///
+
+La UI de los docs también necesitaría el esquema de OpenAPI para declarar que este API `servidor` se encuentra en `/api/v1` (detrás del proxy). Por ejemplo:
+
+```JSON hl_lines="4-8"
+{
+ "openapi": "3.1.0",
+ // Más cosas aquí
+ "servers": [
+ {
+ "url": "/api/v1"
+ }
+ ],
+ "paths": {
+ // Más cosas aquí
+ }
+}
+```
+
+En este ejemplo, el "Proxy" podría ser algo como **Traefik**. Y el servidor sería algo como FastAPI CLI con **Uvicorn**, ejecutando tu aplicación de FastAPI.
+
+### Proporcionando el `root_path`
+
+Para lograr esto, puedes usar la opción de línea de comandos `--root-path` como:
+
+
+
+```console
+$ fastapi run main.py --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Si usas Hypercorn, también tiene la opción `--root-path`.
+
+/// note | Detalles Técnicos
+
+La especificación ASGI define un `root_path` para este caso de uso.
+
+Y la opción de línea de comandos `--root-path` proporciona ese `root_path`.
+
+///
+
+### Revisar el `root_path` actual
+
+Puedes obtener el `root_path` actual utilizado por tu aplicación para cada request, es parte del diccionario `scope` (que es parte de la especificación ASGI).
+
+Aquí lo estamos incluyendo en el mensaje solo con fines de demostración.
+
+{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *}
+
+Luego, si inicias Uvicorn con:
+
+
+
+```console
+$ fastapi run main.py --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+El response sería algo como:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+### Configurar el `root_path` en la app de FastAPI
+
+Alternativamente, si no tienes una forma de proporcionar una opción de línea de comandos como `--root-path` o su equivalente, puedes configurar el parámetro `root_path` al crear tu app de FastAPI:
+
+{* ../../docs_src/behind_a_proxy/tutorial002.py hl[3] *}
+
+Pasar el `root_path` a `FastAPI` sería el equivalente a pasar la opción de línea de comandos `--root-path` a Uvicorn o Hypercorn.
+
+### Acerca de `root_path`
+
+Ten en cuenta que el servidor (Uvicorn) no usará ese `root_path` para nada, a excepción de pasárselo a la app.
+
+Pero si vas con tu navegador a http://127.0.0.1:8000/app verás el response normal:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+Así que no se esperará que sea accedido en `http://127.0.0.1:8000/api/v1/app`.
+
+Uvicorn esperará que el proxy acceda a Uvicorn en `http://127.0.0.1:8000/app`, y luego será responsabilidad del proxy añadir el prefijo extra `/api/v1` encima.
+
+## Sobre proxies con un prefijo de path eliminado
+
+Ten en cuenta que un proxy con prefijo de path eliminado es solo una de las formas de configurarlo.
+
+Probablemente en muchos casos, el valor predeterminado será que el proxy no tenga un prefijo de path eliminado.
+
+En un caso así (sin un prefijo de path eliminado), el proxy escucharía algo como `https://myawesomeapp.com`, y luego si el navegador va a `https://myawesomeapp.com/api/v1/app` y tu servidor (por ejemplo, Uvicorn) escucha en `http://127.0.0.1:8000`, el proxy (sin un prefijo de path eliminado) accedería a Uvicorn en el mismo path: `http://127.0.0.1:8000/api/v1/app`.
+
+## Probando localmente con Traefik
+
+Puedes ejecutar fácilmente el experimento localmente con un prefijo de path eliminado usando Traefik.
+
+Descarga Traefik, es un archivo binario único, puedes extraer el archivo comprimido y ejecutarlo directamente desde la terminal.
+
+Luego crea un archivo `traefik.toml` con:
+
+```TOML hl_lines="3"
+[entryPoints]
+ [entryPoints.http]
+ address = ":9999"
+
+[providers]
+ [providers.file]
+ filename = "routes.toml"
+```
+
+Esto le dice a Traefik que escuche en el puerto 9999 y que use otro archivo `routes.toml`.
+
+/// tip | Consejo
+
+Estamos utilizando el puerto 9999 en lugar del puerto HTTP estándar 80 para que no tengas que ejecutarlo con privilegios de administrador (`sudo`).
+
+///
+
+Ahora crea ese otro archivo `routes.toml`:
+
+```TOML hl_lines="5 12 20"
+[http]
+ [http.middlewares]
+
+ [http.middlewares.api-stripprefix.stripPrefix]
+ prefixes = ["/api/v1"]
+
+ [http.routers]
+
+ [http.routers.app-http]
+ entryPoints = ["http"]
+ service = "app"
+ rule = "PathPrefix(`/api/v1`)"
+ middlewares = ["api-stripprefix"]
+
+ [http.services]
+
+ [http.services.app]
+ [http.services.app.loadBalancer]
+ [[http.services.app.loadBalancer.servers]]
+ url = "http://127.0.0.1:8000"
+```
+
+Este archivo configura Traefik para usar el prefijo de path `/api/v1`.
+
+Y luego Traefik redireccionará sus requests a tu Uvicorn ejecutándose en `http://127.0.0.1:8000`.
+
+Ahora inicia Traefik:
+
+
+
+Y ahora inicia tu app, utilizando la opción `--root-path`:
+
+
+
+```console
+$ fastapi run main.py --root-path /api/v1
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+### Revisa los responses
+
+Ahora, si vas a la URL con el puerto para Uvicorn: http://127.0.0.1:8000/app, verás el response normal:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+/// tip | Consejo
+
+Nota que incluso aunque estés accediendo en `http://127.0.0.1:8000/app`, muestra el `root_path` de `/api/v1`, tomado de la opción `--root-path`.
+
+///
+
+Y ahora abre la URL con el puerto para Traefik, incluyendo el prefijo de path: http://127.0.0.1:9999/api/v1/app.
+
+Obtenemos el mismo response:
+
+```JSON
+{
+ "message": "Hello World",
+ "root_path": "/api/v1"
+}
+```
+
+pero esta vez en la URL con el prefijo de path proporcionado por el proxy: `/api/v1`.
+
+Por supuesto, la idea aquí es que todos accedan a la app a través del proxy, así que la versión con el prefijo de path `/api/v1` es la "correcta".
+
+Y la versión sin el prefijo de path (`http://127.0.0.1:8000/app`), proporcionada directamente por Uvicorn, sería exclusivamente para que el _proxy_ (Traefik) la acceda.
+
+Eso demuestra cómo el Proxy (Traefik) usa el prefijo de path y cómo el servidor (Uvicorn) usa el `root_path` de la opción `--root-path`.
+
+### Revisa la UI de los docs
+
+Pero aquí está la parte divertida. ✨
+
+La forma "oficial" de acceder a la app sería a través del proxy con el prefijo de path que definimos. Así que, como esperaríamos, si intentas usar la UI de los docs servida por Uvicorn directamente, sin el prefijo de path en la URL, no funcionará, porque espera ser accedida a través del proxy.
+
+Puedes verificarlo en http://127.0.0.1:8000/docs:
+
+
+
+Pero si accedemos a la UI de los docs en la URL "oficial" usando el proxy con puerto `9999`, en `/api/v1/docs`, ¡funciona correctamente! 🎉
+
+Puedes verificarlo en http://127.0.0.1:9999/api/v1/docs:
+
+
+
+Justo como queríamos. ✔️
+
+Esto es porque FastAPI usa este `root_path` para crear el `server` por defecto en OpenAPI con la URL proporcionada por `root_path`.
+
+## Servidores adicionales
+
+/// warning | Advertencia
+
+Este es un caso de uso más avanzado. Siéntete libre de omitirlo.
+
+///
+
+Por defecto, **FastAPI** creará un `server` en el esquema de OpenAPI con la URL para el `root_path`.
+
+Pero también puedes proporcionar otros `servers` alternativos, por ejemplo, si deseas que *la misma* UI de los docs interactúe con un entorno de pruebas y de producción.
+
+Si pasas una lista personalizada de `servers` y hay un `root_path` (porque tu API existe detrás de un proxy), **FastAPI** insertará un "server" con este `root_path` al comienzo de la lista.
+
+Por ejemplo:
+
+{* ../../docs_src/behind_a_proxy/tutorial003.py hl[4:7] *}
+
+Generará un esquema de OpenAPI como:
+
+```JSON hl_lines="5-7"
+{
+ "openapi": "3.1.0",
+ // Más cosas aquí
+ "servers": [
+ {
+ "url": "/api/v1"
+ },
+ {
+ "url": "https://stag.example.com",
+ "description": "Entorno de pruebas"
+ },
+ {
+ "url": "https://prod.example.com",
+ "description": "Entorno de producción"
+ }
+ ],
+ "paths": {
+ // Más cosas aquí
+ }
+}
+```
+
+/// tip | Consejo
+
+Observa el server auto-generado con un valor `url` de `/api/v1`, tomado del `root_path`.
+
+///
+
+En la UI de los docs en http://127.0.0.1:9999/api/v1/docs se vería como:
+
+
+
+/// tip | Consejo
+
+La UI de los docs interactuará con el server que selecciones.
+
+///
+
+### Desactivar el server automático de `root_path`
+
+Si no quieres que **FastAPI** incluya un server automático usando el `root_path`, puedes usar el parámetro `root_path_in_servers=False`:
+
+{* ../../docs_src/behind_a_proxy/tutorial004.py hl[9] *}
+
+y entonces no lo incluirá en el esquema de OpenAPI.
+
+## Montando una sub-aplicación
+
+Si necesitas montar una sub-aplicación (como se describe en [Aplicaciones secundarias - Monturas](sub-applications.md){.internal-link target=_blank}) mientras usas un proxy con `root_path`, puedes hacerlo normalmente, como esperarías.
+
+FastAPI usará internamente el `root_path` de manera inteligente, así que simplemente funcionará. ✨
diff --git a/docs/es/docs/advanced/custom-response.md b/docs/es/docs/advanced/custom-response.md
new file mode 100644
index 000000000..f7bd81bcc
--- /dev/null
+++ b/docs/es/docs/advanced/custom-response.md
@@ -0,0 +1,312 @@
+# Response Personalizado - HTML, Stream, Archivo, otros
+
+Por defecto, **FastAPI** devolverá los responses usando `JSONResponse`.
+
+Puedes sobrescribirlo devolviendo un `Response` directamente como se ve en [Devolver una Response directamente](response-directly.md){.internal-link target=_blank}.
+
+Pero si devuelves un `Response` directamente (o cualquier subclase, como `JSONResponse`), los datos no se convertirán automáticamente (incluso si declaras un `response_model`), y la documentación no se generará automáticamente (por ejemplo, incluyendo el "media type" específico, en el HTTP header `Content-Type` como parte del OpenAPI generado).
+
+Pero también puedes declarar el `Response` que quieres usar (por ejemplo, cualquier subclase de `Response`), en el *path operation decorator* usando el parámetro `response_class`.
+
+Los contenidos que devuelvas desde tu *path operation function* se colocarán dentro de esa `Response`.
+
+Y si ese `Response` tiene un media type JSON (`application/json`), como es el caso con `JSONResponse` y `UJSONResponse`, los datos que devuelvas se convertirán automáticamente (y serán filtrados) con cualquier `response_model` de Pydantic que hayas declarado en el *path operation decorator*.
+
+/// note | Nota
+
+Si usas una clase de response sin media type, FastAPI esperará que tu response no tenga contenido, por lo que no documentará el formato del response en su OpenAPI generado.
+
+///
+
+## Usa `ORJSONResponse`
+
+Por ejemplo, si estás exprimendo el rendimiento, puedes instalar y usar `orjson` y establecer el response como `ORJSONResponse`.
+
+Importa la clase `Response` (sub-clase) que quieras usar y declárala en el *path operation decorator*.
+
+Para responses grandes, devolver una `Response` directamente es mucho más rápido que devolver un diccionario.
+
+Esto se debe a que, por defecto, FastAPI inspeccionará cada elemento dentro y se asegurará de que sea serializable como JSON, usando el mismo [Codificador Compatible con JSON](../tutorial/encoder.md){.internal-link target=_blank} explicado en el tutorial. Esto es lo que te permite devolver **objetos arbitrarios**, por ejemplo, modelos de bases de datos.
+
+Pero si estás seguro de que el contenido que estás devolviendo es **serializable con JSON**, puedes pasarlo directamente a la clase de response y evitar la sobrecarga extra que FastAPI tendría al pasar tu contenido de retorno a través de `jsonable_encoder` antes de pasarlo a la clase de response.
+
+{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
+
+/// info | Información
+
+El parámetro `response_class` también se utilizará para definir el "media type" del response.
+
+En este caso, el HTTP header `Content-Type` se establecerá en `application/json`.
+
+Y se documentará así en OpenAPI.
+
+///
+
+/// tip | Consejo
+
+El `ORJSONResponse` solo está disponible en FastAPI, no en Starlette.
+
+///
+
+## Response HTML
+
+Para devolver un response con HTML directamente desde **FastAPI**, usa `HTMLResponse`.
+
+* Importa `HTMLResponse`.
+* Pasa `HTMLResponse` como parámetro `response_class` de tu *path operation decorator*.
+
+{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
+
+/// info | Información
+
+El parámetro `response_class` también se utilizará para definir el "media type" del response.
+
+En este caso, el HTTP header `Content-Type` se establecerá en `text/html`.
+
+Y se documentará así en OpenAPI.
+
+///
+
+### Devuelve una `Response`
+
+Como se ve en [Devolver una Response directamente](response-directly.md){.internal-link target=_blank}, también puedes sobrescribir el response directamente en tu *path operation*, devolviéndolo.
+
+El mismo ejemplo de arriba, devolviendo una `HTMLResponse`, podría verse así:
+
+{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
+
+/// warning | Advertencia
+
+Una `Response` devuelta directamente por tu *path operation function* no se documentará en OpenAPI (por ejemplo, el `Content-Type` no se documentará) y no será visible en la documentación interactiva automática.
+
+///
+
+/// info | Información
+
+Por supuesto, el `Content-Type` header real, el código de estado, etc., provendrán del objeto `Response` que devolviste.
+
+///
+
+### Documenta en OpenAPI y sobrescribe `Response`
+
+Si quieres sobrescribir el response desde dentro de la función pero al mismo tiempo documentar el "media type" en OpenAPI, puedes usar el parámetro `response_class` Y devolver un objeto `Response`.
+
+El `response_class` solo se usará para documentar el OpenAPI *path operation*, pero tu `Response` se usará tal cual.
+
+#### Devuelve un `HTMLResponse` directamente
+
+Por ejemplo, podría ser algo así:
+
+{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
+
+En este ejemplo, la función `generate_html_response()` ya genera y devuelve una `Response` en lugar de devolver el HTML en un `str`.
+
+Al devolver el resultado de llamar a `generate_html_response()`, ya estás devolviendo una `Response` que sobrescribirá el comportamiento predeterminado de **FastAPI**.
+
+Pero como pasaste `HTMLResponse` en el `response_class` también, **FastAPI** sabrá cómo documentarlo en OpenAPI y la documentación interactiva como HTML con `text/html`:
+
+
+
+## Responses disponibles
+
+Aquí hay algunos de los responses disponibles.
+
+Ten en cuenta que puedes usar `Response` para devolver cualquier otra cosa, o incluso crear una sub-clase personalizada.
+
+/// note | Nota Técnica
+
+También podrías usar `from starlette.responses import HTMLResponse`.
+
+**FastAPI** proporciona los mismos `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.
+
+///
+
+### `Response`
+
+La clase principal `Response`, todos los otros responses heredan de ella.
+
+Puedes devolverla directamente.
+
+Acepta los siguientes parámetros:
+
+* `content` - Un `str` o `bytes`.
+* `status_code` - Un código de estado HTTP `int`.
+* `headers` - Un `dict` de strings.
+* `media_type` - Un `str` que da el media type. Por ejemplo, `"text/html"`.
+
+FastAPI (de hecho Starlette) incluirá automáticamente un header Content-Length. También incluirá un header Content-Type, basado en el `media_type` y añadiendo un conjunto de caracteres para tipos de texto.
+
+{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
+
+### `HTMLResponse`
+
+Toma algún texto o bytes y devuelve un response HTML, como leíste arriba.
+
+### `PlainTextResponse`
+
+Toma algún texto o bytes y devuelve un response de texto plano.
+
+{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}
+
+### `JSONResponse`
+
+Toma algunos datos y devuelve un response codificado como `application/json`.
+
+Este es el response predeterminado usado en **FastAPI**, como leíste arriba.
+
+### `ORJSONResponse`
+
+Un response JSON rápido alternativo usando `orjson`, como leíste arriba.
+
+/// info | Información
+
+Esto requiere instalar `orjson`, por ejemplo, con `pip install orjson`.
+
+///
+
+### `UJSONResponse`
+
+Un response JSON alternativo usando `ujson`.
+
+/// info | Información
+
+Esto requiere instalar `ujson`, por ejemplo, con `pip install ujson`.
+
+///
+
+/// warning | Advertencia
+
+`ujson` es menos cuidadoso que la implementación integrada de Python en cómo maneja algunos casos extremos.
+
+///
+
+{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
+
+/// tip | Consejo
+
+Es posible que `ORJSONResponse` sea una alternativa más rápida.
+
+///
+
+### `RedirectResponse`
+
+Devuelve una redirección HTTP. Usa un código de estado 307 (Redirección Temporal) por defecto.
+
+Puedes devolver un `RedirectResponse` directamente:
+
+{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
+
+---
+
+O puedes usarlo en el parámetro `response_class`:
+
+{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *}
+
+Si haces eso, entonces puedes devolver la URL directamente desde tu *path operation function*.
+
+En este caso, el `status_code` utilizado será el predeterminado para `RedirectResponse`, que es `307`.
+
+---
+
+También puedes usar el parámetro `status_code` combinado con el parámetro `response_class`:
+
+{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *}
+
+### `StreamingResponse`
+
+Toma un generador `async` o un generador/iterador normal y transmite el cuerpo del response.
+
+{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
+
+#### Usando `StreamingResponse` con objetos similares a archivos
+
+Si tienes un objeto similar a un archivo (por ejemplo, el objeto devuelto por `open()`), puedes crear una función generadora para iterar sobre ese objeto similar a un archivo.
+
+De esa manera, no tienes que leerlo todo primero en memoria, y puedes pasar esa función generadora al `StreamingResponse`, y devolverlo.
+
+Esto incluye muchos paquetes para interactuar con almacenamiento en la nube, procesamiento de video y otros.
+
+{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}
+
+1. Esta es la función generadora. Es una "función generadora" porque contiene declaraciones `yield` dentro.
+2. Al usar un bloque `with`, nos aseguramos de que el objeto similar a un archivo se cierre después de que la función generadora termine. Así, después de que termina de enviar el response.
+3. Este `yield from` le dice a la función que itere sobre esa cosa llamada `file_like`. Y luego, para cada parte iterada, yield esa parte como proveniente de esta función generadora (`iterfile`).
+
+ Entonces, es una función generadora que transfiere el trabajo de "generar" a algo más internamente.
+
+ Al hacerlo de esta manera, podemos ponerlo en un bloque `with`, y de esa manera, asegurarnos de que el objeto similar a un archivo se cierre después de finalizar.
+
+/// tip | Consejo
+
+Nota que aquí como estamos usando `open()` estándar que no admite `async` y `await`, declaramos el path operation con `def` normal.
+
+///
+
+### `FileResponse`
+
+Transmite un archivo asincrónicamente como response.
+
+Toma un conjunto diferente de argumentos para crear un instance que los otros tipos de response:
+
+* `path` - La path del archivo para el archivo a transmitir.
+* `headers` - Cualquier header personalizado para incluir, como un diccionario.
+* `media_type` - Un string que da el media type. Si no se establece, se usará el nombre de archivo o la path para inferir un media type.
+* `filename` - Si se establece, se incluirá en el response `Content-Disposition`.
+
+Los responses de archivos incluirán los headers apropiados `Content-Length`, `Last-Modified` y `ETag`.
+
+{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}
+
+También puedes usar el parámetro `response_class`:
+
+{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *}
+
+En este caso, puedes devolver la path del archivo directamente desde tu *path operation* function.
+
+## Clase de response personalizada
+
+Puedes crear tu propia clase de response personalizada, heredando de `Response` y usándola.
+
+Por ejemplo, digamos que quieres usar `orjson`, pero con algunas configuraciones personalizadas no utilizadas en la clase `ORJSONResponse` incluida.
+
+Digamos que quieres que devuelva JSON con sangría y formato, por lo que quieres usar la opción de orjson `orjson.OPT_INDENT_2`.
+
+Podrías crear un `CustomORJSONResponse`. Lo principal que tienes que hacer es crear un método `Response.render(content)` que devuelva el contenido como `bytes`:
+
+{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *}
+
+Ahora en lugar de devolver:
+
+```json
+{"message": "Hello World"}
+```
+
+...este response devolverá:
+
+```json
+{
+ "message": "Hello World"
+}
+```
+
+Por supuesto, probablemente encontrarás formas mucho mejores de aprovechar esto que formatear JSON. 😉
+
+## Clase de response predeterminada
+
+Al crear una instance de la clase **FastAPI** o un `APIRouter`, puedes especificar qué clase de response usar por defecto.
+
+El parámetro que define esto es `default_response_class`.
+
+En el ejemplo a continuación, **FastAPI** usará `ORJSONResponse` por defecto, en todas las *path operations*, en lugar de `JSONResponse`.
+
+{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
+
+/// tip | Consejo
+
+Todavía puedes sobrescribir `response_class` en *path operations* como antes.
+
+///
+
+## Documentación adicional
+
+También puedes declarar el media type y muchos otros detalles en OpenAPI usando `responses`: [Responses Adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
diff --git a/docs/es/docs/advanced/dataclasses.md b/docs/es/docs/advanced/dataclasses.md
new file mode 100644
index 000000000..0ca1fd3b6
--- /dev/null
+++ b/docs/es/docs/advanced/dataclasses.md
@@ -0,0 +1,95 @@
+# Usando Dataclasses
+
+FastAPI está construido sobre **Pydantic**, y te he estado mostrando cómo usar modelos de Pydantic para declarar requests y responses.
+
+Pero FastAPI también soporta el uso de `dataclasses` de la misma manera:
+
+{* ../../docs_src/dataclasses/tutorial001.py hl[1,7:12,19:20] *}
+
+Esto sigue siendo soportado gracias a **Pydantic**, ya que tiene soporte interno para `dataclasses`.
+
+Así que, incluso con el código anterior que no usa Pydantic explícitamente, FastAPI está usando Pydantic para convertir esos dataclasses estándar en su propia versión de dataclasses de Pydantic.
+
+Y por supuesto, soporta lo mismo:
+
+* validación de datos
+* serialización de datos
+* documentación de datos, etc.
+
+Esto funciona de la misma manera que con los modelos de Pydantic. Y en realidad se logra de la misma manera internamente, utilizando Pydantic.
+
+/// info | Información
+
+Ten en cuenta que los dataclasses no pueden hacer todo lo que los modelos de Pydantic pueden hacer.
+
+Así que, podrías necesitar seguir usando modelos de Pydantic.
+
+Pero si tienes un montón de dataclasses por ahí, este es un buen truco para usarlos para potenciar una API web usando FastAPI. 🤓
+
+///
+
+## Dataclasses en `response_model`
+
+También puedes usar `dataclasses` en el parámetro `response_model`:
+
+{* ../../docs_src/dataclasses/tutorial002.py hl[1,7:13,19] *}
+
+El dataclass será automáticamente convertido a un dataclass de Pydantic.
+
+De esta manera, su esquema aparecerá en la interfaz de usuario de la documentación de la API:
+
+
+
+## Dataclasses en Estructuras de Datos Anidadas
+
+También puedes combinar `dataclasses` con otras anotaciones de tipos para crear estructuras de datos anidadas.
+
+En algunos casos, todavía podrías tener que usar la versión de `dataclasses` de Pydantic. Por ejemplo, si tienes errores con la documentación de la API generada automáticamente.
+
+En ese caso, simplemente puedes intercambiar los `dataclasses` estándar con `pydantic.dataclasses`, que es un reemplazo directo:
+
+{* ../../docs_src/dataclasses/tutorial003.py hl[1,5,8:11,14:17,23:25,28] *}
+
+1. Todavía importamos `field` de los `dataclasses` estándar.
+
+2. `pydantic.dataclasses` es un reemplazo directo para `dataclasses`.
+
+3. El dataclass `Author` incluye una lista de dataclasses `Item`.
+
+4. El dataclass `Author` se usa como el parámetro `response_model`.
+
+5. Puedes usar otras anotaciones de tipos estándar con dataclasses como el request body.
+
+ En este caso, es una lista de dataclasses `Item`.
+
+6. Aquí estamos regresando un diccionario que contiene `items`, que es una lista de dataclasses.
+
+ FastAPI todavía es capaz de serializar los datos a JSON.
+
+7. Aquí el `response_model` está usando una anotación de tipo de una lista de dataclasses `Author`.
+
+ Nuevamente, puedes combinar `dataclasses` con anotaciones de tipos estándar.
+
+8. Nota que esta *path operation function* usa `def` regular en lugar de `async def`.
+
+ Como siempre, en FastAPI puedes combinar `def` y `async def` según sea necesario.
+
+ Si necesitas un repaso sobre cuándo usar cuál, revisa la sección _"¿Con prisa?"_ en la documentación sobre [`async` y `await`](../async.md#in-a-hurry){.internal-link target=_blank}.
+
+9. Esta *path operation function* no está devolviendo dataclasses (aunque podría), sino una lista de diccionarios con datos internos.
+
+ FastAPI usará el parámetro `response_model` (que incluye dataclasses) para convertir el response.
+
+Puedes combinar `dataclasses` con otras anotaciones de tipos en muchas combinaciones diferentes para formar estructuras de datos complejas.
+
+Revisa las anotaciones en el código arriba para ver más detalles específicos.
+
+## Aprende Más
+
+También puedes combinar `dataclasses` con otros modelos de Pydantic, heredar de ellos, incluirlos en tus propios modelos, etc.
+
+Para saber más, revisa la documentación de Pydantic sobre dataclasses.
+
+## Versión
+
+Esto está disponible desde la versión `0.67.0` de FastAPI. 🔖
diff --git a/docs/es/docs/advanced/events.md b/docs/es/docs/advanced/events.md
new file mode 100644
index 000000000..022fb5a42
--- /dev/null
+++ b/docs/es/docs/advanced/events.md
@@ -0,0 +1,165 @@
+# Eventos de Lifespan
+
+Puedes definir lógica (código) que debería ser ejecutada antes de que la aplicación **inicie**. Esto significa que este código será ejecutado **una vez**, **antes** de que la aplicación **comience a recibir requests**.
+
+De la misma manera, puedes definir lógica (código) que debería ser ejecutada cuando la aplicación esté **cerrándose**. En este caso, este código será ejecutado **una vez**, **después** de haber manejado posiblemente **muchos requests**.
+
+Debido a que este código se ejecuta antes de que la aplicación **comience** a tomar requests, y justo después de que **termine** de manejarlos, cubre todo el **lifespan** de la aplicación (la palabra "lifespan" será importante en un momento 😉).
+
+Esto puede ser muy útil para configurar **recursos** que necesitas usar para toda la app, y que son **compartidos** entre requests, y/o que necesitas **limpiar** después. Por ejemplo, un pool de conexiones a una base de datos, o cargando un modelo de machine learning compartido.
+
+## Caso de Uso
+
+Empecemos con un ejemplo de **caso de uso** y luego veamos cómo resolverlo con esto.
+
+Imaginemos que tienes algunos **modelos de machine learning** que quieres usar para manejar requests. 🤖
+
+Los mismos modelos son compartidos entre requests, por lo que no es un modelo por request, o uno por usuario o algo similar.
+
+Imaginemos que cargar el modelo puede **tomar bastante tiempo**, porque tiene que leer muchos **datos del disco**. Entonces no quieres hacerlo para cada request.
+
+Podrías cargarlo en el nivel superior del módulo/archivo, pero eso también significaría que **cargaría el modelo** incluso si solo estás ejecutando una simple prueba automatizada, entonces esa prueba sería **lenta** porque tendría que esperar a que el modelo se cargue antes de poder ejecutar una parte independiente del código.
+
+Eso es lo que resolveremos, vamos a cargar el modelo antes de que los requests sean manejados, pero solo justo antes de que la aplicación comience a recibir requests, no mientras el código se está cargando.
+
+## Lifespan
+
+Puedes definir esta lógica de *startup* y *shutdown* usando el parámetro `lifespan` de la app de `FastAPI`, y un "context manager" (te mostraré lo que es en un momento).
+
+Comencemos con un ejemplo y luego veámoslo en detalle.
+
+Creamos una función asíncrona `lifespan()` con `yield` así:
+
+{* ../../docs_src/events/tutorial003.py hl[16,19] *}
+
+Aquí estamos simulando la operación costosa de *startup* de cargar el modelo poniendo la función del (falso) modelo en el diccionario con modelos de machine learning antes del `yield`. Este código será ejecutado **antes** de que la aplicación **comience a tomar requests**, durante el *startup*.
+
+Y luego, justo después del `yield`, quitaremos el modelo de memoria. Este código será ejecutado **después** de que la aplicación **termine de manejar requests**, justo antes del *shutdown*. Esto podría, por ejemplo, liberar recursos como la memoria o una GPU.
+
+/// tip | Consejo
+
+El `shutdown` ocurriría cuando estás **deteniendo** la aplicación.
+
+Quizás necesites iniciar una nueva versión, o simplemente te cansaste de ejecutarla. 🤷
+
+///
+
+### Función de Lifespan
+
+Lo primero que hay que notar es que estamos definiendo una función asíncrona con `yield`. Esto es muy similar a las Dependencias con `yield`.
+
+{* ../../docs_src/events/tutorial003.py hl[14:19] *}
+
+La primera parte de la función, antes del `yield`, será ejecutada **antes** de que la aplicación comience.
+
+Y la parte después del `yield` será ejecutada **después** de que la aplicación haya terminado.
+
+### Async Context Manager
+
+Si revisas, la función está decorada con un `@asynccontextmanager`.
+
+Eso convierte a la función en algo llamado un "**async context manager**".
+
+{* ../../docs_src/events/tutorial003.py hl[1,13] *}
+
+Un **context manager** en Python es algo que puedes usar en una declaración `with`, por ejemplo, `open()` puede ser usado como un context manager:
+
+```Python
+with open("file.txt") as file:
+ file.read()
+```
+
+En versiones recientes de Python, también hay un **async context manager**. Lo usarías con `async with`:
+
+```Python
+async with lifespan(app):
+ await do_stuff()
+```
+
+Cuando creas un context manager o un async context manager como arriba, lo que hace es que, antes de entrar al bloque `with`, ejecutará el código antes del `yield`, y al salir del bloque `with`, ejecutará el código después del `yield`.
+
+En nuestro ejemplo de código arriba, no lo usamos directamente, pero se lo pasamos a FastAPI para que lo use.
+
+El parámetro `lifespan` de la app de `FastAPI` toma un **async context manager**, por lo que podemos pasar nuestro nuevo `lifespan` async context manager a él.
+
+{* ../../docs_src/events/tutorial003.py hl[22] *}
+
+## Eventos Alternativos (obsoleto)
+
+/// warning | Advertencia
+
+La forma recomendada de manejar el *startup* y el *shutdown* es usando el parámetro `lifespan` de la app de `FastAPI` como se describió arriba. Si proporcionas un parámetro `lifespan`, los manejadores de eventos `startup` y `shutdown` ya no serán llamados. Es solo `lifespan` o solo los eventos, no ambos.
+
+Probablemente puedas saltarte esta parte.
+
+///
+
+Hay una forma alternativa de definir esta lógica para ser ejecutada durante el *startup* y durante el *shutdown*.
+
+Puedes definir manejadores de eventos (funciones) que necesitan ser ejecutadas antes de que la aplicación se inicie, o cuando la aplicación se está cerrando.
+
+Estas funciones pueden ser declaradas con `async def` o `def` normal.
+
+### Evento `startup`
+
+Para añadir una función que debería ejecutarse antes de que la aplicación inicie, declárala con el evento `"startup"`:
+
+{* ../../docs_src/events/tutorial001.py hl[8] *}
+
+En este caso, la función manejadora del evento `startup` inicializará los ítems de la "base de datos" (solo un `dict`) con algunos valores.
+
+Puedes añadir más de un manejador de eventos.
+
+Y tu aplicación no comenzará a recibir requests hasta que todos los manejadores de eventos `startup` hayan completado.
+
+### Evento `shutdown`
+
+Para añadir una función que debería ejecutarse cuando la aplicación se esté cerrando, declárala con el evento `"shutdown"`:
+
+{* ../../docs_src/events/tutorial002.py hl[6] *}
+
+Aquí, la función manejadora del evento `shutdown` escribirá una línea de texto `"Application shutdown"` a un archivo `log.txt`.
+
+/// info | Información
+
+En la función `open()`, el `mode="a"` significa "añadir", por lo tanto, la línea será añadida después de lo que sea que esté en ese archivo, sin sobrescribir el contenido anterior.
+
+///
+
+/// tip | Consejo
+
+Nota que en este caso estamos usando una función estándar de Python `open()` que interactúa con un archivo.
+
+Entonces, involucra I/O (entrada/salida), que requiere "esperar" para que las cosas se escriban en el disco.
+
+Pero `open()` no usa `async` y `await`.
+
+Por eso, declaramos la función manejadora del evento con `def` estándar en vez de `async def`.
+
+///
+
+### `startup` y `shutdown` juntos
+
+Hay una gran posibilidad de que la lógica para tu *startup* y *shutdown* esté conectada, podrías querer iniciar algo y luego finalizarlo, adquirir un recurso y luego liberarlo, etc.
+
+Hacer eso en funciones separadas que no comparten lógica o variables juntas es más difícil ya que necesitarías almacenar valores en variables globales o trucos similares.
+
+Debido a eso, ahora se recomienda en su lugar usar el `lifespan` como se explicó arriba.
+
+## Detalles Técnicos
+
+Solo un detalle técnico para los nerds curiosos. 🤓
+
+Por debajo, en la especificación técnica ASGI, esto es parte del Protocolo de Lifespan, y define eventos llamados `startup` y `shutdown`.
+
+/// info | Información
+
+Puedes leer más sobre los manejadores `lifespan` de Starlette en la documentación de `Lifespan` de Starlette.
+
+Incluyendo cómo manejar el estado de lifespan que puede ser usado en otras áreas de tu código.
+
+///
+
+## Sub Aplicaciones
+
+🚨 Ten en cuenta que estos eventos de lifespan (startup y shutdown) solo serán ejecutados para la aplicación principal, no para [Sub Aplicaciones - Mounts](sub-applications.md){.internal-link target=_blank}.
diff --git a/docs/es/docs/advanced/generate-clients.md b/docs/es/docs/advanced/generate-clients.md
new file mode 100644
index 000000000..bf2e5cb4f
--- /dev/null
+++ b/docs/es/docs/advanced/generate-clients.md
@@ -0,0 +1,261 @@
+# Genera Clientes
+
+Como **FastAPI** está basado en la especificación OpenAPI, obtienes compatibilidad automática con muchas herramientas, incluyendo la documentación automática de la API (proporcionada por Swagger UI).
+
+Una ventaja particular que no es necesariamente obvia es que puedes **generar clientes** (a veces llamados **SDKs** ) para tu API, para muchos **lenguajes de programación** diferentes.
+
+## Generadores de Clientes OpenAPI
+
+Hay muchas herramientas para generar clientes desde **OpenAPI**.
+
+Una herramienta común es OpenAPI Generator.
+
+Si estás construyendo un **frontend**, una alternativa muy interesante es openapi-ts.
+
+## Generadores de Clientes y SDKs - Sponsor
+
+También hay algunos generadores de Clientes y SDKs **respaldados por empresas** basados en OpenAPI (FastAPI), en algunos casos pueden ofrecerte **funcionalidades adicionales** además de SDKs/clientes generados de alta calidad.
+
+Algunos de ellos también ✨ [**sponsorean FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, esto asegura el **desarrollo** continuo y saludable de FastAPI y su **ecosistema**.
+
+Y muestra su verdadero compromiso con FastAPI y su **comunidad** (tú), ya que no solo quieren proporcionarte un **buen servicio** sino también asegurarse de que tengas un **buen y saludable framework**, FastAPI. 🙇
+
+Por ejemplo, podrías querer probar:
+
+* Speakeasy
+* Stainless
+* liblab
+
+También hay varias otras empresas que ofrecen servicios similares que puedes buscar y encontrar en línea. 🤓
+
+## Genera un Cliente Frontend en TypeScript
+
+Empecemos con una aplicación simple de FastAPI:
+
+{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
+
+Nota que las *path operations* definen los modelos que usan para el payload de la petición y el payload del response, usando los modelos `Item` y `ResponseMessage`.
+
+### Documentación de la API
+
+Si vas a la documentación de la API, verás que tiene los **esquemas** para los datos que se enviarán en las peticiones y se recibirán en los responses:
+
+
+
+Puedes ver esos esquemas porque fueron declarados con los modelos en la aplicación.
+
+Esa información está disponible en el **JSON Schema** de OpenAPI de la aplicación, y luego se muestra en la documentación de la API (por Swagger UI).
+
+Y esa misma información de los modelos que está incluida en OpenAPI es lo que puede usarse para **generar el código del cliente**.
+
+### Genera un Cliente en TypeScript
+
+Ahora que tenemos la aplicación con los modelos, podemos generar el código del cliente para el frontend.
+
+#### Instalar `openapi-ts`
+
+Puedes instalar `openapi-ts` en tu código de frontend con:
+
+
+
+Ese comando generará código en `./src/client` y usará `axios` (el paquete HTTP de frontend) internamente.
+
+### Prueba el Código del Cliente
+
+Ahora puedes importar y usar el código del cliente, podría verse así, nota que tienes autocompletado para los métodos:
+
+
+
+También obtendrás autocompletado para el payload a enviar:
+
+
+
+/// tip | Consejo
+
+Nota el autocompletado para `name` y `price`, que fue definido en la aplicación de FastAPI, en el modelo `Item`.
+
+///
+
+Tendrás errores en línea para los datos que envíes:
+
+
+
+El objeto de response también tendrá autocompletado:
+
+
+
+## App de FastAPI con Tags
+
+En muchos casos tu aplicación de FastAPI será más grande, y probablemente usarás tags para separar diferentes grupos de *path operations*.
+
+Por ejemplo, podrías tener una sección para **items** y otra sección para **usuarios**, y podrían estar separadas por tags:
+
+{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
+
+### Genera un Cliente TypeScript con Tags
+
+Si generas un cliente para una aplicación de FastAPI usando tags, normalmente también separará el código del cliente basándose en los tags.
+
+De esta manera podrás tener las cosas ordenadas y agrupadas correctamente para el código del cliente:
+
+
+
+En este caso tienes:
+
+* `ItemsService`
+* `UsersService`
+
+### Nombres de los Métodos del Cliente
+
+Ahora mismo los nombres de los métodos generados como `createItemItemsPost` no se ven muy limpios:
+
+```TypeScript
+ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
+```
+
+...eso es porque el generador del cliente usa el **operation ID** interno de OpenAPI para cada *path operation*.
+
+OpenAPI requiere que cada operation ID sea único a través de todas las *path operations*, por lo que FastAPI usa el **nombre de la función**, el **path**, y el **método/operación HTTP** para generar ese operation ID, porque de esa manera puede asegurarse de que los operation IDs sean únicos.
+
+Pero te mostraré cómo mejorar eso a continuación. 🤓
+
+## Operation IDs Personalizados y Mejores Nombres de Métodos
+
+Puedes **modificar** la forma en que estos operation IDs son **generados** para hacerlos más simples y tener **nombres de métodos más simples** en los clientes.
+
+En este caso tendrás que asegurarte de que cada operation ID sea **único** de alguna otra manera.
+
+Por ejemplo, podrías asegurarte de que cada *path operation* tenga un tag, y luego generar el operation ID basado en el **tag** y el nombre de la *path operation* **name** (el nombre de la función).
+
+### Función Personalizada para Generar ID Único
+
+FastAPI usa un **ID único** para cada *path operation*, se usa para el **operation ID** y también para los nombres de cualquier modelo personalizado necesario, para requests o responses.
+
+Puedes personalizar esa función. Toma un `APIRoute` y retorna un string.
+
+Por ejemplo, aquí está usando el primer tag (probablemente tendrás solo un tag) y el nombre de la *path operation* (el nombre de la función).
+
+Puedes entonces pasar esa función personalizada a **FastAPI** como el parámetro `generate_unique_id_function`:
+
+{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
+
+### Generar un Cliente TypeScript con Operation IDs Personalizados
+
+Ahora si generas el cliente de nuevo, verás que tiene los nombres de métodos mejorados:
+
+
+
+Como ves, los nombres de métodos ahora tienen el tag y luego el nombre de la función, ahora no incluyen información del path de la URL y la operación HTTP.
+
+### Preprocesa la Especificación OpenAPI para el Generador de Clientes
+
+El código generado aún tiene algo de **información duplicada**.
+
+Ya sabemos que este método está relacionado con los **items** porque esa palabra está en el `ItemsService` (tomado del tag), pero aún tenemos el nombre del tag prefijado en el nombre del método también. 😕
+
+Probablemente aún querremos mantenerlo para OpenAPI en general, ya que eso asegurará que los operation IDs sean **únicos**.
+
+Pero para el cliente generado podríamos **modificar** los operation IDs de OpenAPI justo antes de generar los clientes, solo para hacer esos nombres de métodos más bonitos y **limpios**.
+
+Podríamos descargar el JSON de OpenAPI a un archivo `openapi.json` y luego podríamos **remover ese tag prefijado** con un script como este:
+
+{* ../../docs_src/generate_clients/tutorial004.py *}
+
+//// tab | Node.js
+
+```Javascript
+{!> ../../docs_src/generate_clients/tutorial004.js!}
+```
+
+////
+
+Con eso, los operation IDs serían renombrados de cosas como `items-get_items` a solo `get_items`, de esa manera el generador del cliente puede generar nombres de métodos más simples.
+
+### Generar un Cliente TypeScript con el OpenAPI Preprocesado
+
+Ahora como el resultado final está en un archivo `openapi.json`, modificarías el `package.json` para usar ese archivo local, por ejemplo:
+
+```JSON hl_lines="7"
+{
+ "name": "frontend-app",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "generate-client": "openapi-ts --input ./openapi.json --output ./src/client --client axios"
+ },
+ "author": "",
+ "license": "",
+ "devDependencies": {
+ "@hey-api/openapi-ts": "^0.27.38",
+ "typescript": "^4.6.2"
+ }
+}
+```
+
+Después de generar el nuevo cliente, ahora tendrías nombres de métodos **limpios**, con todo el **autocompletado**, **errores en línea**, etc:
+
+
+
+## Beneficios
+
+Cuando usas los clientes generados automáticamente obtendrás **autocompletado** para:
+
+* Métodos.
+* Payloads de peticiones en el cuerpo, parámetros de query, etc.
+* Payloads de responses.
+
+También tendrás **errores en línea** para todo.
+
+Y cada vez que actualices el código del backend, y **regeneres** el frontend, tendrás las nuevas *path operations* disponibles como métodos, las antiguas eliminadas, y cualquier otro cambio se reflejará en el código generado. 🤓
+
+Esto también significa que si algo cambió será **reflejado** automáticamente en el código del cliente. Y si haces **build** del cliente, te dará error si tienes algún **desajuste** en los datos utilizados.
+
+Así que, **detectarás muchos errores** muy temprano en el ciclo de desarrollo en lugar de tener que esperar a que los errores se muestren a tus usuarios finales en producción para luego intentar depurar dónde está el problema. ✨
diff --git a/docs/es/docs/advanced/index.md b/docs/es/docs/advanced/index.md
index 10a1ff0d5..0626a1563 100644
--- a/docs/es/docs/advanced/index.md
+++ b/docs/es/docs/advanced/index.md
@@ -1,21 +1,36 @@
-# Guía de Usuario Avanzada
+# Guía avanzada del usuario
-## Características Adicionales
+## Funcionalidades adicionales
-El [Tutorial - Guía de Usuario](../tutorial/index.md){.internal-link target=_blank} principal debe ser suficiente para darte un paseo por todas las características principales de **FastAPI**
+El [Tutorial - Guía del usuario](../tutorial/index.md){.internal-link target=_blank} principal debería ser suficiente para darte un recorrido por todas las funcionalidades principales de **FastAPI**.
-En las secciones siguientes verás otras opciones, configuraciones, y características adicionales.
+En las siguientes secciones verás otras opciones, configuraciones y funcionalidades adicionales.
/// tip | Consejo
-Las próximas secciones **no son necesariamente "avanzadas"**.
+Las siguientes secciones **no son necesariamente "avanzadas"**.
-Y es posible que para tu caso, la solución se encuentre en una de estas.
+Y es posible que para tu caso de uso, la solución esté en una de ellas.
///
## Lee primero el Tutorial
-Puedes continuar usando la mayoría de las características de **FastAPI** con el conocimiento del [Tutorial - Guía de Usuario](../tutorial/index.md){.internal-link target=_blank} principal.
+Aún podrías usar la mayoría de las funcionalidades en **FastAPI** con el conocimiento del [Tutorial - Guía del usuario](../tutorial/index.md){.internal-link target=_blank} principal.
-En las siguientes secciones se asume que lo has leído y conoces esas ideas principales.
+Y las siguientes secciones asumen que ya lo leíste y que conoces esas ideas principales.
+
+## Cursos externos
+
+Aunque el [Tutorial - Guía del usuario](../tutorial/index.md){.internal-link target=_blank} y esta **Guía avanzada del usuario** están escritos como un tutorial guiado (como un libro) y deberían ser suficientes para que **aprendas FastAPI**, podrías querer complementarlo con cursos adicionales.
+
+O podría ser que simplemente prefieras tomar otros cursos porque se adaptan mejor a tu estilo de aprendizaje.
+
+Algunos proveedores de cursos ✨ [**sponsorean FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, esto asegura el desarrollo continuo y saludable de FastAPI y su **ecosistema**.
+
+Y muestra su verdadero compromiso con FastAPI y su **comunidad** (tú), ya que no solo quieren brindarte una **buena experiencia de aprendizaje** sino que también quieren asegurarse de que tengas un **buen y saludable framework**, FastAPI. 🙇
+
+Podrías querer probar sus cursos:
+
+* Talk Python Training
+* Desarrollo guiado por pruebas
diff --git a/docs/es/docs/advanced/middleware.md b/docs/es/docs/advanced/middleware.md
new file mode 100644
index 000000000..b8fd86185
--- /dev/null
+++ b/docs/es/docs/advanced/middleware.md
@@ -0,0 +1,96 @@
+# Middleware Avanzado
+
+En el tutorial principal leíste cómo agregar [Middleware Personalizado](../tutorial/middleware.md){.internal-link target=_blank} a tu aplicación.
+
+Y luego también leíste cómo manejar [CORS con el `CORSMiddleware`](../tutorial/cors.md){.internal-link target=_blank}.
+
+En esta sección veremos cómo usar otros middlewares.
+
+## Agregando middlewares ASGI
+
+Como **FastAPI** está basado en Starlette e implementa la especificación ASGI, puedes usar cualquier middleware ASGI.
+
+Un middleware no tiene que estar hecho para FastAPI o Starlette para funcionar, siempre que siga la especificación ASGI.
+
+En general, los middlewares ASGI son clases que esperan recibir una aplicación ASGI como primer argumento.
+
+Entonces, en la documentación de middlewares ASGI de terceros probablemente te indicarán que hagas algo como:
+
+```Python
+from unicorn import UnicornMiddleware
+
+app = SomeASGIApp()
+
+new_app = UnicornMiddleware(app, some_config="rainbow")
+```
+
+Pero FastAPI (en realidad Starlette) proporciona una forma más simple de hacerlo que asegura que los middlewares internos manejen errores del servidor y los controladores de excepciones personalizadas funcionen correctamente.
+
+Para eso, usas `app.add_middleware()` (como en el ejemplo para CORS).
+
+```Python
+from fastapi import FastAPI
+from unicorn import UnicornMiddleware
+
+app = FastAPI()
+
+app.add_middleware(UnicornMiddleware, some_config="rainbow")
+```
+
+`app.add_middleware()` recibe una clase de middleware como primer argumento y cualquier argumento adicional que se le quiera pasar al middleware.
+
+## Middlewares integrados
+
+**FastAPI** incluye varios middlewares para casos de uso común, veremos a continuación cómo usarlos.
+
+/// note | Detalles Técnicos
+
+Para los próximos ejemplos, también podrías usar `from starlette.middleware.something import SomethingMiddleware`.
+
+**FastAPI** proporciona varios middlewares en `fastapi.middleware` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los middlewares disponibles provienen directamente de Starlette.
+
+///
+
+## `HTTPSRedirectMiddleware`
+
+Impone que todas las requests entrantes deben ser `https` o `wss`.
+
+Cualquier request entrante a `http` o `ws` será redirigida al esquema seguro.
+
+{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *}
+
+## `TrustedHostMiddleware`
+
+Impone que todas las requests entrantes tengan correctamente configurado el header `Host`, para proteger contra ataques de HTTP Host Header.
+
+{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *}
+
+Se soportan los siguientes argumentos:
+
+* `allowed_hosts` - Una list de nombres de dominio que deberían ser permitidos como nombres de host. Se soportan dominios comodín como `*.example.com` para hacer coincidir subdominios. Para permitir cualquier nombre de host, usa `allowed_hosts=["*"]` u omite el middleware.
+
+Si una request entrante no se valida correctamente, se enviará un response `400`.
+
+## `GZipMiddleware`
+
+Maneja responses GZip para cualquier request que incluya `"gzip"` en el header `Accept-Encoding`.
+
+El middleware manejará tanto responses estándar como en streaming.
+
+{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *}
+
+Se soportan los siguientes argumentos:
+
+* `minimum_size` - No comprimir con GZip responses que sean más pequeñas que este tamaño mínimo en bytes. Por defecto es `500`.
+* `compresslevel` - Usado durante la compresión GZip. Es un entero que varía de 1 a 9. Por defecto es `9`. Un valor más bajo resulta en una compresión más rápida pero archivos más grandes, mientras que un valor más alto resulta en una compresión más lenta pero archivos más pequeños.
+
+## Otros middlewares
+
+Hay muchos otros middlewares ASGI.
+
+Por ejemplo:
+
+* `ProxyHeadersMiddleware` de Uvicorn
+* MessagePack
+
+Para ver otros middlewares disponibles, revisa la documentación de Middleware de Starlette y la Lista ASGI Awesome.
diff --git a/docs/es/docs/advanced/openapi-callbacks.md b/docs/es/docs/advanced/openapi-callbacks.md
new file mode 100644
index 000000000..60d5cb3cc
--- /dev/null
+++ b/docs/es/docs/advanced/openapi-callbacks.md
@@ -0,0 +1,186 @@
+# OpenAPI Callbacks
+
+Podrías crear una API con una *path operation* que podría desencadenar un request a una *API externa* creada por alguien más (probablemente el mismo desarrollador que estaría *usando* tu API).
+
+El proceso que ocurre cuando tu aplicación API llama a la *API externa* se llama un "callback". Porque el software que escribió el desarrollador externo envía un request a tu API y luego tu API *responde*, enviando un request a una *API externa* (que probablemente fue creada por el mismo desarrollador).
+
+En este caso, podrías querer documentar cómo esa API externa *debería* verse. Qué *path operation* debería tener, qué cuerpo debería esperar, qué response debería devolver, etc.
+
+## Una aplicación con callbacks
+
+Veamos todo esto con un ejemplo.
+
+Imagina que desarrollas una aplicación que permite crear facturas.
+
+Estas facturas tendrán un `id`, `title` (opcional), `customer`, y `total`.
+
+El usuario de tu API (un desarrollador externo) creará una factura en tu API con un request POST.
+
+Luego tu API (imaginemos):
+
+* Enviará la factura a algún cliente del desarrollador externo.
+* Recogerá el dinero.
+* Enviará una notificación de vuelta al usuario de la API (el desarrollador externo).
+ * Esto se hará enviando un request POST (desde *tu API*) a alguna *API externa* proporcionada por ese desarrollador externo (este es el "callback").
+
+## La aplicación normal de **FastAPI**
+
+Primero veamos cómo sería la aplicación API normal antes de agregar el callback.
+
+Tendrá una *path operation* que recibirá un cuerpo `Invoice`, y un parámetro de query `callback_url` que contendrá la URL para el callback.
+
+Esta parte es bastante normal, probablemente ya estés familiarizado con la mayor parte del código:
+
+{* ../../docs_src/openapi_callbacks/tutorial001.py hl[9:13,36:53] *}
+
+/// tip | Consejo
+
+El parámetro de query `callback_url` utiliza un tipo Url de Pydantic.
+
+///
+
+Lo único nuevo es el `callbacks=invoices_callback_router.routes` como un argumento para el *decorador de path operation*. Veremos qué es eso a continuación.
+
+## Documentar el callback
+
+El código real del callback dependerá mucho de tu propia aplicación API.
+
+Y probablemente variará mucho de una aplicación a otra.
+
+Podría ser solo una o dos líneas de código, como:
+
+```Python
+callback_url = "https://example.com/api/v1/invoices/events/"
+httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
+```
+
+Pero posiblemente la parte más importante del callback es asegurarse de que el usuario de tu API (el desarrollador externo) implemente la *API externa* correctamente, de acuerdo con los datos que *tu API* va a enviar en el request body del callback, etc.
+
+Entonces, lo que haremos a continuación es agregar el código para documentar cómo debería verse esa *API externa* para recibir el callback de *tu API*.
+
+Esa documentación aparecerá en la Swagger UI en `/docs` en tu API, y permitirá a los desarrolladores externos saber cómo construir la *API externa*.
+
+Este ejemplo no implementa el callback en sí (eso podría ser solo una línea de código), solo la parte de documentación.
+
+/// tip | Consejo
+
+El callback real es solo un request HTTP.
+
+Cuando implementes el callback tú mismo, podrías usar algo como HTTPX o Requests.
+
+///
+
+## Escribir el código de documentación del callback
+
+Este código no se ejecutará en tu aplicación, solo lo necesitamos para *documentar* cómo debería verse esa *API externa*.
+
+Pero, ya sabes cómo crear fácilmente documentación automática para una API con **FastAPI**.
+
+Así que vamos a usar ese mismo conocimiento para documentar cómo debería verse la *API externa*... creando la(s) *path operation(s)* que la API externa debería implementar (las que tu API va a llamar).
+
+/// tip | Consejo
+
+Cuando escribas el código para documentar un callback, podría ser útil imaginar que eres ese *desarrollador externo*. Y que actualmente estás implementando la *API externa*, no *tu API*.
+
+Adoptar temporalmente este punto de vista (del *desarrollador externo*) puede ayudarte a sentir que es más obvio dónde poner los parámetros, el modelo de Pydantic para el body, para el response, etc. para esa *API externa*.
+
+///
+
+### Crear un `APIRouter` de callback
+
+Primero crea un nuevo `APIRouter` que contendrá uno o más callbacks.
+
+{* ../../docs_src/openapi_callbacks/tutorial001.py hl[3,25] *}
+
+### Crear la *path operation* del callback
+
+Para crear la *path operation* del callback utiliza el mismo `APIRouter` que creaste anteriormente.
+
+Debería verse como una *path operation* normal de FastAPI:
+
+* Probablemente debería tener una declaración del body que debería recibir, por ejemplo `body: InvoiceEvent`.
+* Y también podría tener una declaración del response que debería devolver, por ejemplo `response_model=InvoiceEventReceived`.
+
+{* ../../docs_src/openapi_callbacks/tutorial001.py hl[16:18,21:22,28:32] *}
+
+Hay 2 diferencias principales respecto a una *path operation* normal:
+
+* No necesita tener ningún código real, porque tu aplicación nunca llamará a este código. Solo se usa para documentar la *API externa*. Así que, la función podría simplemente tener `pass`.
+* El *path* puede contener una expresión OpenAPI 3 (ver más abajo) donde puede usar variables con parámetros y partes del request original enviado a *tu API*.
+
+### La expresión del path del callback
+
+El *path* del callback puede tener una expresión OpenAPI 3 que puede contener partes del request original enviado a *tu API*.
+
+En este caso, es el `str`:
+
+```Python
+"{$callback_url}/invoices/{$request.body.id}"
+```
+
+Entonces, si el usuario de tu API (el desarrollador externo) envía un request a *tu API* a:
+
+```
+https://yourapi.com/invoices/?callback_url=https://www.external.org/events
+```
+
+con un JSON body de:
+
+```JSON
+{
+ "id": "2expen51ve",
+ "customer": "Mr. Richie Rich",
+ "total": "9999"
+}
+```
+
+luego *tu API* procesará la factura, y en algún momento después, enviará un request de callback al `callback_url` (la *API externa*):
+
+```
+https://www.external.org/events/invoices/2expen51ve
+```
+
+con un JSON body que contiene algo como:
+
+```JSON
+{
+ "description": "Payment celebration",
+ "paid": true
+}
+```
+
+y esperaría un response de esa *API externa* con un JSON body como:
+
+```JSON
+{
+ "ok": true
+}
+```
+
+/// tip | Consejo
+
+Observa cómo la URL del callback utilizada contiene la URL recibida como parámetro de query en `callback_url` (`https://www.external.org/events`) y también el `id` de la factura desde dentro del JSON body (`2expen51ve`).
+
+///
+
+### Agregar el router de callback
+
+En este punto tienes las *path operation(s)* del callback necesarias (las que el *desarrollador externo* debería implementar en la *API externa*) en el router de callback que creaste antes.
+
+Ahora usa el parámetro `callbacks` en el *decorador de path operation de tu API* para pasar el atributo `.routes` (que en realidad es solo un `list` de rutas/*path operations*) de ese router de callback:
+
+{* ../../docs_src/openapi_callbacks/tutorial001.py hl[35] *}
+
+/// tip | Consejo
+
+Observa que no estás pasando el router en sí (`invoices_callback_router`) a `callback=`, sino el atributo `.routes`, como en `invoices_callback_router.routes`.
+
+///
+
+### Revisa la documentación
+
+Ahora puedes iniciar tu aplicación e ir a http://127.0.0.1:8000/docs.
+
+Verás tu documentación incluyendo una sección de "Callbacks" para tu *path operation* que muestra cómo debería verse la *API externa*:
+
+
diff --git a/docs/es/docs/advanced/openapi-webhooks.md b/docs/es/docs/advanced/openapi-webhooks.md
new file mode 100644
index 000000000..01235b3ab
--- /dev/null
+++ b/docs/es/docs/advanced/openapi-webhooks.md
@@ -0,0 +1,55 @@
+# Webhooks de OpenAPI
+
+Hay casos donde quieres decirle a los **usuarios** de tu API que tu aplicación podría llamar a *su* aplicación (enviando una request) con algunos datos, normalmente para **notificar** de algún tipo de **evento**.
+
+Esto significa que en lugar del proceso normal de tus usuarios enviando requests a tu API, es **tu API** (o tu aplicación) la que podría **enviar requests a su sistema** (a su API, su aplicación).
+
+Esto normalmente se llama un **webhook**.
+
+## Pasos de los webhooks
+
+El proceso normalmente es que **tú defines** en tu código cuál es el mensaje que enviarás, el **body de la request**.
+
+También defines de alguna manera en qué **momentos** tu aplicación enviará esas requests o eventos.
+
+Y **tus usuarios** definen de alguna manera (por ejemplo en un panel web en algún lugar) el **URL** donde tu aplicación debería enviar esas requests.
+
+Toda la **lógica** sobre cómo registrar los URLs para webhooks y el código para realmente enviar esas requests depende de ti. Lo escribes como quieras en **tu propio código**.
+
+## Documentando webhooks con **FastAPI** y OpenAPI
+
+Con **FastAPI**, usando OpenAPI, puedes definir los nombres de estos webhooks, los tipos de operaciones HTTP que tu aplicación puede enviar (por ejemplo, `POST`, `PUT`, etc.) y los **bodies** de las requests que tu aplicación enviaría.
+
+Esto puede hacer mucho más fácil para tus usuarios **implementar sus APIs** para recibir tus requests de **webhook**, incluso podrían ser capaces de autogenerar algo de su propio código de API.
+
+/// info | Información
+
+Los webhooks están disponibles en OpenAPI 3.1.0 y superiores, soportados por FastAPI `0.99.0` y superiores.
+
+///
+
+## Una aplicación con webhooks
+
+Cuando creas una aplicación de **FastAPI**, hay un atributo `webhooks` que puedes usar para definir *webhooks*, de la misma manera que definirías *path operations*, por ejemplo con `@app.webhooks.post()`.
+
+{* ../../docs_src/openapi_webhooks/tutorial001.py hl[9:13,36:53] *}
+
+Los webhooks que defines terminarán en el esquema de **OpenAPI** y en la interfaz automática de **documentación**.
+
+/// info | Información
+
+El objeto `app.webhooks` es en realidad solo un `APIRouter`, el mismo tipo que usarías al estructurar tu aplicación con múltiples archivos.
+
+///
+
+Nota que con los webhooks en realidad no estás declarando un *path* (como `/items/`), el texto que pasas allí es solo un **identificador** del webhook (el nombre del evento), por ejemplo en `@app.webhooks.post("new-subscription")`, el nombre del webhook es `new-subscription`.
+
+Esto es porque se espera que **tus usuarios** definan el actual **URL path** donde quieren recibir la request del webhook de alguna otra manera (por ejemplo, un panel web).
+
+### Revisa la documentación
+
+Ahora puedes iniciar tu app e ir a http://127.0.0.1:8000/docs.
+
+Verás que tu documentación tiene las *path operations* normales y ahora también algunos **webhooks**:
+
+
diff --git a/docs/es/docs/advanced/path-operation-advanced-configuration.md b/docs/es/docs/advanced/path-operation-advanced-configuration.md
index 12399d581..2b20819aa 100644
--- a/docs/es/docs/advanced/path-operation-advanced-configuration.md
+++ b/docs/es/docs/advanced/path-operation-advanced-configuration.md
@@ -1,61 +1,204 @@
-# Configuración avanzada de las operaciones de path
+# Configuración Avanzada de Path Operation
-## OpenAPI operationId
+## operationId de OpenAPI
/// warning | Advertencia
-Si no eres una persona "experta" en OpenAPI, probablemente no necesitas leer esto.
+Si no eres un "experto" en OpenAPI, probablemente no necesites esto.
///
-Puedes asignar el `operationId` de OpenAPI para ser usado en tu *operación de path* con el parámetro `operation_id`.
+Puedes establecer el `operationId` de OpenAPI para ser usado en tu *path operation* con el parámetro `operation_id`.
-En este caso tendrías que asegurarte de que sea único para cada operación.
+Tienes que asegurarte de que sea único para cada operación.
-```Python hl_lines="6"
-{!../../docs_src/path_operation_advanced_configuration/tutorial001.py!}
-```
+{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *}
-### Usando el nombre de la *función de la operación de path* en el operationId
+### Usar el nombre de la *función de path operation* como el operationId
-Si quieres usar tus nombres de funciones de API como `operationId`s, puedes iterar sobre todos ellos y sobrescribir `operation_id` de cada *operación de path* usando su `APIRoute.name`.
+Si quieres usar los nombres de las funciones de tus APIs como `operationId`s, puedes iterar sobre todas ellas y sobrescribir el `operation_id` de cada *path operation* usando su `APIRoute.name`.
-Deberías hacerlo después de adicionar todas tus *operaciones de path*.
+Deberías hacerlo después de agregar todas tus *path operations*.
-```Python hl_lines="2 12 13 14 15 16 17 18 19 20 21 24"
-{!../../docs_src/path_operation_advanced_configuration/tutorial002.py!}
-```
+{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2, 12:21, 24] *}
/// tip | Consejo
-Si llamas manualmente a `app.openapi()`, debes actualizar el `operationId`s antes de hacerlo.
+Si llamas manualmente a `app.openapi()`, deberías actualizar los `operationId`s antes de eso.
///
/// warning | Advertencia
-Si haces esto, debes asegurarte de que cada una de tus *funciones de las operaciones de path* tenga un nombre único.
+Si haces esto, tienes que asegurarte de que cada una de tus *funciones de path operation* tenga un nombre único.
-Incluso si están en diferentes módulos (archivos Python).
+Incluso si están en diferentes módulos (archivos de Python).
///
## Excluir de OpenAPI
-Para excluir una *operación de path* del esquema OpenAPI generado (y por tanto del la documentación generada automáticamente), usa el parámetro `include_in_schema` y asigna el valor como `False`;
+Para excluir una *path operation* del esquema OpenAPI generado (y por lo tanto, de los sistemas de documentación automática), utiliza el parámetro `include_in_schema` y configúralo en `False`:
-```Python hl_lines="6"
-{!../../docs_src/path_operation_advanced_configuration/tutorial003.py!}
-```
+{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *}
## Descripción avanzada desde el docstring
-Puedes limitar las líneas usadas desde el docstring de una *operación de path* para OpenAPI.
+Puedes limitar las líneas usadas del docstring de una *función de path operation* para OpenAPI.
+
+Añadir un `\f` (un carácter de separación de página escapado) hace que **FastAPI** trunque la salida usada para OpenAPI en este punto.
+
+No aparecerá en la documentación, pero otras herramientas (como Sphinx) podrán usar el resto.
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial004.py hl[19:29] *}
+
+## Responses Adicionales
+
+Probablemente has visto cómo declarar el `response_model` y el `status_code` para una *path operation*.
+
+Eso define los metadatos sobre el response principal de una *path operation*.
+
+También puedes declarar responses adicionales con sus modelos, códigos de estado, etc.
+
+Hay un capítulo entero en la documentación sobre ello, puedes leerlo en [Responses Adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
+
+## OpenAPI Extra
+
+Cuando declaras una *path operation* en tu aplicación, **FastAPI** genera automáticamente los metadatos relevantes sobre esa *path operation* para incluirlos en el esquema de OpenAPI.
+
+/// note | Nota
+
+En la especificación de OpenAPI se llama el Objeto de Operación.
+
+///
-Agregar un `\f` (un carácter de "form feed" escapado) hace que **FastAPI** trunque el output utilizada para OpenAPI en ese punto.
+Tiene toda la información sobre la *path operation* y se usa para generar la documentación automática.
-No será mostrado en la documentación, pero otras herramientas (como Sphinx) serán capaces de usar el resto.
+Incluye los `tags`, `parameters`, `requestBody`, `responses`, etc.
-```Python hl_lines="19 20 21 22 23 24 25 26 27 28 29"
-{!../../docs_src/path_operation_advanced_configuration/tutorial004.py!}
+Este esquema de OpenAPI específico de *path operation* normalmente se genera automáticamente por **FastAPI**, pero también puedes extenderlo.
+
+/// tip | Consejo
+
+Este es un punto de extensión de bajo nivel.
+
+Si solo necesitas declarar responses adicionales, una forma más conveniente de hacerlo es con [Responses Adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
+
+///
+
+Puedes extender el esquema de OpenAPI para una *path operation* usando el parámetro `openapi_extra`.
+
+### Extensiones de OpenAPI
+
+Este `openapi_extra` puede ser útil, por ejemplo, para declarar [Extensiones de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *}
+
+Si abres la documentación automática de la API, tu extensión aparecerá en la parte inferior de la *path operation* específica.
+
+
+
+Y si ves el OpenAPI resultante (en `/openapi.json` en tu API), verás tu extensión como parte de la *path operation* específica también:
+
+```JSON hl_lines="22"
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "summary": "Read Items",
+ "operationId": "read_items_items__get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {}
+ }
+ }
+ }
+ },
+ "x-aperture-labs-portal": "blue"
+ }
+ }
+ }
+}
```
+
+### Esquema de *path operation* personalizada de OpenAPI
+
+El diccionario en `openapi_extra` se combinará profundamente con el esquema de OpenAPI generado automáticamente para la *path operation*.
+
+Por lo tanto, podrías añadir datos adicionales al esquema generado automáticamente.
+
+Por ejemplo, podrías decidir leer y validar el request con tu propio código, sin usar las funcionalidades automáticas de FastAPI con Pydantic, pero aún podrías querer definir el request en el esquema de OpenAPI.
+
+Podrías hacer eso con `openapi_extra`:
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[19:36, 39:40] *}
+
+En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el cuerpo del request ni siquiera se parse como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera.
+
+Sin embargo, podemos declarar el esquema esperado para el cuerpo del request.
+
+### Tipo de contenido personalizado de OpenAPI
+
+Usando este mismo truco, podrías usar un modelo Pydantic para definir el esquema JSON que luego se incluye en la sección personalizada del esquema OpenAPI para la *path operation*.
+
+Y podrías hacer esto incluso si el tipo de datos en el request no es JSON.
+
+Por ejemplo, en esta aplicación no usamos la funcionalidad integrada de FastAPI para extraer el esquema JSON de los modelos Pydantic ni la validación automática para JSON. De hecho, estamos declarando el tipo de contenido del request como YAML, no JSON:
+
+//// tab | Pydantic v2
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[17:22, 24] *}
+
+////
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1.py hl[17:22, 24] *}
+
+////
+
+/// info | Información
+
+En la versión 1 de Pydantic el método para obtener el esquema JSON para un modelo se llamaba `Item.schema()`, en la versión 2 de Pydantic, el método se llama `Item.model_json_schema()`.
+
+///
+
+Sin embargo, aunque no estamos usando la funcionalidad integrada por defecto, aún estamos usando un modelo Pydantic para generar manualmente el esquema JSON para los datos que queremos recibir en YAML.
+
+Luego usamos el request directamente, y extraemos el cuerpo como `bytes`. Esto significa que FastAPI ni siquiera intentará parsear la carga útil del request como JSON.
+
+Y luego en nuestro código, parseamos ese contenido YAML directamente, y nuevamente estamos usando el mismo modelo Pydantic para validar el contenido YAML:
+
+//// tab | Pydantic v2
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007.py hl[26:33] *}
+
+////
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1.py hl[26:33] *}
+
+////
+
+/// info | Información
+
+En la versión 1 de Pydantic el método para parsear y validar un objeto era `Item.parse_obj()`, en la versión 2 de Pydantic, el método se llama `Item.model_validate()`.
+
+///
+
+/// tip | Consejo
+
+Aquí reutilizamos el mismo modelo Pydantic.
+
+Pero de la misma manera, podríamos haberlo validado de alguna otra forma.
+
+///
diff --git a/docs/es/docs/advanced/response-change-status-code.md b/docs/es/docs/advanced/response-change-status-code.md
index ddfd05a77..e0889c474 100644
--- a/docs/es/docs/advanced/response-change-status-code.md
+++ b/docs/es/docs/advanced/response-change-status-code.md
@@ -1,33 +1,31 @@
-# Response - Cambiar el Status Code
+# Response - Cambiar Código de Estado
-Probablemente ya has leído con anterioridad que puedes establecer un [Response Status Code](../tutorial/response-status-code.md){.internal-link target=_blank} por defecto.
+Probablemente leíste antes que puedes establecer un [Código de Estado de Response](../tutorial/response-status-code.md){.internal-link target=_blank} por defecto.
-Pero en algunos casos necesitas retornar un status code diferente al predeterminado.
+Pero en algunos casos necesitas devolver un código de estado diferente al predeterminado.
-## Casos de uso
+## Caso de uso
-Por ejemplo, imagina que quieres retornar un HTTP status code de "OK" `200` por defecto.
+Por ejemplo, imagina que quieres devolver un código de estado HTTP de "OK" `200` por defecto.
-Pero si los datos no existen, quieres crearlos y retornar un HTTP status code de "CREATED" `201`.
+Pero si los datos no existieran, quieres crearlos y devolver un código de estado HTTP de "CREATED" `201`.
-Pero aún quieres poder filtrar y convertir los datos que retornas con un `response_model`.
+Pero todavía quieres poder filtrar y convertir los datos que devuelves con un `response_model`.
Para esos casos, puedes usar un parámetro `Response`.
-## Usar un parámetro `Response`
+## Usa un parámetro `Response`
-Puedes declarar un parámetro de tipo `Response` en tu *función de la operación de path* (como puedes hacer para cookies y headers).
+Puedes declarar un parámetro de tipo `Response` en tu *función de path operation* (como puedes hacer para cookies y headers).
-Y luego puedes establecer el `status_code` en ese objeto de respuesta *temporal*.
+Y luego puedes establecer el `status_code` en ese objeto de response *temporal*.
-```Python hl_lines="1 9 12"
-{!../../docs_src/response_change_status_code/tutorial001.py!}
-```
+{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *}
-Y luego puedes retornar cualquier objeto que necesites, como normalmente lo harías (un `dict`, un modelo de base de datos, etc).
+Y luego puedes devolver cualquier objeto que necesites, como lo harías normalmente (un `dict`, un modelo de base de datos, etc.).
-Y si declaraste un `response_model`, aún se usará para filtrar y convertir el objeto que retornaste.
+Y si declaraste un `response_model`, todavía se utilizará para filtrar y convertir el objeto que devolviste.
-**FastAPI** usará esa respuesta *temporal* para extraer el código de estado (también cookies y headers), y los pondrá en la respuesta final que contiene el valor que retornaste, filtrado por cualquier `response_model`.
+**FastAPI** usará ese response *temporal* para extraer el código de estado (también cookies y headers), y los pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier `response_model`.
-También puedes declarar la dependencia del parámetro `Response`, y establecer el código de estado en ellos. Pero ten en cuenta que el último en establecerse será el que gane.
+También puedes declarar el parámetro `Response` en dependencias y establecer el código de estado en ellas. Pero ten en cuenta que el último establecido prevalecerá.
diff --git a/docs/es/docs/advanced/response-cookies.md b/docs/es/docs/advanced/response-cookies.md
new file mode 100644
index 000000000..c4472eaa1
--- /dev/null
+++ b/docs/es/docs/advanced/response-cookies.md
@@ -0,0 +1,51 @@
+# Cookies de Response
+
+## Usar un parámetro `Response`
+
+Puedes declarar un parámetro de tipo `Response` en tu *path operation function*.
+
+Y luego puedes establecer cookies en ese objeto de response *temporal*.
+
+{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *}
+
+Y entonces puedes devolver cualquier objeto que necesites, como normalmente lo harías (un `dict`, un modelo de base de datos, etc).
+
+Y si declaraste un `response_model`, todavía se utilizará para filtrar y convertir el objeto que devolviste.
+
+**FastAPI** utilizará ese response *temporal* para extraer las cookies (también los headers y el código de estado), y las pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier `response_model`.
+
+También puedes declarar el parámetro `Response` en las dependencias, y establecer cookies (y headers) en ellas.
+
+## Devolver una `Response` directamente
+
+También puedes crear cookies al devolver una `Response` directamente en tu código.
+
+Para hacer eso, puedes crear un response como se describe en [Devolver un Response Directamente](response-directly.md){.internal-link target=_blank}.
+
+Luego establece Cookies en ella, y luego devuélvela:
+
+{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *}
+
+/// tip | Consejo
+
+Ten en cuenta que si devuelves un response directamente en lugar de usar el parámetro `Response`, FastAPI lo devolverá directamente.
+
+Así que tendrás que asegurarte de que tus datos son del tipo correcto. Por ejemplo, que sea compatible con JSON, si estás devolviendo un `JSONResponse`.
+
+Y también que no estés enviando ningún dato que debería haber sido filtrado por un `response_model`.
+
+///
+
+### Más información
+
+/// note | Detalles Técnicos
+
+También podrías usar `from starlette.responses import Response` o `from starlette.responses import JSONResponse`.
+
+**FastAPI** proporciona los mismos `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.
+
+Y como el `Response` se puede usar frecuentemente para establecer headers y cookies, **FastAPI** también lo proporciona en `fastapi.Response`.
+
+///
+
+Para ver todos los parámetros y opciones disponibles, revisa la documentación en Starlette.
diff --git a/docs/es/docs/advanced/response-directly.md b/docs/es/docs/advanced/response-directly.md
index 8800d2510..8594011d6 100644
--- a/docs/es/docs/advanced/response-directly.md
+++ b/docs/es/docs/advanced/response-directly.md
@@ -1,18 +1,18 @@
-# Devolver una respuesta directamente
+# Devolver una Response Directamente
-Cuando creas una *operación de path* normalmente puedes devolver cualquier dato: un `dict`, una `list`, un modelo Pydantic, un modelo de base de datos, etc.
+Cuando creas una *path operation* en **FastAPI**, normalmente puedes devolver cualquier dato desde ella: un `dict`, una `list`, un modelo de Pydantic, un modelo de base de datos, etc.
-Por defecto, **FastAPI** convertiría automáticamente ese valor devuelto a JSON usando el `jsonable_encoder` explicado en [Codificador Compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}.
+Por defecto, **FastAPI** convertiría automáticamente ese valor de retorno a JSON usando el `jsonable_encoder` explicado en [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
-Luego, tras bastidores, pondría esos datos compatibles con JSON (por ejemplo, un `dict`) dentro de una `JSONResponse` que se usaría para enviar la respuesta al cliente.
+Luego, detrás de escena, pondría esos datos compatibles con JSON (por ejemplo, un `dict`) dentro de un `JSONResponse` que se usaría para enviar el response al cliente.
-Pero puedes devolver una `JSONResponse` directamente de tu *operación de path*.
+Pero puedes devolver un `JSONResponse` directamente desde tus *path operations*.
-Esto puede ser útil, por ejemplo, para devolver cookies o headers personalizados.
+Esto podría ser útil, por ejemplo, para devolver headers o cookies personalizados.
## Devolver una `Response`
-De hecho, puedes devolver cualquier `Response` o cualquier subclase de la misma.
+De hecho, puedes devolver cualquier `Response` o cualquier subclase de ella.
/// tip | Consejo
@@ -22,48 +22,44 @@ De hecho, puedes devolver cualquier `Response` o cualquier subclase de la misma.
Y cuando devuelves una `Response`, **FastAPI** la pasará directamente.
-No hará ninguna conversión de datos con modelos Pydantic, no convertirá el contenido a ningún tipo, etc.
+No hará ninguna conversión de datos con los modelos de Pydantic, no convertirá los contenidos a ningún tipo, etc.
-Esto te da mucha flexibilidad. Puedes devolver cualquier tipo de dato, sobrescribir cualquier declaración de datos o validación, etc.
+Esto te da mucha flexibilidad. Puedes devolver cualquier tipo de datos, sobrescribir cualquier declaración o validación de datos, etc.
-## Usando el `jsonable_encoder` en una `Response`
+## Usar el `jsonable_encoder` en una `Response`
-Como **FastAPI** no realiza ningún cambio en la `Response` que devuelves, debes asegurarte de que el contenido está listo.
+Como **FastAPI** no realiza cambios en una `Response` que devuelves, tienes que asegurarte de que sus contenidos estén listos para ello.
-Por ejemplo, no puedes poner un modelo Pydantic en una `JSONResponse` sin primero convertirlo a un `dict` con todos los tipos de datos (como `datetime`, `UUID`, etc) convertidos a tipos compatibles con JSON.
+Por ejemplo, no puedes poner un modelo de Pydantic en un `JSONResponse` sin primero convertirlo a un `dict` con todos los tipos de datos (como `datetime`, `UUID`, etc.) convertidos a tipos compatibles con JSON.
-Para esos casos, puedes usar el `jsonable_encoder` para convertir tus datos antes de pasarlos a la respuesta:
+Para esos casos, puedes usar el `jsonable_encoder` para convertir tus datos antes de pasarlos a un response:
-```Python hl_lines="4 6 20 21"
-{!../../docs_src/response_directly/tutorial001.py!}
-```
+{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
-/// note | Detalles Técnicos
+/// note | Nota
-También puedes usar `from starlette.responses import JSONResponse`.
+También podrías usar `from starlette.responses import JSONResponse`.
-**FastAPI** provee `starlette.responses` como `fastapi.responses`, simplemente como una conveniencia para ti, el desarrollador. Pero la mayoría de las respuestas disponibles vienen directamente de Starlette.
+**FastAPI** proporciona los mismos `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.
///
-## Devolviendo una `Response` personalizada
+## Devolver una `Response` personalizada
-El ejemplo anterior muestra las partes que necesitas, pero no es muy útil todavía, dado que podrías simplemente devolver el `item` directamente, y **FastAPI** lo pondría en una `JSONResponse` por ti, convirtiéndolo en un `dict`, etc. Todo esto por defecto.
+El ejemplo anterior muestra todas las partes que necesitas, pero aún no es muy útil, ya que podrías haber devuelto el `item` directamente, y **FastAPI** lo colocaría en un `JSONResponse` por ti, convirtiéndolo a un `dict`, etc. Todo eso por defecto.
-Ahora, veamos cómo puedes usarlo para devolver una respuesta personalizada.
+Ahora, veamos cómo podrías usar eso para devolver un response personalizado.
-Digamos que quieres devolver una respuesta XML.
+Digamos que quieres devolver un response en XML.
-Podrías poner tu contenido XML en un string, ponerlo en una `Response` y devolverlo:
+Podrías poner tu contenido XML en un string, poner eso en un `Response`, y devolverlo:
-```Python hl_lines="1 18"
-{!../../docs_src/response_directly/tutorial002.py!}
-```
+{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
## Notas
-Cuando devuelves una `Response` directamente, los datos no son validados, convertidos (serializados), ni documentados automáticamente.
+Cuando devuelves una `Response` directamente, sus datos no son validados, convertidos (serializados), ni documentados automáticamente.
-Pero todavía es posible documentarlo como es descrito en [Respuestas adicionales en OpenAPI](additional-responses.md){.internal-link target=_blank}.
+Pero aún puedes documentarlo como se describe en [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}.
-Puedes ver en secciones posteriores como usar/declarar esas `Response`s personalizadas aún teniendo conversión automática de datos, documentación, etc.
+Puedes ver en secciones posteriores cómo usar/declarar estas `Response`s personalizadas mientras todavía tienes conversión automática de datos, documentación, etc.
diff --git a/docs/es/docs/advanced/response-headers.md b/docs/es/docs/advanced/response-headers.md
index 01d4fbc08..49eaa53c1 100644
--- a/docs/es/docs/advanced/response-headers.md
+++ b/docs/es/docs/advanced/response-headers.md
@@ -1,47 +1,41 @@
-# Headers de Respuesta
+# Response Headers
-## Usar un parámetro `Response`
+## Usa un parámetro `Response`
-Puedes declarar un parámetro de tipo `Response` en tu *función de operación de path* (de manera similar como se hace con las cookies).
+Puedes declarar un parámetro de tipo `Response` en tu *función de path operation* (como puedes hacer para cookies).
-Y entonces, podrás configurar las cookies en ese objeto de response *temporal*.
+Y luego puedes establecer headers en ese objeto de response *temporal*.
-```Python hl_lines="1 7-8"
-{!../../docs_src/response_headers/tutorial002.py!}
-```
+{* ../../docs_src/response_headers/tutorial002.py hl[1, 7:8] *}
-Posteriormente, puedes devolver cualquier objeto que necesites, como normalmente harías (un `dict`, un modelo de base de datos, etc).
+Y luego puedes devolver cualquier objeto que necesites, como harías normalmente (un `dict`, un modelo de base de datos, etc).
-Si declaraste un `response_model`, este se continuará usando para filtrar y convertir el objeto que devolviste.
+Y si declaraste un `response_model`, aún se usará para filtrar y convertir el objeto que devolviste.
-**FastAPI** usará ese response *temporal* para extraer los headers (al igual que las cookies y el status code), además las pondrá en el response final que contendrá el valor retornado y filtrado por algún `response_model`.
+**FastAPI** usará ese response *temporal* para extraer los headers (también cookies y el código de estado), y los pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier `response_model`.
-También puedes declarar el parámetro `Response` en dependencias, así como configurar los headers (y las cookies) en ellas.
+También puedes declarar el parámetro `Response` en dependencias y establecer headers (y cookies) en ellas.
+## Retorna una `Response` directamente
-## Retornar una `Response` directamente
+También puedes agregar headers cuando devuelves un `Response` directamente.
-Adicionalmente, puedes añadir headers cuando se retorne una `Response` directamente.
+Crea un response como se describe en [Retorna un Response Directamente](response-directly.md){.internal-link target=_blank} y pasa los headers como un parámetro adicional:
-Crea un response tal como se describe en [Retornar una respuesta directamente](response-directly.md){.internal-link target=_blank} y pasa los headers como un parámetro adicional:
-
-```Python hl_lines="10-12"
-{!../../docs_src/response_headers/tutorial001.py!}
-```
+{* ../../docs_src/response_headers/tutorial001.py hl[10:12] *}
/// note | Detalles Técnicos
-También podrías utilizar `from starlette.responses import Response` o `from starlette.responses import JSONResponse`.
-
-**FastAPI** proporciona las mismas `starlette.responses` en `fastapi.responses` sólo que de una manera más conveniente para ti, el desarrollador. En otras palabras, muchas de las responses disponibles provienen directamente de Starlette.
+También podrías usar `from starlette.responses import Response` o `from starlette.responses import JSONResponse`.
+**FastAPI** proporciona las mismas `starlette.responses` como `fastapi.responses` solo por conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles provienen directamente de Starlette.
-Y como la `Response` puede ser usada frecuentemente para configurar headers y cookies, **FastAPI** también la provee en `fastapi.Response`.
+Y como el `Response` se puede usar frecuentemente para establecer headers y cookies, **FastAPI** también lo proporciona en `fastapi.Response`.
///
## Headers Personalizados
-Ten en cuenta que se pueden añadir headers propietarios personalizados usando el prefijo 'X-'.
+Ten en cuenta que los headers propietarios personalizados se pueden agregar usando el prefijo 'X-'.
-Si tienes headers personalizados y deseas que un cliente pueda verlos en el navegador, es necesario que los añadas a tus configuraciones de CORS (puedes leer más en [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), usando el parámetro `expose_headers` documentado en Starlette's CORS docs.
+Pero si tienes headers personalizados que quieres que un cliente en un navegador pueda ver, necesitas agregarlos a tus configuraciones de CORS (leer más en [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}), usando el parámetro `expose_headers` documentado en la documentación CORS de Starlette.
diff --git a/docs/es/docs/advanced/security/http-basic-auth.md b/docs/es/docs/advanced/security/http-basic-auth.md
new file mode 100644
index 000000000..629e6c50a
--- /dev/null
+++ b/docs/es/docs/advanced/security/http-basic-auth.md
@@ -0,0 +1,107 @@
+# HTTP Basic Auth
+
+Para los casos más simples, puedes usar HTTP Basic Auth.
+
+En HTTP Basic Auth, la aplicación espera un header que contiene un nombre de usuario y una contraseña.
+
+Si no lo recibe, devuelve un error HTTP 401 "Unauthorized".
+
+Y devuelve un header `WWW-Authenticate` con un valor de `Basic`, y un parámetro `realm` opcional.
+
+Eso le dice al navegador que muestre el prompt integrado para un nombre de usuario y contraseña.
+
+Luego, cuando escribes ese nombre de usuario y contraseña, el navegador los envía automáticamente en el header.
+
+## Simple HTTP Basic Auth
+
+* Importa `HTTPBasic` y `HTTPBasicCredentials`.
+* Crea un "esquema de `security`" usando `HTTPBasic`.
+* Usa ese `security` con una dependencia en tu *path operation*.
+* Devuelve un objeto de tipo `HTTPBasicCredentials`:
+ * Contiene el `username` y `password` enviados.
+
+{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
+
+Cuando intentas abrir la URL por primera vez (o haces clic en el botón "Execute" en la documentación) el navegador te pedirá tu nombre de usuario y contraseña:
+
+
+
+## Revisa el nombre de usuario
+
+Aquí hay un ejemplo más completo.
+
+Usa una dependencia para comprobar si el nombre de usuario y la contraseña son correctos.
+
+Para esto, usa el módulo estándar de Python `secrets` para verificar el nombre de usuario y la contraseña.
+
+`secrets.compare_digest()` necesita tomar `bytes` o un `str` que solo contenga caracteres ASCII (los carácteres en inglés), esto significa que no funcionaría con caracteres como `á`, como en `Sebastián`.
+
+Para manejar eso, primero convertimos el `username` y `password` a `bytes` codificándolos con UTF-8.
+
+Luego podemos usar `secrets.compare_digest()` para asegurar que `credentials.username` es `"stanleyjobson"`, y que `credentials.password` es `"swordfish"`.
+
+{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
+
+Esto sería similar a:
+
+```Python
+if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
+ # Return some error
+ ...
+```
+
+Pero al usar `secrets.compare_digest()` será seguro contra un tipo de ataques llamados "timing attacks".
+
+### Timing Attacks
+
+¿Pero qué es un "timing attack"?
+
+Imaginemos que algunos atacantes están tratando de adivinar el nombre de usuario y la contraseña.
+
+Y envían un request con un nombre de usuario `johndoe` y una contraseña `love123`.
+
+Entonces el código de Python en tu aplicación equivaldría a algo como:
+
+```Python
+if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+Pero justo en el momento en que Python compara la primera `j` en `johndoe` con la primera `s` en `stanleyjobson`, devolverá `False`, porque ya sabe que esas dos strings no son iguales, pensando que "no hay necesidad de gastar más computación comparando el resto de las letras". Y tu aplicación dirá "Nombre de usuario o contraseña incorrectos".
+
+Pero luego los atacantes prueban con el nombre de usuario `stanleyjobsox` y contraseña `love123`.
+
+Y el código de tu aplicación hace algo así como:
+
+```Python
+if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
+ ...
+```
+
+Python tendrá que comparar todo `stanleyjobso` en ambos `stanleyjobsox` y `stanleyjobson` antes de darse cuenta de que ambas strings no son las mismas. Así que tomará algunos microsegundos extra para responder "Nombre de usuario o contraseña incorrectos".
+
+#### El tiempo de respuesta ayuda a los atacantes
+
+En ese punto, al notar que el servidor tardó algunos microsegundos más en enviar el response "Nombre de usuario o contraseña incorrectos", los atacantes sabrán que acertaron en _algo_, algunas de las letras iniciales eran correctas.
+
+Y luego pueden intentar de nuevo sabiendo que probablemente es algo más similar a `stanleyjobsox` que a `johndoe`.
+
+#### Un ataque "profesional"
+
+Por supuesto, los atacantes no intentarían todo esto a mano, escribirían un programa para hacerlo, posiblemente con miles o millones de pruebas por segundo. Y obtendrían solo una letra correcta adicional a la vez.
+
+Pero haciendo eso, en algunos minutos u horas, los atacantes habrían adivinado el nombre de usuario y la contraseña correctos, con la "ayuda" de nuestra aplicación, solo usando el tiempo tomado para responder.
+
+#### Arréglalo con `secrets.compare_digest()`
+
+Pero en nuestro código estamos usando realmente `secrets.compare_digest()`.
+
+En resumen, tomará el mismo tiempo comparar `stanleyjobsox` con `stanleyjobson` que comparar `johndoe` con `stanleyjobson`. Y lo mismo para la contraseña.
+
+De esa manera, usando `secrets.compare_digest()` en el código de tu aplicación, será seguro contra todo este rango de ataques de seguridad.
+
+### Devuelve el error
+
+Después de detectar que las credenciales son incorrectas, regresa un `HTTPException` con un código de estado 401 (el mismo que se devuelve cuando no se proporcionan credenciales) y agrega el header `WWW-Authenticate` para que el navegador muestre el prompt de inicio de sesión nuevamente:
+
+{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}
diff --git a/docs/es/docs/advanced/security/index.md b/docs/es/docs/advanced/security/index.md
index 92de67d6a..e4ccb5978 100644
--- a/docs/es/docs/advanced/security/index.md
+++ b/docs/es/docs/advanced/security/index.md
@@ -1,19 +1,19 @@
# Seguridad Avanzada
-## Características Adicionales
+## Funcionalidades Adicionales
-Hay algunas características adicionales para manejar la seguridad además de las que se tratan en el [Tutorial - Guía de Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank}.
+Hay algunas funcionalidades extra para manejar la seguridad aparte de las cubiertas en el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank}.
/// tip | Consejo
-Las siguientes secciones **no necesariamente son "avanzadas"**.
+Las siguientes secciones **no son necesariamente "avanzadas"**.
-Y es posible que para tu caso de uso, la solución esté en alguna de ellas.
+Y es posible que para tu caso de uso, la solución esté en una de ellas.
///
-## Leer primero el Tutorial
+## Lee primero el Tutorial
-En las siguientes secciones asumimos que ya has leído el principal [Tutorial - Guía de Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank}.
+Las siguientes secciones asumen que ya leíste el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md){.internal-link target=_blank}.
-Están basadas en los mismos conceptos, pero permiten algunas funcionalidades adicionales.
+Todas están basadas en los mismos conceptos, pero permiten algunas funcionalidades adicionales.
diff --git a/docs/es/docs/advanced/security/oauth2-scopes.md b/docs/es/docs/advanced/security/oauth2-scopes.md
new file mode 100644
index 000000000..17f7b19ca
--- /dev/null
+++ b/docs/es/docs/advanced/security/oauth2-scopes.md
@@ -0,0 +1,274 @@
+# Scopes de OAuth2
+
+Puedes usar scopes de OAuth2 directamente con **FastAPI**, están integrados para funcionar de manera fluida.
+
+Esto te permitiría tener un sistema de permisos más detallado, siguiendo el estándar de OAuth2, integrado en tu aplicación OpenAPI (y la documentación de la API).
+
+OAuth2 con scopes es el mecanismo usado por muchos grandes proveedores de autenticación, como Facebook, Google, GitHub, Microsoft, Twitter, etc. Lo usan para proporcionar permisos específicos a usuarios y aplicaciones.
+
+Cada vez que te "logueas con" Facebook, Google, GitHub, Microsoft, Twitter, esa aplicación está usando OAuth2 con scopes.
+
+En esta sección verás cómo manejar autenticación y autorización con el mismo OAuth2 con scopes en tu aplicación de **FastAPI**.
+
+/// warning | Advertencia
+
+Esta es una sección más o menos avanzada. Si estás comenzando, puedes saltarla.
+
+No necesariamente necesitas scopes de OAuth2, y puedes manejar autenticación y autorización como quieras.
+
+Pero OAuth2 con scopes se puede integrar muy bien en tu API (con OpenAPI) y en la documentación de tu API.
+
+No obstante, tú aún impones esos scopes, o cualquier otro requisito de seguridad/autorización, como necesites, en tu código.
+
+En muchos casos, OAuth2 con scopes puede ser un exceso.
+
+Pero si sabes que lo necesitas, o tienes curiosidad, sigue leyendo.
+
+///
+
+## Scopes de OAuth2 y OpenAPI
+
+La especificación de OAuth2 define "scopes" como una lista de strings separados por espacios.
+
+El contenido de cada uno de estos strings puede tener cualquier formato, pero no debe contener espacios.
+
+Estos scopes representan "permisos".
+
+En OpenAPI (por ejemplo, en la documentación de la API), puedes definir "esquemas de seguridad".
+
+Cuando uno de estos esquemas de seguridad usa OAuth2, también puedes declarar y usar scopes.
+
+Cada "scope" es solo un string (sin espacios).
+
+Normalmente se utilizan para declarar permisos de seguridad específicos, por ejemplo:
+
+* `users:read` o `users:write` son ejemplos comunes.
+* `instagram_basic` es usado por Facebook / Instagram.
+* `https://www.googleapis.com/auth/drive` es usado por Google.
+
+/// info | Información
+
+En OAuth2 un "scope" es solo un string que declara un permiso específico requerido.
+
+No importa si tiene otros caracteres como `:` o si es una URL.
+
+Esos detalles son específicos de la implementación.
+
+Para OAuth2 son solo strings.
+
+///
+
+## Vista global
+
+Primero, echemos un vistazo rápido a las partes que cambian desde los ejemplos en el **Tutorial - User Guide** principal para [OAuth2 con Password (y hashing), Bearer con tokens JWT](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank}. Ahora usando scopes de OAuth2:
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:125,129:135,140,156] *}
+
+Ahora revisemos esos cambios paso a paso.
+
+## Esquema de seguridad OAuth2
+
+El primer cambio es que ahora estamos declarando el esquema de seguridad OAuth2 con dos scopes disponibles, `me` y `items`.
+
+El parámetro `scopes` recibe un `dict` con cada scope como clave y la descripción como valor:
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
+
+Como ahora estamos declarando esos scopes, aparecerán en la documentación de la API cuando inicies sesión/autorices.
+
+Y podrás seleccionar cuáles scopes quieres dar de acceso: `me` y `items`.
+
+Este es el mismo mecanismo utilizado cuando das permisos al iniciar sesión con Facebook, Google, GitHub, etc:
+
+
+
+## Token JWT con scopes
+
+Ahora, modifica la *path operation* del token para devolver los scopes solicitados.
+
+Todavía estamos usando el mismo `OAuth2PasswordRequestForm`. Incluye una propiedad `scopes` con una `list` de `str`, con cada scope que recibió en el request.
+
+Y devolvemos los scopes como parte del token JWT.
+
+/// danger | Peligro
+
+Para simplificar, aquí solo estamos añadiendo los scopes recibidos directamente al token.
+
+Pero en tu aplicación, por seguridad, deberías asegurarte de añadir solo los scopes que el usuario realmente puede tener, o los que has predefinido.
+
+///
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[156] *}
+
+## Declarar scopes en *path operations* y dependencias
+
+Ahora declaramos que la *path operation* para `/users/me/items/` requiere el scope `items`.
+
+Para esto, importamos y usamos `Security` de `fastapi`.
+
+Puedes usar `Security` para declarar dependencias (igual que `Depends`), pero `Security` también recibe un parámetro `scopes` con una lista de scopes (strings).
+
+En este caso, pasamos una función de dependencia `get_current_active_user` a `Security` (de la misma manera que haríamos con `Depends`).
+
+Pero también pasamos una `list` de scopes, en este caso con solo un scope: `items` (podría tener más).
+
+Y la función de dependencia `get_current_active_user` también puede declarar sub-dependencias, no solo con `Depends` sino también con `Security`. Declarando su propia función de sub-dependencia (`get_current_user`), y más requisitos de scope.
+
+En este caso, requiere el scope `me` (podría requerir más de un scope).
+
+/// note | Nota
+
+No necesariamente necesitas añadir diferentes scopes en diferentes lugares.
+
+Lo estamos haciendo aquí para demostrar cómo **FastAPI** maneja scopes declarados en diferentes niveles.
+
+///
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[5,140,171] *}
+
+/// info | Información Técnica
+
+`Security` es en realidad una subclase de `Depends`, y tiene solo un parámetro extra que veremos más adelante.
+
+Pero al usar `Security` en lugar de `Depends`, **FastAPI** sabrá que puede declarar scopes de seguridad, usarlos internamente y documentar la API con OpenAPI.
+
+Pero cuando importas `Query`, `Path`, `Depends`, `Security` y otros de `fastapi`, en realidad son funciones que devuelven clases especiales.
+
+///
+
+## Usar `SecurityScopes`
+
+Ahora actualiza la dependencia `get_current_user`.
+
+Esta es la que usan las dependencias anteriores.
+
+Aquí es donde estamos usando el mismo esquema de OAuth2 que creamos antes, declarándolo como una dependencia: `oauth2_scheme`.
+
+Porque esta función de dependencia no tiene ningún requisito de scope en sí, podemos usar `Depends` con `oauth2_scheme`, no tenemos que usar `Security` cuando no necesitamos especificar scopes de seguridad.
+
+También declaramos un parámetro especial de tipo `SecurityScopes`, importado de `fastapi.security`.
+
+Esta clase `SecurityScopes` es similar a `Request` (`Request` se usó para obtener el objeto request directamente).
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}
+
+## Usar los `scopes`
+
+El parámetro `security_scopes` será del tipo `SecurityScopes`.
+
+Tendrá una propiedad `scopes` con una lista que contiene todos los scopes requeridos por sí mismo y por todas las dependencias que lo usan como sub-dependencia. Eso significa, todos los "dependientes"... esto podría sonar confuso, se explica de nuevo más abajo.
+
+El objeto `security_scopes` (de la clase `SecurityScopes`) también proporciona un atributo `scope_str` con un único string, que contiene esos scopes separados por espacios (lo vamos a usar).
+
+Creamos una `HTTPException` que podemos reutilizar (`raise`) más tarde en varios puntos.
+
+En esta excepción, incluimos los scopes requeridos (si los hay) como un string separado por espacios (usando `scope_str`). Ponemos ese string que contiene los scopes en el header `WWW-Authenticate` (esto es parte de la especificación).
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}
+
+## Verificar el `username` y la forma de los datos
+
+Verificamos que obtenemos un `username`, y extraemos los scopes.
+
+Y luego validamos esos datos con el modelo de Pydantic (capturando la excepción `ValidationError`), y si obtenemos un error leyendo el token JWT o validando los datos con Pydantic, lanzamos la `HTTPException` que creamos antes.
+
+Para eso, actualizamos el modelo de Pydantic `TokenData` con una nueva propiedad `scopes`.
+
+Al validar los datos con Pydantic podemos asegurarnos de que tenemos, por ejemplo, exactamente una `list` de `str` con los scopes y un `str` con el `username`.
+
+En lugar de, por ejemplo, un `dict`, o algo más, ya que podría romper la aplicación en algún punto posterior, haciéndolo un riesgo de seguridad.
+
+También verificamos que tenemos un usuario con ese username, y si no, lanzamos esa misma excepción que creamos antes.
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:128] *}
+
+## Verificar los `scopes`
+
+Ahora verificamos que todos los scopes requeridos, por esta dependencia y todos los dependientes (incluyendo *path operations*), estén incluidos en los scopes proporcionados en el token recibido, de lo contrario, lanzamos una `HTTPException`.
+
+Para esto, usamos `security_scopes.scopes`, que contiene una `list` con todos estos scopes como `str`.
+
+{* ../../docs_src/security/tutorial005_an_py310.py hl[129:135] *}
+
+## Árbol de dependencias y scopes
+
+Revisemos de nuevo este árbol de dependencias y los scopes.
+
+Como la dependencia `get_current_active_user` tiene como sub-dependencia a `get_current_user`, el scope `"me"` declarado en `get_current_active_user` se incluirá en la lista de scopes requeridos en el `security_scopes.scopes` pasado a `get_current_user`.
+
+La *path operation* en sí también declara un scope, `"items"`, por lo que esto también estará en la lista de `security_scopes.scopes` pasado a `get_current_user`.
+
+Así es como se ve la jerarquía de dependencias y scopes:
+
+* La *path operation* `read_own_items` tiene:
+ * Scopes requeridos `["items"]` con la dependencia:
+ * `get_current_active_user`:
+ * La función de dependencia `get_current_active_user` tiene:
+ * Scopes requeridos `["me"]` con la dependencia:
+ * `get_current_user`:
+ * La función de dependencia `get_current_user` tiene:
+ * No requiere scopes por sí misma.
+ * Una dependencia usando `oauth2_scheme`.
+ * Un parámetro `security_scopes` de tipo `SecurityScopes`:
+ * Este parámetro `security_scopes` tiene una propiedad `scopes` con una `list` que contiene todos estos scopes declarados arriba, por lo que:
+ * `security_scopes.scopes` contendrá `["me", "items"]` para la *path operation* `read_own_items`.
+ * `security_scopes.scopes` contendrá `["me"]` para la *path operation* `read_users_me`, porque está declarado en la dependencia `get_current_active_user`.
+ * `security_scopes.scopes` contendrá `[]` (nada) para la *path operation* `read_system_status`, porque no declaró ningún `Security` con `scopes`, y su dependencia, `get_current_user`, tampoco declara ningún `scopes`.
+
+/// tip | Consejo
+
+Lo importante y "mágico" aquí es que `get_current_user` tendrá una lista diferente de `scopes` para verificar para cada *path operation*.
+
+Todo depende de los `scopes` declarados en cada *path operation* y cada dependencia en el árbol de dependencias para esa *path operation* específica.
+
+///
+
+## Más detalles sobre `SecurityScopes`
+
+Puedes usar `SecurityScopes` en cualquier punto, y en múltiples lugares, no tiene que ser en la dependencia "raíz".
+
+Siempre tendrá los scopes de seguridad declarados en las dependencias `Security` actuales y todos los dependientes para **esa específica** *path operation* y **ese específico** árbol de dependencias.
+
+Debido a que `SecurityScopes` tendrá todos los scopes declarados por dependientes, puedes usarlo para verificar que un token tiene los scopes requeridos en una función de dependencia central, y luego declarar diferentes requisitos de scope en diferentes *path operations*.
+
+Serán verificados independientemente para cada *path operation*.
+
+## Revisa
+
+Si abres la documentación de la API, puedes autenticarte y especificar qué scopes deseas autorizar.
+
+
+
+Si no seleccionas ningún scope, estarás "autenticado", pero cuando intentes acceder a `/users/me/` o `/users/me/items/` obtendrás un error diciendo que no tienes suficientes permisos. Aún podrás acceder a `/status/`.
+
+Y si seleccionas el scope `me` pero no el scope `items`, podrás acceder a `/users/me/` pero no a `/users/me/items/`.
+
+Eso es lo que pasaría a una aplicación de terceros que intentara acceder a una de estas *path operations* con un token proporcionado por un usuario, dependiendo de cuántos permisos el usuario otorgó a la aplicación.
+
+## Acerca de las integraciones de terceros
+
+En este ejemplo estamos usando el flujo de OAuth2 "password".
+
+Esto es apropiado cuando estamos iniciando sesión en nuestra propia aplicación, probablemente con nuestro propio frontend.
+
+Porque podemos confiar en ella para recibir el `username` y `password`, ya que la controlamos.
+
+Pero si estás construyendo una aplicación OAuth2 a la que otros se conectarían (es decir, si estás construyendo un proveedor de autenticación equivalente a Facebook, Google, GitHub, etc.) deberías usar uno de los otros flujos.
+
+El más común es el flujo implícito.
+
+El más seguro es el flujo de código, pero es más complejo de implementar ya que requiere más pasos. Como es más complejo, muchos proveedores terminan sugiriendo el flujo implícito.
+
+/// note | Nota
+
+Es común que cada proveedor de autenticación nombre sus flujos de una manera diferente, para hacerlos parte de su marca.
+
+Pero al final, están implementando el mismo estándar OAuth2.
+
+///
+
+**FastAPI** incluye utilidades para todos estos flujos de autenticación OAuth2 en `fastapi.security.oauth2`.
+
+## `Security` en `dependencies` del decorador
+
+De la misma manera que puedes definir una `list` de `Depends` en el parámetro `dependencies` del decorador (como se explica en [Dependencias en decoradores de path operation](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}), también podrías usar `Security` con `scopes` allí.
diff --git a/docs/es/docs/advanced/settings.md b/docs/es/docs/advanced/settings.md
new file mode 100644
index 000000000..7e591cc01
--- /dev/null
+++ b/docs/es/docs/advanced/settings.md
@@ -0,0 +1,346 @@
+# Configuraciones y Variables de Entorno
+
+En muchos casos, tu aplicación podría necesitar algunas configuraciones o ajustes externos, por ejemplo, claves secretas, credenciales de base de datos, credenciales para servicios de correo electrónico, etc.
+
+La mayoría de estas configuraciones son variables (pueden cambiar), como las URLs de bases de datos. Y muchas podrían ser sensibles, como los secretos.
+
+Por esta razón, es común proporcionarlas en variables de entorno que son leídas por la aplicación.
+
+/// tip | Consejo
+
+Para entender las variables de entorno, puedes leer [Variables de Entorno](../environment-variables.md){.internal-link target=_blank}.
+
+///
+
+## Tipos y validación
+
+Estas variables de entorno solo pueden manejar strings de texto, ya que son externas a Python y tienen que ser compatibles con otros programas y el resto del sistema (e incluso con diferentes sistemas operativos, como Linux, Windows, macOS).
+
+Eso significa que cualquier valor leído en Python desde una variable de entorno será un `str`, y cualquier conversión a un tipo diferente o cualquier validación tiene que hacerse en código.
+
+## Pydantic `Settings`
+
+Afortunadamente, Pydantic proporciona una gran utilidad para manejar estas configuraciones provenientes de variables de entorno con Pydantic: Settings management.
+
+### Instalar `pydantic-settings`
+
+Primero, asegúrate de crear tu [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo y luego instala el paquete `pydantic-settings`:
+
+
+
+/// info | Información
+
+En Pydantic v1 venía incluido con el paquete principal. Ahora se distribuye como este paquete independiente para que puedas elegir si instalarlo o no si no necesitas esa funcionalidad.
+
+///
+
+### Crear el objeto `Settings`
+
+Importa `BaseSettings` de Pydantic y crea una sub-clase, muy similar a un modelo de Pydantic.
+
+De la misma forma que con los modelos de Pydantic, declaras atributos de clase con anotaciones de tipos, y posiblemente, valores por defecto.
+
+Puedes usar todas las mismas funcionalidades de validación y herramientas que usas para los modelos de Pydantic, como diferentes tipos de datos y validaciones adicionales con `Field()`.
+
+//// tab | Pydantic v2
+
+{* ../../docs_src/settings/tutorial001.py hl[2,5:8,11] *}
+
+////
+
+//// tab | Pydantic v1
+
+/// info | Información
+
+En Pydantic v1 importarías `BaseSettings` directamente desde `pydantic` en lugar de desde `pydantic_settings`.
+
+///
+
+{* ../../docs_src/settings/tutorial001_pv1.py hl[2,5:8,11] *}
+
+////
+
+/// tip | Consejo
+
+Si quieres algo rápido para copiar y pegar, no uses este ejemplo, usa el último más abajo.
+
+///
+
+Luego, cuando creas una instance de esa clase `Settings` (en este caso, en el objeto `settings`), Pydantic leerá las variables de entorno de una manera indiferente a mayúsculas y minúsculas, por lo que una variable en mayúsculas `APP_NAME` aún será leída para el atributo `app_name`.
+
+Luego convertirá y validará los datos. Así que, cuando uses ese objeto `settings`, tendrás datos de los tipos que declaraste (por ejemplo, `items_per_user` será un `int`).
+
+### Usar el `settings`
+
+Luego puedes usar el nuevo objeto `settings` en tu aplicación:
+
+{* ../../docs_src/settings/tutorial001.py hl[18:20] *}
+
+### Ejecutar el servidor
+
+Luego, ejecutarías el servidor pasando las configuraciones como variables de entorno, por ejemplo, podrías establecer un `ADMIN_EMAIL` y `APP_NAME` con:
+
+
+
+```console
+$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+/// tip | Consejo
+
+Para establecer múltiples variables de entorno para un solo comando, simplemente sepáralas con un espacio y ponlas todas antes del comando.
+
+///
+
+Y luego la configuración `admin_email` se establecería en `"deadpool@example.com"`.
+
+El `app_name` sería `"ChimichangApp"`.
+
+Y el `items_per_user` mantendría su valor por defecto de `50`.
+
+## Configuraciones en otro módulo
+
+Podrías poner esas configuraciones en otro archivo de módulo como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md){.internal-link target=_blank}.
+
+Por ejemplo, podrías tener un archivo `config.py` con:
+
+{* ../../docs_src/settings/app01/config.py *}
+
+Y luego usarlo en un archivo `main.py`:
+
+{* ../../docs_src/settings/app01/main.py hl[3,11:13] *}
+
+/// tip | Consejo
+
+También necesitarías un archivo `__init__.py` como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md){.internal-link target=_blank}.
+
+///
+
+## Configuraciones en una dependencia
+
+En algunas ocasiones podría ser útil proporcionar las configuraciones desde una dependencia, en lugar de tener un objeto global con `settings` que se use en todas partes.
+
+Esto podría ser especialmente útil durante las pruebas, ya que es muy fácil sobrescribir una dependencia con tus propias configuraciones personalizadas.
+
+### El archivo de configuración
+
+Proveniente del ejemplo anterior, tu archivo `config.py` podría verse como:
+
+{* ../../docs_src/settings/app02/config.py hl[10] *}
+
+Nota que ahora no creamos una instance por defecto `settings = Settings()`.
+
+### El archivo principal de la app
+
+Ahora creamos una dependencia que devuelve un nuevo `config.Settings()`.
+
+{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *}
+
+/// tip | Consejo
+
+Hablaremos del `@lru_cache` en un momento.
+
+Por ahora puedes asumir que `get_settings()` es una función normal.
+
+///
+
+Y luego podemos requerirlo desde la *path operation function* como una dependencia y usarlo donde lo necesitemos.
+
+{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *}
+
+### Configuraciones y pruebas
+
+Luego sería muy fácil proporcionar un objeto de configuraciones diferente durante las pruebas al sobrescribir una dependencia para `get_settings`:
+
+{* ../../docs_src/settings/app02/test_main.py hl[9:10,13,21] *}
+
+En la dependencia sobreescrita establecemos un nuevo valor para el `admin_email` al crear el nuevo objeto `Settings`, y luego devolvemos ese nuevo objeto.
+
+Luego podemos probar que se está usando.
+
+## Leer un archivo `.env`
+
+Si tienes muchas configuraciones que posiblemente cambien mucho, tal vez en diferentes entornos, podría ser útil ponerlos en un archivo y luego leerlos desde allí como si fueran variables de entorno.
+
+Esta práctica es lo suficientemente común que tiene un nombre, estas variables de entorno generalmente se colocan en un archivo `.env`, y el archivo se llama un "dotenv".
+
+/// tip | Consejo
+
+Un archivo que comienza con un punto (`.`) es un archivo oculto en sistemas tipo Unix, como Linux y macOS.
+
+Pero un archivo dotenv realmente no tiene que tener ese nombre exacto.
+
+///
+
+Pydantic tiene soporte para leer desde estos tipos de archivos usando un paquete externo. Puedes leer más en Pydantic Settings: Dotenv (.env) support.
+
+/// tip | Consejo
+
+Para que esto funcione, necesitas `pip install python-dotenv`.
+
+///
+
+### El archivo `.env`
+
+Podrías tener un archivo `.env` con:
+
+```bash
+ADMIN_EMAIL="deadpool@example.com"
+APP_NAME="ChimichangApp"
+```
+
+### Leer configuraciones desde `.env`
+
+Y luego actualizar tu `config.py` con:
+
+//// tab | Pydantic v2
+
+{* ../../docs_src/settings/app03_an/config.py hl[9] *}
+
+/// tip | Consejo
+
+El atributo `model_config` se usa solo para configuración de Pydantic. Puedes leer más en Pydantic: Concepts: Configuration.
+
+///
+
+////
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/settings/app03_an/config_pv1.py hl[9:10] *}
+
+/// tip | Consejo
+
+La clase `Config` se usa solo para configuración de Pydantic. Puedes leer más en Pydantic Model Config.
+
+///
+
+////
+
+/// info | Información
+
+En la versión 1 de Pydantic la configuración se hacía en una clase interna `Config`, en la versión 2 de Pydantic se hace en un atributo `model_config`. Este atributo toma un `dict`, y para obtener autocompletado y errores en línea, puedes importar y usar `SettingsConfigDict` para definir ese `dict`.
+
+///
+
+Aquí definimos la configuración `env_file` dentro de tu clase Pydantic `Settings`, y establecemos el valor en el nombre del archivo con el archivo dotenv que queremos usar.
+
+### Creando el `Settings` solo una vez con `lru_cache`
+
+Leer un archivo desde el disco es normalmente una operación costosa (lenta), por lo que probablemente quieras hacerlo solo una vez y luego reutilizar el mismo objeto de configuraciones, en lugar de leerlo para cada request.
+
+Pero cada vez que hacemos:
+
+```Python
+Settings()
+```
+
+se crearía un nuevo objeto `Settings`, y al crearse leería el archivo `.env` nuevamente.
+
+Si la función de dependencia fuera simplemente así:
+
+```Python
+def get_settings():
+ return Settings()
+```
+
+crearíamos ese objeto para cada request, y estaríamos leyendo el archivo `.env` para cada request. ⚠️
+
+Pero como estamos usando el decorador `@lru_cache` encima, el objeto `Settings` se creará solo una vez, la primera vez que se llame. ✔️
+
+{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
+
+Entonces, para cualquier llamada subsiguiente de `get_settings()` en las dependencias de los próximos requests, en lugar de ejecutar el código interno de `get_settings()` y crear un nuevo objeto `Settings`, devolverá el mismo objeto que fue devuelto en la primera llamada, una y otra vez.
+
+#### Detalles Técnicos de `lru_cache`
+
+`@lru_cache` modifica la función que decora para devolver el mismo valor que se devolvió la primera vez, en lugar de calcularlo nuevamente, ejecutando el código de la función cada vez.
+
+Así que la función debajo se ejecutará una vez por cada combinación de argumentos. Y luego, los valores devueltos por cada una de esas combinaciones de argumentos se utilizarán una y otra vez cada vez que la función sea llamada con exactamente la misma combinación de argumentos.
+
+Por ejemplo, si tienes una función:
+
+```Python
+@lru_cache
+def say_hi(name: str, salutation: str = "Ms."):
+ return f"Hello {salutation} {name}"
+```
+
+tu programa podría ejecutarse así:
+
+```mermaid
+sequenceDiagram
+
+participant code as Código
+participant function as say_hi()
+participant execute as Ejecutar función
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> execute: ejecutar código de la función
+ execute ->> code: devolver el resultado
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> code: devolver resultado almacenado
+ end
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Rick")
+ function ->> execute: ejecutar código de la función
+ execute ->> code: devolver el resultado
+ end
+
+ rect rgba(0, 255, 0, .1)
+ code ->> function: say_hi(name="Rick", salutation="Mr.")
+ function ->> execute: ejecutar código de la función
+ execute ->> code: devolver el resultado
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Rick")
+ function ->> code: devolver resultado almacenado
+ end
+
+ rect rgba(0, 255, 255, .1)
+ code ->> function: say_hi(name="Camila")
+ function ->> code: devolver resultado almacenado
+ end
+```
+
+En el caso de nuestra dependencia `get_settings()`, la función ni siquiera toma argumentos, por lo que siempre devolverá el mismo valor.
+
+De esa manera, se comporta casi como si fuera solo una variable global. Pero como usa una función de dependencia, entonces podemos sobrescribirla fácilmente para las pruebas.
+
+`@lru_cache` es parte de `functools`, que es parte del library estándar de Python, puedes leer más sobre él en las docs de Python para `@lru_cache`.
+
+## Resumen
+
+Puedes usar Pydantic Settings para manejar las configuraciones o ajustes de tu aplicación, con todo el poder de los modelos de Pydantic.
+
+* Al usar una dependencia, puedes simplificar las pruebas.
+* Puedes usar archivos `.env` con él.
+* Usar `@lru_cache` te permite evitar leer el archivo dotenv una y otra vez para cada request, mientras te permite sobrescribirlo durante las pruebas.
diff --git a/docs/es/docs/advanced/sub-applications.md b/docs/es/docs/advanced/sub-applications.md
new file mode 100644
index 000000000..ccb31f1ea
--- /dev/null
+++ b/docs/es/docs/advanced/sub-applications.md
@@ -0,0 +1,67 @@
+# Sub Aplicaciones - Mounts
+
+Si necesitas tener dos aplicaciones de **FastAPI** independientes, cada una con su propio OpenAPI independiente y su propia interfaz de docs, puedes tener una aplicación principal y "montar" una (o más) sub-aplicación(es).
+
+## Montar una aplicación **FastAPI**
+
+"Montar" significa añadir una aplicación completamente "independiente" en un path específico, que luego se encarga de manejar todo bajo ese path, con las _path operations_ declaradas en esa sub-aplicación.
+
+### Aplicación de nivel superior
+
+Primero, crea la aplicación principal de nivel superior de **FastAPI**, y sus *path operations*:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *}
+
+### Sub-aplicación
+
+Luego, crea tu sub-aplicación, y sus *path operations*.
+
+Esta sub-aplicación es solo otra aplicación estándar de FastAPI, pero es la que se "montará":
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *}
+
+### Montar la sub-aplicación
+
+En tu aplicación de nivel superior, `app`, monta la sub-aplicación, `subapi`.
+
+En este caso, se montará en el path `/subapi`:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *}
+
+### Revisa la documentación automática de la API
+
+Ahora, ejecuta el comando `fastapi` con tu archivo:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Y abre la documentación en http://127.0.0.1:8000/docs.
+
+Verás la documentación automática de la API para la aplicación principal, incluyendo solo sus propias _path operations_:
+
+
+
+Y luego, abre la documentación para la sub-aplicación, en http://127.0.0.1:8000/subapi/docs.
+
+Verás la documentación automática de la API para la sub-aplicación, incluyendo solo sus propias _path operations_, todas bajo el prefijo correcto del sub-path `/subapi`:
+
+
+
+Si intentas interactuar con cualquiera de las dos interfaces de usuario, funcionarán correctamente, porque el navegador podrá comunicarse con cada aplicación o sub-aplicación específica.
+
+### Detalles Técnicos: `root_path`
+
+Cuando montas una sub-aplicación como se describe arriba, FastAPI se encargará de comunicar el path de montaje para la sub-aplicación usando un mecanismo de la especificación ASGI llamado `root_path`.
+
+De esa manera, la sub-aplicación sabrá usar ese prefijo de path para la interfaz de documentación.
+
+Y la sub-aplicación también podría tener sus propias sub-aplicaciones montadas y todo funcionaría correctamente, porque FastAPI maneja todos estos `root_path`s automáticamente.
+
+Aprenderás más sobre el `root_path` y cómo usarlo explícitamente en la sección sobre [Detrás de un Proxy](behind-a-proxy.md){.internal-link target=_blank}.
diff --git a/docs/es/docs/advanced/templates.md b/docs/es/docs/advanced/templates.md
new file mode 100644
index 000000000..9de866c2b
--- /dev/null
+++ b/docs/es/docs/advanced/templates.md
@@ -0,0 +1,126 @@
+# Plantillas
+
+Puedes usar cualquier motor de plantillas que desees con **FastAPI**.
+
+Una elección común es Jinja2, el mismo que usa Flask y otras herramientas.
+
+Hay utilidades para configurarlo fácilmente que puedes usar directamente en tu aplicación de **FastAPI** (proporcionadas por Starlette).
+
+## Instalar dependencias
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo e instalar `jinja2`:
+
+
+
+## Usando `Jinja2Templates`
+
+* Importa `Jinja2Templates`.
+* Crea un objeto `templates` que puedas reutilizar más tarde.
+* Declara un parámetro `Request` en la *path operation* que devolverá una plantilla.
+* Usa los `templates` que creaste para renderizar y devolver un `TemplateResponse`, pasa el nombre de la plantilla, el objeto de request, y un diccionario "context" con pares clave-valor que se usarán dentro de la plantilla Jinja2.
+
+{* ../../docs_src/templates/tutorial001.py hl[4,11,15:18] *}
+
+/// note | Nota
+
+Antes de FastAPI 0.108.0, Starlette 0.29.0, el `name` era el primer parámetro.
+
+Además, antes de eso, en versiones anteriores, el objeto `request` se pasaba como parte de los pares clave-valor en el contexto para Jinja2.
+
+///
+
+/// tip | Consejo
+
+Al declarar `response_class=HTMLResponse`, la interfaz de usuario de la documentación podrá saber que el response será HTML.
+
+///
+
+/// note | Nota Técnica
+
+También podrías usar `from starlette.templating import Jinja2Templates`.
+
+**FastAPI** proporciona el mismo `starlette.templating` como `fastapi.templating`, solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette. Lo mismo con `Request` y `StaticFiles`.
+
+///
+
+## Escribiendo plantillas
+
+Luego puedes escribir una plantilla en `templates/item.html` con, por ejemplo:
+
+```jinja hl_lines="7"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+### Valores de Contexto de la Plantilla
+
+En el HTML que contiene:
+
+{% raw %}
+
+```jinja
+Item ID: {{ id }}
+```
+
+{% endraw %}
+
+...mostrará el `id` tomado del `dict` de "contexto" que pasaste:
+
+```Python
+{"id": id}
+```
+
+Por ejemplo, con un ID de `42`, esto se renderizaría como:
+
+```html
+Item ID: 42
+```
+
+### Argumentos de la Plantilla `url_for`
+
+También puedes usar `url_for()` dentro de la plantilla, toma como argumentos los mismos que usaría tu *path operation function*.
+
+Entonces, la sección con:
+
+{% raw %}
+
+```jinja
+
+```
+
+{% endraw %}
+
+...generará un enlace hacia la misma URL que manejaría la *path operation function* `read_item(id=id)`.
+
+Por ejemplo, con un ID de `42`, esto se renderizaría como:
+
+```html
+
+```
+
+## Plantillas y archivos estáticos
+
+También puedes usar `url_for()` dentro de la plantilla, y usarlo, por ejemplo, con los `StaticFiles` que montaste con el `name="static"`.
+
+```jinja hl_lines="4"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+En este ejemplo, enlazaría a un archivo CSS en `static/styles.css` con:
+
+```CSS hl_lines="4"
+{!../../docs_src/templates/static/styles.css!}
+```
+
+Y porque estás usando `StaticFiles`, ese archivo CSS sería servido automáticamente por tu aplicación de **FastAPI** en la URL `/static/styles.css`.
+
+## Más detalles
+
+Para más detalles, incluyendo cómo testear plantillas, revisa la documentación de Starlette sobre plantillas.
diff --git a/docs/es/docs/advanced/testing-dependencies.md b/docs/es/docs/advanced/testing-dependencies.md
new file mode 100644
index 000000000..14b90ea06
--- /dev/null
+++ b/docs/es/docs/advanced/testing-dependencies.md
@@ -0,0 +1,53 @@
+# Probando Dependencias con Overrides
+
+## Sobrescribir dependencias durante las pruebas
+
+Hay algunos escenarios donde podrías querer sobrescribir una dependencia durante las pruebas.
+
+No quieres que la dependencia original se ejecute (ni ninguna de las sub-dependencias que pueda tener).
+
+En cambio, quieres proporcionar una dependencia diferente que se usará solo durante las pruebas (posiblemente solo algunas pruebas específicas), y que proporcionará un valor que pueda ser usado donde se usó el valor de la dependencia original.
+
+### Casos de uso: servicio externo
+
+Un ejemplo podría ser que tienes un proveedor de autenticación externo al que necesitas llamar.
+
+Le envías un token y te devuelve un usuario autenticado.
+
+Este proveedor podría estar cobrándote por cada request, y llamarlo podría tomar más tiempo adicional que si tuvieras un usuario de prueba fijo para los tests.
+
+Probablemente quieras probar el proveedor externo una vez, pero no necesariamente llamarlo para cada test que se realice.
+
+En este caso, puedes sobrescribir la dependencia que llama a ese proveedor y usar una dependencia personalizada que devuelva un usuario de prueba, solo para tus tests.
+
+### Usa el atributo `app.dependency_overrides`
+
+Para estos casos, tu aplicación **FastAPI** tiene un atributo `app.dependency_overrides`, es un simple `dict`.
+
+Para sobrescribir una dependencia para las pruebas, colocas como clave la dependencia original (una función), y como valor, tu dependencia para sobreescribir (otra función).
+
+Y entonces **FastAPI** llamará a esa dependencia para sobreescribir en lugar de la dependencia original.
+
+{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}
+
+/// tip | Consejo
+
+Puedes sobreescribir una dependencia utilizada en cualquier lugar de tu aplicación **FastAPI**.
+
+La dependencia original podría ser utilizada en una *path operation function*, un *path operation decorator* (cuando no usas el valor de retorno), una llamada a `.include_router()`, etc.
+
+FastAPI todavía podrá sobrescribirla.
+
+///
+
+Entonces puedes restablecer las dependencias sobreescritas configurando `app.dependency_overrides` para que sea un `dict` vacío:
+
+```Python
+app.dependency_overrides = {}
+```
+
+/// tip | Consejo
+
+Si quieres sobrescribir una dependencia solo durante algunos tests, puedes establecer la sobrescritura al inicio del test (dentro de la función del test) y restablecerla al final (al final de la función del test).
+
+///
diff --git a/docs/es/docs/advanced/testing-events.md b/docs/es/docs/advanced/testing-events.md
new file mode 100644
index 000000000..9c2ec77b9
--- /dev/null
+++ b/docs/es/docs/advanced/testing-events.md
@@ -0,0 +1,5 @@
+# Testing Events: startup - shutdown
+
+Cuando necesitas que tus manejadores de eventos (`startup` y `shutdown`) se ejecuten en tus tests, puedes usar el `TestClient` con un statement `with`:
+
+{* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *}
diff --git a/docs/es/docs/advanced/testing-websockets.md b/docs/es/docs/advanced/testing-websockets.md
new file mode 100644
index 000000000..6d2eaf94d
--- /dev/null
+++ b/docs/es/docs/advanced/testing-websockets.md
@@ -0,0 +1,13 @@
+# Probando WebSockets
+
+Puedes usar el mismo `TestClient` para probar WebSockets.
+
+Para esto, usas el `TestClient` en un statement `with`, conectándote al WebSocket:
+
+{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *}
+
+/// note | Nota
+
+Para más detalles, revisa la documentación de Starlette sobre probando sesiones WebSocket.
+
+///
diff --git a/docs/es/docs/advanced/using-request-directly.md b/docs/es/docs/advanced/using-request-directly.md
new file mode 100644
index 000000000..be8afffcc
--- /dev/null
+++ b/docs/es/docs/advanced/using-request-directly.md
@@ -0,0 +1,56 @@
+# Usar el Request Directamente
+
+Hasta ahora, has estado declarando las partes del request que necesitas con sus tipos.
+
+Tomando datos de:
+
+* El path como parámetros.
+* Headers.
+* Cookies.
+* etc.
+
+Y al hacerlo, **FastAPI** está validando esos datos, convirtiéndolos y generando documentación para tu API automáticamente.
+
+Pero hay situaciones donde podrías necesitar acceder al objeto `Request` directamente.
+
+## Detalles sobre el objeto `Request`
+
+Como **FastAPI** es en realidad **Starlette** por debajo, con una capa de varias herramientas encima, puedes usar el objeto `Request` de Starlette directamente cuando lo necesites.
+
+También significa que si obtienes datos del objeto `Request` directamente (por ejemplo, leyendo el cuerpo) no serán validados, convertidos o documentados (con OpenAPI, para la interfaz automática de usuario de la API) por FastAPI.
+
+Aunque cualquier otro parámetro declarado normalmente (por ejemplo, el cuerpo con un modelo de Pydantic) seguiría siendo validado, convertido, anotado, etc.
+
+Pero hay casos específicos donde es útil obtener el objeto `Request`.
+
+## Usa el objeto `Request` directamente
+
+Imaginemos que quieres obtener la dirección IP/host del cliente dentro de tu *path operation function*.
+
+Para eso necesitas acceder al request directamente.
+
+{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *}
+
+Al declarar un parámetro de *path operation function* con el tipo siendo `Request`, **FastAPI** sabrá pasar el `Request` en ese parámetro.
+
+/// tip | Consejo
+
+Nota que en este caso, estamos declarando un parámetro de path además del parámetro del request.
+
+Así que, el parámetro de path será extraído, validado, convertido al tipo especificado y anotado con OpenAPI.
+
+De la misma manera, puedes declarar cualquier otro parámetro como normalmente, y adicionalmente, obtener también el `Request`.
+
+///
+
+## Documentación de `Request`
+
+Puedes leer más detalles sobre el objeto `Request` en el sitio de documentación oficial de Starlette.
+
+/// note | Detalles Técnicos
+
+Podrías también usar `from starlette.requests import Request`.
+
+**FastAPI** lo proporciona directamente solo como conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.
+
+///
diff --git a/docs/es/docs/advanced/websockets.md b/docs/es/docs/advanced/websockets.md
new file mode 100644
index 000000000..95141c1ca
--- /dev/null
+++ b/docs/es/docs/advanced/websockets.md
@@ -0,0 +1,186 @@
+# WebSockets
+
+Puedes usar WebSockets con **FastAPI**.
+
+## Instalar `WebSockets`
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo e instalar `websockets`:
+
+
+
+## Cliente WebSockets
+
+### En producción
+
+En tu sistema de producción, probablemente tengas un frontend creado con un framework moderno como React, Vue.js o Angular.
+
+Y para comunicarte usando WebSockets con tu backend probablemente usarías las utilidades de tu frontend.
+
+O podrías tener una aplicación móvil nativa que se comunica con tu backend de WebSocket directamente, en código nativo.
+
+O podrías tener alguna otra forma de comunicarte con el endpoint de WebSocket.
+
+---
+
+Pero para este ejemplo, usaremos un documento HTML muy simple con algo de JavaScript, todo dentro de un string largo.
+
+Esto, por supuesto, no es lo ideal y no lo usarías para producción.
+
+En producción tendrías una de las opciones anteriores.
+
+Pero es la forma más sencilla de enfocarse en el lado del servidor de WebSockets y tener un ejemplo funcional:
+
+{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
+
+## Crear un `websocket`
+
+En tu aplicación de **FastAPI**, crea un `websocket`:
+
+{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *}
+
+/// note | Detalles Técnicos
+
+También podrías usar `from starlette.websockets import WebSocket`.
+
+**FastAPI** proporciona el mismo `WebSocket` directamente solo como una conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.
+
+///
+
+## Esperar mensajes y enviar mensajes
+
+En tu ruta de WebSocket puedes `await` para recibir mensajes y enviar mensajes.
+
+{* ../../docs_src/websockets/tutorial001.py hl[48:52] *}
+
+Puedes recibir y enviar datos binarios, de texto y JSON.
+
+## Pruébalo
+
+Si tu archivo se llama `main.py`, ejecuta tu aplicación con:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Abre tu navegador en http://127.0.0.1:8000.
+
+Verás una página simple como:
+
+
+
+Puedes escribir mensajes en el cuadro de entrada y enviarlos:
+
+
+
+Y tu aplicación **FastAPI** con WebSockets responderá de vuelta:
+
+
+
+Puedes enviar (y recibir) muchos mensajes:
+
+
+
+Y todos usarán la misma conexión WebSocket.
+
+## Usando `Depends` y otros
+
+En endpoints de WebSocket puedes importar desde `fastapi` y usar:
+
+* `Depends`
+* `Security`
+* `Cookie`
+* `Header`
+* `Path`
+* `Query`
+
+Funcionan de la misma manera que para otros endpoints de FastAPI/*path operations*:
+
+{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
+
+/// info | Información
+
+Como esto es un WebSocket no tiene mucho sentido lanzar un `HTTPException`, en su lugar lanzamos un `WebSocketException`.
+
+Puedes usar un código de cierre de los códigos válidos definidos en la especificación.
+
+///
+
+### Prueba los WebSockets con dependencias
+
+Si tu archivo se llama `main.py`, ejecuta tu aplicación con:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Abre tu navegador en http://127.0.0.1:8000.
+
+Ahí puedes establecer:
+
+* El "ID del Ítem", usado en el path.
+* El "Token" usado como un parámetro query.
+
+/// tip | Consejo
+
+Nota que el query `token` será manejado por una dependencia.
+
+///
+
+Con eso puedes conectar el WebSocket y luego enviar y recibir mensajes:
+
+
+
+## Manejar desconexiones y múltiples clientes
+
+Cuando una conexión de WebSocket se cierra, el `await websocket.receive_text()` lanzará una excepción `WebSocketDisconnect`, que puedes capturar y manejar como en este ejemplo.
+
+{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
+
+Para probarlo:
+
+* Abre la aplicación con varias pestañas del navegador.
+* Escribe mensajes desde ellas.
+* Luego cierra una de las pestañas.
+
+Eso lanzará la excepción `WebSocketDisconnect`, y todos los otros clientes recibirán un mensaje como:
+
+```
+Client #1596980209979 left the chat
+```
+
+/// tip | Consejo
+
+La aplicación anterior es un ejemplo mínimo y simple para demostrar cómo manejar y transmitir mensajes a varias conexiones WebSocket.
+
+Pero ten en cuenta que, como todo se maneja en memoria, en una sola lista, solo funcionará mientras el proceso esté en ejecución, y solo funcionará con un solo proceso.
+
+Si necesitas algo fácil de integrar con FastAPI pero que sea más robusto, soportado por Redis, PostgreSQL u otros, revisa encode/broadcaster.
+
+///
+
+## Más información
+
+Para aprender más sobre las opciones, revisa la documentación de Starlette para:
+
+* La clase `WebSocket`.
+* Manejo de WebSocket basado en clases.
diff --git a/docs/es/docs/advanced/wsgi.md b/docs/es/docs/advanced/wsgi.md
new file mode 100644
index 000000000..7df62fc9a
--- /dev/null
+++ b/docs/es/docs/advanced/wsgi.md
@@ -0,0 +1,35 @@
+# Incluyendo WSGI - Flask, Django, otros
+
+Puedes montar aplicaciones WSGI como viste con [Sub Aplicaciones - Mounts](sub-applications.md){.internal-link target=_blank}, [Detrás de un Proxy](behind-a-proxy.md){.internal-link target=_blank}.
+
+Para eso, puedes usar `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.
+
+## Usando `WSGIMiddleware`
+
+Necesitas importar `WSGIMiddleware`.
+
+Luego envuelve la aplicación WSGI (p. ej., Flask) con el middleware.
+
+Y luego móntala bajo un path.
+
+{* ../../docs_src/wsgi/tutorial001.py hl[2:3,3] *}
+
+## Revisa
+
+Ahora, cada request bajo el path `/v1/` será manejado por la aplicación Flask.
+
+Y el resto será manejado por **FastAPI**.
+
+Si lo ejecutas y vas a http://localhost:8000/v1/ verás el response de Flask:
+
+```txt
+Hello, World from Flask!
+```
+
+Y si vas a http://localhost:8000/v2 verás el response de FastAPI:
+
+```JSON
+{
+ "message": "Hello World"
+}
+```
diff --git a/docs/es/docs/alternatives.md b/docs/es/docs/alternatives.md
new file mode 100644
index 000000000..753b827c0
--- /dev/null
+++ b/docs/es/docs/alternatives.md
@@ -0,0 +1,485 @@
+# Alternativas, Inspiración y Comparaciones
+
+Lo que inspiró a **FastAPI**, cómo se compara con las alternativas y lo que aprendió de ellas.
+
+## Introducción
+
+**FastAPI** no existiría si no fuera por el trabajo previo de otros.
+
+Se han creado muchas herramientas antes que han ayudado a inspirar su creación.
+
+He estado evitando la creación de un nuevo framework durante varios años. Primero intenté resolver todas las funcionalidades cubiertas por **FastAPI** usando muchos frameworks diferentes, plug-ins y herramientas.
+
+Pero en algún punto, no hubo otra opción que crear algo que proporcionara todas estas funcionalidades, tomando las mejores ideas de herramientas previas y combinándolas de la mejor manera posible, usando funcionalidades del lenguaje que ni siquiera estaban disponibles antes (anotaciones de tipos de Python 3.6+).
+
+## Herramientas previas
+
+### Django
+
+Es el framework más popular de Python y es ampliamente confiable. Se utiliza para construir sistemas como Instagram.
+
+Está relativamente acoplado con bases de datos relacionales (como MySQL o PostgreSQL), por lo que tener una base de datos NoSQL (como Couchbase, MongoDB, Cassandra, etc) como motor de almacenamiento principal no es muy fácil.
+
+Fue creado para generar el HTML en el backend, no para crear APIs utilizadas por un frontend moderno (como React, Vue.js y Angular) o por otros sistemas (como dispositivos del IoT) comunicándose con él.
+
+### Django REST Framework
+
+El framework Django REST fue creado para ser un kit de herramientas flexible para construir APIs Web utilizando Django, mejorando sus capacidades API.
+
+Es utilizado por muchas empresas, incluidas Mozilla, Red Hat y Eventbrite.
+
+Fue uno de los primeros ejemplos de **documentación automática de APIs**, y esto fue específicamente una de las primeras ideas que inspiraron "la búsqueda de" **FastAPI**.
+
+/// note | Nota
+
+Django REST Framework fue creado por Tom Christie. El mismo creador de Starlette y Uvicorn, en los cuales **FastAPI** está basado.
+
+///
+
+/// check | Inspiró a **FastAPI** a
+
+Tener una interfaz de usuario web de documentación automática de APIs.
+
+///
+
+### Flask
+
+Flask es un "microframework", no incluye integraciones de bases de datos ni muchas de las cosas que vienen por defecto en Django.
+
+Esta simplicidad y flexibilidad permiten hacer cosas como usar bases de datos NoSQL como el sistema de almacenamiento de datos principal.
+
+Como es muy simple, es relativamente intuitivo de aprender, aunque la documentación se vuelve algo técnica en algunos puntos.
+
+También se utiliza comúnmente para otras aplicaciones que no necesariamente necesitan una base de datos, gestión de usuarios, o cualquiera de las muchas funcionalidades que vienen preconstruidas en Django. Aunque muchas de estas funcionalidades se pueden añadir con plug-ins.
+
+Esta separación de partes, y ser un "microframework" que podría extenderse para cubrir exactamente lo que se necesita, fue una funcionalidad clave que quise mantener.
+
+Dada la simplicidad de Flask, parecía una buena opción para construir APIs. Lo siguiente a encontrar era un "Django REST Framework" para Flask.
+
+/// check | Inspiró a **FastAPI** a
+
+Ser un micro-framework. Haciendo fácil mezclar y combinar las herramientas y partes necesarias.
+
+Tener un sistema de routing simple y fácil de usar.
+
+///
+
+### Requests
+
+**FastAPI** no es en realidad una alternativa a **Requests**. Su ámbito es muy diferente.
+
+De hecho, sería común usar Requests *dentro* de una aplicación FastAPI.
+
+Aun así, FastAPI se inspiró bastante en Requests.
+
+**Requests** es un paquete para *interactuar* con APIs (como cliente), mientras que **FastAPI** es un paquete para *construir* APIs (como servidor).
+
+Están, más o menos, en extremos opuestos, complementándose entre sí.
+
+Requests tiene un diseño muy simple e intuitivo, es muy fácil de usar, con valores predeterminados sensatos. Pero al mismo tiempo, es muy poderoso y personalizable.
+
+Por eso, como se dice en el sitio web oficial:
+
+> Requests es uno de los paquetes Python más descargados de todos los tiempos
+
+La forma en que lo usas es muy sencilla. Por ejemplo, para hacer un `GET` request, escribirías:
+
+```Python
+response = requests.get("http://example.com/some/url")
+```
+
+La operación de path equivalente en FastAPI podría verse como:
+
+```Python hl_lines="1"
+@app.get("/some/url")
+def read_url():
+ return {"message": "Hello World"}
+```
+
+Mira las similitudes entre `requests.get(...)` y `@app.get(...)`.
+
+/// check | Inspiró a **FastAPI** a
+
+* Tener un API simple e intuitivo.
+* Usar nombres de métodos HTTP (operaciones) directamente, de una manera sencilla e intuitiva.
+* Tener valores predeterminados sensatos, pero personalizaciones poderosas.
+
+///
+
+### Swagger / OpenAPI
+
+La principal funcionalidad que quería de Django REST Framework era la documentación automática de la API.
+
+Luego descubrí que había un estándar para documentar APIs, usando JSON (o YAML, una extensión de JSON) llamado Swagger.
+
+Y ya existía una interfaz de usuario web para las APIs Swagger. Por lo tanto, ser capaz de generar documentación Swagger para una API permitiría usar esta interfaz de usuario web automáticamente.
+
+En algún punto, Swagger fue entregado a la Linux Foundation, para ser renombrado OpenAPI.
+
+Es por eso que cuando se habla de la versión 2.0 es común decir "Swagger", y para la versión 3+ "OpenAPI".
+
+/// check | Inspiró a **FastAPI** a
+
+Adoptar y usar un estándar abierto para especificaciones de API, en lugar de usar un esquema personalizado.
+
+Y a integrar herramientas de interfaz de usuario basadas en estándares:
+
+* Swagger UI
+* ReDoc
+
+Estas dos fueron elegidas por ser bastante populares y estables, pero haciendo una búsqueda rápida, podrías encontrar docenas de interfaces de usuario alternativas para OpenAPI (que puedes usar con **FastAPI**).
+
+///
+
+### Frameworks REST para Flask
+
+Existen varios frameworks REST para Flask, pero después de invertir tiempo y trabajo investigándolos, encontré que muchos son descontinuados o abandonados, con varios problemas existentes que los hacían inadecuados.
+
+### Marshmallow
+
+Una de las principales funcionalidades necesitadas por los sistemas API es la "serialización" de datos, que consiste en tomar datos del código (Python) y convertirlos en algo que pueda ser enviado a través de la red. Por ejemplo, convertir un objeto que contiene datos de una base de datos en un objeto JSON. Convertir objetos `datetime` en strings, etc.
+
+Otra gran funcionalidad necesaria por las APIs es la validación de datos, asegurarse de que los datos sean válidos, dados ciertos parámetros. Por ejemplo, que algún campo sea un `int`, y no algún string aleatorio. Esto es especialmente útil para los datos entrantes.
+
+Sin un sistema de validación de datos, tendrías que hacer todas las comprobaciones a mano, en código.
+
+Estas funcionalidades son para lo que fue creado Marshmallow. Es un gran paquete, y lo he usado mucho antes.
+
+Pero fue creado antes de que existieran las anotaciones de tipos en Python. Así que, para definir cada esquema necesitas usar utilidades y clases específicas proporcionadas por Marshmallow.
+
+/// check | Inspiró a **FastAPI** a
+
+Usar código para definir "esquemas" que proporcionen tipos de datos y validación automáticamente.
+
+///
+
+### Webargs
+
+Otra gran funcionalidad requerida por las APIs es el parse de datos de las requests entrantes.
+
+Webargs es una herramienta que fue creada para proporcionar esa funcionalidad sobre varios frameworks, incluido Flask.
+
+Usa Marshmallow por debajo para hacer la validación de datos. Y fue creada por los mismos desarrolladores.
+
+Es una gran herramienta y la he usado mucho también, antes de tener **FastAPI**.
+
+/// info | Información
+
+Webargs fue creada por los mismos desarrolladores de Marshmallow.
+
+///
+
+/// check | Inspiró a **FastAPI** a
+
+Tener validación automática de datos entrantes en una request.
+
+///
+
+### APISpec
+
+Marshmallow y Webargs proporcionan validación, parse y serialización como plug-ins.
+
+Pero la documentación todavía falta. Entonces APISpec fue creado.
+
+Es un plug-in para muchos frameworks (y hay un plug-in para Starlette también).
+
+La manera en que funciona es que escribes la definición del esquema usando el formato YAML dentro del docstring de cada función que maneja una ruta.
+
+Y genera esquemas OpenAPI.
+
+Así es como funciona en Flask, Starlette, Responder, etc.
+
+Pero luego, tenemos otra vez el problema de tener una micro-sintaxis, dentro de un string de Python (un gran YAML).
+
+El editor no puede ayudar mucho con eso. Y si modificamos parámetros o esquemas de Marshmallow y olvidamos también modificar ese docstring YAML, el esquema generado estaría obsoleto.
+
+/// info | Información
+
+APISpec fue creado por los mismos desarrolladores de Marshmallow.
+
+///
+
+/// check | Inspiró a **FastAPI** a
+
+Soportar el estándar abierto para APIs, OpenAPI.
+
+///
+
+### Flask-apispec
+
+Es un plug-in de Flask, que conecta juntos Webargs, Marshmallow y APISpec.
+
+Usa la información de Webargs y Marshmallow para generar automáticamente esquemas OpenAPI, usando APISpec.
+
+Es una gran herramienta, muy subestimada. Debería ser mucho más popular que muchos plug-ins de Flask por ahí. Puede que se deba a que su documentación es demasiado concisa y abstracta.
+
+Esto resolvió tener que escribir YAML (otra sintaxis) dentro de docstrings de Python.
+
+Esta combinación de Flask, Flask-apispec con Marshmallow y Webargs fue mi stack de backend favorito hasta construir **FastAPI**.
+
+Usarlo llevó a la creación de varios generadores de full-stack para Flask. Estos son los principales stacks que yo (y varios equipos externos) hemos estado usando hasta ahora:
+
+* https://github.com/tiangolo/full-stack
+* https://github.com/tiangolo/full-stack-flask-couchbase
+* https://github.com/tiangolo/full-stack-flask-couchdb
+
+Y estos mismos generadores de full-stack fueron la base de los [Generadores de Proyectos **FastAPI**](project-generation.md){.internal-link target=_blank}.
+
+/// info | Información
+
+Flask-apispec fue creado por los mismos desarrolladores de Marshmallow.
+
+///
+
+/// check | Inspiró a **FastAPI** a
+
+Generar el esquema OpenAPI automáticamente, desde el mismo código que define la serialización y validación.
+
+///
+
+### NestJS (y Angular)
+
+Esto ni siquiera es Python, NestJS es un framework de JavaScript (TypeScript) NodeJS inspirado por Angular.
+
+Logra algo algo similar a lo que se puede hacer con Flask-apispec.
+
+Tiene un sistema de inyección de dependencias integrado, inspirado por Angular 2. Requiere pre-registrar los "inyectables" (como todos los otros sistemas de inyección de dependencias que conozco), por lo que añade a la verbosidad y repetición de código.
+
+Como los parámetros se describen con tipos de TypeScript (similar a las anotaciones de tipos en Python), el soporte editorial es bastante bueno.
+
+Pero como los datos de TypeScript no se preservan después de la compilación a JavaScript, no puede depender de los tipos para definir validación, serialización y documentación al mismo tiempo. Debido a esto y algunas decisiones de diseño, para obtener validación, serialización y generación automática del esquema, es necesario agregar decoradores en muchos lugares. Por lo tanto, se vuelve bastante verboso.
+
+No puede manejar muy bien modelos anidados. Entonces, si el cuerpo JSON en la request es un objeto JSON que tiene campos internos que a su vez son objetos JSON anidados, no puede ser documentado y validado apropiadamente.
+
+/// check | Inspiró a **FastAPI** a
+
+Usar tipos de Python para tener un gran soporte del editor.
+
+Tener un poderoso sistema de inyección de dependencias. Encontrar una forma de minimizar la repetición de código.
+
+///
+
+### Sanic
+
+Fue uno de los primeros frameworks de Python extremadamente rápidos basados en `asyncio`. Fue hecho para ser muy similar a Flask.
+
+/// note | Detalles Técnicos
+
+Usó `uvloop` en lugar del loop `asyncio` por defecto de Python. Eso fue lo que lo hizo tan rápido.
+
+Claramente inspiró a Uvicorn y Starlette, que actualmente son más rápidos que Sanic en benchmarks abiertos.
+
+///
+
+/// check | Inspiró a **FastAPI** a
+
+Encontrar una manera de tener un rendimiento impresionante.
+
+Por eso **FastAPI** se basa en Starlette, ya que es el framework más rápido disponible (probado por benchmarks de terceros).
+
+///
+
+### Falcon
+
+Falcon es otro framework de Python de alto rendimiento, está diseñado para ser minimalista y funcionar como la base de otros frameworks como Hug.
+
+Está diseñado para tener funciones que reciben dos parámetros, un "request" y un "response". Luego "lees" partes del request y "escribes" partes en el response. Debido a este diseño, no es posible declarar parámetros de request y cuerpos con las anotaciones de tipos estándar de Python como parámetros de función.
+
+Por lo tanto, la validación de datos, la serialización y la documentación, tienen que hacerse en código, no automáticamente. O tienen que implementarse como un framework sobre Falcon, como Hug. Esta misma distinción ocurre en otros frameworks que se inspiran en el diseño de Falcon, de tener un objeto request y un objeto response como parámetros.
+
+/// check | Inspiró a **FastAPI** a
+
+Buscar maneras de obtener un gran rendimiento.
+
+Junto con Hug (ya que Hug se basa en Falcon), inspiraron a **FastAPI** a declarar un parámetro `response` en las funciones.
+
+Aunque en FastAPI es opcional, y se utiliza principalmente para configurar headers, cookies y códigos de estado alternativos.
+
+///
+
+### Molten
+
+Descubrí Molten en las primeras etapas de construcción de **FastAPI**. Y tiene ideas bastante similares:
+
+* Basado en las anotaciones de tipos de Python.
+* Validación y documentación a partir de estos tipos.
+* Sistema de Inyección de Dependencias.
+
+No utiliza un paquete de validación de datos, serialización y documentación de terceros como Pydantic, tiene el suyo propio. Por lo tanto, estas definiciones de tipos de datos no serían reutilizables tan fácilmente.
+
+Requiere configuraciones un poquito más verbosas. Y dado que se basa en WSGI (en lugar de ASGI), no está diseñado para aprovechar el alto rendimiento proporcionado por herramientas como Uvicorn, Starlette y Sanic.
+
+El sistema de inyección de dependencias requiere pre-registrar las dependencias y las dependencias se resuelven en base a los tipos declarados. Por lo tanto, no es posible declarar más de un "componente" que proporcione cierto tipo.
+
+Las rutas se declaran en un solo lugar, usando funciones declaradas en otros lugares (en lugar de usar decoradores que pueden colocarse justo encima de la función que maneja el endpoint). Esto se acerca más a cómo lo hace Django que a cómo lo hace Flask (y Starlette). Separa en el código cosas que están relativamente acopladas.
+
+/// check | Inspiró a **FastAPI** a
+
+Definir validaciones extra para tipos de datos usando el valor "default" de los atributos del modelo. Esto mejora el soporte del editor y no estaba disponible en Pydantic antes.
+
+Esto en realidad inspiró la actualización de partes de Pydantic, para soportar el mismo estilo de declaración de validación (toda esta funcionalidad ya está disponible en Pydantic).
+
+///
+
+### Hug
+
+Hug fue uno de los primeros frameworks en implementar la declaración de tipos de parámetros API usando las anotaciones de tipos de Python. Esta fue una gran idea que inspiró a otras herramientas a hacer lo mismo.
+
+Usaba tipos personalizados en sus declaraciones en lugar de tipos estándar de Python, pero aún así fue un gran avance.
+
+También fue uno de los primeros frameworks en generar un esquema personalizado declarando toda la API en JSON.
+
+No se basaba en un estándar como OpenAPI y JSON Schema. Por lo que no sería sencillo integrarlo con otras herramientas, como Swagger UI. Pero, nuevamente, fue una idea muy innovadora.
+
+Tiene una funcionalidad interesante e inusual: usando el mismo framework, es posible crear APIs y también CLIs.
+
+Dado que se basa en el estándar previo para frameworks web Python sincrónicos (WSGI), no puede manejar Websockets y otras cosas, aunque aún así tiene un alto rendimiento también.
+
+/// info | Información
+
+Hug fue creado por Timothy Crosley, el mismo creador de `isort`, una gran herramienta para ordenar automáticamente imports en archivos Python.
+
+///
+
+/// check | Ideas que inspiraron a **FastAPI**
+
+Hug inspiró partes de APIStar, y fue una de las herramientas que encontré más prometedoras, junto a APIStar.
+
+Hug ayudó a inspirar a **FastAPI** a usar anotaciones de tipos de Python para declarar parámetros, y a generar un esquema definiendo la API automáticamente.
+
+Hug inspiró a **FastAPI** a declarar un parámetro `response` en funciones para configurar headers y cookies.
+
+///
+
+### APIStar (<= 0.5)
+
+Justo antes de decidir construir **FastAPI** encontré **APIStar** server. Tenía casi todo lo que estaba buscando y tenía un gran diseño.
+
+Era una de las primeras implementaciones de un framework utilizando las anotaciones de tipos de Python para declarar parámetros y requests que jamás vi (antes de NestJS y Molten). Lo encontré más o menos al mismo tiempo que Hug. Pero APIStar usaba el estándar OpenAPI.
+
+Tenía validación de datos automática, serialización de datos y generación del esquema OpenAPI basada en las mismas anotaciones de tipos en varios lugares.
+
+Las definiciones de esquema de cuerpo no usaban las mismas anotaciones de tipos de Python como Pydantic, era un poco más similar a Marshmallow, por lo que el soporte del editor no sería tan bueno, pero aún así, APIStar era la mejor opción disponible.
+
+Tenía los mejores benchmarks de rendimiento en ese momento (solo superado por Starlette).
+
+Al principio, no tenía una interfaz de usuario web de documentación de API automática, pero sabía que podía agregar Swagger UI a él.
+
+Tenía un sistema de inyección de dependencias. Requería pre-registrar componentes, como otras herramientas discutidas anteriormente. Pero aún así, era una gran funcionalidad.
+
+Nunca pude usarlo en un proyecto completo, ya que no tenía integración de seguridad, por lo que no podía reemplazar todas las funcionalidades que tenía con los generadores de full-stack basados en Flask-apispec. Tenía en mi lista de tareas pendientes de proyectos crear un pull request agregando esa funcionalidad.
+
+Pero luego, el enfoque del proyecto cambió.
+
+Ya no era un framework web API, ya que el creador necesitaba enfocarse en Starlette.
+
+Ahora APIStar es un conjunto de herramientas para validar especificaciones OpenAPI, no un framework web.
+
+/// info | Información
+
+APIStar fue creado por Tom Christie. El mismo que creó:
+
+* Django REST Framework
+* Starlette (en la cual **FastAPI** está basado)
+* Uvicorn (usado por Starlette y **FastAPI**)
+
+///
+
+/// check | Inspiró a **FastAPI** a
+
+Existir.
+
+La idea de declarar múltiples cosas (validación de datos, serialización y documentación) con los mismos tipos de Python, que al mismo tiempo proporcionaban un gran soporte del editor, era algo que consideré una idea brillante.
+
+Y después de buscar durante mucho tiempo un framework similar y probar muchas alternativas diferentes, APIStar fue la mejor opción disponible.
+
+Luego APIStar dejó de existir como servidor y Starlette fue creado, y fue una nueva y mejor base para tal sistema. Esa fue la inspiración final para construir **FastAPI**.
+
+Considero a **FastAPI** un "sucesor espiritual" de APIStar, mientras mejora y aumenta las funcionalidades, el sistema de tipos y otras partes, basándose en los aprendizajes de todas estas herramientas previas.
+
+///
+
+## Usado por **FastAPI**
+
+### Pydantic
+
+Pydantic es un paquete para definir validación de datos, serialización y documentación (usando JSON Schema) basándose en las anotaciones de tipos de Python.
+
+Eso lo hace extremadamente intuitivo.
+
+Es comparable a Marshmallow. Aunque es más rápido que Marshmallow en benchmarks. Y como está basado en las mismas anotaciones de tipos de Python, el soporte del editor es estupendo.
+
+/// check | **FastAPI** lo usa para
+
+Manejar toda la validación de datos, serialización de datos y documentación automática de modelos (basada en JSON Schema).
+
+**FastAPI** luego toma esos datos JSON Schema y los coloca en OpenAPI, aparte de todas las otras cosas que hace.
+
+///
+
+### Starlette
+
+Starlette es un framework/toolkit ASGI liviano, ideal para construir servicios asyncio de alto rendimiento.
+
+Es muy simple e intuitivo. Está diseñado para ser fácilmente extensible y tener componentes modulares.
+
+Tiene:
+
+* Un rendimiento seriamente impresionante.
+* Soporte para WebSocket.
+* Tareas en segundo plano dentro del proceso.
+* Eventos de inicio y apagado.
+* Cliente de pruebas basado en HTTPX.
+* CORS, GZip, Archivos estáticos, Responses en streaming.
+* Soporte para sesiones y cookies.
+* Cobertura de tests del 100%.
+* Base de código 100% tipada.
+* Pocas dependencias obligatorias.
+
+Starlette es actualmente el framework de Python más rápido probado. Solo superado por Uvicorn, que no es un framework, sino un servidor.
+
+Starlette proporciona toda la funcionalidad básica de un microframework web.
+
+Pero no proporciona validación de datos automática, serialización o documentación.
+
+Esa es una de las principales cosas que **FastAPI** agrega, todo basado en las anotaciones de tipos de Python (usando Pydantic). Eso, además del sistema de inyección de dependencias, utilidades de seguridad, generación de esquemas OpenAPI, etc.
+
+/// note | Detalles Técnicos
+
+ASGI es un nuevo "estándar" que está siendo desarrollado por miembros del equipo central de Django. Todavía no es un "estándar de Python" (un PEP), aunque están en proceso de hacerlo.
+
+No obstante, ya está siendo usado como un "estándar" por varias herramientas. Esto mejora enormemente la interoperabilidad, ya que podrías cambiar Uvicorn por cualquier otro servidor ASGI (como Daphne o Hypercorn), o podrías añadir herramientas compatibles con ASGI, como `python-socketio`.
+
+///
+
+/// check | **FastAPI** lo usa para
+
+Manejar todas las partes web centrales. Añadiendo funcionalidades encima.
+
+La clase `FastAPI` en sí misma hereda directamente de la clase `Starlette`.
+
+Por lo tanto, cualquier cosa que puedas hacer con Starlette, puedes hacerlo directamente con **FastAPI**, ya que es básicamente Starlette potenciado.
+
+///
+
+### Uvicorn
+
+Uvicorn es un servidor ASGI extremadamente rápido, construido sobre uvloop y httptools.
+
+No es un framework web, sino un servidor. Por ejemplo, no proporciona herramientas para el enrutamiento por paths. Eso es algo que un framework como Starlette (o **FastAPI**) proporcionaría encima.
+
+Es el servidor recomendado para Starlette y **FastAPI**.
+
+/// check | **FastAPI** lo recomienda como
+
+El servidor web principal para ejecutar aplicaciones **FastAPI**.
+
+También puedes usar la opción de línea de comandos `--workers` para tener un servidor multiproceso asíncrono.
+
+Revisa más detalles en la sección [Despliegue](deployment/index.md){.internal-link target=_blank}.
+
+///
+
+## Benchmarks y velocidad
+
+Para entender, comparar, y ver la diferencia entre Uvicorn, Starlette y FastAPI, revisa la sección sobre [Benchmarks](benchmarks.md){.internal-link target=_blank}.
diff --git a/docs/es/docs/async.md b/docs/es/docs/async.md
index 5ab2ff9a4..e3fd077c4 100644
--- a/docs/es/docs/async.md
+++ b/docs/es/docs/async.md
@@ -1,18 +1,18 @@
# Concurrencia y async / await
-Detalles sobre la sintaxis `async def` para *path operation functions* y un poco de información sobre código asíncrono, concurrencia y paralelismo.
+Detalles sobre la sintaxis `async def` para *path operation functions* y algunos antecedentes sobre el código asíncrono, la concurrencia y el paralelismo.
-## ¿Tienes prisa?
+## ¿Con prisa?
TL;DR:
-Si estás utilizando libraries de terceros que te dicen que las llames con `await`, del tipo:
+Si estás usando paquetes de terceros que te dicen que los llames con `await`, como:
```Python
results = await some_library()
```
-Entonces declara tus *path operation functions* con `async def` de la siguiente manera:
+Entonces, declara tus *path operation functions* con `async def` así:
```Python hl_lines="2"
@app.get('/')
@@ -29,7 +29,7 @@ Solo puedes usar `await` dentro de funciones creadas con `async def`.
---
-Si estás utilizando libraries de terceros que se comunican con algo (una base de datos, una API, el sistema de archivos, etc.) y no tienes soporte para `await` (este es el caso para la mayoría de las libraries de bases de datos), declara tus *path operation functions* de forma habitual, con solo `def`, de la siguiente manera:
+Si estás usando un paquete de terceros que se comunica con algo (una base de datos, una API, el sistema de archivos, etc.) y no tiene soporte para usar `await` (este es actualmente el caso para la mayoría de los paquetes de base de datos), entonces declara tus *path operation functions* como normalmente, usando simplemente `def`, así:
```Python hl_lines="2"
@app.get('/')
@@ -40,7 +40,7 @@ def results():
---
-Si tu aplicación (de alguna manera) no tiene que comunicarse con nada más y en consecuencia esperar a que responda, usa `async def`.
+Si tu aplicación (de alguna manera) no tiene que comunicarse con nada más y esperar a que responda, usa `async def`.
---
@@ -48,17 +48,17 @@ Si simplemente no lo sabes, usa `def` normal.
---
-**Nota**: puedes mezclar `def` y `async def` en tus *path operation functions* tanto como lo necesites y definir cada una utilizando la mejor opción para ti. FastAPI hará lo correcto con ellos.
+**Nota**: Puedes mezclar `def` y `async def` en tus *path operation functions* tanto como necesites y definir cada una utilizando la mejor opción para ti. FastAPI hará lo correcto con ellas.
De todos modos, en cualquiera de los casos anteriores, FastAPI seguirá funcionando de forma asíncrona y será extremadamente rápido.
-Pero siguiendo los pasos anteriores, FastAPI podrá hacer algunas optimizaciones de rendimiento.
+Pero al seguir los pasos anteriores, podrá hacer algunas optimizaciones de rendimiento.
## Detalles Técnicos
-Las versiones modernas de Python tienen soporte para **"código asíncrono"** usando algo llamado **"coroutines"**, usando la sintaxis **`async` y `await`**.
+Las versiones modernas de Python tienen soporte para **"código asíncrono"** utilizando algo llamado **"coroutines"**, con la sintaxis **`async` y `await`**.
-Veamos esa frase por partes en las secciones siguientes:
+Veamos esa frase por partes en las secciones a continuación:
* **Código Asíncrono**
* **`async` y `await`**
@@ -66,203 +66,200 @@ Veamos esa frase por partes en las secciones siguientes:
## Código Asíncrono
-El código asíncrono sólo significa que el lenguaje 💬 tiene una manera de decirle al sistema / programa 🤖 que, en algún momento del código, 🤖 tendrá que esperar a que *algo más* termine en otro sitio. Digamos que ese *algo más* se llama, por ejemplo, "archivo lento" 📝.
+El código asíncrono simplemente significa que el lenguaje 💬 tiene una forma de decirle a la computadora / programa 🤖 que en algún momento del código, tendrá que esperar que *otra cosa* termine en otro lugar. Digamos que esa *otra cosa* se llama "archivo-lento" 📝.
-Durante ese tiempo, el sistema puede hacer otras cosas, mientras "archivo lento" 📝 termina.
+Entonces, durante ese tiempo, la computadora puede ir y hacer algún otro trabajo, mientras "archivo-lento" 📝 termina.
-Entonces el sistema / programa 🤖 volverá cada vez que pueda, sea porque está esperando otra vez, porque 🤖 ha terminado todo el trabajo que tenía en ese momento. Y 🤖 verá si alguna de las tareas por las que estaba esperando ha terminado, haciendo lo que tenía que hacer.
+Luego la computadora / programa 🤖 volverá cada vez que tenga una oportunidad porque está esperando nuevamente, o siempre que 🤖 haya terminado todo el trabajo que tenía en ese punto. Y 🤖 comprobará si alguna de las tareas que estaba esperando ya se han completado, haciendo lo que tenía que hacer.
-Luego, 🤖 cogerá la primera tarea finalizada (digamos, nuestro "archivo lento" 📝) y continuará con lo que tenía que hacer con esa tarea.
+Después, 🤖 toma la primera tarea que termine (digamos, nuestro "archivo-lento" 📝) y continúa con lo que tenía que hacer con ella.
-Esa "espera de otra cosa" normalmente se refiere a operaciones I/O que son relativamente "lentas" (en relación a la velocidad del procesador y memoria RAM), como por ejemplo esperar por:
+Ese "esperar otra cosa" normalmente se refiere a las operaciones de I/O que son relativamente "lentas" (comparadas con la velocidad del procesador y la memoria RAM), como esperar:
-* los datos de cliente que se envían a través de la red
-* los datos enviados por tu programa para ser recibidos por el cliente a través de la red
-* el contenido de un archivo en disco para ser leído por el sistema y entregado al programa
-* los contenidos que tu programa da al sistema para ser escritos en disco
-* una operación relacionada con una API remota
-* una operación de base de datos
-* el retorno de resultados de una consulta de base de datos
+* que los datos del cliente se envíen a través de la red
+* que los datos enviados por tu programa sean recibidos por el cliente a través de la red
+* que el contenido de un archivo en el disco sea leído por el sistema y entregado a tu programa
+* que el contenido que tu programa entregó al sistema sea escrito en el disco
+* una operación de API remota
+* que una operación de base de datos termine
+* que una query de base de datos devuelva los resultados
* etc.
-Como el tiempo de ejecución se consume principalmente al esperar a operaciones de I/O, las llaman operaciones "I/O bound".
+Como el tiempo de ejecución se consume principalmente esperando operaciones de I/O, las llaman operaciones "I/O bound".
-Se llama "asíncrono" porque el sistema / programa no tiene que estar "sincronizado" con la tarea lenta, esperando el momento exacto en que finaliza la tarea, sin hacer nada, para poder recoger el resultado de la tarea y continuar el trabajo.
+Se llama "asíncrono" porque la computadora / programa no tiene que estar "sincronizado" con la tarea lenta, esperando el momento exacto en que la tarea termine, sin hacer nada, para poder tomar el resultado de la tarea y continuar el trabajo.
-En lugar de eso, al ser un sistema "asíncrono", una vez finalizada, la tarea puede esperar un poco en la cola (algunos microsegundos) para que la computadora / programa termine lo que estaba haciendo, y luego vuelva para recoger los resultados y seguir trabajando con ellos.
+En lugar de eso, al ser un sistema "asíncrono", una vez terminado, la tarea puede esperar un poco en la cola (algunos microsegundos) para que la computadora / programa termine lo que salió a hacer, y luego regrese para tomar los resultados y continuar trabajando con ellos.
-Por "síncrono" (contrario a "asíncrono") también se usa habitualmente el término "secuencial", porque el sistema / programa sigue todos los pasos secuencialmente antes de cambiar a una tarea diferente, incluso si esos pasos implican esperas.
+Para el "sincrónico" (contrario al "asíncrono") comúnmente también usan el término "secuencial", porque la computadora / programa sigue todos los pasos en secuencia antes de cambiar a una tarea diferente, incluso si esos pasos implican esperar.
### Concurrencia y Hamburguesas
-El concepto de código **asíncrono** descrito anteriormente a veces también se llama **"concurrencia"**. Es diferente del **"paralelismo"**.
+Esta idea de código **asíncrono** descrita anteriormente a veces también se llama **"concurrencia"**. Es diferente del **"paralelismo"**.
-**Concurrencia** y **paralelismo** ambos se relacionan con "cosas diferentes que suceden más o menos al mismo tiempo".
+**Concurrencia** y **paralelismo** ambos se relacionan con "diferentes cosas sucediendo más o menos al mismo tiempo".
Pero los detalles entre *concurrencia* y *paralelismo* son bastante diferentes.
-Para entender las diferencias, imagina la siguiente historia sobre hamburguesas:
+Para ver la diferencia, imagina la siguiente historia sobre hamburguesas:
### Hamburguesas Concurrentes
-Vas con la persona que te gusta 😍 a pedir comida rápida 🍔, haces cola mientras el cajero 💁 recoge los pedidos de las personas de delante tuyo.
+Vas con tu crush a conseguir comida rápida, te pones en fila mientras el cajero toma los pedidos de las personas frente a ti. 😍
-
+
-Llega tu turno, haces tu pedido de 2 hamburguesas impresionantes para esa persona 😍 y para ti.
+Luego es tu turno, haces tu pedido de 2 hamburguesas muy sofisticadas para tu crush y para ti. 🍔🍔
-
+
-El cajero 💁 le dice algo al chico de la cocina 👨🍳 para que sepa que tiene que preparar tus hamburguesas 🍔 (a pesar de que actualmente está preparando las de los clientes anteriores).
+El cajero dice algo al cocinero en la cocina para que sepan que tienen que preparar tus hamburguesas (aunque actualmente están preparando las de los clientes anteriores).
-
+
-Pagas 💸.
-El cajero 💁 te da el número de tu turno.
+Pagas. 💸
+
+El cajero te da el número de tu turno.
-
+
-Mientras esperas, vas con esa persona 😍 y eliges una mesa, se sientan y hablan durante un rato largo (ya que las hamburguesas son muy impresionantes y necesitan un rato para prepararse ✨🍔✨).
+Mientras esperas, vas con tu crush y eliges una mesa, te sientas y hablas con tu crush por un largo rato (ya que tus hamburguesas son muy sofisticadas y toman un tiempo en prepararse).
-Mientras te sientas en la mesa con esa persona 😍, esperando las hamburguesas 🍔, puedes disfrutar ese tiempo admirando lo increíble, inteligente, y bien que se ve ✨😍✨.
+Mientras estás sentado en la mesa con tu crush, mientras esperas las hamburguesas, puedes pasar ese tiempo admirando lo increíble, lindo e inteligente que es tu crush ✨😍✨.
-
+
-Mientras esperas y hablas con esa persona 😍, de vez en cuando, verificas el número del mostrador para ver si ya es tu turno.
+Mientras esperas y hablas con tu crush, de vez en cuando revisas el número mostrado en el mostrador para ver si ya es tu turno.
-Al final, en algún momento, llega tu turno. Vas al mostrador, coges tus hamburguesas 🍔 y vuelves a la mesa.
+Luego, en algún momento, finalmente es tu turno. Vas al mostrador, obtienes tus hamburguesas y vuelves a la mesa.
-
+
-Tú y esa persona 😍 se comen las hamburguesas 🍔 y la pasan genial ✨.
+Tú y tu crush comen las hamburguesas y pasan un buen rato. ✨
-
+
/// info | Información
-Las ilustraciones fueron creados por Ketrina Thompson. 🎨
+Hermosas ilustraciones de Ketrina Thompson. 🎨
///
---
-Imagina que eres el sistema / programa 🤖 en esa historia.
+Imagina que eres la computadora / programa 🤖 en esa historia.
-Mientras estás en la cola, estás quieto 😴, esperando tu turno, sin hacer nada muy "productivo". Pero la línea va rápida porque el cajero 💁 solo recibe los pedidos (no los prepara), así que está bien.
+Mientras estás en la fila, estás inactivo 😴, esperando tu turno, sin hacer nada muy "productivo". Pero la fila es rápida porque el cajero solo está tomando los pedidos (no preparándolos), así que está bien.
-Luego, cuando llega tu turno, haces un trabajo "productivo" real 🤓, procesas el menú, decides lo que quieres, lo que quiere esa persona 😍, pagas 💸, verificas que das el billete o tarjeta correctos, verificas que te cobren correctamente, que el pedido tiene los artículos correctos, etc.
+Luego, cuando es tu turno, haces un trabajo realmente "productivo", procesas el menú, decides lo que quieres, obtienes la elección de tu crush, pagas, verificas que das el billete o tarjeta correctos, verificas que te cobren correctamente, verificas que el pedido tenga los artículos correctos, etc.
-Pero entonces, aunque aún no tienes tus hamburguesas 🍔, el trabajo hecho con el cajero 💁 está "en pausa" ⏸, porque debes esperar 🕙 a que tus hamburguesas estén listas.
+Pero luego, aunque todavía no tienes tus hamburguesas, tu trabajo con el cajero está "en pausa" ⏸, porque tienes que esperar 🕙 a que tus hamburguesas estén listas.
-Pero como te alejas del mostrador y te sientas en la mesa con un número para tu turno, puedes cambiar tu atención 🔀 a esa persona 😍 y "trabajar" ⏯ 🤓 en eso. Entonces nuevamente estás haciendo algo muy "productivo" 🤓, como coquetear con esa persona 😍.
+Pero como te alejas del mostrador y te sientas en la mesa con un número para tu turno, puedes cambiar 🔀 tu atención a tu crush, y "trabajar" ⏯ 🤓 en eso. Luego, nuevamente estás haciendo algo muy "productivo" como es coquetear con tu crush 😍.
-Después, el 💁 cajero dice "he terminado de hacer las hamburguesas" 🍔 poniendo tu número en la pantalla del mostrador, pero no saltas al momento que el número que se muestra es el tuyo. Sabes que nadie robará tus hamburguesas 🍔 porque tienes el número de tu turno y ellos tienen el suyo.
+Luego el cajero 💁 dice "he terminado de hacer las hamburguesas" al poner tu número en el mostrador, pero no saltas como loco inmediatamente cuando el número mostrado cambia a tu número de turno. Sabes que nadie robará tus hamburguesas porque tienes el número de tu turno, y ellos tienen el suyo.
-Así que esperas a que esa persona 😍 termine la historia (terminas el trabajo actual ⏯ / tarea actual que se está procesando 🤓), sonríes gentilmente y le dices que vas por las hamburguesas ⏸.
+Así que esperas a que tu crush termine la historia (termine el trabajo ⏯ / tarea actual que se está procesando 🤓), sonríes amablemente y dices que vas por las hamburguesas ⏸.
-Luego vas al mostrador 🔀, a la tarea inicial que ya está terminada ⏯, recoges las hamburguesas 🍔, les dices gracias y las llevas a la mesa. Eso termina esa fase / tarea de interacción con el mostrador ⏹. Eso a su vez, crea una nueva tarea, "comer hamburguesas" 🔀 ⏯, pero la anterior de "conseguir hamburguesas" está terminada ⏹.
+Luego vas al mostrador 🔀, a la tarea inicial que ahora está terminada ⏯, recoges las hamburguesas, das las gracias y las llevas a la mesa. Eso termina ese paso / tarea de interacción con el mostrador ⏹. Eso a su vez, crea una nueva tarea, de "comer hamburguesas" 🔀 ⏯, pero la anterior de "obtener hamburguesas" ha terminado ⏹.
### Hamburguesas Paralelas
-Ahora imagina que estas no son "Hamburguesas Concurrentes" sino "Hamburguesas Paralelas".
+Ahora imaginemos que estas no son "Hamburguesas Concurrentes", sino "Hamburguesas Paralelas".
-Vas con la persona que te gusta 😍 por comida rápida paralela 🍔.
+Vas con tu crush a obtener comida rápida paralela.
-Haces la cola mientras varios cajeros (digamos 8) que a la vez son cocineros 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳 toman los pedidos de las personas que están delante de ti.
+Te pones en fila mientras varios (digamos 8) cajeros que al mismo tiempo son cocineros toman los pedidos de las personas frente a ti.
-Todos los que están antes de ti están esperando 🕙 que sus hamburguesas 🍔 estén listas antes de dejar el mostrador porque cada uno de los 8 cajeros prepara la hamburguesa de inmediato antes de recibir el siguiente pedido.
+Todos antes que tú están esperando a que sus hamburguesas estén listas antes de dejar el mostrador porque cada uno de los 8 cajeros va y prepara la hamburguesa de inmediato antes de obtener el siguiente pedido.
-
+
-Entonces finalmente es tu turno, haces tu pedido de 2 hamburguesas 🍔 impresionantes para esa persona 😍 y para ti.
+Luego, finalmente es tu turno, haces tu pedido de 2 hamburguesas muy sofisticadas para tu crush y para ti.
Pagas 💸.
-
+
-El cajero va a la cocina 👨🍳.
+El cajero va a la cocina.
-Esperas, de pie frente al mostrador 🕙, para que nadie más recoja tus hamburguesas 🍔, ya que no hay números para los turnos.
+Esperas, de pie frente al mostrador 🕙, para que nadie más tome tus hamburguesas antes que tú, ya que no hay números para los turnos.
-
+
-Como tu y esa persona 😍 están ocupados en impedir que alguien se ponga delante y recoja tus hamburguesas apenas llegan 🕙, tampoco puedes prestarle atención a esa persona 😞.
+Como tú y tu crush están ocupados no dejando que nadie se interponga y tome tus hamburguesas cuando lleguen, no puedes prestar atención a tu crush. 😞
-Este es un trabajo "síncrono", estás "sincronizado" con el cajero / cocinero 👨🍳. Tienes que esperar y estar allí en el momento exacto en que el cajero / cocinero 👨🍳 termina las hamburguesas 🍔 y te las da, o de lo contrario, alguien más podría cogerlas.
+Este es un trabajo "sincrónico", estás "sincronizado" con el cajero/cocinero 👨🍳. Tienes que esperar 🕙 y estar allí en el momento exacto en que el cajero/cocinero 👨🍳 termine las hamburguesas y te las entregue, o de lo contrario, alguien más podría tomarlas.
-
+
-Luego, el cajero / cocinero 👨🍳 finalmente regresa con tus hamburguesas 🍔, después de mucho tiempo esperando 🕙 frente al mostrador.
+Luego tu cajero/cocinero 👨🍳 finalmente regresa con tus hamburguesas, después de mucho tiempo esperando 🕙 allí frente al mostrador.
-
+
-Coges tus hamburguesas 🍔 y vas a la mesa con esa persona 😍.
+Tomas tus hamburguesas y vas a la mesa con tu crush.
-Sólo las comes y listo 🍔 ⏹.
+Simplemente las comes, y has terminado. ⏹
-
+
-No has hablado ni coqueteado mucho, ya que has pasado la mayor parte del tiempo esperando 🕙 frente al mostrador 😞.
+No hubo mucho hablar o coquetear ya que la mayor parte del tiempo se dedicó a esperar 🕙 frente al mostrador. 😞
/// info | Información
-Las ilustraciones fueron creados por Ketrina Thompson. 🎨
+Hermosas ilustraciones de Ketrina Thompson. 🎨
///
---
-En este escenario de las hamburguesas paralelas, tú eres un sistema / programa 🤖 con dos procesadores (tú y la persona que te gusta 😍), ambos esperando 🕙 y dedicando su atención ⏯ a estar "esperando en el mostrador" 🕙 durante mucho tiempo.
+En este escenario de las hamburguesas paralelas, eres una computadora / programa 🤖 con dos procesadores (tú y tu crush), ambos esperando 🕙 y dedicando su atención ⏯ a estar "esperando en el mostrador" 🕙 por mucho tiempo.
-La tienda de comida rápida tiene 8 procesadores (cajeros / cocineros) 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳. Mientras que la tienda de hamburguesas concurrentes podría haber tenido solo 2 (un cajero y un cocinero) 💁 👨🍳.
+La tienda de comida rápida tiene 8 procesadores (cajeros/cocineros). Mientras que la tienda de hamburguesas concurrentes podría haber tenido solo 2 (un cajero y un cocinero).
-Pero aún así, la experiencia final no es la mejor 😞.
+Pero aún así, la experiencia final no es la mejor. 😞
---
-Esta sería la historia paralela equivalente de las hamburguesas 🍔.
+Esta sería la historia equivalente de las hamburguesas paralelas. 🍔
-Para un ejemplo más "real" de ésto, imagina un banco.
+Para un ejemplo más "de la vida real" de esto, imagina un banco.
-Hasta hace poco, la mayoría de los bancos tenían varios cajeros 👨💼👨💼👨💼👨💼 y una gran línea 🕙🕙🕙🕙🕙🕙🕙🕙.
+Hasta hace poco, la mayoría de los bancos tenían múltiples cajeros 👨💼👨💼👨💼👨💼 y una gran fila 🕙🕙🕙🕙🕙🕙🕙🕙.
Todos los cajeros haciendo todo el trabajo con un cliente tras otro 👨💼⏯.
-Y tienes que esperar 🕙 en la fila durante mucho tiempo o perderás tu turno.
-
-Probablemente no querrás llevar contigo a la persona que te gusta 😍 a hacer encargos al banco 🏦.
+Y tienes que esperar 🕙 en la fila por mucho tiempo o pierdes tu turno.
-### Conclusión de las Hamburguesa
+Probablemente no querrías llevar a tu crush 😍 contigo a hacer trámites en el banco 🏦.
-En este escenario de "hamburguesas de comida rápida con tu pareja", debido a que hay mucha espera 🕙, tiene mucho más sentido tener un sistema con concurrencia ⏸🔀⏯.
+### Conclusión de las Hamburguesas
-Este es el caso de la mayoría de las aplicaciones web.
+En este escenario de "hamburguesas de comida rápida con tu crush", como hay mucha espera 🕙, tiene mucho más sentido tener un sistema concurrente ⏸🔀⏯.
-Muchos, muchos usuarios, pero el servidor está esperando 🕙 el envío de las peticiones ya que su conexión no es buena.
+Este es el caso para la mayoría de las aplicaciones web.
-Y luego esperando 🕙 nuevamente a que las respuestas retornen.
+Muchos, muchos usuarios, pero tu servidor está esperando 🕙 su conexión no tan buena para enviar sus requests.
-Esta "espera" 🕙 se mide en microsegundos, pero aun así, sumando todo, al final es mucha espera.
+Y luego esperar 🕙 nuevamente a que los responses retornen.
-Es por eso que tiene mucho sentido usar código asíncrono ⏸🔀⏯ para las API web.
+Esta "espera" 🕙 se mide en microsegundos, pero aún así, sumándolo todo, es mucha espera al final.
-La mayoría de los framework populares de Python existentes (incluidos Flask y Django) se crearon antes de que existieran las nuevas funciones asíncronas en Python. Por lo tanto, las formas en que pueden implementarse admiten la ejecución paralela y una forma más antigua de ejecución asíncrona que no es tan potente como la actual.
+Por eso tiene mucho sentido usar código asíncrono ⏸🔀⏯ para las APIs web.
-A pesar de que la especificación principal para Python web asíncrono (ASGI) se desarrolló en Django, para agregar soporte para WebSockets.
-
-Ese tipo de asincronía es lo que hizo popular a NodeJS (aunque NodeJS no es paralelo) y esa es la fortaleza de Go como lenguaje de programación.
+Este tipo de asincronía es lo que hizo popular a NodeJS (aunque NodeJS no es paralelo) y esa es la fortaleza de Go como lenguaje de programación.
Y ese es el mismo nivel de rendimiento que obtienes con **FastAPI**.
-Y como puede tener paralelismo y asincronía al mismo tiempo, obtienes un mayor rendimiento que la mayoría de los frameworks de NodeJS probados y a la par con Go, que es un lenguaje compilado más cercano a C (todo gracias Starlette).
+Y como puedes tener paralelismo y asincronía al mismo tiempo, obtienes un mayor rendimiento que la mayoría de los frameworks de NodeJS probados y a la par con Go, que es un lenguaje compilado más cercano a C (todo gracias a Starlette).
### ¿Es la concurrencia mejor que el paralelismo?
¡No! Esa no es la moraleja de la historia.
-La concurrencia es diferente al paralelismo. Y es mejor en escenarios **específicos** que implican mucha espera. Debido a eso, generalmente es mucho mejor que el paralelismo para el desarrollo de aplicaciones web. Pero no para todo.
+La concurrencia es diferente del paralelismo. Y es mejor en escenarios **específicos** que implican mucha espera. Debido a eso, generalmente es mucho mejor que el paralelismo para el desarrollo de aplicaciones web. Pero no para todo.
-Entonces, para explicar eso, imagina la siguiente historia corta:
+Así que, para equilibrar eso, imagina la siguiente historia corta:
> Tienes que limpiar una casa grande y sucia.
@@ -270,80 +267,80 @@ Entonces, para explicar eso, imagina la siguiente historia corta:
---
-No hay esperas 🕙, solo hay mucho trabajo por hacer, en varios lugares de la casa.
+No hay esperas 🕙 en ninguna parte, solo mucho trabajo por hacer, en múltiples lugares de la casa.
-Podrías tener turnos como en el ejemplo de las hamburguesas, primero la sala de estar, luego la cocina, pero como no estás esperando nada, solo limpiando y limpiando, los turnos no afectarían nada.
+Podrías tener turnos como en el ejemplo de las hamburguesas, primero la sala de estar, luego la cocina, pero como no estás esperando 🕙 nada, solo limpiando y limpiando, los turnos no afectarían nada.
Tomaría la misma cantidad de tiempo terminar con o sin turnos (concurrencia) y habrías hecho la misma cantidad de trabajo.
-Pero en este caso, si pudieras traer a los 8 ex cajeros / cocineros / ahora limpiadores 👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳👨🍳, y cada uno de ellos (y tú) podría tomar una zona de la casa para limpiarla, podría hacer todo el trabajo en **paralelo**, con la ayuda adicional y terminar mucho antes.
+Pero en este caso, si pudieras traer a los 8 ex-cajeros/cocineros/ahora-limpiadores, y cada uno de ellos (más tú) pudiera tomar una zona de la casa para limpiarla, podrías hacer todo el trabajo en **paralelo**, con la ayuda extra, y terminar mucho antes.
-En este escenario, cada uno de los limpiadores (incluido tú) sería un procesador, haciendo su parte del trabajo.
+En este escenario, cada uno de los limpiadores (incluyéndote) sería un procesador, haciendo su parte del trabajo.
-Y como la mayor parte del tiempo de ejecución lo coge el trabajo real (en lugar de esperar), y el trabajo en un sistema lo realiza una CPU , a estos problemas se les llama "CPU bound".
+Y como la mayor parte del tiempo de ejecución se dedica al trabajo real (en lugar de esperar), y el trabajo en una computadora lo realiza una CPU, llaman a estos problemas "CPU bound".
---
-Ejemplos típicos de operaciones dependientes de CPU son cosas que requieren un procesamiento matemático complejo.
+Ejemplos comunes de operaciones limitadas por la CPU son cosas que requieren procesamiento matemático complejo.
Por ejemplo:
-* **Audio** o **procesamiento de imágenes**.
-* **Visión por computadora**: una imagen está compuesta de millones de píxeles, cada píxel tiene 3 valores / colores, procesamiento que normalmente requiere calcular algo en esos píxeles, todo al mismo tiempo.
-* **Machine Learning**: normalmente requiere muchas multiplicaciones de "matrices" y "vectores". Imagina en una enorme hoja de cálculo con números y tener que multiplicarlos todos al mismo tiempo.
-* **Deep Learning**: este es un subcampo de Machine Learning, por lo tanto, aplica lo mismo. Es solo que no hay una sola hoja de cálculo de números para multiplicar, sino un gran conjunto de ellas, y en muchos casos, usa un procesador especial para construir y / o usar esos modelos.
+* **Procesamiento de audio** o **imágenes**.
+* **Visión por computadora**: una imagen está compuesta de millones de píxeles, cada píxel tiene 3 valores / colores, procesar eso normalmente requiere calcular algo en esos píxeles, todos al mismo tiempo.
+* **Machine Learning**: normalmente requiere muchas multiplicaciones de "matrices" y "vectores". Piensa en una enorme hoja de cálculo con números y multiplicando todos juntos al mismo tiempo.
+* **Deep Learning**: este es un subcampo de Machine Learning, por lo tanto, se aplica lo mismo. Es solo que no hay una sola hoja de cálculo de números para multiplicar, sino un enorme conjunto de ellas, y en muchos casos, usas un procesador especial para construir y / o usar esos modelos.
### Concurrencia + Paralelismo: Web + Machine Learning
-Con **FastAPI** puedes aprovechar la concurrencia que es muy común para el desarrollo web (atractivo principal de NodeJS).
+Con **FastAPI** puedes aprovechar la concurrencia que es muy común para el desarrollo web (la misma atracción principal de NodeJS).
-Pero también puedes aprovechar los beneficios del paralelismo y el multiprocesamiento (tener múltiples procesos ejecutándose en paralelo) para cargas de trabajo **CPU bound** como las de los sistemas de Machine Learning.
+Pero también puedes explotar los beneficios del paralelismo y la multiprocesamiento (tener múltiples procesos ejecutándose en paralelo) para cargas de trabajo **CPU bound** como las de los sistemas de Machine Learning.
-Eso, más el simple hecho de que Python es el lenguaje principal para **Data Science**, Machine Learning y especialmente Deep Learning, hacen de FastAPI una muy buena combinación para las API y aplicaciones web de Data Science / Machine Learning (entre muchas otras).
+Eso, más el simple hecho de que Python es el lenguaje principal para **Data Science**, Machine Learning y especialmente Deep Learning, hacen de FastAPI una muy buena opción para APIs web de Data Science / Machine Learning y aplicaciones (entre muchas otras).
-Para ver cómo lograr este paralelismo en producción, consulta la sección sobre [Despliegue](deployment/index.md){.internal-link target=_blank}.
+Para ver cómo lograr este paralelismo en producción, consulta la sección sobre [Deployment](deployment/index.md){.internal-link target=_blank}.
## `async` y `await`
-Las versiones modernas de Python tienen una forma muy intuitiva de definir código asíncrono. Esto hace que se vea como un código "secuencial" normal y que haga la "espera" por ti en los momentos correctos.
+Las versiones modernas de Python tienen una forma muy intuitiva de definir código asíncrono. Esto hace que se vea igual que el código "secuencial" normal y hace el "wait" por ti en los momentos adecuados.
-Cuando hay una operación que requerirá esperar antes de dar los resultados y tiene soporte para estas nuevas características de Python, puedes programarlo como:
+Cuando hay una operación que requerirá esperar antes de dar los resultados y tiene soporte para estas nuevas funcionalidades de Python, puedes programarlo así:
```Python
burgers = await get_burgers(2)
```
-La clave aquí es `await`. Eso le dice a Python que tiene que esperar ⏸ a que `get_burgers (2)` termine de hacer lo suyo 🕙 antes de almacenar los resultados en `hamburguesas`. Con eso, Python sabrá que puede ir y hacer otra cosa 🔀 ⏯ mientras tanto (como recibir otra solicitud).
+La clave aquí es el `await`. Dice a Python que tiene que esperar ⏸ a que `get_burgers(2)` termine de hacer su cosa 🕙 antes de almacenar los resultados en `burgers`. Con eso, Python sabrá que puede ir y hacer algo más 🔀 ⏯ mientras tanto (como recibir otro request).
-Para que `await` funcione, tiene que estar dentro de una función que admita esta asincronía. Para hacer eso, simplemente lo declaras con `async def`:
+Para que `await` funcione, tiene que estar dentro de una función que soporte esta asincronía. Para hacer eso, solo declara la función con `async def`:
```Python hl_lines="1"
async def get_burgers(number: int):
- # Do some asynchronous stuff to create the burgers
+ # Hacer algunas cosas asíncronas para crear las hamburguesas
return burgers
```
-...en vez de `def`:
+...en lugar de `def`:
```Python hl_lines="2"
-# This is not asynchronous
+# Esto no es asíncrono
def get_sequential_burgers(number: int):
- # Do some sequential stuff to create the burgers
+ # Hacer algunas cosas secuenciales para crear las hamburguesas
return burgers
```
-Con `async def`, Python sabe que, dentro de esa función, debe tener en cuenta las expresiones `wait` y que puede "pausar" ⏸ la ejecución de esa función e ir a hacer otra cosa 🔀 antes de regresar.
+Con `async def`, Python sabe que, dentro de esa función, tiene que estar atento a las expresiones `await`, y que puede "pausar" ⏸ la ejecución de esa función e ir a hacer algo más 🔀 antes de regresar.
-Cuando desees llamar a una función `async def`, debes "esperarla". Entonces, esto no funcionará:
+Cuando deseas llamar a una función `async def`, tienes que "await" dicha función. Así que, esto no funcionará:
```Python
-# Esto no funcionará, porque get_burgers se definió con: async def
-hamburguesas = get_burgers (2)
+# Esto no funcionará, porque get_burgers fue definido con: async def
+burgers = get_burgers(2)
```
---
-Por lo tanto, si estás utilizando una library que te dice que puedes llamarla con `await`, debes crear las *path operation functions* que la usan con `async def`, como en:
+Así que, si estás usando un paquete que te dice que puedes llamarlo con `await`, necesitas crear las *path operation functions* que lo usen con `async def`, como en:
```Python hl_lines="2-3"
@app.get('/burgers')
@@ -354,15 +351,25 @@ async def read_burgers():
### Más detalles técnicos
-Es posible que hayas notado que `await` solo se puede usar dentro de las funciones definidas con `async def`.
+Podrías haber notado que `await` solo se puede usar dentro de funciones definidas con `async def`.
+
+Pero al mismo tiempo, las funciones definidas con `async def` deben ser "awaited". Por lo tanto, las funciones con `async def` solo se pueden llamar dentro de funciones definidas con `async def` también.
+
+Entonces, sobre el huevo y la gallina, ¿cómo llamas a la primera función `async`?
+
+Si estás trabajando con **FastAPI** no tienes que preocuparte por eso, porque esa "primera" función será tu *path operation function*, y FastAPI sabrá cómo hacer lo correcto.
+
+Pero si deseas usar `async` / `await` sin FastAPI, también puedes hacerlo.
+
+### Escribe tu propio código async
-Pero al mismo tiempo, las funciones definidas con `async def` deben ser "esperadas". Por lo tanto, las funciones con `async def` solo se pueden invocar dentro de las funciones definidas con `async def` también.
+Starlette (y **FastAPI**) están basados en AnyIO, lo que lo hace compatible tanto con la librería estándar de Python asyncio como con Trio.
-Entonces, relacionado con la paradoja del huevo y la gallina, ¿cómo se llama a la primera función `async`?
+En particular, puedes usar directamente AnyIO para tus casos de uso avanzados de concurrencia que requieran patrones más avanzados en tu propio código.
-Si estás trabajando con **FastAPI** no tienes que preocuparte por eso, porque esa "primera" función será tu *path operation function*, y FastAPI sabrá cómo hacer lo pertinente.
+E incluso si no estuvieras usando FastAPI, también podrías escribir tus propias aplicaciones asíncronas con AnyIO para ser altamente compatibles y obtener sus beneficios (p.ej. *concurrencia estructurada*).
-En el caso de que desees usar `async` / `await` sin FastAPI, revisa la documentación oficial de Python.
+Creé otro paquete sobre AnyIO, como una capa delgada, para mejorar un poco las anotaciones de tipos y obtener mejor **autocompletado**, **errores en línea**, etc. También tiene una introducción amigable y tutorial para ayudarte a **entender** y escribir **tu propio código async**: Asyncer. Sería particularmente útil si necesitas **combinar código async con regular** (bloqueante/sincrónico).
### Otras formas de código asíncrono
@@ -370,68 +377,68 @@ Este estilo de usar `async` y `await` es relativamente nuevo en el lenguaje.
Pero hace que trabajar con código asíncrono sea mucho más fácil.
-Esta misma sintaxis (o casi idéntica) también se incluyó recientemente en las versiones modernas de JavaScript (en Browser y NodeJS).
+Esta misma sintaxis (o casi idéntica) también se incluyó recientemente en las versiones modernas de JavaScript (en el Navegador y NodeJS).
-Pero antes de eso, manejar código asíncrono era bastante más complejo y difícil.
+Pero antes de eso, manejar el código asíncrono era mucho más complejo y difícil.
-En versiones anteriores de Python, podrías haber utilizado threads o Gevent. Pero el código es mucho más complejo de entender, depurar y desarrollar.
+En versiones previas de Python, podrías haber usado hilos o Gevent. Pero el código es mucho más complejo de entender, depurar y razonar.
-En versiones anteriores de NodeJS / Browser JavaScript, habrías utilizado "callbacks". Lo que conduce a callback hell.
+En versiones previas de NodeJS / JavaScript en el Navegador, habrías usado "callbacks". Lo que lleva al callback hell.
## Coroutines
-**Coroutine** es un término sofisticado para referirse a la cosa devuelta por una función `async def`. Python sabe que es algo así como una función que puede iniciar y que terminará en algún momento, pero que también podría pausarse ⏸ internamente, siempre que haya un `await` dentro de ella.
+**Coroutines** es simplemente el término muy elegante para la cosa que devuelve una función `async def`. Python sabe que es algo parecido a una función, que puede comenzar y que terminará en algún momento, pero que podría pausar ⏸ internamente también, siempre que haya un `await` dentro de él.
-Pero toda esta funcionalidad de usar código asincrónico con `async` y `await` se resume muchas veces como usar "coroutines". Es comparable a la característica principal de Go, las "Goroutines".
+Pero toda esta funcionalidad de usar código asíncrono con `async` y `await` a menudo se resume como utilizar "coroutines". Es comparable a la funcionalidad clave principal de Go, las "Goroutines".
## Conclusión
Veamos la misma frase de arriba:
-> Las versiones modernas de Python tienen soporte para **"código asíncrono"** usando algo llamado **"coroutines"**, con la sintaxis **`async` y `await`**.
+> Las versiones modernas de Python tienen soporte para **"código asíncrono"** utilizando algo llamado **"coroutines"**, con la sintaxis **`async` y `await`**.
-Eso ya debería tener más sentido ahora. ✨
+Eso debería tener más sentido ahora. ✨
Todo eso es lo que impulsa FastAPI (a través de Starlette) y lo que hace que tenga un rendimiento tan impresionante.
-## Detalles muy técnicos
+## Detalles Muy Técnicos
/// warning | Advertencia
Probablemente puedas saltarte esto.
-Estos son detalles muy técnicos de cómo **FastAPI** funciona a muy bajo nivel.
+Estos son detalles muy técnicos de cómo funciona **FastAPI** en su interior.
-Si tienes bastante conocimiento técnico (coroutines, threads, bloqueos, etc.) y tienes curiosidad acerca de cómo FastAPI gestiona `async def` vs `def` normal, continúa.
+Si tienes bastante conocimiento técnico (coroutines, hilos, bloqueo, etc.) y tienes curiosidad sobre cómo FastAPI maneja `async def` vs `def` normal, adelante.
///
-### Path operation functions
+### Funciones de *path operation*
-Cuando declaras una *path operation function* con `def` normal en lugar de `async def`, se ejecuta en un threadpool externo que luego es "awaited", en lugar de ser llamado directamente (ya que bloquearía el servidor).
+Cuando declaras una *path operation function* con `def` normal en lugar de `async def`, se ejecuta en un threadpool externo que luego es esperado, en lugar de ser llamado directamente (ya que bloquearía el servidor).
-Si vienes de otro framework asíncrono que no funciona de la manera descrita anteriormente y estás acostumbrado a definir *path operation functions* del tipo sólo cálculo con `def` simple para una pequeña ganancia de rendimiento (aproximadamente 100 nanosegundos), ten en cuenta que en **FastAPI** el efecto sería bastante opuesto. En estos casos, es mejor usar `async def` a menos que tus *path operation functions* usen un código que realice el bloqueo I/O.
+Si vienes de otro framework async que no funciona de la manera descrita anteriormente y estás acostumbrado a definir funciones de *path operation* solo de cómputo trivial con `def` normal para una pequeña ganancia de rendimiento (alrededor de 100 nanosegundos), ten en cuenta que en **FastAPI** el efecto sería bastante opuesto. En estos casos, es mejor usar `async def` a menos que tus *path operation functions* usen código que realice I/O de bloqueo.
-Aún así, en ambas situaciones, es probable que **FastAPI** sea [aún más rápido](index.md#rendimiento){.Internal-link target=_blank} que (o al menos comparable) a tu framework anterior.
+Aun así, en ambas situaciones, es probable que **FastAPI** [siga siendo más rápida](index.md#performance){.internal-link target=_blank} que (o al menos comparable a) tu framework anterior.
### Dependencias
-Lo mismo se aplica para las dependencias. Si una dependencia es una función estándar `def` en lugar de `async def`, se ejecuta en el threadpool externo.
+Lo mismo aplica para las [dependencias](tutorial/dependencies/index.md){.internal-link target=_blank}. Si una dependencia es una función estándar `def` en lugar de `async def`, se ejecuta en el threadpool externo.
-### Subdependencias
+### Sub-dependencias
-Puedes tener múltiples dependencias y subdependencias que se requieren unas a otras (como parámetros de las definiciones de cada función), algunas de ellas pueden crearse con `async def` y otras con `def` normal. Igual todo seguiría funcionando correctamente, y las creadas con `def` normal se llamarían en un thread externo (del threadpool) en lugar de ser "awaited".
+Puedes tener múltiples dependencias y [sub-dependencias](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requiriéndose mutuamente (como parámetros de las definiciones de funciones), algunas de ellas podrían ser creadas con `async def` y algunas con `def` normal. Aun funcionará, y las que fueron creadas con `def` normal serían llamadas en un hilo externo (del threadpool) en lugar de ser "awaited".
-### Otras funciones de utilidades
+### Otras funciones de utilidad
-Cualquier otra función de utilidad que llames directamente se puede crear con `def` o `async def` normales y FastAPI no afectará la manera en que la llames.
+Cualquier otra función de utilidad que llames directamente puede ser creada con `def` normal o `async def` y FastAPI no afectará la forma en que la llames.
-Esto contrasta con las funciones que FastAPI llama por ti: las *path operation functions* y dependencias.
+Esto contrasta con las funciones que FastAPI llama por ti: *path operation functions* y dependencias.
-Si tu función de utilidad es creada con `def` normal, se llamará directamente (tal cual la escribes en tu código), no en un threadpool, si la función se crea con `async def`, entonces debes usar `await` con esa función cuando la llamas en tu código.
+Si tu función de utilidad es una función normal con `def`, será llamada directamente (como la escribas en tu código), no en un threadpool; si la función es creada con `async def` entonces deberías "await" por esa función cuando la llames en tu código.
---
-Nuevamente, estos son detalles muy técnicos que probablemente sólo son útiles si los viniste a buscar expresamente.
+Nuevamente, estos son detalles muy técnicos que probablemente serían útiles si los buscaste.
-De lo contrario, la guía de la sección anterior debería ser suficiente: ¿Tienes prisa?.
+De lo contrario, deberías estar bien con las pautas de la sección anterior: ¿Con prisa?.
diff --git a/docs/es/docs/benchmarks.md b/docs/es/docs/benchmarks.md
index 3e02d4e9f..49d65b6ba 100644
--- a/docs/es/docs/benchmarks.md
+++ b/docs/es/docs/benchmarks.md
@@ -1,33 +1,34 @@
# Benchmarks
-Los benchmarks independientes de TechEmpower muestran aplicaciones de **FastAPI** que se ejecutan en Uvicorn como uno de los frameworks de Python más rápidos disponibles, solo por debajo de Starlette y Uvicorn (utilizados internamente por FastAPI). (*)
+Los benchmarks independientes de TechEmpower muestran aplicaciones de **FastAPI** ejecutándose bajo Uvicorn como uno de los frameworks de Python más rápidos disponibles, solo por debajo de Starlette y Uvicorn en sí mismos (utilizados internamente por FastAPI).
-Pero al comprobar benchmarks y comparaciones debes tener en cuenta lo siguiente.
+Pero al revisar benchmarks y comparaciones, debes tener en cuenta lo siguiente.
## Benchmarks y velocidad
-Cuando revisas los benchmarks, es común ver varias herramientas de diferentes tipos comparadas como equivalentes.
+Cuando ves los benchmarks, es común ver varias herramientas de diferentes tipos comparadas como equivalentes.
-Específicamente, para ver Uvicorn, Starlette y FastAPI comparadas entre sí (entre muchas otras herramientas).
+Específicamente, ver Uvicorn, Starlette y FastAPI comparados juntos (entre muchas otras herramientas).
-Cuanto más sencillo sea el problema resuelto por la herramienta, mejor rendimiento obtendrá. Y la mayoría de los benchmarks no prueban las funciones adicionales proporcionadas por la herramienta.
+Cuanto más simple sea el problema resuelto por la herramienta, mejor rendimiento tendrá. Y la mayoría de los benchmarks no prueban las funcionalidades adicionales proporcionadas por la herramienta.
-La jerarquía sería:
+La jerarquía es como:
-* **Uvicorn**: como servidor ASGI
+* **Uvicorn**: un servidor ASGI
* **Starlette**: (usa Uvicorn) un microframework web
- * **FastAPI**: (usa Starlette) un microframework API con varias características adicionales para construir APIs, con validación de datos, etc.
+ * **FastAPI**: (usa Starlette) un microframework para APIs con varias funcionalidades adicionales para construir APIs, con validación de datos, etc.
+
* **Uvicorn**:
* Tendrá el mejor rendimiento, ya que no tiene mucho código extra aparte del propio servidor.
- * No escribirías una aplicación directamente en Uvicorn. Eso significaría que tu código tendría que incluir más o menos, al menos, todo el código proporcionado por Starlette (o **FastAPI**). Y si hicieras eso, tu aplicación final tendría la misma sobrecarga que si hubieras usado un framework y minimizado el código de tu aplicación y los errores.
- * Si estás comparando Uvicorn, compáralo con los servidores de aplicaciones Daphne, Hypercorn, uWSGI, etc.
+ * No escribirías una aplicación directamente en Uvicorn. Eso significaría que tu código tendría que incluir, más o menos, al menos, todo el código proporcionado por Starlette (o **FastAPI**). Y si hicieras eso, tu aplicación final tendría la misma carga que si hubieras usado un framework, minimizando el código de tu aplicación y los bugs.
+ * Si estás comparando Uvicorn, compáralo con Daphne, Hypercorn, uWSGI, etc. Servidores de aplicaciones.
* **Starlette**:
- * Tendrá el siguiente mejor desempeño, después de Uvicorn. De hecho, Starlette usa Uvicorn para correr. Por lo tanto, probablemente sólo pueda volverse "más lento" que Uvicorn al tener que ejecutar más código.
- * Pero te proporciona las herramientas para crear aplicaciones web simples, con routing basado en paths, etc.
+ * Tendrá el siguiente mejor rendimiento, después de Uvicorn. De hecho, Starlette usa Uvicorn para ejecutarse. Así que probablemente solo pueda ser "más lento" que Uvicorn por tener que ejecutar más código.
+ * Pero te proporciona las herramientas para construir aplicaciones web sencillas, con enrutamiento basado en paths, etc.
* Si estás comparando Starlette, compáralo con Sanic, Flask, Django, etc. Frameworks web (o microframeworks).
* **FastAPI**:
- * De la misma manera que Starlette usa Uvicorn y no puede ser más rápido que él, **FastAPI** usa Starlette, por lo que no puede ser más rápido que él.
- * * FastAPI ofrece más características además de las de Starlette. Funciones que casi siempre necesitas al crear una API, como validación y serialización de datos. Y al usarlo, obtienes documentación automática de forma gratuita (la documentación automática ni siquiera agrega gastos generales a las aplicaciones en ejecución, se genera al iniciar).
- * Si no usaras FastAPI y usaras Starlette directamente (u otra herramienta, como Sanic, Flask, Responder, etc.), tendrías que implementar toda la validación y serialización de datos tu mismo. Por lo tanto, tu aplicación final seguirá teniendo la misma sobrecarga que si se hubiera creado con FastAPI. Y en muchos casos, esta validación y serialización de datos constituye la mayor cantidad de código escrito en las aplicaciones.
- * Entonces, al usar FastAPI estás ahorrando tiempo de desarrollo, errores, líneas de código y probablemente obtendrías el mismo rendimiento (o mejor) que obtendrías si no lo usaras (ya que tendrías que implementarlo todo en tu código).
- * Si estás comparando FastAPI, compáralo con un framework de aplicaciones web (o conjunto de herramientas) que proporciona validación, serialización y documentación de datos, como Flask-apispec, NestJS, Molten, etc. Frameworks con validación, serialización y documentación automáticas integradas.
+ * De la misma forma en que Starlette usa Uvicorn y no puede ser más rápido que él, **FastAPI** usa Starlette, por lo que no puede ser más rápido que él.
+ * FastAPI ofrece más funcionalidades además de las de Starlette. Funcionalidades que casi siempre necesitas al construir APIs, como la validación y serialización de datos. Y al utilizarlo, obtienes documentación automática gratis (la documentación automática ni siquiera añade carga a las aplicaciones en ejecución, se genera al inicio).
+ * Si no usabas FastAPI y utilizabas Starlette directamente (u otra herramienta, como Sanic, Flask, Responder, etc.) tendrías que implementar toda la validación y serialización de datos por ti mismo. Entonces, tu aplicación final aún tendría la misma carga que si hubiera sido construida usando FastAPI. Y en muchos casos, esta validación y serialización de datos es la mayor cantidad de código escrito en las aplicaciones.
+ * Entonces, al usar FastAPI estás ahorrando tiempo de desarrollo, bugs, líneas de código, y probablemente obtendrías el mismo rendimiento (o mejor) que si no lo usaras (ya que tendrías que implementarlo todo en tu código).
+ * Si estás comparando FastAPI, compáralo con un framework de aplicación web (o conjunto de herramientas) que proporcione validación de datos, serialización y documentación, como Flask-apispec, NestJS, Molten, etc. Frameworks con validación de datos, serialización y documentación automáticas integradas.
diff --git a/docs/es/docs/deployment/cloud.md b/docs/es/docs/deployment/cloud.md
new file mode 100644
index 000000000..fe47d5dcf
--- /dev/null
+++ b/docs/es/docs/deployment/cloud.md
@@ -0,0 +1,18 @@
+# Despliega FastAPI en Proveedores de Nube
+
+Puedes usar prácticamente **cualquier proveedor de nube** para desplegar tu aplicación FastAPI.
+
+En la mayoría de los casos, los principales proveedores de nube tienen guías para desplegar FastAPI con ellos.
+
+## Proveedores de Nube - Sponsors
+
+Algunos proveedores de nube ✨ [**son sponsors de FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, esto asegura el desarrollo **continuado** y **saludable** de FastAPI y su **ecosistema**.
+
+Y muestra su verdadero compromiso con FastAPI y su **comunidad** (tú), ya que no solo quieren proporcionarte un **buen servicio**, sino también asegurarse de que tengas un **framework bueno y saludable**, FastAPI. 🙇
+
+Podrías querer probar sus servicios y seguir sus guías:
+
+* Platform.sh
+* Porter
+* Coherence
+* Render
diff --git a/docs/es/docs/deployment/concepts.md b/docs/es/docs/deployment/concepts.md
new file mode 100644
index 000000000..bcc7948bc
--- /dev/null
+++ b/docs/es/docs/deployment/concepts.md
@@ -0,0 +1,321 @@
+# Conceptos de Implementación
+
+Cuando implementas una aplicación **FastAPI**, o en realidad, cualquier tipo de API web, hay varios conceptos que probablemente te importen, y al entenderlos, puedes encontrar la **forma más adecuada** de **implementar tu aplicación**.
+
+Algunos de los conceptos importantes son:
+
+* Seguridad - HTTPS
+* Ejecución al iniciar
+* Reinicios
+* Replicación (la cantidad de procesos en ejecución)
+* Memoria
+* Pasos previos antes de iniciar
+
+Veremos cómo afectan estas **implementaciones**.
+
+Al final, el objetivo principal es poder **servir a tus clientes de API** de una manera que sea **segura**, para **evitar interrupciones**, y usar los **recursos de cómputo** (por ejemplo, servidores remotos/máquinas virtuales) de la manera más eficiente posible. 🚀
+
+Te contaré un poquito más sobre estos **conceptos** aquí, y eso, con suerte, te dará la **intuición** que necesitarías para decidir cómo implementar tu API en diferentes entornos, posiblemente incluso en aquellos **futuros** que aún no existen.
+
+Al considerar estos conceptos, podrás **evaluar y diseñar** la mejor manera de implementar **tus propias APIs**.
+
+En los próximos capítulos, te daré más **recetas concretas** para implementar aplicaciones de FastAPI.
+
+Pero por ahora, revisemos estas importantes **ideas conceptuales**. Estos conceptos también se aplican a cualquier otro tipo de API web. 💡
+
+## Seguridad - HTTPS
+
+En el [capítulo anterior sobre HTTPS](https.md){.internal-link target=_blank} aprendimos sobre cómo HTTPS proporciona cifrado para tu API.
+
+También vimos que HTTPS es normalmente proporcionado por un componente **externo** a tu servidor de aplicaciones, un **Proxy de Terminación TLS**.
+
+Y debe haber algo encargado de **renovar los certificados HTTPS**, podría ser el mismo componente o algo diferente.
+
+### Herramientas de Ejemplo para HTTPS
+
+Algunas de las herramientas que podrías usar como Proxy de Terminación TLS son:
+
+* Traefik
+ * Maneja automáticamente las renovaciones de certificados ✨
+* Caddy
+ * Maneja automáticamente las renovaciones de certificados ✨
+* Nginx
+ * Con un componente externo como Certbot para las renovaciones de certificados
+* HAProxy
+ * Con un componente externo como Certbot para las renovaciones de certificados
+* Kubernetes con un Controlador de Ingress como Nginx
+ * Con un componente externo como cert-manager para las renovaciones de certificados
+* Manejado internamente por un proveedor de nube como parte de sus servicios (lee abajo 👇)
+
+Otra opción es que podrías usar un **servicio de nube** que haga más del trabajo, incluyendo configurar HTTPS. Podría tener algunas restricciones o cobrarte más, etc. Pero en ese caso, no tendrías que configurar un Proxy de Terminación TLS tú mismo.
+
+Te mostraré algunos ejemplos concretos en los próximos capítulos.
+
+---
+
+Luego, los siguientes conceptos a considerar son todos acerca del programa que ejecuta tu API real (por ejemplo, Uvicorn).
+
+## Programa y Proceso
+
+Hablaremos mucho sobre el "**proceso**" en ejecución, así que es útil tener claridad sobre lo que significa y cuál es la diferencia con la palabra "**programa**".
+
+### Qué es un Programa
+
+La palabra **programa** se usa comúnmente para describir muchas cosas:
+
+* El **código** que escribes, los **archivos Python**.
+* El **archivo** que puede ser **ejecutado** por el sistema operativo, por ejemplo: `python`, `python.exe` o `uvicorn`.
+* Un programa específico mientras está siendo **ejecutado** en el sistema operativo, usando la CPU y almacenando cosas en la memoria. Esto también se llama **proceso**.
+
+### Qué es un Proceso
+
+La palabra **proceso** se usa normalmente de una manera más específica, refiriéndose solo a lo que está ejecutándose en el sistema operativo (como en el último punto anterior):
+
+* Un programa específico mientras está siendo **ejecutado** en el sistema operativo.
+ * Esto no se refiere al archivo, ni al código, se refiere **específicamente** a lo que está siendo **ejecutado** y gestionado por el sistema operativo.
+* Cualquier programa, cualquier código, **solo puede hacer cosas** cuando está siendo **ejecutado**. Así que, cuando hay un **proceso en ejecución**.
+* El proceso puede ser **terminado** (o "matado") por ti, o por el sistema operativo. En ese punto, deja de ejecutarse/ser ejecutado, y ya no puede **hacer cosas**.
+* Cada aplicación que tienes en ejecución en tu computadora tiene algún proceso detrás, cada programa en ejecución, cada ventana, etc. Y normalmente hay muchos procesos ejecutándose **al mismo tiempo** mientras una computadora está encendida.
+* Puede haber **múltiples procesos** del **mismo programa** ejecutándose al mismo tiempo.
+
+Si revisas el "administrador de tareas" o "monitor del sistema" (o herramientas similares) en tu sistema operativo, podrás ver muchos de esos procesos en ejecución.
+
+Y, por ejemplo, probablemente verás que hay múltiples procesos ejecutando el mismo programa del navegador (Firefox, Chrome, Edge, etc.). Normalmente ejecutan un proceso por pestaña, además de algunos otros procesos extra.
+
+
+
+---
+
+Ahora que conocemos la diferencia entre los términos **proceso** y **programa**, sigamos hablando sobre implementaciones.
+
+## Ejecución al Iniciar
+
+En la mayoría de los casos, cuando creas una API web, quieres que esté **siempre en ejecución**, ininterrumpida, para que tus clientes puedan acceder a ella en cualquier momento. Esto, por supuesto, a menos que tengas una razón específica para que se ejecute solo en ciertas situaciones, pero la mayoría de las veces quieres que esté constantemente en ejecución y **disponible**.
+
+### En un Servidor Remoto
+
+Cuando configuras un servidor remoto (un servidor en la nube, una máquina virtual, etc.) lo más sencillo que puedes hacer es usar `fastapi run` (que utiliza Uvicorn) o algo similar, manualmente, de la misma manera que lo haces al desarrollar localmente.
+
+Y funcionará y será útil **durante el desarrollo**.
+
+Pero si pierdes la conexión con el servidor, el **proceso en ejecución** probablemente morirá.
+
+Y si el servidor se reinicia (por ejemplo, después de actualizaciones o migraciones del proveedor de la nube) probablemente **no lo notarás**. Y debido a eso, ni siquiera sabrás que tienes que reiniciar el proceso manualmente. Así, tu API simplemente quedará muerta. 😱
+
+### Ejecutar Automáticamente al Iniciar
+
+En general, probablemente querrás que el programa del servidor (por ejemplo, Uvicorn) se inicie automáticamente al arrancar el servidor, y sin necesidad de ninguna **intervención humana**, para tener siempre un proceso en ejecución con tu API (por ejemplo, Uvicorn ejecutando tu aplicación FastAPI).
+
+### Programa Separado
+
+Para lograr esto, normalmente tendrás un **programa separado** que se asegurará de que tu aplicación se ejecute al iniciarse. Y en muchos casos, también se asegurará de que otros componentes o aplicaciones se ejecuten, por ejemplo, una base de datos.
+
+### Herramientas de Ejemplo para Ejecutar al Iniciar
+
+Algunos ejemplos de las herramientas que pueden hacer este trabajo son:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Docker en Modo Swarm
+* Systemd
+* Supervisor
+* Manejado internamente por un proveedor de nube como parte de sus servicios
+* Otros...
+
+Te daré más ejemplos concretos en los próximos capítulos.
+
+## Reinicios
+
+De manera similar a asegurarte de que tu aplicación se ejecute al iniciar, probablemente también quieras asegurarte de que se **reinicie** después de fallos.
+
+### Cometemos Errores
+
+Nosotros, como humanos, cometemos **errores**, todo el tiempo. El software casi *siempre* tiene **bugs** ocultos en diferentes lugares. 🐛
+
+Y nosotros, como desarrolladores, seguimos mejorando el código a medida que encontramos esos bugs y a medida que implementamos nuevas funcionalidades (posiblemente agregando nuevos bugs también 😅).
+
+### Errores Pequeños Manejados Automáticamente
+
+Al construir APIs web con FastAPI, si hay un error en nuestro código, FastAPI normalmente lo contiene a la solicitud única que desencadenó el error. 🛡
+
+El cliente obtendrá un **500 Internal Server Error** para esa solicitud, pero la aplicación continuará funcionando para las siguientes solicitudes en lugar de simplemente colapsar por completo.
+
+### Errores Mayores - Colapsos
+
+Sin embargo, puede haber casos en los que escribamos algún código que **colapse toda la aplicación** haciendo que Uvicorn y Python colapsen. 💥
+
+Y aún así, probablemente no querrías que la aplicación quede muerta porque hubo un error en un lugar, probablemente querrás que **siga ejecutándose** al menos para las *path operations* que no estén rotas.
+
+### Reiniciar Después del Colapso
+
+Pero en esos casos con errores realmente malos que colapsan el **proceso en ejecución**, querrías un componente externo encargado de **reiniciar** el proceso, al menos un par de veces...
+
+/// tip | Consejo
+
+...Aunque si la aplicación completa **colapsa inmediatamente**, probablemente no tenga sentido seguir reiniciándola eternamente. Pero en esos casos, probablemente lo notarás durante el desarrollo, o al menos justo después de la implementación.
+
+Así que enfoquémonos en los casos principales, donde podría colapsar por completo en algunos casos particulares **en el futuro**, y aún así tenga sentido reiniciarla.
+
+///
+
+Probablemente querrías que la cosa encargada de reiniciar tu aplicación sea un **componente externo**, porque para ese punto, la misma aplicación con Uvicorn y Python ya colapsó, así que no hay nada en el mismo código de la misma aplicación que pueda hacer algo al respecto.
+
+### Herramientas de Ejemplo para Reiniciar Automáticamente
+
+En la mayoría de los casos, la misma herramienta que se utiliza para **ejecutar el programa al iniciar** también se utiliza para manejar reinicios automáticos.
+
+Por ejemplo, esto podría ser manejado por:
+
+* Docker
+* Kubernetes
+* Docker Compose
+* Docker en Modo Swarm
+* Systemd
+* Supervisor
+* Manejado internamente por un proveedor de nube como parte de sus servicios
+* Otros...
+
+## Replicación - Procesos y Memoria
+
+Con una aplicación FastAPI, usando un programa servidor como el comando `fastapi` que ejecuta Uvicorn, ejecutarlo una vez en **un proceso** puede servir a múltiples clientes concurrentemente.
+
+Pero en muchos casos, querrás ejecutar varios worker processes al mismo tiempo.
+
+### Múltiples Procesos - Workers
+
+Si tienes más clientes de los que un solo proceso puede manejar (por ejemplo, si la máquina virtual no es muy grande) y tienes **múltiples núcleos** en la CPU del servidor, entonces podrías tener **múltiples procesos** ejecutando la misma aplicación al mismo tiempo, y distribuir todas las requests entre ellos.
+
+Cuando ejecutas **múltiples procesos** del mismo programa de API, comúnmente se les llama **workers**.
+
+### Worker Processes y Puertos
+
+Recuerda de la documentación [Sobre HTTPS](https.md){.internal-link target=_blank} que solo un proceso puede estar escuchando en una combinación de puerto y dirección IP en un servidor.
+
+Esto sigue siendo cierto.
+
+Así que, para poder tener **múltiples procesos** al mismo tiempo, tiene que haber un **solo proceso escuchando en un puerto** que luego transmita la comunicación a cada worker process de alguna forma.
+
+### Memoria por Proceso
+
+Ahora, cuando el programa carga cosas en memoria, por ejemplo, un modelo de machine learning en una variable, o el contenido de un archivo grande en una variable, todo eso **consume un poco de la memoria (RAM)** del servidor.
+
+Y múltiples procesos normalmente **no comparten ninguna memoria**. Esto significa que cada proceso en ejecución tiene sus propias cosas, variables y memoria. Y si estás consumiendo una gran cantidad de memoria en tu código, **cada proceso** consumirá una cantidad equivalente de memoria.
+
+### Memoria del Servidor
+
+Por ejemplo, si tu código carga un modelo de Machine Learning con **1 GB de tamaño**, cuando ejecutas un proceso con tu API, consumirá al menos 1 GB de RAM. Y si inicias **4 procesos** (4 workers), cada uno consumirá 1 GB de RAM. Así que, en total, tu API consumirá **4 GB de RAM**.
+
+Y si tu servidor remoto o máquina virtual solo tiene 3 GB de RAM, intentar cargar más de 4 GB de RAM causará problemas. 🚨
+
+### Múltiples Procesos - Un Ejemplo
+
+En este ejemplo, hay un **Proceso Administrador** que inicia y controla dos **Worker Processes**.
+
+Este Proceso Administrador probablemente sería el que escuche en el **puerto** en la IP. Y transmitirá toda la comunicación a los worker processes.
+
+Esos worker processes serían los que ejecutan tu aplicación, realizarían los cálculos principales para recibir un **request** y devolver un **response**, y cargarían cualquier cosa que pongas en variables en RAM.
+
+
+
+Y por supuesto, la misma máquina probablemente tendría **otros procesos** ejecutándose también, aparte de tu aplicación.
+
+Un detalle interesante es que el porcentaje de **CPU utilizado** por cada proceso puede **variar** mucho con el tiempo, pero la **memoria (RAM)** normalmente permanece más o menos **estable**.
+
+Si tienes una API que hace una cantidad comparable de cálculos cada vez y tienes muchos clientes, entonces la **utilización de CPU** probablemente *también sea estable* (en lugar de constantemente subir y bajar rápidamente).
+
+### Ejemplos de Herramientas y Estrategias de Replicación
+
+Puede haber varios enfoques para lograr esto, y te contaré más sobre estrategias específicas en los próximos capítulos, por ejemplo, al hablar sobre Docker y contenedores.
+
+La principal restricción a considerar es que tiene que haber un **componente único** manejando el **puerto** en la **IP pública**. Y luego debe tener una forma de **transmitir** la comunicación a los **procesos/workers** replicados.
+
+Aquí hay algunas combinaciones y estrategias posibles:
+
+* **Uvicorn** con `--workers`
+ * Un administrador de procesos de Uvicorn **escucharía** en la **IP** y **puerto**, y iniciaría **múltiples worker processes de Uvicorn**.
+* **Kubernetes** y otros sistemas de **contenedor distribuidos**
+ * Algo en la capa de **Kubernetes** escucharía en la **IP** y **puerto**. La replicación sería al tener **múltiples contenedores**, cada uno con **un proceso de Uvicorn** ejecutándose.
+* **Servicios en la Nube** que manejan esto por ti
+ * El servicio en la nube probablemente **manejará la replicación por ti**. Posiblemente te permitiría definir **un proceso para ejecutar**, o una **imagen de contenedor** para usar, en cualquier caso, lo más probable es que sería **un solo proceso de Uvicorn**, y el servicio en la nube se encargaría de replicarlo.
+
+/// tip | Consejo
+
+No te preocupes si algunos de estos elementos sobre **contenedores**, Docker, o Kubernetes no tienen mucho sentido todavía.
+
+Te contaré más sobre imágenes de contenedores, Docker, Kubernetes, etc. en un capítulo futuro: [FastAPI en Contenedores - Docker](docker.md){.internal-link target=_blank}.
+
+///
+
+## Pasos Previos Antes de Iniciar
+
+Hay muchos casos en los que quieres realizar algunos pasos **antes de iniciar** tu aplicación.
+
+Por ejemplo, podrías querer ejecutar **migraciones de base de datos**.
+
+Pero en la mayoría de los casos, querrás realizar estos pasos solo **una vez**.
+
+Así que, querrás tener un **único proceso** para realizar esos **pasos previos**, antes de iniciar la aplicación.
+
+Y tendrás que asegurarte de que sea un único proceso ejecutando esos pasos previos incluso si después, inicias **múltiples procesos** (múltiples workers) para la propia aplicación. Si esos pasos fueran ejecutados por **múltiples procesos**, **duplicarían** el trabajo al ejecutarlo en **paralelo**, y si los pasos fueran algo delicado como una migración de base de datos, podrían causar conflictos entre sí.
+
+Por supuesto, hay algunos casos en los que no hay problema en ejecutar los pasos previos múltiples veces, en ese caso, es mucho más fácil de manejar.
+
+/// tip | Consejo
+
+También, ten en cuenta que dependiendo de tu configuración, en algunos casos **quizás ni siquiera necesites realizar pasos previos** antes de iniciar tu aplicación.
+
+En ese caso, no tendrías que preocuparte por nada de esto. 🤷
+
+///
+
+### Ejemplos de Estrategias para Pasos Previos
+
+Esto **dependerá mucho** de la forma en que **implementarás tu sistema**, y probablemente estará conectado con la forma en que inicias programas, manejas reinicios, etc.
+
+Aquí hay algunas ideas posibles:
+
+* Un "Contenedor de Inicio" en Kubernetes que se ejecuta antes de tu contenedor de aplicación
+* Un script de bash que ejecuta los pasos previos y luego inicia tu aplicación
+ * Aún necesitarías una forma de iniciar/reiniciar *ese* script de bash, detectar errores, etc.
+
+/// tip | Consejo
+
+Te daré más ejemplos concretos para hacer esto con contenedores en un capítulo futuro: [FastAPI en Contenedores - Docker](docker.md){.internal-link target=_blank}.
+
+///
+
+## Utilización de Recursos
+
+Tu(s) servidor(es) es(son) un **recurso** que puedes consumir o **utilizar**, con tus programas, el tiempo de cómputo en las CPUs y la memoria RAM disponible.
+
+¿Cuánto de los recursos del sistema quieres consumir/utilizar? Podría ser fácil pensar "no mucho", pero en realidad, probablemente querrás consumir **lo más posible sin colapsar**.
+
+Si estás pagando por 3 servidores pero solo estás usando un poquito de su RAM y CPU, probablemente estés **desperdiciando dinero** 💸, y probablemente **desperdiciando la energía eléctrica del servidor** 🌎, etc.
+
+En ese caso, podría ser mejor tener solo 2 servidores y usar un mayor porcentaje de sus recursos (CPU, memoria, disco, ancho de banda de red, etc.).
+
+Por otro lado, si tienes 2 servidores y estás usando **100% de su CPU y RAM**, en algún momento un proceso pedirá más memoria y el servidor tendrá que usar el disco como "memoria" (lo cual puede ser miles de veces más lento), o incluso **colapsar**. O un proceso podría necesitar hacer algún cálculo y tendría que esperar hasta que la CPU esté libre de nuevo.
+
+En este caso, sería mejor obtener **un servidor extra** y ejecutar algunos procesos en él para que todos tengan **suficiente RAM y tiempo de CPU**.
+
+También existe la posibilidad de que, por alguna razón, tengas un **pico** de uso de tu API. Tal vez se volvió viral, o tal vez otros servicios o bots comienzan a usarla. Y podrías querer tener recursos extra para estar a salvo en esos casos.
+
+Podrías establecer un **número arbitrario** para alcanzar, por ejemplo, algo **entre 50% a 90%** de utilización de recursos. El punto es que esas son probablemente las principales cosas que querrás medir y usar para ajustar tus implementaciones.
+
+Puedes usar herramientas simples como `htop` para ver la CPU y RAM utilizadas en tu servidor o la cantidad utilizada por cada proceso. O puedes usar herramientas de monitoreo más complejas, que pueden estar distribuidas a través de servidores, etc.
+
+## Resumen
+
+Has estado leyendo aquí algunos de los conceptos principales que probablemente necesitarás tener en mente al decidir cómo implementar tu aplicación:
+
+* Seguridad - HTTPS
+* Ejecución al iniciar
+* Reinicios
+* Replicación (la cantidad de procesos en ejecución)
+* Memoria
+* Pasos previos antes de iniciar
+
+Comprender estas ideas y cómo aplicarlas debería darte la intuición necesaria para tomar decisiones al configurar y ajustar tus implementaciones. 🤓
+
+En las próximas secciones, te daré ejemplos más concretos de posibles estrategias que puedes seguir. 🚀
diff --git a/docs/es/docs/deployment/docker.md b/docs/es/docs/deployment/docker.md
new file mode 100644
index 000000000..3a39d3661
--- /dev/null
+++ b/docs/es/docs/deployment/docker.md
@@ -0,0 +1,620 @@
+# FastAPI en Contenedores - Docker
+
+Al desplegar aplicaciones de FastAPI, un enfoque común es construir una **imagen de contenedor de Linux**. Normalmente se realiza usando **Docker**. Luego puedes desplegar esa imagen de contenedor de varias formas.
+
+Usar contenedores de Linux tiene varias ventajas, incluyendo **seguridad**, **replicabilidad**, **simplicidad**, y otras.
+
+/// tip | Consejo
+
+¿Tienes prisa y ya conoces esto? Salta al [`Dockerfile` más abajo 👇](#construir-una-imagen-de-docker-para-fastapi).
+
+///
+
+
+Vista previa del 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 ["fastapi", "run", "app/main.py", "--port", "80"]
+
+# Si estás detrás de un proxy como Nginx o Traefik añade --proxy-headers
+# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
+```
+
+
+
+## Qué es un Contenedor
+
+Los contenedores (principalmente contenedores de Linux) son una forma muy **ligera** de empaquetar aplicaciones incluyendo todas sus dependencias y archivos necesarios, manteniéndolos aislados de otros contenedores (otras aplicaciones o componentes) en el mismo sistema.
+
+Los contenedores de Linux se ejecutan utilizando el mismo núcleo de Linux del host (máquina, máquina virtual, servidor en la nube, etc.). Esto significa que son muy ligeros (en comparación con las máquinas virtuales completas que emulan un sistema operativo completo).
+
+De esta forma, los contenedores consumen **pocos recursos**, una cantidad comparable a ejecutar los procesos directamente (una máquina virtual consumiría mucho más).
+
+Los contenedores también tienen sus propios procesos de ejecución **aislados** (normalmente solo un proceso), sistema de archivos y red, simplificando el despliegue, la seguridad, el desarrollo, etc.
+
+## Qué es una Imagen de Contenedor
+
+Un **contenedor** se ejecuta desde una **imagen de contenedor**.
+
+Una imagen de contenedor es una versión **estática** de todos los archivos, variables de entorno y el comando/programa por defecto que debería estar presente en un contenedor. **Estático** aquí significa que la imagen de contenedor **no se está ejecutando**, no está siendo ejecutada, son solo los archivos empaquetados y los metadatos.
+
+En contraste con una "**imagen de contenedor**" que son los contenidos estáticos almacenados, un "**contenedor**" normalmente se refiere a la instance en ejecución, lo que está siendo **ejecutado**.
+
+Cuando el **contenedor** se inicia y está en funcionamiento (iniciado a partir de una **imagen de contenedor**), puede crear o cambiar archivos, variables de entorno, etc. Esos cambios existirán solo en ese contenedor, pero no persistirán en la imagen de contenedor subyacente (no se guardarán en disco).
+
+Una imagen de contenedor es comparable al archivo de **programa** y sus contenidos, por ejemplo, `python` y algún archivo `main.py`.
+
+Y el **contenedor** en sí (en contraste con la **imagen de contenedor**) es la instance real en ejecución de la imagen, comparable a un **proceso**. De hecho, un contenedor solo se está ejecutando cuando tiene un **proceso en ejecución** (y normalmente es solo un proceso). El contenedor se detiene cuando no hay un proceso en ejecución en él.
+
+## Imágenes de Contenedor
+
+Docker ha sido una de las herramientas principales para crear y gestionar **imágenes de contenedor** y **contenedores**.
+
+Y hay un Docker Hub público con **imágenes de contenedores oficiales** pre-hechas para muchas herramientas, entornos, bases de datos y aplicaciones.
+
+Por ejemplo, hay una Imagen de Python oficial.
+
+Y hay muchas otras imágenes para diferentes cosas como bases de datos, por ejemplo para:
+
+* PostgreSQL
+* MySQL
+* MongoDB
+* Redis, etc.
+
+Usando una imagen de contenedor pre-hecha es muy fácil **combinar** y utilizar diferentes herramientas. Por ejemplo, para probar una nueva base de datos. En la mayoría de los casos, puedes usar las **imágenes oficiales**, y simplemente configurarlas con variables de entorno.
+
+De esta manera, en muchos casos puedes aprender sobre contenedores y Docker y reutilizar ese conocimiento con muchas herramientas y componentes diferentes.
+
+Así, ejecutarías **múltiples contenedores** con diferentes cosas, como una base de datos, una aplicación de Python, un servidor web con una aplicación frontend en React, y conectarlos entre sí a través de su red interna.
+
+Todos los sistemas de gestión de contenedores (como Docker o Kubernetes) tienen estas características de redes integradas en ellos.
+
+## Contenedores y Procesos
+
+Una **imagen de contenedor** normalmente incluye en sus metadatos el programa o comando por defecto que debería ser ejecutado cuando el **contenedor** se inicie y los parámetros que deben pasar a ese programa. Muy similar a lo que sería si estuviera en la línea de comandos.
+
+Cuando un **contenedor** se inicia, ejecutará ese comando/programa (aunque puedes sobrescribirlo y hacer que ejecute un comando/programa diferente).
+
+Un contenedor está en ejecución mientras el **proceso principal** (comando o programa) esté en ejecución.
+
+Un contenedor normalmente tiene un **proceso único**, pero también es posible iniciar subprocesos desde el proceso principal, y de esa manera tendrás **múltiples procesos** en el mismo contenedor.
+
+Pero no es posible tener un contenedor en ejecución sin **al menos un proceso en ejecución**. Si el proceso principal se detiene, el contenedor se detiene.
+
+## Construir una Imagen de Docker para FastAPI
+
+¡Bien, construyamos algo ahora! 🚀
+
+Te mostraré cómo construir una **imagen de Docker** para FastAPI **desde cero**, basada en la imagen **oficial de Python**.
+
+Esto es lo que querrías hacer en **la mayoría de los casos**, por ejemplo:
+
+* Usando **Kubernetes** o herramientas similares
+* Al ejecutar en un **Raspberry Pi**
+* Usando un servicio en la nube que ejecutaría una imagen de contenedor por ti, etc.
+
+### Requisitos del Paquete
+
+Normalmente tendrías los **requisitos del paquete** para tu aplicación en algún archivo.
+
+Dependería principalmente de la herramienta que uses para **instalar** esos requisitos.
+
+La forma más común de hacerlo es tener un archivo `requirements.txt` con los nombres de los paquetes y sus versiones, uno por línea.
+
+Por supuesto, usarías las mismas ideas que leíste en [Acerca de las versiones de FastAPI](versions.md){.internal-link target=_blank} para establecer los rangos de versiones.
+
+Por ejemplo, tu `requirements.txt` podría verse así:
+
+```
+fastapi[standard]>=0.113.0,<0.114.0
+pydantic>=2.7.0,<3.0.0
+```
+
+Y normalmente instalarías esas dependencias de los paquetes con `pip`, por ejemplo:
+
+
+
+/// info | Información
+
+Existen otros formatos y herramientas para definir e instalar dependencias de paquetes.
+
+///
+
+### Crear el Código de **FastAPI**
+
+* Crea un directorio `app` y entra en él.
+* Crea un archivo vacío `__init__.py`.
+* Crea un archivo `main.py` con:
+
+```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
+
+Ahora, en el mismo directorio del proyecto, crea un archivo `Dockerfile` con:
+
+```{ .dockerfile .annotate }
+# (1)!
+FROM python:3.9
+
+# (2)!
+WORKDIR /code
+
+# (3)!
+COPY ./requirements.txt /code/requirements.txt
+
+# (4)!
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (5)!
+COPY ./app /code/app
+
+# (6)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+```
+
+1. Comenzar desde la imagen base oficial de Python.
+
+2. Establecer el directorio de trabajo actual a `/code`.
+
+ Aquí es donde pondremos el archivo `requirements.txt` y el directorio `app`.
+
+3. Copiar el archivo con los requisitos al directorio `/code`.
+
+ Copiar **solo** el archivo con los requisitos primero, no el resto del código.
+
+ Como este archivo **no cambia a menudo**, Docker lo detectará y usará la **caché** para este paso, habilitando la caché para el siguiente paso también.
+
+4. Instalar las dependencias de los paquetes en el archivo de requisitos.
+
+ La opción `--no-cache-dir` le dice a `pip` que no guarde los paquetes descargados localmente, ya que eso solo sería si `pip` fuese a ejecutarse de nuevo para instalar los mismos paquetes, pero ese no es el caso al trabajar con contenedores.
+
+ /// note | Nota
+
+ El `--no-cache-dir` está relacionado solo con `pip`, no tiene nada que ver con Docker o contenedores.
+
+ ///
+
+ La opción `--upgrade` le dice a `pip` que actualice los paquetes si ya están instalados.
+
+ Debido a que el paso anterior de copiar el archivo podría ser detectado por la **caché de Docker**, este paso también **usará la caché de Docker** cuando esté disponible.
+
+ Usar la caché en este paso te **ahorrará** mucho **tiempo** al construir la imagen una y otra vez durante el desarrollo, en lugar de **descargar e instalar** todas las dependencias **cada vez**.
+
+5. Copiar el directorio `./app` dentro del directorio `/code`.
+
+ Como esto contiene todo el código, que es lo que **cambia con más frecuencia**, la **caché de Docker** no se utilizará para este u otros **pasos siguientes** fácilmente.
+
+ Así que es importante poner esto **cerca del final** del `Dockerfile`, para optimizar los tiempos de construcción de la imagen del contenedor.
+
+6. Establecer el **comando** para usar `fastapi run`, que utiliza Uvicorn debajo.
+
+ `CMD` toma una lista de cadenas, cada una de estas cadenas es lo que escribirías en la línea de comandos separado por espacios.
+
+ Este comando se ejecutará desde el **directorio de trabajo actual**, el mismo directorio `/code` que estableciste antes con `WORKDIR /code`.
+
+/// tip | Consejo
+
+Revisa qué hace cada línea haciendo clic en cada número en la burbuja del código. 👆
+
+///
+
+/// warning | Advertencia
+
+Asegúrate de **siempre** usar la **forma exec** de la instrucción `CMD`, como se explica a continuación.
+
+///
+
+#### Usar `CMD` - Forma Exec
+
+La instrucción Docker `CMD` se puede escribir usando dos formas:
+
+✅ **Forma Exec**:
+
+```Dockerfile
+# ✅ Haz esto
+CMD ["fastapi", "run", "app/main.py", "--port", "80"]
+```
+
+⛔️ **Forma Shell**:
+
+```Dockerfile
+# ⛔️ No hagas esto
+CMD fastapi run app/main.py --port 80
+```
+
+Asegúrate de siempre usar la **forma exec** para garantizar que FastAPI pueda cerrarse de manera adecuada y que [los eventos de lifespan](../advanced/events.md){.internal-link target=_blank} sean disparados.
+
+Puedes leer más sobre esto en las documentación de Docker para formas de shell y exec.
+
+Esto puede ser bastante notorio al usar `docker compose`. Consulta esta sección de preguntas frecuentes de Docker Compose para más detalles técnicos: ¿Por qué mis servicios tardan 10 segundos en recrearse o detenerse?.
+
+#### Estructura de Directorios
+
+Ahora deberías tener una estructura de directorios como:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+├── Dockerfile
+└── requirements.txt
+```
+
+#### Detrás de un Proxy de Terminación TLS
+
+Si estás ejecutando tu contenedor detrás de un Proxy de Terminación TLS (load balancer) como Nginx o Traefik, añade la opción `--proxy-headers`, esto le dirá a Uvicorn (a través de la CLI de FastAPI) que confíe en los headers enviados por ese proxy indicando que la aplicación se está ejecutando detrás de HTTPS, etc.
+
+```Dockerfile
+CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
+```
+
+#### Cache de Docker
+
+Hay un truco importante en este `Dockerfile`, primero copiamos **el archivo con las dependencias solo**, no el resto del código. Déjame decirte por qué es así.
+
+```Dockerfile
+COPY ./requirements.txt /code/requirements.txt
+```
+
+Docker y otras herramientas **construyen** estas imágenes de contenedor **incrementalmente**, añadiendo **una capa sobre la otra**, empezando desde la parte superior del `Dockerfile` y añadiendo cualquier archivo creado por cada una de las instrucciones del `Dockerfile`.
+
+Docker y herramientas similares también usan una **caché interna** al construir la imagen, si un archivo no ha cambiado desde la última vez que se construyó la imagen del contenedor, entonces reutilizará la misma capa creada la última vez, en lugar de copiar el archivo de nuevo y crear una nueva capa desde cero.
+
+Solo evitar copiar archivos no mejora necesariamente las cosas mucho, pero porque se usó la caché para ese paso, puede **usar la caché para el siguiente paso**. Por ejemplo, podría usar la caché para la instrucción que instala las dependencias con:
+
+```Dockerfile
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+```
+
+El archivo con los requisitos de los paquetes **no cambiará con frecuencia**. Así que, al copiar solo ese archivo, Docker podrá **usar la caché** para ese paso.
+
+Y luego, Docker podrá **usar la caché para el siguiente paso** que descarga e instala esas dependencias. Y aquí es donde **ahorramos mucho tiempo**. ✨ ...y evitamos el aburrimiento de esperar. 😪😆
+
+Descargar e instalar las dependencias de los paquetes **podría llevar minutos**, pero usando la **caché** tomaría **segundos** como máximo.
+
+Y como estarías construyendo la imagen del contenedor una y otra vez durante el desarrollo para comprobar que los cambios en tu código funcionan, hay una gran cantidad de tiempo acumulado que te ahorrarías.
+
+Luego, cerca del final del `Dockerfile`, copiamos todo el código. Como esto es lo que **cambia con más frecuencia**, lo ponemos cerca del final, porque casi siempre, cualquier cosa después de este paso no podrá usar la caché.
+
+```Dockerfile
+COPY ./app /code/app
+```
+
+### Construir la Imagen de Docker
+
+Ahora que todos los archivos están en su lugar, vamos a construir la imagen del contenedor.
+
+* Ve al directorio del proyecto (donde está tu `Dockerfile`, conteniendo tu directorio `app`).
+* Construye tu imagen de FastAPI:
+
+
+
+/// tip | Consejo
+
+Fíjate en el `.` al final, es equivalente a `./`, le indica a Docker el directorio a usar para construir la imagen del contenedor.
+
+En este caso, es el mismo directorio actual (`.`).
+
+///
+
+### Iniciar el Contenedor Docker
+
+* Ejecuta un contenedor basado en tu imagen:
+
+
+
+## Revísalo
+
+Deberías poder revisarlo en la URL de tu contenedor de Docker, por ejemplo: http://192.168.99.100/items/5?q=somequery o http://127.0.0.1/items/5?q=somequery (o equivalente, usando tu host de Docker).
+
+Verás algo como:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+## Documentación Interactiva de la API
+
+Ahora puedes ir a http://192.168.99.100/docs o http://127.0.0.1/docs (o equivalente, usando tu host de Docker).
+
+Verás la documentación interactiva automática de la API (proporcionada por Swagger UI):
+
+
+
+## Documentación Alternativa de la API
+
+Y también puedes ir a http://192.168.99.100/redoc o http://127.0.0.1/redoc (o equivalente, usando tu host de Docker).
+
+Verás la documentación alternativa automática (proporcionada por ReDoc):
+
+
+
+## Construir una Imagen de Docker con un FastAPI de Un Solo Archivo
+
+Si tu FastAPI es un solo archivo, por ejemplo, `main.py` sin un directorio `./app`, tu estructura de archivos podría verse así:
+
+```
+.
+├── Dockerfile
+├── main.py
+└── requirements.txt
+```
+
+Entonces solo tendrías que cambiar las rutas correspondientes para copiar el archivo dentro del `Dockerfile`:
+
+```{ .dockerfile .annotate hl_lines="10 13" }
+FROM python:3.9
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+# (1)!
+COPY ./main.py /code/
+
+# (2)!
+CMD ["fastapi", "run", "main.py", "--port", "80"]
+```
+
+1. Copia el archivo `main.py` directamente al directorio `/code` (sin ningún directorio `./app`).
+
+2. Usa `fastapi run` para servir tu aplicación en el archivo único `main.py`.
+
+Cuando pasas el archivo a `fastapi run`, detectará automáticamente que es un archivo único y no parte de un paquete y sabrá cómo importarlo y servir tu aplicación FastAPI. 😎
+
+## Conceptos de Despliegue
+
+Hablemos nuevamente de algunos de los mismos [Conceptos de Despliegue](concepts.md){.internal-link target=_blank} en términos de contenedores.
+
+Los contenedores son principalmente una herramienta para simplificar el proceso de **construcción y despliegue** de una aplicación, pero no imponen un enfoque particular para manejar estos **conceptos de despliegue**, y hay varias estrategias posibles.
+
+La **buena noticia** es que con cada estrategia diferente hay una forma de cubrir todos los conceptos de despliegue. 🎉
+
+Revisemos estos **conceptos de despliegue** en términos de contenedores:
+
+* HTTPS
+* Ejecutar en el inicio
+* Reinicios
+* Replicación (el número de procesos en ejecución)
+* Memoria
+* Pasos previos antes de comenzar
+
+## HTTPS
+
+Si nos enfocamos solo en la **imagen de contenedor** para una aplicación FastAPI (y luego el **contenedor** en ejecución), HTTPS normalmente sería manejado **externamente** por otra herramienta.
+
+Podría ser otro contenedor, por ejemplo, con Traefik, manejando **HTTPS** y la adquisición **automática** de **certificados**.
+
+/// tip | Consejo
+
+Traefik tiene integraciones con Docker, Kubernetes, y otros, por lo que es muy fácil configurar y configurar HTTPS para tus contenedores con él.
+
+///
+
+Alternativamente, HTTPS podría ser manejado por un proveedor de la nube como uno de sus servicios (mientras que la aplicación aún se ejecuta en un contenedor).
+
+## Ejecutar en el Inicio y Reinicios
+
+Normalmente hay otra herramienta encargada de **iniciar y ejecutar** tu contenedor.
+
+Podría ser **Docker** directamente, **Docker Compose**, **Kubernetes**, un **servicio en la nube**, etc.
+
+En la mayoría (o todas) de las casos, hay una opción sencilla para habilitar la ejecución del contenedor al inicio y habilitar los reinicios en caso de fallos. Por ejemplo, en Docker, es la opción de línea de comandos `--restart`.
+
+Sin usar contenedores, hacer que las aplicaciones se ejecuten al inicio y con reinicios puede ser engorroso y difícil. Pero al **trabajar con contenedores** en la mayoría de los casos, esa funcionalidad se incluye por defecto. ✨
+
+## Replicación - Número de Procesos
+
+Si tienes un cluster de máquinas con **Kubernetes**, Docker Swarm Mode, Nomad, u otro sistema complejo similar para gestionar contenedores distribuidos en varias máquinas, entonces probablemente querrás manejar la **replicación** a nivel de **cluster** en lugar de usar un **gestor de procesos** (como Uvicorn con workers) en cada contenedor.
+
+Uno de esos sistemas de gestión de contenedores distribuidos como Kubernetes normalmente tiene alguna forma integrada de manejar la **replicación de contenedores** mientras aún soporta el **load balancing** para las requests entrantes. Todo a nivel de **cluster**.
+
+En esos casos, probablemente desearías construir una **imagen de Docker desde cero** como se [explica arriba](#dockerfile), instalando tus dependencias, y ejecutando **un solo proceso de Uvicorn** en lugar de usar múltiples workers de Uvicorn.
+
+### Load Balancer
+
+Al usar contenedores, normalmente tendrías algún componente **escuchando en el puerto principal**. Podría posiblemente ser otro contenedor que es también un **Proxy de Terminación TLS** para manejar **HTTPS** o alguna herramienta similar.
+
+Como este componente tomaría la **carga** de las requests y las distribuiría entre los workers de una manera (esperablemente) **balanceada**, también se le llama comúnmente **Load Balancer**.
+
+/// tip | Consejo
+
+El mismo componente **Proxy de Terminación TLS** usado para HTTPS probablemente también sería un **Load Balancer**.
+
+///
+
+Y al trabajar con contenedores, el mismo sistema que usas para iniciarlos y gestionarlos ya tendría herramientas internas para transmitir la **comunicación en red** (e.g., requests HTTP) desde ese **load balancer** (que también podría ser un **Proxy de Terminación TLS**) a los contenedores con tu aplicación.
+
+### Un Load Balancer - Múltiples Contenedores Worker
+
+Al trabajar con **Kubernetes** u otros sistemas de gestión de contenedores distribuidos similares, usar sus mecanismos de red internos permitiría que el único **load balancer** que está escuchando en el **puerto** principal transmita la comunicación (requests) a posiblemente **múltiples contenedores** ejecutando tu aplicación.
+
+Cada uno de estos contenedores ejecutando tu aplicación normalmente tendría **solo un proceso** (e.g., un proceso Uvicorn ejecutando tu aplicación FastAPI). Todos serían **contenedores idénticos**, ejecutando lo mismo, pero cada uno con su propio proceso, memoria, etc. De esa forma, aprovecharías la **paralelización** en **diferentes núcleos** de la CPU, o incluso en **diferentes máquinas**.
+
+Y el sistema de contenedores distribuido con el **load balancer** **distribuiría las requests** a cada uno de los contenedores **replicados** que ejecutan tu aplicación **en turnos**. Así, cada request podría ser manejado por uno de los múltiples **contenedores replicados** ejecutando tu aplicación.
+
+Y normalmente este **load balancer** podría manejar requests que vayan a *otras* aplicaciones en tu cluster (p. ej., a un dominio diferente, o bajo un prefijo de ruta de URL diferente), y transmitiría esa comunicación a los contenedores correctos para *esa otra* aplicación ejecutándose en tu cluster.
+
+### Un Proceso por Contenedor
+
+En este tipo de escenario, probablemente querrías tener **un solo proceso (Uvicorn) por contenedor**, ya que ya estarías manejando la replicación a nivel de cluster.
+
+Así que, en este caso, **no** querrías tener múltiples workers en el contenedor, por ejemplo, con la opción de línea de comandos `--workers`. Querrías tener solo un **proceso Uvicorn por contenedor** (pero probablemente múltiples contenedores).
+
+Tener otro gestor de procesos dentro del contenedor (como sería con múltiples workers) solo añadiría **complejidad innecesaria** que probablemente ya estés manejando con tu sistema de cluster.
+
+### Contenedores con Múltiples Procesos y Casos Especiales
+
+Por supuesto, hay **casos especiales** donde podrías querer tener **un contenedor** con varios **worker processes de Uvicorn** dentro.
+
+En esos casos, puedes usar la opción de línea de comandos `--workers` para establecer el número de workers que deseas ejecutar:
+
+```{ .dockerfile .annotate }
+FROM python:3.9
+
+WORKDIR /code
+
+COPY ./requirements.txt /code/requirements.txt
+
+RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
+
+COPY ./app /code/app
+
+# (1)!
+CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
+```
+
+1. Aquí usamos la opción de línea de comandos `--workers` para establecer el número de workers a 4.
+
+Aquí hay algunos ejemplos de cuándo eso podría tener sentido:
+
+#### Una Aplicación Simple
+
+Podrías querer un gestor de procesos en el contenedor si tu aplicación es **lo suficientemente simple** que pueda ejecutarse en un **servidor único**, no un cluster.
+
+#### Docker Compose
+
+Podrías estar desplegando en un **servidor único** (no un cluster) con **Docker Compose**, por lo que no tendrías una forma fácil de gestionar la replicación de contenedores (con Docker Compose) mientras se preserva la red compartida y el **load balancing**.
+
+Entonces podrías querer tener **un solo contenedor** con un **gestor de procesos** iniciando **varios worker processes** dentro.
+
+---
+
+El punto principal es que, **ninguna** de estas son **reglas escritas en piedra** que debas seguir a ciegas. Puedes usar estas ideas para **evaluar tu propio caso de uso** y decidir cuál es el mejor enfoque para tu sistema, verificando cómo gestionar los conceptos de:
+
+* Seguridad - HTTPS
+* Ejecutar en el inicio
+* Reinicios
+* Replicación (el número de procesos en ejecución)
+* Memoria
+* Pasos previos antes de comenzar
+
+## Memoria
+
+Si ejecutas **un solo proceso por contenedor**, tendrás una cantidad de memoria más o menos bien definida, estable y limitada consumida por cada uno de esos contenedores (más de uno si están replicados).
+
+Y luego puedes establecer esos mismos límites de memoria y requisitos en tus configuraciones para tu sistema de gestión de contenedores (por ejemplo, en **Kubernetes**). De esa manera, podrá **replicar los contenedores** en las **máquinas disponibles** teniendo en cuenta la cantidad de memoria necesaria por ellos, y la cantidad disponible en las máquinas en el cluster.
+
+Si tu aplicación es **simple**, probablemente esto **no será un problema**, y puede que no necesites especificar límites de memoria estrictos. Pero si estás **usando mucha memoria** (por ejemplo, con modelos de **Machine Learning**), deberías verificar cuánta memoria estás consumiendo y ajustar el **número de contenedores** que se ejecutan en **cada máquina** (y tal vez agregar más máquinas a tu cluster).
+
+Si ejecutas **múltiples procesos por contenedor**, tendrás que asegurarte de que el número de procesos iniciados no **consuma más memoria** de la que está disponible.
+
+## Pasos Previos Antes de Comenzar y Contenedores
+
+Si estás usando contenedores (por ejemplo, Docker, Kubernetes), entonces hay dos enfoques principales que puedes usar.
+
+### Múltiples Contenedores
+
+Si tienes **múltiples contenedores**, probablemente cada uno ejecutando un **proceso único** (por ejemplo, en un cluster de **Kubernetes**), entonces probablemente querrías tener un **contenedor separado** realizando el trabajo de los **pasos previos** en un solo contenedor, ejecutando un solo proceso, **antes** de ejecutar los contenedores worker replicados.
+
+/// info | Información
+
+Si estás usando Kubernetes, probablemente sería un Contenedor de Inicialización.
+
+///
+
+Si en tu caso de uso no hay problema en ejecutar esos pasos previos **múltiples veces en paralelo** (por ejemplo, si no estás ejecutando migraciones de base de datos, sino simplemente verificando si la base de datos está lista), entonces también podrías simplemente ponerlos en cada contenedor justo antes de iniciar el proceso principal.
+
+### Un Contenedor Único
+
+Si tienes una configuración simple, con un **contenedor único** que luego inicia múltiples **worker processes** (o también solo un proceso), entonces podrías ejecutar esos pasos previos en el mismo contenedor, justo antes de iniciar el proceso con la aplicación.
+
+### Imagen Base de Docker
+
+Solía haber una imagen official de Docker de FastAPI: tiangolo/uvicorn-gunicorn-fastapi. Pero ahora está obsoleta. ⛔️
+
+Probablemente **no** deberías usar esta imagen base de Docker (o cualquier otra similar).
+
+Si estás usando **Kubernetes** (u otros) y ya estás configurando la **replicación** a nivel de cluster, con múltiples **contenedores**. En esos casos, es mejor que **construyas una imagen desde cero** como se describe arriba: [Construir una Imagen de Docker para FastAPI](#build-a-docker-image-for-fastapi).
+
+Y si necesitas tener múltiples workers, puedes simplemente utilizar la opción de línea de comandos `--workers`.
+
+/// note | Detalles Técnicos
+
+La imagen de Docker se creó cuando Uvicorn no soportaba gestionar y reiniciar workers muertos, por lo que era necesario usar Gunicorn con Uvicorn, lo que añadía bastante complejidad, solo para que Gunicorn gestionara y reiniciara los worker processes de Uvicorn.
+
+Pero ahora que Uvicorn (y el comando `fastapi`) soportan el uso de `--workers`, no hay razón para utilizar una imagen base de Docker en lugar de construir la tuya propia (es prácticamente la misma cantidad de código 😅).
+
+///
+
+## Desplegar la Imagen del Contenedor
+
+Después de tener una Imagen de Contenedor (Docker) hay varias maneras de desplegarla.
+
+Por ejemplo:
+
+* Con **Docker Compose** en un servidor único
+* Con un cluster de **Kubernetes**
+* Con un cluster de Docker Swarm Mode
+* Con otra herramienta como Nomad
+* Con un servicio en la nube que tome tu imagen de contenedor y la despliegue
+
+## Imagen de Docker con `uv`
+
+Si estás usando uv para instalar y gestionar tu proyecto, puedes seguir su guía de Docker de uv.
+
+## Resumen
+
+Usando sistemas de contenedores (por ejemplo, con **Docker** y **Kubernetes**) se vuelve bastante sencillo manejar todos los **conceptos de despliegue**:
+
+* HTTPS
+* Ejecutar en el inicio
+* Reinicios
+* Replicación (el número de procesos en ejecución)
+* Memoria
+* Pasos previos antes de comenzar
+
+En la mayoría de los casos, probablemente no querrás usar ninguna imagen base, y en su lugar **construir una imagen de contenedor desde cero** basada en la imagen oficial de Docker de Python.
+
+Teniendo en cuenta el **orden** de las instrucciones en el `Dockerfile` y la **caché de Docker** puedes **minimizar los tiempos de construcción**, para maximizar tu productividad (y evitar el aburrimiento). 😎
diff --git a/docs/es/docs/deployment/https.md b/docs/es/docs/deployment/https.md
new file mode 100644
index 000000000..3ccb5dc47
--- /dev/null
+++ b/docs/es/docs/deployment/https.md
@@ -0,0 +1,199 @@
+# Sobre HTTPS
+
+Es fácil asumir que HTTPS es algo que simplemente está "activado" o no.
+
+Pero es mucho más complejo que eso.
+
+/// tip | Consejo
+
+Si tienes prisa o no te importa, continúa con las siguientes secciones para ver instrucciones paso a paso para configurar todo con diferentes técnicas.
+
+///
+
+Para **aprender los conceptos básicos de HTTPS**, desde una perspectiva de consumidor, revisa https://howhttps.works/.
+
+Ahora, desde una **perspectiva de desarrollador**, aquí hay varias cosas a tener en cuenta al pensar en HTTPS:
+
+* Para HTTPS, **el servidor** necesita **tener "certificados"** generados por un **tercero**.
+ * Esos certificados en realidad son **adquiridos** del tercero, no "generados".
+* Los certificados tienen una **vida útil**.
+ * Ellos **expiran**.
+ * Y luego necesitan ser **renovados**, **adquiridos nuevamente** del tercero.
+* La encriptación de la conexión ocurre a nivel de **TCP**.
+ * Esa es una capa **debajo de HTTP**.
+ * Por lo tanto, el manejo de **certificados y encriptación** se realiza **antes de HTTP**.
+* **TCP no sabe acerca de "dominios"**. Solo sobre direcciones IP.
+ * La información sobre el **dominio específico** solicitado va en los **datos HTTP**.
+* Los **certificados HTTPS** "certifican" un **cierto dominio**, pero el protocolo y la encriptación ocurren a nivel de TCP, **antes de saber** con cuál dominio se está tratando.
+* **Por defecto**, eso significaría que solo puedes tener **un certificado HTTPS por dirección IP**.
+ * No importa cuán grande sea tu servidor o qué tan pequeña pueda ser cada aplicación que tengas en él.
+ * Sin embargo, hay una **solución** para esto.
+* Hay una **extensión** para el protocolo **TLS** (el que maneja la encriptación a nivel de TCP, antes de HTTP) llamada **SNI**.
+ * Esta extensión SNI permite que un solo servidor (con una **sola dirección IP**) tenga **varios certificados HTTPS** y sirva **múltiples dominios/aplicaciones HTTPS**.
+ * Para que esto funcione, un componente (programa) **único** que se ejecute en el servidor, escuchando en la **dirección IP pública**, debe tener **todos los certificados HTTPS** en el servidor.
+* **Después** de obtener una conexión segura, el protocolo de comunicación sigue siendo **HTTP**.
+ * Los contenidos están **encriptados**, aunque se envién con el **protocolo HTTP**.
+
+Es una práctica común tener **un programa/servidor HTTP** ejecutándose en el servidor (la máquina, host, etc.) y **gestionando todas las partes de HTTPS**: recibiendo los **requests HTTPS encriptados**, enviando los **requests HTTP desencriptados** a la aplicación HTTP real que se ejecuta en el mismo servidor (la aplicación **FastAPI**, en este caso), tomando el **response HTTP** de la aplicación, **encriptándolo** usando el **certificado HTTPS** adecuado y enviándolo de vuelta al cliente usando **HTTPS**. Este servidor a menudo se llama un **TLS Termination Proxy**.
+
+Algunas de las opciones que podrías usar como un TLS Termination Proxy son:
+
+* Traefik (que también puede manejar la renovación de certificados)
+* Caddy (que también puede manejar la renovación de certificados)
+* Nginx
+* HAProxy
+
+## Let's Encrypt
+
+Antes de Let's Encrypt, estos **certificados HTTPS** eran vendidos por terceros.
+
+El proceso para adquirir uno de estos certificados solía ser complicado, requerir bastante papeleo y los certificados eran bastante costosos.
+
+Pero luego se creó **Let's Encrypt**.
+
+Es un proyecto de la Linux Foundation. Proporciona **certificados HTTPS de forma gratuita**, de manera automatizada. Estos certificados usan toda la seguridad criptográfica estándar, y tienen una corta duración (aproximadamente 3 meses), por lo que la **seguridad es en realidad mejor** debido a su corta vida útil.
+
+Los dominios son verificados de manera segura y los certificados se generan automáticamente. Esto también permite automatizar la renovación de estos certificados.
+
+La idea es automatizar la adquisición y renovación de estos certificados para que puedas tener **HTTPS seguro, gratuito, para siempre**.
+
+## HTTPS para Desarrolladores
+
+Aquí tienes un ejemplo de cómo podría ser una API HTTPS, paso a paso, prestando atención principalmente a las ideas importantes para los desarrolladores.
+
+### Nombre de Dominio
+
+Probablemente todo comenzaría adquiriendo un **nombre de dominio**. Luego, lo configurarías en un servidor DNS (posiblemente tu mismo proveedor de la nube).
+
+Probablemente conseguirías un servidor en la nube (una máquina virtual) o algo similar, y tendría una **dirección IP pública** fija.
+
+En el/los servidor(es) DNS configurarías un registro (un "`A record`") para apuntar **tu dominio** a la **dirección IP pública de tu servidor**.
+
+Probablemente harías esto solo una vez, la primera vez, al configurar todo.
+
+/// tip | Consejo
+
+Esta parte del Nombre de Dominio es mucho antes de HTTPS, pero como todo depende del dominio y la dirección IP, vale la pena mencionarlo aquí.
+
+///
+
+### DNS
+
+Ahora centrémonos en todas las partes realmente de HTTPS.
+
+Primero, el navegador consultaría con los **servidores DNS** cuál es la **IP del dominio**, en este caso, `someapp.example.com`.
+
+Los servidores DNS le dirían al navegador que use una **dirección IP** específica. Esa sería la dirección IP pública utilizada por tu servidor, que configuraste en los servidores DNS.
+
+
+
+### Inicio del Handshake TLS
+
+El navegador luego se comunicaría con esa dirección IP en el **puerto 443** (el puerto HTTPS).
+
+La primera parte de la comunicación es solo para establecer la conexión entre el cliente y el servidor y decidir las claves criptográficas que usarán, etc.
+
+
+
+Esta interacción entre el cliente y el servidor para establecer la conexión TLS se llama **handshake TLS**.
+
+### TLS con Extensión SNI
+
+**Solo un proceso** en el servidor puede estar escuchando en un **puerto** específico en una **dirección IP** específica. Podría haber otros procesos escuchando en otros puertos en la misma dirección IP, pero solo uno para cada combinación de dirección IP y puerto.
+
+TLS (HTTPS) utiliza el puerto específico `443` por defecto. Así que ese es el puerto que necesitaríamos.
+
+Como solo un proceso puede estar escuchando en este puerto, el proceso que lo haría sería el **TLS Termination Proxy**.
+
+El TLS Termination Proxy tendría acceso a uno o más **certificados TLS** (certificados HTTPS).
+
+Usando la **extensión SNI** discutida anteriormente, el TLS Termination Proxy verificaría cuál de los certificados TLS (HTTPS) disponibles debería usar para esta conexión, usando el que coincida con el dominio esperado por el cliente.
+
+En este caso, usaría el certificado para `someapp.example.com`.
+
+
+
+El cliente ya **confía** en la entidad que generó ese certificado TLS (en este caso Let's Encrypt, pero lo veremos más adelante), por lo que puede **verificar** que el certificado sea válido.
+
+Luego, usando el certificado, el cliente y el TLS Termination Proxy **deciden cómo encriptar** el resto de la **comunicación TCP**. Esto completa la parte de **Handshake TLS**.
+
+Después de esto, el cliente y el servidor tienen una **conexión TCP encriptada**, esto es lo que proporciona TLS. Y luego pueden usar esa conexión para iniciar la comunicación **HTTP real**.
+
+Y eso es lo que es **HTTPS**, es simplemente HTTP simple **dentro de una conexión TLS segura** en lugar de una conexión TCP pura (sin encriptar).
+
+/// tip | Consejo
+
+Ten en cuenta que la encriptación de la comunicación ocurre a nivel de **TCP**, no a nivel de HTTP.
+
+///
+
+### Request HTTPS
+
+Ahora que el cliente y el servidor (específicamente el navegador y el TLS Termination Proxy) tienen una **conexión TCP encriptada**, pueden iniciar la **comunicación HTTP**.
+
+Así que, el cliente envía un **request HTTPS**. Esto es simplemente un request HTTP a través de una conexión TLS encriptada.
+
+
+
+### Desencriptar el Request
+
+El TLS Termination Proxy usaría la encriptación acordada para **desencriptar el request**, y transmitiría el **request HTTP simple (desencriptado)** al proceso que ejecuta la aplicación (por ejemplo, un proceso con Uvicorn ejecutando la aplicación FastAPI).
+
+
+
+### Response HTTP
+
+La aplicación procesaría el request y enviaría un **response HTTP simple (sin encriptar)** al TLS Termination Proxy.
+
+
+
+### Response HTTPS
+
+El TLS Termination Proxy entonces **encriptaría el response** usando la criptografía acordada antes (que comenzó con el certificado para `someapp.example.com`), y lo enviaría de vuelta al navegador.
+
+Luego, el navegador verificaría que el response sea válido y encriptado con la clave criptográfica correcta, etc. Entonces **desencriptaría el response** y lo procesaría.
+
+
+
+El cliente (navegador) sabrá que el response proviene del servidor correcto porque está utilizando la criptografía que acordaron usando el **certificado HTTPS** anteriormente.
+
+### Múltiples Aplicaciones
+
+En el mismo servidor (o servidores), podrían haber **múltiples aplicaciones**, por ejemplo, otros programas API o una base de datos.
+
+Solo un proceso puede estar gestionando la IP y puerto específica (el TLS Termination Proxy en nuestro ejemplo) pero las otras aplicaciones/procesos pueden estar ejecutándose en el/los servidor(es) también, siempre y cuando no intenten usar la misma **combinación de IP pública y puerto**.
+
+
+
+De esa manera, el TLS Termination Proxy podría gestionar HTTPS y certificados para **múltiples dominios**, para múltiples aplicaciones, y luego transmitir los requests a la aplicación correcta en cada caso.
+
+### Renovación de Certificados
+
+En algún momento en el futuro, cada certificado **expiraría** (alrededor de 3 meses después de haberlo adquirido).
+
+Y entonces, habría otro programa (en algunos casos es otro programa, en algunos casos podría ser el mismo TLS Termination Proxy) que hablaría con Let's Encrypt y renovaría el/los certificado(s).
+
+
+
+Los **certificados TLS** están **asociados con un nombre de dominio**, no con una dirección IP.
+
+Entonces, para renovar los certificados, el programa de renovación necesita **probar** a la autoridad (Let's Encrypt) que de hecho **"posee" y controla ese dominio**.
+
+Para hacer eso, y para acomodar diferentes necesidades de aplicaciones, hay varias formas en que puede hacerlo. Algunas formas populares son:
+
+* **Modificar algunos registros DNS**.
+ * Para esto, el programa de renovación necesita soportar las API del proveedor de DNS, por lo que, dependiendo del proveedor de DNS que estés utilizando, esto podría o no ser una opción.
+* **Ejecutarse como un servidor** (al menos durante el proceso de adquisición del certificado) en la dirección IP pública asociada con el dominio.
+ * Como dijimos anteriormente, solo un proceso puede estar escuchando en una IP y puerto específicos.
+ * Esta es una de las razones por las que es muy útil cuando el mismo TLS Termination Proxy también se encarga del proceso de renovación del certificado.
+ * De lo contrario, podrías tener que detener momentáneamente el TLS Termination Proxy, iniciar el programa de renovación para adquirir los certificados, luego configurarlos con el TLS Termination Proxy, y luego reiniciar el TLS Termination Proxy. Esto no es ideal, ya que tus aplicaciones no estarán disponibles durante el tiempo que el TLS Termination Proxy esté apagado.
+
+Todo este proceso de renovación, mientras aún se sirve la aplicación, es una de las principales razones por las que querrías tener un **sistema separado para gestionar el HTTPS** con un TLS Termination Proxy en lugar de simplemente usar los certificados TLS con el servidor de aplicaciones directamente (por ejemplo, Uvicorn).
+
+## Resumen
+
+Tener **HTTPS** es muy importante y bastante **crítico** en la mayoría de los casos. La mayor parte del esfuerzo que como desarrollador tienes que poner en torno a HTTPS es solo sobre **entender estos conceptos** y cómo funcionan.
+
+Pero una vez que conoces la información básica de **HTTPS para desarrolladores** puedes combinar y configurar fácilmente diferentes herramientas para ayudarte a gestionar todo de una manera sencilla.
+
+En algunos de los siguientes capítulos, te mostraré varios ejemplos concretos de cómo configurar **HTTPS** para aplicaciones **FastAPI**. 🔒
diff --git a/docs/es/docs/deployment/index.md b/docs/es/docs/deployment/index.md
index 74b0e22f0..3b6dcc05d 100644
--- a/docs/es/docs/deployment/index.md
+++ b/docs/es/docs/deployment/index.md
@@ -1,21 +1,21 @@
-# Despliegue - Introducción
+# Despliegue
-Desplegar una aplicación hecha con **FastAPI** es relativamente fácil.
+Desplegar una aplicación **FastAPI** es relativamente fácil.
-## ¿Qué significa desplegar una aplicación?
+## Qué Significa Despliegue
-**Desplegar** una aplicación significa realizar una serie de pasos para hacerla **disponible para los usuarios**.
+**Desplegar** una aplicación significa realizar los pasos necesarios para hacerla **disponible para los usuarios**.
-Para una **API web**, normalmente implica ponerla en una **máquina remota**, con un **programa de servidor** que proporcione un buen rendimiento, estabilidad, etc, para que sus **usuarios** puedan **acceder** a la aplicación de manera eficiente y sin interrupciones o problemas.
+Para una **API web**, normalmente implica ponerla en una **máquina remota**, con un **programa de servidor** que proporcione buen rendimiento, estabilidad, etc., para que tus **usuarios** puedan **acceder** a la aplicación de manera eficiente y sin interrupciones o problemas.
-Esto difiere en las fases de **desarrollo**, donde estás constantemente cambiando el código, rompiéndolo y arreglándolo, deteniendo y reiniciando el servidor de desarrollo, etc.
+Esto contrasta con las etapas de **desarrollo**, donde estás constantemente cambiando el código, rompiéndolo y arreglándolo, deteniendo y reiniciando el servidor de desarrollo, etc.
-## Estrategias de despliegue
+## Estrategias de Despliegue
-Existen varias formas de hacerlo dependiendo de tu caso de uso específico y las herramientas que uses.
+Hay varias maneras de hacerlo dependiendo de tu caso de uso específico y las herramientas que utilices.
-Puedes **desplegar un servidor** tú mismo usando un conjunto de herramientas, puedes usar **servicios en la nube** que haga parte del trabajo por ti, o usar otras posibles opciones.
+Podrías **desplegar un servidor** tú mismo utilizando una combinación de herramientas, podrías usar un **servicio en la nube** que hace parte del trabajo por ti, u otras opciones posibles.
-Te enseñaré algunos de los conceptos principales que debes tener en cuenta al desplegar aplicaciones hechas con **FastAPI** (aunque la mayoría de estos conceptos aplican para cualquier otro tipo de aplicación web).
+Te mostraré algunos de los conceptos principales que probablemente deberías tener en cuenta al desplegar una aplicación **FastAPI** (aunque la mayoría se aplica a cualquier otro tipo de aplicación web).
-Podrás ver más detalles para tener en cuenta y algunas de las técnicas para hacerlo en las próximas secciones.✨
+Verás más detalles a tener en cuenta y algunas de las técnicas para hacerlo en las siguientes secciones. ✨
diff --git a/docs/es/docs/deployment/manually.md b/docs/es/docs/deployment/manually.md
new file mode 100644
index 000000000..509b9ebdb
--- /dev/null
+++ b/docs/es/docs/deployment/manually.md
@@ -0,0 +1,169 @@
+# Ejecutar un Servidor Manualmente
+
+## Usa el Comando `fastapi run`
+
+En resumen, usa `fastapi run` para servir tu aplicación FastAPI:
+
+
+
+```console
+$ fastapi run main.py
+INFO Usando path main.py
+INFO Path absoluto resuelto /home/user/code/awesomeapp/main.py
+INFO Buscando una estructura de archivos de paquete desde directorios con archivos __init__.py
+INFO Importando desde /home/user/code/awesomeapp
+
+ ╭─ Archivo de módulo de Python ─╮
+ │ │
+ │ 🐍 main.py │
+ │ │
+ ╰──────────────────────╯
+
+INFO Importando módulo main
+INFO Encontrada aplicación FastAPI importable
+
+ ╭─ Aplicación FastAPI importable ─╮
+ │ │
+ │ from main import app │
+ │ │
+ ╰──────────────────────────╯
+
+INFO Usando la cadena de import main:app
+
+ ╭─────────── CLI de FastAPI - Modo Producción ───────────╮
+ │ │
+ │ Sirviendo en: http://0.0.0.0:8000 │
+ │ │
+ │ Docs de API: http://0.0.0.0:8000/docs │
+ │ │
+ │ Corriendo en modo producción, para desarrollo usa: │
+ │ │
+ │ fastapi dev │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Iniciado el proceso del servidor [2306215]
+INFO: Esperando el inicio de la aplicación.
+INFO: Inicio de la aplicación completado.
+INFO: Uvicorn corriendo en http://0.0.0.0:8000 (Presiona CTRL+C para salir)
+```
+
+
+
+Eso funcionaría para la mayoría de los casos. 😎
+
+Podrías usar ese comando, por ejemplo, para iniciar tu app **FastAPI** en un contenedor, en un servidor, etc.
+
+## Servidores ASGI
+
+Vamos a profundizar un poquito en los detalles.
+
+FastAPI usa un estándar para construir frameworks de web y servidores de Python llamado ASGI. FastAPI es un framework web ASGI.
+
+Lo principal que necesitas para ejecutar una aplicación **FastAPI** (o cualquier otra aplicación ASGI) en una máquina de servidor remota es un programa de servidor ASGI como **Uvicorn**, que es el que viene por defecto en el comando `fastapi`.
+
+Hay varias alternativas, incluyendo:
+
+* Uvicorn: un servidor ASGI de alto rendimiento.
+* Hypercorn: un servidor ASGI compatible con HTTP/2 y Trio entre otras funcionalidades.
+* Daphne: el servidor ASGI construido para Django Channels.
+* Granian: Un servidor HTTP Rust para aplicaciones en Python.
+* NGINX Unit: NGINX Unit es un runtime para aplicaciones web ligero y versátil.
+
+## Máquina Servidor y Programa Servidor
+
+Hay un pequeño detalle sobre los nombres que hay que tener en cuenta. 💡
+
+La palabra "**servidor**" se utiliza comúnmente para referirse tanto al computador remoto/en la nube (la máquina física o virtual) como al programa que se está ejecutando en esa máquina (por ejemplo, Uvicorn).
+
+Solo ten en cuenta que cuando leas "servidor" en general, podría referirse a una de esas dos cosas.
+
+Al referirse a la máquina remota, es común llamarla **servidor**, pero también **máquina**, **VM** (máquina virtual), **nodo**. Todos esos se refieren a algún tipo de máquina remota, generalmente con Linux, donde ejecutas programas.
+
+## Instala el Programa del Servidor
+
+Cuando instalas FastAPI, viene con un servidor de producción, Uvicorn, y puedes iniciarlo con el comando `fastapi run`.
+
+Pero también puedes instalar un servidor ASGI manualmente.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo, y luego puedes instalar la aplicación del servidor.
+
+Por ejemplo, para instalar Uvicorn:
+
+
+
+Un proceso similar se aplicaría a cualquier otro programa de servidor ASGI.
+
+/// tip | Consejo
+
+Al añadir `standard`, Uvicorn instalará y usará algunas dependencias adicionales recomendadas.
+
+Eso incluye `uvloop`, el reemplazo de alto rendimiento para `asyncio`, que proporciona un gran impulso de rendimiento en concurrencia.
+
+Cuando instalas FastAPI con algo como `pip install "fastapi[standard]"` ya obtienes `uvicorn[standard]` también.
+
+///
+
+## Ejecuta el Programa del Servidor
+
+Si instalaste un servidor ASGI manualmente, normalmente necesitarías pasar una cadena de import en un formato especial para que importe tu aplicación FastAPI:
+
+
+
+/// note | Nota
+
+El comando `uvicorn main:app` se refiere a:
+
+* `main`: el archivo `main.py` (el "módulo" de Python).
+* `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`.
+
+Es equivalente a:
+
+```Python
+from main import app
+```
+
+///
+
+Cada programa alternativo de servidor ASGI tendría un comando similar, puedes leer más en su respectiva documentación.
+
+/// warning | Advertencia
+
+Uvicorn y otros servidores soportan una opción `--reload` que es útil durante el desarrollo.
+
+La opción `--reload` consume muchos más recursos, es más inestable, etc.
+
+Ayuda mucho durante el **desarrollo**, pero **no** deberías usarla en **producción**.
+
+///
+
+## Conceptos de Despliegue
+
+Estos ejemplos ejecutan el programa del servidor (por ejemplo, Uvicorn), iniciando **un solo proceso**, escuchando en todas las IPs (`0.0.0.0`) en un puerto predefinido (por ejemplo, `80`).
+
+Esta es la idea básica. Pero probablemente querrás encargarte de algunas cosas adicionales, como:
+
+* Seguridad - HTTPS
+* Ejecución en el arranque
+* Reinicios
+* Replicación (el número de procesos ejecutándose)
+* Memoria
+* Pasos previos antes de comenzar
+
+Te contaré más sobre cada uno de estos conceptos, cómo pensarlos, y algunos ejemplos concretos con estrategias para manejarlos en los próximos capítulos. 🚀
diff --git a/docs/es/docs/deployment/server-workers.md b/docs/es/docs/deployment/server-workers.md
new file mode 100644
index 000000000..1a1127ca6
--- /dev/null
+++ b/docs/es/docs/deployment/server-workers.md
@@ -0,0 +1,152 @@
+# Servidores Workers - Uvicorn con Workers
+
+Vamos a revisar esos conceptos de despliegue de antes:
+
+* Seguridad - HTTPS
+* Ejecución al inicio
+* Reinicios
+* **Replicación (el número de procesos en ejecución)**
+* Memoria
+* Pasos previos antes de empezar
+
+Hasta este punto, con todos los tutoriales en la documentación, probablemente has estado ejecutando un **programa de servidor**, por ejemplo, usando el comando `fastapi`, que ejecuta Uvicorn, corriendo un **solo proceso**.
+
+Al desplegar aplicaciones probablemente querrás tener algo de **replicación de procesos** para aprovechar **múltiples núcleos** y poder manejar más requests.
+
+Como viste en el capítulo anterior sobre [Conceptos de Despliegue](concepts.md){.internal-link target=_blank}, hay múltiples estrategias que puedes usar.
+
+Aquí te mostraré cómo usar **Uvicorn** con **worker processes** usando el comando `fastapi` o el comando `uvicorn` directamente.
+
+/// info | Información
+
+Si estás usando contenedores, por ejemplo con Docker o Kubernetes, te contaré más sobre eso en el próximo capítulo: [FastAPI en Contenedores - Docker](docker.md){.internal-link target=_blank}.
+
+En particular, cuando corras en **Kubernetes** probablemente **no** querrás usar workers y en cambio correr **un solo proceso de Uvicorn por contenedor**, pero te contaré sobre eso más adelante en ese capítulo.
+
+///
+
+## Múltiples Workers
+
+Puedes iniciar múltiples workers con la opción de línea de comando `--workers`:
+
+//// tab | `fastapi`
+
+Si usas el comando `fastapi`:
+
+
+
+```console
+$
fastapi run --workers 4 main.py
+INFO Using path main.py
+INFO Resolved absolute path /home/user/code/awesomeapp/main.py
+INFO Searching for package file structure from directories with __init__.py files
+INFO Importing from /home/user/code/awesomeapp
+
+ ╭─ Python module file ─╮
+ │ │
+ │ 🐍 main.py │
+ │ │
+ ╰──────────────────────╯
+
+INFO Importing module main
+INFO Found importable FastAPI app
+
+ ╭─ Importable FastAPI app ─╮
+ │ │
+ │ from main import app │
+ │ │
+ ╰──────────────────────────╯
+
+INFO Using import string main:app
+
+ ╭─────────── FastAPI CLI - Production mode ───────────╮
+ │ │
+ │ Serving at: http://0.0.0.0:8000 │
+ │ │
+ │ API docs: http://0.0.0.0:8000/docs │
+ │ │
+ │ Running in production mode, for development use: │
+ │ │
+ │ fastapi dev │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
+INFO: Started parent process [27365]
+INFO: Started server process [27368]
+INFO: 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.
+
+
+```console
+$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
+INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
+INFO: Started parent process [27365]
+INFO: Started server process [27368]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27369]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27370]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+INFO: Started server process [27367]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+////
+
+La única opción nueva aquí es `--workers` indicando a Uvicorn que inicie 4 worker processes.
+
+También puedes ver que muestra el **PID** de cada proceso, `27365` para el proceso padre (este es el **gestor de procesos**) y uno para cada worker process: `27368`, `27369`, `27370`, y `27367`.
+
+## Conceptos de Despliegue
+
+Aquí viste cómo usar múltiples **workers** para **paralelizar** la ejecución de la aplicación, aprovechar los **múltiples núcleos** del CPU, y poder servir **más requests**.
+
+De la lista de conceptos de despliegue de antes, usar workers ayudaría principalmente con la parte de **replicación**, y un poquito con los **reinicios**, pero aún necesitas encargarte de los otros:
+
+* **Seguridad - HTTPS**
+* **Ejecución al inicio**
+* ***Reinicios***
+* Replicación (el número de procesos en ejecución)
+* **Memoria**
+* **Pasos previos antes de empezar**
+
+## Contenedores y Docker
+
+En el próximo capítulo sobre [FastAPI en Contenedores - Docker](docker.md){.internal-link target=_blank} te explicaré algunas estrategias que podrías usar para manejar los otros **conceptos de despliegue**.
+
+Te mostraré cómo **construir tu propia imagen desde cero** para ejecutar un solo proceso de Uvicorn. Es un proceso sencillo y probablemente es lo que querrías hacer al usar un sistema de gestión de contenedores distribuido como **Kubernetes**.
+
+## Resumen
+
+Puedes usar múltiples worker processes con la opción CLI `--workers` con los comandos `fastapi` o `uvicorn` para aprovechar los **CPUs de múltiples núcleos**, para ejecutar **múltiples procesos en paralelo**.
+
+Podrías usar estas herramientas e ideas si estás instalando **tu propio sistema de despliegue** mientras te encargas tú mismo de los otros conceptos de despliegue.
+
+Revisa el próximo capítulo para aprender sobre **FastAPI** con contenedores (por ejemplo, Docker y Kubernetes). Verás que esas herramientas tienen formas sencillas de resolver los otros **conceptos de despliegue** también. ✨
diff --git a/docs/es/docs/deployment/versions.md b/docs/es/docs/deployment/versions.md
index 74243da89..d16ecf0a5 100644
--- a/docs/es/docs/deployment/versions.md
+++ b/docs/es/docs/deployment/versions.md
@@ -1,93 +1,93 @@
-# Acerca de las versiones de FastAPI
+# Sobre las versiones de FastAPI
-**FastAPI** está siendo utilizado en producción en muchas aplicaciones y sistemas. La cobertura de los tests se mantiene al 100%. Sin embargo, su desarrollo sigue siendo rápido.
+**FastAPI** ya se está utilizando en producción en muchas aplicaciones y sistemas. Y la cobertura de tests se mantiene al 100%. Pero su desarrollo sigue avanzando rápidamente.
-Se agregan nuevas características frecuentemente, se corrigen errores continuamente y el código está constantemente mejorando.
+Se añaden nuevas funcionalidades con frecuencia, se corrigen bugs regularmente, y el código sigue mejorando continuamente.
-Por eso las versiones actuales siguen siendo `0.x.x`, esto significa que cada versión puede potencialmente tener *breaking changes*. Las versiones siguen las convenciones de *Semantic Versioning*.
+Por eso las versiones actuales siguen siendo `0.x.x`, esto refleja que cada versión podría tener potencialmente cambios incompatibles. Esto sigue las convenciones de Semantic Versioning.
-Puedes crear aplicaciones listas para producción con **FastAPI** ahora mismo (y probablemente lo has estado haciendo por algún tiempo), solo tienes que asegurarte de usar la versión que funciona correctamente con el resto de tu código.
+Puedes crear aplicaciones de producción con **FastAPI** ahora mismo (y probablemente ya lo has estado haciendo desde hace algún tiempo), solo debes asegurarte de que utilizas una versión que funciona correctamente con el resto de tu código.
-## Fijar la versión de `fastapi`
+## Fijar tu versión de `fastapi`
-Lo primero que debes hacer en tu proyecto es "fijar" la última versión específica de **FastAPI** que sabes que funciona bien con tu aplicación.
+Lo primero que debes hacer es "fijar" la versión de **FastAPI** que estás usando a la versión específica más reciente que sabes que funciona correctamente para tu aplicación.
-Por ejemplo, digamos que estás usando la versión `0.45.0` en tu aplicación.
+Por ejemplo, digamos que estás utilizando la versión `0.112.0` en tu aplicación.
-Si usas el archivo `requirements.txt` puedes especificar la versión con:
+Si usas un archivo `requirements.txt` podrías especificar la versión con:
```txt
-fastapi==0.45.0
+fastapi[standard]==0.112.0
```
-esto significa que usarás específicamente la versión `0.45.0`.
+eso significaría que usarías exactamente la versión `0.112.0`.
-También puedes fijar las versiones de esta forma:
+O también podrías fijarla con:
```txt
-fastapi>=0.45.0,<0.46.0
+fastapi[standard]>=0.112.0,<0.113.0
```
-esto significa que usarás la versión `0.45.0` o superiores, pero menores a la versión `0.46.0`, por ejemplo, la versión `0.45.2` sería aceptada.
+eso significaría que usarías las versiones `0.112.0` o superiores, pero menores que `0.113.0`, por ejemplo, una versión `0.112.2` todavía sería aceptada.
-Si usas cualquier otra herramienta para manejar tus instalaciones, como Poetry, Pipenv, u otras, todas tienen una forma que puedes usar para definir versiones específicas para tus paquetes.
+Si utilizas cualquier otra herramienta para gestionar tus instalaciones, como `uv`, Poetry, Pipenv, u otras, todas tienen una forma que puedes usar para definir versiones específicas para tus paquetes.
## Versiones disponibles
-Puedes ver las versiones disponibles (por ejemplo, para revisar cuál es la actual) en las [Release Notes](../release-notes.md){.internal-link target=_blank}.
+Puedes ver las versiones disponibles (por ejemplo, para revisar cuál es la más reciente) en las [Release Notes](../release-notes.md){.internal-link target=_blank}.
-## Acerca de las versiones
+## Sobre las versiones
-Siguiendo las convenciones de *Semantic Versioning*, cualquier versión por debajo de `1.0.0` puede potencialmente tener *breaking changes*.
+Siguiendo las convenciones del Semantic Versioning, cualquier versión por debajo de `1.0.0` podría potencialmente añadir cambios incompatibles.
-FastAPI también sigue la convención de que cualquier cambio hecho en una "PATCH" version es para solucionar errores y *non-breaking changes*.
+FastAPI también sigue la convención de que cualquier cambio de versión "PATCH" es para corrección de bugs y cambios no incompatibles.
/// tip | Consejo
-El "PATCH" es el último número, por ejemplo, en `0.2.3`, la PATCH version es `3`.
+El "PATCH" es el último número, por ejemplo, en `0.2.3`, la versión PATCH es `3`.
///
-Entonces, deberías fijar la versión así:
+Así que deberías poder fijar a una versión como:
```txt
fastapi>=0.45.0,<0.46.0
```
-En versiones "MINOR" son añadidas nuevas características y posibles breaking changes.
+Los cambios incompatibles y nuevas funcionalidades se añaden en versiones "MINOR".
/// tip | Consejo
-La versión "MINOR" es el número en el medio, por ejemplo, en `0.2.3`, la "MINOR" version es `2`.
+El "MINOR" es el número en el medio, por ejemplo, en `0.2.3`, la versión MINOR es `2`.
///
## Actualizando las versiones de FastAPI
-Para esto es recomendable primero añadir tests a tu aplicación.
+Deberías añadir tests para tu aplicación.
-Con **FastAPI** es muy fácil (gracias a Starlette), revisa la documentación [Testing](../tutorial/testing.md){.internal-link target=_blank}
+Con **FastAPI** es muy fácil (gracias a Starlette), revisa la documentación: [Testing](../tutorial/testing.md){.internal-link target=_blank}
-Luego de tener los tests, puedes actualizar la versión de **FastAPI** a una más reciente y asegurarte de que tu código funciona correctamente ejecutando los tests.
+Después de tener tests, puedes actualizar la versión de **FastAPI** a una más reciente, y asegurarte de que todo tu código está funcionando correctamente ejecutando tus tests.
-Si todo funciona correctamente, o haces los cambios necesarios para que esto suceda, y todos tus tests pasan, entonces puedes fijar tu versión de `fastapi` a la más reciente.
+Si todo está funcionando, o después de hacer los cambios necesarios, y todos tus tests pasan, entonces puedes fijar tu `fastapi` a esa nueva versión más reciente.
-## Acerca de Starlette
+## Sobre Starlette
No deberías fijar la versión de `starlette`.
-Diferentes versiones de **FastAPI** pueden usar una versión específica de Starlette.
+Diferentes versiones de **FastAPI** utilizarán una versión más reciente específica de Starlette.
-Entonces, puedes dejar que **FastAPI** se asegure por sí mismo de qué versión de Starlette usar.
+Así que, puedes simplemente dejar que **FastAPI** use la versión correcta de Starlette.
-## Acerca de Pydantic
+## Sobre Pydantic
-Pydantic incluye los tests para **FastAPI** dentro de sus propios tests, esto significa que las versiones de Pydantic (superiores a `1.0.0`) son compatibles con FastAPI.
+Pydantic incluye los tests para **FastAPI** con sus propios tests, así que nuevas versiones de Pydantic (por encima de `1.0.0`) siempre son compatibles con FastAPI.
-Puedes fijar Pydantic a cualquier versión superior a `1.0.0` e inferior a `2.0.0` que funcione para ti.
+Puedes fijar Pydantic a cualquier versión por encima de `1.0.0` que funcione para ti.
Por ejemplo:
```txt
-pydantic>=1.2.0,<2.0.0
+pydantic>=2.7.0,<3.0.0
```
diff --git a/docs/es/docs/environment-variables.md b/docs/es/docs/environment-variables.md
new file mode 100644
index 000000000..8e85b413c
--- /dev/null
+++ b/docs/es/docs/environment-variables.md
@@ -0,0 +1,298 @@
+# Variables de Entorno
+
+/// tip | Consejo
+
+Si ya sabes qué son las "variables de entorno" y cómo usarlas, siéntete libre de saltarte esto.
+
+///
+
+Una variable de entorno (también conocida como "**env var**") es una variable que vive **fuera** del código de Python, en el **sistema operativo**, y podría ser leída por tu código de Python (o por otros programas también).
+
+Las variables de entorno pueden ser útiles para manejar **configuraciones** de aplicaciones, como parte de la **instalación** de Python, etc.
+
+## Crear y Usar Variables de Entorno
+
+Puedes **crear** y usar variables de entorno en la **shell (terminal)**, sin necesidad de Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Podrías crear una env var MY_NAME con
+$ export MY_NAME="Wade Wilson"
+
+// Luego podrías usarla con otros programas, como
+$ echo "Hello $MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Crea una env var MY_NAME
+$ $Env:MY_NAME = "Wade Wilson"
+
+// Úsala con otros programas, como
+$ echo "Hello $Env:MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+## Leer Variables de Entorno en Python
+
+También podrías crear variables de entorno **fuera** de Python, en la terminal (o con cualquier otro método), y luego **leerlas en Python**.
+
+Por ejemplo, podrías tener un archivo `main.py` con:
+
+```Python hl_lines="3"
+import os
+
+name = os.getenv("MY_NAME", "World")
+print(f"Hello {name} from Python")
+```
+
+/// tip | Consejo
+
+El segundo argumento de `os.getenv()` es el valor por defecto a retornar.
+
+Si no se proporciona, es `None` por defecto; aquí proporcionamos `"World"` como el valor por defecto para usar.
+
+///
+
+Luego podrías llamar a ese programa Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Aquí todavía no configuramos la env var
+$ python main.py
+
+// Como no configuramos la env var, obtenemos el valor por defecto
+
+Hello World from Python
+
+// Pero si creamos una variable de entorno primero
+$ export MY_NAME="Wade Wilson"
+
+// Y luego llamamos al programa nuevamente
+$ python main.py
+
+// Ahora puede leer la variable de entorno
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Aquí todavía no configuramos la env var
+$ python main.py
+
+// Como no configuramos la env var, obtenemos el valor por defecto
+
+Hello World from Python
+
+// Pero si creamos una variable de entorno primero
+$ $Env:MY_NAME = "Wade Wilson"
+
+// Y luego llamamos al programa nuevamente
+$ python main.py
+
+// Ahora puede leer la variable de entorno
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+Dado que las variables de entorno pueden configurarse fuera del código, pero pueden ser leídas por el código, y no tienen que ser almacenadas (committed en `git`) con el resto de los archivos, es común usarlas para configuraciones o **ajustes**.
+
+También puedes crear una variable de entorno solo para una **invocación específica de un programa**, que está disponible solo para ese programa, y solo durante su duración.
+
+Para hacer eso, créala justo antes del programa en sí, en la misma línea:
+
+
+
+```console
+// Crea una env var MY_NAME en línea para esta llamada del programa
+$ MY_NAME="Wade Wilson" python main.py
+
+// Ahora puede leer la variable de entorno
+
+Hello Wade Wilson from Python
+
+// La env var ya no existe después
+$ python main.py
+
+Hello World from Python
+```
+
+
+
+/// tip | Consejo
+
+Puedes leer más al respecto en The Twelve-Factor App: Config.
+
+///
+
+## Tipos y Validación
+
+Estas variables de entorno solo pueden manejar **strings de texto**, ya que son externas a Python y deben ser compatibles con otros programas y el resto del sistema (e incluso con diferentes sistemas operativos, como Linux, Windows, macOS).
+
+Esto significa que **cualquier valor** leído en Python desde una variable de entorno **será un `str`**, y cualquier conversión a un tipo diferente o cualquier validación tiene que hacerse en el código.
+
+Aprenderás más sobre cómo usar variables de entorno para manejar **configuraciones de aplicación** en la [Guía del Usuario Avanzado - Ajustes y Variables de Entorno](./advanced/settings.md){.internal-link target=_blank}.
+
+## Variable de Entorno `PATH`
+
+Hay una variable de entorno **especial** llamada **`PATH`** que es utilizada por los sistemas operativos (Linux, macOS, Windows) para encontrar programas a ejecutar.
+
+El valor de la variable `PATH` es un string largo que consiste en directorios separados por dos puntos `:` en Linux y macOS, y por punto y coma `;` en Windows.
+
+Por ejemplo, la variable de entorno `PATH` podría verse así:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Esto significa que el sistema debería buscar programas en los directorios:
+
+* `/usr/local/bin`
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
+```
+
+Esto significa que el sistema debería buscar programas en los directorios:
+
+* `C:\Program Files\Python312\Scripts`
+* `C:\Program Files\Python312`
+* `C:\Windows\System32`
+
+////
+
+Cuando escribes un **comando** en la terminal, el sistema operativo **busca** el programa en **cada uno de esos directorios** listados en la variable de entorno `PATH`.
+
+Por ejemplo, cuando escribes `python` en la terminal, el sistema operativo busca un programa llamado `python` en el **primer directorio** de esa lista.
+
+Si lo encuentra, entonces lo **utilizará**. De lo contrario, continúa buscando en los **otros directorios**.
+
+### Instalando Python y Actualizando el `PATH`
+
+Cuando instalas Python, se te podría preguntar si deseas actualizar la variable de entorno `PATH`.
+
+//// tab | Linux, macOS
+
+Digamos que instalas Python y termina en un directorio `/opt/custompython/bin`.
+
+Si dices que sí para actualizar la variable de entorno `PATH`, entonces el instalador añadirá `/opt/custompython/bin` a la variable de entorno `PATH`.
+
+Podría verse así:
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
+```
+
+De esta manera, cuando escribes `python` en la terminal, el sistema encontrará el programa Python en `/opt/custompython/bin` (el último directorio) y usará ese.
+
+////
+
+//// tab | Windows
+
+Digamos que instalas Python y termina en un directorio `C:\opt\custompython\bin`.
+
+Si dices que sí para actualizar la variable de entorno `PATH`, entonces el instalador añadirá `C:\opt\custompython\bin` a la variable de entorno `PATH`.
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
+```
+
+De esta manera, cuando escribes `python` en la terminal, el sistema encontrará el programa Python en `C:\opt\custompython\bin` (el último directorio) y usará ese.
+
+////
+
+Entonces, si escribes:
+
+
+
+```console
+$ python
+```
+
+
+
+//// tab | Linux, macOS
+
+El sistema **encontrará** el programa `python` en `/opt/custompython/bin` y lo ejecutará.
+
+Esto sería más o menos equivalente a escribir:
+
+
+
+////
+
+//// tab | Windows
+
+El sistema **encontrará** el programa `python` en `C:\opt\custompython\bin\python` y lo ejecutará.
+
+Esto sería más o menos equivalente a escribir:
+
+
+
+////
+
+Esta información será útil al aprender sobre [Entornos Virtuales](virtual-environments.md){.internal-link target=_blank}.
+
+## Conclusión
+
+Con esto deberías tener una comprensión básica de qué son las **variables de entorno** y cómo usarlas en Python.
+
+También puedes leer más sobre ellas en la Wikipedia para Variable de Entorno.
+
+En muchos casos no es muy obvio cómo las variables de entorno serían útiles y aplicables de inmediato. Pero siguen apareciendo en muchos escenarios diferentes cuando estás desarrollando, así que es bueno conocerlas.
+
+Por ejemplo, necesitarás esta información en la siguiente sección, sobre [Entornos Virtuales](virtual-environments.md).
diff --git a/docs/es/docs/fastapi-cli.md b/docs/es/docs/fastapi-cli.md
new file mode 100644
index 000000000..9d7629fdb
--- /dev/null
+++ b/docs/es/docs/fastapi-cli.md
@@ -0,0 +1,75 @@
+# FastAPI CLI
+
+**FastAPI CLI** es un programa de línea de comandos que puedes usar para servir tu aplicación FastAPI, gestionar tu proyecto FastAPI, y más.
+
+Cuando instalas FastAPI (por ejemplo, con `pip install "fastapi[standard]"`), incluye un paquete llamado `fastapi-cli`, este paquete proporciona el comando `fastapi` en la terminal.
+
+Para ejecutar tu aplicación FastAPI en modo de desarrollo, puedes usar el comando `fastapi dev`:
+
+
+
+```console
+$ fastapi dev main.py
+
+ FastAPI Starting development server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://127.0.0.1:8000
+ server Documentation at http://127.0.0.1:8000/docs
+
+ tip Running in development mode, for production use:
+ fastapi run
+
+ Logs:
+
+ INFO Will watch for changes in these directories:
+ ['/home/user/code/awesomeapp']
+ INFO Uvicorn running on http://127.0.0.1:8000(Press CTRL+C to
+ quit)
+ INFO Started reloader process [383138] using WatchFiles
+ INFO Started server process [383153]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+```
+
+
+
+El programa de línea de comandos llamado `fastapi` es **FastAPI CLI**.
+
+FastAPI CLI toma el path de tu programa Python (por ejemplo, `main.py`), detecta automáticamente la `FastAPI` instance (comúnmente llamada `app`), determina el proceso de import correcto, y luego la sirve.
+
+Para producción usarías `fastapi run` en su lugar. 🚀
+
+Internamente, **FastAPI CLI** usa Uvicorn, un servidor ASGI de alto rendimiento y listo para producción. 😎
+
+## `fastapi dev`
+
+Ejecutar `fastapi dev` inicia el modo de desarrollo.
+
+Por defecto, **auto-reload** está habilitado, recargando automáticamente el servidor cuando realizas cambios en tu código. Esto consume muchos recursos y podría ser menos estable que cuando está deshabilitado. Deberías usarlo solo para desarrollo. También escucha en la dirección IP `127.0.0.1`, que es la IP para que tu máquina se comunique solo consigo misma (`localhost`).
+
+## `fastapi run`
+
+Ejecutar `fastapi run` inicia FastAPI en modo de producción por defecto.
+
+Por defecto, **auto-reload** está deshabilitado. También escucha en la dirección IP `0.0.0.0`, lo que significa todas las direcciones IP disponibles, de esta manera será accesible públicamente por cualquiera que pueda comunicarse con la máquina. Esta es la manera en la que normalmente lo ejecutarías en producción, por ejemplo, en un contenedor.
+
+En la mayoría de los casos tendrías (y deberías) tener un "proxy de terminación" manejando HTTPS por ti, esto dependerá de cómo despliegues tu aplicación, tu proveedor podría hacer esto por ti, o podrías necesitar configurarlo tú mismo.
+
+/// tip | Consejo
+
+Puedes aprender más al respecto en la [documentación de despliegue](deployment/index.md){.internal-link target=_blank}.
+
+///
diff --git a/docs/es/docs/features.md b/docs/es/docs/features.md
index b75918dff..472fdd736 100644
--- a/docs/es/docs/features.md
+++ b/docs/es/docs/features.md
@@ -1,43 +1,43 @@
-# Características
+# Funcionalidades
-## Características de FastAPI
+## Funcionalidades de FastAPI
-**FastAPI** te provee lo siguiente:
+**FastAPI** te ofrece lo siguiente:
### Basado en estándares abiertos
-* OpenAPI para la creación de APIs, incluyendo declaraciones de path operations, parámetros, body requests, seguridad, etc.
-* Documentación automática del modelo de datos con JSON Schema (dado que OpenAPI mismo está basado en JSON Schema).
-* Diseñado alrededor de estos estándares después de un estudio meticuloso. En vez de ser una capa añadida a último momento.
-* Esto también permite la **generación automática de código de cliente** para muchos lenguajes.
+* OpenAPI para la creación de APIs, incluyendo declaraciones de path operations, parámetros, request bodies, seguridad, etc.
+* Documentación automática de modelos de datos con JSON Schema (ya que OpenAPI en sí mismo está basado en JSON Schema).
+* Diseñado alrededor de estos estándares, tras un estudio meticuloso. En lugar de ser una capa adicional.
+* Esto también permite el uso de **generación de código cliente automática** en muchos idiomas.
### Documentación automática
-Documentación interactiva de la API e interfaces web de exploración. Hay múltiples opciones, dos incluidas por defecto, porque el framework está basado en OpenAPI.
+Interfaces web de documentación y exploración de APIs interactivas. Como el framework está basado en OpenAPI, hay múltiples opciones, 2 incluidas por defecto.
-* Swagger UI, con exploración interactiva, llama y prueba tu API directamente desde tu navegador.
+* Swagger UI, con exploración interactiva, llama y prueba tu API directamente desde el navegador.
-
+
-* Documentación alternativa de la API con ReDoc.
+* Documentación alternativa de API con ReDoc.

-### Simplemente Python moderno
+### Solo Python moderno
-Todo está basado en las declaraciones de tipo de **Python 3.8** estándar (gracias a Pydantic). No necesitas aprender una sintaxis nueva, solo Python moderno.
+Todo está basado en declaraciones estándar de **tipos en Python** (gracias a Pydantic). Sin nueva sintaxis que aprender. Solo Python moderno estándar.
-Si necesitas un repaso de 2 minutos de cómo usar los tipos de Python (así no uses FastAPI) prueba el tutorial corto: [Python Types](python-types.md){.internal-link target=_blank}.
+Si necesitas un repaso de 2 minutos sobre cómo usar tipos en Python (aunque no uses FastAPI), revisa el tutorial corto: [Tipos en Python](python-types.md){.internal-link target=_blank}.
-Escribes Python estándar con tipos así:
+Escribes Python estándar con tipos:
```Python
from datetime import date
from pydantic import BaseModel
-# Declaras la variable como un str
-# y obtienes soporte del editor dentro de la función
+# Declara una variable como un str
+# y obtiene soporte del editor dentro de la función
def main(user_id: str):
return user_id
@@ -49,7 +49,7 @@ class User(BaseModel):
joined: date
```
-Este puede ser usado como:
+Que luego puede ser usado como:
```Python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
@@ -67,135 +67,135 @@ my_second_user: User = User(**second_user_data)
`**second_user_data` significa:
-Pasa las keys y los valores del dict `second_user_data` directamente como argumentos de key-value, equivalente a: `User(id=4, name="Mary", joined="2018-11-30")`
+Pasa las claves y valores del dict `second_user_data` directamente como argumentos de clave-valor, equivalente a: `User(id=4, name="Mary", joined="2018-11-30")`
///
### Soporte del editor
-El framework fue diseñado en su totalidad para ser fácil e intuitivo de usar. Todas las decisiones fueron probadas en múltiples editores antes de comenzar el desarrollo para asegurar la mejor experiencia de desarrollo.
+Todo el framework fue diseñado para ser fácil e intuitivo de usar, todas las decisiones fueron probadas en múltiples editores incluso antes de comenzar el desarrollo, para asegurar la mejor experiencia de desarrollo.
-En la última encuesta a desarrolladores de Python fue claro que la característica más usada es el "auto-completado".
+En las encuestas a desarrolladores de Python, es claro que una de las funcionalidades más usadas es el "autocompletado".
-El framework **FastAPI** está creado para satisfacer eso. El auto-completado funciona en todas partes.
+Todo el framework **FastAPI** está basado para satisfacer eso. El autocompletado funciona en todas partes.
-No vas a tener que volver a la documentación seguido.
+Rara vez necesitarás regresar a la documentación.
-Así es como tu editor te puede ayudar:
+Aquí está cómo tu editor podría ayudarte:
* en Visual Studio Code:
-
+
* en PyCharm:
-
+
-Obtendrás completado para tu código que podrías haber considerado imposible antes. Por ejemplo, el key `price` dentro del JSON body (que podría haber estado anidado) que viene de un request.
+Obtendrás autocompletado en código que podrías considerar imposible antes. Por ejemplo, la clave `price` dentro de un cuerpo JSON (que podría haber estado anidado) que proviene de un request.
-Ya no pasará que escribas los nombres de key equivocados, o que tengas que revisar constantemente la documentación o desplazarte arriba y abajo para saber si usaste `username` o `user_name`.
+No más escribir nombres de claves incorrectos, yendo de un lado a otro entre la documentación, o desplazándote hacia arriba y abajo para encontrar si finalmente usaste `username` o `user_name`.
-### Corto
+### Breve
-Tiene **configuraciones por defecto** razonables para todo, con configuraciones opcionales en todas partes. Todos los parámetros pueden ser ajustados para tus necesidades y las de tu API.
+Tiene **valores predeterminados** sensatos para todo, con configuraciones opcionales en todas partes. Todos los parámetros se pueden ajustar finamente para hacer lo que necesitas y para definir el API que necesitas.
-Pero, todo **simplemente funciona** por defecto.
+Pero por defecto, todo **"simplemente funciona"**.
### Validación
-* Validación para la mayoría (¿o todos?) los **tipos de datos** de Python incluyendo:
+* Validación para la mayoría (¿o todas?) de los **tipos de datos** de Python, incluyendo:
* Objetos JSON (`dict`).
- * JSON array (`list`) definiendo tipos de ítem.
- * Campos de texto (`str`) definiendo longitudes mínimas y máximas.
+ * Array JSON (`list`) definiendo tipos de elementos.
+ * Campos de cadena de caracteres (`str`), definiendo longitudes mínimas y máximas.
* Números (`int`, `float`) con valores mínimos y máximos, etc.
-* Validación para tipos más exóticos como:
+* Validación para tipos más exóticos, como:
* URL.
* Email.
* UUID.
* ...y otros.
-Toda la validación es manejada por **Pydantic**, que es robusto y sólidamente establecido.
+Toda la validación es manejada por **Pydantic**, una herramienta bien establecida y robusta.
### Seguridad y autenticación
-La seguridad y la autenticación están integradas. Sin ningún compromiso con bases de datos ni modelos de datos.
+Seguridad y autenticación integradas. Sin ningún compromiso con bases de datos o modelos de datos.
-Todos los schemes de seguridad están definidos en OpenAPI incluyendo:
+Todos los esquemas de seguridad definidos en OpenAPI, incluyendo:
-* HTTP Basic.
-* **OAuth2** (también con **JWT tokens**). Prueba el tutorial en [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
+* HTTP Básico.
+* **OAuth2** (también con **tokens JWT**). Revisa el tutorial sobre [OAuth2 con JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* API keys en:
* Headers.
- * Parámetros de Query.
+ * Parámetros de query.
* Cookies, etc.
-Más todas las características de seguridad de Starlette (incluyendo **session cookies**).
+Además de todas las características de seguridad de Starlette (incluyendo **cookies de sesión**).
-Todo ha sido construido como herramientas y componentes reutilizables que son fácilmente integrados con tus sistemas, almacenamiento de datos, bases de datos relacionales y no relacionales, etc.
+Todo construido como herramientas y componentes reutilizables que son fáciles de integrar con tus sistemas, almacenes de datos, bases de datos relacionales y NoSQL, etc.
-### Dependency Injection
+### Inyección de dependencias
-FastAPI incluye un sistema de Dependency Injection extremadamente poderoso y fácil de usar.
+FastAPI incluye un sistema de Inyección de Dependencias extremadamente fácil de usar, pero extremadamente potente.
-* Inclusive las dependencias pueden tener dependencias creando una jerarquía o un **"grafo" de dependencias**.
-* Todas son **manejadas automáticamente** por el framework.
-* Todas las dependencias pueden requerir datos de los requests y aumentar las restricciones del *path operation* y la documentación automática.
-* **Validación automática** inclusive para parámetros del *path operation* definidos en las dependencias.
-* Soporte para sistemas complejos de autenticación de usuarios, **conexiones con bases de datos**, etc.
-* **Sin comprometerse** con bases de datos, frontend, etc. Pero permitiendo integración fácil con todos ellos.
+* Incluso las dependencias pueden tener dependencias, creando una jerarquía o **"gráfico de dependencias"**.
+* Todo **manejado automáticamente** por el framework.
+* Todas las dependencias pueden requerir datos de los requests y **aumentar las restricciones de la path operation** y la documentación automática.
+* **Validación automática** incluso para los parámetros de *path operation* definidos en las dependencias.
+* Soporte para sistemas de autenticación de usuario complejos, **conexiones a bases de datos**, etc.
+* **Sin compromisos** con bases de datos, frontends, etc. Pero fácil integración con todos ellos.
### "Plug-ins" ilimitados
-O dicho de otra manera, no hay necesidad para "plug-ins". Importa y usa el código que necesites.
+O de otra manera, no hay necesidad de ellos, importa y usa el código que necesitas.
-Cualquier integración está diseñada para que sea tan sencilla de usar (con dependencias) que puedas crear un "plug-in" para tu aplicación en dos líneas de código usando la misma estructura y sintaxis que usaste para tus *path operations*.
+Cualquier integración está diseñada para ser tan simple de usar (con dependencias) que puedes crear un "plug-in" para tu aplicación en 2 líneas de código usando la misma estructura y sintaxis utilizada para tus *path operations*.
### Probado
-* Cobertura de pruebas al 100%.
-* Base de código 100% anotada con tipos.
+* 100% de cobertura de tests.
+* Código completamente anotado con tipos.
* Usado en aplicaciones en producción.
-## Características de Starlette
+## Funcionalidades de Starlette
-**FastAPI** está basado y es completamente compatible con Starlette. Tanto así, que cualquier código de Starlette que tengas también funcionará.
+**FastAPI** es totalmente compatible con (y está basado en) Starlette. Así que, cualquier código adicional de Starlette que tengas, también funcionará.
-`FastAPI` es realmente una sub-clase de `Starlette`. Así que, si ya conoces o usas Starlette, muchas de las características funcionarán de la misma manera.
+`FastAPI` es en realidad una subclase de `Starlette`. Así que, si ya conoces o usas Starlette, la mayoría de las funcionalidades funcionarán de la misma manera.
-Con **FastAPI** obtienes todas las características de **Starlette** (porque FastAPI es simplemente Starlette en esteroides):
+Con **FastAPI** obtienes todas las funcionalidades de **Starlette** (ya que FastAPI es simplemente Starlette potenciado):
-* Desempeño realmente impresionante. Es uno de los frameworks de Python más rápidos, a la par con **NodeJS** y **Go**.
+* Rendimiento seriamente impresionante. Es uno de los frameworks de Python más rápidos disponibles, a la par de **NodeJS** y **Go**.
* Soporte para **WebSocket**.
-* Tareas en background.
-* Eventos de startup y shutdown.
-* Cliente de pruebas construido con HTTPX.
-* **CORS**, GZip, Static Files, Streaming responses.
-* Soporte para **Session and Cookie**.
-* Cobertura de pruebas al 100%.
-* Base de código 100% anotada con tipos.
+* Tareas en segundo plano en el mismo proceso.
+* Eventos de inicio y apagado.
+* Cliente de prueba basado en HTTPX.
+* **CORS**, GZip, archivos estáticos, responses en streaming.
+* Soporte para **Session y Cookie**.
+* Cobertura de tests del 100%.
+* Código completamente anotado con tipos.
-## Características de Pydantic
+## Funcionalidades de Pydantic
-**FastAPI** está basado y es completamente compatible con Pydantic. Tanto así, que cualquier código de Pydantic que tengas también funcionará.
+**FastAPI** es totalmente compatible con (y está basado en) Pydantic. Por lo tanto, cualquier código adicional de Pydantic que tengas, también funcionará.
-Esto incluye a librerías externas basadas en Pydantic como ORMs y ODMs para bases de datos.
+Incluyendo paquetes externos también basados en Pydantic, como ORMs, ODMs para bases de datos.
-Esto también significa que en muchos casos puedes pasar el mismo objeto que obtuviste de un request **directamente a la base de datos**, dado que todo es validado automáticamente.
+Esto también significa que, en muchos casos, puedes pasar el mismo objeto que obtienes de un request **directamente a la base de datos**, ya que todo se valida automáticamente.
-Lo mismo aplica para el sentido contrario. En muchos casos puedes pasar el objeto que obtienes de la base de datos **directamente al cliente**.
+Lo mismo aplica al revés, en muchos casos puedes simplemente pasar el objeto que obtienes de la base de datos **directamente al cliente**.
-Con **FastAPI** obtienes todas las características de **Pydantic** (dado que FastAPI está basado en Pydantic para todo el manejo de datos):
+Con **FastAPI** obtienes todas las funcionalidades de **Pydantic** (ya que FastAPI está basado en Pydantic para todo el manejo de datos):
-* **Sin dificultades para entender**:
- * No necesitas aprender un nuevo micro-lenguaje de definición de schemas.
- * Si sabes tipos de Python, sabes cómo usar Pydantic.
-* Interactúa bien con tu **IDE/linter/cerebro**:
- * Porque las estructuras de datos de Pydantic son solo instances de clases que tu defines, el auto-completado, el linting, mypy y tu intuición deberían funcionar bien con tus datos validados.
+* **Sin complicaciones**:
+ * Sin micro-lenguaje de definición de esquemas nuevo que aprender.
+ * Si conoces los tipos en Python sabes cómo usar Pydantic.
+* Se lleva bien con tu **IDE/linter/cerebro**:
+ * Porque las estructuras de datos de pydantic son solo instances de clases que defines; autocompletado, linting, mypy y tu intuición deberían funcionar correctamente con tus datos validados.
* Valida **estructuras complejas**:
- * Usa modelos jerárquicos de modelos de Pydantic, `typing` de Python, `List` y `Dict`, etc.
- * Los validadores también permiten que se definan fácil y claramente schemas complejos de datos. Estos son chequeados y documentados como JSON Schema.
- * Puedes tener objetos de **JSON profundamente anidados** y que todos sean validados y anotados.
+ * Uso de modelos jerárquicos de Pydantic, `List` y `Dict` de `typing` de Python, etc.
+ * Y los validadores permiten definir, verificar y documentar de manera clara y fácil esquemas de datos complejos como JSON Schema.
+ * Puedes tener objetos JSON profundamente **anidados** y validarlos todos y anotarlos.
* **Extensible**:
- * Pydantic permite que se definan tipos de datos a la medida o puedes extender la validación con métodos en un modelo decorado con el decorador de validación.
-* Cobertura de pruebas al 100%.
+ * Pydantic permite definir tipos de datos personalizados o puedes extender la validación con métodos en un modelo decorados con el decorador validator.
+* Cobertura de tests del 100%.
diff --git a/docs/es/docs/help-fastapi.md b/docs/es/docs/help-fastapi.md
new file mode 100644
index 000000000..37f6b927d
--- /dev/null
+++ b/docs/es/docs/help-fastapi.md
@@ -0,0 +1,269 @@
+# Ayuda a FastAPI - Consigue Ayuda
+
+¿Te gusta **FastAPI**?
+
+¿Te gustaría ayudar a FastAPI, a otros usuarios y al autor?
+
+¿O te gustaría conseguir ayuda con **FastAPI**?
+
+Hay formas muy sencillas de ayudar (varias implican solo uno o dos clics).
+
+Y también hay varias formas de conseguir ayuda.
+
+## Suscríbete al boletín
+
+Puedes suscribirte al (esporádico) boletín [**FastAPI and friends**](newsletter.md){.internal-link target=_blank} para mantenerte al día sobre:
+
+* Noticias sobre FastAPI y amigos 🚀
+* Guías 📝
+* Funcionalidades ✨
+* Cambios importantes 🚨
+* Consejos y trucos ✅
+
+## Sigue a FastAPI en Twitter
+
+Sigue a @fastapi en **Twitter** para obtener las últimas noticias sobre **FastAPI**. 🐦
+
+## Dale una estrella a **FastAPI** en GitHub
+
+Puedes "darle una estrella" a FastAPI en GitHub (haciendo clic en el botón de estrella en la parte superior derecha): https://github.com/fastapi/fastapi. ⭐️
+
+Al agregar una estrella, otros usuarios podrán encontrarlo más fácilmente y ver que ya ha sido útil para otros.
+
+## Observa el repositorio de GitHub para lanzamientos
+
+Puedes "observar" FastAPI en GitHub (haciendo clic en el botón "watch" en la parte superior derecha): https://github.com/fastapi/fastapi. 👀
+
+Allí puedes seleccionar "Releases only".
+
+Al hacerlo, recibirás notificaciones (en tu email) cada vez que haya un nuevo lanzamiento (una nueva versión) de **FastAPI** con correcciones de bugs y nuevas funcionalidades.
+
+## Conéctate con el autor
+
+Puedes conectar conmigo (Sebastián Ramírez / `tiangolo`), el autor.
+
+Puedes:
+
+* Seguirme en **GitHub**.
+ * Ver otros proyectos de Código Abierto que he creado y que podrían ayudarte.
+ * Seguirme para ver cuándo creo un nuevo proyecto de Código Abierto.
+* Seguirme en **Twitter** o Mastodon.
+ * Contarme cómo usas FastAPI (me encanta oír eso).
+ * Enterarte cuando hago anuncios o lanzo nuevas herramientas.
+ * También puedes seguir @fastapi en Twitter (una cuenta aparte).
+* Seguirme en **LinkedIn**.
+ * Enterarte cuando hago anuncios o lanzo nuevas herramientas (aunque uso Twitter más a menudo 🤷♂).
+* Leer lo que escribo (o seguirme) en **Dev.to** o **Medium**.
+ * Leer otras ideas, artículos, y leer sobre las herramientas que he creado.
+ * Seguirme para leer lo que publico nuevo.
+
+## Twittea sobre **FastAPI**
+
+Twittea sobre **FastAPI** y dime a mí y a otros por qué te gusta. 🎉
+
+Me encanta escuchar cómo se está utilizando **FastAPI**, qué te ha gustado, en qué proyecto/empresa lo estás usando, etc.
+
+## Vota por FastAPI
+
+* Vota por **FastAPI** en Slant.
+* Vota por **FastAPI** en AlternativeTo.
+* Di que usas **FastAPI** en StackShare.
+
+## Ayuda a otros con preguntas en GitHub
+
+Puedes intentar ayudar a otros con sus preguntas en:
+
+* GitHub Discussions
+* GitHub Issues
+
+En muchos casos, probablemente ya conozcas la respuesta a esas preguntas. 🤓
+
+Si estás ayudando mucho a la gente con sus preguntas, te convertirás en un [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank} oficial. 🎉
+
+Solo recuerda, el punto más importante es: trata de ser amable. La gente llega con sus frustraciones y, en muchos casos, no pregunta de la mejor manera, pero haz todo lo posible por ser amable. 🤗
+
+La idea es que la comunidad de **FastAPI** sea amable y acogedora. Al mismo tiempo, no aceptes acoso o comportamiento irrespetuoso hacia los demás. Tenemos que cuidarnos unos a otros.
+
+---
+
+Aquí te explico cómo ayudar a otros con preguntas (en discusiones o issues):
+
+### Entiende la pregunta
+
+* Revisa si puedes entender cuál es el **propósito** y el caso de uso de la persona que pregunta.
+
+* Luego revisa si la pregunta (la gran mayoría son preguntas) es **clara**.
+
+* En muchos casos, la pregunta planteada es sobre una solución imaginaria del usuario, pero podría haber una **mejor**. Si puedes entender mejor el problema y el caso de uso, podrías sugerir una mejor **solución alternativa**.
+
+* Si no puedes entender la pregunta, pide más **detalles**.
+
+### Reproduce el problema
+
+En la mayoría de los casos y preguntas hay algo relacionado con el **código original** de la persona.
+
+En muchos casos solo copiarán un fragmento del código, pero eso no es suficiente para **reproducir el problema**.
+
+* Puedes pedirles que proporcionen un ejemplo mínimo, reproducible, que puedas **copiar-pegar** y ejecutar localmente para ver el mismo error o comportamiento que están viendo, o para entender mejor su caso de uso.
+
+* Si te sientes muy generoso, puedes intentar **crear un ejemplo** así tú mismo, solo basado en la descripción del problema. Solo ten en cuenta que esto podría llevar mucho tiempo y podría ser mejor pedirles que aclaren el problema primero.
+
+### Sugerir soluciones
+
+* Después de poder entender la pregunta, puedes darles un posible **respuesta**.
+
+* En muchos casos, es mejor entender su **problema subyacente o caso de uso**, porque podría haber una mejor manera de resolverlo que lo que están intentando hacer.
+
+### Pide cerrar
+
+Si responden, hay una alta probabilidad de que hayas resuelto su problema, felicidades, ¡**eres un héroe**! 🦸
+
+* Ahora, si eso resolvió su problema, puedes pedirles que:
+
+ * En GitHub Discussions: marquen el comentario como la **respuesta**.
+ * En GitHub Issues: **cierren** el issue.
+
+## Observa el repositorio de GitHub
+
+Puedes "observar" FastAPI en GitHub (haciendo clic en el botón "watch" en la parte superior derecha): https://github.com/fastapi/fastapi. 👀
+
+Si seleccionas "Watching" en lugar de "Releases only", recibirás notificaciones cuando alguien cree un nuevo issue o pregunta. También puedes especificar que solo deseas que te notifiquen sobre nuevos issues, discusiones, PRs, etc.
+
+Luego puedes intentar ayudarlos a resolver esas preguntas.
+
+## Haz preguntas
+
+Puedes crear una nueva pregunta en el repositorio de GitHub, por ejemplo, para:
+
+* Hacer una **pregunta** o preguntar sobre un **problema**.
+* Sugerir una nueva **funcionalidad**.
+
+**Nota**: si lo haces, entonces te voy a pedir que también ayudes a otros. 😉
+
+## Revisa Pull Requests
+
+Puedes ayudarme a revisar pull requests de otros.
+
+De nuevo, por favor, haz tu mejor esfuerzo por ser amable. 🤗
+
+---
+
+Aquí está lo que debes tener en cuenta y cómo revisar un pull request:
+
+### Entiende el problema
+
+* Primero, asegúrate de **entender el problema** que el pull request está intentando resolver. Podría tener una discusión más larga en una GitHub Discussion o issue.
+
+* También hay una buena posibilidad de que el pull request no sea realmente necesario porque el problema se puede resolver de una manera **diferente**. Entonces puedes sugerir o preguntar sobre eso.
+
+### No te preocupes por el estilo
+
+* No te preocupes demasiado por cosas como los estilos de los mensajes de commit, yo haré squash y merge personalizando el commit manualmente.
+
+* Tampoco te preocupes por las reglas de estilo, hay herramientas automatizadas verificando eso.
+
+Y si hay alguna otra necesidad de estilo o consistencia, pediré directamente eso, o agregaré commits encima con los cambios necesarios.
+
+### Revisa el código
+
+* Revisa y lee el código, ve si tiene sentido, **ejecútalo localmente** y ve si realmente resuelve el problema.
+
+* Luego **comenta** diciendo que hiciste eso, así sabré que realmente lo revisaste.
+
+/// info | Información
+
+Desafortunadamente, no puedo simplemente confiar en PRs que solo tienen varias aprobaciones.
+
+Varias veces ha sucedido que hay PRs con 3, 5 o más aprobaciones, probablemente porque la descripción es atractiva, pero cuando reviso los PRs, en realidad están rotos, tienen un bug, o no resuelven el problema que dicen resolver. 😅
+
+Así que, es realmente importante que realmente leas y ejecutes el código, y me hagas saber en los comentarios que lo hiciste. 🤓
+
+///
+
+* Si el PR se puede simplificar de alguna manera, puedes pedir eso, pero no hay necesidad de ser demasiado exigente, podría haber muchos puntos de vista subjetivos (y yo tendré el mío también 🙈), así que es mejor si puedes centrarte en las cosas fundamentales.
+
+### Tests
+
+* Ayúdame a verificar que el PR tenga **tests**.
+
+* Verifica que los tests **fallen** antes del PR. 🚨
+
+* Luego verifica que los tests **pasen** después del PR. ✅
+
+* Muchos PRs no tienen tests, puedes **recordarles** que agreguen tests, o incluso puedes **sugerir** algunos tests tú mismo. Eso es una de las cosas que consume más tiempo y puedes ayudar mucho con eso.
+
+* Luego también comenta lo que intentaste, de esa manera sabré que lo revisaste. 🤓
+
+## Crea un Pull Request
+
+Puedes [contribuir](contributing.md){.internal-link target=_blank} al código fuente con Pull Requests, por ejemplo:
+
+* Para corregir un error tipográfico que encontraste en la documentación.
+* Para compartir un artículo, video o podcast que creaste o encontraste sobre FastAPI editando este archivo.
+ * Asegúrate de agregar tu enlace al inicio de la sección correspondiente.
+* Para ayudar a [traducir la documentación](contributing.md#translations){.internal-link target=_blank} a tu idioma.
+ * También puedes ayudar a revisar las traducciones creadas por otros.
+* Para proponer nuevas secciones de documentación.
+* Para corregir un issue/bug existente.
+ * Asegúrate de agregar tests.
+* Para agregar una nueva funcionalidad.
+ * Asegúrate de agregar tests.
+ * Asegúrate de agregar documentación si es relevante.
+
+## Ayuda a Mantener FastAPI
+
+¡Ayúdame a mantener **FastAPI**! 🤓
+
+Hay mucho trabajo por hacer, y para la mayoría de ello, **TÚ** puedes hacerlo.
+
+Las tareas principales que puedes hacer ahora son:
+
+* [Ayudar a otros con preguntas en GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (ver la sección arriba).
+* [Revisar Pull Requests](#review-pull-requests){.internal-link target=_blank} (ver la sección arriba).
+
+Esas dos tareas son las que **consumen más tiempo**. Ese es el trabajo principal de mantener FastAPI.
+
+Si puedes ayudarme con eso, **me estás ayudando a mantener FastAPI** y asegurando que siga **avanzando más rápido y mejor**. 🚀
+
+## Únete al chat
+
+Únete al servidor de chat 👥 Discord 👥 y charla con otros en la comunidad de FastAPI.
+
+/// tip | Consejo
+
+Para preguntas, házlas en GitHub Discussions, hay muchas más probabilidades de que recibas ayuda de parte de los [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank}.
+
+Usa el chat solo para otras conversaciones generales.
+
+///
+
+### No uses el chat para preguntas
+
+Ten en cuenta que dado que los chats permiten una "conversación más libre", es fácil hacer preguntas que son demasiado generales y más difíciles de responder, por lo que es posible que no recibas respuestas.
+
+En GitHub, la plantilla te guiará para escribir la pregunta correcta para que puedas obtener más fácilmente una buena respuesta, o incluso resolver el problema por ti mismo antes de preguntar. Y en GitHub puedo asegurarme de responder siempre todo, incluso si lleva tiempo. No puedo hacer eso personalmente con los sistemas de chat. 😅
+
+Las conversaciones en los sistemas de chat tampoco son tan fácilmente buscables como en GitHub, por lo que las preguntas y respuestas podrían perderse en la conversación. Y solo las que están en GitHub cuentan para convertirse en un [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}, por lo que probablemente recibirás más atención en GitHub.
+
+Por otro lado, hay miles de usuarios en los sistemas de chat, por lo que hay muchas posibilidades de que encuentres a alguien con quien hablar allí, casi todo el tiempo. 😄
+
+## Patrocina al autor
+
+También puedes apoyar financieramente al autor (a mí) a través de GitHub sponsors.
+
+Allí podrías comprarme un café ☕️ para decir gracias. 😄
+
+Y también puedes convertirte en un sponsor de Plata o de Oro para FastAPI. 🏅🎉
+
+## Patrocina las herramientas que impulsan FastAPI
+
+Como habrás visto en la documentación, FastAPI se apoya en los hombros de gigantes, Starlette y Pydantic.
+
+También puedes patrocinar:
+
+* Samuel Colvin (Pydantic)
+* Encode (Starlette, Uvicorn)
+
+---
+
+¡Gracias! 🚀
diff --git a/docs/es/docs/history-design-future.md b/docs/es/docs/history-design-future.md
new file mode 100644
index 000000000..8beb4f400
--- /dev/null
+++ b/docs/es/docs/history-design-future.md
@@ -0,0 +1,79 @@
+# Historia, Diseño y Futuro
+
+Hace algún tiempo, un usuario de **FastAPI** preguntó:
+
+> ¿Cuál es la historia de este proyecto? Parece haber surgido de la nada y ser increíble en pocas semanas [...]
+
+Aquí hay un poquito de esa historia.
+
+## Alternativas
+
+He estado creando APIs con requisitos complejos durante varios años (Machine Learning, sistemas distribuidos, trabajos asíncronos, bases de datos NoSQL, etc.), liderando varios equipos de desarrolladores.
+
+Como parte de eso, necesitaba investigar, probar y usar muchas alternativas.
+
+La historia de **FastAPI** es en gran parte la historia de sus predecesores.
+
+Como se dice en la sección [Alternativas](alternatives.md){.internal-link target=_blank}:
+
+
+
+**FastAPI** no existiría si no fuera por el trabajo previo de otros.
+
+Ha habido muchas herramientas creadas antes que han ayudado a inspirar su creación.
+
+He estado evitando la creación de un nuevo framework durante varios años. Primero traté de resolver todas las funcionalidades cubiertas por **FastAPI** usando varios frameworks, complementos y herramientas diferentes.
+
+Pero en algún momento, no había otra opción que crear algo que proporcionara todas estas funcionalidades, tomando las mejores ideas de herramientas anteriores y combinándolas de la mejor manera posible, usando funcionalidades del lenguaje que ni siquiera estaban disponibles antes (anotaciones de tipos de Python 3.6+).
+
+
+
+## Investigación
+
+Al usar todas las alternativas anteriores, tuve la oportunidad de aprender de todas ellas, tomar ideas y combinarlas de la mejor manera que pude encontrar para mí y los equipos de desarrolladores con los que he trabajado.
+
+Por ejemplo, estaba claro que idealmente debería estar basado en las anotaciones de tipos estándar de Python.
+
+También, el mejor enfoque era usar estándares ya existentes.
+
+Entonces, antes de siquiera empezar a programar **FastAPI**, pasé varios meses estudiando las especificaciones de OpenAPI, JSON Schema, OAuth2, etc. Entendiendo su relación, superposición y diferencias.
+
+## Diseño
+
+Luego pasé algún tiempo diseñando la "API" de desarrollador que quería tener como usuario (como desarrollador usando FastAPI).
+
+Probé varias ideas en los editores de Python más populares: PyCharm, VS Code, editores basados en Jedi.
+
+Según la última Encuesta de Desarrolladores de Python, estos editores cubren alrededor del 80% de los usuarios.
+
+Esto significa que **FastAPI** fue específicamente probado con los editores usados por el 80% de los desarrolladores de Python. Y como la mayoría de los otros editores tienden a funcionar de manera similar, todos sus beneficios deberían funcionar prácticamente para todos los editores.
+
+De esa manera, pude encontrar las mejores maneras de reducir la duplicación de código tanto como fuera posible, para tener autocompletado en todas partes, chequeos de tipos y errores, etc.
+
+Todo de una manera que proporcionara la mejor experiencia de desarrollo para todos los desarrolladores.
+
+## Requisitos
+
+Después de probar varias alternativas, decidí que iba a usar **Pydantic** por sus ventajas.
+
+Luego contribuí a este, para hacerlo totalmente compatible con JSON Schema, para soportar diferentes maneras de definir declaraciones de restricciones, y para mejorar el soporte de los editores (chequeo de tipos, autocompletado) basado en las pruebas en varios editores.
+
+Durante el desarrollo, también contribuí a **Starlette**, el otro requisito clave.
+
+## Desarrollo
+
+Para cuando comencé a crear el propio **FastAPI**, la mayoría de las piezas ya estaban en su lugar, el diseño estaba definido, los requisitos y herramientas estaban listos, y el conocimiento sobre los estándares y especificaciones estaba claro y fresco.
+
+## Futuro
+
+A este punto, ya está claro que **FastAPI** con sus ideas está siendo útil para muchas personas.
+
+Está siendo elegido sobre alternativas anteriores por adaptarse mejor a muchos casos de uso.
+
+Muchos desarrolladores y equipos ya dependen de **FastAPI** para sus proyectos (incluyéndome a mí y a mi equipo).
+
+Pero aún así, hay muchas mejoras y funcionalidades por venir.
+
+**FastAPI** tiene un gran futuro por delante.
+
+Y [tu ayuda](help-fastapi.md){.internal-link target=_blank} es muy apreciada.
diff --git a/docs/es/docs/how-to/conditional-openapi.md b/docs/es/docs/how-to/conditional-openapi.md
new file mode 100644
index 000000000..4f806ef6c
--- /dev/null
+++ b/docs/es/docs/how-to/conditional-openapi.md
@@ -0,0 +1,56 @@
+# OpenAPI Condicional
+
+Si lo necesitaras, podrías usar configuraciones y variables de entorno para configurar OpenAPI condicionalmente según el entorno, e incluso desactivarlo por completo.
+
+## Sobre seguridad, APIs y documentación
+
+Ocultar las interfaces de usuario de la documentación en producción *no debería* ser la forma de proteger tu API.
+
+Eso no añade ninguna seguridad extra a tu API, las *path operations* seguirán estando disponibles donde están.
+
+Si hay una falla de seguridad en tu código, seguirá existiendo.
+
+Ocultar la documentación solo hace que sea más difícil entender cómo interactuar con tu API y podría dificultar más depurarla en producción. Podría considerarse simplemente una forma de Seguridad mediante oscuridad.
+
+Si quieres asegurar tu API, hay varias cosas mejores que puedes hacer, por ejemplo:
+
+* Asegúrate de tener modelos Pydantic bien definidos para tus request bodies y responses.
+* Configura los permisos y roles necesarios usando dependencias.
+* Nunca guardes contraseñas en texto plano, solo hashes de contraseñas.
+* Implementa y utiliza herramientas criptográficas bien conocidas, como Passlib y JWT tokens, etc.
+* Añade controles de permisos más detallados con OAuth2 scopes donde sea necesario.
+* ...etc.
+
+No obstante, podrías tener un caso de uso muy específico donde realmente necesites desactivar la documentación de la API para algún entorno (por ejemplo, para producción) o dependiendo de configuraciones de variables de entorno.
+
+## OpenAPI condicional desde configuraciones y variables de entorno
+
+Puedes usar fácilmente las mismas configuraciones de Pydantic para configurar tu OpenAPI generado y las interfaces de usuario de la documentación.
+
+Por ejemplo:
+
+{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *}
+
+Aquí declaramos la configuración `openapi_url` con el mismo valor predeterminado de `"/openapi.json"`.
+
+Y luego la usamos al crear la app de `FastAPI`.
+
+Entonces podrías desactivar OpenAPI (incluyendo las UI de documentación) configurando la variable de entorno `OPENAPI_URL` a una string vacía, así:
+
+
+
+```console
+$ OPENAPI_URL= uvicorn main:app
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Luego, si vas a las URLs en `/openapi.json`, `/docs`, o `/redoc`, solo obtendrás un error `404 Not Found` como:
+
+```JSON
+{
+ "detail": "Not Found"
+}
+```
diff --git a/docs/es/docs/how-to/configure-swagger-ui.md b/docs/es/docs/how-to/configure-swagger-ui.md
new file mode 100644
index 000000000..4243c191c
--- /dev/null
+++ b/docs/es/docs/how-to/configure-swagger-ui.md
@@ -0,0 +1,70 @@
+# Configurar Swagger UI
+
+Puedes configurar algunos parámetros adicionales de Swagger UI.
+
+Para configurarlos, pasa el argumento `swagger_ui_parameters` al crear el objeto de la app `FastAPI()` o a la función `get_swagger_ui_html()`.
+
+`swagger_ui_parameters` recibe un diccionario con las configuraciones pasadas directamente a Swagger UI.
+
+FastAPI convierte las configuraciones a **JSON** para hacerlas compatibles con JavaScript, ya que eso es lo que Swagger UI necesita.
+
+## Desactivar el resaltado de sintaxis
+
+Por ejemplo, podrías desactivar el resaltado de sintaxis en Swagger UI.
+
+Sin cambiar la configuración, el resaltado de sintaxis está activado por defecto:
+
+
+
+Pero puedes desactivarlo estableciendo `syntaxHighlight` en `False`:
+
+{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *}
+
+...y entonces Swagger UI ya no mostrará el resaltado de sintaxis:
+
+
+
+## Cambiar el tema
+
+De la misma manera, podrías configurar el tema del resaltado de sintaxis con la clave `"syntaxHighlight.theme"` (ten en cuenta que tiene un punto en el medio):
+
+{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *}
+
+Esa configuración cambiaría el tema de color del resaltado de sintaxis:
+
+
+
+## Cambiar los parámetros predeterminados de Swagger UI
+
+FastAPI incluye algunos parámetros de configuración predeterminados apropiados para la mayoría de los casos de uso.
+
+Incluye estas configuraciones predeterminadas:
+
+{* ../../fastapi/openapi/docs.py ln[8:23] hl[17:23] *}
+
+Puedes sobrescribir cualquiera de ellos estableciendo un valor diferente en el argumento `swagger_ui_parameters`.
+
+Por ejemplo, para desactivar `deepLinking` podrías pasar estas configuraciones a `swagger_ui_parameters`:
+
+{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *}
+
+## Otros parámetros de Swagger UI
+
+Para ver todas las demás configuraciones posibles que puedes usar, lee la documentación oficial de los parámetros de Swagger UI.
+
+## Configuraciones solo de JavaScript
+
+Swagger UI también permite otras configuraciones que son objetos **solo de JavaScript** (por ejemplo, funciones de JavaScript).
+
+FastAPI también incluye estas configuraciones `presets` solo de JavaScript:
+
+```JavaScript
+presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+]
+```
+
+Estos son objetos de **JavaScript**, no strings, por lo que no puedes pasarlos directamente desde código de Python.
+
+Si necesitas usar configuraciones solo de JavaScript como esas, puedes usar uno de los métodos anteriores. Sobrescribe toda la *path operation* de Swagger UI y escribe manualmente cualquier JavaScript que necesites.
diff --git a/docs/es/docs/how-to/custom-docs-ui-assets.md b/docs/es/docs/how-to/custom-docs-ui-assets.md
new file mode 100644
index 000000000..0a03ff330
--- /dev/null
+++ b/docs/es/docs/how-to/custom-docs-ui-assets.md
@@ -0,0 +1,185 @@
+# Recursos Estáticos Personalizados para la Docs UI (Self-Hosting)
+
+La documentación de la API utiliza **Swagger UI** y **ReDoc**, y cada uno de estos necesita algunos archivos JavaScript y CSS.
+
+Por defecto, esos archivos se sirven desde un CDN.
+
+Pero es posible personalizarlo, puedes establecer un CDN específico, o servir los archivos tú mismo.
+
+## CDN Personalizado para JavaScript y CSS
+
+Digamos que quieres usar un CDN diferente, por ejemplo, quieres usar `https://unpkg.com/`.
+
+Esto podría ser útil si, por ejemplo, vives en un país que restringe algunas URLs.
+
+### Desactiva la documentación automática
+
+El primer paso es desactivar la documentación automática, ya que por defecto, esos usan el CDN predeterminado.
+
+Para desactivarlos, establece sus URLs en `None` cuando crees tu aplicación de `FastAPI`:
+
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *}
+
+### Incluye la documentación personalizada
+
+Ahora puedes crear las *path operations* para la documentación personalizada.
+
+Puedes reutilizar las funciones internas de FastAPI para crear las páginas HTML para la documentación, y pasarles los argumentos necesarios:
+
+* `openapi_url`: la URL donde la página HTML para la documentación puede obtener el OpenAPI esquema de tu API. Puedes usar aquí el atributo `app.openapi_url`.
+* `title`: el título de tu API.
+* `oauth2_redirect_url`: puedes usar `app.swagger_ui_oauth2_redirect_url` aquí para usar el valor predeterminado.
+* `swagger_js_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **JavaScript**. Esta es la URL personalizada del CDN.
+* `swagger_css_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **CSS**. Esta es la URL personalizada del CDN.
+
+Y de manera similar para ReDoc...
+
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *}
+
+/// tip | Consejo
+
+La *path operation* para `swagger_ui_redirect` es una herramienta cuando utilizas OAuth2.
+
+Si integras tu API con un proveedor OAuth2, podrás autenticarte y regresar a la documentación de la API con las credenciales adquiridas. E interactuar con ella usando la autenticación real de OAuth2.
+
+Swagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar de "redirección".
+
+///
+
+### Crea una *path operation* para probarlo
+
+Ahora, para poder probar que todo funciona, crea una *path operation*:
+
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *}
+
+### Pruébalo
+
+Ahora, deberías poder ir a tu documentación en http://127.0.0.1:8000/docs, y recargar la página, cargará esos recursos desde el nuevo CDN.
+
+## Self-hosting de JavaScript y CSS para la documentación
+
+El self-hosting de JavaScript y CSS podría ser útil si, por ejemplo, necesitas que tu aplicación siga funcionando incluso offline, sin acceso a Internet, o en una red local.
+
+Aquí verás cómo servir esos archivos tú mismo, en la misma aplicación de FastAPI, y configurar la documentación para usarla.
+
+### Estructura de archivos del proyecto
+
+Supongamos que la estructura de archivos de tu proyecto se ve así:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+```
+
+Ahora crea un directorio para almacenar esos archivos estáticos.
+
+Tu nueva estructura de archivos podría verse así:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static/
+```
+
+### Descarga los archivos
+
+Descarga los archivos estáticos necesarios para la documentación y ponlos en ese directorio `static/`.
+
+Probablemente puedas hacer clic derecho en cada enlace y seleccionar una opción similar a `Guardar enlace como...`.
+
+**Swagger UI** utiliza los archivos:
+
+* `swagger-ui-bundle.js`
+* `swagger-ui.css`
+
+Y **ReDoc** utiliza el archivo:
+
+* `redoc.standalone.js`
+
+Después de eso, tu estructura de archivos podría verse así:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+└── static
+ ├── redoc.standalone.js
+ ├── swagger-ui-bundle.js
+ └── swagger-ui.css
+```
+
+### Sirve los archivos estáticos
+
+* Importa `StaticFiles`.
+* "Monta" una instance de `StaticFiles()` en un path específico.
+
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *}
+
+### Prueba los archivos estáticos
+
+Inicia tu aplicación y ve a http://127.0.0.1:8000/static/redoc.standalone.js.
+
+Deberías ver un archivo JavaScript muy largo de **ReDoc**.
+
+Podría comenzar con algo como:
+
+```JavaScript
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
+...
+```
+
+Eso confirma que puedes servir archivos estáticos desde tu aplicación, y que colocaste los archivos estáticos para la documentación en el lugar correcto.
+
+Ahora podemos configurar la aplicación para usar esos archivos estáticos para la documentación.
+
+### Desactiva la documentación automática para archivos estáticos
+
+Igual que cuando usas un CDN personalizado, el primer paso es desactivar la documentación automática, ya que esos usan el CDN por defecto.
+
+Para desactivarlos, establece sus URLs en `None` cuando crees tu aplicación de `FastAPI`:
+
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *}
+
+### Incluye la documentación personalizada para archivos estáticos
+
+Y de la misma manera que con un CDN personalizado, ahora puedes crear las *path operations* para la documentación personalizada.
+
+Nuevamente, puedes reutilizar las funciones internas de FastAPI para crear las páginas HTML para la documentación, y pasarles los argumentos necesarios:
+
+* `openapi_url`: la URL donde la página HTML para la documentación puede obtener el OpenAPI esquema de tu API. Puedes usar aquí el atributo `app.openapi_url`.
+* `title`: el título de tu API.
+* `oauth2_redirect_url`: puedes usar `app.swagger_ui_oauth2_redirect_url` aquí para usar el valor predeterminado.
+* `swagger_js_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **JavaScript**. **Este es el que tu propia aplicación está sirviendo ahora**.
+* `swagger_css_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **CSS**. **Este es el que tu propia aplicación está sirviendo ahora**.
+
+Y de manera similar para ReDoc...
+
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *}
+
+/// tip | Consejo
+
+La *path operation* para `swagger_ui_redirect` es una herramienta cuando utilizas OAuth2.
+
+Si integras tu API con un proveedor OAuth2, podrás autenticarte y regresar a la documentación de la API con las credenciales adquiridas. Y interactuar con ella usando la autenticación real de OAuth2.
+
+Swagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar de "redirección".
+
+///
+
+### Crea una *path operation* para probar archivos estáticos
+
+Ahora, para poder probar que todo funciona, crea una *path operation*:
+
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *}
+
+### Prueba la UI de Archivos Estáticos
+
+Ahora, deberías poder desconectar tu WiFi, ir a tu documentación en http://127.0.0.1:8000/docs, y recargar la página.
+
+E incluso sin Internet, podrás ver la documentación de tu API e interactuar con ella.
diff --git a/docs/es/docs/how-to/custom-request-and-route.md b/docs/es/docs/how-to/custom-request-and-route.md
new file mode 100644
index 000000000..0b479bf00
--- /dev/null
+++ b/docs/es/docs/how-to/custom-request-and-route.md
@@ -0,0 +1,109 @@
+# Clase personalizada de Request y APIRoute
+
+En algunos casos, puede que quieras sobrescribir la lógica utilizada por las clases `Request` y `APIRoute`.
+
+En particular, esta puede ser una buena alternativa a la lógica en un middleware.
+
+Por ejemplo, si quieres leer o manipular el request body antes de que sea procesado por tu aplicación.
+
+/// danger | Advertencia
+
+Esta es una funcionalidad "avanzada".
+
+Si apenas estás comenzando con **FastAPI**, quizás quieras saltar esta sección.
+
+///
+
+## Casos de uso
+
+Algunos casos de uso incluyen:
+
+* Convertir cuerpos de requests no-JSON a JSON (por ejemplo, `msgpack`).
+* Descomprimir cuerpos de requests comprimidos con gzip.
+* Registrar automáticamente todos los request bodies.
+
+## Manejo de codificaciones personalizadas de request body
+
+Veamos cómo hacer uso de una subclase personalizada de `Request` para descomprimir requests gzip.
+
+Y una subclase de `APIRoute` para usar esa clase de request personalizada.
+
+### Crear una clase personalizada `GzipRequest`
+
+/// tip | Consejo
+
+Este es un ejemplo sencillo para demostrar cómo funciona. Si necesitas soporte para Gzip, puedes usar el [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware){.internal-link target=_blank} proporcionado.
+
+///
+
+Primero, creamos una clase `GzipRequest`, que sobrescribirá el método `Request.body()` para descomprimir el cuerpo si hay un header apropiado.
+
+Si no hay `gzip` en el header, no intentará descomprimir el cuerpo.
+
+De esa manera, la misma clase de ruta puede manejar requests comprimidos con gzip o no comprimidos.
+
+{* ../../docs_src/custom_request_and_route/tutorial001.py hl[8:15] *}
+
+### Crear una clase personalizada `GzipRoute`
+
+A continuación, creamos una subclase personalizada de `fastapi.routing.APIRoute` que hará uso de `GzipRequest`.
+
+Esta vez, sobrescribirá el método `APIRoute.get_route_handler()`.
+
+Este método devuelve una función. Y esa función es la que recibirá un request y devolverá un response.
+
+Aquí lo usamos para crear un `GzipRequest` a partir del request original.
+
+{* ../../docs_src/custom_request_and_route/tutorial001.py hl[18:26] *}
+
+/// note | Detalles técnicos
+
+Un `Request` tiene un atributo `request.scope`, que es simplemente un `dict` de Python que contiene los metadatos relacionados con el request.
+
+Un `Request` también tiene un `request.receive`, que es una función para "recibir" el cuerpo del request.
+
+El `dict` `scope` y la función `receive` son ambos parte de la especificación ASGI.
+
+Y esas dos cosas, `scope` y `receive`, son lo que se necesita para crear una nueva *Request instance*.
+
+Para aprender más sobre el `Request`, revisa la documentación de Starlette sobre Requests.
+
+///
+
+La única cosa que la función devuelta por `GzipRequest.get_route_handler` hace diferente es convertir el `Request` en un `GzipRequest`.
+
+Haciendo esto, nuestro `GzipRequest` se encargará de descomprimir los datos (si es necesario) antes de pasarlos a nuestras *path operations*.
+
+Después de eso, toda la lógica de procesamiento es la misma.
+
+Pero debido a nuestros cambios en `GzipRequest.body`, el request body se descomprimirá automáticamente cuando sea cargado por **FastAPI** si es necesario.
+
+## Accediendo al request body en un manejador de excepciones
+
+/// tip | Consejo
+
+Para resolver este mismo problema, probablemente sea mucho más fácil usar el `body` en un manejador personalizado para `RequestValidationError` ([Manejo de Errores](../tutorial/handling-errors.md#use-the-requestvalidationerror-body){.internal-link target=_blank}).
+
+Pero este ejemplo sigue siendo válido y muestra cómo interactuar con los componentes internos.
+
+///
+
+También podemos usar este mismo enfoque para acceder al request body en un manejador de excepciones.
+
+Todo lo que necesitamos hacer es manejar el request dentro de un bloque `try`/`except`:
+
+{* ../../docs_src/custom_request_and_route/tutorial002.py hl[13,15] *}
+
+Si ocurre una excepción, la `Request instance` aún estará en el alcance, así que podemos leer y hacer uso del request body cuando manejamos el error:
+
+{* ../../docs_src/custom_request_and_route/tutorial002.py hl[16:18] *}
+
+## Clase personalizada `APIRoute` en un router
+
+También puedes establecer el parámetro `route_class` de un `APIRouter`:
+
+{* ../../docs_src/custom_request_and_route/tutorial003.py hl[26] *}
+
+En este ejemplo, las *path operations* bajo el `router` usarán la clase personalizada `TimedRoute`, y tendrán un header `X-Response-Time` extra en el response con el tiempo que tomó generar el response:
+
+{* ../../docs_src/custom_request_and_route/tutorial003.py hl[13:20] *}
diff --git a/docs/es/docs/how-to/extending-openapi.md b/docs/es/docs/how-to/extending-openapi.md
new file mode 100644
index 000000000..3dbdd666b
--- /dev/null
+++ b/docs/es/docs/how-to/extending-openapi.md
@@ -0,0 +1,80 @@
+# Extender OpenAPI
+
+Hay algunos casos en los que podrías necesitar modificar el esquema de OpenAPI generado.
+
+En esta sección verás cómo hacerlo.
+
+## El proceso normal
+
+El proceso normal (por defecto) es el siguiente.
+
+Una aplicación (instance) de `FastAPI` tiene un método `.openapi()` que se espera que devuelva el esquema de OpenAPI.
+
+Como parte de la creación del objeto de la aplicación, se registra una *path operation* para `/openapi.json` (o para lo que sea que configures tu `openapi_url`).
+
+Simplemente devuelve un response JSON con el resultado del método `.openapi()` de la aplicación.
+
+Por defecto, lo que hace el método `.openapi()` es revisar la propiedad `.openapi_schema` para ver si tiene contenido y devolverlo.
+
+Si no lo tiene, lo genera usando la función de utilidad en `fastapi.openapi.utils.get_openapi`.
+
+Y esa función `get_openapi()` recibe como parámetros:
+
+* `title`: El título de OpenAPI, mostrado en la documentación.
+* `version`: La versión de tu API, por ejemplo `2.5.0`.
+* `openapi_version`: La versión de la especificación OpenAPI utilizada. Por defecto, la más reciente: `3.1.0`.
+* `summary`: Un breve resumen de la API.
+* `description`: La descripción de tu API, esta puede incluir markdown y se mostrará en la documentación.
+* `routes`: Una list de rutas, estas son cada una de las *path operations* registradas. Se toman de `app.routes`.
+
+/// info | Información
+
+El parámetro `summary` está disponible en OpenAPI 3.1.0 y versiones superiores, soportado por FastAPI 0.99.0 y superiores.
+
+///
+
+## Sobrescribir los valores por defecto
+
+Usando la información anterior, puedes usar la misma función de utilidad para generar el esquema de OpenAPI y sobrescribir cada parte que necesites.
+
+Por ejemplo, vamos a añadir la extensión OpenAPI de ReDoc para incluir un logo personalizado.
+
+### **FastAPI** normal
+
+Primero, escribe toda tu aplicación **FastAPI** como normalmente:
+
+{* ../../docs_src/extending_openapi/tutorial001.py hl[1,4,7:9] *}
+
+### Generar el esquema de OpenAPI
+
+Luego, usa la misma función de utilidad para generar el esquema de OpenAPI, dentro de una función `custom_openapi()`:
+
+{* ../../docs_src/extending_openapi/tutorial001.py hl[2,15:21] *}
+
+### Modificar el esquema de OpenAPI
+
+Ahora puedes añadir la extensión de ReDoc, agregando un `x-logo` personalizado al "objeto" `info` en el esquema de OpenAPI:
+
+{* ../../docs_src/extending_openapi/tutorial001.py hl[22:24] *}
+
+### Cachear el esquema de OpenAPI
+
+Puedes usar la propiedad `.openapi_schema` como un "cache", para almacenar tu esquema generado.
+
+De esa forma, tu aplicación no tendrá que generar el esquema cada vez que un usuario abra la documentación de tu API.
+
+Se generará solo una vez, y luego se usará el mismo esquema cacheado para las siguientes requests.
+
+{* ../../docs_src/extending_openapi/tutorial001.py hl[13:14,25:26] *}
+
+### Sobrescribir el método
+
+Ahora puedes reemplazar el método `.openapi()` por tu nueva función.
+
+{* ../../docs_src/extending_openapi/tutorial001.py hl[29] *}
+
+### Revisa
+
+Una vez que vayas a http://127.0.0.1:8000/redoc verás que estás usando tu logo personalizado (en este ejemplo, el logo de **FastAPI**):
+
+
diff --git a/docs/es/docs/how-to/general.md b/docs/es/docs/how-to/general.md
new file mode 100644
index 000000000..e10621ce5
--- /dev/null
+++ b/docs/es/docs/how-to/general.md
@@ -0,0 +1,39 @@
+# General - Cómo Hacer - Recetas
+
+Aquí tienes varias indicaciones hacia otros lugares en la documentación, para preguntas generales o frecuentes.
+
+## Filtrar Datos - Seguridad
+
+Para asegurarte de que no devuelves más datos de los que deberías, lee la documentación para [Tutorial - Modelo de Response - Tipo de Retorno](../tutorial/response-model.md){.internal-link target=_blank}.
+
+## Etiquetas de Documentación - OpenAPI
+
+Para agregar etiquetas a tus *path operations*, y agruparlas en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Etiquetas](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}.
+
+## Resumen y Descripción de Documentación - OpenAPI
+
+Para agregar un resumen y descripción a tus *path operations*, y mostrarlos en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Resumen y Descripción](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}.
+
+## Documentación de Descripción de Response - OpenAPI
+
+Para definir la descripción del response, mostrada en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Descripción del Response](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}.
+
+## Documentar la Deprecación de una *Path Operation* - OpenAPI
+
+Para deprecar una *path operation*, y mostrarla en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Deprecación](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}.
+
+## Convertir cualquier Dato a Compatible con JSON
+
+Para convertir cualquier dato a compatible con JSON, lee la documentación para [Tutorial - Codificador Compatible con JSON](../tutorial/encoder.md){.internal-link target=_blank}.
+
+## Metadatos OpenAPI - Documentación
+
+Para agregar metadatos a tu esquema de OpenAPI, incluyendo una licencia, versión, contacto, etc, lee la documentación para [Tutorial - Metadatos y URLs de Documentación](../tutorial/metadata.md){.internal-link target=_blank}.
+
+## URL Personalizada de OpenAPI
+
+Para personalizar la URL de OpenAPI (o eliminarla), lee la documentación para [Tutorial - Metadatos y URLs de Documentación](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}.
+
+## URLs de Documentación de OpenAPI
+
+Para actualizar las URLs usadas para las interfaces de usuario de documentación generadas automáticamente, lee la documentación para [Tutorial - Metadatos y URLs de Documentación](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}.
diff --git a/docs/es/docs/how-to/graphql.md b/docs/es/docs/how-to/graphql.md
index 9e5f3c9d5..52f163809 100644
--- a/docs/es/docs/how-to/graphql.md
+++ b/docs/es/docs/how-to/graphql.md
@@ -1,62 +1,60 @@
# GraphQL
-Como **FastAPI** está basado en el estándar **ASGI**, es muy fácil integrar cualquier library **GraphQL** que sea compatible con ASGI.
+Como **FastAPI** se basa en el estándar **ASGI**, es muy fácil integrar cualquier paquete de **GraphQL** que también sea compatible con ASGI.
-Puedes combinar *operaciones de path* regulares de la library de FastAPI con GraphQL en la misma aplicación.
+Puedes combinar las *path operations* normales de FastAPI con GraphQL en la misma aplicación.
/// tip | Consejo
-**GraphQL** resuelve algunos casos de uso específicos.
+**GraphQL** resuelve algunos casos de uso muy específicos.
-Tiene **ventajas** y **desventajas** cuando lo comparas con **APIs web** comunes.
+Tiene **ventajas** y **desventajas** en comparación con las **APIs web** comunes.
-Asegúrate de evaluar si los **beneficios** para tu caso de uso compensan las **desventajas.** 🤓
+Asegúrate de evaluar si los **beneficios** para tu caso de uso compensan los **inconvenientes**. 🤓
///
-## Librerías GraphQL
+## Paquetes de GraphQL
-Aquí hay algunas de las libraries de **GraphQL** que tienen soporte con **ASGI** las cuales podrías usar con **FastAPI**:
+Aquí algunos de los paquetes de **GraphQL** que tienen soporte **ASGI**. Podrías usarlos con **FastAPI**:
* Strawberry 🍓
* Con documentación para FastAPI
* Ariadne
* Con documentación para FastAPI
* Tartiflette
- * Con Tartiflette ASGI para proveer integración con ASGI
+ * Con Tartiflette ASGI para proporcionar integración con ASGI
* Graphene
* Con starlette-graphene3
## GraphQL con Strawberry
-Si necesitas o quieres trabajar con **GraphQL**, **Strawberry** es la library **recomendada** por el diseño más cercano a **FastAPI**, el cual es completamente basado en **anotaciones de tipo**.
+Si necesitas o quieres trabajar con **GraphQL**, **Strawberry** es el paquete **recomendado** ya que tiene un diseño muy similar al diseño de **FastAPI**, todo basado en **anotaciones de tipos**.
-Dependiendo de tus casos de uso, podrías preferir usar una library diferente, pero si me preguntas, probablemente te recomendaría **Strawberry**.
+Dependiendo de tu caso de uso, podrías preferir usar un paquete diferente, pero si me preguntas, probablemente te sugeriría probar **Strawberry**.
-Aquí hay una pequeña muestra de cómo podrías integrar Strawberry con FastAPI:
+Aquí tienes una pequeña vista previa de cómo podrías integrar Strawberry con FastAPI:
-```Python hl_lines="3 22 25-26"
-{!../../docs_src/graphql/tutorial001.py!}
-```
+{* ../../docs_src/graphql/tutorial001.py hl[3,22,25:26] *}
Puedes aprender más sobre Strawberry en la documentación de Strawberry.
-Y también en la documentación sobre Strawberry con FastAPI.
+Y también la documentación sobre Strawberry con FastAPI.
-## Clase obsoleta `GraphQLApp` en Starlette
+## `GraphQLApp` viejo de Starlette
-Versiones anteriores de Starlette incluyen la clase `GraphQLApp` para integrarlo con Graphene.
+Las versiones anteriores de Starlette incluían una clase `GraphQLApp` para integrar con Graphene.
-Esto fue marcado como obsoleto en Starlette, pero si aún tienes código que lo usa, puedes fácilmente **migrar** a starlette-graphene3, la cual cubre el mismo caso de uso y tiene una **interfaz casi idéntica.**
+Fue deprecada de Starlette, pero si tienes código que lo usaba, puedes fácilmente **migrar** a starlette-graphene3, que cubre el mismo caso de uso y tiene una **interfaz casi idéntica**.
/// tip | Consejo
-Si necesitas GraphQL, te recomendaría revisar Strawberry, que es basada en anotaciones de tipo en vez de clases y tipos personalizados.
+Si necesitas GraphQL, aún te recomendaría revisar Strawberry, ya que se basa en anotaciones de tipos en lugar de clases y tipos personalizados.
///
-## Aprende más
+## Aprende Más
-Puedes aprender más acerca de **GraphQL** en la documentación oficial de GraphQL.
+Puedes aprender más sobre **GraphQL** en la documentación oficial de GraphQL.
-También puedes leer más acerca de cada library descrita anteriormente en sus enlaces.
+También puedes leer más sobre cada uno de esos paquetes descritos arriba en sus enlaces.
diff --git a/docs/es/docs/how-to/index.md b/docs/es/docs/how-to/index.md
new file mode 100644
index 000000000..152499af8
--- /dev/null
+++ b/docs/es/docs/how-to/index.md
@@ -0,0 +1,13 @@
+# How To - Recetas
+
+Aquí verás diferentes recetas o guías de "cómo hacer" para **varios temas**.
+
+La mayoría de estas ideas serían más o menos **independientes**, y en la mayoría de los casos solo deberías estudiarlas si aplican directamente a **tu proyecto**.
+
+Si algo parece interesante y útil para tu proyecto, adelante y revísalo, pero de lo contrario, probablemente puedas simplemente omitirlas.
+
+/// tip | Consejo
+
+Si quieres **aprender FastAPI** de una manera estructurada (recomendado), ve y lee el [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} capítulo por capítulo.
+
+///
diff --git a/docs/es/docs/how-to/separate-openapi-schemas.md b/docs/es/docs/how-to/separate-openapi-schemas.md
new file mode 100644
index 000000000..b77915851
--- /dev/null
+++ b/docs/es/docs/how-to/separate-openapi-schemas.md
@@ -0,0 +1,104 @@
+# Separación de Esquemas OpenAPI para Entrada y Salida o No
+
+Al usar **Pydantic v2**, el OpenAPI generado es un poco más exacto y **correcto** que antes. 😎
+
+De hecho, en algunos casos, incluso tendrá **dos JSON Schemas** en OpenAPI para el mismo modelo Pydantic, para entrada y salida, dependiendo de si tienen **valores por defecto**.
+
+Veamos cómo funciona eso y cómo cambiarlo si necesitas hacerlo.
+
+## Modelos Pydantic para Entrada y Salida
+
+Digamos que tienes un modelo Pydantic con valores por defecto, como este:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
+
+### Modelo para Entrada
+
+Si usas este modelo como entrada, como aquí:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
+
+...entonces el campo `description` **no será requerido**. Porque tiene un valor por defecto de `None`.
+
+### Modelo de Entrada en la Documentación
+
+Puedes confirmar eso en la documentación, el campo `description` no tiene un **asterisco rojo**, no está marcado como requerido:
+
+
+
+
+
+### Modelo para Salida
+
+Pero si usas el mismo modelo como salida, como aquí:
+
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
+
+...entonces, porque `description` tiene un valor por defecto, si **no devuelves nada** para ese campo, aún tendrá ese **valor por defecto**.
+
+### Modelo para Datos de Response de Salida
+
+Si interactúas con la documentación y revisas el response, aunque el código no agregó nada en uno de los campos `description`, el response JSON contiene el valor por defecto (`null`):
+
+
+
+
+
+Esto significa que **siempre tendrá un valor**, solo que a veces el valor podría ser `None` (o `null` en JSON).
+
+Eso significa que, los clientes que usan tu API no tienen que comprobar si el valor existe o no, pueden **asumir que el campo siempre estará allí**, pero solo que en algunos casos tendrá el valor por defecto de `None`.
+
+La forma de describir esto en OpenAPI es marcar ese campo como **requerido**, porque siempre estará allí.
+
+Debido a eso, el JSON Schema para un modelo puede ser diferente dependiendo de si se usa para **entrada o salida**:
+
+* para **entrada** el `description` **no será requerido**
+* para **salida** será **requerido** (y posiblemente `None`, o en términos de JSON, `null`)
+
+### Modelo para Salida en la Documentación
+
+También puedes revisar el modelo de salida en la documentación, **ambos** `name` y `description` están marcados como **requeridos** con un **asterisco rojo**:
+
+
+
+
+
+### Modelo para Entrada y Salida en la Documentación
+
+Y si revisas todos los esquemas disponibles (JSON Schemas) en OpenAPI, verás que hay dos, uno `Item-Input` y uno `Item-Output`.
+
+Para `Item-Input`, `description` **no es requerido**, no tiene un asterisco rojo.
+
+Pero para `Item-Output`, `description` **es requerido**, tiene un asterisco rojo.
+
+
+
+
+
+Con esta funcionalidad de **Pydantic v2**, la documentación de tu API es más **precisa**, y si tienes clientes y SDKs autogenerados, también serán más precisos, con una mejor **experiencia para desarrolladores** y consistencia. 🎉
+
+## No Separar Esquemas
+
+Ahora, hay algunos casos donde podrías querer tener el **mismo esquema para entrada y salida**.
+
+Probablemente el caso principal para esto es si ya tienes algún código cliente/SDKs autogenerado y no quieres actualizar todo el código cliente/SDKs autogenerado aún, probablemente querrás hacerlo en algún momento, pero tal vez no ahora.
+
+En ese caso, puedes desactivar esta funcionalidad en **FastAPI**, con el parámetro `separate_input_output_schemas=False`.
+
+/// info | Información
+
+El soporte para `separate_input_output_schemas` fue agregado en FastAPI `0.102.0`. 🤓
+
+///
+
+{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
+
+### Mismo Esquema para Modelos de Entrada y Salida en la Documentación
+
+Y ahora habrá un único esquema para entrada y salida para el modelo, solo `Item`, y tendrá `description` como **no requerido**:
+
+
+
+
+
+Este es el mismo comportamiento que en Pydantic v1. 🤓
diff --git a/docs/es/docs/how-to/testing-database.md b/docs/es/docs/how-to/testing-database.md
new file mode 100644
index 000000000..b76f4c33a
--- /dev/null
+++ b/docs/es/docs/how-to/testing-database.md
@@ -0,0 +1,7 @@
+# Probando una Base de Datos
+
+Puedes estudiar sobre bases de datos, SQL y SQLModel en la documentación de SQLModel. 🤓
+
+Hay un mini tutorial sobre el uso de SQLModel con FastAPI. ✨
+
+Ese tutorial incluye una sección sobre cómo probar bases de datos SQL. 😎
diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md
index 73d9b679e..c1da5d633 100644
--- a/docs/es/docs/index.md
+++ b/docs/es/docs/index.md
@@ -8,18 +8,21 @@
- FastAPI framework, alto desempeño, fácil de aprender, rápido de programar, listo para producción
+ FastAPI framework, alto rendimiento, fácil de aprender, rápido de programar, listo para producción
---
@@ -29,21 +32,21 @@
**Código Fuente**: https://github.com/fastapi/fastapi
---
-FastAPI es un web framework moderno y rápido (de alto rendimiento) para construir APIs con Python basado en las anotaciones de tipos estándar de Python.
-Sus características principales son:
+FastAPI es un framework web moderno, rápido (de alto rendimiento), para construir APIs con Python basado en las anotaciones de tipos estándar de Python.
-* **Rapidez**: Alto rendimiento, a la par con **NodeJS** y **Go** (gracias a Starlette y Pydantic). [Uno de los frameworks de Python más rápidos](#rendimiento).
+Las características clave son:
-* **Rápido de programar**: Incrementa la velocidad de desarrollo entre 200% y 300%. *
-* **Menos errores**: Reduce los errores humanos (de programador) aproximadamente un 40%. *
-* **Intuitivo**: Gran soporte en los editores con auto completado en todas partes. Gasta menos tiempo debugging.
-* **Fácil**: Está diseñado para ser fácil de usar y aprender. Gastando menos tiempo leyendo documentación.
-* **Corto**: Minimiza la duplicación de código. Múltiples funcionalidades con cada declaración de parámetros. Menos errores.
-* **Robusto**: Crea código listo para producción con documentación automática interactiva.
-* **Basado en estándares**: Basado y totalmente compatible con los estándares abiertos para APIs: OpenAPI (conocido previamente como Swagger) y JSON Schema.
+* **Rápido**: Muy alto rendimiento, a la par con **NodeJS** y **Go** (gracias a Starlette y Pydantic). [Uno de los frameworks Python más rápidos disponibles](#performance).
+* **Rápido de programar**: Aumenta la velocidad para desarrollar funcionalidades en aproximadamente un 200% a 300%. *
+* **Menos bugs**: Reduce en aproximadamente un 40% los errores inducidos por humanos (desarrolladores). *
+* **Intuitivo**: Gran soporte para editores. Autocompletado en todas partes. Menos tiempo depurando.
+* **Fácil**: Diseñado para ser fácil de usar y aprender. Menos tiempo leyendo documentación.
+* **Corto**: Minimiza la duplicación de código. Múltiples funcionalidades desde cada declaración de parámetro. Menos bugs.
+* **Robusto**: Obtén código listo para producción. Con documentación interactiva automática.
+* **Basado en estándares**: Basado (y completamente compatible) con los estándares abiertos para APIs: OpenAPI (anteriormente conocido como Swagger) y JSON Schema.
-* Esta estimación está basada en pruebas con un equipo de desarrollo interno construyendo aplicaciones listas para producción.
+* estimación basada en pruebas con un equipo de desarrollo interno, construyendo aplicaciones de producción.
## Sponsors
@@ -64,41 +67,47 @@ Sus características principales son:
## Opiniones
-"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
+"_[...] Estoy usando **FastAPI** un montón estos días. [...] De hecho, estoy planeando usarlo para todos los servicios de **ML de mi equipo en Microsoft**. Algunos de ellos se están integrando en el núcleo del producto **Windows** y algunos productos de **Office**._"
---
-"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_"
+"_Adoptamos el paquete **FastAPI** para crear un servidor **REST** que pueda ser consultado para obtener **predicciones**. [para Ludwig]_"
-
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber(ref)
+
Piero Molino, Yaroslav Dudin, y Sai Sumanth Miryala - Uber(ref)
---
-"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_"
+"_**Netflix** se complace en anunciar el lanzamiento de código abierto de nuestro framework de orquestación de **gestión de crisis**: **Dispatch**! [construido con **FastAPI**]_"
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix(ref)
---
-"_I’m over the moon excited about **FastAPI**. It’s so fun!_"
+"_Estoy súper emocionado con **FastAPI**. ¡Es tan divertido!_"
-
---
-"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._"
+"_Honestamente, lo que has construido parece súper sólido y pulido. En muchos aspectos, es lo que quería que **Hug** fuera; es realmente inspirador ver a alguien construir eso._"
-
---
-"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_"
+"_Si estás buscando aprender un **framework moderno** para construir APIs REST, échale un vistazo a **FastAPI** [...] Es rápido, fácil de usar y fácil de aprender [...]_"
+
+"_Nos hemos cambiado a **FastAPI** para nuestras **APIs** [...] Creo que te gustará [...]_"
+
+
+
+---
-"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_"
+"_Si alguien está buscando construir una API de Python para producción, altamente recomendaría **FastAPI**. Está **hermosamente diseñado**, es **simple de usar** y **altamente escalable**, se ha convertido en un **componente clave** en nuestra estrategia de desarrollo API primero y está impulsando muchas automatizaciones y servicios como nuestro Ingeniero Virtual TAC._"
-
---
@@ -106,41 +115,33 @@ Sus características principales son:
-Si estás construyendo un app de CLI para ser usada en la terminal en vez de una API web, fíjate en **Typer**.
+Si estás construyendo una aplicación de CLI para ser usada en el terminal en lugar de una API web, revisa **Typer**.
-**Typer** es el hermano menor de FastAPI. La intención es que sea el **FastAPI de las CLIs**. ⌨️ 🚀
+**Typer** es el hermano pequeño de FastAPI. Y está destinado a ser el **FastAPI de las CLIs**. ⌨️ 🚀
## Requisitos
-FastAPI está sobre los hombros de gigantes:
+FastAPI se apoya en hombros de gigantes:
* Starlette para las partes web.
* Pydantic para las partes de datos.
## Instalación
-
+**Nota**: Asegúrate de poner `"fastapi[standard]"` entre comillas para asegurar que funcione en todas las terminales.
+
## Ejemplo
### Créalo
@@ -148,9 +149,10 @@ $ pip install "uvicorn[standard]"
* Crea un archivo `main.py` con:
```Python
-from fastapi import FastAPI
from typing import Union
+from fastapi import FastAPI
+
app = FastAPI()
@@ -169,10 +171,11 @@ def read_item(item_id: int, q: Union[str, None] = None):
Si tu código usa `async` / `await`, usa `async def`:
-```Python hl_lines="7 12"
-from fastapi import FastAPI
+```Python hl_lines="9 14"
from typing import Union
+from fastapi import FastAPI
+
app = FastAPI()
@@ -188,7 +191,7 @@ async def read_item(item_id: int, q: Union[str, None] = None):
**Nota**:
-Si no lo sabes, revisa la sección _"¿Con prisa?"_ sobre `async` y `await` en la documentación.
+Si no lo sabes, revisa la sección _"¿Con prisa?"_ sobre `async` y `await` en la documentación.
@@ -199,11 +202,24 @@ Corre el servidor con:
```console
-$ uvicorn main:app --reload
-
+$ fastapi dev main.py
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-INFO: Started reloader process [28720]
-INFO: Started server process [28722]
+INFO: Started reloader process [2248755] using WatchFiles
+INFO: Started server process [2248757]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
@@ -211,13 +227,13 @@ INFO: Application startup complete.
-Sobre el comando uvicorn main:app --reload...
+Acerca del comando fastapi dev main.py...
+
+El comando `fastapi dev` lee tu archivo `main.py`, detecta la app **FastAPI** en él y arranca un servidor usando Uvicorn.
-El comando `uvicorn main:app` se refiere a:
+Por defecto, `fastapi dev` comenzará con auto-recarga habilitada para el desarrollo local.
-* `main`: el archivo `main.py` (el"modulo" de Python).
-* `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`.
-* `--reload`: hace que el servidor se reinicie después de cambios en el código. Esta opción solo debe ser usada en desarrollo.
+Puedes leer más sobre esto en la documentación del CLI de FastAPI.
@@ -225,7 +241,7 @@ El comando `uvicorn main:app` se refiere a:
Abre tu navegador en http://127.0.0.1:8000/items/5?q=somequery.
-Verás la respuesta de JSON cómo:
+Verás el response JSON como:
```JSON
{"item_id": 5, "q": "somequery"}
@@ -233,37 +249,38 @@ Verás la respuesta de JSON cómo:
Ya creaste una API que:
-* Recibe HTTP requests en los _paths_ `/` y `/items/{item_id}`.
-* Ambos _paths_ toman operaciones `GET` (también conocido como HTTP _methods_).
-* El _path_ `/items/{item_id}` tiene un _path parameter_ `item_id` que debería ser un `int`.
-* El _path_ `/items/{item_id}` tiene un `str` _query parameter_ `q` opcional.
+* Recibe requests HTTP en los _paths_ `/` y `/items/{item_id}`.
+* Ambos _paths_ toman _operaciones_ `GET` (también conocidas como métodos HTTP).
+* El _path_ `/items/{item_id}` tiene un _parámetro de path_ `item_id` que debe ser un `int`.
+* El _path_ `/items/{item_id}` tiene un _parámetro de query_ `q` opcional que es un `str`.
-### Documentación interactiva de APIs
+### Documentación interactiva de la API
Ahora ve a http://127.0.0.1:8000/docs.
-Verás la documentación automática e interactiva de la API (proveída por Swagger UI):
+Verás la documentación interactiva automática de la API (proporcionada por Swagger UI):

-### Documentación alternativa de la API
+### Documentación de API Alternativa
-Ahora, ve a http://127.0.0.1:8000/redoc.
+Y ahora, ve a http://127.0.0.1:8000/redoc.
-Ahora verás la documentación automática alternativa (proveída por ReDoc):
+Verás la documentación alternativa automática (proporcionada por ReDoc):

-## Mejora al ejemplo
+## Actualización del Ejemplo
-Ahora modifica el archivo `main.py` para recibir un body del `PUT` request.
+Ahora modifica el archivo `main.py` para recibir un body desde un request `PUT`.
-Declara el body usando las declaraciones de tipo estándares de Python gracias a Pydantic.
+Declara el body usando tipos estándar de Python, gracias a Pydantic.
+
+```Python hl_lines="4 9-12 25-27"
+from typing import Union
-```Python hl_lines="2 7-10 23-25"
from fastapi import FastAPI
from pydantic import BaseModel
-from typing import Union
app = FastAPI()
@@ -289,9 +306,9 @@ def update_item(item_id: int, item: Item):
return {"item_name": item.name, "item_id": item_id}
```
-El servidor debería recargar automáticamente (porque añadiste `--reload` al comando `uvicorn` que está más arriba).
+El servidor `fastapi dev` debería recargarse automáticamente.
-### Mejora a la documentación interactiva de APIs
+### Actualización de la Documentación Interactiva de la API
Ahora ve a http://127.0.0.1:8000/docs.
@@ -299,29 +316,29 @@ Ahora ve a http://127.0.0.1:8000/redoc.
+Y ahora, ve a http://127.0.0.1:8000/redoc.
-* La documentación alternativa también reflejará el nuevo parámetro de query y el body:
+* La documentación alternativa también reflejará el nuevo parámetro de query y body:

### Resumen
-En resumen, declaras los tipos de parámetros, body, etc. **una vez** como parámetros de la función.
+En resumen, declaras **una vez** los tipos de parámetros, body, etc. como parámetros de función.
-Lo haces con tipos modernos estándar de Python.
+Lo haces con tipos estándar modernos de Python.
-No tienes que aprender una sintaxis nueva, los métodos o clases de una library específica, etc.
+No tienes que aprender una nueva sintaxis, los métodos o clases de un paquete específico, etc.
Solo **Python** estándar.
@@ -331,7 +348,7 @@ Por ejemplo, para un `int`:
item_id: int
```
-o para un modelo más complejo de `Item`:
+o para un modelo `Item` más complejo:
```Python
item: Item
@@ -339,62 +356,62 @@ item: Item
...y con esa única declaración obtienes:
-* Soporte del editor incluyendo:
- * Auto completado.
- * Anotaciones de tipos.
+* Soporte para editores, incluyendo:
+ * Autocompletado.
+ * Chequeo de tipos.
* Validación de datos:
- * Errores automáticos y claros cuándo los datos son inválidos.
- * Validación, incluso para objetos JSON profundamente anidados.
-* Conversión de datos de input: viniendo de la red a datos y tipos de Python. Leyendo desde:
+ * Errores automáticos y claros cuando los datos son inválidos.
+ * Validación incluso para objetos JSON profundamente anidados.
+* Conversión de datos de entrada: de la red a los datos y tipos de Python. Leyendo desde:
* JSON.
- * Path parameters.
- * Query parameters.
+ * Parámetros de path.
+ * Parámetros de query.
* Cookies.
* Headers.
- * Formularios.
+ * Forms.
* Archivos.
-* Conversión de datos de output: convirtiendo de datos y tipos de Python a datos para la red (como JSON):
+* Conversión de datos de salida: convirtiendo de datos y tipos de Python a datos de red (como JSON):
* Convertir tipos de Python (`str`, `int`, `float`, `bool`, `list`, etc).
* Objetos `datetime`.
* Objetos `UUID`.
- * Modelos de bases de datos.
+ * Modelos de base de datos.
* ...y muchos más.
-* Documentación automática e interactiva incluyendo 2 interfaces de usuario alternativas:
+* Documentación interactiva automática de la API, incluyendo 2 interfaces de usuario alternativas:
* Swagger UI.
* ReDoc.
---
-Volviendo al ejemplo de código anterior, **FastAPI** va a:
-
-* Validar que existe un `item_id` en el path para requests usando `GET` y `PUT`.
-* Validar que el `item_id` es del tipo `int` para requests de tipo `GET` y `PUT`.
- * Si no lo es, el cliente verá un mensaje de error útil y claro.
-* Revisar si existe un query parameter opcional llamado `q` (cómo en `http://127.0.0.1:8000/items/foo?q=somequery`) para requests de tipo `GET`.
- * Como el parámetro `q` fue declarado con `= None` es opcional.
- * Sin el `None` sería obligatorio (cómo lo es el body en el caso con `PUT`).
-* Para requests de tipo `PUT` a `/items/{item_id}` leer el body como JSON:
- * Revisar si tiene un atributo requerido `name` que debe ser un `str`.
- * Revisar si tiene un atributo requerido `price` que debe ser un `float`.
- * Revisar si tiene un atributo opcional `is_offer`, que debe ser un `bool`si está presente.
- * Todo esto funcionaría para objetos JSON profundamente anidados.
-* Convertir de y a JSON automáticamente.
-* Documentar todo con OpenAPI que puede ser usado por:
+Volviendo al ejemplo de código anterior, **FastAPI**:
+
+* Validará que haya un `item_id` en el path para requests `GET` y `PUT`.
+* Validará que el `item_id` sea del tipo `int` para requests `GET` y `PUT`.
+ * Si no lo es, el cliente verá un error útil y claro.
+* Comprobará si hay un parámetro de query opcional llamado `q` (como en `http://127.0.0.1:8000/items/foo?q=somequery`) para requests `GET`.
+ * Como el parámetro `q` está declarado con `= None`, es opcional.
+ * Sin el `None` sería requerido (como lo es el body en el caso con `PUT`).
+* Para requests `PUT` a `/items/{item_id}`, leerá el body como JSON:
+ * Comprobará que tiene un atributo requerido `name` que debe ser un `str`.
+ * Comprobará que tiene un atributo requerido `price` que debe ser un `float`.
+ * Comprobará que tiene un atributo opcional `is_offer`, que debe ser un `bool`, si está presente.
+ * Todo esto también funcionaría para objetos JSON profundamente anidados.
+* Convertirá de y a JSON automáticamente.
+* Documentará todo con OpenAPI, que puede ser usado por:
* Sistemas de documentación interactiva.
- * Sistemas de generación automática de código de cliente para muchos lenguajes.
-* Proveer directamente 2 interfaces de documentación web interactivas.
+ * Sistemas de generación automática de código cliente, para muchos lenguajes.
+* Proporcionará 2 interfaces web de documentación interactiva directamente.
---
-Hasta ahora, escasamente vimos lo básico pero ya tienes una idea de cómo funciona.
+Solo tocamos los conceptos básicos, pero ya te haces una idea de cómo funciona todo.
-Intenta cambiando la línea a:
+Intenta cambiar la línea con:
```Python
return {"item_name": item.name, "item_id": item_id}
```
-...de:
+...desde:
```Python
... "item_name": item.name ...
@@ -406,56 +423,74 @@ Intenta cambiando la línea a:
... "item_price": item.price ...
```
-... y mira como el editor va a auto-completar los atributos y sabrá sus tipos:
+...y observa cómo tu editor autocompleta los atributos y conoce sus tipos:
-
+
-Para un ejemplo más completo que incluye más características ve el Tutorial - Guía de Usuario.
+Para un ejemplo más completo incluyendo más funcionalidades, ve al Tutorial - Guía del Usuario.
-**Spoiler alert**: el Tutorial - Guía de Usuario incluye:
+**Alerta de spoilers**: el tutorial - guía del usuario incluye:
-* Declaración de **parámetros** en otros lugares diferentes cómo los: **headers**, **cookies**, **formularios** y **archivos**.
-* Cómo agregar **requisitos de validación** cómo `maximum_length` o `regex`.
-* Un sistema de **Dependency Injection** poderoso y fácil de usar.
-* Seguridad y autenticación incluyendo soporte para **OAuth2** con **JWT tokens** y **HTTP Basic** auth.
-* Técnicas más avanzadas, pero igual de fáciles, para declarar **modelos de JSON profundamente anidados** (gracias a Pydantic).
-* Muchas características extra (gracias a Starlette) como:
+* Declaración de **parámetros** desde otros lugares diferentes como: **headers**, **cookies**, **campos de formulario** y **archivos**.
+* Cómo establecer **restricciones de validación** como `maximum_length` o `regex`.
+* Un sistema de **Inyección de Dependencias** muy poderoso y fácil de usar.
+* Seguridad y autenticación, incluyendo soporte para **OAuth2** con **tokens JWT** y autenticación **HTTP Basic**.
+* Técnicas más avanzadas (pero igualmente fáciles) para declarar **modelos JSON profundamente anidados** (gracias a Pydantic).
+* Integración con **GraphQL** usando Strawberry y otros paquetes.
+* Muchas funcionalidades extra (gracias a Starlette) como:
* **WebSockets**
- * **GraphQL**
- * pruebas extremadamente fáciles con HTTPX y `pytest`
+ * pruebas extremadamente fáciles basadas en HTTPX y `pytest`
* **CORS**
- * **Cookie Sessions**
- * ...y mucho más.
+ * **Sesiones de Cookies**
+ * ...y más.
## Rendimiento
-Benchmarks independientes de TechEmpower muestran que aplicaciones de **FastAPI** corriendo con Uvicorn cómo uno de los frameworks de Python más rápidos, únicamente debajo de Starlette y Uvicorn (usados internamente por FastAPI). (*)
+Benchmarks independientes de TechEmpower muestran aplicaciones **FastAPI** ejecutándose bajo Uvicorn como uno de los frameworks Python más rápidos disponibles, solo por debajo de Starlette y Uvicorn (usados internamente por FastAPI). (*)
+
+Para entender más sobre esto, ve la sección Benchmarks.
-Para entender más al respecto revisa la sección Benchmarks.
+## Dependencias
-## Dependencias Opcionales
+FastAPI depende de Pydantic y Starlette.
+
+### Dependencias `standard`
+
+Cuando instalas FastAPI con `pip install "fastapi[standard]"` viene con el grupo `standard` de dependencias opcionales:
Usadas por Pydantic:
-* email-validator - para validación de emails.
+* email-validator - para validación de correos electrónicos.
+
+Usadas por Starlette:
+
+* httpx - Requerido si deseas usar el `TestClient`.
+* jinja2 - Requerido si deseas usar la configuración de plantilla predeterminada.
+* python-multipart - Requerido si deseas soportar "parsing" de forms, con `request.form()`.
+
+Usadas por FastAPI / Starlette:
+
+* uvicorn - para el servidor que carga y sirve tu aplicación. Esto incluye `uvicorn[standard]`, que incluye algunas dependencias (por ejemplo, `uvloop`) necesarias para servir con alto rendimiento.
+* `fastapi-cli` - para proporcionar el comando `fastapi`.
+
+### Sin Dependencias `standard`
+
+Si no deseas incluir las dependencias opcionales `standard`, puedes instalar con `pip install fastapi` en lugar de `pip install "fastapi[standard]"`.
+
+### Dependencias Opcionales Adicionales
-Usados por Starlette:
+Existen algunas dependencias adicionales que podrías querer instalar.
-* httpx - Requerido si quieres usar el `TestClient`.
-* jinja2 - Requerido si quieres usar la configuración por defecto de templates.
-* python-multipart - Requerido si quieres dar soporte a "parsing" de formularios, con `request.form()`.
-* itsdangerous - Requerido para dar soporte a `SessionMiddleware`.
-* pyyaml - Requerido para dar soporte al `SchemaGenerator` de Starlette (probablemente no lo necesites con FastAPI).
-* graphene - Requerido para dar soporte a `GraphQLApp`.
+Dependencias opcionales adicionales de Pydantic:
-Usado por FastAPI / Starlette:
+* pydantic-settings - para la gestión de configuraciones.
+* pydantic-extra-types - para tipos extra para ser usados con Pydantic.
-* uvicorn - para el servidor que carga y sirve tu aplicación.
-* orjson - Requerido si quieres usar `ORJSONResponse`.
-* ujson - Requerido si quieres usar `UJSONResponse`.
+Dependencias opcionales adicionales de FastAPI:
-Puedes instalarlos con `pip install fastapi[all]`.
+* orjson - Requerido si deseas usar `ORJSONResponse`.
+* ujson - Requerido si deseas usar `UJSONResponse`.
## Licencia
-Este proyecto está licenciado bajo los términos de la licencia del MIT.
+Este proyecto tiene licencia bajo los términos de la licencia MIT.
diff --git a/docs/es/docs/learn/index.md b/docs/es/docs/learn/index.md
index b8d26cf34..cc6c7cc3f 100644
--- a/docs/es/docs/learn/index.md
+++ b/docs/es/docs/learn/index.md
@@ -1,5 +1,5 @@
-# Aprender
+# Aprende
Aquí están las secciones introductorias y los tutoriales para aprender **FastAPI**.
-Podrías considerar esto como un **libro**, un **curso**, la forma **oficial** y recomendada de aprender FastAPI. 😎
+Podrías considerar esto un **libro**, un **curso**, la forma **oficial** y recomendada de aprender FastAPI. 😎
diff --git a/docs/es/docs/project-generation.md b/docs/es/docs/project-generation.md
index 6aa570397..559995151 100644
--- a/docs/es/docs/project-generation.md
+++ b/docs/es/docs/project-generation.md
@@ -1,28 +1,28 @@
-# Plantilla de FastAPI Full Stack
+# Plantilla Full Stack FastAPI
-Las plantillas, aunque típicamente vienen con una configuración específica, están diseñadas para ser flexibles y personalizables. Esto te permite modificarlas y adaptarlas a los requisitos de tu proyecto, lo que las convierte en un excelente punto de partida. 🏁
+Las plantillas, aunque normalmente vienen con una configuración específica, están diseñadas para ser flexibles y personalizables. Esto te permite modificarlas y adaptarlas a los requisitos de tu proyecto, haciéndolas un excelente punto de partida. 🏁
-Puedes utilizar esta plantilla para comenzar, ya que incluye gran parte de la configuración inicial, seguridad, base de datos y algunos endpoints de API ya realizados.
+Puedes usar esta plantilla para comenzar, ya que incluye gran parte de la configuración inicial, seguridad, base de datos y algunos endpoints de API ya hechos para ti.
-Repositorio en GitHub: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)
+Repositorio de GitHub: Plantilla Full Stack FastAPI
-## Plantilla de FastAPI Full Stack - Tecnología y Características
+## Plantilla Full Stack FastAPI - Tecnología y Funcionalidades
-- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) para el backend API en Python.
- - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para las interacciones con la base de datos SQL en Python (ORM).
- - 🔍 [Pydantic](https://docs.pydantic.dev), utilizado por FastAPI, para la validación de datos y la gestión de configuraciones.
- - 💾 [PostgreSQL](https://www.postgresql.org) como la base de datos SQL.
+- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) para la API del backend en Python.
+ - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para las interacciones con bases de datos SQL en Python (ORM).
+ - 🔍 [Pydantic](https://docs.pydantic.dev), utilizado por FastAPI, para la validación de datos y gestión de configuraciones.
+ - 💾 [PostgreSQL](https://www.postgresql.org) como base de datos SQL.
- 🚀 [React](https://react.dev) para el frontend.
- - 💃 Usando TypeScript, hooks, [Vite](https://vitejs.dev) y otras partes de un stack de frontend moderno.
+ - 💃 Usando TypeScript, hooks, [Vite](https://vitejs.dev), y otras partes de una stack moderna de frontend.
- 🎨 [Chakra UI](https://chakra-ui.com) para los componentes del frontend.
- - 🤖 Un cliente frontend generado automáticamente.
+ - 🤖 Un cliente de frontend generado automáticamente.
- 🧪 [Playwright](https://playwright.dev) para pruebas End-to-End.
- 🦇 Soporte para modo oscuro.
- 🐋 [Docker Compose](https://www.docker.com) para desarrollo y producción.
- 🔒 Hashing seguro de contraseñas por defecto.
-- 🔑 Autenticación con token JWT.
+- 🔑 Autenticación con tokens JWT.
- 📫 Recuperación de contraseñas basada en email.
-- ✅ Tests con [Pytest](https://pytest.org).
+- ✅ Pruebas con [Pytest](https://pytest.org).
- 📞 [Traefik](https://traefik.io) como proxy inverso / balanceador de carga.
-- 🚢 Instrucciones de despliegue utilizando Docker Compose, incluyendo cómo configurar un proxy frontend Traefik para manejar certificados HTTPS automáticos.
+- 🚢 Instrucciones de despliegue usando Docker Compose, incluyendo cómo configurar un proxy Traefik frontend para manejar certificados HTTPS automáticos.
- 🏭 CI (integración continua) y CD (despliegue continuo) basados en GitHub Actions.
diff --git a/docs/es/docs/python-types.md b/docs/es/docs/python-types.md
index 156907ad1..769204f8f 100644
--- a/docs/es/docs/python-types.md
+++ b/docs/es/docs/python-types.md
@@ -1,20 +1,20 @@
-# Introducción a los Tipos de Python
+# Introducción a Tipos en Python
-**Python 3.6+** tiene soporte para "type hints" opcionales.
+Python tiene soporte para "anotaciones de tipos" opcionales (también llamadas "type hints").
-Estos **type hints** son una nueva sintaxis, desde Python 3.6+, que permite declarar el tipo de una variable.
+Estas **"anotaciones de tipos"** o type hints son una sintaxis especial que permite declarar el tipo de una variable.
-Usando las declaraciones de tipos para tus variables, los editores y otras herramientas pueden proveerte un soporte mejor.
+Al declarar tipos para tus variables, los editores y herramientas te pueden proporcionar un mejor soporte.
-Este es solo un **tutorial corto** sobre los Python type hints. Solo cubre lo mínimo necesario para usarlos con **FastAPI**... realmente es muy poco lo que necesitas.
+Este es solo un **tutorial rápido / recordatorio** sobre las anotaciones de tipos en Python. Cubre solo lo mínimo necesario para usarlas con **FastAPI**... que en realidad es muy poco.
-Todo **FastAPI** está basado en estos type hints, lo que le da muchas ventajas y beneficios.
+**FastAPI** se basa completamente en estas anotaciones de tipos, dándole muchas ventajas y beneficios.
-Pero, así nunca uses **FastAPI** te beneficiarás de aprender un poco sobre los type hints.
+Pero incluso si nunca usas **FastAPI**, te beneficiaría aprender un poco sobre ellas.
/// note | Nota
-Si eres un experto en Python y ya lo sabes todo sobre los type hints, salta al siguiente capítulo.
+Si eres un experto en Python, y ya sabes todo sobre las anotaciones de tipos, salta al siguiente capítulo.
///
@@ -22,11 +22,9 @@ Si eres un experto en Python y ya lo sabes todo sobre los type hints, salta al s
Comencemos con un ejemplo simple:
-```Python
-{!../../docs_src/python_types/tutorial001.py!}
-```
+{* ../../docs_src/python_types/tutorial001.py *}
-Llamar este programa nos muestra el siguiente output:
+Llamar a este programa genera:
```
John Doe
@@ -34,39 +32,37 @@ John Doe
La función hace lo siguiente:
-* Toma un `first_name` y un `last_name`.
-* Convierte la primera letra de cada uno en una letra mayúscula con `title()`.
-* Las concatena con un espacio en la mitad.
+* Toma un `first_name` y `last_name`.
+* Convierte la primera letra de cada uno a mayúsculas con `title()`.
+* Concatena ambos con un espacio en el medio.
-```Python hl_lines="2"
-{!../../docs_src/python_types/tutorial001.py!}
-```
+{* ../../docs_src/python_types/tutorial001.py hl[2] *}
### Edítalo
Es un programa muy simple.
-Ahora, imagina que lo estás escribiendo desde cero.
+Pero ahora imagina que lo escribieras desde cero.
-En algún punto habrías comenzado con la definición de la función, tenías los parámetros listos...
+En algún momento habrías empezado la definición de la función, tenías los parámetros listos...
-Pero, luego tienes que llamar "ese método que convierte la primera letra en una mayúscula".
+Pero luego tienes que llamar "ese método que convierte la primera letra a mayúscula".
-Era `upper`? O era `uppercase`? `first_uppercase`? `capitalize`?
+¿Era `upper`? ¿Era `uppercase`? `first_uppercase`? `capitalize`?
-Luego lo intentas con el viejo amigo de los programadores, el auto-completado del editor.
+Entonces, pruebas con el amigo del viejo programador, el autocompletado del editor.
-Escribes el primer parámetro de la función `first_name`, luego un punto (`.`) y luego presionas `Ctrl+Space` para iniciar el auto-completado.
+Escribes el primer parámetro de la función, `first_name`, luego un punto (`.`) y luego presionas `Ctrl+Espacio` para activar el autocompletado.
-Tristemente, no obtienes nada útil:
+Pero, tristemente, no obtienes nada útil:
-
+
-### Añade tipos
+### Añadir tipos
-Vamos a modificar una única línea de la versión previa.
+Modifiquemos una sola línea de la versión anterior.
-Vamos a cambiar exactamente este fragmento, los parámetros de la función, de:
+Cambiaremos exactamente este fragmento, los parámetros de la función, de:
```Python
first_name, last_name
@@ -80,216 +76,501 @@ a:
Eso es todo.
-Esos son los "type hints":
+Esas son las "anotaciones de tipos":
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial002.py!}
-```
+{* ../../docs_src/python_types/tutorial002.py hl[1] *}
-No es lo mismo a declarar valores por defecto, como sería con:
+Eso no es lo mismo que declarar valores predeterminados como sería con:
```Python
first_name="john", last_name="doe"
```
-Es algo diferente.
+Es una cosa diferente.
-Estamos usando los dos puntos (`:`), no un símbolo de igual (`=`).
+Estamos usando dos puntos (`:`), no igualdades (`=`).
-Añadir los type hints normalmente no cambia lo que sucedería si ellos no estuviesen presentes.
+Y agregar anotaciones de tipos normalmente no cambia lo que sucede de lo que ocurriría sin ellas.
-Pero ahora imagina que nuevamente estás creando la función, pero con los type hints.
+Pero ahora, imagina que nuevamente estás en medio de la creación de esa función, pero con anotaciones de tipos.
-En el mismo punto intentas iniciar el auto-completado con `Ctrl+Space` y ves:
+En el mismo punto, intentas activar el autocompletado con `Ctrl+Espacio` y ves:
-
+
-Con esto puedes moverte hacia abajo viendo las opciones hasta que encuentras una que te suene:
+Con eso, puedes desplazarte, viendo las opciones, hasta que encuentres la que "te suene":
-
+
## Más motivación
-Mira esta función que ya tiene type hints:
+Revisa esta función, ya tiene anotaciones de tipos:
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial003.py!}
-```
+{* ../../docs_src/python_types/tutorial003.py hl[1] *}
-Como el editor conoce el tipo de las variables no solo obtienes auto-completado, si no que también obtienes chequeo de errores:
+Porque el editor conoce los tipos de las variables, no solo obtienes autocompletado, también obtienes chequeo de errores:
-
+
-Ahora que sabes que tienes que arreglarlo convierte `age` a un string con `str(age)`:
+Ahora sabes que debes corregirlo, convertir `age` a un string con `str(age)`:
-```Python hl_lines="2"
-{!../../docs_src/python_types/tutorial004.py!}
-```
+{* ../../docs_src/python_types/tutorial004.py hl[2] *}
-## Declarando tipos
+## Declaración de tipos
-Acabas de ver el lugar principal para declarar los type hints. Como parámetros de las funciones.
+Acabas de ver el lugar principal para declarar anotaciones de tipos. Como parámetros de función.
-Este es también el lugar principal en que los usarías con **FastAPI**.
+Este también es el lugar principal donde los utilizarías con **FastAPI**.
### Tipos simples
-Puedes declarar todos los tipos estándar de Python, no solamente `str`.
+Puedes declarar todos los tipos estándar de Python, no solo `str`.
-Por ejemplo, puedes usar:
+Puedes usar, por ejemplo:
* `int`
* `float`
* `bool`
* `bytes`
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial005.py!}
-```
+{* ../../docs_src/python_types/tutorial005.py hl[1] *}
+
+### Tipos genéricos con parámetros de tipo
+
+Hay algunas estructuras de datos que pueden contener otros valores, como `dict`, `list`, `set` y `tuple`. Y los valores internos también pueden tener su propio tipo.
+
+Estos tipos que tienen tipos internos se denominan tipos "**genéricos**". Y es posible declararlos, incluso con sus tipos internos.
+
+Para declarar esos tipos y los tipos internos, puedes usar el módulo estándar de Python `typing`. Existe específicamente para soportar estas anotaciones de tipos.
+
+#### Versiones más recientes de Python
+
+La sintaxis que utiliza `typing` es **compatible** con todas las versiones, desde Python 3.6 hasta las versiones más recientes, incluyendo Python 3.9, Python 3.10, etc.
+
+A medida que avanza Python, las **versiones más recientes** vienen con soporte mejorado para estas anotaciones de tipos y en muchos casos ni siquiera necesitarás importar y usar el módulo `typing` para declarar las anotaciones de tipos.
+
+Si puedes elegir una versión más reciente de Python para tu proyecto, podrás aprovechar esa simplicidad adicional.
+
+En toda la documentación hay ejemplos compatibles con cada versión de Python (cuando hay una diferencia).
+
+Por ejemplo, "**Python 3.6+**" significa que es compatible con Python 3.6 o superior (incluyendo 3.7, 3.8, 3.9, 3.10, etc). Y "**Python 3.9+**" significa que es compatible con Python 3.9 o superior (incluyendo 3.10, etc).
+
+Si puedes usar las **últimas versiones de Python**, utiliza los ejemplos para la última versión, esos tendrán la **mejor y más simple sintaxis**, por ejemplo, "**Python 3.10+**".
+
+#### Lista
-### Tipos con sub-tipos
+Por ejemplo, vamos a definir una variable para ser una `list` de `str`.
-Existen algunas estructuras de datos que pueden contener otros valores, como `dict`, `list`, `set` y `tuple`. Los valores internos pueden tener su propio tipo también.
+//// tab | Python 3.9+
-Para declarar esos tipos y sub-tipos puedes usar el módulo estándar de Python `typing`.
+Declara la variable, con la misma sintaxis de dos puntos (`:`).
-Él existe específicamente para dar soporte a este tipo de type hints.
+Como tipo, pon `list`.
-#### Listas
+Como la lista es un tipo que contiene algunos tipos internos, los pones entre corchetes:
-Por ejemplo, vamos a definir una variable para que sea una `list` compuesta de `str`.
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial006_py39.py!}
+```
+
+////
+
+//// tab | Python 3.8+
De `typing`, importa `List` (con una `L` mayúscula):
```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial006.py!}
+{!> ../../docs_src/python_types/tutorial006.py!}
```
-Declara la variable con la misma sintaxis de los dos puntos (`:`).
+Declara la variable, con la misma sintaxis de dos puntos (`:`).
-Pon `List` como el tipo.
+Como tipo, pon el `List` que importaste de `typing`.
-Como la lista es un tipo que permite tener un "sub-tipo" pones el sub-tipo en corchetes `[]`:
+Como la lista es un tipo que contiene algunos tipos internos, los pones entre corchetes:
```Python hl_lines="4"
-{!../../docs_src/python_types/tutorial006.py!}
+{!> ../../docs_src/python_types/tutorial006.py!}
```
-Esto significa: la variable `items` es una `list` y cada uno de los ítems en esta lista es un `str`.
+////
+
+/// info | Información
+
+Esos tipos internos en los corchetes se denominan "parámetros de tipo".
+
+En este caso, `str` es el parámetro de tipo pasado a `List` (o `list` en Python 3.9 y superior).
+
+///
+
+Eso significa: "la variable `items` es una `list`, y cada uno de los ítems en esta lista es un `str`".
-Con esta declaración tu editor puede proveerte soporte inclusive mientras está procesando ítems de la lista.
+/// tip | Consejo
-Sin tipos el auto-completado en este tipo de estructura es casi imposible de lograr:
+Si usas Python 3.9 o superior, no tienes que importar `List` de `typing`, puedes usar el mismo tipo `list` regular en su lugar.
-
+///
+
+Al hacer eso, tu editor puede proporcionar soporte incluso mientras procesa elementos de la lista:
+
+
-Observa que la variable `item` es unos de los elementos en la lista `items`.
+Sin tipos, eso es casi imposible de lograr.
-El editor aún sabe que es un `str` y provee soporte para ello.
+Nota que la variable `item` es uno de los elementos en la lista `items`.
-#### Tuples y Sets
+Y aún así, el editor sabe que es un `str` y proporciona soporte para eso.
+
+#### Tuple y Set
Harías lo mismo para declarar `tuple`s y `set`s:
+//// tab | Python 3.9+
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial007_py39.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial007.py!}
+{!> ../../docs_src/python_types/tutorial007.py!}
```
+////
+
Esto significa:
* La variable `items_t` es un `tuple` con 3 ítems, un `int`, otro `int`, y un `str`.
-* La variable `items_s` es un `set` y cada uno de sus ítems es de tipo `bytes`.
+* La variable `items_s` es un `set`, y cada uno de sus ítems es del tipo `bytes`.
-#### Diccionarios (Dicts)
+#### Dict
-Para definir un `dict` le pasas 2 sub-tipos separados por comas.
+Para definir un `dict`, pasas 2 parámetros de tipo, separados por comas.
-El primer sub-tipo es para los keys del `dict`.
+El primer parámetro de tipo es para las claves del `dict`.
-El segundo sub-tipo es para los valores del `dict`:
+El segundo parámetro de tipo es para los valores del `dict`:
+
+//// tab | Python 3.9+
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial008_py39.py!}
+```
+
+////
+
+//// tab | Python 3.8+
```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial008.py!}
+{!> ../../docs_src/python_types/tutorial008.py!}
```
+////
+
Esto significa:
* La variable `prices` es un `dict`:
- * Los keys de este `dict` son de tipo `str` (Digamos que son el nombre de cada ítem).
- * Los valores de este `dict` son de tipo `float` (Digamos que son el precio de cada ítem).
+ * Las claves de este `dict` son del tipo `str` (digamos, el nombre de cada ítem).
+ * Los valores de este `dict` son del tipo `float` (digamos, el precio de cada ítem).
-### Clases como tipos
+#### Union
-También puedes declarar una clase como el tipo de una variable.
+Puedes declarar que una variable puede ser cualquier de **varios tipos**, por ejemplo, un `int` o un `str`.
-Digamos que tienes una clase `Person`con un nombre:
+En Python 3.6 y posterior (incluyendo Python 3.10) puedes usar el tipo `Union` de `typing` y poner dentro de los corchetes los posibles tipos a aceptar.
-```Python hl_lines="1-3"
-{!../../docs_src/python_types/tutorial009.py!}
+En Python 3.10 también hay una **nueva sintaxis** donde puedes poner los posibles tipos separados por una barra vertical (`|`).
+
+//// tab | Python 3.10+
+
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
-Entonces puedes declarar una variable que sea de tipo `Person`:
+////
+
+//// tab | Python 3.8+
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial008b.py!}
+```
+
+////
+
+En ambos casos, esto significa que `item` podría ser un `int` o un `str`.
+
+#### Posiblemente `None`
+
+Puedes declarar que un valor podría tener un tipo, como `str`, pero que también podría ser `None`.
+
+En Python 3.6 y posteriores (incluyendo Python 3.10) puedes declararlo importando y usando `Optional` del módulo `typing`.
-```Python hl_lines="6"
+```Python hl_lines="1 4"
{!../../docs_src/python_types/tutorial009.py!}
```
-Una vez más tendrás todo el soporte del editor:
+Usar `Optional[str]` en lugar de solo `str` te permitirá al editor ayudarte a detectar errores donde podrías estar asumiendo que un valor siempre es un `str`, cuando en realidad también podría ser `None`.
+
+`Optional[Something]` es realmente un atajo para `Union[Something, None]`, son equivalentes.
-
+Esto también significa que en Python 3.10, puedes usar `Something | None`:
-## Modelos de Pydantic
+//// tab | Python 3.10+
-Pydantic es una library de Python para llevar a cabo validación de datos.
+```Python hl_lines="1"
+{!> ../../docs_src/python_types/tutorial009_py310.py!}
+```
-Tú declaras la "forma" de los datos mediante clases con atributos.
+////
-Cada atributo tiene un tipo.
+//// tab | Python 3.8+
-Luego creas un instance de esa clase con algunos valores y Pydantic validará los valores, los convertirá al tipo apropiado (si ese es el caso) y te dará un objeto con todos los datos.
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial009.py!}
+```
+
+////
+
+//// tab | Python 3.8+ alternative
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial009b.py!}
+```
-Y obtienes todo el soporte del editor con el objeto resultante.
+////
-Tomado de la documentación oficial de Pydantic:
+#### Uso de `Union` u `Optional`
+
+Si estás usando una versión de Python inferior a 3.10, aquí tienes un consejo desde mi punto de vista muy **subjetivo**:
+
+* 🚨 Evita usar `Optional[SomeType]`
+* En su lugar ✨ **usa `Union[SomeType, None]`** ✨.
+
+Ambos son equivalentes y debajo son lo mismo, pero recomendaría `Union` en lugar de `Optional` porque la palabra "**opcional**" parecería implicar que el valor es opcional, y en realidad significa "puede ser `None`", incluso si no es opcional y aún es requerido.
+
+Creo que `Union[SomeType, None]` es más explícito sobre lo que significa.
+
+Se trata solo de las palabras y nombres. Pero esas palabras pueden afectar cómo tú y tus compañeros de equipo piensan sobre el código.
+
+Como ejemplo, tomemos esta función:
+
+{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *}
+
+El parámetro `name` está definido como `Optional[str]`, pero **no es opcional**, no puedes llamar a la función sin el parámetro:
```Python
-{!../../docs_src/python_types/tutorial010.py!}
+say_hi() # ¡Oh, no, esto lanza un error! 😱
```
+El parámetro `name` sigue siendo **requerido** (no *opcional*) porque no tiene un valor predeterminado. Aún así, `name` acepta `None` como valor:
+
+```Python
+say_hi(name=None) # Esto funciona, None es válido 🎉
+```
+
+La buena noticia es que, una vez que estés en Python 3.10, no tendrás que preocuparte por eso, ya que podrás simplemente usar `|` para definir uniones de tipos:
+
+{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
+
+Y entonces no tendrás que preocuparte por nombres como `Optional` y `Union`. 😎
+
+#### Tipos genéricos
+
+Estos tipos que toman parámetros de tipo en corchetes se llaman **Tipos Genéricos** o **Genéricos**, por ejemplo:
+
+//// tab | Python 3.10+
+
+Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):
+
+* `list`
+* `tuple`
+* `set`
+* `dict`
+
+Y lo mismo que con Python 3.8, desde el módulo `typing`:
+
+* `Union`
+* `Optional` (lo mismo que con Python 3.8)
+* ...y otros.
+
+En Python 3.10, como alternativa a usar los genéricos `Union` y `Optional`, puedes usar la barra vertical (`|`) para declarar uniones de tipos, eso es mucho mejor y más simple.
+
+////
+
+//// tab | Python 3.9+
+
+Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):
+
+* `list`
+* `tuple`
+* `set`
+* `dict`
+
+Y lo mismo que con Python 3.8, desde el módulo `typing`:
+
+* `Union`
+* `Optional`
+* ...y otros.
+
+////
+
+//// tab | Python 3.8+
+
+* `List`
+* `Tuple`
+* `Set`
+* `Dict`
+* `Union`
+* `Optional`
+* ...y otros.
+
+////
+
+### Clases como tipos
+
+También puedes declarar una clase como el tipo de una variable.
+
+Digamos que tienes una clase `Person`, con un nombre:
+
+{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
+
+Luego puedes declarar una variable para que sea de tipo `Person`:
+
+{* ../../docs_src/python_types/tutorial010.py hl[6] *}
+
+Y luego, nuevamente, obtienes todo el soporte del editor:
+
+
+
+Nota que esto significa "`one_person` es una **instance** de la clase `Person`".
+
+No significa "`one_person` es la **clase** llamada `Person`".
+
+## Modelos Pydantic
+
+Pydantic es un paquete de Python para realizar la validación de datos.
+
+Declaras la "forma" de los datos como clases con atributos.
+
+Y cada atributo tiene un tipo.
+
+Entonces creas un instance de esa clase con algunos valores y validará los valores, los convertirá al tipo adecuado (si es el caso) y te dará un objeto con todos los datos.
+
+Y obtienes todo el soporte del editor con ese objeto resultante.
+
+Un ejemplo de la documentación oficial de Pydantic:
+
+//// tab | Python 3.10+
+
+```Python
+{!> ../../docs_src/python_types/tutorial011_py310.py!}
+```
+
+////
+
+//// tab | Python 3.9+
+
+```Python
+{!> ../../docs_src/python_types/tutorial011_py39.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+{!> ../../docs_src/python_types/tutorial011.py!}
+```
+
+////
+
/// info | Información
-Para aprender más sobre Pydantic mira su documentación.
+Para saber más sobre Pydantic, revisa su documentación.
///
-**FastAPI** está todo basado en Pydantic.
+**FastAPI** está completamente basado en Pydantic.
+
+Verás mucho más de todo esto en práctica en el [Tutorial - Guía del Usuario](tutorial/index.md){.internal-link target=_blank}.
+
+/// tip | Consejo
+
+Pydantic tiene un comportamiento especial cuando utilizas `Optional` o `Union[Something, None]` sin un valor por defecto, puedes leer más sobre ello en la documentación de Pydantic sobre Required Optional fields.
+
+///
+
+## Anotaciones de tipos con metadata
+
+Python también tiene una funcionalidad que permite poner **metadata adicional** en estas anotaciones de tipos usando `Annotated`.
+
+//// tab | Python 3.9+
-Vas a ver mucho más de esto en práctica en el [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
+En Python 3.9, `Annotated` es parte de la librería estándar, así que puedes importarlo desde `typing`.
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial013_py39.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+En versiones por debajo de Python 3.9, importas `Annotated` de `typing_extensions`.
+
+Ya estará instalado con **FastAPI**.
+
+```Python hl_lines="1 4"
+{!> ../../docs_src/python_types/tutorial013.py!}
+```
+
+////
+
+Python en sí no hace nada con este `Annotated`. Y para los editores y otras herramientas, el tipo sigue siendo `str`.
+
+Pero puedes usar este espacio en `Annotated` para proporcionar a **FastAPI** metadata adicional sobre cómo quieres que se comporte tu aplicación.
+
+Lo importante a recordar es que **el primer *parámetro de tipo*** que pasas a `Annotated` es el **tipo real**. El resto es solo metadata para otras herramientas.
+
+Por ahora, solo necesitas saber que `Annotated` existe, y que es Python estándar. 😎
+
+Luego verás lo **poderoso** que puede ser.
+
+/// tip | Consejo
+
+El hecho de que esto sea **Python estándar** significa que seguirás obteniendo la **mejor experiencia de desarrollador posible** en tu editor, con las herramientas que usas para analizar y refactorizar tu código, etc. ✨
+
+Y también que tu código será muy compatible con muchas otras herramientas y paquetes de Python. 🚀
+
+///
-## Type hints en **FastAPI**
+## Anotaciones de tipos en **FastAPI**
-**FastAPI** aprovecha estos type hints para hacer varias cosas.
+**FastAPI** aprovecha estas anotaciones de tipos para hacer varias cosas.
-Con **FastAPI** declaras los parámetros con type hints y obtienes:
+Con **FastAPI** declaras parámetros con anotaciones de tipos y obtienes:
-* **Soporte en el editor**.
-* **Type checks**.
+* **Soporte del editor**.
+* **Chequeo de tipos**.
...y **FastAPI** usa las mismas declaraciones para:
-* **Definir requerimientos**: desde request path parameters, query parameters, headers, bodies, dependencies, etc.
-* **Convertir datos**: desde el request al tipo requerido.
-* **Validar datos**: viniendo de cada request:
+* **Definir requerimientos**: de parámetros de path de la request, parámetros de query, headers, bodies, dependencias, etc.
+* **Convertir datos**: de la request al tipo requerido.
+* **Validar datos**: provenientes de cada request:
* Generando **errores automáticos** devueltos al cliente cuando los datos son inválidos.
* **Documentar** la API usando OpenAPI:
- * que en su caso es usada por las interfaces de usuario de la documentación automática e interactiva.
+ * Que luego es usada por las interfaces de documentación interactiva automática.
-Puede que todo esto suene abstracto. Pero no te preocupes que todo lo verás en acción en el [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
+Todo esto puede sonar abstracto. No te preocupes. Verás todo esto en acción en el [Tutorial - Guía del Usuario](tutorial/index.md){.internal-link target=_blank}.
-Lo importante es que usando los tipos de Python estándar en un único lugar (en vez de añadir más clases, decorator, etc.) **FastAPI** hará mucho del trabajo por ti.
+Lo importante es que al usar tipos estándar de Python, en un solo lugar (en lugar de agregar más clases, decoradores, etc.), **FastAPI** hará gran parte del trabajo por ti.
/// info | Información
-Si ya pasaste por todo el tutorial y volviste a la sección de los tipos, una buena referencia es la "cheat sheet" de `mypy`.
+Si ya revisaste todo el tutorial y volviste para ver más sobre tipos, un buen recurso es la "cheat sheet" de `mypy`.
///
diff --git a/docs/es/docs/tutorial/background-tasks.md b/docs/es/docs/tutorial/background-tasks.md
new file mode 100644
index 000000000..3fe961e41
--- /dev/null
+++ b/docs/es/docs/tutorial/background-tasks.md
@@ -0,0 +1,84 @@
+# Tareas en Segundo Plano
+
+Puedes definir tareas en segundo plano para que se ejecuten *después* de devolver un response.
+
+Esto es útil para operaciones que necesitan ocurrir después de un request, pero para las que el cliente realmente no necesita esperar a que la operación termine antes de recibir el response.
+
+Esto incluye, por ejemplo:
+
+* Notificaciones por email enviadas después de realizar una acción:
+ * Como conectarse a un servidor de email y enviar un email tiende a ser "lento" (varios segundos), puedes devolver el response de inmediato y enviar la notificación por email en segundo plano.
+* Procesamiento de datos:
+ * Por ejemplo, supongamos que recibes un archivo que debe pasar por un proceso lento, puedes devolver un response de "Accepted" (HTTP 202) y procesar el archivo en segundo plano.
+
+## Usando `BackgroundTasks`
+
+Primero, importa `BackgroundTasks` y define un parámetro en tu *path operation function* con una declaración de tipo de `BackgroundTasks`:
+
+{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
+
+**FastAPI** creará el objeto de tipo `BackgroundTasks` por ti y lo pasará como ese parámetro.
+
+## Crear una función de tarea
+
+Crea una función para que se ejecute como la tarea en segundo plano.
+
+Es solo una función estándar que puede recibir parámetros.
+
+Puede ser una función `async def` o una función normal `def`, **FastAPI** sabrá cómo manejarla correctamente.
+
+En este caso, la función de tarea escribirá en un archivo (simulando el envío de un email).
+
+Y como la operación de escritura no usa `async` y `await`, definimos la función con un `def` normal:
+
+{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
+
+## Agregar la tarea en segundo plano
+
+Dentro de tu *path operation function*, pasa tu función de tarea al objeto de *background tasks* con el método `.add_task()`:
+
+{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
+
+`.add_task()` recibe como argumentos:
+
+* Una función de tarea para ejecutar en segundo plano (`write_notification`).
+* Cualquier secuencia de argumentos que deba pasarse a la función de tarea en orden (`email`).
+* Cualquier argumento de palabras clave que deba pasarse a la función de tarea (`message="some notification"`).
+
+## Inyección de Dependencias
+
+Usar `BackgroundTasks` también funciona con el sistema de inyección de dependencias, puedes declarar un parámetro de tipo `BackgroundTasks` en varios niveles: en una *path operation function*, en una dependencia (dependable), en una sub-dependencia, etc.
+
+**FastAPI** sabe qué hacer en cada caso y cómo reutilizar el mismo objeto, de modo que todas las tareas en segundo plano se combinan y ejecutan en segundo plano después:
+
+{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
+
+En este ejemplo, los mensajes se escribirán en el archivo `log.txt` *después* de que se envíe el response.
+
+Si hay un query en el request, se escribirá en el log en una tarea en segundo plano.
+
+Y luego otra tarea en segundo plano generada en la *path operation function* escribirá un mensaje usando el parámetro de path `email`.
+
+## Detalles Técnicos
+
+La clase `BackgroundTasks` proviene directamente de `starlette.background`.
+
+Se importa/incluye directamente en FastAPI para que puedas importarla desde `fastapi` y evitar importar accidentalmente la alternativa `BackgroundTask` (sin la `s` al final) de `starlette.background`.
+
+Al usar solo `BackgroundTasks` (y no `BackgroundTask`), es posible usarla como un parámetro de *path operation function* y dejar que **FastAPI** maneje el resto por ti, tal como cuando usas el objeto `Request` directamente.
+
+Todavía es posible usar `BackgroundTask` solo en FastAPI, pero debes crear el objeto en tu código y devolver una `Response` de Starlette incluyéndolo.
+
+Puedes ver más detalles en la documentación oficial de Starlette sobre Background Tasks.
+
+## Advertencia
+
+Si necesitas realizar una computación intensa en segundo plano y no necesariamente necesitas que se ejecute por el mismo proceso (por ejemplo, no necesitas compartir memoria, variables, etc.), podrías beneficiarte del uso de otras herramientas más grandes como Celery.
+
+Tienden a requerir configuraciones más complejas, un gestor de cola de mensajes/trabajos, como RabbitMQ o Redis, pero te permiten ejecutar tareas en segundo plano en múltiples procesos, y especialmente, en múltiples servidores.
+
+Pero si necesitas acceder a variables y objetos de la misma app de **FastAPI**, o necesitas realizar pequeñas tareas en segundo plano (como enviar una notificación por email), simplemente puedes usar `BackgroundTasks`.
+
+## Resumen
+
+Importa y usa `BackgroundTasks` con parámetros en *path operation functions* y dependencias para agregar tareas en segundo plano.
diff --git a/docs/es/docs/tutorial/bigger-applications.md b/docs/es/docs/tutorial/bigger-applications.md
new file mode 100644
index 000000000..c3d8f0686
--- /dev/null
+++ b/docs/es/docs/tutorial/bigger-applications.md
@@ -0,0 +1,554 @@
+# Aplicaciones más grandes - Múltiples archivos
+
+Si estás construyendo una aplicación o una API web, rara vez podrás poner todo en un solo archivo.
+
+**FastAPI** proporciona una herramienta conveniente para estructurar tu aplicación manteniendo toda la flexibilidad.
+
+/// info | Información
+
+Si vienes de Flask, esto sería el equivalente a los Blueprints de Flask.
+
+///
+
+## Un ejemplo de estructura de archivos
+
+Digamos que tienes una estructura de archivos como esta:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ ├── dependencies.py
+│ └── routers
+│ │ ├── __init__.py
+│ │ ├── items.py
+│ │ └── users.py
+│ └── internal
+│ ├── __init__.py
+│ └── admin.py
+```
+
+/// tip | Consejo
+
+Hay varios archivos `__init__.py`: uno en cada directorio o subdirectorio.
+
+Esto es lo que permite importar código de un archivo a otro.
+
+Por ejemplo, en `app/main.py` podrías tener una línea como:
+
+```
+from app.routers import items
+```
+
+///
+
+* El directorio `app` contiene todo. Y tiene un archivo vacío `app/__init__.py`, por lo que es un "paquete de Python" (una colección de "módulos de Python"): `app`.
+* Contiene un archivo `app/main.py`. Como está dentro de un paquete de Python (un directorio con un archivo `__init__.py`), es un "módulo" de ese paquete: `app.main`.
+* También hay un archivo `app/dependencies.py`, al igual que `app/main.py`, es un "módulo": `app.dependencies`.
+* Hay un subdirectorio `app/routers/` con otro archivo `__init__.py`, por lo que es un "subpaquete de Python": `app.routers`.
+* El archivo `app/routers/items.py` está dentro de un paquete, `app/routers/`, por lo que es un submódulo: `app.routers.items`.
+* Lo mismo con `app/routers/users.py`, es otro submódulo: `app.routers.users`.
+* También hay un subdirectorio `app/internal/` con otro archivo `__init__.py`, por lo que es otro "subpaquete de Python": `app.internal`.
+* Y el archivo `app/internal/admin.py` es otro submódulo: `app.internal.admin`.
+
+
+
+La misma estructura de archivos con comentarios:
+
+```
+.
+├── app # "app" es un paquete de Python
+│ ├── __init__.py # este archivo hace que "app" sea un "paquete de Python"
+│ ├── main.py # módulo "main", por ejemplo import app.main
+│ ├── dependencies.py # módulo "dependencies", por ejemplo import app.dependencies
+│ └── routers # "routers" es un "subpaquete de Python"
+│ │ ├── __init__.py # hace que "routers" sea un "subpaquete de Python"
+│ │ ├── items.py # submódulo "items", por ejemplo import app.routers.items
+│ │ └── users.py # submódulo "users", por ejemplo import app.routers.users
+│ └── internal # "internal" es un "subpaquete de Python"
+│ ├── __init__.py # hace que "internal" sea un "subpaquete de Python"
+│ └── admin.py # submódulo "admin", por ejemplo import app.internal.admin
+```
+
+## `APIRouter`
+
+Digamos que el archivo dedicado solo a manejar usuarios es el submódulo en `/app/routers/users.py`.
+
+Quieres tener las *path operations* relacionadas con tus usuarios separadas del resto del código, para mantenerlo organizado.
+
+Pero todavía es parte de la misma aplicación/web API de **FastAPI** (es parte del mismo "paquete de Python").
+
+Puedes crear las *path operations* para ese módulo usando `APIRouter`.
+
+### Importar `APIRouter`
+
+Lo importas y creas una "instance" de la misma manera que lo harías con la clase `FastAPI`:
+
+```Python hl_lines="1 3" title="app/routers/users.py"
+{!../../docs_src/bigger_applications/app/routers/users.py!}
+```
+
+### *Path operations* con `APIRouter`
+
+Y luego lo usas para declarar tus *path operations*.
+
+Úsalo de la misma manera que usarías la clase `FastAPI`:
+
+```Python hl_lines="6 11 16" title="app/routers/users.py"
+{!../../docs_src/bigger_applications/app/routers/users.py!}
+```
+
+Puedes pensar en `APIRouter` como una clase "mini `FastAPI`".
+
+Se soportan todas las mismas opciones.
+
+Todos los mismos `parameters`, `responses`, `dependencies`, `tags`, etc.
+
+/// tip | Consejo
+
+En este ejemplo, la variable se llama `router`, pero puedes nombrarla como quieras.
+
+///
+
+Vamos a incluir este `APIRouter` en la aplicación principal de `FastAPI`, pero primero, revisemos las dependencias y otro `APIRouter`.
+
+## Dependencias
+
+Vemos que vamos a necesitar algunas dependencias usadas en varios lugares de la aplicación.
+
+Así que las ponemos en su propio módulo `dependencies` (`app/dependencies.py`).
+
+Ahora utilizaremos una dependencia simple para leer un encabezado `X-Token` personalizado:
+
+//// tab | Python 3.9+
+
+```Python hl_lines="3 6-8" title="app/dependencies.py"
+{!> ../../docs_src/bigger_applications/app_an_py39/dependencies.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python hl_lines="1 5-7" title="app/dependencies.py"
+{!> ../../docs_src/bigger_applications/app_an/dependencies.py!}
+```
+
+////
+
+//// tab | Python 3.8+ non-Annotated
+
+/// tip | Consejo
+
+Preferiblemente usa la versión `Annotated` si es posible.
+
+///
+
+```Python hl_lines="1 4-6" title="app/dependencies.py"
+{!> ../../docs_src/bigger_applications/app/dependencies.py!}
+```
+
+////
+
+/// tip | Consejo
+
+Estamos usando un encabezado inventado para simplificar este ejemplo.
+
+Pero en casos reales obtendrás mejores resultados usando las [utilidades de Seguridad](security/index.md){.internal-link target=_blank} integradas.
+
+///
+
+## Otro módulo con `APIRouter`
+
+Digamos que también tienes los endpoints dedicados a manejar "items" de tu aplicación en el módulo `app/routers/items.py`.
+
+Tienes *path operations* para:
+
+* `/items/`
+* `/items/{item_id}`
+
+Es toda la misma estructura que con `app/routers/users.py`.
+
+Pero queremos ser más inteligentes y simplificar un poco el código.
+
+Sabemos que todas las *path operations* en este módulo tienen el mismo:
+
+* Prefijo de path: `/items`.
+* `tags`: (solo una etiqueta: `items`).
+* `responses` extra.
+* `dependencies`: todas necesitan esa dependencia `X-Token` que creamos.
+
+Entonces, en lugar de agregar todo eso a cada *path operation*, podemos agregarlo al `APIRouter`.
+
+```Python hl_lines="5-10 16 21" title="app/routers/items.py"
+{!../../docs_src/bigger_applications/app/routers/items.py!}
+```
+
+Como el path de cada *path operation* tiene que empezar con `/`, como en:
+
+```Python hl_lines="1"
+@router.get("/{item_id}")
+async def read_item(item_id: str):
+ ...
+```
+
+...el prefijo no debe incluir un `/` final.
+
+Así que, el prefijo en este caso es `/items`.
+
+También podemos agregar una lista de `tags` y `responses` extra que se aplicarán a todas las *path operations* incluidas en este router.
+
+Y podemos agregar una lista de `dependencies` que se añadirá a todas las *path operations* en el router y se ejecutarán/solucionarán por cada request que les haga.
+
+/// tip | Consejo
+
+Nota que, al igual que [dependencias en decoradores de *path operations*](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, ningún valor será pasado a tu *path operation function*.
+
+///
+
+El resultado final es que los paths de item son ahora:
+
+* `/items/`
+* `/items/{item_id}`
+
+...como pretendíamos.
+
+* Serán marcados con una lista de tags que contiene un solo string `"items"`.
+ * Estos "tags" son especialmente útiles para los sistemas de documentación interactiva automática (usando OpenAPI).
+* Todos incluirán las `responses` predefinidas.
+* Todas estas *path operations* tendrán la lista de `dependencies` evaluadas/ejecutadas antes de ellas.
+ * Si también declaras dependencias en una *path operation* específica, **también se ejecutarán**.
+ * Las dependencias del router se ejecutan primero, luego las [dependencias en el decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, y luego las dependencias de parámetros normales.
+ * También puedes agregar [dependencias de `Security` con `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
+
+/// tip | Consejo
+
+Tener `dependencies` en el `APIRouter` puede ser usado, por ejemplo, para requerir autenticación para un grupo completo de *path operations*. Incluso si las dependencias no son añadidas individualmente a cada una de ellas.
+
+///
+
+/// check | Revisa
+
+Los parámetros `prefix`, `tags`, `responses`, y `dependencies` son (como en muchos otros casos) solo una funcionalidad de **FastAPI** para ayudarte a evitar la duplicación de código.
+
+///
+
+### Importar las dependencias
+
+Este código vive en el módulo `app.routers.items`, el archivo `app/routers/items.py`.
+
+Y necesitamos obtener la función de dependencia del módulo `app.dependencies`, el archivo `app/dependencies.py`.
+
+Así que usamos un import relativo con `..` para las dependencias:
+
+```Python hl_lines="3" title="app/routers/items.py"
+{!../../docs_src/bigger_applications/app/routers/items.py!}
+```
+
+#### Cómo funcionan los imports relativos
+
+/// tip | Consejo
+
+Si sabes perfectamente cómo funcionan los imports, continúa a la siguiente sección.
+
+///
+
+Un solo punto `.`, como en:
+
+```Python
+from .dependencies import get_token_header
+```
+
+significaría:
+
+* Partiendo en el mismo paquete en el que este módulo (el archivo `app/routers/items.py`) habita (el directorio `app/routers/`)...
+* busca el módulo `dependencies` (un archivo imaginario en `app/routers/dependencies.py`)...
+* y de él, importa la función `get_token_header`.
+
+Pero ese archivo no existe, nuestras dependencias están en un archivo en `app/dependencies.py`.
+
+Recuerda cómo se ve nuestra estructura de aplicación/archivo:
+
+
+
+---
+
+Los dos puntos `..`, como en:
+
+```Python
+from ..dependencies import get_token_header
+```
+
+significan:
+
+* Partiendo en el mismo paquete en el que este módulo (el archivo `app/routers/items.py`) habita (el directorio `app/routers/`)...
+* ve al paquete padre (el directorio `app/`)...
+* y allí, busca el módulo `dependencies` (el archivo en `app/dependencies.py`)...
+* y de él, importa la función `get_token_header`.
+
+¡Eso funciona correctamente! 🎉
+
+---
+
+De la misma manera, si hubiéramos usado tres puntos `...`, como en:
+
+```Python
+from ...dependencies import get_token_header
+```
+
+eso significaría:
+
+* Partiendo en el mismo paquete en el que este módulo (el archivo `app/routers/items.py`) habita (el directorio `app/routers/`)...
+* ve al paquete padre (el directorio `app/`)...
+* luego ve al paquete padre de ese paquete (no hay paquete padre, `app` es el nivel superior 😱)...
+* y allí, busca el módulo `dependencies` (el archivo en `app/dependencies.py`)...
+* y de él, importa la función `get_token_header`.
+
+Eso se referiría a algún paquete arriba de `app/`, con su propio archivo `__init__.py`, etc. Pero no tenemos eso. Así que, eso lanzaría un error en nuestro ejemplo. 🚨
+
+Pero ahora sabes cómo funciona, para que puedas usar imports relativos en tus propias aplicaciones sin importar cuán complejas sean. 🤓
+
+### Agregar algunos `tags`, `responses`, y `dependencies` personalizados
+
+No estamos agregando el prefijo `/items` ni los `tags=["items"]` a cada *path operation* porque los hemos añadido al `APIRouter`.
+
+Pero aún podemos agregar _más_ `tags` que se aplicarán a una *path operation* específica, y también algunas `responses` extra específicas para esa *path operation*:
+
+```Python hl_lines="30-31" title="app/routers/items.py"
+{!../../docs_src/bigger_applications/app/routers/items.py!}
+```
+
+/// tip | Consejo
+
+Esta última *path operation* tendrá la combinación de tags: `["items", "custom"]`.
+
+Y también tendrá ambas responses en la documentación, una para `404` y otra para `403`.
+
+///
+
+## El `FastAPI` principal
+
+Ahora, veamos el módulo en `app/main.py`.
+
+Aquí es donde importas y usas la clase `FastAPI`.
+
+Este será el archivo principal en tu aplicación que conecta todo.
+
+### Importar `FastAPI`
+
+Importas y creas una clase `FastAPI` como de costumbre.
+
+Y podemos incluso declarar [dependencias globales](dependencies/global-dependencies.md){.internal-link target=_blank} que se combinarán con las dependencias para cada `APIRouter`:
+
+```Python hl_lines="1 3 7" title="app/main.py"
+{!../../docs_src/bigger_applications/app/main.py!}
+```
+
+### Importar el `APIRouter`
+
+Ahora importamos los otros submódulos que tienen `APIRouter`s:
+
+```Python hl_lines="4-5" title="app/main.py"
+{!../../docs_src/bigger_applications/app/main.py!}
+```
+
+Como los archivos `app/routers/users.py` y `app/routers/items.py` son submódulos que son parte del mismo paquete de Python `app`, podemos usar un solo punto `.` para importarlos usando "imports relativos".
+
+### Cómo funciona la importación
+
+La sección:
+
+```Python
+from .routers import items, users
+```
+
+significa:
+
+* Partiendo en el mismo paquete en el que este módulo (el archivo `app/main.py`) habita (el directorio `app/`)...
+* busca el subpaquete `routers` (el directorio en `app/routers/`)...
+* y de él, importa el submódulo `items` (el archivo en `app/routers/items.py`) y `users` (el archivo en `app/routers/users.py`)...
+
+El módulo `items` tendrá una variable `router` (`items.router`). Este es el mismo que creamos en el archivo `app/routers/items.py`, es un objeto `APIRouter`.
+
+Y luego hacemos lo mismo para el módulo `users`.
+
+También podríamos importarlos así:
+
+```Python
+from app.routers import items, users
+```
+
+/// info | Información
+
+La primera versión es un "import relativo":
+
+```Python
+from .routers import items, users
+```
+
+La segunda versión es un "import absoluto":
+
+```Python
+from app.routers import items, users
+```
+
+Para aprender más sobre Paquetes y Módulos de Python, lee la documentación oficial de Python sobre Módulos.
+
+///
+
+### Evitar colisiones de nombres
+
+Estamos importando el submódulo `items` directamente, en lugar de importar solo su variable `router`.
+
+Esto se debe a que también tenemos otra variable llamada `router` en el submódulo `users`.
+
+Si hubiéramos importado uno después del otro, como:
+
+```Python
+from .routers.items import router
+from .routers.users import router
+```
+
+el `router` de `users` sobrescribiría el de `items` y no podríamos usarlos al mismo tiempo.
+
+Así que, para poder usar ambos en el mismo archivo, importamos los submódulos directamente:
+
+```Python hl_lines="5" title="app/main.py"
+{!../../docs_src/bigger_applications/app/main.py!}
+```
+
+### Incluir los `APIRouter`s para `users` y `items`
+
+Ahora, incluyamos los `router`s de los submódulos `users` y `items`:
+
+```Python hl_lines="10-11" title="app/main.py"
+{!../../docs_src/bigger_applications/app/main.py!}
+```
+
+/// info | Información
+
+`users.router` contiene el `APIRouter` dentro del archivo `app/routers/users.py`.
+
+Y `items.router` contiene el `APIRouter` dentro del archivo `app/routers/items.py`.
+
+///
+
+Con `app.include_router()` podemos agregar cada `APIRouter` a la aplicación principal de `FastAPI`.
+
+Incluirá todas las rutas de ese router como parte de ella.
+
+/// note | Detalles Técnicos
+
+En realidad creará internamente una *path operation* para cada *path operation* que fue declarada en el `APIRouter`.
+
+Así, detrás de escena, funcionará como si todo fuera la misma única aplicación.
+
+///
+
+/// check | Revisa
+
+No tienes que preocuparte por el rendimiento al incluir routers.
+
+Esto tomará microsegundos y solo sucederá al inicio.
+
+Así que no afectará el rendimiento. ⚡
+
+///
+
+### Incluir un `APIRouter` con un `prefix`, `tags`, `responses`, y `dependencies` personalizados
+
+Ahora, imaginemos que tu organización te dio el archivo `app/internal/admin.py`.
+
+Contiene un `APIRouter` con algunas *path operations* de administración que tu organización comparte entre varios proyectos.
+
+Para este ejemplo será súper simple. Pero digamos que porque está compartido con otros proyectos en la organización, no podemos modificarlo y agregar un `prefix`, `dependencies`, `tags`, etc. directamente al `APIRouter`:
+
+```Python hl_lines="3" title="app/internal/admin.py"
+{!../../docs_src/bigger_applications/app/internal/admin.py!}
+```
+
+Pero aún queremos configurar un `prefix` personalizado al incluir el `APIRouter` para que todas sus *path operations* comiencen con `/admin`, queremos asegurarlo con las `dependencies` que ya tenemos para este proyecto, y queremos incluir `tags` y `responses`.
+
+Podemos declarar todo eso sin tener que modificar el `APIRouter` original pasando esos parámetros a `app.include_router()`:
+
+```Python hl_lines="14-17" title="app/main.py"
+{!../../docs_src/bigger_applications/app/main.py!}
+```
+
+De esa manera, el `APIRouter` original permanecerá sin modificar, por lo que aún podemos compartir ese mismo archivo `app/internal/admin.py` con otros proyectos en la organización.
+
+El resultado es que, en nuestra aplicación, cada una de las *path operations* del módulo `admin` tendrá:
+
+* El prefix `/admin`.
+* El tag `admin`.
+* La dependencia `get_token_header`.
+* La response `418`. 🍵
+
+Pero eso solo afectará a ese `APIRouter` en nuestra aplicación, no en ningún otro código que lo utilice.
+
+Así, por ejemplo, otros proyectos podrían usar el mismo `APIRouter` con un método de autenticación diferente.
+
+### Incluir una *path operation*
+
+También podemos agregar *path operations* directamente a la aplicación de `FastAPI`.
+
+Aquí lo hacemos... solo para mostrar que podemos 🤷:
+
+```Python hl_lines="21-23" title="app/main.py"
+{!../../docs_src/bigger_applications/app/main.py!}
+```
+
+y funcionará correctamente, junto con todas las otras *path operations* añadidas con `app.include_router()`.
+
+/// info | Detalles Muy Técnicos
+
+**Nota**: este es un detalle muy técnico que probablemente puedes **simplemente omitir**.
+
+---
+
+Los `APIRouter`s no están "montados", no están aislados del resto de la aplicación.
+
+Esto se debe a que queremos incluir sus *path operations* en el esquema de OpenAPI y las interfaces de usuario.
+
+Como no podemos simplemente aislarlos y "montarlos" independientemente del resto, se "clonan" las *path operations* (se vuelven a crear), no se incluyen directamente.
+
+///
+
+## Revisa la documentación automática de la API
+
+Ahora, ejecuta tu aplicación:
+
+
+
+```console
+$ fastapi dev app/main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Y abre la documentación en http://127.0.0.1:8000/docs.
+
+Verás la documentación automática de la API, incluyendo los paths de todos los submódulos, usando los paths correctos (y prefijos) y las tags correctas:
+
+
+
+## Incluir el mismo router múltiples veces con diferentes `prefix`
+
+También puedes usar `.include_router()` múltiples veces con el *mismo* router usando diferentes prefijos.
+
+Esto podría ser útil, por ejemplo, para exponer la misma API bajo diferentes prefijos, por ejemplo, `/api/v1` y `/api/latest`.
+
+Este es un uso avanzado que quizás no necesites realmente, pero está allí en caso de que lo necesites.
+
+## Incluir un `APIRouter` en otro
+
+De la misma manera que puedes incluir un `APIRouter` en una aplicación `FastAPI`, puedes incluir un `APIRouter` en otro `APIRouter` usando:
+
+```Python
+router.include_router(other_router)
+```
+
+Asegúrate de hacerlo antes de incluir `router` en la aplicación de `FastAPI`, para que las *path operations* de `other_router` también se incluyan.
diff --git a/docs/es/docs/tutorial/body-fields.md b/docs/es/docs/tutorial/body-fields.md
new file mode 100644
index 000000000..d07d214ec
--- /dev/null
+++ b/docs/es/docs/tutorial/body-fields.md
@@ -0,0 +1,60 @@
+# Body - Campos
+
+De la misma manera que puedes declarar validaciones adicionales y metadatos en los parámetros de las *path operation function* con `Query`, `Path` y `Body`, puedes declarar validaciones y metadatos dentro de los modelos de Pydantic usando `Field` de Pydantic.
+
+## Importar `Field`
+
+Primero, tienes que importarlo:
+
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
+
+/// warning | Advertencia
+
+Fíjate que `Field` se importa directamente desde `pydantic`, no desde `fastapi` como el resto (`Query`, `Path`, `Body`, etc).
+
+///
+
+## Declarar atributos del modelo
+
+Después puedes utilizar `Field` con los atributos del modelo:
+
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
+
+`Field` funciona de la misma manera que `Query`, `Path` y `Body`, tiene todos los mismos parámetros, etc.
+
+/// note | Detalles técnicos
+
+En realidad, `Query`, `Path` y otros que verás a continuación crean objetos de subclases de una clase común `Param`, que es a su vez una subclase de la clase `FieldInfo` de Pydantic.
+
+Y `Field` de Pydantic también regresa una instance de `FieldInfo`.
+
+`Body` también devuelve objetos de una subclase de `FieldInfo` directamente. Y hay otros que verás más adelante que son subclases de la clase `Body`.
+
+Recuerda que cuando importas `Query`, `Path`, y otros desde `fastapi`, en realidad son funciones que devuelven clases especiales.
+
+///
+
+/// tip | Consejo
+
+Observa cómo cada atributo del modelo con un tipo, un valor por defecto y `Field` tiene la misma estructura que un parámetro de una *path operation function*, con `Field` en lugar de `Path`, `Query` y `Body`.
+
+///
+
+## Agregar información extra
+
+Puedes declarar información extra en `Field`, `Query`, `Body`, etc. Y será incluida en el JSON Schema generado.
+
+Aprenderás más sobre cómo agregar información extra más adelante en la documentación, cuando aprendamos a declarar ejemplos.
+
+/// warning | Advertencia
+
+Las claves extra pasadas a `Field` también estarán presentes en el esquema de OpenAPI resultante para tu aplicación.
+Como estas claves no necesariamente tienen que ser parte de la especificación de OpenAPI, algunas herramientas de OpenAPI, por ejemplo [el validador de OpenAPI](https://validator.swagger.io/), podrían no funcionar con tu esquema generado.
+
+///
+
+## Resumen
+
+Puedes utilizar `Field` de Pydantic para declarar validaciones adicionales y metadatos para los atributos del modelo.
+
+También puedes usar los argumentos de palabra clave extra para pasar metadatos adicionales del JSON Schema.
diff --git a/docs/es/docs/tutorial/body-multiple-params.md b/docs/es/docs/tutorial/body-multiple-params.md
new file mode 100644
index 000000000..df6560b62
--- /dev/null
+++ b/docs/es/docs/tutorial/body-multiple-params.md
@@ -0,0 +1,173 @@
+# Cuerpo - Múltiples Parámetros
+
+Ahora que hemos visto cómo usar `Path` y `Query`, veamos usos más avanzados de las declaraciones del request body.
+
+## Mezclar `Path`, `Query` y parámetros del cuerpo
+
+Primero, por supuesto, puedes mezclar las declaraciones de parámetros de `Path`, `Query` y del request body libremente y **FastAPI** sabrá qué hacer.
+
+Y también puedes declarar parámetros del cuerpo como opcionales, estableciendo el valor predeterminado a `None`:
+
+{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
+
+## Múltiples parámetros del cuerpo
+
+/// note | Nota
+
+Ten en cuenta que, en este caso, el `item` que se tomaría del cuerpo es opcional. Ya que tiene un valor por defecto de `None`.
+
+///
+
+## Múltiples parámetros del cuerpo
+
+En el ejemplo anterior, las *path operations* esperarían un cuerpo JSON con los atributos de un `Item`, como:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+Pero también puedes declarar múltiples parámetros del cuerpo, por ejemplo `item` y `user`:
+
+{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
+
+En este caso, **FastAPI** notará que hay más de un parámetro del cuerpo en la función (hay dos parámetros que son modelos de Pydantic).
+
+Entonces, usará los nombres de los parámetros como claves (nombres de campo) en el cuerpo, y esperará un cuerpo como:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ }
+}
+```
+
+/// note | Nota
+
+Ten en cuenta que aunque el `item` se declaró de la misma manera que antes, ahora se espera que esté dentro del cuerpo con una clave `item`.
+
+///
+
+**FastAPI** hará la conversión automática del request, de modo que el parámetro `item` reciba su contenido específico y lo mismo para `user`.
+
+Realizará la validación de los datos compuestos, y los documentará así para el esquema de OpenAPI y la documentación automática.
+
+## Valores singulares en el cuerpo
+
+De la misma manera que hay un `Query` y `Path` para definir datos extra para parámetros de query y path, **FastAPI** proporciona un equivalente `Body`.
+
+Por ejemplo, ampliando el modelo anterior, podrías decidir que deseas tener otra clave `importance` en el mismo cuerpo, además de `item` y `user`.
+
+Si lo declaras tal cual, debido a que es un valor singular, **FastAPI** asumirá que es un parámetro de query.
+
+Pero puedes instruir a **FastAPI** para que lo trate como otra clave del cuerpo usando `Body`:
+
+{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
+
+En este caso, **FastAPI** esperará un cuerpo como:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ },
+ "importance": 5
+}
+```
+
+Nuevamente, convertirá los tipos de datos, validará, documentará, etc.
+
+## Múltiples parámetros de cuerpo y query
+
+Por supuesto, también puedes declarar parámetros adicionales de query siempre que lo necesites, además de cualquier parámetro del cuerpo.
+
+Como, por defecto, los valores singulares se interpretan como parámetros de query, no tienes que añadir explícitamente un `Query`, solo puedes hacer:
+
+```Python
+q: Union[str, None] = None
+```
+
+O en Python 3.10 y superior:
+
+```Python
+q: str | None = None
+```
+
+Por ejemplo:
+
+{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
+
+/// info | Información
+
+`Body` también tiene todos los mismos parámetros de validación y metadatos extras que `Query`, `Path` y otros que verás luego.
+
+///
+
+## Embeber un solo parámetro de cuerpo
+
+Supongamos que solo tienes un único parámetro de cuerpo `item` de un modelo Pydantic `Item`.
+
+Por defecto, **FastAPI** esperará su cuerpo directamente.
+
+Pero si deseas que espere un JSON con una clave `item` y dentro de ella los contenidos del modelo, como lo hace cuando declaras parámetros de cuerpo extra, puedes usar el parámetro especial `Body` `embed`:
+
+```Python
+item: Item = Body(embed=True)
+```
+
+como en:
+
+{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
+
+En este caso, **FastAPI** esperará un cuerpo como:
+
+```JSON hl_lines="2"
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ }
+}
+```
+
+en lugar de:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+## Resumen
+
+Puedes añadir múltiples parámetros de cuerpo a tu *path operation function*, aunque un request solo puede tener un único cuerpo.
+
+Pero **FastAPI** lo manejará, te dará los datos correctos en tu función, y validará y documentará el esquema correcto en la *path operation*.
+
+También puedes declarar valores singulares para ser recibidos como parte del cuerpo.
+
+Y puedes instruir a **FastAPI** para embeber el cuerpo en una clave incluso cuando solo hay un único parámetro declarado.
diff --git a/docs/es/docs/tutorial/body-nested-models.md b/docs/es/docs/tutorial/body-nested-models.md
new file mode 100644
index 000000000..5b4cfc14c
--- /dev/null
+++ b/docs/es/docs/tutorial/body-nested-models.md
@@ -0,0 +1,247 @@
+# Cuerpo - Modelos Anidados
+
+Con **FastAPI**, puedes definir, validar, documentar y usar modelos anidados de manera arbitraria (gracias a Pydantic).
+
+## Campos de lista
+
+Puedes definir un atributo como un subtipo. Por ejemplo, una `list` en Python:
+
+{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
+
+Esto hará que `tags` sea una lista, aunque no declare el tipo de los elementos de la lista.
+
+## Campos de lista con parámetro de tipo
+
+Pero Python tiene una forma específica de declarar listas con tipos internos, o "parámetros de tipo":
+
+### Importar `List` de typing
+
+En Python 3.9 y superior, puedes usar el `list` estándar para declarar estas anotaciones de tipo como veremos a continuación. 💡
+
+Pero en versiones de Python anteriores a 3.9 (desde 3.6 en adelante), primero necesitas importar `List` del módulo `typing` estándar de Python:
+
+{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
+
+### Declarar una `list` con un parámetro de tipo
+
+Para declarar tipos que tienen parámetros de tipo (tipos internos), como `list`, `dict`, `tuple`:
+
+* Si estás en una versión de Python inferior a 3.9, importa su versión equivalente del módulo `typing`
+* Pasa el/los tipo(s) interno(s) como "parámetros de tipo" usando corchetes: `[` y `]`
+
+En Python 3.9 sería:
+
+```Python
+my_list: list[str]
+```
+
+En versiones de Python anteriores a 3.9, sería:
+
+```Python
+from typing import List
+
+my_list: List[str]
+```
+
+Eso es toda la sintaxis estándar de Python para declaraciones de tipo.
+
+Usa esa misma sintaxis estándar para atributos de modelos con tipos internos.
+
+Así, en nuestro ejemplo, podemos hacer que `tags` sea específicamente una "lista de strings":
+
+{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
+
+## Tipos de conjunto
+
+Pero luego pensamos en ello, y nos damos cuenta de que los tags no deberían repetirse, probablemente serían strings únicos.
+
+Y Python tiene un tipo de datos especial para conjuntos de elementos únicos, el `set`.
+
+Entonces podemos declarar `tags` como un conjunto de strings:
+
+{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
+
+Con esto, incluso si recibes un request con datos duplicados, se convertirá en un conjunto de elementos únicos.
+
+Y siempre que emitas esos datos, incluso si la fuente tenía duplicados, se emitirá como un conjunto de elementos únicos.
+
+Y también se anotará/documentará en consecuencia.
+
+## Modelos Anidados
+
+Cada atributo de un modelo Pydantic tiene un tipo.
+
+Pero ese tipo puede ser en sí mismo otro modelo Pydantic.
+
+Así que, puedes declarar "objetos" JSON anidados profundamente con nombres de atributos específicos, tipos y validaciones.
+
+Todo eso, de manera arbitraria.
+
+### Definir un submodelo
+
+Por ejemplo, podemos definir un modelo `Image`:
+
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
+
+### Usar el submodelo como tipo
+
+Y luego podemos usarlo como el tipo de un atributo:
+
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
+
+Esto significaría que **FastAPI** esperaría un cuerpo similar a:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": ["rock", "metal", "bar"],
+ "image": {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ }
+}
+```
+
+Nuevamente, haciendo solo esa declaración, con **FastAPI** obtienes:
+
+* Soporte de editor (autocompletado, etc.), incluso para modelos anidados
+* Conversión de datos
+* Validación de datos
+* Documentación automática
+
+## Tipos especiales y validación
+
+Además de tipos singulares normales como `str`, `int`, `float`, etc., puedes usar tipos singulares más complejos que heredan de `str`.
+
+Para ver todas las opciones que tienes, revisa el Overview de Tipos de Pydantic. Verás algunos ejemplos en el siguiente capítulo.
+
+Por ejemplo, como en el modelo `Image` tenemos un campo `url`, podemos declararlo como una instance de `HttpUrl` de Pydantic en lugar de un `str`:
+
+{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
+
+El string será verificado para ser una URL válida, y documentado en JSON Schema / OpenAPI como tal.
+
+## Atributos con listas de submodelos
+
+También puedes usar modelos Pydantic como subtipos de `list`, `set`, etc.:
+
+{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
+
+Esto esperará (convertirá, validará, documentará, etc.) un cuerpo JSON como:
+
+```JSON hl_lines="11"
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": [
+ "rock",
+ "metal",
+ "bar"
+ ],
+ "images": [
+ {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ },
+ {
+ "url": "http://example.com/dave.jpg",
+ "name": "The Baz"
+ }
+ ]
+}
+```
+
+/// info | Información
+
+Nota cómo la clave `images` ahora tiene una lista de objetos de imagen.
+
+///
+
+## Modelos anidados profundamente
+
+Puedes definir modelos anidados tan profundamente como desees:
+
+{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
+
+/// info | Información
+
+Observa cómo `Offer` tiene una lista de `Item`s, que a su vez tienen una lista opcional de `Image`s
+
+///
+
+## Cuerpos de listas puras
+
+Si el valor superior del cuerpo JSON que esperas es un `array` JSON (una `list` en Python), puedes declarar el tipo en el parámetro de la función, al igual que en los modelos Pydantic:
+
+```Python
+images: List[Image]
+```
+
+o en Python 3.9 y superior:
+
+```Python
+images: list[Image]
+```
+
+como en:
+
+{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
+
+## Soporte de editor en todas partes
+
+Y obtienes soporte de editor en todas partes.
+
+Incluso para elementos dentro de listas:
+
+
+
+No podrías obtener este tipo de soporte de editor si estuvieras trabajando directamente con `dict` en lugar de modelos Pydantic.
+
+Pero tampoco tienes que preocuparte por ellos, los `dicts` entrantes se convierten automáticamente y tu salida se convierte automáticamente a JSON también.
+
+## Cuerpos de `dict`s arbitrarios
+
+También puedes declarar un cuerpo como un `dict` con claves de algún tipo y valores de algún otro tipo.
+
+De esta manera, no tienes que saber de antemano cuáles son los nombres válidos de campo/atributo (como sería el caso con modelos Pydantic).
+
+Esto sería útil si deseas recibir claves que aún no conoces.
+
+---
+
+Otro caso útil es cuando deseas tener claves de otro tipo (por ejemplo, `int`).
+
+Eso es lo que vamos a ver aquí.
+
+En este caso, aceptarías cualquier `dict` siempre que tenga claves `int` con valores `float`:
+
+{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
+
+/// tip | Consejo
+
+Ten en cuenta que JSON solo admite `str` como claves.
+
+Pero Pydantic tiene conversión automática de datos.
+
+Esto significa que, aunque tus clientes de API solo pueden enviar strings como claves, mientras esos strings contengan enteros puros, Pydantic los convertirá y validará.
+
+Y el `dict` que recibas como `weights` tendrá realmente claves `int` y valores `float`.
+
+///
+
+## Resumen
+
+Con **FastAPI** tienes la máxima flexibilidad proporcionada por los modelos Pydantic, manteniendo tu código simple, corto y elegante.
+
+Pero con todos los beneficios:
+
+* Soporte de editor (¡autocompletado en todas partes!)
+* Conversión de datos (también conocido como parsing/serialización)
+* Validación de datos
+* Documentación del esquema
+* Documentación automática
diff --git a/docs/es/docs/tutorial/body-updates.md b/docs/es/docs/tutorial/body-updates.md
new file mode 100644
index 000000000..26cd3345f
--- /dev/null
+++ b/docs/es/docs/tutorial/body-updates.md
@@ -0,0 +1,116 @@
+# Cuerpo - Actualizaciones
+
+## Actualización reemplazando con `PUT`
+
+Para actualizar un ítem puedes utilizar la operación de HTTP `PUT`.
+
+Puedes usar el `jsonable_encoder` para convertir los datos de entrada en datos que se puedan almacenar como JSON (por ejemplo, con una base de datos NoSQL). Por ejemplo, convirtiendo `datetime` a `str`.
+
+{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
+
+`PUT` se usa para recibir datos que deben reemplazar los datos existentes.
+
+### Advertencia sobre el reemplazo
+
+Esto significa que si quieres actualizar el ítem `bar` usando `PUT` con un body que contenga:
+
+```Python
+{
+ "name": "Barz",
+ "price": 3,
+ "description": None,
+}
+```
+
+debido a que no incluye el atributo ya almacenado `"tax": 20.2`, el modelo de entrada tomaría el valor por defecto de `"tax": 10.5`.
+
+Y los datos se guardarían con ese "nuevo" `tax` de `10.5`.
+
+## Actualizaciones parciales con `PATCH`
+
+También puedes usar la operación de HTTP `PATCH` para actualizar *parcialmente* datos.
+
+Esto significa que puedes enviar solo los datos que deseas actualizar, dejando el resto intacto.
+
+/// note | Nota
+
+`PATCH` es menos usado y conocido que `PUT`.
+
+Y muchos equipos utilizan solo `PUT`, incluso para actualizaciones parciales.
+
+Eres **libre** de usarlos como desees, **FastAPI** no impone ninguna restricción.
+
+Pero esta guía te muestra, más o menos, cómo se pretende que se usen.
+
+///
+
+### Uso del parámetro `exclude_unset` de Pydantic
+
+Si quieres recibir actualizaciones parciales, es muy útil usar el parámetro `exclude_unset` en el `.model_dump()` del modelo de Pydantic.
+
+Como `item.model_dump(exclude_unset=True)`.
+
+/// info | Información
+
+En Pydantic v1 el método se llamaba `.dict()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_dump()`.
+
+Los ejemplos aquí usan `.dict()` para compatibilidad con Pydantic v1, pero deberías usar `.model_dump()` si puedes usar Pydantic v2.
+
+///
+
+Eso generaría un `dict` solo con los datos que se establecieron al crear el modelo `item`, excluyendo los valores por defecto.
+
+Luego puedes usar esto para generar un `dict` solo con los datos que se establecieron (enviados en el request), omitiendo los valores por defecto:
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
+
+### Uso del parámetro `update` de Pydantic
+
+Ahora, puedes crear una copia del modelo existente usando `.model_copy()`, y pasar el parámetro `update` con un `dict` que contenga los datos a actualizar.
+
+/// info | Información
+
+En Pydantic v1 el método se llamaba `.copy()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_copy()`.
+
+Los ejemplos aquí usan `.copy()` para compatibilidad con Pydantic v1, pero deberías usar `.model_copy()` si puedes usar Pydantic v2.
+
+///
+
+Como `stored_item_model.model_copy(update=update_data)`:
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
+
+### Resumen de actualizaciones parciales
+
+En resumen, para aplicar actualizaciones parciales deberías:
+
+* (Opcionalmente) usar `PATCH` en lugar de `PUT`.
+* Recuperar los datos almacenados.
+* Poner esos datos en un modelo de Pydantic.
+* Generar un `dict` sin valores por defecto del modelo de entrada (usando `exclude_unset`).
+ * De esta manera puedes actualizar solo los valores realmente establecidos por el usuario, en lugar de sobrescribir valores ya almacenados con valores por defecto en tu modelo.
+* Crear una copia del modelo almacenado, actualizando sus atributos con las actualizaciones parciales recibidas (usando el parámetro `update`).
+* Convertir el modelo copiado en algo que pueda almacenarse en tu base de datos (por ejemplo, usando el `jsonable_encoder`).
+ * Esto es comparable a usar el método `.model_dump()` del modelo de nuevo, pero asegura (y convierte) los valores a tipos de datos que pueden convertirse a JSON, por ejemplo, `datetime` a `str`.
+* Guardar los datos en tu base de datos.
+* Devolver el modelo actualizado.
+
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
+
+/// tip | Consejo
+
+Puedes realmente usar esta misma técnica con una operación HTTP `PUT`.
+
+Pero el ejemplo aquí usa `PATCH` porque fue creado para estos casos de uso.
+
+///
+
+/// note | Nota
+
+Observa que el modelo de entrada sigue siendo validado.
+
+Entonces, si deseas recibir actualizaciones parciales que puedan omitir todos los atributos, necesitas tener un modelo con todos los atributos marcados como opcionales (con valores por defecto o `None`).
+
+Para distinguir entre los modelos con todos los valores opcionales para **actualizaciones** y modelos con valores requeridos para **creación**, puedes utilizar las ideas descritas en [Modelos Extra](extra-models.md){.internal-link target=_blank}.
+
+///
diff --git a/docs/es/docs/tutorial/body.md b/docs/es/docs/tutorial/body.md
new file mode 100644
index 000000000..6d0aa7c60
--- /dev/null
+++ b/docs/es/docs/tutorial/body.md
@@ -0,0 +1,164 @@
+# Request Body
+
+Cuando necesitas enviar datos desde un cliente (digamos, un navegador) a tu API, los envías como un **request body**.
+
+Un **request** body es un dato enviado por el cliente a tu API. Un **response** body es el dato que tu API envía al cliente.
+
+Tu API casi siempre tiene que enviar un **response** body. Pero los clientes no necesariamente necesitan enviar **request bodies** todo el tiempo, a veces solo solicitan un path, quizás con algunos parámetros de query, pero no envían un body.
+
+Para declarar un **request** body, usas modelos de Pydantic con todo su poder y beneficios.
+
+/// info | Información
+
+Para enviar datos, deberías usar uno de estos métodos: `POST` (el más común), `PUT`, `DELETE` o `PATCH`.
+
+Enviar un body con un request `GET` tiene un comportamiento indefinido en las especificaciones, no obstante, es soportado por FastAPI, solo para casos de uso muy complejos/extremos.
+
+Como no se recomienda, la documentación interactiva con Swagger UI no mostrará la documentación para el body cuando se usa `GET`, y los proxies intermedios podrían no soportarlo.
+
+///
+
+## Importar `BaseModel` de Pydantic
+
+Primero, necesitas importar `BaseModel` de `pydantic`:
+
+{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
+
+## Crea tu modelo de datos
+
+Luego, declaras tu modelo de datos como una clase que hereda de `BaseModel`.
+
+Usa tipos estándar de Python para todos los atributos:
+
+{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
+
+Al igual que al declarar parámetros de query, cuando un atributo del modelo tiene un valor por defecto, no es obligatorio. De lo contrario, es obligatorio. Usa `None` para hacerlo opcional.
+
+Por ejemplo, el modelo anterior declara un “`object`” JSON (o `dict` en Python) como:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "An optional description",
+ "price": 45.2,
+ "tax": 3.5
+}
+```
+
+...dado que `description` y `tax` son opcionales (con un valor por defecto de `None`), este “`object`” JSON también sería válido:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 45.2
+}
+```
+
+## Decláralo como un parámetro
+
+Para añadirlo a tu *path operation*, decláralo de la misma manera que declaraste parámetros de path y query:
+
+{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
+
+...y declara su tipo como el modelo que creaste, `Item`.
+
+## Resultados
+
+Con solo esa declaración de tipo en Python, **FastAPI** hará lo siguiente:
+
+* Leer el body del request como JSON.
+* Convertir los tipos correspondientes (si es necesario).
+* Validar los datos.
+ * Si los datos son inválidos, devolverá un error claro e indicado, señalando exactamente dónde y qué fue lo incorrecto.
+* Proporcionar los datos recibidos en el parámetro `item`.
+ * Como lo declaraste en la función como de tipo `Item`, también tendrás todo el soporte del editor (autocompletado, etc.) para todos los atributos y sus tipos.
+* Generar definiciones de JSON Schema para tu modelo, que también puedes usar en cualquier otro lugar si tiene sentido para tu proyecto.
+* Esquemas que serán parte del esquema de OpenAPI generado y usados por la UIs de documentación automática.
+
+## Documentación automática
+
+Los JSON Schemas de tus modelos serán parte del esquema OpenAPI generado y se mostrarán en la documentación API interactiva:
+
+
+
+Y también se utilizarán en la documentación API dentro de cada *path operation* que los necesite:
+
+
+
+## Soporte del editor
+
+En tu editor, dentro de tu función, obtendrás anotaciones de tipos y autocompletado en todas partes (esto no sucedería si recibieras un `dict` en lugar de un modelo de Pydantic):
+
+
+
+También recibirás chequeos de errores para operaciones de tipo incorrecto:
+
+
+
+No es por casualidad, todo el framework fue construido alrededor de ese diseño.
+
+Y fue rigurosamente probado en la fase de diseño, antes de cualquier implementación, para garantizar que funcionaría con todos los editores.
+
+Incluso se hicieron algunos cambios en Pydantic para admitir esto.
+
+Las capturas de pantalla anteriores se tomaron con Visual Studio Code.
+
+Pero obtendrías el mismo soporte en el editor con PyCharm y la mayoría de los otros editores de Python:
+
+
+
+/// tip | Consejo
+
+Si usas PyCharm como tu editor, puedes usar el Pydantic PyCharm Plugin.
+
+Mejora el soporte del editor para modelos de Pydantic, con:
+
+* autocompletado
+* chequeo de tipos
+* refactorización
+* búsqueda
+* inspecciones
+
+///
+
+## Usa el modelo
+
+Dentro de la función, puedes acceder a todos los atributos del objeto modelo directamente:
+
+{* ../../docs_src/body/tutorial002_py310.py *}
+
+## Request body + parámetros de path
+
+Puedes declarar parámetros de path y request body al mismo tiempo.
+
+**FastAPI** reconocerá que los parámetros de función que coinciden con los parámetros de path deben ser **tomados del path**, y que los parámetros de función que se declaran como modelos de Pydantic deben ser **tomados del request body**.
+
+{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
+
+## Request body + path + parámetros de query
+
+También puedes declarar parámetros de **body**, **path** y **query**, todos al mismo tiempo.
+
+**FastAPI** reconocerá cada uno de ellos y tomará los datos del lugar correcto.
+
+{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
+
+Los parámetros de la función se reconocerán de la siguiente manera:
+
+* Si el parámetro también se declara en el **path**, se utilizará como un parámetro de path.
+* Si el parámetro es de un **tipo singular** (como `int`, `float`, `str`, `bool`, etc.), se interpretará como un parámetro de **query**.
+* Si el parámetro se declara como del tipo de un **modelo de Pydantic**, se interpretará como un **request body**.
+
+/// note | Nota
+
+FastAPI sabrá que el valor de `q` no es requerido debido al valor por defecto `= None`.
+
+El `str | None` (Python 3.10+) o `Union` en `Union[str, None]` (Python 3.8+) no es utilizado por FastAPI para determinar que el valor no es requerido, sabrá que no es requerido porque tiene un valor por defecto de `= None`.
+
+Pero agregar las anotaciones de tipos permitirá que tu editor te brinde un mejor soporte y detecte errores.
+
+///
+
+## Sin Pydantic
+
+Si no quieres usar modelos de Pydantic, también puedes usar parámetros **Body**. Consulta la documentación para [Body - Multiples Parametros: Valores singulares en body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
diff --git a/docs/es/docs/tutorial/cookie-param-models.md b/docs/es/docs/tutorial/cookie-param-models.md
new file mode 100644
index 000000000..ebdb59265
--- /dev/null
+++ b/docs/es/docs/tutorial/cookie-param-models.md
@@ -0,0 +1,76 @@
+# Modelos de Cookies
+
+Si tienes un grupo de **cookies** que están relacionadas, puedes crear un **modelo de Pydantic** para declararlas. 🍪
+
+Esto te permitirá **reutilizar el modelo** en **múltiples lugares** y también declarar validaciones y metadatos para todos los parámetros a la vez. 😎
+
+/// note | Nota
+
+Esto es compatible desde la versión `0.115.0` de FastAPI. 🤓
+
+///
+
+/// tip | Consejo
+
+Esta misma técnica se aplica a `Query`, `Cookie`, y `Header`. 😎
+
+///
+
+## Cookies con un Modelo de Pydantic
+
+Declara los parámetros de **cookie** que necesites en un **modelo de Pydantic**, y luego declara el parámetro como `Cookie`:
+
+{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
+
+**FastAPI** **extraerá** los datos para **cada campo** de las **cookies** recibidas en el request y te entregará el modelo de Pydantic que definiste.
+
+## Revisa la Documentación
+
+Puedes ver las cookies definidas en la UI de la documentación en `/docs`:
+
+
+
+
+
+/// info | Información
+
+Ten en cuenta que, como los **navegadores manejan las cookies** de maneras especiales y detrás de escenas, **no** permiten fácilmente que **JavaScript** las toque.
+
+Si vas a la **UI de la documentación de la API** en `/docs` podrás ver la **documentación** de las cookies para tus *path operations*.
+
+Pero incluso si **rellenas los datos** y haces clic en "Execute", como la UI de la documentación funciona con **JavaScript**, las cookies no serán enviadas y verás un **mensaje de error** como si no hubieras escrito ningún valor.
+
+///
+
+## Prohibir Cookies Extra
+
+En algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** las cookies que deseas recibir.
+
+Tu API ahora tiene el poder de controlar su propio consentimiento de cookies. 🤪🍪
+
+Puedes usar la configuración del modelo de Pydantic para `prohibir` cualquier campo `extra`:
+
+{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *}
+
+Si un cliente intenta enviar algunas **cookies extra**, recibirán un response de **error**.
+
+Pobres banners de cookies con todo su esfuerzo para obtener tu consentimiento para que la API lo rechace. 🍪
+
+Por ejemplo, si el cliente intenta enviar una cookie `santa_tracker` con un valor de `good-list-please`, el cliente recibirá un response de **error** que le informa que la cookie `santa_tracker` no está permitida:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["cookie", "santa_tracker"],
+ "msg": "Extra inputs are not permitted",
+ "input": "good-list-please",
+ }
+ ]
+}
+```
+
+## Resumen
+
+Puedes usar **modelos de Pydantic** para declarar **cookies** en **FastAPI**. 😎
diff --git a/docs/es/docs/tutorial/cookie-params.md b/docs/es/docs/tutorial/cookie-params.md
index 9a3b1a00b..45b113ff9 100644
--- a/docs/es/docs/tutorial/cookie-params.md
+++ b/docs/es/docs/tutorial/cookie-params.md
@@ -1,30 +1,30 @@
# Parámetros de Cookie
-Puedes definir parámetros de Cookie de la misma manera que defines parámetros de `Query` y `Path`.
+Puedes definir parámetros de Cookie de la misma manera que defines los parámetros `Query` y `Path`.
## Importar `Cookie`
Primero importa `Cookie`:
-{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3]*}
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
## Declarar parámetros de `Cookie`
Luego declara los parámetros de cookie usando la misma estructura que con `Path` y `Query`.
-El primer valor es el valor por defecto, puedes pasar todos los parámetros adicionales de validación o anotación:
+Puedes definir el valor por defecto así como toda la validación extra o los parámetros de anotación:
-{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9]*}
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
/// note | Detalles Técnicos
`Cookie` es una clase "hermana" de `Path` y `Query`. También hereda de la misma clase común `Param`.
-Pero recuerda que cuando importas `Query`, `Path`, `Cookie` y otros de `fastapi`, en realidad son funciones que devuelven clases especiales.
+Pero recuerda que cuando importas `Query`, `Path`, `Cookie` y otros desde `fastapi`, en realidad son funciones que devuelven clases especiales.
///
-/// info
+/// info | Información
Para declarar cookies, necesitas usar `Cookie`, porque de lo contrario los parámetros serían interpretados como parámetros de query.
diff --git a/docs/es/docs/tutorial/cors.md b/docs/es/docs/tutorial/cors.md
new file mode 100644
index 000000000..e493d4431
--- /dev/null
+++ b/docs/es/docs/tutorial/cors.md
@@ -0,0 +1,85 @@
+# CORS (Cross-Origin Resource Sharing)
+
+CORS o "Cross-Origin Resource Sharing" se refiere a situaciones en las que un frontend que se ejecuta en un navegador tiene código JavaScript que se comunica con un backend, y el backend está en un "origen" diferente al frontend.
+
+## Origen
+
+Un origen es la combinación de protocolo (`http`, `https`), dominio (`myapp.com`, `localhost`, `localhost.tiangolo.com`) y puerto (`80`, `443`, `8080`).
+
+Así que, todos estos son orígenes diferentes:
+
+* `http://localhost`
+* `https://localhost`
+* `http://localhost:8080`
+
+Aunque todos están en `localhost`, usan protocolos o puertos diferentes, por lo tanto, son "orígenes" diferentes.
+
+## Pasos
+
+Entonces, digamos que tienes un frontend corriendo en tu navegador en `http://localhost:8080`, y su JavaScript está tratando de comunicarse con un backend corriendo en `http://localhost` (porque no especificamos un puerto, el navegador asumirá el puerto por defecto `80`).
+
+Entonces, el navegador enviará un request HTTP `OPTIONS` al backend `:80`, y si el backend envía los headers apropiados autorizando la comunicación desde este origen diferente (`http://localhost:8080`), entonces el navegador `:8080` permitirá que el JavaScript en el frontend envíe su request al backend `:80`.
+
+Para lograr esto, el backend `:80` debe tener una lista de "orígenes permitidos".
+
+En este caso, la lista tendría que incluir `http://localhost:8080` para que el frontend `:8080` funcione correctamente.
+
+## Comodines
+
+También es posible declarar la lista como `"*"` (un "comodín") para decir que todos están permitidos.
+
+Pero eso solo permitirá ciertos tipos de comunicación, excluyendo todo lo que implique credenciales: Cookies, headers de autorización como los utilizados con Bearer Tokens, etc.
+
+Así que, para que todo funcione correctamente, es mejor especificar explícitamente los orígenes permitidos.
+
+## Usa `CORSMiddleware`
+
+Puedes configurarlo en tu aplicación **FastAPI** usando el `CORSMiddleware`.
+
+* Importa `CORSMiddleware`.
+* Crea una lista de orígenes permitidos (como strings).
+* Agrégalo como un "middleware" a tu aplicación **FastAPI**.
+
+También puedes especificar si tu backend permite:
+
+* Credenciales (headers de autorización, cookies, etc).
+* Métodos HTTP específicos (`POST`, `PUT`) o todos ellos con el comodín `"*"`.
+* Headers HTTP específicos o todos ellos con el comodín `"*"`.
+
+{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
+
+Los parámetros predeterminados utilizados por la implementación de `CORSMiddleware` son restrictivos por defecto, por lo que necesitarás habilitar explícitamente orígenes, métodos o headers particulares para que los navegadores estén permitidos de usarlos en un contexto de Cross-Domain.
+
+Se admiten los siguientes argumentos:
+
+* `allow_origins` - Una lista de orígenes que deberían estar permitidos para hacer requests cross-origin. Por ejemplo, `['https://example.org', 'https://www.example.org']`. Puedes usar `['*']` para permitir cualquier origen.
+* `allow_origin_regex` - Una cadena regex para coincidir con orígenes que deberían estar permitidos para hacer requests cross-origin. por ejemplo, `'https://.*\.example\.org'`.
+* `allow_methods` - Una lista de métodos HTTP que deberían estar permitidos para requests cross-origin. Por defecto es `['GET']`. Puedes usar `['*']` para permitir todos los métodos estándar.
+* `allow_headers` - Una lista de headers de request HTTP que deberían estar soportados para requests cross-origin. Por defecto es `[]`. Puedes usar `['*']` para permitir todos los headers. Los headers `Accept`, `Accept-Language`, `Content-Language` y `Content-Type` siempre están permitidos para requests CORS simples.
+* `allow_credentials` - Indica que las cookies deberían estar soportadas para requests cross-origin. Por defecto es `False`. Además, `allow_origins` no puede ser configurado a `['*']` para que las credenciales estén permitidas, los orígenes deben ser especificados.
+* `expose_headers` - Indica cualquier header de response que debería ser accesible para el navegador. Por defecto es `[]`.
+* `max_age` - Establece un tiempo máximo en segundos para que los navegadores almacenen en caché los responses CORS. Por defecto es `600`.
+
+El middleware responde a dos tipos particulares de request HTTP...
+
+### Requests de preflight CORS
+
+Estos son cualquier request `OPTIONS` con headers `Origin` y `Access-Control-Request-Method`.
+
+En este caso, el middleware interceptará el request entrante y responderá con los headers CORS adecuados, y un response `200` o `400` con fines informativos.
+
+### Requests simples
+
+Cualquier request con un header `Origin`. En este caso, el middleware pasará el request a través de lo normal, pero incluirá los headers CORS adecuados en el response.
+
+## Más info
+
+Para más información sobre CORS, revisa la documentación de CORS de Mozilla.
+
+/// note | Detalles Técnicos
+
+También podrías usar `from starlette.middleware.cors import CORSMiddleware`.
+
+**FastAPI** proporciona varios middlewares en `fastapi.middleware` como una conveniencia para ti, el desarrollador. Pero la mayoría de los middlewares disponibles provienen directamente de Starlette.
+
+///
diff --git a/docs/es/docs/tutorial/debugging.md b/docs/es/docs/tutorial/debugging.md
new file mode 100644
index 000000000..2a7544e83
--- /dev/null
+++ b/docs/es/docs/tutorial/debugging.md
@@ -0,0 +1,113 @@
+# Depuración
+
+Puedes conectar el depurador en tu editor, por ejemplo con Visual Studio Code o PyCharm.
+
+## Llama a `uvicorn`
+
+En tu aplicación de FastAPI, importa y ejecuta `uvicorn` directamente:
+
+{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
+
+### Acerca de `__name__ == "__main__"`
+
+El objetivo principal de `__name__ == "__main__"` es tener algo de código que se ejecute cuando tu archivo es llamado con:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+pero no es llamado cuando otro archivo lo importa, como en:
+
+```Python
+from myapp import app
+```
+
+#### Más detalles
+
+Supongamos que tu archivo se llama `myapp.py`.
+
+Si lo ejecutas con:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+entonces la variable interna `__name__` en tu archivo, creada automáticamente por Python, tendrá como valor el string `"__main__"`.
+
+Así que, la sección:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+se ejecutará.
+
+---
+
+Esto no ocurrirá si importas ese módulo (archivo).
+
+Entonces, si tienes otro archivo `importer.py` con:
+
+```Python
+from myapp import app
+
+# Algún código adicional
+```
+
+en ese caso, la variable creada automáticamente dentro de `myapp.py` no tendrá la variable `__name__` con un valor de `"__main__"`.
+
+Así que, la línea:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+no se ejecutará.
+
+/// info | Información
+
+Para más información, revisa la documentación oficial de Python.
+
+///
+
+## Ejecuta tu código con tu depurador
+
+Dado que estás ejecutando el servidor Uvicorn directamente desde tu código, puedes llamar a tu programa de Python (tu aplicación FastAPI) directamente desde el depurador.
+
+---
+
+Por ejemplo, en Visual Studio Code, puedes:
+
+* Ir al panel de "Debug".
+* "Add configuration...".
+* Seleccionar "Python".
+* Ejecutar el depurador con la opción "`Python: Current File (Integrated Terminal)`".
+
+Luego, iniciará el servidor con tu código **FastAPI**, deteniéndose en tus puntos de interrupción, etc.
+
+Así es como podría verse:
+
+
+
+---
+
+Si usas PyCharm, puedes:
+
+* Abrir el menú "Run".
+* Seleccionar la opción "Debug...".
+* Luego aparece un menú contextual.
+* Selecciona el archivo para depurar (en este caso, `main.py`).
+
+Luego, iniciará el servidor con tu código **FastAPI**, deteniéndose en tus puntos de interrupción, etc.
+
+Así es como podría verse:
+
+
diff --git a/docs/es/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/es/docs/tutorial/dependencies/classes-as-dependencies.md
new file mode 100644
index 000000000..d0868240e
--- /dev/null
+++ b/docs/es/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -0,0 +1,288 @@
+# Clases como dependencias
+
+Antes de profundizar en el sistema de **Inyección de Dependencias**, vamos a mejorar el ejemplo anterior.
+
+## Un `dict` del ejemplo anterior
+
+En el ejemplo anterior, estábamos devolviendo un `dict` de nuestra dependencia ("dependable"):
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
+
+Pero luego obtenemos un `dict` en el parámetro `commons` de la *path operation function*.
+
+Y sabemos que los editores no pueden proporcionar mucho soporte (como autocompletado) para `dict`s, porque no pueden conocer sus claves y tipos de valor.
+
+Podemos hacerlo mejor...
+
+## Qué hace a una dependencia
+
+Hasta ahora has visto dependencias declaradas como funciones.
+
+Pero esa no es la única forma de declarar dependencias (aunque probablemente sea la más común).
+
+El factor clave es que una dependencia debe ser un "callable".
+
+Un "**callable**" en Python es cualquier cosa que Python pueda "llamar" como una función.
+
+Entonces, si tienes un objeto `something` (que podría _no_ ser una función) y puedes "llamarlo" (ejecutarlo) como:
+
+```Python
+something()
+```
+
+o
+
+```Python
+something(some_argument, some_keyword_argument="foo")
+```
+
+entonces es un "callable".
+
+## Clases como dependencias
+
+Puedes notar que para crear una instance de una clase en Python, utilizas esa misma sintaxis.
+
+Por ejemplo:
+
+```Python
+class Cat:
+ def __init__(self, name: str):
+ self.name = name
+
+
+fluffy = Cat(name="Mr Fluffy")
+```
+
+En este caso, `fluffy` es una instance de la clase `Cat`.
+
+Y para crear `fluffy`, estás "llamando" a `Cat`.
+
+Entonces, una clase en Python también es un **callable**.
+
+Entonces, en **FastAPI**, podrías usar una clase de Python como una dependencia.
+
+Lo que **FastAPI** realmente comprueba es que sea un "callable" (función, clase o cualquier otra cosa) y los parámetros definidos.
+
+Si pasas un "callable" como dependencia en **FastAPI**, analizará los parámetros de ese "callable", y los procesará de la misma manera que los parámetros de una *path operation function*. Incluyendo sub-dependencias.
+
+Eso también se aplica a los callables sin parámetros. Igual que sería para *path operation functions* sin parámetros.
+
+Entonces, podemos cambiar la dependencia "dependable" `common_parameters` de arriba a la clase `CommonQueryParams`:
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
+
+Presta atención al método `__init__` usado para crear la instance de la clase:
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
+
+...tiene los mismos parámetros que nuestros `common_parameters` anteriores:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
+
+Esos parámetros son los que **FastAPI** usará para "resolver" la dependencia.
+
+En ambos casos, tendrá:
+
+* Un parámetro de query `q` opcional que es un `str`.
+* Un parámetro de query `skip` que es un `int`, con un valor por defecto de `0`.
+* Un parámetro de query `limit` que es un `int`, con un valor por defecto de `100`.
+
+En ambos casos, los datos serán convertidos, validados, documentados en el esquema de OpenAPI, etc.
+
+## Úsalo
+
+Ahora puedes declarar tu dependencia usando esta clase.
+
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
+
+**FastAPI** llama a la clase `CommonQueryParams`. Esto crea una "instance" de esa clase y la instance será pasada como el parámetro `commons` a tu función.
+
+## Anotación de tipos vs `Depends`
+
+Nota cómo escribimos `CommonQueryParams` dos veces en el código anterior:
+
+//// tab | Python 3.8+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.8+ sin `Annotated`
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+El último `CommonQueryParams`, en:
+
+```Python
+... Depends(CommonQueryParams)
+```
+
+...es lo que **FastAPI** utilizará realmente para saber cuál es la dependencia.
+
+Es a partir de este que **FastAPI** extraerá los parámetros declarados y es lo que **FastAPI** realmente llamará.
+
+---
+
+En este caso, el primer `CommonQueryParams`, en:
+
+//// tab | Python 3.8+
+
+```Python
+commons: Annotated[CommonQueryParams, ...
+```
+
+////
+
+//// tab | Python 3.8+ sin `Annotated`
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+commons: CommonQueryParams ...
+```
+
+////
+
+...no tiene ningún significado especial para **FastAPI**. **FastAPI** no lo usará para la conversión de datos, validación, etc. (ya que está usando `Depends(CommonQueryParams)` para eso).
+
+De hecho, podrías escribir simplemente:
+
+//// tab | Python 3.8+
+
+```Python
+commons: Annotated[Any, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.8+ sin `Annotated`
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+commons = Depends(CommonQueryParams)
+```
+
+////
+
+...como en:
+
+{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
+
+Pero declarar el tipo es recomendable, ya que de esa manera tu editor sabrá lo que se pasará como el parámetro `commons`, y entonces podrá ayudarte con el autocompletado, chequeo de tipos, etc:
+
+
+
+## Atajo
+
+Pero ves que estamos teniendo algo de repetición de código aquí, escribiendo `CommonQueryParams` dos veces:
+
+//// tab | Python 3.8+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.8+ sin `Annotated`
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+**FastAPI** proporciona un atajo para estos casos, en donde la dependencia es *específicamente* una clase que **FastAPI** "llamará" para crear una instance de la clase misma.
+
+Para esos casos específicos, puedes hacer lo siguiente:
+
+En lugar de escribir:
+
+//// tab | Python 3.8+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
+```
+
+////
+
+//// tab | Python 3.8+ sin `Annotated`
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends(CommonQueryParams)
+```
+
+////
+
+...escribes:
+
+//// tab | Python 3.8+
+
+```Python
+commons: Annotated[CommonQueryParams, Depends()]
+```
+
+////
+
+//// tab | Python 3.8 sin `Annotated`
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+commons: CommonQueryParams = Depends()
+```
+
+////
+
+Declaras la dependencia como el tipo del parámetro, y usas `Depends()` sin ningún parámetro, en lugar de tener que escribir la clase completa *otra vez* dentro de `Depends(CommonQueryParams)`.
+
+El mismo ejemplo se vería entonces así:
+
+{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
+
+...y **FastAPI** sabrá qué hacer.
+
+/// tip | Consejo
+
+Si eso parece más confuso que útil, ignóralo, no lo *necesitas*.
+
+Es solo un atajo. Porque a **FastAPI** le importa ayudarte a minimizar la repetición de código.
+
+///
diff --git a/docs/es/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/es/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
new file mode 100644
index 000000000..fbe17c67a
--- /dev/null
+++ b/docs/es/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -0,0 +1,69 @@
+# Dependencias en decoradores de *path operation*
+
+En algunos casos realmente no necesitas el valor de retorno de una dependencia dentro de tu *path operation function*.
+
+O la dependencia no devuelve un valor.
+
+Pero aún necesitas que sea ejecutada/resuelta.
+
+Para esos casos, en lugar de declarar un parámetro de *path operation function* con `Depends`, puedes añadir una `list` de `dependencies` al decorador de *path operation*.
+
+## Agregar `dependencies` al decorador de *path operation*
+
+El decorador de *path operation* recibe un argumento opcional `dependencies`.
+
+Debe ser una `list` de `Depends()`:
+
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
+
+Estas dependencias serán ejecutadas/resueltas de la misma manera que las dependencias normales. Pero su valor (si devuelven alguno) no será pasado a tu *path operation function*.
+
+/// tip | Consejo
+
+Algunos editores revisan los parámetros de función no usados y los muestran como errores.
+
+Usando estas `dependencies` en el decorador de *path operation* puedes asegurarte de que se ejecutan mientras evitas errores en editores/herramientas.
+
+También puede ayudar a evitar confusiones para nuevos desarrolladores que vean un parámetro no usado en tu código y puedan pensar que es innecesario.
+
+///
+
+/// info | Información
+
+En este ejemplo usamos headers personalizados inventados `X-Key` y `X-Token`.
+
+Pero en casos reales, al implementar seguridad, obtendrías más beneficios usando las [Utilidades de Seguridad integradas (el próximo capítulo)](../security/index.md){.internal-link target=_blank}.
+
+///
+
+## Errores de dependencias y valores de retorno
+
+Puedes usar las mismas *funciones* de dependencia que usas normalmente.
+
+### Requisitos de dependencia
+
+Pueden declarar requisitos de request (como headers) u otras sub-dependencias:
+
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
+
+### Lanzar excepciones
+
+Estas dependencias pueden `raise` excepciones, igual que las dependencias normales:
+
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
+
+### Valores de retorno
+
+Y pueden devolver valores o no, los valores no serán usados.
+
+Así que, puedes reutilizar una dependencia normal (que devuelve un valor) que ya uses en otro lugar, y aunque el valor no se use, la dependencia será ejecutada:
+
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
+
+## Dependencias para un grupo de *path operations*
+
+Más adelante, cuando leas sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md){.internal-link target=_blank}), posiblemente con múltiples archivos, aprenderás cómo declarar un único parámetro `dependencies` para un grupo de *path operations*.
+
+## Dependencias Globales
+
+A continuación veremos cómo añadir dependencias a toda la aplicación `FastAPI`, de modo que se apliquen a cada *path operation*.
diff --git a/docs/es/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/es/docs/tutorial/dependencies/dependencies-with-yield.md
new file mode 100644
index 000000000..94290443a
--- /dev/null
+++ b/docs/es/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -0,0 +1,275 @@
+# Dependencias con yield
+
+FastAPI admite dependencias que realizan algunos pasos adicionales después de finalizar.
+
+Para hacer esto, usa `yield` en lugar de `return` y escribe los pasos adicionales (código) después.
+
+/// tip | Consejo
+
+Asegúrate de usar `yield` una sola vez por dependencia.
+
+///
+
+/// note | Nota técnica
+
+Cualquier función que sea válida para usar con:
+
+* `@contextlib.contextmanager` o
+* `@contextlib.asynccontextmanager`
+
+sería válida para usar como una dependencia en **FastAPI**.
+
+De hecho, FastAPI usa esos dos decoradores internamente.
+
+///
+
+## Una dependencia de base de datos con `yield`
+
+Por ejemplo, podrías usar esto para crear una sesión de base de datos y cerrarla después de finalizar.
+
+Solo el código anterior e incluyendo la declaración `yield` se ejecuta antes de crear un response:
+
+{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *}
+
+El valor generado es lo que se inyecta en *path operations* y otras dependencias:
+
+{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
+
+El código posterior a la declaración `yield` se ejecuta después de crear el response pero antes de enviarla:
+
+{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *}
+
+/// tip | Consejo
+
+Puedes usar funciones `async` o regulares.
+
+**FastAPI** hará lo correcto con cada una, igual que con dependencias normales.
+
+///
+
+## Una dependencia con `yield` y `try`
+
+Si usas un bloque `try` en una dependencia con `yield`, recibirás cualquier excepción que se haya lanzado al usar la dependencia.
+
+Por ejemplo, si algún código en algún punto intermedio, en otra dependencia o en una *path operation*, realiza un "rollback" en una transacción de base de datos o crea cualquier otro error, recibirás la excepción en tu dependencia.
+
+Por lo tanto, puedes buscar esa excepción específica dentro de la dependencia con `except SomeException`.
+
+Del mismo modo, puedes usar `finally` para asegurarte de que los pasos de salida se ejecuten, sin importar si hubo una excepción o no.
+
+{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *}
+
+## Sub-dependencias con `yield`
+
+Puedes tener sub-dependencias y "árboles" de sub-dependencias de cualquier tamaño y forma, y cualquiera o todas ellas pueden usar `yield`.
+
+**FastAPI** se asegurará de que el "código de salida" en cada dependencia con `yield` se ejecute en el orden correcto.
+
+Por ejemplo, `dependency_c` puede tener una dependencia de `dependency_b`, y `dependency_b` de `dependency_a`:
+
+{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
+
+Y todas ellas pueden usar `yield`.
+
+En este caso, `dependency_c`, para ejecutar su código de salida, necesita que el valor de `dependency_b` (aquí llamado `dep_b`) todavía esté disponible.
+
+Y, a su vez, `dependency_b` necesita que el valor de `dependency_a` (aquí llamado `dep_a`) esté disponible para su código de salida.
+
+{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
+
+De la misma manera, podrías tener algunas dependencias con `yield` y otras dependencias con `return`, y hacer que algunas de esas dependan de algunas de las otras.
+
+Y podrías tener una sola dependencia que requiera varias otras dependencias con `yield`, etc.
+
+Puedes tener cualquier combinación de dependencias que quieras.
+
+**FastAPI** se asegurará de que todo se ejecute en el orden correcto.
+
+/// note | Nota técnica
+
+Esto funciona gracias a los Context Managers de Python.
+
+**FastAPI** los utiliza internamente para lograr esto.
+
+///
+
+## Dependencias con `yield` y `HTTPException`
+
+Viste que puedes usar dependencias con `yield` y tener bloques `try` que capturen excepciones.
+
+De la misma manera, podrías lanzar una `HTTPException` o similar en el código de salida, después del `yield`.
+
+/// tip | Consejo
+
+Esta es una técnica algo avanzada, y en la mayoría de los casos realmente no lo necesitarás, ya que puedes lanzar excepciones (incluyendo `HTTPException`) desde dentro del resto del código de tu aplicación, por ejemplo, en la *path operation function*.
+
+Pero está ahí para ti si la necesitas. 🤓
+
+///
+
+{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
+
+Una alternativa que podrías usar para capturar excepciones (y posiblemente también lanzar otra `HTTPException`) es crear un [Manejador de Excepciones Personalizado](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
+
+## Dependencias con `yield` y `except`
+
+Si capturas una excepción usando `except` en una dependencia con `yield` y no la lanzas nuevamente (o lanzas una nueva excepción), FastAPI no podrá notar que hubo una excepción, al igual que sucedería con Python normal:
+
+{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
+
+En este caso, el cliente verá un response *HTTP 500 Internal Server Error* como debería, dado que no estamos lanzando una `HTTPException` o similar, pero el servidor **no tendrá ningún registro** ni ninguna otra indicación de cuál fue el error. 😱
+
+### Siempre `raise` en Dependencias con `yield` y `except`
+
+Si capturas una excepción en una dependencia con `yield`, a menos que estés lanzando otra `HTTPException` o similar, deberías volver a lanzar la excepción original.
+
+Puedes volver a lanzar la misma excepción usando `raise`:
+
+{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
+
+Ahora el cliente obtendrá el mismo response *HTTP 500 Internal Server Error*, pero el servidor tendrá nuestro `InternalError` personalizado en los registros. 😎
+
+## Ejecución de dependencias con `yield`
+
+La secuencia de ejecución es más o menos como este diagrama. El tiempo fluye de arriba a abajo. Y cada columna es una de las partes que interactúa o ejecuta código.
+
+```mermaid
+sequenceDiagram
+
+participant client as Client
+participant handler as Exception handler
+participant dep as Dep with yield
+participant operation as Path Operation
+participant tasks as Background tasks
+
+ Note over client,operation: Puede lanzar excepciones, incluyendo HTTPException
+ client ->> dep: Iniciar request
+ Note over dep: Ejecutar código hasta yield
+ opt raise Exception
+ dep -->> handler: Lanzar Exception
+ handler -->> client: Response HTTP de error
+ end
+ dep ->> operation: Ejecutar dependencia, por ejemplo, sesión de BD
+ opt raise
+ operation -->> dep: Lanzar Exception (por ejemplo, HTTPException)
+ opt handle
+ dep -->> dep: Puede capturar excepción, lanzar una nueva HTTPException, lanzar otra excepción
+ end
+ handler -->> client: Response HTTP de error
+ end
+
+ operation ->> client: Devolver response al cliente
+ Note over client,operation: El response ya fue enviado, no se puede cambiar
+ opt Tasks
+ operation -->> tasks: Enviar tareas en background
+ end
+ opt Lanzar otra excepción
+ tasks -->> tasks: Manejar excepciones en el código de la tarea en background
+ end
+```
+
+/// info | Información
+
+Solo **un response** será enviado al cliente. Podría ser uno de los responses de error o será el response de la *path operation*.
+
+Después de que se envíe uno de esos responses, no se podrá enviar ningún otro response.
+
+///
+
+/// tip | Consejo
+
+Este diagrama muestra `HTTPException`, pero también podrías lanzar cualquier otra excepción que captures en una dependencia con `yield` o con un [Manejador de Excepciones Personalizado](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
+
+Si lanzas alguna excepción, será pasada a las dependencias con yield, incluyendo `HTTPException`. En la mayoría de los casos querrás volver a lanzar esa misma excepción o una nueva desde la dependencia con `yield` para asegurarte de que se maneje correctamente.
+
+///
+
+## Dependencias con `yield`, `HTTPException`, `except` y Tareas en Background
+
+/// warning | Advertencia
+
+Probablemente no necesites estos detalles técnicos, puedes omitir esta sección y continuar abajo.
+
+Estos detalles son útiles principalmente si estabas usando una versión de FastAPI anterior a 0.106.0 y usabas recursos de dependencias con `yield` en tareas en background.
+
+///
+
+### Dependencias con `yield` y `except`, Detalles Técnicos
+
+Antes de FastAPI 0.110.0, si usabas una dependencia con `yield`, y luego capturabas una excepción con `except` en esa dependencia, y no volvías a lanzar la excepción, la excepción se lanzaría automáticamente/transmitiría a cualquier manejador de excepciones o al manejador de errores interno del servidor.
+
+Esto se cambió en la versión 0.110.0 para corregir el consumo no gestionado de memoria de excepciones transmitidas sin un manejador (errores internos del servidor), y para que sea consistente con el comportamiento del código regular de Python.
+
+### Tareas en Background y Dependencias con `yield`, Detalles Técnicos
+
+Antes de FastAPI 0.106.0, lanzar excepciones después de `yield` no era posible, el código de salida en dependencias con `yield` se ejecutaba *después* de que el response se enviara, por lo que los [Manejadores de Excepciones](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} ya se habrían ejecutado.
+
+Esto se diseñó de esta manera principalmente para permitir usar los mismos objetos "extraídos" por dependencias dentro de tareas en background, porque el código de salida se ejecutaría después de que las tareas en background terminaran.
+
+Sin embargo, ya que esto significaría esperar a que el response viaje a través de la red mientras se retiene innecesariamente un recurso en una dependencia con yield (por ejemplo, una conexión a base de datos), esto se cambió en FastAPI 0.106.0.
+
+/// tip | Consejo
+
+Además, una tarea en background es normalmente un conjunto independiente de lógica que debería manejarse por separado, con sus propios recursos (por ejemplo, su propia conexión a base de datos).
+
+De esta manera probablemente tendrás un código más limpio.
+
+///
+
+Si solías depender de este comportamiento, ahora deberías crear los recursos para tareas en background dentro de la propia tarea en background, y usar internamente solo datos que no dependan de los recursos de las dependencias con `yield`.
+
+Por ejemplo, en lugar de usar la misma sesión de base de datos, crearías una nueva sesión de base de datos dentro de la tarea en background, y obtendrías los objetos de la base de datos usando esta nueva sesión. Y luego, en lugar de pasar el objeto de la base de datos como parámetro a la función de tarea en background, pasarías el ID de ese objeto y luego obtendrías el objeto nuevamente dentro de la función de tarea en background.
+
+## Context Managers
+
+### Qué son los "Context Managers"
+
+Los "Context Managers" son aquellos objetos de Python que puedes usar en una declaración `with`.
+
+Por ejemplo, puedes usar `with` para leer un archivo:
+
+```Python
+with open("./somefile.txt") as f:
+ contents = f.read()
+ print(contents)
+```
+
+Internamente, `open("./somefile.txt")` crea un objeto llamado "Context Manager".
+
+Cuando el bloque `with` termina, se asegura de cerrar el archivo, incluso si hubo excepciones.
+
+Cuando creas una dependencia con `yield`, **FastAPI** creará internamente un context manager para ella y lo combinará con algunas otras herramientas relacionadas.
+
+### Usando context managers en dependencias con `yield`
+
+/// warning | Advertencia
+
+Esto es, más o menos, una idea "avanzada".
+
+Si apenas estás comenzando con **FastAPI**, podrías querer omitirlo por ahora.
+
+///
+
+En Python, puedes crear Context Managers creando una clase con dos métodos: `__enter__()` y `__exit__()`.
+
+También puedes usarlos dentro de las dependencias de **FastAPI** con `yield` usando
+`with` o `async with` en la función de dependencia:
+
+{* ../../docs_src/dependencies/tutorial010.py hl[1:9,13] *}
+
+/// tip | Consejo
+
+Otra manera de crear un context manager es con:
+
+* `@contextlib.contextmanager` o
+* `@contextlib.asynccontextmanager`
+
+usándolos para decorar una función con un solo `yield`.
+
+Eso es lo que **FastAPI** usa internamente para dependencias con `yield`.
+
+Pero no tienes que usar los decoradores para las dependencias de FastAPI (y no deberías).
+
+FastAPI lo hará por ti internamente.
+
+///
diff --git a/docs/es/docs/tutorial/dependencies/global-dependencies.md b/docs/es/docs/tutorial/dependencies/global-dependencies.md
new file mode 100644
index 000000000..08dd3d5c5
--- /dev/null
+++ b/docs/es/docs/tutorial/dependencies/global-dependencies.md
@@ -0,0 +1,15 @@
+# Dependencias Globales
+
+Para algunos tipos de aplicaciones, podrías querer agregar dependencias a toda la aplicación.
+
+Similar a como puedes [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, puedes agregarlos a la aplicación de `FastAPI`.
+
+En ese caso, se aplicarán a todas las *path operations* en la aplicación:
+
+{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *}
+
+Y todas las ideas en la sección sobre [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} siguen aplicándose, pero en este caso, a todas las *path operations* en la app.
+
+## Dependencias para grupos de *path operations*
+
+Más adelante, al leer sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md){.internal-link target=_blank}), posiblemente con múltiples archivos, aprenderás cómo declarar un solo parámetro de `dependencies` para un grupo de *path operations*.
diff --git a/docs/es/docs/tutorial/dependencies/index.md b/docs/es/docs/tutorial/dependencies/index.md
new file mode 100644
index 000000000..2fb060177
--- /dev/null
+++ b/docs/es/docs/tutorial/dependencies/index.md
@@ -0,0 +1,250 @@
+# Dependencias
+
+**FastAPI** tiene un sistema de **Inyección de Dependencias** muy poderoso pero intuitivo.
+
+Está diseñado para ser muy simple de usar, y para hacer que cualquier desarrollador integre otros componentes con **FastAPI** de forma muy sencilla.
+
+## Qué es la "Inyección de Dependencias"
+
+**"Inyección de Dependencias"** significa, en programación, que hay una manera para que tu código (en este caso, tus *path operation functions*) declare las cosas que necesita para funcionar y utilizar: "dependencias".
+
+Y luego, ese sistema (en este caso **FastAPI**) se encargará de hacer lo que sea necesario para proporcionar a tu código esas dependencias necesarias ("inyectar" las dependencias).
+
+Esto es muy útil cuando necesitas:
+
+* Tener lógica compartida (la misma lógica de código una y otra vez).
+* Compartir conexiones a bases de datos.
+* Imponer seguridad, autenticación, requisitos de roles, etc.
+* Y muchas otras cosas...
+
+Todo esto, mientras minimizas la repetición de código.
+
+## Primeros Pasos
+
+Veamos un ejemplo muy simple. Será tan simple que no es muy útil, por ahora.
+
+Pero de esta manera podemos enfocarnos en cómo funciona el sistema de **Inyección de Dependencias**.
+
+### Crear una dependencia, o "dependable"
+
+Primero enfoquémonos en la dependencia.
+
+Es solo una función que puede tomar todos los mismos parámetros que una *path operation function* puede tomar:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
+
+Eso es todo.
+
+**2 líneas**.
+
+Y tiene la misma forma y estructura que todas tus *path operation functions*.
+
+Puedes pensar en ella como una *path operation function* sin el "decorador" (sin el `@app.get("/some-path")`).
+
+Y puede devolver lo que quieras.
+
+En este caso, esta dependencia espera:
+
+* Un parámetro de query opcional `q` que es un `str`.
+* Un parámetro de query opcional `skip` que es un `int`, y por defecto es `0`.
+* Un parámetro de query opcional `limit` que es un `int`, y por defecto es `100`.
+
+Y luego solo devuelve un `dict` que contiene esos valores.
+
+/// info | Información
+
+FastAPI agregó soporte para `Annotated` (y comenzó a recomendarlo) en la versión 0.95.0.
+
+Si tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.
+
+Asegúrate de [Actualizar la versión de FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} al menos a la 0.95.1 antes de usar `Annotated`.
+
+///
+
+### Importar `Depends`
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
+
+### Declarar la dependencia, en el "dependant"
+
+De la misma forma en que usas `Body`, `Query`, etc. con los parámetros de tu *path operation function*, usa `Depends` con un nuevo parámetro:
+
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
+
+Aunque usas `Depends` en los parámetros de tu función de la misma manera que usas `Body`, `Query`, etc., `Depends` funciona un poco diferente.
+
+Le das a `Depends` un solo parámetro.
+
+Este parámetro debe ser algo como una función.
+
+**No la llames** directamente (no agregues los paréntesis al final), solo pásala como un parámetro a `Depends()`.
+
+Y esa función toma parámetros de la misma manera que las *path operation functions*.
+
+/// tip | Consejo
+
+Verás qué otras "cosas", además de funciones, pueden usarse como dependencias en el próximo capítulo.
+
+///
+
+Cada vez que llega un nuevo request, **FastAPI** se encargará de:
+
+* Llamar a tu función de dependencia ("dependable") con los parámetros correctos.
+* Obtener el resultado de tu función.
+* Asignar ese resultado al parámetro en tu *path operation function*.
+
+```mermaid
+graph TB
+
+common_parameters(["common_parameters"])
+read_items["/items/"]
+read_users["/users/"]
+
+common_parameters --> read_items
+common_parameters --> read_users
+```
+
+De esta manera escribes código compartido una vez y **FastAPI** se encarga de llamarlo para tus *path operations*.
+
+/// check | Revisa
+
+Nota que no tienes que crear una clase especial y pasarla en algún lugar a **FastAPI** para "registrarla" o algo similar.
+
+Solo la pasas a `Depends` y **FastAPI** sabe cómo hacer el resto.
+
+///
+
+## Compartir dependencias `Annotated`
+
+En los ejemplos anteriores, ves que hay un poquito de **duplicación de código**.
+
+Cuando necesitas usar la dependencia `common_parameters()`, tienes que escribir todo el parámetro con la anotación de tipo y `Depends()`:
+
+```Python
+commons: Annotated[dict, Depends(common_parameters)]
+```
+
+Pero como estamos usando `Annotated`, podemos almacenar ese valor `Annotated` en una variable y usarlo en múltiples lugares:
+
+{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
+
+/// tip | Consejo
+
+Esto es solo Python estándar, se llama un "alias de tipo", en realidad no es específico de **FastAPI**.
+
+Pero porque **FastAPI** está basado en los estándares de Python, incluido `Annotated`, puedes usar este truco en tu código. 😎
+
+///
+
+Las dependencias seguirán funcionando como se esperaba, y la **mejor parte** es que la **información de tipo se preservará**, lo que significa que tu editor podrá seguir proporcionándote **autocompletado**, **errores en línea**, etc. Lo mismo para otras herramientas como `mypy`.
+
+Esto será especialmente útil cuando lo uses en una **gran base de código** donde uses **las mismas dependencias** una y otra vez en **muchas *path operations***.
+
+## Usar `async` o no usar `async`
+
+Como las dependencias también serán llamadas por **FastAPI** (lo mismo que tus *path operation functions*), las mismas reglas aplican al definir tus funciones.
+
+Puedes usar `async def` o `def` normal.
+
+Y puedes declarar dependencias con `async def` dentro de *path operation functions* normales `def`, o dependencias `def` dentro de *path operation functions* `async def`, etc.
+
+No importa. **FastAPI** sabrá qué hacer.
+
+/// note | Nota
+
+Si no lo sabes, revisa la sección [Async: *"¿Con prisa?"*](../../async.md#in-a-hurry){.internal-link target=_blank} sobre `async` y `await` en la documentación.
+
+///
+
+## Integración con OpenAPI
+
+Todas las declaraciones de request, validaciones y requisitos de tus dependencias (y sub-dependencias) se integrarán en el mismo esquema de OpenAPI.
+
+Así, la documentación interactiva tendrá toda la información de estas dependencias también:
+
+
+
+## Uso simple
+
+Si lo ves, las *path operation functions* se declaran para ser usadas siempre que un *path* y una *operación* coincidan, y luego **FastAPI** se encarga de llamar la función con los parámetros correctos, extrayendo los datos del request.
+
+En realidad, todos (o la mayoría) de los frameworks web funcionan de esta misma manera.
+
+Nunca llamas directamente a esas funciones. Son llamadas por tu framework (en este caso, **FastAPI**).
+
+Con el sistema de Inyección de Dependencias, también puedes decirle a **FastAPI** que tu *path operation function* también "depende" de algo más que debe ejecutarse antes que tu *path operation function*, y **FastAPI** se encargará de ejecutarlo e "inyectar" los resultados.
+
+Otros términos comunes para esta misma idea de "inyección de dependencias" son:
+
+* recursos
+* proveedores
+* servicios
+* inyectables
+* componentes
+
+## Plug-ins de **FastAPI**
+
+Las integraciones y "plug-ins" pueden construirse usando el sistema de **Inyección de Dependencias**. Pero, de hecho, en realidad **no hay necesidad de crear "plug-ins"**, ya que al usar dependencias es posible declarar una cantidad infinita de integraciones e interacciones que se vuelven disponibles para tus *path operation functions*.
+
+Y las dependencias se pueden crear de una manera muy simple e intuitiva que te permite simplemente importar los paquetes de Python que necesitas, e integrarlos con tus funciones de API en un par de líneas de código, *literalmente*.
+
+Verás ejemplos de esto en los próximos capítulos, sobre bases de datos relacionales y NoSQL, seguridad, etc.
+
+## Compatibilidad de **FastAPI**
+
+La simplicidad del sistema de inyección de dependencias hace que **FastAPI** sea compatible con:
+
+* todas las bases de datos relacionales
+* bases de datos NoSQL
+* paquetes externos
+* APIs externas
+* sistemas de autenticación y autorización
+* sistemas de monitoreo de uso de la API
+* sistemas de inyección de datos de response
+* etc.
+
+## Simple y Poderoso
+
+Aunque el sistema de inyección de dependencias jerárquico es muy simple de definir y usar, sigue siendo muy poderoso.
+
+Puedes definir dependencias que a su vez pueden definir dependencias ellas mismas.
+
+Al final, se construye un árbol jerárquico de dependencias, y el sistema de **Inyección de Dependencias** se encarga de resolver todas estas dependencias por ti (y sus sub-dependencias) y proporcionar (inyectar) los resultados en cada paso.
+
+Por ejemplo, digamos que tienes 4 endpoints de API (*path operations*):
+
+* `/items/public/`
+* `/items/private/`
+* `/users/{user_id}/activate`
+* `/items/pro/`
+
+entonces podrías agregar diferentes requisitos de permiso para cada uno de ellos solo con dependencias y sub-dependencias:
+
+```mermaid
+graph TB
+
+current_user(["current_user"])
+active_user(["active_user"])
+admin_user(["admin_user"])
+paying_user(["paying_user"])
+
+public["/items/public/"]
+private["/items/private/"]
+activate_user["/users/{user_id}/activate"]
+pro_items["/items/pro/"]
+
+current_user --> active_user
+active_user --> admin_user
+active_user --> paying_user
+
+current_user --> public
+active_user --> private
+admin_user --> activate_user
+paying_user --> pro_items
+```
+
+## Integrado con **OpenAPI**
+
+Todas estas dependencias, al declarar sus requisitos, también añaden parámetros, validaciones, etc. a tus *path operations*.
+
+**FastAPI** se encargará de agregar todo al esquema de OpenAPI, para que se muestre en los sistemas de documentación interactiva.
diff --git a/docs/es/docs/tutorial/dependencies/sub-dependencies.md b/docs/es/docs/tutorial/dependencies/sub-dependencies.md
new file mode 100644
index 000000000..bba532207
--- /dev/null
+++ b/docs/es/docs/tutorial/dependencies/sub-dependencies.md
@@ -0,0 +1,105 @@
+# Sub-dependencias
+
+Puedes crear dependencias que tengan **sub-dependencias**.
+
+Pueden ser tan **profundas** como necesites.
+
+**FastAPI** se encargará de resolverlas.
+
+## Primera dependencia "dependable"
+
+Podrías crear una primera dependencia ("dependable") así:
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}
+
+Declara un parámetro de query opcional `q` como un `str`, y luego simplemente lo devuelve.
+
+Esto es bastante simple (no muy útil), pero nos ayudará a centrarnos en cómo funcionan las sub-dependencias.
+
+## Segunda dependencia, "dependable" y "dependant"
+
+Luego puedes crear otra función de dependencia (un "dependable") que al mismo tiempo declare una dependencia propia (por lo que también es un "dependant"):
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
+
+Centrémonos en los parámetros declarados:
+
+* Aunque esta función es una dependencia ("dependable") en sí misma, también declara otra dependencia (depende de algo más).
+ * Depende del `query_extractor`, y asigna el valor que devuelve al parámetro `q`.
+* También declara una `last_query` cookie opcional, como un `str`.
+ * Si el usuario no proporcionó ningún query `q`, usamos el último query utilizado, que guardamos previamente en una cookie.
+
+## Usa la dependencia
+
+Entonces podemos usar la dependencia con:
+
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
+
+/// info | Información
+
+Fíjate que solo estamos declarando una dependencia en la *path operation function*, `query_or_cookie_extractor`.
+
+Pero **FastAPI** sabrá que tiene que resolver `query_extractor` primero, para pasar los resultados de eso a `query_or_cookie_extractor` al llamarlo.
+
+///
+
+```mermaid
+graph TB
+
+query_extractor(["query_extractor"])
+query_or_cookie_extractor(["query_or_cookie_extractor"])
+
+read_query["/items/"]
+
+query_extractor --> query_or_cookie_extractor --> read_query
+```
+
+## Usando la misma dependencia múltiples veces
+
+Si una de tus dependencias se declara varias veces para la misma *path operation*, por ejemplo, múltiples dependencias tienen una sub-dependencia común, **FastAPI** sabrá llamar a esa sub-dependencia solo una vez por request.
+
+Y guardará el valor devuelto en un "cache" y lo pasará a todos los "dependants" que lo necesiten en ese request específico, en lugar de llamar a la dependencia varias veces para el mismo request.
+
+En un escenario avanzado donde sabes que necesitas que la dependencia se llame en cada paso (posiblemente varias veces) en el mismo request en lugar de usar el valor "cache", puedes establecer el parámetro `use_cache=False` al usar `Depends`:
+
+//// tab | Python 3.8+
+
+```Python hl_lines="1"
+async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):
+ return {"fresh_value": fresh_value}
+```
+
+////
+
+//// tab | Python 3.8+ sin Anotaciones
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python hl_lines="1"
+async def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):
+ return {"fresh_value": fresh_value}
+```
+
+////
+
+## Resumen
+
+Aparte de todas las palabras rimbombantes usadas aquí, el sistema de **Inyección de Dependencias** es bastante simple.
+
+Solo son funciones que se ven igual que las *path operation functions*.
+
+Pero aun así, es muy potente y te permite declarar "grafos" de dependencia anidados arbitrariamente profundos (árboles).
+
+/// tip | Consejo
+
+Todo esto podría no parecer tan útil con estos ejemplos simples.
+
+Pero verás lo útil que es en los capítulos sobre **seguridad**.
+
+Y también verás la cantidad de código que te ahorrará.
+
+///
diff --git a/docs/es/docs/tutorial/encoder.md b/docs/es/docs/tutorial/encoder.md
new file mode 100644
index 000000000..9b8919d4b
--- /dev/null
+++ b/docs/es/docs/tutorial/encoder.md
@@ -0,0 +1,35 @@
+# JSON Compatible Encoder
+
+Hay algunos casos en los que podrías necesitar convertir un tipo de dato (como un modelo de Pydantic) a algo compatible con JSON (como un `dict`, `list`, etc).
+
+Por ejemplo, si necesitas almacenarlo en una base de datos.
+
+Para eso, **FastAPI** proporciona una función `jsonable_encoder()`.
+
+## Usando el `jsonable_encoder`
+
+Imaginemos que tienes una base de datos `fake_db` que solo recibe datos compatibles con JSON.
+
+Por ejemplo, no recibe objetos `datetime`, ya que no son compatibles con JSON.
+
+Entonces, un objeto `datetime` tendría que ser convertido a un `str` que contenga los datos en formato ISO.
+
+De la misma manera, esta base de datos no recibiría un modelo de Pydantic (un objeto con atributos), solo un `dict`.
+
+Puedes usar `jsonable_encoder` para eso.
+
+Recibe un objeto, como un modelo de Pydantic, y devuelve una versión compatible con JSON:
+
+{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
+
+En este ejemplo, convertiría el modelo de Pydantic a un `dict`, y el `datetime` a un `str`.
+
+El resultado de llamarlo es algo que puede ser codificado con la función estándar de Python `json.dumps()`.
+
+No devuelve un gran `str` que contenga los datos en formato JSON (como una cadena de texto). Devuelve una estructura de datos estándar de Python (por ejemplo, un `dict`) con valores y sub-valores que son todos compatibles con JSON.
+
+/// note | Nota
+
+`jsonable_encoder` es utilizado internamente por **FastAPI** para convertir datos. Pero es útil en muchos otros escenarios.
+
+///
diff --git a/docs/es/docs/tutorial/extra-data-types.md b/docs/es/docs/tutorial/extra-data-types.md
new file mode 100644
index 000000000..28775780f
--- /dev/null
+++ b/docs/es/docs/tutorial/extra-data-types.md
@@ -0,0 +1,62 @@
+# Tipos de Datos Extra
+
+Hasta ahora, has estado usando tipos de datos comunes, como:
+
+* `int`
+* `float`
+* `str`
+* `bool`
+
+Pero también puedes usar tipos de datos más complejos.
+
+Y seguirás teniendo las mismas funcionalidades como hasta ahora:
+
+* Gran soporte de editor.
+* Conversión de datos de requests entrantes.
+* Conversión de datos para datos de response.
+* Validación de datos.
+* Anotación y documentación automática.
+
+## Otros tipos de datos
+
+Aquí hay algunos de los tipos de datos adicionales que puedes usar:
+
+* `UUID`:
+ * Un "Identificador Universalmente Único" estándar, común como un ID en muchas bases de datos y sistemas.
+ * En requests y responses se representará como un `str`.
+* `datetime.datetime`:
+ * Un `datetime.datetime` de Python.
+ * En requests y responses se representará como un `str` en formato ISO 8601, como: `2008-09-15T15:53:00+05:00`.
+* `datetime.date`:
+ * `datetime.date` de Python.
+ * En requests y responses se representará como un `str` en formato ISO 8601, como: `2008-09-15`.
+* `datetime.time`:
+ * Un `datetime.time` de Python.
+ * En requests y responses se representará como un `str` en formato ISO 8601, como: `14:23:55.003`.
+* `datetime.timedelta`:
+ * Un `datetime.timedelta` de Python.
+ * En requests y responses se representará como un `float` de segundos totales.
+ * Pydantic también permite representarlo como una "codificación de diferencia horaria ISO 8601", consulta la documentación para más información.
+* `frozenset`:
+ * En requests y responses, tratado igual que un `set`:
+ * En requests, se leerá una list, eliminando duplicados y convirtiéndola en un `set`.
+ * En responses, el `set` se convertirá en una `list`.
+ * El esquema generado especificará que los valores del `set` son únicos (usando `uniqueItems` de JSON Schema).
+* `bytes`:
+ * `bytes` estándar de Python.
+ * En requests y responses se tratará como `str`.
+ * El esquema generado especificará que es un `str` con "binary" como "format".
+* `Decimal`:
+ * `Decimal` estándar de Python.
+ * En requests y responses, manejado igual que un `float`.
+* Puedes revisar todos los tipos de datos válidos de Pydantic aquí: Tipos de datos de Pydantic.
+
+## Ejemplo
+
+Aquí tienes un ejemplo de una *path operation* con parámetros usando algunos de los tipos anteriores.
+
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
+
+Nota que los parámetros dentro de la función tienen su tipo de dato natural, y puedes, por ejemplo, realizar manipulaciones de fechas normales, como:
+
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
diff --git a/docs/es/docs/tutorial/extra-models.md b/docs/es/docs/tutorial/extra-models.md
new file mode 100644
index 000000000..0380b9690
--- /dev/null
+++ b/docs/es/docs/tutorial/extra-models.md
@@ -0,0 +1,222 @@
+# Modelos Extra
+
+Continuando con el ejemplo anterior, será común tener más de un modelo relacionado.
+
+Esto es especialmente el caso para los modelos de usuario, porque:
+
+* El **modelo de entrada** necesita poder tener una contraseña.
+* El **modelo de salida** no debería tener una contraseña.
+* El **modelo de base de datos** probablemente necesitaría tener una contraseña hasheada.
+
+/// danger | Peligro
+
+Nunca almacenes contraseñas de usuarios en texto plano. Siempre almacena un "hash seguro" que puedas verificar luego.
+
+Si no lo sabes, aprenderás qué es un "hash de contraseña" en los [capítulos de seguridad](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
+
+///
+
+## Múltiples modelos
+
+Aquí tienes una idea general de cómo podrían ser los modelos con sus campos de contraseña y los lugares donde se utilizan:
+
+{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
+
+/// info | Información
+
+En Pydantic v1 el método se llamaba `.dict()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_dump()`.
+
+Los ejemplos aquí usan `.dict()` para compatibilidad con Pydantic v1, pero deberías usar `.model_dump()` en su lugar si puedes usar Pydantic v2.
+
+///
+
+### Acerca de `**user_in.dict()`
+
+#### `.dict()` de Pydantic
+
+`user_in` es un modelo Pydantic de la clase `UserIn`.
+
+Los modelos Pydantic tienen un método `.dict()` que devuelve un `dict` con los datos del modelo.
+
+Así que, si creamos un objeto Pydantic `user_in` como:
+
+```Python
+user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
+```
+
+y luego llamamos a:
+
+```Python
+user_dict = user_in.dict()
+```
+
+ahora tenemos un `dict` con los datos en la variable `user_dict` (es un `dict` en lugar de un objeto modelo Pydantic).
+
+Y si llamamos a:
+
+```Python
+print(user_dict)
+```
+
+obtendremos un `dict` de Python con:
+
+```Python
+{
+ 'username': 'john',
+ 'password': 'secret',
+ 'email': 'john.doe@example.com',
+ 'full_name': None,
+}
+```
+
+#### Desempaquetando un `dict`
+
+Si tomamos un `dict` como `user_dict` y lo pasamos a una función (o clase) con `**user_dict`, Python lo "desempaquetará". Pasará las claves y valores del `user_dict` directamente como argumentos clave-valor.
+
+Así que, continuando con el `user_dict` anterior, escribir:
+
+```Python
+UserInDB(**user_dict)
+```
+
+sería equivalente a algo como:
+
+```Python
+UserInDB(
+ username="john",
+ password="secret",
+ email="john.doe@example.com",
+ full_name=None,
+)
+```
+
+O más exactamente, usando `user_dict` directamente, con cualquier contenido que pueda tener en el futuro:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+)
+```
+
+#### Un modelo Pydantic a partir del contenido de otro
+
+Como en el ejemplo anterior obtuvimos `user_dict` de `user_in.dict()`, este código:
+
+```Python
+user_dict = user_in.dict()
+UserInDB(**user_dict)
+```
+
+sería equivalente a:
+
+```Python
+UserInDB(**user_in.dict())
+```
+
+...porque `user_in.dict()` es un `dict`, y luego hacemos que Python lo "desempaquete" al pasarlo a `UserInDB` con el prefijo `**`.
+
+Así, obtenemos un modelo Pydantic a partir de los datos en otro modelo Pydantic.
+
+#### Desempaquetando un `dict` y palabras clave adicionales
+
+Y luego agregando el argumento de palabra clave adicional `hashed_password=hashed_password`, como en:
+
+```Python
+UserInDB(**user_in.dict(), hashed_password=hashed_password)
+```
+
+...termina siendo como:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ hashed_password = hashed_password,
+)
+```
+
+/// warning | Advertencia
+
+Las funciones adicionales de soporte `fake_password_hasher` y `fake_save_user` son solo para demostrar un posible flujo de datos, pero por supuesto no proporcionan ninguna seguridad real.
+
+///
+
+## Reducir duplicación
+
+Reducir la duplicación de código es una de las ideas centrales en **FastAPI**.
+
+Ya que la duplicación de código incrementa las posibilidades de bugs, problemas de seguridad, problemas de desincronización de código (cuando actualizas en un lugar pero no en los otros), etc.
+
+Y estos modelos están compartiendo muchos de los datos y duplicando nombres y tipos de atributos.
+
+Podríamos hacerlo mejor.
+
+Podemos declarar un modelo `UserBase` que sirva como base para nuestros otros modelos. Y luego podemos hacer subclases de ese modelo que heredan sus atributos (declaraciones de tipo, validación, etc).
+
+Toda la conversión de datos, validación, documentación, etc. seguirá funcionando normalmente.
+
+De esa manera, podemos declarar solo las diferencias entre los modelos (con `password` en texto plano, con `hashed_password` y sin contraseña):
+
+{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
+
+## `Union` o `anyOf`
+
+Puedes declarar un response que sea la `Union` de dos o más tipos, eso significa que el response sería cualquiera de ellos.
+
+Se definirá en OpenAPI con `anyOf`.
+
+Para hacerlo, usa el type hint estándar de Python `typing.Union`:
+
+/// note | Nota
+
+Al definir una `Union`, incluye el tipo más específico primero, seguido por el tipo menos específico. En el ejemplo a continuación, el más específico `PlaneItem` viene antes de `CarItem` en `Union[PlaneItem, CarItem]`.
+
+///
+
+{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
+
+
+### `Union` en Python 3.10
+
+En este ejemplo pasamos `Union[PlaneItem, CarItem]` como el valor del argumento `response_model`.
+
+Porque lo estamos pasando como un **valor a un argumento** en lugar de ponerlo en una **anotación de tipo**, tenemos que usar `Union` incluso en Python 3.10.
+
+Si estuviera en una anotación de tipo podríamos haber usado la barra vertical, como:
+
+```Python
+some_variable: PlaneItem | CarItem
+```
+
+Pero si ponemos eso en la asignación `response_model=PlaneItem | CarItem` obtendríamos un error, porque Python intentaría realizar una **operación inválida** entre `PlaneItem` y `CarItem` en lugar de interpretar eso como una anotación de tipo.
+
+## Lista de modelos
+
+De la misma manera, puedes declarar responses de listas de objetos.
+
+Para eso, usa el `typing.List` estándar de Python (o simplemente `list` en Python 3.9 y posteriores):
+
+{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
+
+
+## Response con `dict` arbitrario
+
+También puedes declarar un response usando un `dict` arbitrario plano, declarando solo el tipo de las claves y valores, sin usar un modelo Pydantic.
+
+Esto es útil si no conoces los nombres de los campos/atributos válidos (que serían necesarios para un modelo Pydantic) de antemano.
+
+En este caso, puedes usar `typing.Dict` (o solo `dict` en Python 3.9 y posteriores):
+
+{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
+
+
+## Recapitulación
+
+Usa múltiples modelos Pydantic y hereda libremente para cada caso.
+
+No necesitas tener un solo modelo de datos por entidad si esa entidad debe poder tener diferentes "estados". Como el caso con la "entidad" usuario con un estado que incluye `password`, `password_hash` y sin contraseña.
diff --git a/docs/es/docs/tutorial/first-steps.md b/docs/es/docs/tutorial/first-steps.md
index 68df00e64..5d869c22f 100644
--- a/docs/es/docs/tutorial/first-steps.md
+++ b/docs/es/docs/tutorial/first-steps.md
@@ -1,52 +1,74 @@
-# Primeros pasos
+# Primeros Pasos
-Un archivo muy simple de FastAPI podría verse así:
+El archivo FastAPI más simple podría verse así:
-```Python
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py *}
-Copia eso a un archivo `main.py`.
+Copia eso en un archivo `main.py`.
-Corre el servidor en vivo:
+Ejecuta el servidor en vivo:
```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 dev main.py
+INFO Using path main.py
+INFO Resolved absolute path /home/user/code/awesomeapp/main.py
+INFO Searching for package file structure from directories with __init__.py files
+INFO Importing from /home/user/code/awesomeapp
+
+ ╭─ Python module file ─╮
+ │ │
+ │ 🐍 main.py │
+ │ │
+ ╰──────────────────────╯
+
+INFO Importing module main
+INFO Found importable FastAPI app
+
+ ╭─ Importable FastAPI app ─╮
+ │ │
+ │ from main import app │
+ │ │
+ ╰──────────────────────────╯
+
+INFO Using import string main:app
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [2265862] using WatchFiles
+INFO: Started server process [2265873]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
```
-/// note | Nota
-
-El comando `uvicorn main:app` se refiere a:
-
-* `main`: el archivo `main.py` (el "módulo" de Python).
-* `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`.
-* `--reload`: hace que el servidor se reinicie cada vez que cambia el código. Úsalo únicamente para desarrollo.
-
-///
-
-En el output, hay una línea que dice más o menos:
+En el resultado, hay una línea con algo como:
```hl_lines="4"
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
-Esa línea muestra la URL dónde se está sirviendo tu app en tu maquina local.
+Esa línea muestra la URL donde tu aplicación está siendo servida, en tu máquina local.
-### Revísalo
+### Compruébalo
Abre tu navegador en http://127.0.0.1:8000.
-Verás la respuesta en JSON:
+Verás el response JSON como:
```JSON
{"message": "Hello World"}
@@ -54,55 +76,55 @@ Verás la respuesta en JSON:
### Documentación interactiva de la API
-Ahora dirígete a http://127.0.0.1:8000/docs.
+Ahora ve a http://127.0.0.1:8000/docs.
-Ahí verás la documentación automática e interactiva de la API (proveída por Swagger UI):
+Verás la documentación interactiva automática de la API (proporcionada por Swagger UI):

### Documentación alternativa de la API
-Ahora, dirígete a http://127.0.0.1:8000/redoc.
+Y ahora, ve a http://127.0.0.1:8000/redoc.
-Aquí verás la documentación automática alternativa (proveída por ReDoc):
+Verás la documentación alternativa automática (proporcionada por ReDoc):

### OpenAPI
-**FastAPI** genera un "schema" con toda tu API usando el estándar para definir APIs, **OpenAPI**.
+**FastAPI** genera un "esquema" con toda tu API utilizando el estándar **OpenAPI** para definir APIs.
-#### "Schema"
+#### "Esquema"
-Un "schema" es una definición o descripción de algo. No es el código que la implementa, sino solo una descripción abstracta.
+Un "esquema" es una definición o descripción de algo. No el código que lo implementa, sino solo una descripción abstracta.
-#### "Schema" de la API
+#### Esquema de la API
-En este caso, OpenAPI es una especificación que dicta como se debe definir el schema de tu API.
+En este caso, OpenAPI es una especificación que dicta cómo definir un esquema de tu API.
-La definición del schema incluye los paths de tu API, los parámetros que podría recibir, etc.
+Esta definición de esquema incluye los paths de tu API, los posibles parámetros que toman, etc.
-#### "Schema" de datos
+#### Esquema de Datos
-El concepto "schema" también se puede referir a la forma de algunos datos, como un contenido en formato JSON.
+El término "esquema" también podría referirse a la forma de algunos datos, como el contenido JSON.
-En ese caso haría referencia a los atributos del JSON, los tipos de datos que tiene, etc.
+En ese caso, significaría los atributos del JSON, los tipos de datos que tienen, etc.
#### OpenAPI y JSON Schema
-OpenAPI define un schema de API para tu API. Ese schema incluye definiciones (o "schemas") de los datos enviados y recibidos por tu API usando **JSON Schema**, el estándar para los schemas de datos en JSON.
+OpenAPI define un esquema de API para tu API. Y ese esquema incluye definiciones (o "esquemas") de los datos enviados y recibidos por tu API utilizando **JSON Schema**, el estándar para esquemas de datos JSON.
#### Revisa el `openapi.json`
-Si sientes curiosidad por saber cómo se ve el schema de OpenAPI en bruto, FastAPI genera automáticamente un (schema) JSON con la descripción de todo tu API.
+Si tienes curiosidad por cómo se ve el esquema OpenAPI en bruto, FastAPI automáticamente genera un JSON (esquema) con las descripciones de toda tu API.
-Lo puedes ver directamente en: http://127.0.0.1:8000/openapi.json.
+Puedes verlo directamente en: http://127.0.0.1:8000/openapi.json.
-Esto te mostrará un JSON que comienza con algo como:
+Mostrará un JSON que empieza con algo como:
```JSON
{
- "openapi": "3.0.2",
+ "openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
@@ -121,79 +143,45 @@ Esto te mostrará un JSON que comienza con algo como:
...
```
-#### ¿Para qué se usa OpenAPI?
+#### Para qué sirve OpenAPI
-El schema de OpenAPI es lo que alimenta a los dos sistemas de documentación interactiva incluidos.
+El esquema OpenAPI es lo que impulsa los dos sistemas de documentación interactiva incluidos.
-También hay docenas de alternativas, todas basadas en OpenAPI. Podrías añadir fácilmente cualquiera de esas alternativas a tu aplicación construida con **FastAPI**.
+Y hay docenas de alternativas, todas basadas en OpenAPI. Podrías añadir fácilmente cualquiera de esas alternativas a tu aplicación construida con **FastAPI**.
-También podrías usarlo para generar código automáticamente, para los clientes que se comunican con tu API. Por ejemplo, frontend, móvil o aplicaciones de IoT.
+También podrías usarlo para generar código automáticamente, para clientes que se comuniquen con tu API. Por ejemplo, aplicaciones frontend, móviles o IoT.
-## Repaso, paso a paso
+## Recapitulación, paso a paso
### Paso 1: importa `FastAPI`
-```Python hl_lines="1"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
-`FastAPI` es una clase de Python que provee toda la funcionalidad para tu API.
+`FastAPI` es una clase de Python que proporciona toda la funcionalidad para tu API.
/// note | Detalles Técnicos
`FastAPI` es una clase que hereda directamente de `Starlette`.
-También puedes usar toda la funcionalidad de Starlette.
+Puedes usar toda la funcionalidad de Starlette con `FastAPI` también.
///
-### Paso 2: crea un "instance" de `FastAPI`
+### Paso 2: crea una "instance" de `FastAPI`
-```Python hl_lines="3"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
-
-Aquí la variable `app` será un instance de la clase `FastAPI`.
+{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
-Este será el punto de interacción principal para crear todo tu API.
+Aquí la variable `app` será una "instance" de la clase `FastAPI`.
-Esta `app` es la misma a la que nos referimos cuando usamos el comando de `uvicorn`:
+Este será el punto principal de interacción para crear toda tu API.
-
-
-```console
-$ uvicorn main:app --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-Si creas un app como:
-
-```Python hl_lines="3"
-{!../../docs_src/first_steps/tutorial002.py!}
-```
-
-y lo guardas en un archivo `main.py`, entonces ejecutarías `uvicorn` así:
-
-
-
-```console
-$ uvicorn main:my_awesome_api --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-### Paso 3: crea una *operación de path*
+### Paso 3: crea una *path operation*
#### Path
-"Path" aquí se refiere a la última parte de una URL comenzando desde el primer `/`.
+"Path" aquí se refiere a la última parte de la URL empezando desde la primera `/`.
-Entonces, en una URL como:
+Así que, en una URL como:
```
https://example.com/items/foo
@@ -205,19 +193,19 @@ https://example.com/items/foo
/items/foo
```
-/// info | Información
+/// info
-Un "path" también se conoce habitualmente como "endpoint", "route" o "ruta".
+Un "path" también es comúnmente llamado "endpoint" o "ruta".
///
-Cuando construyes una API, el "path" es la manera principal de separar los "intereses" y los "recursos".
+Mientras construyes una API, el "path" es la forma principal de separar "concerns" y "resources".
#### Operación
-"Operación" aquí se refiere a uno de los "métodos" de HTTP.
+"Operación" aquí se refiere a uno de los "métodos" HTTP.
-Uno como:
+Uno de:
* `POST`
* `GET`
@@ -231,45 +219,43 @@ Uno como:
* `PATCH`
* `TRACE`
-En el protocolo de HTTP, te puedes comunicar con cada path usando uno (o más) de estos "métodos".
+En el protocolo HTTP, puedes comunicarte con cada path usando uno (o más) de estos "métodos".
---
-Cuando construyes APIs, normalmente usas uno de estos métodos específicos de HTTP para realizar una acción específica.
+Al construir APIs, normalmente usas estos métodos HTTP específicos para realizar una acción específica.
Normalmente usas:
* `POST`: para crear datos.
* `GET`: para leer datos.
* `PUT`: para actualizar datos.
-* `DELETE`: para borrar datos.
+* `DELETE`: para eliminar datos.
-Así que en OpenAPI, cada uno de estos métodos de HTTP es referido como una "operación".
+Así que, en OpenAPI, cada uno de los métodos HTTP se llama una "operation".
-Nosotros también los llamaremos "**operación**".
+Vamos a llamarlas "**operaciones**" también.
-#### Define un *decorador de operaciones de path*
+#### Define un *path operation decorator*
-```Python hl_lines="6"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
-El `@app.get("/")` le dice a **FastAPI** que la función que tiene justo debajo está a cargo de manejar los requests que van a:
+El `@app.get("/")` le dice a **FastAPI** que la función justo debajo se encarga de manejar requests que vayan a:
* el path `/`
-* usando una operación get
+* usando una get operation
/// info | Información sobre `@decorator`
-Esa sintaxis `@algo` se llama un "decorador" en Python.
+Esa sintaxis `@algo` en Python se llama un "decorador".
-Lo pones encima de una función. Es como un lindo sombrero decorado (creo que de ahí salió el concepto).
+Lo pones encima de una función. Como un bonito sombrero decorativo (supongo que de ahí viene el término).
-Un "decorador" toma la función que tiene debajo y hace algo con ella.
+Un "decorador" toma la función de abajo y hace algo con ella.
-En nuestro caso, este decorador le dice a **FastAPI** que la función que está debajo corresponde al **path** `/` con una **operación** `get`.
+En nuestro caso, este decorador le dice a **FastAPI** que la función de abajo corresponde al **path** `/` con una **operation** `get`.
-Es el "**decorador de operaciones de path**".
+Es el "**path operation decorator**".
///
@@ -279,73 +265,67 @@ También puedes usar las otras operaciones:
* `@app.put()`
* `@app.delete()`
-y las más exóticas:
+Y los más exóticos:
* `@app.options()`
* `@app.head()`
* `@app.patch()`
* `@app.trace()`
-/// tip | Consejo
+/// tip
-Tienes la libertad de usar cada operación (método de HTTP) como quieras.
+Eres libre de usar cada operación (método HTTP) como quieras.
-**FastAPI** no impone ningún significado específico.
+**FastAPI** no fuerza ningún significado específico.
-La información que está presentada aquí es una guía, no un requerimiento.
+La información aquí se presenta como una guía, no un requisito.
-Por ejemplo, cuando usas GraphQL normalmente realizas todas las acciones usando únicamente operaciones `POST`.
+Por ejemplo, cuando usas GraphQL normalmente realizas todas las acciones usando solo operaciones `POST`.
///
-### Paso 4: define la **función de la operación de path**
+### Paso 4: define la **path operation function**
-Esta es nuestra "**función de la operación de path**":
+Esta es nuestra "**path operation function**":
* **path**: es `/`.
-* **operación**: es `get`.
-* **función**: es la función debajo del "decorador" (debajo de `@app.get("/")`).
+* **operation**: es `get`.
+* **function**: es la función debajo del "decorador" (debajo de `@app.get("/")`).
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
-Esto es una función de Python.
+Esta es una función de Python.
-Esta función será llamada por **FastAPI** cada vez que reciba un request en la URL "`/`" usando una operación `GET`.
+Será llamada por **FastAPI** cuando reciba un request en la URL "`/`" usando una operación `GET`.
-En este caso es una función `async`.
+En este caso, es una función `async`.
---
-También podrías definirla como una función estándar en lugar de `async def`:
+También podrías definirla como una función normal en lugar de `async def`:
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial003.py!}
-```
+{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note | Nota
-Si no sabes la diferencia, revisa el [Async: *"¿Tienes prisa?"*](../async.md#tienes-prisa){.internal-link target=_blank}.
+Si no sabes la diferencia, revisa la sección [Async: *"¿Tienes prisa?"*](../async.md#in-a-hurry){.internal-link target=_blank}.
///
-### Paso 5: devuelve el contenido
+### Paso 5: retorna el contenido
-```Python hl_lines="8"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
-Puedes devolver `dict`, `list`, valores singulares como un `str`, `int`, etc.
+Puedes retornar un `dict`, `list`, valores singulares como `str`, `int`, etc.
-También puedes devolver modelos de Pydantic (ya verás más sobre esto más adelante).
+También puedes retornar modelos de Pydantic (verás más sobre eso más adelante).
-Hay muchos objetos y modelos que pueden ser convertidos automáticamente a JSON (incluyendo ORMs, etc.). Intenta usar tus favoritos, es muy probable que ya tengan soporte.
+Hay muchos otros objetos y modelos que serán automáticamente convertidos a JSON (incluyendo ORMs, etc). Intenta usar tus favoritos, es altamente probable que ya sean compatibles.
-## Repaso
+## Recapitulación
* Importa `FastAPI`.
-* Crea un instance de `app`.
-* Escribe un **decorador de operación de path** (como `@app.get("/")`).
-* Escribe una **función de la operación de path** (como `def root(): ...` arriba).
-* Corre el servidor de desarrollo (como `uvicorn main:app --reload`).
+* Crea una instancia `app`.
+* Escribe un **path operation decorator** usando decoradores como `@app.get("/")`.
+* Define una **path operation function**; por ejemplo, `def root(): ...`.
+* Ejecuta el servidor de desarrollo usando el comando `fastapi dev`.
diff --git a/docs/es/docs/tutorial/handling-errors.md b/docs/es/docs/tutorial/handling-errors.md
new file mode 100644
index 000000000..2e4464989
--- /dev/null
+++ b/docs/es/docs/tutorial/handling-errors.md
@@ -0,0 +1,255 @@
+# Manejo de Errores
+
+Existen muchas situaciones en las que necesitas notificar un error a un cliente que está usando tu API.
+
+Este cliente podría ser un navegador con un frontend, un código de otra persona, un dispositivo IoT, etc.
+
+Podrías necesitar decirle al cliente que:
+
+* El cliente no tiene suficientes privilegios para esa operación.
+* El cliente no tiene acceso a ese recurso.
+* El ítem al que el cliente intentaba acceder no existe.
+* etc.
+
+En estos casos, normalmente devolverías un **código de estado HTTP** en el rango de **400** (de 400 a 499).
+
+Esto es similar a los códigos de estado HTTP 200 (de 200 a 299). Esos códigos de estado "200" significan que de alguna manera hubo un "éxito" en el request.
+
+Los códigos de estado en el rango de 400 significan que hubo un error por parte del cliente.
+
+¿Recuerdas todos esos errores de **"404 Not Found"** (y chistes)?
+
+## Usa `HTTPException`
+
+Para devolver responses HTTP con errores al cliente, usa `HTTPException`.
+
+### Importa `HTTPException`
+
+{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
+
+### Lanza un `HTTPException` en tu código
+
+`HTTPException` es una excepción de Python normal con datos adicionales relevantes para APIs.
+
+Debido a que es una excepción de Python, no la `return`, sino que la `raise`.
+
+Esto también significa que si estás dentro de una función de utilidad que estás llamando dentro de tu *path operation function*, y lanzas el `HTTPException` desde dentro de esa función de utilidad, no se ejecutará el resto del código en la *path operation function*, terminará ese request de inmediato y enviará el error HTTP del `HTTPException` al cliente.
+
+El beneficio de lanzar una excepción en lugar de `return`ar un valor será más evidente en la sección sobre Dependencias y Seguridad.
+
+En este ejemplo, cuando el cliente solicita un ítem por un ID que no existe, lanza una excepción con un código de estado de `404`:
+
+{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
+
+### El response resultante
+
+Si el cliente solicita `http://example.com/items/foo` (un `item_id` `"foo"`), ese cliente recibirá un código de estado HTTP de 200, y un response JSON de:
+
+```JSON
+{
+ "item": "The Foo Wrestlers"
+}
+```
+
+Pero si el cliente solicita `http://example.com/items/bar` (un `item_id` inexistente `"bar"`), ese cliente recibirá un código de estado HTTP de 404 (el error "no encontrado"), y un response JSON de:
+
+```JSON
+{
+ "detail": "Item not found"
+}
+```
+
+/// tip | Consejo
+
+Cuando lanzas un `HTTPException`, puedes pasar cualquier valor que pueda convertirse a JSON como el parámetro `detail`, no solo `str`.
+
+Podrías pasar un `dict`, un `list`, etc.
+
+Son manejados automáticamente por **FastAPI** y convertidos a JSON.
+
+///
+
+## Agrega headers personalizados
+
+Existen algunas situaciones en las que es útil poder agregar headers personalizados al error HTTP. Por ejemplo, para algunos tipos de seguridad.
+
+Probablemente no necesitarás usarlos directamente en tu código.
+
+Pero en caso de que los necesites para un escenario avanzado, puedes agregar headers personalizados:
+
+{* ../../docs_src/handling_errors/tutorial002.py hl[14] *}
+
+## Instalar manejadores de excepciones personalizados
+
+Puedes agregar manejadores de excepciones personalizados con las mismas utilidades de excepciones de Starlette.
+
+Supongamos que tienes una excepción personalizada `UnicornException` que tú (o un paquete que usas) podría lanzar.
+
+Y quieres manejar esta excepción globalmente con FastAPI.
+
+Podrías agregar un manejador de excepciones personalizado con `@app.exception_handler()`:
+
+{* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *}
+
+Aquí, si solicitas `/unicorns/yolo`, la *path operation* lanzará un `UnicornException`.
+
+Pero será manejado por el `unicorn_exception_handler`.
+
+Así que recibirás un error limpio, con un código de estado HTTP de `418` y un contenido JSON de:
+
+```JSON
+{"message": "Oops! yolo did something. There goes a rainbow..."}
+```
+
+/// note | Nota Técnica
+
+También podrías usar `from starlette.requests import Request` y `from starlette.responses import JSONResponse`.
+
+**FastAPI** ofrece las mismas `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette. Lo mismo con `Request`.
+
+///
+
+## Sobrescribir los manejadores de excepciones predeterminados
+
+**FastAPI** tiene algunos manejadores de excepciones predeterminados.
+
+Estos manejadores se encargan de devolver los responses JSON predeterminadas cuando lanzas un `HTTPException` y cuando el request tiene datos inválidos.
+
+Puedes sobrescribir estos manejadores de excepciones con los tuyos propios.
+
+### Sobrescribir excepciones de validación de request
+
+Cuando un request contiene datos inválidos, **FastAPI** lanza internamente un `RequestValidationError`.
+
+Y también incluye un manejador de excepciones predeterminado para ello.
+
+Para sobrescribirlo, importa el `RequestValidationError` y úsalo con `@app.exception_handler(RequestValidationError)` para decorar el manejador de excepciones.
+
+El manejador de excepciones recibirá un `Request` y la excepción.
+
+{* ../../docs_src/handling_errors/tutorial004.py hl[2,14:16] *}
+
+Ahora, si vas a `/items/foo`, en lugar de obtener el error JSON por defecto con:
+
+```JSON
+{
+ "detail": [
+ {
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer"
+ }
+ ]
+}
+```
+
+obtendrás una versión en texto, con:
+
+```
+1 validation error
+path -> item_id
+ value is not a valid integer (type=type_error.integer)
+```
+
+#### `RequestValidationError` vs `ValidationError`
+
+/// warning | Advertencia
+
+Estos son detalles técnicos que podrías omitir si no es importante para ti en este momento.
+
+///
+
+`RequestValidationError` es una subclase de `ValidationError` de Pydantic.
+
+**FastAPI** la usa para que, si usas un modelo Pydantic en `response_model`, y tus datos tienen un error, lo verás en tu log.
+
+Pero el cliente/usuario no lo verá. En su lugar, el cliente recibirá un "Error Interno del Servidor" con un código de estado HTTP `500`.
+
+Debería ser así porque si tienes un `ValidationError` de Pydantic en tu *response* o en cualquier lugar de tu código (no en el *request* del cliente), en realidad es un bug en tu código.
+
+Y mientras lo arreglas, tus clientes/usuarios no deberían tener acceso a información interna sobre el error, ya que eso podría exponer una vulnerabilidad de seguridad.
+
+### Sobrescribir el manejador de errores de `HTTPException`
+
+De la misma manera, puedes sobrescribir el manejador de `HTTPException`.
+
+Por ejemplo, podrías querer devolver un response de texto plano en lugar de JSON para estos errores:
+
+{* ../../docs_src/handling_errors/tutorial004.py hl[3:4,9:11,22] *}
+
+/// note | Nota Técnica
+
+También podrías usar `from starlette.responses import PlainTextResponse`.
+
+**FastAPI** ofrece las mismas `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.
+
+///
+
+### Usar el body de `RequestValidationError`
+
+El `RequestValidationError` contiene el `body` que recibió con datos inválidos.
+
+Podrías usarlo mientras desarrollas tu aplicación para registrar el body y depurarlo, devolverlo al usuario, etc.
+
+{* ../../docs_src/handling_errors/tutorial005.py hl[14] *}
+
+Ahora intenta enviar un ítem inválido como:
+
+```JSON
+{
+ "title": "towel",
+ "size": "XL"
+}
+```
+
+Recibirás un response que te dirá que los datos son inválidos conteniendo el body recibido:
+
+```JSON hl_lines="12-15"
+{
+ "detail": [
+ {
+ "loc": [
+ "body",
+ "size"
+ ],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer"
+ }
+ ],
+ "body": {
+ "title": "towel",
+ "size": "XL"
+ }
+}
+```
+
+#### `HTTPException` de FastAPI vs `HTTPException` de Starlette
+
+**FastAPI** tiene su propio `HTTPException`.
+
+Y la clase de error `HTTPException` de **FastAPI** hereda de la clase de error `HTTPException` de Starlette.
+
+La única diferencia es que el `HTTPException` de **FastAPI** acepta cualquier dato JSON-able para el campo `detail`, mientras que el `HTTPException` de Starlette solo acepta strings para ello.
+
+Así que puedes seguir lanzando un `HTTPException` de **FastAPI** como de costumbre en tu código.
+
+Pero cuando registras un manejador de excepciones, deberías registrarlo para el `HTTPException` de Starlette.
+
+De esta manera, si alguna parte del código interno de Starlette, o una extensión o complemento de Starlette, lanza un `HTTPException` de Starlette, tu manejador podrá capturarlo y manejarlo.
+
+En este ejemplo, para poder tener ambos `HTTPException` en el mismo código, las excepciones de Starlette son renombradas a `StarletteHTTPException`:
+
+```Python
+from starlette.exceptions import HTTPException as StarletteHTTPException
+```
+
+### Reutilizar los manejadores de excepciones de **FastAPI**
+
+Si quieres usar la excepción junto con los mismos manejadores de excepciones predeterminados de **FastAPI**, puedes importar y reutilizar los manejadores de excepciones predeterminados de `fastapi.exception_handlers`:
+
+{* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *}
+
+En este ejemplo solo estás `print`eando el error con un mensaje muy expresivo, pero te haces una idea. Puedes usar la excepción y luego simplemente reutilizar los manejadores de excepciones predeterminados.
diff --git a/docs/es/docs/tutorial/header-param-models.md b/docs/es/docs/tutorial/header-param-models.md
new file mode 100644
index 000000000..3676231e6
--- /dev/null
+++ b/docs/es/docs/tutorial/header-param-models.md
@@ -0,0 +1,56 @@
+# Modelos de Parámetros de Header
+
+Si tienes un grupo de **parámetros de header** relacionados, puedes crear un **modelo Pydantic** para declararlos.
+
+Esto te permitirá **reutilizar el modelo** en **múltiples lugares** y también declarar validaciones y metadatos para todos los parámetros al mismo tiempo. 😎
+
+/// note | Nota
+
+Esto es compatible desde la versión `0.115.0` de FastAPI. 🤓
+
+///
+
+## Parámetros de Header con un Modelo Pydantic
+
+Declara los **parámetros de header** que necesitas en un **modelo Pydantic**, y luego declara el parámetro como `Header`:
+
+{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
+
+**FastAPI** **extraerá** los datos para **cada campo** de los **headers** en el request y te dará el modelo Pydantic que definiste.
+
+## Revisa la Documentación
+
+Puedes ver los headers requeridos en la interfaz de documentación en `/docs`:
+
+
+
+
+
+## Prohibir Headers Extra
+
+En algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** los headers que deseas recibir.
+
+Puedes usar la configuración del modelo de Pydantic para `prohibir` cualquier campo `extra`:
+
+{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}
+
+Si un cliente intenta enviar algunos **headers extra**, recibirán un response de **error**.
+
+Por ejemplo, si el cliente intenta enviar un header `tool` con un valor de `plumbus`, recibirán un response de **error** indicando que el parámetro de header `tool` no está permitido:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["header", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus",
+ }
+ ]
+}
+```
+
+## Resumen
+
+Puedes usar **modelos Pydantic** para declarar **headers** en **FastAPI**. 😎
diff --git a/docs/es/docs/tutorial/header-params.md b/docs/es/docs/tutorial/header-params.md
new file mode 100644
index 000000000..9c0112bb2
--- /dev/null
+++ b/docs/es/docs/tutorial/header-params.md
@@ -0,0 +1,91 @@
+# Parámetros de Header
+
+Puedes definir los parámetros de Header de la misma manera que defines los parámetros de `Query`, `Path` y `Cookie`.
+
+## Importar `Header`
+
+Primero importa `Header`:
+
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
+
+## Declarar parámetros de `Header`
+
+Luego declara los parámetros de header usando la misma estructura que con `Path`, `Query` y `Cookie`.
+
+Puedes definir el valor por defecto así como toda la validación extra o los parámetros de anotaciones:
+
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
+
+/// note | Detalles Técnicos
+
+`Header` es una clase "hermana" de `Path`, `Query` y `Cookie`. También hereda de la misma clase común `Param`.
+
+Pero recuerda que cuando importas `Query`, `Path`, `Header`, y otros de `fastapi`, en realidad son funciones que retornan clases especiales.
+
+///
+
+/// info | Información
+
+Para declarar headers, necesitas usar `Header`, porque de otra forma los parámetros serían interpretados como parámetros de query.
+
+///
+
+## Conversión automática
+
+`Header` tiene un poquito de funcionalidad extra además de lo que proporcionan `Path`, `Query` y `Cookie`.
+
+La mayoría de los headers estándar están separados por un carácter "guion", también conocido como el "símbolo menos" (`-`).
+
+Pero una variable como `user-agent` es inválida en Python.
+
+Así que, por defecto, `Header` convertirá los caracteres de los nombres de los parámetros de guion bajo (`_`) a guion (`-`) para extraer y documentar los headers.
+
+Además, los headers HTTP no diferencian entre mayúsculas y minúsculas, por lo que los puedes declarar con el estilo estándar de Python (también conocido como "snake_case").
+
+Así que, puedes usar `user_agent` como normalmente lo harías en código Python, en lugar de necesitar capitalizar las primeras letras como `User_Agent` o algo similar.
+
+Si por alguna razón necesitas desactivar la conversión automática de guiones bajos a guiones, establece el parámetro `convert_underscores` de `Header` a `False`:
+
+{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
+
+/// warning | Advertencia
+
+Antes de establecer `convert_underscores` a `False`, ten en cuenta que algunos proxies y servidores HTTP no permiten el uso de headers con guiones bajos.
+
+///
+
+## Headers duplicados
+
+Es posible recibir headers duplicados. Eso significa, el mismo header con múltiples valores.
+
+Puedes definir esos casos usando una lista en la declaración del tipo.
+
+Recibirás todos los valores del header duplicado como una `list` de Python.
+
+Por ejemplo, para declarar un header de `X-Token` que puede aparecer más de una vez, puedes escribir:
+
+{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
+
+Si te comunicas con esa *path operation* enviando dos headers HTTP como:
+
+```
+X-Token: foo
+X-Token: bar
+```
+
+El response sería como:
+
+```JSON
+{
+ "X-Token values": [
+ "bar",
+ "foo"
+ ]
+}
+```
+
+## Recapitulación
+
+Declara headers con `Header`, usando el mismo patrón común que `Query`, `Path` y `Cookie`.
+
+Y no te preocupes por los guiones bajos en tus variables, **FastAPI** se encargará de convertirlos.
diff --git a/docs/es/docs/tutorial/index.md b/docs/es/docs/tutorial/index.md
index fa13450f0..dcfc6cdfb 100644
--- a/docs/es/docs/tutorial/index.md
+++ b/docs/es/docs/tutorial/index.md
@@ -1,81 +1,102 @@
-# Tutorial - Guía de Usuario
+# Tutorial - Guía del Usuario
-Este tutorial te muestra cómo usar **FastAPI** con la mayoría de sus características paso a paso.
+Este tutorial te muestra cómo usar **FastAPI** con la mayoría de sus funcionalidades, paso a paso.
-Cada sección se basa gradualmente en las anteriores, pero está estructurada en temas separados, así puedes ir directamente a cualquier tema en concreto para resolver tus necesidades específicas sobre la API.
+Cada sección se basa gradualmente en las anteriores, pero está estructurada para separar temas, de manera que puedas ir directamente a cualquier sección específica para resolver tus necesidades específicas de API.
-Funciona también como una referencia futura, para que puedas volver y ver exactamente lo que necesitas.
+También está diseñado para funcionar como una referencia futura para que puedas volver y ver exactamente lo que necesitas.
## Ejecuta el código
-Todos los bloques de código se pueden copiar y usar directamente (en realidad son archivos Python probados).
+Todos los bloques de código pueden ser copiados y usados directamente (de hecho, son archivos Python probados).
-Para ejecutar cualquiera de los ejemplos, copia el código en un archivo llamado `main.py`, y ejecuta `uvicorn` de la siguiente manera en tu terminal:
+Para ejecutar cualquiera de los ejemplos, copia el código a un archivo `main.py`, y comienza `fastapi dev` con:
```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 dev main.py
+INFO Using path main.py
+INFO Resolved absolute path /home/user/code/awesomeapp/main.py
+INFO Searching for package file structure from directories with __init__.py files
+INFO Importing from /home/user/code/awesomeapp
+
+ ╭─ Python module file ─╮
+ │ │
+ │ 🐍 main.py │
+ │ │
+ ╰──────────────────────╯
+
+INFO Importing module main
+INFO Found importable FastAPI app
+
+ ╭─ Importable FastAPI app ─╮
+ │ │
+ │ from main import app │
+ │ │
+ ╰──────────────────────────╯
+
+INFO Using import string main:app
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [2265862] using WatchFiles
+INFO: Started server process [2265873]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+
```
-Se **RECOMIENDA** que escribas o copies el código, lo edites y lo ejecutes localmente.
+Es **ALTAMENTE recomendable** que escribas o copies el código, lo edites y lo ejecutes localmente.
-Usarlo en tu editor de código es lo que realmente te muestra los beneficios de FastAPI, al ver la poca cantidad de código que tienes que escribir, todas las verificaciones de tipo, auto-completado, etc.
+Usarlo en tu editor es lo que realmente te muestra los beneficios de FastAPI, al ver cuán poco código tienes que escribir, todos los chequeos de tipos, autocompletado, etc.
---
-## Instala FastAPI
+## Instalar FastAPI
El primer paso es instalar FastAPI.
-Para el tutorial, es posible que quieras instalarlo con todas las dependencias y características opcionales:
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo, y luego **instala FastAPI**:
-...eso también incluye `uvicorn` que puedes usar como el servidor que ejecuta tu código.
-
/// note | Nota
-También puedes instalarlo parte por parte.
-
-Esto es lo que probablemente harías una vez que desees implementar tu aplicación en producción:
-
-```
-pip install fastapi
-```
-
-También debes instalar `uvicorn` para que funcione como tu servidor:
-
-```
-pip install "uvicorn[standard]"
-```
+Cuando instalas con `pip install "fastapi[standard]"` viene con algunas dependencias opcionales estándar por defecto.
-Y lo mismo para cada una de las dependencias opcionales que quieras utilizar.
+Si no quieres tener esas dependencias opcionales, en su lugar puedes instalar `pip install fastapi`.
///
-## Guía Avanzada de Usuario
+## Guía Avanzada del Usuario
-También hay una **Guía Avanzada de Usuario** que puedes leer luego de este **Tutorial - Guía de Usuario**.
+También hay una **Guía Avanzada del Usuario** que puedes leer después de esta **Tutorial - Guía del Usuario**.
-La **Guía Avanzada de Usuario**, se basa en este tutorial, utiliza los mismos conceptos y enseña algunas características adicionales.
+La **Guía Avanzada del Usuario** se basa en esta, utiliza los mismos conceptos y te enseña algunas funcionalidades adicionales.
-Pero primero deberías leer el **Tutorial - Guía de Usuario** (lo que estas leyendo ahora mismo).
+Pero primero deberías leer la **Tutorial - Guía del Usuario** (lo que estás leyendo ahora mismo).
-La guía esa diseñada para que puedas crear una aplicación completa con solo el **Tutorial - Guía de Usuario**, y luego extenderlo de diferentes maneras, según tus necesidades, utilizando algunas de las ideas adicionales de la **Guía Avanzada de Usuario**.
+Está diseñada para que puedas construir una aplicación completa solo con la **Tutorial - Guía del Usuario**, y luego extenderla de diferentes maneras, dependiendo de tus necesidades, utilizando algunas de las ideas adicionales de la **Guía Avanzada del Usuario**.
diff --git a/docs/es/docs/tutorial/metadata.md b/docs/es/docs/tutorial/metadata.md
new file mode 100644
index 000000000..1561e4ae3
--- /dev/null
+++ b/docs/es/docs/tutorial/metadata.md
@@ -0,0 +1,120 @@
+# Metadata y URLs de Docs
+
+Puedes personalizar varias configuraciones de metadata en tu aplicación **FastAPI**.
+
+## Metadata para la API
+
+Puedes establecer los siguientes campos que se usan en la especificación OpenAPI y en las interfaces automáticas de documentación de la API:
+
+| Parámetro | Tipo | Descripción |
+|------------|------|-------------|
+| `title` | `str` | El título de la API. |
+| `summary` | `str` | Un resumen corto de la API. Disponible desde OpenAPI 3.1.0, FastAPI 0.99.0. |
+| `description` | `str` | Una breve descripción de la API. Puede usar Markdown. |
+| `version` | `string` | La versión de la API. Esta es la versión de tu propia aplicación, no de OpenAPI. Por ejemplo, `2.5.0`. |
+| `terms_of_service` | `str` | Una URL a los Términos de Servicio para la API. Si se proporciona, debe ser una URL. |
+| `contact` | `dict` | La información de contacto para la API expuesta. Puede contener varios campos. contact fields
Parámetro
Tipo
Descripción
name
str
El nombre identificativo de la persona/organización de contacto.
url
str
La URL que apunta a la información de contacto. DEBE tener el formato de una URL.
email
str
La dirección de correo electrónico de la persona/organización de contacto. DEBE tener el formato de una dirección de correo.
|
+| `license_info` | `dict` | La información de la licencia para la API expuesta. Puede contener varios campos. license_info fields
Parámetro
Tipo
Descripción
name
str
REQUERIDO (si se establece un license_info). El nombre de la licencia utilizada para la API.
identifier
str
Una expresión de licencia SPDX para la API. El campo identifier es mutuamente excluyente del campo url. Disponible desde OpenAPI 3.1.0, FastAPI 0.99.0.
url
str
Una URL a la licencia utilizada para la API. DEBE tener el formato de una URL.
|
+
+Puedes configurarlos de la siguiente manera:
+
+{* ../../docs_src/metadata/tutorial001.py hl[3:16, 19:32] *}
+
+/// tip | Consejo
+
+Puedes escribir Markdown en el campo `description` y se mostrará en el resultado.
+
+///
+
+Con esta configuración, la documentación automática de la API se vería así:
+
+
+
+## Identificador de licencia
+
+Desde OpenAPI 3.1.0 y FastAPI 0.99.0, también puedes establecer la `license_info` con un `identifier` en lugar de una `url`.
+
+Por ejemplo:
+
+{* ../../docs_src/metadata/tutorial001_1.py hl[31] *}
+
+## Metadata para etiquetas
+
+También puedes agregar metadata adicional para las diferentes etiquetas usadas para agrupar tus path operations con el parámetro `openapi_tags`.
+
+Este toma una list que contiene un diccionario para cada etiqueta.
+
+Cada diccionario puede contener:
+
+* `name` (**requerido**): un `str` con el mismo nombre de etiqueta que usas en el parámetro `tags` en tus *path operations* y `APIRouter`s.
+* `description`: un `str` con una breve descripción de la etiqueta. Puede tener Markdown y se mostrará en la interfaz de documentación.
+* `externalDocs`: un `dict` que describe documentación externa con:
+ * `description`: un `str` con una breve descripción para la documentación externa.
+ * `url` (**requerido**): un `str` con la URL para la documentación externa.
+
+### Crear metadata para etiquetas
+
+Probemos eso en un ejemplo con etiquetas para `users` y `items`.
+
+Crea metadata para tus etiquetas y pásala al parámetro `openapi_tags`:
+
+{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *}
+
+Nota que puedes utilizar Markdown dentro de las descripciones, por ejemplo "login" se mostrará en negrita (**login**) y "fancy" se mostrará en cursiva (_fancy_).
+
+/// tip | Consejo
+
+No tienes que agregar metadata para todas las etiquetas que uses.
+
+///
+
+### Usar tus etiquetas
+
+Usa el parámetro `tags` con tus *path operations* (y `APIRouter`s) para asignarlas a diferentes etiquetas:
+
+{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
+
+/// info | Información
+
+Lee más sobre etiquetas en [Configuración de Path Operation](path-operation-configuration.md#tags){.internal-link target=_blank}.
+
+///
+
+### Revisa la documentación
+
+Ahora, si revisas la documentación, mostrará toda la metadata adicional:
+
+
+
+### Orden de las etiquetas
+
+El orden de cada diccionario de metadata de etiqueta también define el orden mostrado en la interfaz de documentación.
+
+Por ejemplo, aunque `users` iría después de `items` en orden alfabético, se muestra antes porque agregamos su metadata como el primer diccionario en la list.
+
+## URL de OpenAPI
+
+Por defecto, el esquema OpenAPI se sirve en `/openapi.json`.
+
+Pero puedes configurarlo con el parámetro `openapi_url`.
+
+Por ejemplo, para configurarlo para que se sirva en `/api/v1/openapi.json`:
+
+{* ../../docs_src/metadata/tutorial002.py hl[3] *}
+
+Si quieres deshabilitar el esquema OpenAPI completamente, puedes establecer `openapi_url=None`, eso también deshabilitará las interfaces de usuario de documentación que lo usan.
+
+## URLs de Docs
+
+Puedes configurar las dos interfaces de usuario de documentación incluidas:
+
+* **Swagger UI**: servida en `/docs`.
+ * Puedes establecer su URL con el parámetro `docs_url`.
+ * Puedes deshabilitarla estableciendo `docs_url=None`.
+* **ReDoc**: servida en `/redoc`.
+ * Puedes establecer su URL con el parámetro `redoc_url`.
+ * Puedes deshabilitarla estableciendo `redoc_url=None`.
+
+Por ejemplo, para configurar Swagger UI para que se sirva en `/documentation` y deshabilitar ReDoc:
+
+{* ../../docs_src/metadata/tutorial003.py hl[3] *}
diff --git a/docs/es/docs/tutorial/middleware.md b/docs/es/docs/tutorial/middleware.md
new file mode 100644
index 000000000..296374525
--- /dev/null
+++ b/docs/es/docs/tutorial/middleware.md
@@ -0,0 +1,72 @@
+# Middleware
+
+Puedes añadir middleware a las aplicaciones de **FastAPI**.
+
+Un "middleware" es una función que trabaja con cada **request** antes de que sea procesada por cualquier *path operation* específica. Y también con cada **response** antes de devolverla.
+
+* Toma cada **request** que llega a tu aplicación.
+* Puede entonces hacer algo a esa **request** o ejecutar cualquier código necesario.
+* Luego pasa la **request** para que sea procesada por el resto de la aplicación (por alguna *path operation*).
+* Después toma la **response** generada por la aplicación (por alguna *path operation*).
+* Puede hacer algo a esa **response** o ejecutar cualquier código necesario.
+* Luego devuelve la **response**.
+
+/// note | Detalles Técnicos
+
+Si tienes dependencias con `yield`, el código de salida se ejecutará *después* del middleware.
+
+Si hubiera alguna tarea en segundo plano (documentada más adelante), se ejecutará *después* de todo el middleware.
+
+///
+
+## Crear un middleware
+
+Para crear un middleware usas el decorador `@app.middleware("http")` encima de una función.
+
+La función middleware recibe:
+
+* La `request`.
+* Una función `call_next` que recibirá la `request` como parámetro.
+ * Esta función pasará la `request` a la correspondiente *path operation*.
+ * Luego devuelve la `response` generada por la correspondiente *path operation*.
+* Puedes entonces modificar aún más la `response` antes de devolverla.
+
+{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
+
+/// tip | Consejo
+
+Ten en cuenta que los custom proprietary headers se pueden añadir usando el prefijo 'X-'.
+
+Pero si tienes custom headers que deseas que un cliente en un navegador pueda ver, necesitas añadirlos a tus configuraciones de CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}) usando el parámetro `expose_headers` documentado en la documentación de CORS de Starlette.
+
+///
+
+/// note | Detalles Técnicos
+
+También podrías usar `from starlette.requests import Request`.
+
+**FastAPI** lo proporciona como una conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.
+
+///
+
+### Antes y después de la `response`
+
+Puedes añadir código que se ejecute con la `request`, antes de que cualquier *path operation* la reciba.
+
+Y también después de que se genere la `response`, antes de devolverla.
+
+Por ejemplo, podrías añadir un custom header `X-Process-Time` que contenga el tiempo en segundos que tomó procesar la request y generar una response:
+
+{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
+
+/// tip | Consejo
+
+Aquí usamos `time.perf_counter()` en lugar de `time.time()` porque puede ser más preciso para estos casos de uso. 🤓
+
+///
+
+## Otros middlewares
+
+Más adelante puedes leer sobre otros middlewares en la [Guía del Usuario Avanzado: Middleware Avanzado](../advanced/middleware.md){.internal-link target=_blank}.
+
+Leerás sobre cómo manejar CORS con un middleware en la siguiente sección.
diff --git a/docs/es/docs/tutorial/path-operation-configuration.md b/docs/es/docs/tutorial/path-operation-configuration.md
new file mode 100644
index 000000000..909cd69b9
--- /dev/null
+++ b/docs/es/docs/tutorial/path-operation-configuration.md
@@ -0,0 +1,107 @@
+# Configuración de Path Operation
+
+Hay varios parámetros que puedes pasar a tu *path operation decorator* para configurarlo.
+
+/// warning | Advertencia
+
+Ten en cuenta que estos parámetros se pasan directamente al *path operation decorator*, no a tu *path operation function*.
+
+///
+
+## Código de Estado del Response
+
+Puedes definir el `status_code` (HTTP) que se utilizará en el response de tu *path operation*.
+
+Puedes pasar directamente el código `int`, como `404`.
+
+Pero si no recuerdas para qué es cada código numérico, puedes usar las constantes atajo en `status`:
+
+{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
+
+Ese código de estado se usará en el response y se añadirá al esquema de OpenAPI.
+
+/// note | Detalles Técnicos
+
+También podrías usar `from starlette import status`.
+
+**FastAPI** ofrece el mismo `starlette.status` como `fastapi.status` solo por conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.
+
+///
+
+## Tags
+
+Puedes añadir tags a tu *path operation*, pasando el parámetro `tags` con un `list` de `str` (comúnmente solo una `str`):
+
+{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
+
+Serán añadidas al esquema de OpenAPI y usadas por las interfaces de documentación automática:
+
+
+
+### Tags con Enums
+
+Si tienes una gran aplicación, podrías terminar acumulando **varias tags**, y querrías asegurarte de que siempre uses la **misma tag** para *path operations* relacionadas.
+
+En estos casos, podría tener sentido almacenar las tags en un `Enum`.
+
+**FastAPI** soporta eso de la misma manera que con strings normales:
+
+{* ../../docs_src/path_operation_configuration/tutorial002b.py hl[1,8:10,13,18] *}
+
+## Resumen y Descripción
+
+Puedes añadir un `summary` y `description`:
+
+{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
+
+## Descripción desde docstring
+
+Como las descripciones tienden a ser largas y cubrir múltiples líneas, puedes declarar la descripción de la *path operation* en la docstring de la función y **FastAPI** la leerá desde allí.
+
+Puedes escribir Markdown en el docstring, se interpretará y mostrará correctamente (teniendo en cuenta la indentación del docstring).
+
+{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
+
+Será usado en la documentación interactiva:
+
+
+
+## Descripción del Response
+
+Puedes especificar la descripción del response con el parámetro `response_description`:
+
+{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
+
+/// info | Información
+
+Ten en cuenta que `response_description` se refiere específicamente al response, mientras que `description` se refiere a la *path operation* en general.
+
+///
+
+/// check | Revisa
+
+OpenAPI especifica que cada *path operation* requiere una descripción de response.
+
+Entonces, si no proporcionas una, **FastAPI** generará automáticamente una de "Response exitoso".
+
+///
+
+
+
+## Deprecar una *path operation*
+
+Si necesitas marcar una *path operation* como deprecated, pero sin eliminarla, pasa el parámetro `deprecated`:
+
+{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *}
+
+Se marcará claramente como deprecado en la documentación interactiva:
+
+
+
+Revisa cómo lucen las *path operations* deprecadas y no deprecadas:
+
+
+
+## Resumen
+
+Puedes configurar y añadir metadatos a tus *path operations* fácilmente pasando parámetros a los *path operation decorators*.
diff --git a/docs/es/docs/tutorial/path-params-numeric-validations.md b/docs/es/docs/tutorial/path-params-numeric-validations.md
new file mode 100644
index 000000000..44d73b5ed
--- /dev/null
+++ b/docs/es/docs/tutorial/path-params-numeric-validations.md
@@ -0,0 +1,164 @@
+# Parámetros de Path y Validaciones Numéricas
+
+De la misma manera que puedes declarar más validaciones y metadatos para los parámetros de query con `Query`, puedes declarar el mismo tipo de validaciones y metadatos para los parámetros de path con `Path`.
+
+## Importar Path
+
+Primero, importa `Path` de `fastapi`, e importa `Annotated`:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
+
+/// info | Información
+
+FastAPI agregó soporte para `Annotated` (y comenzó a recomendar su uso) en la versión 0.95.0.
+
+Si tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.
+
+Asegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} a al menos la 0.95.1 antes de usar `Annotated`.
+
+///
+
+## Declarar metadatos
+
+Puedes declarar todos los mismos parámetros que para `Query`.
+
+Por ejemplo, para declarar un valor de metadato `title` para el parámetro de path `item_id` puedes escribir:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
+
+/// note | Nota
+
+Un parámetro de path siempre es requerido ya que tiene que formar parte del path. Incluso si lo declaras con `None` o le asignas un valor por defecto, no afectará en nada, siempre será requerido.
+
+///
+
+## Ordena los parámetros como necesites
+
+/// tip | Consejo
+
+Esto probablemente no es tan importante o necesario si usas `Annotated`.
+
+///
+
+Supongamos que quieres declarar el parámetro de query `q` como un `str` requerido.
+
+Y no necesitas declarar nada más para ese parámetro, así que realmente no necesitas usar `Query`.
+
+Pero aún necesitas usar `Path` para el parámetro de path `item_id`. Y no quieres usar `Annotated` por alguna razón.
+
+Python se quejará si pones un valor con un "default" antes de un valor que no tenga un "default".
+
+Pero puedes reordenarlos y poner el valor sin un default (el parámetro de query `q`) primero.
+
+No importa para **FastAPI**. Detectará los parámetros por sus nombres, tipos y declaraciones por defecto (`Query`, `Path`, etc.), no le importa el orden.
+
+Así que puedes declarar tu función como:
+
+//// tab | Python 3.8 non-Annotated
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
+
+////
+
+Pero ten en cuenta que si usas `Annotated`, no tendrás este problema, no importará ya que no estás usando los valores por defecto de los parámetros de la función para `Query()` o `Path()`.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+
+## Ordena los parámetros como necesites, trucos
+
+/// tip | Consejo
+
+Esto probablemente no es tan importante o necesario si usas `Annotated`.
+
+///
+
+Aquí hay un **pequeño truco** que puede ser útil, pero no lo necesitarás a menudo.
+
+Si quieres:
+
+* declarar el parámetro de query `q` sin un `Query` ni ningún valor por defecto
+* declarar el parámetro de path `item_id` usando `Path`
+* tenerlos en un orden diferente
+* no usar `Annotated`
+
+...Python tiene una sintaxis especial para eso.
+
+Pasa `*`, como el primer parámetro de la función.
+
+Python no hará nada con ese `*`, pero sabrá que todos los parámetros siguientes deben ser llamados como argumentos de palabras clave (parejas key-value), también conocidos como kwargs. Incluso si no tienen un valor por defecto.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
+
+### Mejor con `Annotated`
+
+Ten en cuenta que si usas `Annotated`, como no estás usando valores por defecto de los parámetros de la función, no tendrás este problema y probablemente no necesitarás usar `*`.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
+
+## Validaciones numéricas: mayor o igual
+
+Con `Query` y `Path` (y otros que verás más adelante) puedes declarar restricciones numéricas.
+
+Aquí, con `ge=1`, `item_id` necesitará ser un número entero "`g`reater than or `e`qual" a `1`.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
+
+## Validaciones numéricas: mayor que y menor o igual
+
+Lo mismo aplica para:
+
+* `gt`: `g`reater `t`han
+* `le`: `l`ess than or `e`qual
+
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
+
+## Validaciones numéricas: flotantes, mayor y menor
+
+Las validaciones numéricas también funcionan para valores `float`.
+
+Aquí es donde se convierte en importante poder declarar gt y no solo ge. Ya que con esto puedes requerir, por ejemplo, que un valor sea mayor que `0`, incluso si es menor que `1`.
+
+Así, `0.5` sería un valor válido. Pero `0.0` o `0` no lo serían.
+
+Y lo mismo para lt.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
+
+## Resumen
+
+Con `Query`, `Path` (y otros que aún no has visto) puedes declarar metadatos y validaciones de string de las mismas maneras que con [Parámetros de Query y Validaciones de String](query-params-str-validations.md){.internal-link target=_blank}.
+
+Y también puedes declarar validaciones numéricas:
+
+* `gt`: `g`reater `t`han
+* `ge`: `g`reater than or `e`qual
+* `lt`: `l`ess `t`han
+* `le`: `l`ess than or `e`qual
+
+/// info | Información
+
+`Query`, `Path` y otras clases que verás más adelante son subclases de una clase común `Param`.
+
+Todas ellas comparten los mismos parámetros para validación adicional y metadatos que has visto.
+
+///
+
+/// note | Nota técnica
+
+Cuando importas `Query`, `Path` y otros de `fastapi`, en realidad son funciones.
+
+Que cuando se llaman, retornan instances de clases con el mismo nombre.
+
+Así que importas `Query`, que es una función. Y cuando la llamas, retorna una instance de una clase también llamada `Query`.
+
+Estas funciones están allí (en lugar de usar simplemente las clases directamente) para que tu editor no marque errores sobre sus tipos.
+
+De esa forma puedes usar tu editor y herramientas de programación normales sin tener que agregar configuraciones personalizadas para omitir esos errores.
+
+///
diff --git a/docs/es/docs/tutorial/path-params.md b/docs/es/docs/tutorial/path-params.md
index 167c88659..12a1b647b 100644
--- a/docs/es/docs/tutorial/path-params.md
+++ b/docs/es/docs/tutorial/path-params.md
@@ -1,14 +1,12 @@
-# Parámetros de path
+# Parámetros de Path
-Puedes declarar los "parámetros" o "variables" con la misma sintaxis que usan los format strings de Python:
+Puedes declarar "parámetros" o "variables" de path con la misma sintaxis que se usa en los format strings de Python:
-```Python hl_lines="6-7"
-{!../../docs_src/path_params/tutorial001.py!}
-```
+{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
-El valor del parámetro de path `item_id` será pasado a tu función como el argumento `item_id`.
+El valor del parámetro de path `item_id` se pasará a tu función como el argumento `item_id`.
-Entonces, si corres este ejemplo y vas a http://127.0.0.1:8000/items/foo, verás una respuesta de:
+Así que, si ejecutas este ejemplo y vas a http://127.0.0.1:8000/items/foo, verás un response de:
```JSON
{"item_id":"foo"}
@@ -16,23 +14,21 @@ Entonces, si corres este ejemplo y vas a Conversión de datos
+## Conversión de datos
-Si corres este ejemplo y abres tu navegador en http://127.0.0.1:8000/items/3 verás una respuesta de:
+Si ejecutas este ejemplo y abres tu navegador en http://127.0.0.1:8000/items/3, verás un response de:
```JSON
{"item_id":3}
@@ -40,172 +36,168 @@ Si corres este ejemplo y abres tu navegador en "parsing" automático del request.
+Entonces, con esa declaración de tipo, **FastAPI** te ofrece "parsing" automático de requests.
///
## Validación de datos
-Pero si abres tu navegador en http://127.0.0.1:8000/items/foo verás este lindo error de HTTP:
+Pero si vas al navegador en http://127.0.0.1:8000/items/foo, verás un bonito error HTTP de:
```JSON
{
- "detail": [
- {
- "loc": [
- "path",
- "item_id"
- ],
- "msg": "value is not a valid integer",
- "type": "type_error.integer"
- }
- ]
+ "detail": [
+ {
+ "type": "int_parsing",
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "Input should be a valid integer, unable to parse string as an integer",
+ "input": "foo",
+ "url": "https://errors.pydantic.dev/2.1/v/int_parsing"
+ }
+ ]
}
```
-debido a que el parámetro de path `item_id` tenía el valor `"foo"`, que no es un `int`.
+porque el parámetro de path `item_id` tenía un valor de `"foo"`, que no es un `int`.
-El mismo error aparecería si pasaras un `float` en vez de un `int` como en: http://127.0.0.1:8000/items/4.2
+El mismo error aparecería si proporcionaras un `float` en lugar de un `int`, como en: http://127.0.0.1:8000/items/4.2
/// check | Revisa
-Así, con la misma declaración de tipo de Python, **FastAPI** te da validación de datos.
+Entonces, con la misma declaración de tipo de Python, **FastAPI** te ofrece validación de datos.
-Observa que el error también muestra claramente el punto exacto en el que no pasó la validación.
+Nota que el error también indica claramente el punto exacto donde la validación falló.
-Esto es increíblemente útil cuando estás desarrollando y debugging código que interactúa con tu API.
+Esto es increíblemente útil mientras desarrollas y depuras código que interactúa con tu API.
///
## Documentación
-Cuando abras tu navegador en http://127.0.0.1:8000/docs verás la documentación automática e interactiva del API como:
+Y cuando abras tu navegador en http://127.0.0.1:8000/docs, verás una documentación de API automática e interactiva como:
/// check | Revisa
-Nuevamente, con la misma declaración de tipo de Python, **FastAPI** te da documentación automática e interactiva (integrándose con Swagger UI)
+Nuevamente, solo con esa misma declaración de tipo de Python, **FastAPI** te ofrece documentación automática e interactiva (integrando Swagger UI).
-Observa que el parámetro de path está declarado como un integer.
+Nota que el parámetro de path está declarado como un entero.
///
## Beneficios basados en estándares, documentación alternativa
-Debido a que el schema generado es del estándar OpenAPI hay muchas herramientas compatibles.
+Y porque el esquema generado es del estándar OpenAPI, hay muchas herramientas compatibles.
-Es por esto que **FastAPI** mismo provee una documentación alternativa de la API (usando ReDoc), a la que puedes acceder en http://127.0.0.1:8000/redoc:
+Debido a esto, el propio **FastAPI** proporciona una documentación de API alternativa (usando ReDoc), a la cual puedes acceder en http://127.0.0.1:8000/redoc:
-De la misma manera hay muchas herramientas compatibles. Incluyendo herramientas de generación de código para muchos lenguajes.
+De la misma manera, hay muchas herramientas compatibles. Incluyendo herramientas de generación de código para muchos lenguajes.
## Pydantic
-Toda la validación de datos es realizada tras bastidores por Pydantic, así que obtienes todos sus beneficios. Así sabes que estás en buenas manos.
+Toda la validación de datos se realiza internamente con Pydantic, así que obtienes todos los beneficios de esta. Y sabes que estás en buenas manos.
-Puedes usar las mismas declaraciones de tipos con `str`, `float`, `bool` y otros tipos de datos más complejos.
+Puedes usar las mismas declaraciones de tipo con `str`, `float`, `bool` y muchos otros tipos de datos complejos.
-Exploraremos varios de estos tipos en los próximos capítulos del tutorial.
+Varios de estos se exploran en los siguientes capítulos del tutorial.
## El orden importa
-Cuando creas *operaciones de path* puedes encontrarte con situaciones en las que tengas un path fijo.
+Al crear *path operations*, puedes encontrarte en situaciones donde tienes un path fijo.
-Digamos algo como `/users/me` que sea para obtener datos del usuario actual.
+Como `/users/me`, imaginemos que es para obtener datos sobre el usuario actual.
-... y luego puedes tener el path `/users/{user_id}` para obtener los datos sobre un usuario específico asociados a un ID de usuario.
+Y luego también puedes tener un path `/users/{user_id}` para obtener datos sobre un usuario específico por algún ID de usuario.
-Porque las *operaciones de path* son evaluadas en orden, tienes que asegurarte de que el path para `/users/me` sea declarado antes que el path para `/users/{user_id}`:
+Debido a que las *path operations* se evalúan en orden, necesitas asegurarte de que el path para `/users/me` se declara antes que el de `/users/{user_id}`:
-```Python hl_lines="6 11"
-{!../../docs_src/path_params/tutorial003.py!}
-```
+{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
+
+De lo contrario, el path para `/users/{user_id}` también coincidiría para `/users/me`, "pensando" que está recibiendo un parámetro `user_id` con un valor de `"me"`.
+
+De manera similar, no puedes redefinir una path operation:
+
+{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *}
-De otra manera el path para `/users/{user_id}` coincidiría también con `/users/me` "pensando" que está recibiendo el parámetro `user_id` con el valor `"me"`.
+La primera siempre será utilizada ya que el path coincide primero.
## Valores predefinidos
-Si tienes una *operación de path* que recibe un *parámetro de path* pero quieres que los valores posibles del *parámetro de path* sean predefinidos puedes usar un `Enum` estándar de Python.
+Si tienes una *path operation* que recibe un *path parameter*, pero quieres que los valores posibles válidos del *path parameter* estén predefinidos, puedes usar un `Enum` estándar de Python.
-### Crea una clase `Enum`
+### Crear una clase `Enum`
-Importa `Enum` y crea una sub-clase que herede desde `str` y desde `Enum`.
+Importa `Enum` y crea una subclase que herede de `str` y de `Enum`.
-Al heredar desde `str` la documentación de la API podrá saber que los valores deben ser de tipo `string` y podrá mostrarlos correctamente.
+Al heredar de `str`, la documentación de la API podrá saber que los valores deben ser de tipo `string` y podrá representarlos correctamente.
-Luego crea atributos de clase con valores fijos, que serán los valores disponibles válidos:
+Luego crea atributos de clase con valores fijos, que serán los valores válidos disponibles:
-```Python hl_lines="1 6-9"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
/// info | Información
-Las Enumerations (o enums) están disponibles en Python desde la versión 3.4.
+Las enumeraciones (o enums) están disponibles en Python desde la versión 3.4.
///
/// tip | Consejo
-Si lo estás dudando, "AlexNet", "ResNet", y "LeNet" son solo nombres de modelos de Machine Learning.
+Si te estás preguntando, "AlexNet", "ResNet" y "LeNet" son solo nombres de modelos de Machine Learning.
///
-### Declara un *parámetro de path*
+### Declarar un *path parameter*
-Luego, crea un *parámetro de path* con anotaciones de tipos usando la clase enum que creaste (`ModelName`):
+Luego crea un *path parameter* con una anotación de tipo usando la clase enum que creaste (`ModelName`):
-```Python hl_lines="16"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[16] *}
### Revisa la documentación
-Debido a que los valores disponibles para el *parámetro de path* están predefinidos, la documentación interactiva los puede mostrar bien:
+Como los valores disponibles para el *path parameter* están predefinidos, la documentación interactiva puede mostrarlos de manera ordenada:
-### Trabajando con los *enumerations* de Python
+### Trabajando con *enumeraciones* de Python
-El valor del *parámetro de path* será un *enumeration member*.
+El valor del *path parameter* será un *miembro* de enumeración.
-#### Compara *enumeration members*
+#### Comparar *miembros* de enumeraciones
-Puedes compararlo con el *enumeration member* en el enum (`ModelName`) que creaste:
+Puedes compararlo con el *miembro* de enumeración en tu enum creada `ModelName`:
-```Python hl_lines="17"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[17] *}
-#### Obtén el *enumeration value*
+#### Obtener el valor de *enumeración*
-Puedes obtener el valor exacto (un `str` en este caso) usando `model_name.value`, o en general, `your_enum_member.value`:
+Puedes obtener el valor actual (un `str` en este caso) usando `model_name.value`, o en general, `your_enum_member.value`:
-```Python hl_lines="20"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[20] *}
/// tip | Consejo
-También podrías obtener el valor `"lenet"` con `ModelName.lenet.value`.
+También podrías acceder al valor `"lenet"` con `ModelName.lenet.value`.
///
-#### Devuelve *enumeration members*
+#### Devolver *miembros* de enumeración
-Puedes devolver *enum members* desde tu *operación de path* inclusive en un body de JSON anidado (por ejemplo, un `dict`).
+Puedes devolver *miembros de enum* desde tu *path operation*, incluso anidados en un cuerpo JSON (por ejemplo, un `dict`).
-Ellos serán convertidos a sus valores correspondientes (strings en este caso) antes de devolverlos al cliente:
+Serán convertidos a sus valores correspondientes (cadenas en este caso) antes de devolverlos al cliente:
-```Python hl_lines="18 21 23"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
-En tu cliente obtendrás una respuesta en JSON como:
+En tu cliente recibirás un response JSON como:
```JSON
{
@@ -214,55 +206,53 @@ En tu cliente obtendrás una respuesta en JSON como:
}
```
-## Parámetros de path parameters que contienen paths
+## Parámetros de path conteniendo paths
-Digamos que tienes una *operación de path* con un path `/files/{file_path}`.
+Imaginemos que tienes una *path operation* con un path `/files/{file_path}`.
-Pero necesitas que el mismo `file_path` contenga un path como `home/johndoe/myfile.txt`.
+Pero necesitas que `file_path` en sí mismo contenga un *path*, como `home/johndoe/myfile.txt`.
Entonces, la URL para ese archivo sería algo como: `/files/home/johndoe/myfile.txt`.
### Soporte de OpenAPI
-OpenAPI no soporta una manera de declarar un *parámetro de path* que contenga un path, dado que esto podría llevar a escenarios que son difíciles de probar y definir.
+OpenAPI no soporta una manera de declarar un *path parameter* para que contenga un *path* dentro, ya que eso podría llevar a escenarios que son difíciles de probar y definir.
-Sin embargo, lo puedes hacer en **FastAPI** usando una de las herramientas internas de Starlette.
+Sin embargo, todavía puedes hacerlo en **FastAPI**, usando una de las herramientas internas de Starlette.
-La documentación seguirá funcionando, aunque no añadirá ninguna información diciendo que el parámetro debería contener un path.
+Y la documentación seguiría funcionando, aunque no agregue ninguna documentación indicando que el parámetro debe contener un path.
-### Convertidor de path
+### Convertidor de Path
-Usando una opción directamente desde Starlette puedes declarar un *parámetro de path* que contenga un path usando una URL como:
+Usando una opción directamente de Starlette puedes declarar un *path parameter* conteniendo un *path* usando una URL como:
```
/files/{file_path:path}
```
-En este caso el nombre del parámetro es `file_path` y la última parte, `:path`, le dice que el parámetro debería coincidir con cualquier path.
+En este caso, el nombre del parámetro es `file_path`, y la última parte, `:path`, indica que el parámetro debería coincidir con cualquier *path*.
-Entonces lo puedes usar con:
+Así que, puedes usarlo con:
-```Python hl_lines="6"
-{!../../docs_src/path_params/tutorial004.py!}
-```
+{* ../../docs_src/path_params/tutorial004.py hl[6] *}
/// tip | Consejo
-Podrías necesitar que el parámetro contenga `/home/johndoe/myfile.txt` con un slash inicial (`/`).
+Podrías necesitar que el parámetro contenga `/home/johndoe/myfile.txt`, con una barra inclinada (`/`) inicial.
-En este caso la URL sería `/files//home/johndoe/myfile.txt` con un slash doble (`//`) entre `files` y `home`.
+En ese caso, la URL sería: `/files//home/johndoe/myfile.txt`, con una doble barra inclinada (`//`) entre `files` y `home`.
///
-## Repaso
+## Resumen
-Con **FastAPI**, usando declaraciones de tipo de Python intuitivas y estándares, obtienes:
+Con **FastAPI**, al usar declaraciones de tipo estándar de Python, cortas e intuitivas, obtienes:
-* Soporte en el editor: chequeo de errores, auto-completado, etc.
-* "Parsing" de datos
+* Soporte del editor: chequeo de errores, autocompletado, etc.
+* "parsing" de datos
* Validación de datos
-* Anotación de la API y documentación automática
+* Anotación de API y documentación automática
-Solo tienes que declararlos una vez.
+Y solo tienes que declararlos una vez.
-Esa es probablemente la principal ventaja visible de **FastAPI** sobre otros frameworks alternativos (aparte del rendimiento puro).
+Probablemente esa sea la principal ventaja visible de **FastAPI** en comparación con otros frameworks alternativos (aparte del rendimiento bruto).
diff --git a/docs/es/docs/tutorial/query-param-models.md b/docs/es/docs/tutorial/query-param-models.md
new file mode 100644
index 000000000..8338fc358
--- /dev/null
+++ b/docs/es/docs/tutorial/query-param-models.md
@@ -0,0 +1,68 @@
+# Modelos de Parámetros Query
+
+Si tienes un grupo de **parámetros query** que están relacionados, puedes crear un **modelo de Pydantic** para declararlos.
+
+Esto te permitiría **reutilizar el modelo** en **múltiples lugares** y también declarar validaciones y metadatos para todos los parámetros de una vez. 😎
+
+/// note | Nota
+
+Esto es compatible desde la versión `0.115.0` de FastAPI. 🤓
+
+///
+
+## Parámetros Query con un Modelo Pydantic
+
+Declara los **parámetros query** que necesitas en un **modelo de Pydantic**, y luego declara el parámetro como `Query`:
+
+{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
+
+**FastAPI** **extraerá** los datos para **cada campo** de los **parámetros query** en el request y te proporcionará el modelo de Pydantic que definiste.
+
+## Revisa la Documentación
+
+Puedes ver los parámetros query en la UI de documentación en `/docs`:
+
+
+
+
+
+## Prohibir Parámetros Query Extras
+
+En algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** los parámetros query que deseas recibir.
+
+Puedes usar la configuración del modelo de Pydantic para `forbid` cualquier campo `extra`:
+
+{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
+
+Si un cliente intenta enviar algunos datos **extra** en los **parámetros query**, recibirán un response de **error**.
+
+Por ejemplo, si el cliente intenta enviar un parámetro query `tool` con un valor de `plumbus`, como:
+
+```http
+https://example.com/items/?limit=10&tool=plumbus
+```
+
+Recibirán un response de **error** que les indica que el parámetro query `tool` no está permitido:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["query", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus"
+ }
+ ]
+}
+```
+
+## Resumen
+
+Puedes usar **modelos de Pydantic** para declarar **parámetros query** en **FastAPI**. 😎
+
+/// tip | Consejo
+
+Alerta de spoiler: también puedes usar modelos de Pydantic para declarar cookies y headers, pero leerás sobre eso más adelante en el tutorial. 🤫
+
+///
diff --git a/docs/es/docs/tutorial/query-params-str-validations.md b/docs/es/docs/tutorial/query-params-str-validations.md
new file mode 100644
index 000000000..9cb76156f
--- /dev/null
+++ b/docs/es/docs/tutorial/query-params-str-validations.md
@@ -0,0 +1,499 @@
+# Parámetros de Query y Validaciones de String
+
+**FastAPI** te permite declarar información adicional y validación para tus parámetros.
+
+Tomemos esta aplicación como ejemplo:
+
+{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
+
+El parámetro de query `q` es del tipo `Union[str, None]` (o `str | None` en Python 3.10), lo que significa que es de tipo `str` pero también podría ser `None`, y de hecho, el valor por defecto es `None`, así que FastAPI sabrá que no es requerido.
+
+/// note | Nota
+
+FastAPI sabrá que el valor de `q` no es requerido por el valor por defecto `= None`.
+
+El `Union` en `Union[str, None]` permitirá a tu editor darte un mejor soporte y detectar errores.
+
+///
+
+## Validaciones adicionales
+
+Vamos a hacer que, aunque `q` sea opcional, siempre que se proporcione, **su longitud no exceda los 50 caracteres**.
+
+### Importar `Query` y `Annotated`
+
+Para lograr eso, primero importa:
+
+* `Query` desde `fastapi`
+* `Annotated` desde `typing` (o desde `typing_extensions` en Python por debajo de 3.9)
+
+//// tab | Python 3.10+
+
+En Python 3.9 o superior, `Annotated` es parte de la biblioteca estándar, así que puedes importarlo desde `typing`.
+
+```Python hl_lines="1 3"
+{!> ../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+En versiones de Python por debajo de 3.9 importas `Annotated` desde `typing_extensions`.
+
+Ya estará instalado con FastAPI.
+
+```Python hl_lines="3-4"
+{!> ../../docs_src/query_params_str_validations/tutorial002_an.py!}
+```
+
+////
+
+/// info | Información
+
+FastAPI añadió soporte para `Annotated` (y empezó a recomendarlo) en la versión 0.95.0.
+
+Si tienes una versión más antigua, obtendrás errores al intentar usar `Annotated`.
+
+Asegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} a al menos 0.95.1 antes de usar `Annotated`.
+
+///
+
+## Usar `Annotated` en el tipo del parámetro `q`
+
+¿Recuerdas que te dije antes que `Annotated` puede ser usado para agregar metadatos a tus parámetros en la [Introducción a Tipos de Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
+
+Ahora es el momento de usarlo con FastAPI. 🚀
+
+Teníamos esta anotación de tipo:
+
+//// tab | Python 3.10+
+
+```Python
+q: str | None = None
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+q: Union[str, None] = None
+```
+
+////
+
+Lo que haremos es envolver eso con `Annotated`, para que se convierta en:
+
+//// tab | Python 3.10+
+
+```Python
+q: Annotated[str | None] = None
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+q: Annotated[Union[str, None]] = None
+```
+
+////
+
+Ambas versiones significan lo mismo, `q` es un parámetro que puede ser un `str` o `None`, y por defecto, es `None`.
+
+Ahora vamos a lo divertido. 🎉
+
+## Agregar `Query` a `Annotated` en el parámetro `q`
+
+Ahora que tenemos este `Annotated` donde podemos poner más información (en este caso algunas validaciones adicionales), agrega `Query` dentro de `Annotated`, y establece el parámetro `max_length` a `50`:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
+
+Nota que el valor por defecto sigue siendo `None`, por lo que el parámetro sigue siendo opcional.
+
+Pero ahora, al tener `Query(max_length=50)` dentro de `Annotated`, le estamos diciendo a FastAPI que queremos que tenga **validación adicional** para este valor, queremos que tenga un máximo de 50 caracteres. 😎
+
+/// tip | Consejo
+
+Aquí estamos usando `Query()` porque este es un **parámetro de query**. Más adelante veremos otros como `Path()`, `Body()`, `Header()`, y `Cookie()`, que también aceptan los mismos argumentos que `Query()`.
+
+///
+
+FastAPI ahora:
+
+* **Validará** los datos asegurándose de que la longitud máxima sea de 50 caracteres
+* Mostrará un **error claro** para el cliente cuando los datos no sean válidos
+* **Documentará** el parámetro en el OpenAPI esquema *path operation* (así aparecerá en la **UI de documentación automática**)
+
+## Alternativa (antigua): `Query` como valor por defecto
+
+Versiones anteriores de FastAPI (antes de 0.95.0) requerían que usaras `Query` como el valor por defecto de tu parámetro, en lugar de ponerlo en `Annotated`. Hay una alta probabilidad de que veas código usándolo alrededor, así que te lo explicaré.
+
+/// tip | Consejo
+
+Para nuevo código y siempre que sea posible, usa `Annotated` como se explicó arriba. Hay múltiples ventajas (explicadas a continuación) y no hay desventajas. 🍰
+
+///
+
+Así es como usarías `Query()` como el valor por defecto de tu parámetro de función, estableciendo el parámetro `max_length` a 50:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
+
+Ya que en este caso (sin usar `Annotated`) debemos reemplazar el valor por defecto `None` en la función con `Query()`, ahora necesitamos establecer el valor por defecto con el parámetro `Query(default=None)`, esto sirve al mismo propósito de definir ese valor por defecto (al menos para FastAPI).
+
+Entonces:
+
+```Python
+q: Union[str, None] = Query(default=None)
+```
+
+...hace que el parámetro sea opcional, con un valor por defecto de `None`, lo mismo que:
+
+```Python
+q: Union[str, None] = None
+```
+
+Y en Python 3.10 y superior:
+
+```Python
+q: str | None = Query(default=None)
+```
+
+...hace que el parámetro sea opcional, con un valor por defecto de `None`, lo mismo que:
+
+```Python
+q: str | None = None
+```
+
+Pero las versiones de `Query` lo declaran explícitamente como un parámetro de query.
+
+/// info | Información
+
+Ten en cuenta que la parte más importante para hacer un parámetro opcional es la parte:
+
+```Python
+= None
+```
+
+o la parte:
+
+```Python
+= Query(default=None)
+```
+
+ya que usará ese `None` como el valor por defecto, y de esa manera hará el parámetro **no requerido**.
+
+La parte `Union[str, None]` permite que tu editor brinde un mejor soporte, pero no es lo que le dice a FastAPI que este parámetro no es requerido.
+
+///
+
+Luego, podemos pasar más parámetros a `Query`. En este caso, el parámetro `max_length` que se aplica a los strings:
+
+```Python
+q: Union[str, None] = Query(default=None, max_length=50)
+```
+
+Esto validará los datos, mostrará un error claro cuando los datos no sean válidos, y documentará el parámetro en el esquema del *path operation* de OpenaPI.
+
+### `Query` como valor por defecto o en `Annotated`
+
+Ten en cuenta que cuando uses `Query` dentro de `Annotated` no puedes usar el parámetro `default` para `Query`.
+
+En su lugar utiliza el valor por defecto real del parámetro de la función. De lo contrario, sería inconsistente.
+
+Por ejemplo, esto no está permitido:
+
+```Python
+q: Annotated[str, Query(default="rick")] = "morty"
+```
+
+...porque no está claro si el valor por defecto debería ser `"rick"` o `"morty"`.
+
+Así que utilizarías (preferentemente):
+
+```Python
+q: Annotated[str, Query()] = "rick"
+```
+
+...o en code bases más antiguos encontrarás:
+
+```Python
+q: str = Query(default="rick")
+```
+
+### Ventajas de `Annotated`
+
+**Usar `Annotated` es recomendado** en lugar del valor por defecto en los parámetros de función, es **mejor** por múltiples razones. 🤓
+
+El valor **por defecto** del **parámetro de función** es el valor **real por defecto**, eso es más intuitivo con Python en general. 😌
+
+Podrías **llamar** a esa misma función en **otros lugares** sin FastAPI, y **funcionaría como se espera**. Si hay un parámetro **requerido** (sin un valor por defecto), tu **editor** te avisará con un error, **Python** también se quejará si lo ejecutas sin pasar el parámetro requerido.
+
+Cuando no usas `Annotated` y en su lugar usas el estilo de valor por defecto **(antiguo)**, si llamas a esa función sin FastAPI en **otros lugares**, tienes que **recordar** pasar los argumentos a la función para que funcione correctamente, de lo contrario, los valores serán diferentes de lo que esperas (por ejemplo, `QueryInfo` o algo similar en lugar de `str`). Y tu editor no se quejará, y Python no se quejará al ejecutar esa función, solo cuando los errores dentro de las operaciones hagan que funcione incorrectamente.
+
+Dado que `Annotated` puede tener más de una anotación de metadato, ahora podrías incluso usar la misma función con otras herramientas, como Typer. 🚀
+
+## Agregar más validaciones
+
+También puedes agregar un parámetro `min_length`:
+
+{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
+
+## Agregar expresiones regulares
+
+Puedes definir una expresión regular `pattern` que el parámetro debe coincidir:
+
+{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
+
+Este patrón específico de expresión regular comprueba que el valor recibido del parámetro:
+
+* `^`: comience con los siguientes caracteres, no tiene caracteres antes.
+* `fixedquery`: tiene el valor exacto `fixedquery`.
+* `$`: termina allí, no tiene más caracteres después de `fixedquery`.
+
+Si te sientes perdido con todas estas ideas de **"expresión regular"**, no te preocupes. Son un tema difícil para muchas personas. Aún puedes hacer muchas cosas sin necesitar expresiones regulares todavía.
+
+Pero cuando las necesites y vayas a aprenderlas, ya sabes que puedes usarlas directamente en **FastAPI**.
+
+### Pydantic v1 `regex` en lugar de `pattern`
+
+Antes de la versión 2 de Pydantic y antes de FastAPI 0.100.0, el parámetro se llamaba `regex` en lugar de `pattern`, pero ahora está en desuso.
+
+Todavía podrías ver algo de código que lo usa:
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
+
+////
+
+Pero que sepas que esto está deprecado y debería actualizarse para usar el nuevo parámetro `pattern`. 🤓
+
+## Valores por defecto
+
+Puedes, por supuesto, usar valores por defecto diferentes de `None`.
+
+Digamos que quieres declarar el parámetro de query `q` para que tenga un `min_length` de `3`, y para que tenga un valor por defecto de `"fixedquery"`:
+
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
+
+/// note | Nota
+
+Tener un valor por defecto de cualquier tipo, incluyendo `None`, hace que el parámetro sea opcional (no requerido).
+
+///
+
+## Parámetros requeridos
+
+Cuando no necesitamos declarar más validaciones o metadatos, podemos hacer que el parámetro de query `q` sea requerido simplemente no declarando un valor por defecto, como:
+
+```Python
+q: str
+```
+
+en lugar de:
+
+```Python
+q: Union[str, None] = None
+```
+
+Pero ahora lo estamos declarando con `Query`, por ejemplo, como:
+
+//// tab | Annotated
+
+```Python
+q: Annotated[Union[str, None], Query(min_length=3)] = None
+```
+
+////
+
+//// tab | non-Annotated
+
+```Python
+q: Union[str, None] = Query(default=None, min_length=3)
+```
+
+////
+
+Así que, cuando necesites declarar un valor como requerido mientras usas `Query`, simplemente puedes no declarar un valor por defecto:
+
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
+
+### Requerido, puede ser `None`
+
+Puedes declarar que un parámetro puede aceptar `None`, pero que aún así es requerido. Esto obligaría a los clientes a enviar un valor, incluso si el valor es `None`.
+
+Para hacer eso, puedes declarar que `None` es un tipo válido pero aún usar `...` como el valor por defecto:
+
+{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
+
+/// tip | Consejo
+
+Pydantic, que es lo que impulsa toda la validación y serialización de datos en FastAPI, tiene un comportamiento especial cuando usas `Optional` o `Union[Something, None]` sin un valor por defecto, puedes leer más al respecto en la documentación de Pydantic sobre Campos requeridos.
+
+///
+
+/// tip | Consejo
+
+Recuerda que en la mayoría de los casos, cuando algo es requerido, puedes simplemente omitir el default, así que normalmente no tienes que usar `...`.
+
+///
+
+## Lista de parámetros de Query / múltiples valores
+
+Cuando defines un parámetro de query explícitamente con `Query` también puedes declararlo para recibir una lista de valores, o dicho de otra manera, para recibir múltiples valores.
+
+Por ejemplo, para declarar un parámetro de query `q` que puede aparecer varias veces en la URL, puedes escribir:
+
+{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
+
+Entonces, con una URL como:
+
+```
+http://localhost:8000/items/?q=foo&q=bar
+```
+
+recibirías los múltiples valores del *query parameter* `q` (`foo` y `bar`) en una `list` de Python dentro de tu *path operation function*, en el *parámetro de función* `q`.
+
+Entonces, el response a esa URL sería:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+/// tip | Consejo
+
+Para declarar un parámetro de query con un tipo de `list`, como en el ejemplo anterior, necesitas usar explícitamente `Query`, de lo contrario sería interpretado como un request body.
+
+///
+
+La documentación interactiva de API se actualizará en consecuencia, para permitir múltiples valores:
+
+
+
+### Lista de parámetros de Query / múltiples valores con valores por defecto
+
+Y también puedes definir un valor por defecto `list` de valores si no se proporcionan ninguno:
+
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
+
+Si vas a:
+
+```
+http://localhost:8000/items/
+```
+
+el valor por defecto de `q` será: `["foo", "bar"]` y tu response será:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+#### Usando solo `list`
+
+También puedes usar `list` directamente en lugar de `List[str]` (o `list[str]` en Python 3.9+):
+
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
+
+/// note | Nota
+
+Ten en cuenta que en este caso, FastAPI no comprobará el contenido de la lista.
+
+Por ejemplo, `List[int]` comprobaría (y documentaría) que el contenido de la lista son enteros. Pero `list` sola no lo haría.
+
+///
+
+## Declarar más metadatos
+
+Puedes agregar más información sobre el parámetro.
+
+Esa información se incluirá en el OpenAPI generado y será utilizada por las interfaces de usuario de documentación y herramientas externas.
+
+/// note | Nota
+
+Ten en cuenta que diferentes herramientas podrían tener diferentes niveles de soporte de OpenAPI.
+
+Algunas de ellas podrían no mostrar toda la información extra declarada todavía, aunque en la mayoría de los casos, la funcionalidad faltante ya está planificada para desarrollo.
+
+///
+
+Puedes agregar un `title`:
+
+{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
+
+Y una `description`:
+
+{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
+
+## Alias para parámetros
+
+Imagina que quieres que el parámetro sea `item-query`.
+
+Como en:
+
+```
+http://127.0.0.1:8000/items/?item-query=foobaritems
+```
+
+Pero `item-query` no es un nombre de variable válido en Python.
+
+Lo más cercano sería `item_query`.
+
+Pero aún necesitas que sea exactamente `item-query`...
+
+Entonces puedes declarar un `alias`, y ese alias será usado para encontrar el valor del parámetro:
+
+{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
+
+## Declarar parámetros obsoletos
+
+Ahora digamos que ya no te gusta este parámetro.
+
+Tienes que dejarlo allí por un tiempo porque hay clientes usándolo, pero quieres que la documentación lo muestre claramente como deprecated.
+
+Luego pasa el parámetro `deprecated=True` a `Query`:
+
+{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
+
+La documentación lo mostrará así:
+
+
+
+## Excluir parámetros de OpenAPI
+
+Para excluir un parámetro de query del esquema de OpenAPI generado (y por lo tanto, de los sistemas de documentación automática), establece el parámetro `include_in_schema` de `Query` a `False`:
+
+{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
+
+## Recapitulación
+
+Puedes declarar validaciones y metadatos adicionales para tus parámetros.
+
+Validaciones genéricas y metadatos:
+
+* `alias`
+* `title`
+* `description`
+* `deprecated`
+
+Validaciones específicas para strings:
+
+* `min_length`
+* `max_length`
+* `pattern`
+
+En estos ejemplos viste cómo declarar validaciones para valores de tipo `str`.
+
+Mira los siguientes capítulos para aprender cómo declarar validaciones para otros tipos, como números.
diff --git a/docs/es/docs/tutorial/query-params.md b/docs/es/docs/tutorial/query-params.md
index f9b5cf69d..09c66a545 100644
--- a/docs/es/docs/tutorial/query-params.md
+++ b/docs/es/docs/tutorial/query-params.md
@@ -1,12 +1,10 @@
-# Parámetros de query
+# Parámetros de Query
-Cuando declaras otros parámetros de la función que no hacen parte de los parámetros de path estos se interpretan automáticamente como parámetros de "query".
+Cuando declaras otros parámetros de función que no son parte de los parámetros de path, son automáticamente interpretados como parámetros de "query".
-```Python hl_lines="9"
-{!../../docs_src/query_params/tutorial001.py!}
-```
+{* ../../docs_src/query_params/tutorial001.py hl[9] *}
-El query es el conjunto de pares de key-value que van después del `?` en la URL, separados por caracteres `&`.
+La query es el conjunto de pares clave-valor que van después del `?` en una URL, separados por caracteres `&`.
Por ejemplo, en la URL:
@@ -19,36 +17,36 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
* `skip`: con un valor de `0`
* `limit`: con un valor de `10`
-Dado que son parte de la URL son strings "naturalmente".
+Como son parte de la URL, son "naturalmente" strings.
-Pero cuando los declaras con tipos de Python (en el ejemplo arriba, como `int`) son convertidos a ese tipo y son validados con él.
+Pero cuando los declaras con tipos de Python (en el ejemplo anterior, como `int`), son convertidos a ese tipo y validados respecto a él.
-Todo el proceso que aplicaba a los parámetros de path también aplica a los parámetros de query:
+Todo el mismo proceso que se aplica para los parámetros de path también se aplica para los parámetros de query:
* Soporte del editor (obviamente)
-* "Parsing" de datos
+* "Parsing" de datos
* Validación de datos
* Documentación automática
-## Configuraciones por defecto
+## Valores por defecto
-Como los parámetros de query no están fijos en una parte del path pueden ser opcionales y pueden tener valores por defecto.
+Como los parámetros de query no son una parte fija de un path, pueden ser opcionales y pueden tener valores por defecto.
-El ejemplo arriba tiene `skip=0` y `limit=10` como los valores por defecto.
+En el ejemplo anterior, tienen valores por defecto de `skip=0` y `limit=10`.
-Entonces, si vas a la URL:
+Entonces, ir a la URL:
```
http://127.0.0.1:8000/items/
```
-Sería lo mismo que ir a:
+sería lo mismo que ir a:
```
http://127.0.0.1:8000/items/?skip=0&limit=10
```
-Pero, si por ejemplo vas a:
+Pero si vas a, por ejemplo:
```
http://127.0.0.1:8000/items/?skip=20
@@ -56,40 +54,26 @@ http://127.0.0.1:8000/items/?skip=20
Los valores de los parámetros en tu función serán:
-* `skip=20`: porque lo definiste en la URL
-* `limit=10`: porque era el valor por defecto
+* `skip=20`: porque lo configuraste en la URL
+* `limit=10`: porque ese era el valor por defecto
## Parámetros opcionales
-Del mismo modo puedes declarar parámetros de query opcionales definiendo el valor por defecto como `None`:
-
-```Python hl_lines="9"
-{!../../docs_src/query_params/tutorial002.py!}
-```
+De la misma manera, puedes declarar parámetros de query opcionales, estableciendo su valor por defecto en `None`:
-En este caso el parámetro de la función `q` será opcional y será `None` por defecto.
+{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
/// check | Revisa
-También puedes notar que **FastAPI** es lo suficientemente inteligente para darse cuenta de que el parámetro de path `item_id` es un parámetro de path y que `q` no lo es, y por lo tanto es un parámetro de query.
-
-///
-
-/// note | Nota
-
-FastAPI sabrá que `q` es opcional por el `= None`.
-
-El `Union` en `Union[str, None]` no es usado por FastAPI (FastAPI solo usará la parte `str`), pero el `Union[str, None]` le permitirá a tu editor ayudarte a encontrar errores en tu código.
+Además, nota que **FastAPI** es lo suficientemente inteligente para notar que el parámetro de path `item_id` es un parámetro de path y `q` no lo es, por lo tanto, es un parámetro de query.
///
-## Conversión de tipos de parámetros de query
+## Conversión de tipos en parámetros de query
-También puedes declarar tipos `bool` y serán convertidos:
+También puedes declarar tipos `bool`, y serán convertidos:
-```Python hl_lines="9"
-{!../../docs_src/query_params/tutorial003.py!}
-```
+{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
En este caso, si vas a:
@@ -121,58 +105,56 @@ o
http://127.0.0.1:8000/items/foo?short=yes
```
-o cualquier otra variación (mayúsculas, primera letra en mayúscula, etc.) tu función verá el parámetro `short` con un valor `bool` de `True`. Si no, lo verá como `False`.
+o cualquier otra variación (mayúsculas, primera letra en mayúscula, etc.), tu función verá el parámetro `short` con un valor `bool` de `True`. De lo contrario, será `False`.
-## Múltiples parámetros de path y query
+## Múltiples parámetros de path y de query
-Puedes declarar múltiples parámetros de path y parámetros de query al mismo tiempo. **FastAPI** sabe cuál es cuál.
+Puedes declarar múltiples parámetros de path y de query al mismo tiempo, **FastAPI** sabe cuál es cuál.
-No los tienes que declarar en un orden específico.
+Y no tienes que declararlos en un orden específico.
Serán detectados por nombre:
-```Python hl_lines="8 10"
-{!../../docs_src/query_params/tutorial004.py!}
-```
+{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
## Parámetros de query requeridos
-Cuando declaras un valor por defecto para los parámetros que no son de path (por ahora solo hemos visto parámetros de query), entonces no es requerido.
+Cuando declaras un valor por defecto para parámetros que no son de path (por ahora, solo hemos visto parámetros de query), entonces no es requerido.
-Si no quieres añadir un valor específico sino solo hacerlo opcional, pon el valor por defecto como `None`.
+Si no quieres agregar un valor específico pero solo hacer que sea opcional, establece el valor por defecto como `None`.
-Pero cuando quieres hacer que un parámetro de query sea requerido, puedes simplemente no declararle un valor por defecto:
+Pero cuando quieres hacer un parámetro de query requerido, simplemente no declares ningún valor por defecto:
-```Python hl_lines="6-7"
-{!../../docs_src/query_params/tutorial005.py!}
-```
+{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
-Aquí el parámetro de query `needy` es un parámetro de query requerido, del tipo `str`.
+Aquí el parámetro de query `needy` es un parámetro de query requerido de tipo `str`.
-Si abres tu navegador en una URL como:
+Si abres en tu navegador una URL como:
```
http://127.0.0.1:8000/items/foo-item
```
-...sin añadir el parámetro `needy` requerido, verás un error como:
+...sin agregar el parámetro requerido `needy`, verás un error como:
```JSON
{
- "detail": [
- {
- "loc": [
- "query",
- "needy"
- ],
- "msg": "field required",
- "type": "value_error.missing"
- }
- ]
+ "detail": [
+ {
+ "type": "missing",
+ "loc": [
+ "query",
+ "needy"
+ ],
+ "msg": "Field required",
+ "input": null,
+ "url": "https://errors.pydantic.dev/2.1/v/missing"
+ }
+ ]
}
```
-Dado que `needy` es un parámetro requerido necesitarías declararlo en la URL:
+Como `needy` es un parámetro requerido, necesitarías establecerlo en la URL:
```
http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
@@ -187,13 +169,11 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
}
```
-Por supuesto que también puedes definir algunos parámetros como requeridos, con un valor por defecto y otros completamente opcionales:
+Y por supuesto, puedes definir algunos parámetros como requeridos, algunos con un valor por defecto, y algunos enteramente opcionales:
-```Python hl_lines="10"
-{!../../docs_src/query_params/tutorial006.py!}
-```
+{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
-En este caso hay 3 parámetros de query:
+En este caso, hay 3 parámetros de query:
* `needy`, un `str` requerido.
* `skip`, un `int` con un valor por defecto de `0`.
@@ -201,6 +181,6 @@ En este caso hay 3 parámetros de query:
/// tip | Consejo
-También podrías usar los `Enum`s de la misma manera que con los [Parámetros de path](path-params.md#valores-predefinidos){.internal-link target=_blank}.
+También podrías usar `Enum`s de la misma manera que con [Parámetros de Path](path-params.md#predefined-values){.internal-link target=_blank}.
///
diff --git a/docs/es/docs/tutorial/request-files.md b/docs/es/docs/tutorial/request-files.md
new file mode 100644
index 000000000..330523c7e
--- /dev/null
+++ b/docs/es/docs/tutorial/request-files.md
@@ -0,0 +1,176 @@
+# Archivos de Request
+
+Puedes definir archivos que serán subidos por el cliente utilizando `File`.
+
+/// info | Información
+
+Para recibir archivos subidos, primero instala `python-multipart`.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalarlo, por ejemplo:
+
+```console
+$ pip install python-multipart
+```
+
+Esto es porque los archivos subidos se envían como "form data".
+
+///
+
+## Importar `File`
+
+Importa `File` y `UploadFile` desde `fastapi`:
+
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
+
+## Definir Parámetros `File`
+
+Crea parámetros de archivo de la misma manera que lo harías para `Body` o `Form`:
+
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
+
+/// info | Información
+
+`File` es una clase que hereda directamente de `Form`.
+
+Pero recuerda que cuando importas `Query`, `Path`, `File` y otros desde `fastapi`, esos son en realidad funciones que devuelven clases especiales.
+
+///
+
+/// tip | Consejo
+
+Para declarar cuerpos de File, necesitas usar `File`, porque de otra manera los parámetros serían interpretados como parámetros query o parámetros de cuerpo (JSON).
+
+///
+
+Los archivos se subirán como "form data".
+
+Si declaras el tipo de tu parámetro de *path operation function* como `bytes`, **FastAPI** leerá el archivo por ti y recibirás el contenido como `bytes`.
+
+Ten en cuenta que esto significa que todo el contenido se almacenará en memoria. Esto funcionará bien para archivos pequeños.
+
+Pero hay varios casos en los que podrías beneficiarte de usar `UploadFile`.
+
+## Parámetros de Archivo con `UploadFile`
+
+Define un parámetro de archivo con un tipo de `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
+
+Usar `UploadFile` tiene varias ventajas sobre `bytes`:
+
+* No tienes que usar `File()` en el valor por defecto del parámetro.
+* Usa un archivo "spooled":
+ * Un archivo almacenado en memoria hasta un límite de tamaño máximo, y después de superar este límite, se almacenará en el disco.
+* Esto significa que funcionará bien para archivos grandes como imágenes, videos, binarios grandes, etc. sin consumir toda la memoria.
+* Puedes obtener metadatos del archivo subido.
+* Tiene una interfaz `async` parecida a un archivo.
+* Expone un objeto Python real `SpooledTemporaryFile` que puedes pasar directamente a otros paquetes que esperan un objeto parecido a un archivo.
+
+### `UploadFile`
+
+`UploadFile` tiene los siguientes atributos:
+
+* `filename`: Un `str` con el nombre original del archivo que fue subido (por ejemplo, `myimage.jpg`).
+* `content_type`: Un `str` con el tipo de contenido (MIME type / media type) (por ejemplo, `image/jpeg`).
+* `file`: Un `SpooledTemporaryFile` (un objeto parecido a un archivo). Este es el objeto de archivo Python real que puedes pasar directamente a otras funciones o paquetes que esperan un objeto "parecido a un archivo".
+
+`UploadFile` tiene los siguientes métodos `async`. Todos ellos llaman a los métodos correspondientes del archivo por debajo (usando el `SpooledTemporaryFile` interno).
+
+* `write(data)`: Escribe `data` (`str` o `bytes`) en el archivo.
+* `read(size)`: Lee `size` (`int`) bytes/caracteres del archivo.
+* `seek(offset)`: Va a la posición de bytes `offset` (`int`) en el archivo.
+ * Por ejemplo, `await myfile.seek(0)` iría al inicio del archivo.
+ * Esto es especialmente útil si ejecutas `await myfile.read()` una vez y luego necesitas leer el contenido nuevamente.
+* `close()`: Cierra el archivo.
+
+Como todos estos métodos son métodos `async`, necesitas "await" para ellos.
+
+Por ejemplo, dentro de una *path operation function* `async` puedes obtener los contenidos con:
+
+```Python
+contents = await myfile.read()
+```
+
+Si estás dentro de una *path operation function* normal `def`, puedes acceder al `UploadFile.file` directamente, por ejemplo:
+
+```Python
+contents = myfile.file.read()
+```
+
+/// note | Detalles Técnicos de `async`
+
+Cuando usas los métodos `async`, **FastAPI** ejecuta los métodos del archivo en un threadpool y los espera.
+
+///
+
+/// note | Detalles Técnicos de Starlette
+
+El `UploadFile` de **FastAPI** hereda directamente del `UploadFile` de **Starlette**, pero añade algunas partes necesarias para hacerlo compatible con **Pydantic** y las otras partes de FastAPI.
+
+///
+
+## Qué es "Form Data"
+
+La manera en que los forms de HTML (``) envían los datos al servidor normalmente utiliza una codificación "especial" para esos datos, es diferente de JSON.
+
+**FastAPI** se asegurará de leer esos datos del lugar correcto en lugar de JSON.
+
+/// note | Detalles Técnicos
+
+Los datos de los forms normalmente se codifican usando el "media type" `application/x-www-form-urlencoded` cuando no incluyen archivos.
+
+Pero cuando el formulario incluye archivos, se codifica como `multipart/form-data`. Si usas `File`, **FastAPI** sabrá que tiene que obtener los archivos de la parte correcta del cuerpo.
+
+Si deseas leer más sobre estas codificaciones y campos de formularios, dirígete a la MDN web docs para POST.
+
+///
+
+/// warning | Advertencia
+
+Puedes declarar múltiples parámetros `File` y `Form` en una *path operation*, pero no puedes declarar campos `Body` que esperas recibir como JSON, ya que el request tendrá el cuerpo codificado usando `multipart/form-data` en lugar de `application/json`.
+
+Esto no es una limitación de **FastAPI**, es parte del protocolo HTTP.
+
+///
+
+## Subida de Archivos Opcional
+
+Puedes hacer un archivo opcional utilizando anotaciones de tipos estándar y estableciendo un valor por defecto de `None`:
+
+{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
+
+## `UploadFile` con Metadatos Adicionales
+
+También puedes usar `File()` con `UploadFile`, por ejemplo, para establecer metadatos adicionales:
+
+{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
+
+## Subidas de Múltiples Archivos
+
+Es posible subir varios archivos al mismo tiempo.
+
+Estarían asociados al mismo "campo de formulario" enviado usando "form data".
+
+Para usar eso, declara una lista de `bytes` o `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+
+Recibirás, como se declaró, una `list` de `bytes` o `UploadFile`s.
+
+/// note | Detalles Técnicos
+
+También podrías usar `from starlette.responses import HTMLResponse`.
+
+**FastAPI** proporciona las mismas `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.
+
+///
+
+### Subidas de Múltiples Archivos con Metadatos Adicionales
+
+Y de la misma manera que antes, puedes usar `File()` para establecer parámetros adicionales, incluso para `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+
+## Recapitulación
+
+Usa `File`, `bytes` y `UploadFile` para declarar archivos que se subirán en el request, enviados como form data.
diff --git a/docs/es/docs/tutorial/request-form-models.md b/docs/es/docs/tutorial/request-form-models.md
new file mode 100644
index 000000000..9d5d7495a
--- /dev/null
+++ b/docs/es/docs/tutorial/request-form-models.md
@@ -0,0 +1,78 @@
+# Modelos de Formulario
+
+Puedes usar **modelos de Pydantic** para declarar **campos de formulario** en FastAPI.
+
+/// info | Información
+
+Para usar formularios, primero instala `python-multipart`.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo, y luego instalarlo, por ejemplo:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+/// note | Nota
+
+Esto es compatible desde la versión `0.113.0` de FastAPI. 🤓
+
+///
+
+## Modelos de Pydantic para Formularios
+
+Solo necesitas declarar un **modelo de Pydantic** con los campos que quieres recibir como **campos de formulario**, y luego declarar el parámetro como `Form`:
+
+{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+
+**FastAPI** **extraerá** los datos de **cada campo** de los **form data** en el request y te dará el modelo de Pydantic que definiste.
+
+## Revisa la Documentación
+
+Puedes verificarlo en la interfaz de documentación en `/docs`:
+
+
+
+
+
+## Prohibir Campos de Formulario Extra
+
+En algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** los campos de formulario a solo aquellos declarados en el modelo de Pydantic. Y **prohibir** cualquier campo **extra**.
+
+/// note | Nota
+
+Esto es compatible desde la versión `0.114.0` de FastAPI. 🤓
+
+///
+
+Puedes usar la configuración del modelo de Pydantic para `forbid` cualquier campo `extra`:
+
+{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+
+Si un cliente intenta enviar datos extra, recibirá un response de **error**.
+
+Por ejemplo, si el cliente intenta enviar los campos de formulario:
+
+* `username`: `Rick`
+* `password`: `Portal Gun`
+* `extra`: `Mr. Poopybutthole`
+
+Recibirá un response de error indicando que el campo `extra` no está permitido:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["body", "extra"],
+ "msg": "Extra inputs are not permitted",
+ "input": "Mr. Poopybutthole"
+ }
+ ]
+}
+```
+
+## Resumen
+
+Puedes usar modelos de Pydantic para declarar campos de formulario en FastAPI. 😎
diff --git a/docs/es/docs/tutorial/request-forms-and-files.md b/docs/es/docs/tutorial/request-forms-and-files.md
new file mode 100644
index 000000000..51dfbb357
--- /dev/null
+++ b/docs/es/docs/tutorial/request-forms-and-files.md
@@ -0,0 +1,41 @@
+# Request Forms and Files
+
+Puedes definir archivos y campos de formulario al mismo tiempo usando `File` y `Form`.
+
+/// info | Información
+
+Para recibir archivos subidos y/o form data, primero instala `python-multipart`.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo y luego instálalo, por ejemplo:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+## Importar `File` y `Form`
+
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
+
+## Definir parámetros `File` y `Form`
+
+Crea parámetros de archivo y formulario de la misma manera que lo harías para `Body` o `Query`:
+
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
+
+Los archivos y campos de formulario se subirán como form data y recibirás los archivos y campos de formulario.
+
+Y puedes declarar algunos de los archivos como `bytes` y algunos como `UploadFile`.
+
+/// warning | Advertencia
+
+Puedes declarar múltiples parámetros `File` y `Form` en una *path operation*, pero no puedes también declarar campos `Body` que esperas recibir como JSON, ya que el request tendrá el body codificado usando `multipart/form-data` en lugar de `application/json`.
+
+Esto no es una limitación de **FastAPI**, es parte del protocolo HTTP.
+
+///
+
+## Resumen
+
+Usa `File` y `Form` juntos cuando necesites recibir datos y archivos en el mismo request.
diff --git a/docs/es/docs/tutorial/request-forms.md b/docs/es/docs/tutorial/request-forms.md
new file mode 100644
index 000000000..a9d62e660
--- /dev/null
+++ b/docs/es/docs/tutorial/request-forms.md
@@ -0,0 +1,73 @@
+# Form Data
+
+Cuando necesitas recibir campos de formulario en lugar de JSON, puedes usar `Form`.
+
+/// info | Información
+
+Para usar forms, primero instala `python-multipart`.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo, y luego instalarlo, por ejemplo:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+## Importar `Form`
+
+Importar `Form` desde `fastapi`:
+
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+
+## Definir parámetros de `Form`
+
+Crea parámetros de formulario de la misma manera que lo harías para `Body` o `Query`:
+
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+
+Por ejemplo, en una de las formas en las que se puede usar la especificación OAuth2 (llamada "password flow") se requiere enviar un `username` y `password` como campos de formulario.
+
+La especificación requiere que los campos se llamen exactamente `username` y `password`, y que se envíen como campos de formulario, no JSON.
+
+Con `Form` puedes declarar las mismas configuraciones que con `Body` (y `Query`, `Path`, `Cookie`), incluyendo validación, ejemplos, un alias (por ejemplo, `user-name` en lugar de `username`), etc.
+
+/// info | Información
+
+`Form` es una clase que hereda directamente de `Body`.
+
+///
+
+/// tip | Consejo
+
+Para declarar bodies de forms, necesitas usar `Form` explícitamente, porque sin él, los parámetros se interpretarían como parámetros de query o como parámetros de body (JSON).
+
+///
+
+## Sobre "Campos de Formulario"
+
+La manera en que los forms HTML (``) envían los datos al servidor normalmente usa una codificación "especial" para esos datos, es diferente de JSON.
+
+**FastAPI** se encargará de leer esos datos del lugar correcto en lugar de JSON.
+
+/// note | Detalles técnicos
+
+Los datos de forms normalmente se codifican usando el "media type" `application/x-www-form-urlencoded`.
+
+Pero cuando el formulario incluye archivos, se codifica como `multipart/form-data`. Leerás sobre la gestión de archivos en el próximo capítulo.
+
+Si quieres leer más sobre estas codificaciones y campos de formulario, dirígete a la MDN web docs para POST.
+
+///
+
+/// warning | Advertencia
+
+Puedes declarar múltiples parámetros `Form` en una *path operation*, pero no puedes también declarar campos `Body` que esperas recibir como JSON, ya que el request tendrá el body codificado usando `application/x-www-form-urlencoded` en lugar de `application/json`.
+
+Esto no es una limitación de **FastAPI**, es parte del protocolo HTTP.
+
+///
+
+## Recapitulación
+
+Usa `Form` para declarar parámetros de entrada de datos de formulario.
diff --git a/docs/es/docs/tutorial/response-model.md b/docs/es/docs/tutorial/response-model.md
new file mode 100644
index 000000000..09682f51b
--- /dev/null
+++ b/docs/es/docs/tutorial/response-model.md
@@ -0,0 +1,357 @@
+# Modelo de Response - Tipo de Retorno
+
+Puedes declarar el tipo utilizado para el response anotando el **tipo de retorno** de la *path operation function*.
+
+Puedes utilizar **anotaciones de tipos** de la misma manera que lo harías para datos de entrada en **parámetros** de función, puedes utilizar modelos de Pydantic, listas, diccionarios, valores escalares como enteros, booleanos, etc.
+
+{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
+
+FastAPI usará este tipo de retorno para:
+
+* **Validar** los datos devueltos.
+ * Si los datos son inválidos (por ejemplo, falta un campo), significa que el código de *tu* aplicación está defectuoso, no devolviendo lo que debería, y retornará un error del servidor en lugar de devolver datos incorrectos. De esta manera, tú y tus clientes pueden estar seguros de que recibirán los datos y la forma de los datos esperada.
+* Agregar un **JSON Schema** para el response, en la *path operation* de OpenAPI.
+ * Esto será utilizado por la **documentación automática**.
+ * También será utilizado por herramientas de generación automática de código de cliente.
+
+Pero lo más importante:
+
+* **Limitará y filtrará** los datos de salida a lo que se define en el tipo de retorno.
+ * Esto es particularmente importante para la **seguridad**, veremos más sobre eso a continuación.
+
+## Parámetro `response_model`
+
+Hay algunos casos en los que necesitas o quieres devolver algunos datos que no son exactamente lo que declara el tipo.
+
+Por ejemplo, podrías querer **devolver un diccionario** u objeto de base de datos, pero **declararlo como un modelo de Pydantic**. De esta manera el modelo de Pydantic haría toda la documentación de datos, validación, etc. para el objeto que devolviste (por ejemplo, un diccionario u objeto de base de datos).
+
+Si añadiste la anotación del tipo de retorno, las herramientas y editores se quejarían con un error (correcto) diciéndote que tu función está devolviendo un tipo (por ejemplo, un dict) que es diferente de lo que declaraste (por ejemplo, un modelo de Pydantic).
+
+En esos casos, puedes usar el parámetro del decorador de path operation `response_model` en lugar del tipo de retorno.
+
+Puedes usar el parámetro `response_model` en cualquiera de las *path operations*:
+
+* `@app.get()`
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+* etc.
+
+{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
+
+/// note | Nota
+
+Observa que `response_model` es un parámetro del método "decorador" (`get`, `post`, etc). No de tu *path operation function*, como todos los parámetros y el cuerpo.
+
+///
+
+`response_model` recibe el mismo tipo que declararías para un campo de modelo Pydantic, por lo que puede ser un modelo de Pydantic, pero también puede ser, por ejemplo, un `list` de modelos de Pydantic, como `List[Item]`.
+
+FastAPI usará este `response_model` para hacer toda la documentación de datos, validación, etc. y también para **convertir y filtrar los datos de salida** a su declaración de tipo.
+
+/// tip | Consejo
+
+Si tienes chequeos estrictos de tipos en tu editor, mypy, etc., puedes declarar el tipo de retorno de la función como `Any`.
+
+De esa manera le dices al editor que intencionalmente estás devolviendo cualquier cosa. Pero FastAPI todavía hará la documentación de datos, validación, filtrado, etc. con `response_model`.
+
+///
+
+### Prioridad del `response_model`
+
+Si declaras tanto un tipo de retorno como un `response_model`, el `response_model` tomará prioridad y será utilizado por FastAPI.
+
+De esta manera puedes añadir anotaciones de tipos correctas a tus funciones incluso cuando estás devolviendo un tipo diferente al modelo de response, para ser utilizado por el editor y herramientas como mypy. Y aún así puedes hacer que FastAPI realice la validación de datos, documentación, etc. usando el `response_model`.
+
+También puedes usar `response_model=None` para desactivar la creación de un modelo de response para esa *path operation*, podrías necesitar hacerlo si estás añadiendo anotaciones de tipos para cosas que no son campos válidos de Pydantic, verás un ejemplo de eso en una de las secciones a continuación.
+
+## Devolver los mismos datos de entrada
+
+Aquí estamos declarando un modelo `UserIn`, contendrá una contraseña en texto plano:
+
+{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
+
+/// info | Información
+
+Para usar `EmailStr`, primero instala `email-validator`.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo, y luego instalarlo, por ejemplo:
+
+```console
+$ pip install email-validator
+```
+
+o con:
+
+```console
+$ pip install "pydantic[email]"
+```
+
+///
+
+Y estamos usando este modelo para declarar nuestra entrada y el mismo modelo para declarar nuestra salida:
+
+{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
+
+Ahora, cada vez que un navegador esté creando un usuario con una contraseña, la API devolverá la misma contraseña en el response.
+
+En este caso, podría no ser un problema, porque es el mismo usuario que envía la contraseña.
+
+Pero si usamos el mismo modelo para otra *path operation*, podríamos estar enviando las contraseñas de nuestros usuarios a cada cliente.
+
+/// danger | Peligro
+
+Nunca almacenes la contraseña en texto plano de un usuario ni la envíes en un response como esta, a menos que conozcas todas las advertencias y sepas lo que estás haciendo.
+
+///
+
+## Añadir un modelo de salida
+
+Podemos en cambio crear un modelo de entrada con la contraseña en texto plano y un modelo de salida sin ella:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
+
+Aquí, aunque nuestra *path operation function* está devolviendo el mismo usuario de entrada que contiene la contraseña:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
+
+...hemos declarado el `response_model` para ser nuestro modelo `UserOut`, que no incluye la contraseña:
+
+{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
+
+Entonces, **FastAPI** se encargará de filtrar todos los datos que no estén declarados en el modelo de salida (usando Pydantic).
+
+### `response_model` o Tipo de Retorno
+
+En este caso, como los dos modelos son diferentes, si anotáramos el tipo de retorno de la función como `UserOut`, el editor y las herramientas se quejarían de que estamos devolviendo un tipo inválido, ya que son clases diferentes.
+
+Por eso en este ejemplo tenemos que declararlo en el parámetro `response_model`.
+
+...pero sigue leyendo abajo para ver cómo superar eso.
+
+## Tipo de Retorno y Filtrado de Datos
+
+Continuemos con el ejemplo anterior. Queríamos **anotar la función con un tipo**, pero queríamos poder devolver desde la función algo que en realidad incluya **más datos**.
+
+Queremos que FastAPI continúe **filtrando** los datos usando el modelo de response. Para que, incluso cuando la función devuelva más datos, el response solo incluya los campos declarados en el modelo de response.
+
+En el ejemplo anterior, debido a que las clases eran diferentes, tuvimos que usar el parámetro `response_model`. Pero eso también significa que no obtenemos el soporte del editor y las herramientas verificando el tipo de retorno de la función.
+
+Pero en la mayoría de los casos en los que necesitamos hacer algo como esto, queremos que el modelo solo **filtre/elimine** algunos de los datos como en este ejemplo.
+
+Y en esos casos, podemos usar clases y herencia para aprovechar las **anotaciones de tipos** de funciones para obtener mejor soporte en el editor y herramientas, y aún así obtener el **filtrado de datos** de FastAPI.
+
+{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
+
+Con esto, obtenemos soporte de las herramientas, de los editores y mypy ya que este código es correcto en términos de tipos, pero también obtenemos el filtrado de datos de FastAPI.
+
+¿Cómo funciona esto? Vamos a echarle un vistazo. 🤓
+
+### Anotaciones de Tipos y Herramientas
+
+Primero vamos a ver cómo los editores, mypy y otras herramientas verían esto.
+
+`BaseUser` tiene los campos base. Luego `UserIn` hereda de `BaseUser` y añade el campo `password`, por lo que incluirá todos los campos de ambos modelos.
+
+Anotamos el tipo de retorno de la función como `BaseUser`, pero en realidad estamos devolviendo una instancia de `UserIn`.
+
+El editor, mypy y otras herramientas no se quejarán de esto porque, en términos de tipificación, `UserIn` es una subclase de `BaseUser`, lo que significa que es un tipo *válido* cuando se espera algo que es un `BaseUser`.
+
+### Filtrado de Datos en FastAPI
+
+Ahora, para FastAPI, verá el tipo de retorno y se asegurará de que lo que devuelves incluya **solo** los campos que están declarados en el tipo.
+
+FastAPI realiza varias cosas internamente con Pydantic para asegurarse de que esas mismas reglas de herencia de clases no se utilicen para el filtrado de datos devueltos, de lo contrario, podrías terminar devolviendo muchos más datos de los que esperabas.
+
+De esta manera, puedes obtener lo mejor de ambos mundos: anotaciones de tipos con **soporte de herramientas** y **filtrado de datos**.
+
+## Verlo en la documentación
+
+Cuando veas la documentación automática, puedes verificar que el modelo de entrada y el modelo de salida tendrán cada uno su propio JSON Schema:
+
+
+
+Y ambos modelos se utilizarán para la documentación interactiva de la API:
+
+
+
+## Otras Anotaciones de Tipos de Retorno
+
+Podría haber casos en los que devuelvas algo que no es un campo válido de Pydantic y lo anotes en la función, solo para obtener el soporte proporcionado por las herramientas (el editor, mypy, etc).
+
+### Devolver un Response Directamente
+
+El caso más común sería [devolver un Response directamente como se explica más adelante en la documentación avanzada](../advanced/response-directly.md){.internal-link target=_blank}.
+
+{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *}
+
+Este caso simple es manejado automáticamente por FastAPI porque la anotación del tipo de retorno es la clase (o una subclase de) `Response`.
+
+Y las herramientas también estarán felices porque tanto `RedirectResponse` como `JSONResponse` son subclases de `Response`, por lo que la anotación del tipo es correcta.
+
+### Anotar una Subclase de Response
+
+También puedes usar una subclase de `Response` en la anotación del tipo:
+
+{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *}
+
+Esto también funcionará porque `RedirectResponse` es una subclase de `Response`, y FastAPI manejará automáticamente este caso simple.
+
+### Anotaciones de Tipos de Retorno Inválidas
+
+Pero cuando devuelves algún otro objeto arbitrario que no es un tipo válido de Pydantic (por ejemplo, un objeto de base de datos) y lo anotas así en la función, FastAPI intentará crear un modelo de response de Pydantic a partir de esa anotación de tipo, y fallará.
+
+Lo mismo sucedería si tuvieras algo como un union entre diferentes tipos donde uno o más de ellos no son tipos válidos de Pydantic, por ejemplo esto fallaría 💥:
+
+{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
+
+...esto falla porque la anotación de tipo no es un tipo de Pydantic y no es solo una sola clase `Response` o subclase, es una unión (cualquiera de los dos) entre una `Response` y un `dict`.
+
+### Desactivar el Modelo de Response
+
+Continuando con el ejemplo anterior, puede que no quieras tener la validación de datos por defecto, documentación, filtrado, etc. que realiza FastAPI.
+
+Pero puedes querer mantener la anotación del tipo de retorno en la función para obtener el soporte de herramientas como editores y verificadores de tipos (por ejemplo, mypy).
+
+En este caso, puedes desactivar la generación del modelo de response configurando `response_model=None`:
+
+{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
+
+Esto hará que FastAPI omita la generación del modelo de response y de esa manera puedes tener cualquier anotación de tipo de retorno que necesites sin que afecte a tu aplicación FastAPI. 🤓
+
+## Parámetros de codificación del Modelo de Response
+
+Tu modelo de response podría tener valores por defecto, como:
+
+{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
+
+* `description: Union[str, None] = None` (o `str | None = None` en Python 3.10) tiene un valor por defecto de `None`.
+* `tax: float = 10.5` tiene un valor por defecto de `10.5`.
+* `tags: List[str] = []` tiene un valor por defecto de una lista vacía: `[]`.
+
+pero podrías querer omitirlos del resultado si no fueron en realidad almacenados.
+
+Por ejemplo, si tienes modelos con muchos atributos opcionales en una base de datos NoSQL, pero no quieres enviar responses JSON muy largos llenos de valores por defecto.
+
+### Usa el parámetro `response_model_exclude_unset`
+
+Puedes configurar el parámetro del decorador de path operation `response_model_exclude_unset=True`:
+
+{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
+
+y esos valores por defecto no serán incluidos en el response, solo los valores realmente establecidos.
+
+Entonces, si envías un request a esa *path operation* para el ítem con ID `foo`, el response (no incluyendo valores por defecto) será:
+
+```JSON
+{
+ "name": "Foo",
+ "price": 50.2
+}
+```
+
+/// info | Información
+
+En Pydantic v1 el método se llamaba `.dict()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_dump()`.
+
+Los ejemplos aquí usan `.dict()` para compatibilidad con Pydantic v1, pero deberías usar `.model_dump()` en su lugar si puedes usar Pydantic v2.
+
+///
+
+/// info | Información
+
+FastAPI usa el método `.dict()` del modelo de Pydantic con su parámetro `exclude_unset` para lograr esto.
+
+///
+
+/// info | Información
+
+También puedes usar:
+
+* `response_model_exclude_defaults=True`
+* `response_model_exclude_none=True`
+
+como se describe en la documentación de Pydantic para `exclude_defaults` y `exclude_none`.
+
+///
+
+#### Datos con valores para campos con valores por defecto
+
+Pero si tus datos tienen valores para los campos del modelo con valores por defecto, como el artículo con ID `bar`:
+
+```Python hl_lines="3 5"
+{
+ "name": "Bar",
+ "description": "The bartenders",
+ "price": 62,
+ "tax": 20.2
+}
+```
+
+serán incluidos en el response.
+
+#### Datos con los mismos valores que los valores por defecto
+
+Si los datos tienen los mismos valores que los valores por defecto, como el artículo con ID `baz`:
+
+```Python hl_lines="3 5-6"
+{
+ "name": "Baz",
+ "description": None,
+ "price": 50.2,
+ "tax": 10.5,
+ "tags": []
+}
+```
+
+FastAPI es lo suficientemente inteligente (de hecho, Pydantic es lo suficientemente inteligente) para darse cuenta de que, a pesar de que `description`, `tax` y `tags` tienen los mismos valores que los valores por defecto, fueron establecidos explícitamente (en lugar de tomados de los valores por defecto).
+
+Por lo tanto, se incluirán en el response JSON.
+
+/// tip | Consejo
+
+Ten en cuenta que los valores por defecto pueden ser cualquier cosa, no solo `None`.
+
+Pueden ser una lista (`[]`), un `float` de `10.5`, etc.
+
+///
+
+### `response_model_include` y `response_model_exclude`
+
+También puedes usar los parámetros del decorador de path operation `response_model_include` y `response_model_exclude`.
+
+Aceptan un `set` de `str` con el nombre de los atributos a incluir (omitiendo el resto) o excluir (incluyendo el resto).
+
+Esto se puede usar como un atajo rápido si solo tienes un modelo de Pydantic y quieres eliminar algunos datos de la salida.
+
+/// tip | Consejo
+
+Pero todavía se recomienda usar las ideas anteriores, usando múltiples clases, en lugar de estos parámetros.
+
+Esto se debe a que el JSON Schema generado en el OpenAPI de tu aplicación (y la documentación) aún será el del modelo completo, incluso si usas `response_model_include` o `response_model_exclude` para omitir algunos atributos.
+
+Esto también se aplica a `response_model_by_alias` que funciona de manera similar.
+
+///
+
+{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
+
+/// tip | Consejo
+
+La sintaxis `{"name", "description"}` crea un `set` con esos dos valores.
+
+Es equivalente a `set(["name", "description"])`.
+
+///
+
+#### Usar `list`s en lugar de `set`s
+
+Si olvidas usar un `set` y usas un `list` o `tuple` en su lugar, FastAPI todavía lo convertirá a un `set` y funcionará correctamente:
+
+{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
+
+## Resumen
+
+Usa el parámetro `response_model` del *decorador de path operation* para definir modelos de response y especialmente para asegurarte de que los datos privados sean filtrados.
+
+Usa `response_model_exclude_unset` para devolver solo los valores establecidos explícitamente.
diff --git a/docs/es/docs/tutorial/response-status-code.md b/docs/es/docs/tutorial/response-status-code.md
new file mode 100644
index 000000000..92df1f4cc
--- /dev/null
+++ b/docs/es/docs/tutorial/response-status-code.md
@@ -0,0 +1,101 @@
+# Código de Estado del Response
+
+De la misma manera que puedes especificar un modelo de response, también puedes declarar el código de estado HTTP usado para el response con el parámetro `status_code` en cualquiera de las *path operations*:
+
+* `@app.get()`
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+* etc.
+
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
+
+/// note | Nota
+
+Observa que `status_code` es un parámetro del método "decorador" (`get`, `post`, etc). No de tu *path operation function*, como todos los parámetros y body.
+
+///
+
+El parámetro `status_code` recibe un número con el código de estado HTTP.
+
+/// info | Información
+
+`status_code` también puede recibir un `IntEnum`, como por ejemplo el `http.HTTPStatus` de Python.
+
+///
+
+Esto hará:
+
+* Devolver ese código de estado en el response.
+* Documentarlo como tal en el esquema de OpenAPI (y por lo tanto, en las interfaces de usuario):
+
+
+
+/// note | Nota
+
+Algunos códigos de response (ver la siguiente sección) indican que el response no tiene un body.
+
+FastAPI sabe esto, y producirá documentación OpenAPI que establece que no hay un response body.
+
+///
+
+## Acerca de los códigos de estado HTTP
+
+/// note | Nota
+
+Si ya sabes qué son los códigos de estado HTTP, salta a la siguiente sección.
+
+///
+
+En HTTP, envías un código de estado numérico de 3 dígitos como parte del response.
+
+Estos códigos de estado tienen un nombre asociado para reconocerlos, pero la parte importante es el número.
+
+En breve:
+
+* `100` y superiores son para "Información". Rara vez los usas directamente. Los responses con estos códigos de estado no pueden tener un body.
+* **`200`** y superiores son para responses "Exitosos". Estos son los que usarías más.
+ * `200` es el código de estado por defecto, lo que significa que todo estaba "OK".
+ * Otro ejemplo sería `201`, "Created". Comúnmente se usa después de crear un nuevo registro en la base de datos.
+ * Un caso especial es `204`, "No Content". Este response se usa cuando no hay contenido para devolver al cliente, por lo tanto, el response no debe tener un body.
+* **`300`** y superiores son para "Redirección". Los responses con estos códigos de estado pueden o no tener un body, excepto `304`, "Not Modified", que no debe tener uno.
+* **`400`** y superiores son para responses de "Error del Cliente". Este es el segundo tipo que probablemente más usarías.
+ * Un ejemplo es `404`, para un response "Not Found".
+ * Para errores genéricos del cliente, puedes usar simplemente `400`.
+* `500` y superiores son para errores del servidor. Casi nunca los usas directamente. Cuando algo sale mal en alguna parte de tu código de aplicación, o del servidor, automáticamente devolverá uno de estos códigos de estado.
+
+/// tip | Consejo
+
+Para saber más sobre cada código de estado y qué código es para qué, revisa la documentación de MDN sobre códigos de estado HTTP.
+
+///
+
+## Atajo para recordar los nombres
+
+Veamos de nuevo el ejemplo anterior:
+
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
+
+`201` es el código de estado para "Created".
+
+Pero no tienes que memorizar lo que significa cada uno de estos códigos.
+
+Puedes usar las variables de conveniencia de `fastapi.status`.
+
+{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
+
+Son solo una conveniencia, mantienen el mismo número, pero de esa manera puedes usar el autocompletado del editor para encontrarlos:
+
+
+
+/// note | Nota Técnica
+
+También podrías usar `from starlette import status`.
+
+**FastAPI** proporciona el mismo `starlette.status` como `fastapi.status` solo como una conveniencia para ti, el desarrollador. Pero proviene directamente de Starlette.
+
+///
+
+## Cambiando el valor por defecto
+
+Más adelante, en la [Guía de Usuario Avanzada](../advanced/response-change-status-code.md){.internal-link target=_blank}, verás cómo devolver un código de estado diferente al valor por defecto que estás declarando aquí.
diff --git a/docs/es/docs/tutorial/schema-extra-example.md b/docs/es/docs/tutorial/schema-extra-example.md
new file mode 100644
index 000000000..645060d71
--- /dev/null
+++ b/docs/es/docs/tutorial/schema-extra-example.md
@@ -0,0 +1,224 @@
+# Declarar Ejemplos de Request
+
+Puedes declarar ejemplos de los datos que tu aplicación puede recibir.
+
+Aquí tienes varias formas de hacerlo.
+
+## Datos extra de JSON Schema en modelos de Pydantic
+
+Puedes declarar `examples` para un modelo de Pydantic que se añadirá al JSON Schema generado.
+
+//// tab | Pydantic v2
+
+{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
+
+////
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
+
+////
+
+Esa información extra se añadirá tal cual al **JSON Schema** generado para ese modelo, y se usará en la documentación de la API.
+
+//// tab | Pydantic v2
+
+En Pydantic versión 2, usarías el atributo `model_config`, que toma un `dict` como se describe en la documentación de Pydantic: Configuración.
+
+Puedes establecer `"json_schema_extra"` con un `dict` que contenga cualquier dato adicional que desees que aparezca en el JSON Schema generado, incluyendo `examples`.
+
+////
+
+//// tab | Pydantic v1
+
+En Pydantic versión 1, usarías una clase interna `Config` y `schema_extra`, como se describe en la documentación de Pydantic: Personalización de Esquema.
+
+Puedes establecer `schema_extra` con un `dict` que contenga cualquier dato adicional que desees que aparezca en el JSON Schema generado, incluyendo `examples`.
+
+////
+
+/// tip | Consejo
+
+Podrías usar la misma técnica para extender el JSON Schema y añadir tu propia información extra personalizada.
+
+Por ejemplo, podrías usarlo para añadir metadatos para una interfaz de usuario frontend, etc.
+
+///
+
+/// info | Información
+
+OpenAPI 3.1.0 (usado desde FastAPI 0.99.0) añadió soporte para `examples`, que es parte del estándar de **JSON Schema**.
+
+Antes de eso, solo soportaba la palabra clave `example` con un solo ejemplo. Eso aún es soportado por OpenAPI 3.1.0, pero está obsoleto y no es parte del estándar de JSON Schema. Así que se recomienda migrar de `example` a `examples`. 🤓
+
+Puedes leer más al final de esta página.
+
+///
+
+## Argumentos adicionales en `Field`
+
+Cuando usas `Field()` con modelos de Pydantic, también puedes declarar `examples` adicionales:
+
+{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
+
+## `examples` en JSON Schema - OpenAPI
+
+Cuando usas cualquiera de:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+también puedes declarar un grupo de `examples` con información adicional que se añadirá a sus **JSON Schemas** dentro de **OpenAPI**.
+
+### `Body` con `examples`
+
+Aquí pasamos `examples` que contiene un ejemplo de los datos esperados en `Body()`:
+
+{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}
+
+### Ejemplo en la interfaz de documentación
+
+Con cualquiera de los métodos anteriores se vería así en los `/docs`:
+
+
+
+### `Body` con múltiples `examples`
+
+Por supuesto, también puedes pasar múltiples `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
+
+Cuando haces esto, los ejemplos serán parte del **JSON Schema** interno para esos datos de body.
+
+Sin embargo, al momento de escribir esto, Swagger UI, la herramienta encargada de mostrar la interfaz de documentación, no soporta mostrar múltiples ejemplos para los datos en **JSON Schema**. Pero lee más abajo para una solución alternativa.
+
+### `examples` específicos de OpenAPI
+
+Desde antes de que **JSON Schema** soportara `examples`, OpenAPI tenía soporte para un campo diferente también llamado `examples`.
+
+Estos `examples` específicos de **OpenAPI** van en otra sección en la especificación de OpenAPI. Van en los **detalles para cada *path operation***, no dentro de cada JSON Schema.
+
+Y Swagger UI ha soportado este campo particular de `examples` por un tiempo. Así que, puedes usarlo para **mostrar** diferentes **ejemplos en la interfaz de documentación**.
+
+La forma de este campo específico de OpenAPI `examples` es un `dict` con **múltiples ejemplos** (en lugar de una `list`), cada uno con información adicional que también se añadirá a **OpenAPI**.
+
+Esto no va dentro de cada JSON Schema contenido en OpenAPI, esto va afuera, directamente en la *path operation*.
+
+### Usando el Parámetro `openapi_examples`
+
+Puedes declarar los `examples` específicos de OpenAPI en FastAPI con el parámetro `openapi_examples` para:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+Las claves del `dict` identifican cada ejemplo, y cada valor es otro `dict`.
+
+Cada `dict` específico del ejemplo en los `examples` puede contener:
+
+* `summary`: Descripción corta del ejemplo.
+* `description`: Una descripción larga que puede contener texto Markdown.
+* `value`: Este es el ejemplo real mostrado, e.g. un `dict`.
+* `externalValue`: alternativa a `value`, una URL que apunta al ejemplo. Aunque esto puede no ser soportado por tantas herramientas como `value`.
+
+Puedes usarlo así:
+
+{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
+
+### Ejemplos de OpenAPI en la Interfaz de Documentación
+
+Con `openapi_examples` añadido a `Body()`, los `/docs` se verían así:
+
+
+
+## Detalles Técnicos
+
+/// tip | Consejo
+
+Si ya estás usando la versión **0.99.0 o superior** de **FastAPI**, probablemente puedes **omitir** estos detalles.
+
+Son más relevantes para versiones más antiguas, antes de que OpenAPI 3.1.0 estuviera disponible.
+
+Puedes considerar esto una breve lección de **historia** de OpenAPI y JSON Schema. 🤓
+
+///
+
+/// warning | Advertencia
+
+Estos son detalles muy técnicos sobre los estándares **JSON Schema** y **OpenAPI**.
+
+Si las ideas anteriores ya funcionan para ti, eso podría ser suficiente, y probablemente no necesites estos detalles, siéntete libre de omitirlos.
+
+///
+
+Antes de OpenAPI 3.1.0, OpenAPI usaba una versión más antigua y modificada de **JSON Schema**.
+
+JSON Schema no tenía `examples`, así que OpenAPI añadió su propio campo `example` a su versión modificada.
+
+OpenAPI también añadió los campos `example` y `examples` a otras partes de la especificación:
+
+* `Parameter Object` (en la especificación) que era usado por FastAPI:
+ * `Path()`
+ * `Query()`
+ * `Header()`
+ * `Cookie()`
+* `Request Body Object`, en el campo `content`, sobre el `Media Type Object` (en la especificación) que era usado por FastAPI:
+ * `Body()`
+ * `File()`
+ * `Form()`
+
+/// info | Información
+
+Este viejo parámetro `examples` específico de OpenAPI ahora es `openapi_examples` desde FastAPI `0.103.0`.
+
+///
+
+### Campo `examples` de JSON Schema
+
+Pero luego JSON Schema añadió un campo `examples` a una nueva versión de la especificación.
+
+Y entonces el nuevo OpenAPI 3.1.0 se basó en la última versión (JSON Schema 2020-12) que incluía este nuevo campo `examples`.
+
+Y ahora este nuevo campo `examples` tiene precedencia sobre el viejo campo único (y personalizado) `example`, que ahora está obsoleto.
+
+Este nuevo campo `examples` en JSON Schema es **solo una `list`** de ejemplos, no un dict con metadatos adicionales como en los otros lugares en OpenAPI (descritos arriba).
+
+/// info | Información
+
+Incluso después de que OpenAPI 3.1.0 fue lanzado con esta nueva integración más sencilla con JSON Schema, por un tiempo, Swagger UI, la herramienta que proporciona la documentación automática, no soportaba OpenAPI 3.1.0 (lo hace desde la versión 5.0.0 🎉).
+
+Debido a eso, las versiones de FastAPI anteriores a 0.99.0 todavía usaban versiones de OpenAPI menores a 3.1.0.
+
+///
+
+### `examples` de Pydantic y FastAPI
+
+Cuando añades `examples` dentro de un modelo de Pydantic, usando `schema_extra` o `Field(examples=["algo"])`, ese ejemplo se añade al **JSON Schema** para ese modelo de Pydantic.
+
+Y ese **JSON Schema** del modelo de Pydantic se incluye en el **OpenAPI** de tu API, y luego se usa en la interfaz de documentación.
+
+En las versiones de FastAPI antes de 0.99.0 (0.99.0 y superior usan el nuevo OpenAPI 3.1.0) cuando usabas `example` o `examples` con cualquiera de las otras utilidades (`Query()`, `Body()`, etc.) esos ejemplos no se añadían al JSON Schema que describe esos datos (ni siquiera a la propia versión de JSON Schema de OpenAPI), se añadían directamente a la declaración de la *path operation* en OpenAPI (fuera de las partes de OpenAPI que usan JSON Schema).
+
+Pero ahora que FastAPI 0.99.0 y superiores usa OpenAPI 3.1.0, que usa JSON Schema 2020-12, y Swagger UI 5.0.0 y superiores, todo es más consistente y los ejemplos se incluyen en JSON Schema.
+
+### Swagger UI y `examples` específicos de OpenAPI
+
+Ahora, como Swagger UI no soportaba múltiples ejemplos de JSON Schema (a fecha de 2023-08-26), los usuarios no tenían una forma de mostrar múltiples ejemplos en los documentos.
+
+Para resolver eso, FastAPI `0.103.0` **añadió soporte** para declarar el mismo viejo campo **específico de OpenAPI** `examples` con el nuevo parámetro `openapi_examples`. 🤓
+
+### Resumen
+
+Solía decir que no me gustaba mucho la historia... y mírame ahora dando lecciones de "historia tecnológica". 😅
+
+En resumen, **actualiza a FastAPI 0.99.0 o superior**, y las cosas son mucho **más simples, consistentes e intuitivas**, y no necesitas conocer todos estos detalles históricos. 😎
diff --git a/docs/es/docs/tutorial/security/first-steps.md b/docs/es/docs/tutorial/security/first-steps.md
new file mode 100644
index 000000000..5dbbab02a
--- /dev/null
+++ b/docs/es/docs/tutorial/security/first-steps.md
@@ -0,0 +1,203 @@
+# Seguridad - Primeros pasos
+
+Imaginemos que tienes tu API de **backend** en algún dominio.
+
+Y tienes un **frontend** en otro dominio o en un path diferente del mismo dominio (o en una aplicación móvil).
+
+Y quieres tener una forma para que el frontend se autentique con el backend, usando un **username** y **password**.
+
+Podemos usar **OAuth2** para construir eso con **FastAPI**.
+
+Pero vamos a ahorrarte el tiempo de leer la larga especificación completa solo para encontrar esos pequeños fragmentos de información que necesitas.
+
+Usemos las herramientas proporcionadas por **FastAPI** para manejar la seguridad.
+
+## Cómo se ve
+
+Primero solo usemos el código y veamos cómo funciona, y luego volveremos para entender qué está sucediendo.
+
+## Crea `main.py`
+
+Copia el ejemplo en un archivo `main.py`:
+
+{* ../../docs_src/security/tutorial001_an_py39.py *}
+
+## Ejecútalo
+
+/// info | Información
+
+El paquete `python-multipart` se instala automáticamente con **FastAPI** cuando ejecutas el comando `pip install "fastapi[standard]"`.
+
+Sin embargo, si usas el comando `pip install fastapi`, el paquete `python-multipart` no se incluye por defecto.
+
+Para instalarlo manualmente, asegúrate de crear un [entorno virtual](../../virtual-environments.md){.internal-link target=_blank}, activarlo, y luego instalarlo con:
+
+```console
+$ pip install python-multipart
+```
+
+Esto se debe a que **OAuth2** utiliza "form data" para enviar el `username` y `password`.
+
+///
+
+Ejecuta el ejemplo con:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+## Revisa
+
+Ve a la documentación interactiva en: http://127.0.0.1:8000/docs.
+
+Verás algo así:
+
+
+
+/// check | ¡Botón de autorización!
+
+Ya tienes un nuevo y brillante botón de "Authorize".
+
+Y tu *path operation* tiene un pequeño candado en la esquina superior derecha que puedes pulsar.
+
+///
+
+Y si lo haces, tendrás un pequeño formulario de autorización para escribir un `username` y `password` (y otros campos opcionales):
+
+
+
+/// note | Nota
+
+No importa lo que escribas en el formulario, aún no funcionará. Pero llegaremos allí.
+
+///
+
+Esto por supuesto no es el frontend para los usuarios finales, pero es una gran herramienta automática para documentar interactivamente toda tu API.
+
+Puede ser utilizada por el equipo de frontend (que también puedes ser tú mismo).
+
+Puede ser utilizada por aplicaciones y sistemas de terceros.
+
+Y también puede ser utilizada por ti mismo, para depurar, revisar y probar la misma aplicación.
+
+## El flujo `password`
+
+Ahora retrocedamos un poco y entendamos qué es todo eso.
+
+El "flujo" `password` es una de las formas ("flujos") definidas en OAuth2, para manejar la seguridad y la autenticación.
+
+OAuth2 fue diseñado para que el backend o la API pudieran ser independientes del servidor que autentica al usuario.
+
+Pero en este caso, la misma aplicación de **FastAPI** manejará la API y la autenticación.
+
+Así que, revisémoslo desde ese punto de vista simplificado:
+
+* El usuario escribe el `username` y `password` en el frontend, y presiona `Enter`.
+* El frontend (ejecutándose en el navegador del usuario) envía ese `username` y `password` a una URL específica en nuestra API (declarada con `tokenUrl="token"`).
+* La API verifica ese `username` y `password`, y responde con un "token" (no hemos implementado nada de esto aún).
+ * Un "token" es solo un string con algún contenido que podemos usar luego para verificar a este usuario.
+ * Normalmente, un token se establece para que expire después de algún tiempo.
+ * Así que, el usuario tendrá que volver a iniciar sesión más adelante.
+ * Y si el token es robado, el riesgo es menor. No es como una llave permanente que funcionará para siempre (en la mayoría de los casos).
+* El frontend almacena temporalmente ese token en algún lugar.
+* El usuario hace clic en el frontend para ir a otra sección de la aplicación web frontend.
+* El frontend necesita obtener más datos de la API.
+ * Pero necesita autenticación para ese endpoint específico.
+ * Así que, para autenticarse con nuestra API, envía un `header` `Authorization` con un valor de `Bearer ` más el token.
+ * Si el token contiene `foobar`, el contenido del `header` `Authorization` sería: `Bearer foobar`.
+
+## `OAuth2PasswordBearer` de **FastAPI**
+
+**FastAPI** proporciona varias herramientas, en diferentes niveles de abstracción, para implementar estas funcionalidades de seguridad.
+
+En este ejemplo vamos a usar **OAuth2**, con el flujo **Password**, usando un token **Bearer**. Hacemos eso utilizando la clase `OAuth2PasswordBearer`.
+
+/// info | Información
+
+Un token "bearer" no es la única opción.
+
+Pero es la mejor para nuestro caso de uso.
+
+Y podría ser la mejor para la mayoría de los casos de uso, a menos que seas un experto en OAuth2 y sepas exactamente por qué hay otra opción que se adapta mejor a tus necesidades.
+
+En ese caso, **FastAPI** también te proporciona las herramientas para construirlo.
+
+///
+
+Cuando creamos una instance de la clase `OAuth2PasswordBearer` pasamos el parámetro `tokenUrl`. Este parámetro contiene la URL que el cliente (el frontend corriendo en el navegador del usuario) usará para enviar el `username` y `password` a fin de obtener un token.
+
+{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
+
+/// tip | Consejo
+
+Aquí `tokenUrl="token"` se refiere a una URL relativa `token` que aún no hemos creado. Como es una URL relativa, es equivalente a `./token`.
+
+Porque estamos usando una URL relativa, si tu API estuviera ubicada en `https://example.com/`, entonces se referiría a `https://example.com/token`. Pero si tu API estuviera ubicada en `https://example.com/api/v1/`, entonces se referiría a `https://example.com/api/v1/token`.
+
+Usar una URL relativa es importante para asegurarse de que tu aplicación siga funcionando incluso en un caso de uso avanzado como [Detrás de un Proxy](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.
+
+///
+
+Este parámetro no crea ese endpoint / *path operation*, pero declara que la URL `/token` será la que el cliente deberá usar para obtener el token. Esa información se usa en OpenAPI, y luego en los sistemas de documentación interactiva del API.
+
+Pronto también crearemos la verdadera *path operation*.
+
+/// info | Información
+
+Si eres un "Pythonista" muy estricto, tal vez no te guste el estilo del nombre del parámetro `tokenUrl` en lugar de `token_url`.
+
+Eso es porque está usando el mismo nombre que en la especificación de OpenAPI. Para que si necesitas investigar más sobre cualquiera de estos esquemas de seguridad, puedas simplemente copiarlo y pegarlo para encontrar más información al respecto.
+
+///
+
+La variable `oauth2_scheme` es una instance de `OAuth2PasswordBearer`, pero también es un "callable".
+
+Podría ser llamada como:
+
+```Python
+oauth2_scheme(some, parameters)
+```
+
+Así que, puede usarse con `Depends`.
+
+### Úsalo
+
+Ahora puedes pasar ese `oauth2_scheme` en una dependencia con `Depends`.
+
+{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+
+Esta dependencia proporcionará un `str` que se asigna al parámetro `token` de la *path operation function*.
+
+**FastAPI** sabrá que puede usar esta dependencia para definir un "security scheme" en el esquema OpenAPI (y en los docs automáticos del API).
+
+/// info | Detalles técnicos
+
+**FastAPI** sabrá que puede usar la clase `OAuth2PasswordBearer` (declarada en una dependencia) para definir el esquema de seguridad en OpenAPI porque hereda de `fastapi.security.oauth2.OAuth2`, que a su vez hereda de `fastapi.security.base.SecurityBase`.
+
+Todas las utilidades de seguridad que se integran con OpenAPI (y los docs automáticos del API) heredan de `SecurityBase`, así es como **FastAPI** puede saber cómo integrarlas en OpenAPI.
+
+///
+
+## Lo que hace
+
+Irá y buscará en el request ese header `Authorization`, verificará si el valor es `Bearer ` más algún token, y devolverá el token como un `str`.
+
+Si no ve un header `Authorization`, o el valor no tiene un token `Bearer `, responderá directamente con un error de código de estado 401 (`UNAUTHORIZED`).
+
+Ni siquiera tienes que verificar si el token existe para devolver un error. Puedes estar seguro de que si tu función se ejecuta, tendrá un `str` en ese token.
+
+Puedes probarlo ya en los docs interactivos:
+
+
+
+Todavía no estamos verificando la validez del token, pero ya es un comienzo.
+
+## Resumen
+
+Así que, en solo 3 o 4 líneas adicionales, ya tienes alguna forma primitiva de seguridad.
diff --git a/docs/es/docs/tutorial/security/get-current-user.md b/docs/es/docs/tutorial/security/get-current-user.md
new file mode 100644
index 000000000..249a70c18
--- /dev/null
+++ b/docs/es/docs/tutorial/security/get-current-user.md
@@ -0,0 +1,103 @@
+# Obtener Usuario Actual
+
+En el capítulo anterior, el sistema de seguridad (que se basa en el sistema de inyección de dependencias) le estaba dando a la *path operation function* un `token` como un `str`:
+
+{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+
+Pero eso aún no es tan útil. Vamos a hacer que nos dé el usuario actual.
+
+## Crear un modelo de usuario
+
+Primero, vamos a crear un modelo de usuario con Pydantic.
+
+De la misma manera que usamos Pydantic para declarar cuerpos, podemos usarlo en cualquier otra parte:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
+
+## Crear una dependencia `get_current_user`
+
+Vamos a crear una dependencia `get_current_user`.
+
+¿Recuerdas que las dependencias pueden tener sub-dependencias?
+
+`get_current_user` tendrá una dependencia con el mismo `oauth2_scheme` que creamos antes.
+
+De la misma manera que estábamos haciendo antes en la *path operation* directamente, nuestra nueva dependencia `get_current_user` recibirá un `token` como un `str` de la sub-dependencia `oauth2_scheme`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}
+
+## Obtener el usuario
+
+`get_current_user` usará una función de utilidad (falsa) que creamos, que toma un token como un `str` y devuelve nuestro modelo de Pydantic `User`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}
+
+## Inyectar al usuario actual
+
+Entonces ahora podemos usar el mismo `Depends` con nuestro `get_current_user` en la *path operation*:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}
+
+Ten en cuenta que declaramos el tipo de `current_user` como el modelo de Pydantic `User`.
+
+Esto nos ayudará dentro de la función con todo el autocompletado y chequeo de tipos.
+
+/// tip | Consejo
+
+Tal vez recuerdes que los cuerpos de request también se declaran con modelos de Pydantic.
+
+Aquí **FastAPI** no se confundirá porque estás usando `Depends`.
+
+///
+
+/// check | Revisa
+
+El modo en que este sistema de dependencias está diseñado nos permite tener diferentes dependencias (diferentes "dependables") que todas devuelven un modelo `User`.
+
+No estamos restringidos a tener solo una dependencia que pueda devolver ese tipo de datos.
+
+///
+
+## Otros modelos
+
+Ahora puedes obtener el usuario actual directamente en las *path operation functions* y manejar los mecanismos de seguridad a nivel de **Dependency Injection**, usando `Depends`.
+
+Y puedes usar cualquier modelo o datos para los requisitos de seguridad (en este caso, un modelo de Pydantic `User`).
+
+Pero no estás limitado a usar algún modelo de datos, clase o tipo específico.
+
+¿Quieres tener un `id` y `email` y no tener un `username` en tu modelo? Claro. Puedes usar estas mismas herramientas.
+
+¿Quieres solo tener un `str`? ¿O solo un `dict`? ¿O un instance de clase modelo de base de datos directamente? Todo funciona de la misma manera.
+
+¿En realidad no tienes usuarios que inicien sesión en tu aplicación sino robots, bots u otros sistemas, que solo tienen un token de acceso? Una vez más, todo funciona igual.
+
+Usa cualquier tipo de modelo, cualquier tipo de clase, cualquier tipo de base de datos que necesites para tu aplicación. **FastAPI** te cubre con el sistema de inyección de dependencias.
+
+## Tamaño del código
+
+Este ejemplo podría parecer extenso. Ten en cuenta que estamos mezclando seguridad, modelos de datos, funciones de utilidad y *path operations* en el mismo archivo.
+
+Pero aquí está el punto clave.
+
+El tema de seguridad e inyección de dependencias se escribe una vez.
+
+Y puedes hacerlo tan complejo como desees. Y aún así, tenerlo escrito solo una vez, en un solo lugar. Con toda la flexibilidad.
+
+Pero puedes tener miles de endpoints (*path operations*) usando el mismo sistema de seguridad.
+
+Y todos ellos (o cualquier porción de ellos que quieras) pueden aprovechar la reutilización de estas dependencias o cualquier otra dependencia que crees.
+
+Y todas estas miles de *path operations* pueden ser tan pequeñas como 3 líneas:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}
+
+## Resumen
+
+Ahora puedes obtener el usuario actual directamente en tu *path operation function*.
+
+Ya estamos a mitad de camino.
+
+Solo necesitamos agregar una *path operation* para que el usuario/cliente envíe realmente el `username` y `password`.
+
+Eso es lo que viene a continuación.
diff --git a/docs/es/docs/tutorial/security/index.md b/docs/es/docs/tutorial/security/index.md
new file mode 100644
index 000000000..12e39fdaa
--- /dev/null
+++ b/docs/es/docs/tutorial/security/index.md
@@ -0,0 +1,105 @@
+# Seguridad
+
+Hay muchas formas de manejar la seguridad, autenticación y autorización.
+
+Y normalmente es un tema complejo y "difícil".
+
+En muchos frameworks y sistemas, solo manejar la seguridad y autenticación requiere una gran cantidad de esfuerzo y código (en muchos casos puede ser el 50% o más de todo el código escrito).
+
+**FastAPI** proporciona varias herramientas para ayudarte a manejar la **Seguridad** de manera fácil, rápida y estándar, sin tener que estudiar y aprender todas las especificaciones de seguridad.
+
+Pero primero, vamos a revisar algunos pequeños conceptos.
+
+## ¿Con prisa?
+
+Si no te importan ninguno de estos términos y solo necesitas agregar seguridad con autenticación basada en nombre de usuario y contraseña *ahora mismo*, salta a los siguientes capítulos.
+
+## OAuth2
+
+OAuth2 es una especificación que define varias maneras de manejar la autenticación y autorización.
+
+Es una especificación bastante extensa y cubre varios casos de uso complejos.
+
+Incluye formas de autenticarse usando un "tercero".
+
+Eso es lo que todos los sistemas con "iniciar sesión con Facebook, Google, Twitter, GitHub" utilizan internamente.
+
+### OAuth 1
+
+Hubo un OAuth 1, que es muy diferente de OAuth2, y más complejo, ya que incluía especificaciones directas sobre cómo encriptar la comunicación.
+
+No es muy popular o usado hoy en día.
+
+OAuth2 no especifica cómo encriptar la comunicación, espera que tengas tu aplicación servida con HTTPS.
+
+/// tip | Consejo
+
+En la sección sobre **deployment** verás cómo configurar HTTPS de forma gratuita, usando Traefik y Let's Encrypt.
+
+///
+
+## OpenID Connect
+
+OpenID Connect es otra especificación, basada en **OAuth2**.
+
+Solo extiende OAuth2 especificando algunas cosas que son relativamente ambiguas en OAuth2, para intentar hacerla más interoperable.
+
+Por ejemplo, el login de Google usa OpenID Connect (que internamente usa OAuth2).
+
+Pero el login de Facebook no soporta OpenID Connect. Tiene su propia versión de OAuth2.
+
+### OpenID (no "OpenID Connect")
+
+Hubo también una especificación "OpenID". Que intentaba resolver lo mismo que **OpenID Connect**, pero no estaba basada en OAuth2.
+
+Entonces, era un sistema completo adicional.
+
+No es muy popular o usado hoy en día.
+
+## OpenAPI
+
+OpenAPI (anteriormente conocido como Swagger) es la especificación abierta para construir APIs (ahora parte de la Linux Foundation).
+
+**FastAPI** se basa en **OpenAPI**.
+
+Eso es lo que hace posible tener múltiples interfaces de documentación interactiva automática, generación de código, etc.
+
+OpenAPI tiene una forma de definir múltiples "esquemas" de seguridad.
+
+Al usarlos, puedes aprovechar todas estas herramientas basadas en estándares, incluidos estos sistemas de documentación interactiva.
+
+OpenAPI define los siguientes esquemas de seguridad:
+
+* `apiKey`: una clave específica de la aplicación que puede provenir de:
+ * Un parámetro de query.
+ * Un header.
+ * Una cookie.
+* `http`: sistemas de autenticación HTTP estándar, incluyendo:
+ * `bearer`: un header `Authorization` con un valor de `Bearer ` más un token. Esto se hereda de OAuth2.
+ * Autenticación básica HTTP.
+ * Digest HTTP, etc.
+* `oauth2`: todas las formas de OAuth2 para manejar la seguridad (llamadas "flujos").
+ * Varios de estos flujos son apropiados para construir un proveedor de autenticación OAuth 2.0 (como Google, Facebook, Twitter, GitHub, etc.):
+ * `implicit`
+ * `clientCredentials`
+ * `authorizationCode`
+ * Pero hay un "flujo" específico que puede usarse perfectamente para manejar la autenticación directamente en la misma aplicación:
+ * `password`: algunos de los próximos capítulos cubrirán ejemplos de esto.
+* `openIdConnect`: tiene una forma de definir cómo descubrir automáticamente los datos de autenticación OAuth2.
+ * Este descubrimiento automático es lo que se define en la especificación de OpenID Connect.
+
+/// tip | Consejo
+
+Integrar otros proveedores de autenticación/autorización como Google, Facebook, Twitter, GitHub, etc. también es posible y relativamente fácil.
+
+El problema más complejo es construir un proveedor de autenticación/autorización como esos, pero **FastAPI** te da las herramientas para hacerlo fácilmente, mientras hace el trabajo pesado por ti.
+
+///
+
+## Utilidades de **FastAPI**
+
+FastAPI proporciona varias herramientas para cada uno de estos esquemas de seguridad en el módulo `fastapi.security` que simplifican el uso de estos mecanismos de seguridad.
+
+En los siguientes capítulos verás cómo agregar seguridad a tu API usando esas herramientas proporcionadas por **FastAPI**.
+
+Y también verás cómo se integra automáticamente en el sistema de documentación interactiva.
diff --git a/docs/es/docs/tutorial/security/oauth2-jwt.md b/docs/es/docs/tutorial/security/oauth2-jwt.md
new file mode 100644
index 000000000..4ab9c8ca2
--- /dev/null
+++ b/docs/es/docs/tutorial/security/oauth2-jwt.md
@@ -0,0 +1,273 @@
+# OAuth2 con Password (y hashing), Bearer con tokens JWT
+
+Ahora que tenemos todo el flujo de seguridad, hagamos que la aplicación sea realmente segura, usando tokens JWT y hashing de contraseñas seguras.
+
+Este código es algo que puedes usar realmente en tu aplicación, guardar los hashes de las contraseñas en tu base de datos, etc.
+
+Vamos a empezar desde donde lo dejamos en el capítulo anterior e incrementarlo.
+
+## Acerca de JWT
+
+JWT significa "JSON Web Tokens".
+
+Es un estándar para codificar un objeto JSON en un string largo y denso sin espacios. Se ve así:
+
+```
+eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
+```
+
+No está encriptado, por lo que cualquiera podría recuperar la información de los contenidos.
+
+Pero está firmado. Así que, cuando recibes un token que has emitido, puedes verificar que realmente lo emitiste.
+
+De esta manera, puedes crear un token con una expiración de, digamos, 1 semana. Y luego, cuando el usuario regresa al día siguiente con el token, sabes que el usuario todavía está registrado en tu sistema.
+
+Después de una semana, el token estará expirado y el usuario no estará autorizado y tendrá que iniciar sesión nuevamente para obtener un nuevo token. Y si el usuario (o un tercero) intenta modificar el token para cambiar la expiración, podrás descubrirlo, porque las firmas no coincidirían.
+
+Si quieres jugar con tokens JWT y ver cómo funcionan, revisa https://jwt.io.
+
+## Instalar `PyJWT`
+
+Necesitamos instalar `PyJWT` para generar y verificar los tokens JWT en Python.
+
+Asegúrate de crear un [entorno virtual](../../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalar `pyjwt`:
+
+
+
+/// info | Información
+
+Si planeas usar algoritmos de firma digital como RSA o ECDSA, deberías instalar la dependencia del paquete de criptografía `pyjwt[crypto]`.
+
+Puedes leer más al respecto en la documentación de instalación de PyJWT.
+
+///
+
+## Hashing de contraseñas
+
+"Hacer hashing" significa convertir algún contenido (una contraseña en este caso) en una secuencia de bytes (solo un string) que parece un galimatías.
+
+Siempre que pases exactamente el mismo contenido (exactamente la misma contraseña) obtienes exactamente el mismo galimatías.
+
+Pero no puedes convertir del galimatías de nuevo a la contraseña.
+
+### Por qué usar hashing de contraseñas
+
+Si tu base de datos es robada, el ladrón no tendrá las contraseñas en texto claro de tus usuarios, solo los hashes.
+
+Por lo tanto, el ladrón no podrá intentar usar esa contraseña en otro sistema (como muchos usuarios usan la misma contraseña en todas partes, esto sería peligroso).
+
+## Instalar `passlib`
+
+PassLib es un gran paquete de Python para manejar hashes de contraseñas.
+
+Soporta muchos algoritmos de hashing seguros y utilidades para trabajar con ellos.
+
+El algoritmo recomendado es "Bcrypt".
+
+Asegúrate de crear un [entorno virtual](../../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalar PassLib con Bcrypt:
+
+
+
+/// tip | Consejo
+
+Con `passlib`, incluso podrías configurarlo para poder leer contraseñas creadas por **Django**, un plug-in de seguridad de **Flask** u otros muchos.
+
+Así, podrías, por ejemplo, compartir los mismos datos de una aplicación de Django en una base de datos con una aplicación de FastAPI. O migrar gradualmente una aplicación de Django usando la misma base de datos.
+
+Y tus usuarios podrían iniciar sesión desde tu aplicación Django o desde tu aplicación **FastAPI**, al mismo tiempo.
+
+///
+
+## Hash y verificación de contraseñas
+
+Importa las herramientas que necesitamos de `passlib`.
+
+Crea un "contexto" de PassLib. Este es el que se usará para hacer el hash y verificar las contraseñas.
+
+/// tip | Consejo
+
+El contexto de PassLib también tiene funcionalidad para usar diferentes algoritmos de hashing, incluidos los antiguos obsoletos solo para permitir verificarlos, etc.
+
+Por ejemplo, podrías usarlo para leer y verificar contraseñas generadas por otro sistema (como Django) pero hacer hash de cualquier contraseña nueva con un algoritmo diferente como Bcrypt.
+
+Y ser compatible con todos ellos al mismo tiempo.
+
+///
+
+Crea una función de utilidad para hacer el hash de una contraseña que venga del usuario.
+
+Y otra utilidad para verificar si una contraseña recibida coincide con el hash almacenado.
+
+Y otra más para autenticar y devolver un usuario.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+
+/// note | Nota
+
+Si revisas la nueva (falsa) base de datos `fake_users_db`, verás cómo se ve ahora la contraseña con hash: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
+
+///
+
+## Manejo de tokens JWT
+
+Importa los módulos instalados.
+
+Crea una clave secreta aleatoria que se usará para firmar los tokens JWT.
+
+Para generar una clave secreta segura al azar usa el comando:
+
+
+
+Y copia el resultado a la variable `SECRET_KEY` (no uses la del ejemplo).
+
+Crea una variable `ALGORITHM` con el algoritmo usado para firmar el token JWT y configúralo a `"HS256"`.
+
+Crea una variable para la expiración del token.
+
+Define un Modelo de Pydantic que se usará en el endpoint de token para el response.
+
+Crea una función de utilidad para generar un nuevo token de acceso.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+
+## Actualizar las dependencias
+
+Actualiza `get_current_user` para recibir el mismo token que antes, pero esta vez, usando tokens JWT.
+
+Decodifica el token recibido, verifícalo y devuelve el usuario actual.
+
+Si el token es inválido, devuelve un error HTTP de inmediato.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+
+## Actualizar la *path operation* `/token`
+
+Crea un `timedelta` con el tiempo de expiración del token.
+
+Crea un verdadero token de acceso JWT y devuélvelo.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+
+### Detalles técnicos sobre el "sujeto" `sub` de JWT
+
+La especificación de JWT dice que hay una clave `sub`, con el sujeto del token.
+
+Es opcional usarlo, pero ahí es donde pondrías la identificación del usuario, por lo que lo estamos usando aquí.
+
+JWT podría ser usado para otras cosas aparte de identificar un usuario y permitirle realizar operaciones directamente en tu API.
+
+Por ejemplo, podrías identificar un "coche" o un "artículo de blog".
+
+Luego, podrías agregar permisos sobre esa entidad, como "conducir" (para el coche) o "editar" (para el blog).
+
+Y luego, podrías darle ese token JWT a un usuario (o bot), y ellos podrían usarlo para realizar esas acciones (conducir el coche, o editar el artículo del blog) sin siquiera necesitar tener una cuenta, solo con el token JWT que tu API generó para eso.
+
+Usando estas ideas, JWT puede ser utilizado para escenarios mucho más sofisticados.
+
+En esos casos, varias de esas entidades podrían tener el mismo ID, digamos `foo` (un usuario `foo`, un coche `foo`, y un artículo del blog `foo`).
+
+Entonces, para evitar colisiones de ID, cuando crees el token JWT para el usuario, podrías prefijar el valor de la clave `sub`, por ejemplo, con `username:`. Así, en este ejemplo, el valor de `sub` podría haber sido: `username:johndoe`.
+
+Lo importante a tener en cuenta es que la clave `sub` debería tener un identificador único a lo largo de toda la aplicación, y debería ser un string.
+
+## Revisa
+
+Ejecuta el servidor y ve a la documentación: http://127.0.0.1:8000/docs.
+
+Verás la interfaz de usuario como:
+
+
+
+Autoriza la aplicación de la misma manera que antes.
+
+Usando las credenciales:
+
+Usuario: `johndoe`
+Contraseña: `secret`
+
+/// check | Revisa
+
+Observa que en ninguna parte del código está la contraseña en texto claro "`secret`", solo tenemos la versión con hash.
+
+///
+
+
+
+Llama al endpoint `/users/me/`, obtendrás el response como:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false
+}
+```
+
+
+
+Si abres las herramientas de desarrollador, podrías ver cómo los datos enviados solo incluyen el token, la contraseña solo se envía en la primera petición para autenticar al usuario y obtener ese token de acceso, pero no después:
+
+
+
+/// note | Nota
+
+Observa el header `Authorization`, con un valor que comienza con `Bearer `.
+
+///
+
+## Uso avanzado con `scopes`
+
+OAuth2 tiene la noción de "scopes".
+
+Puedes usarlos para agregar un conjunto específico de permisos a un token JWT.
+
+Luego, puedes darle este token directamente a un usuario o a un tercero, para interactuar con tu API con un conjunto de restricciones.
+
+Puedes aprender cómo usarlos y cómo están integrados en **FastAPI** más adelante en la **Guía de Usuario Avanzada**.
+
+## Resumen
+
+Con lo que has visto hasta ahora, puedes configurar una aplicación **FastAPI** segura usando estándares como OAuth2 y JWT.
+
+En casi cualquier framework el manejo de la seguridad se convierte en un tema bastante complejo rápidamente.
+
+Muchos paquetes que lo simplifican tienen que hacer muchos compromisos con el modelo de datos, la base de datos y las funcionalidades disponibles. Y algunos de estos paquetes que simplifican las cosas demasiado en realidad tienen fallos de seguridad en el fondo.
+
+---
+
+**FastAPI** no hace ningún compromiso con ninguna base de datos, modelo de datos o herramienta.
+
+Te da toda la flexibilidad para elegir aquellas que se ajusten mejor a tu proyecto.
+
+Y puedes usar directamente muchos paquetes bien mantenidos y ampliamente usados como `passlib` y `PyJWT`, porque **FastAPI** no requiere mecanismos complejos para integrar paquetes externos.
+
+Pero te proporciona las herramientas para simplificar el proceso tanto como sea posible sin comprometer la flexibilidad, la robustez o la seguridad.
+
+Y puedes usar e implementar protocolos seguros y estándar, como OAuth2 de una manera relativamente simple.
+
+Puedes aprender más en la **Guía de Usuario Avanzada** sobre cómo usar "scopes" de OAuth2, para un sistema de permisos más detallado, siguiendo estos mismos estándares. OAuth2 con scopes es el mecanismo utilizado por muchos grandes proveedores de autenticación, como Facebook, Google, GitHub, Microsoft, Twitter, etc. para autorizar aplicaciones de terceros para interactuar con sus APIs en nombre de sus usuarios.
diff --git a/docs/es/docs/tutorial/security/simple-oauth2.md b/docs/es/docs/tutorial/security/simple-oauth2.md
new file mode 100644
index 000000000..67449332f
--- /dev/null
+++ b/docs/es/docs/tutorial/security/simple-oauth2.md
@@ -0,0 +1,289 @@
+# Simple OAuth2 con Password y Bearer
+
+Ahora vamos a construir a partir del capítulo anterior y agregar las partes faltantes para tener un flujo de seguridad completo.
+
+## Obtener el `username` y `password`
+
+Vamos a usar las utilidades de seguridad de **FastAPI** para obtener el `username` y `password`.
+
+OAuth2 especifica que cuando se utiliza el "password flow" (que estamos usando), el cliente/usuario debe enviar campos `username` y `password` como form data.
+
+Y la especificación dice que los campos deben llamarse así. Por lo que `user-name` o `email` no funcionarían.
+
+Pero no te preocupes, puedes mostrarlo como quieras a tus usuarios finales en el frontend.
+
+Y tus modelos de base de datos pueden usar cualquier otro nombre que desees.
+
+Pero para la *path operation* de inicio de sesión, necesitamos usar estos nombres para ser compatibles con la especificación (y poder, por ejemplo, utilizar el sistema de documentación integrada de la API).
+
+La especificación también establece que el `username` y `password` deben enviarse como form data (por lo que no hay JSON aquí).
+
+### `scope`
+
+La especificación también indica que el cliente puede enviar otro campo del formulario llamado "`scope`".
+
+El nombre del campo del formulario es `scope` (en singular), pero en realidad es un string largo con "scopes" separados por espacios.
+
+Cada "scope" es simplemente un string (sin espacios).
+
+Normalmente se utilizan para declarar permisos de seguridad específicos, por ejemplo:
+
+* `users:read` o `users:write` son ejemplos comunes.
+* `instagram_basic` es usado por Facebook / Instagram.
+* `https://www.googleapis.com/auth/drive` es usado por Google.
+
+/// info | Información
+
+En OAuth2 un "scope" es solo un string que declara un permiso específico requerido.
+
+No importa si tiene otros caracteres como `:` o si es una URL.
+
+Esos detalles son específicos de la implementación.
+
+Para OAuth2 son solo strings.
+
+///
+
+## Código para obtener el `username` y `password`
+
+Ahora vamos a usar las utilidades proporcionadas por **FastAPI** para manejar esto.
+
+### `OAuth2PasswordRequestForm`
+
+Primero, importa `OAuth2PasswordRequestForm`, y úsalo como una dependencia con `Depends` en la *path operation* para `/token`:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
+
+`OAuth2PasswordRequestForm` es una dependencia de clase que declara un body de formulario con:
+
+* El `username`.
+* El `password`.
+* Un campo opcional `scope` como un string grande, compuesto por strings separados por espacios.
+* Un `grant_type` opcional.
+
+/// tip | Consejo
+
+La especificación de OAuth2 en realidad *requiere* un campo `grant_type` con un valor fijo de `password`, pero `OAuth2PasswordRequestForm` no lo obliga.
+
+Si necesitas imponerlo, utiliza `OAuth2PasswordRequestFormStrict` en lugar de `OAuth2PasswordRequestForm`.
+
+///
+
+* Un `client_id` opcional (no lo necesitamos para nuestro ejemplo).
+* Un `client_secret` opcional (no lo necesitamos para nuestro ejemplo).
+
+/// info | Información
+
+`OAuth2PasswordRequestForm` no es una clase especial para **FastAPI** como lo es `OAuth2PasswordBearer`.
+
+`OAuth2PasswordBearer` hace que **FastAPI** sepa que es un esquema de seguridad. Así que se añade de esa manera a OpenAPI.
+
+Pero `OAuth2PasswordRequestForm` es solo una dependencia de clase que podrías haber escrito tú mismo, o podrías haber declarado parámetros de `Form` directamente.
+
+Pero como es un caso de uso común, se proporciona directamente por **FastAPI**, solo para facilitarlo.
+
+///
+
+### Usa el form data
+
+/// tip | Consejo
+
+La instance de la clase de dependencia `OAuth2PasswordRequestForm` no tendrá un atributo `scope` con el string largo separado por espacios, en su lugar, tendrá un atributo `scopes` con la lista real de strings para cada scope enviado.
+
+No estamos usando `scopes` en este ejemplo, pero la funcionalidad está ahí si la necesitas.
+
+///
+
+Ahora, obtén los datos del usuario desde la base de datos (falsa), usando el `username` del campo del form.
+
+Si no existe tal usuario, devolvemos un error diciendo "Incorrect username or password".
+
+Para el error, usamos la excepción `HTTPException`:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}
+
+### Revisa el password
+
+En este punto tenemos los datos del usuario de nuestra base de datos, pero no hemos revisado el password.
+
+Primero pongamos esos datos en el modelo `UserInDB` de Pydantic.
+
+Nunca deberías guardar passwords en texto plano, así que, usaremos el sistema de hash de passwords (falso).
+
+Si los passwords no coinciden, devolvemos el mismo error.
+
+#### Hashing de passwords
+
+"Hacer hash" significa: convertir algún contenido (un password en este caso) en una secuencia de bytes (solo un string) que parece un galimatías.
+
+Siempre que pases exactamente el mismo contenido (exactamente el mismo password) obtienes exactamente el mismo galimatías.
+
+Pero no puedes convertir del galimatías al password.
+
+##### Por qué usar hashing de passwords
+
+Si tu base de datos es robada, el ladrón no tendrá los passwords en texto plano de tus usuarios, solo los hashes.
+
+Entonces, el ladrón no podrá intentar usar esos mismos passwords en otro sistema (como muchos usuarios usan el mismo password en todas partes, esto sería peligroso).
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}
+
+#### Sobre `**user_dict`
+
+`UserInDB(**user_dict)` significa:
+
+*Pasa las claves y valores de `user_dict` directamente como argumentos clave-valor, equivalente a:*
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ disabled = user_dict["disabled"],
+ hashed_password = user_dict["hashed_password"],
+)
+```
+
+/// info | Información
+
+Para una explicación más completa de `**user_dict` revisa en [la documentación para **Extra Models**](../extra-models.md#about-user_indict){.internal-link target=_blank}.
+
+///
+
+## Devolver el token
+
+El response del endpoint `token` debe ser un objeto JSON.
+
+Debe tener un `token_type`. En nuestro caso, como estamos usando tokens "Bearer", el tipo de token debe ser "`bearer`".
+
+Y debe tener un `access_token`, con un string que contenga nuestro token de acceso.
+
+Para este ejemplo simple, vamos a ser completamente inseguros y devolver el mismo `username` como el token.
+
+/// tip | Consejo
+
+En el próximo capítulo, verás una implementación segura real, con hashing de passwords y tokens JWT.
+
+Pero por ahora, enfoquémonos en los detalles específicos que necesitamos.
+
+///
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}
+
+/// tip | Consejo
+
+De acuerdo con la especificación, deberías devolver un JSON con un `access_token` y un `token_type`, igual que en este ejemplo.
+
+Esto es algo que tienes que hacer tú mismo en tu código, y asegurarte de usar esas claves JSON.
+
+Es casi lo único que tienes que recordar hacer correctamente tú mismo, para ser compatible con las especificaciones.
+
+Para el resto, **FastAPI** lo maneja por ti.
+
+///
+
+## Actualizar las dependencias
+
+Ahora vamos a actualizar nuestras dependencias.
+
+Queremos obtener el `current_user` *solo* si este usuario está activo.
+
+Entonces, creamos una dependencia adicional `get_current_active_user` que a su vez utiliza `get_current_user` como dependencia.
+
+Ambas dependencias solo devolverán un error HTTP si el usuario no existe, o si está inactivo.
+
+Así que, en nuestro endpoint, solo obtendremos un usuario si el usuario existe, fue autenticado correctamente, y está activo:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
+
+/// info | Información
+
+El header adicional `WWW-Authenticate` con el valor `Bearer` que estamos devolviendo aquí también es parte de la especificación.
+
+Cualquier código de estado HTTP (error) 401 "UNAUTHORIZED" se supone que también debe devolver un header `WWW-Authenticate`.
+
+En el caso de tokens bearer (nuestro caso), el valor de ese header debe ser `Bearer`.
+
+De hecho, puedes omitir ese header extra y aún funcionaría.
+
+Pero se proporciona aquí para cumplir con las especificaciones.
+
+Además, podría haber herramientas que lo esperen y lo usen (ahora o en el futuro) y eso podría ser útil para ti o tus usuarios, ahora o en el futuro.
+
+Ese es el beneficio de los estándares...
+
+///
+
+## Verlo en acción
+
+Abre la documentación interactiva: http://127.0.0.1:8000/docs.
+
+### Autenticar
+
+Haz clic en el botón "Authorize".
+
+Usa las credenciales:
+
+Usuario: `johndoe`
+
+Contraseña: `secret`
+
+
+
+Después de autenticarte en el sistema, lo verás así:
+
+
+
+### Obtener tus propios datos de usuario
+
+Ahora usa la operación `GET` con la path `/users/me`.
+
+Obtendrás los datos de tu usuario, como:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false,
+ "hashed_password": "fakehashedsecret"
+}
+```
+
+
+
+Si haces clic en el icono de candado y cierras sesión, y luego intentas la misma operación nuevamente, obtendrás un error HTTP 401 de:
+
+```JSON
+{
+ "detail": "Not authenticated"
+}
+```
+
+### Usuario inactivo
+
+Ahora prueba con un usuario inactivo, autentícate con:
+
+Usuario: `alice`
+
+Contraseña: `secret2`
+
+Y trata de usar la operación `GET` con la path `/users/me`.
+
+Obtendrás un error de "Usuario inactivo", como:
+
+```JSON
+{
+ "detail": "Inactive user"
+}
+```
+
+## Recapitulación
+
+Ahora tienes las herramientas para implementar un sistema de seguridad completo basado en `username` y `password` para tu API.
+
+Usando estas herramientas, puedes hacer que el sistema de seguridad sea compatible con cualquier base de datos y con cualquier modelo de usuario o de datos.
+
+El único detalle que falta es que en realidad no es "seguro" aún.
+
+En el próximo capítulo verás cómo usar un paquete de hashing de passwords seguro y tokens JWT.
diff --git a/docs/es/docs/tutorial/sql-databases.md b/docs/es/docs/tutorial/sql-databases.md
new file mode 100644
index 000000000..68cc78603
--- /dev/null
+++ b/docs/es/docs/tutorial/sql-databases.md
@@ -0,0 +1,360 @@
+# Bases de Datos SQL (Relacionales)
+
+**FastAPI** no requiere que uses una base de datos SQL (relacional). Pero puedes utilizar **cualquier base de datos** que desees.
+
+Aquí veremos un ejemplo usando SQLModel.
+
+**SQLModel** está construido sobre SQLAlchemy y Pydantic. Fue creado por el mismo autor de **FastAPI** para ser la combinación perfecta para aplicaciones de FastAPI que necesiten usar **bases de datos SQL**.
+
+/// tip | Consejo
+
+Puedes usar cualquier otro paquete de bases de datos SQL o NoSQL que quieras (en algunos casos llamadas "ORMs"), FastAPI no te obliga a usar nada. 😎
+
+///
+
+Como SQLModel se basa en SQLAlchemy, puedes usar fácilmente **cualquier base de datos soportada** por SQLAlchemy (lo que las hace también soportadas por SQLModel), como:
+
+* PostgreSQL
+* MySQL
+* SQLite
+* Oracle
+* Microsoft SQL Server, etc.
+
+En este ejemplo, usaremos **SQLite**, porque utiliza un solo archivo y Python tiene soporte integrado. Así que puedes copiar este ejemplo y ejecutarlo tal cual.
+
+Más adelante, para tu aplicación en producción, es posible que desees usar un servidor de base de datos como **PostgreSQL**.
+
+/// tip | Consejo
+
+Hay un generador de proyectos oficial con **FastAPI** y **PostgreSQL** que incluye un frontend y más herramientas: https://github.com/fastapi/full-stack-fastapi-template
+
+///
+
+Este es un tutorial muy simple y corto, si deseas aprender sobre bases de datos en general, sobre SQL o más funcionalidades avanzadas, ve a la documentación de SQLModel.
+
+## Instalar `SQLModel`
+
+Primero, asegúrate de crear tu [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, actívalo, y luego instala `sqlmodel`:
+
+
+
+## Crear la App con un Solo Modelo
+
+Primero crearemos la versión más simple de la aplicación con un solo modelo de **SQLModel**.
+
+Más adelante la mejoraremos aumentando la seguridad y versatilidad con **múltiples modelos** a continuación. 🤓
+
+### Crear Modelos
+
+Importa `SQLModel` y crea un modelo de base de datos:
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
+
+La clase `Hero` es muy similar a un modelo de Pydantic (de hecho, en el fondo, realmente *es un modelo de Pydantic*).
+
+Hay algunas diferencias:
+
+* `table=True` le dice a SQLModel que este es un *modelo de tabla*, que debe representar una **tabla** en la base de datos SQL, no es solo un *modelo de datos* (como lo sería cualquier otra clase regular de Pydantic).
+
+* `Field(primary_key=True)` le dice a SQLModel que `id` es la **clave primaria** en la base de datos SQL (puedes aprender más sobre claves primarias de SQL en la documentación de SQLModel).
+
+ Al tener el tipo como `int | None`, SQLModel sabrá que esta columna debe ser un `INTEGER` en la base de datos SQL y que debe ser `NULLABLE`.
+
+* `Field(index=True)` le dice a SQLModel que debe crear un **índice SQL** para esta columna, lo que permitirá búsquedas más rápidas en la base de datos cuando se lean datos filtrados por esta columna.
+
+ SQLModel sabrá que algo declarado como `str` será una columna SQL de tipo `TEXT` (o `VARCHAR`, dependiendo de la base de datos).
+
+### Crear un Engine
+
+Un `engine` de SQLModel (en el fondo, realmente es un `engine` de SQLAlchemy) es lo que **mantiene las conexiones** a la base de datos.
+
+Tendrías **un solo objeto `engine`** para todo tu código para conectar a la misma base de datos.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
+
+Usar `check_same_thread=False` permite a FastAPI usar la misma base de datos SQLite en diferentes hilos. Esto es necesario ya que **una sola request** podría usar **más de un hilo** (por ejemplo, en dependencias).
+
+No te preocupes, con la forma en que está estructurado el código, nos aseguraremos de usar **una sola *session* de SQLModel por request** más adelante, esto es realmente lo que intenta lograr el `check_same_thread`.
+
+### Crear las Tablas
+
+Luego añadimos una función que usa `SQLModel.metadata.create_all(engine)` para **crear las tablas** para todos los *modelos de tabla*.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
+
+### Crear una Dependencia de Session
+
+Una **`Session`** es lo que almacena los **objetos en memoria** y lleva un seguimiento de cualquier cambio necesario en los datos, luego **usa el `engine`** para comunicarse con la base de datos.
+
+Crearemos una **dependencia de FastAPI** con `yield` que proporcionará una nueva `Session` para cada request. Esto es lo que asegura que usemos una sola session por request. 🤓
+
+Luego creamos una dependencia `Annotated` `SessionDep` para simplificar el resto del código que usará esta dependencia.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
+
+### Crear Tablas de Base de Datos al Arrancar
+
+Crearemos las tablas de la base de datos cuando arranque la aplicación.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
+
+Aquí creamos las tablas en un evento de inicio de la aplicación.
+
+Para producción probablemente usarías un script de migración que se ejecuta antes de iniciar tu aplicación. 🤓
+
+/// tip | Consejo
+
+SQLModel tendrá utilidades de migración envolviendo Alembic, pero por ahora, puedes usar Alembic directamente.
+
+///
+
+### Crear un Hero
+
+Debido a que cada modelo de SQLModel también es un modelo de Pydantic, puedes usarlo en las mismas **anotaciones de tipos** que podrías usar en modelos de Pydantic.
+
+Por ejemplo, si declaras un parámetro de tipo `Hero`, será leído desde el **JSON body**.
+
+De la misma manera, puedes declararlo como el **tipo de retorno** de la función, y luego la forma de los datos aparecerá en la interfaz automática de documentación de la API.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
+
+
+
+Aquí usamos la dependencia `SessionDep` (una `Session`) para añadir el nuevo `Hero` a la instance `Session`, comiteamos los cambios a la base de datos, refrescamos los datos en el `hero` y luego lo devolvemos.
+
+### Leer Heroes
+
+Podemos **leer** `Hero`s de la base de datos usando un `select()`. Podemos incluir un `limit` y `offset` para paginar los resultados.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
+
+### Leer Un Hero
+
+Podemos **leer** un único `Hero`.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
+
+### Eliminar un Hero
+
+También podemos **eliminar** un `Hero`.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
+
+### Ejecutar la App
+
+Puedes ejecutar la aplicación:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Luego dirígete a la interfaz de `/docs`, verás que **FastAPI** está usando estos **modelos** para **documentar** la API, y los usará para **serializar** y **validar** los datos también.
+
+
+
+
+
+## Actualizar la App con Múltiples Modelos
+
+Ahora vamos a **refactorizar** un poco esta aplicación para aumentar la **seguridad** y la **versatilidad**.
+
+Si revisas la aplicación anterior, en la interfaz verás que, hasta ahora, permite al cliente decidir el `id` del `Hero` a crear. 😱
+
+No deberíamos permitir que eso suceda, podrían sobrescribir un `id` que ya tenemos asignado en la base de datos. Decidir el `id` debería ser tarea del **backend** o la **base de datos**, **no del cliente**.
+
+Además, creamos un `secret_name` para el héroe, pero hasta ahora, lo estamos devolviendo en todas partes, eso no es muy **secreto**... 😅
+
+Arreglaremos estas cosas añadiendo unos **modelos extra**. Aquí es donde SQLModel brillará. ✨
+
+### Crear Múltiples Modelos
+
+En **SQLModel**, cualquier clase de modelo que tenga `table=True` es un **modelo de tabla**.
+
+Y cualquier clase de modelo que no tenga `table=True` es un **modelo de datos**, estos son en realidad solo modelos de Pydantic (con un par de características extra pequeñas). 🤓
+
+Con SQLModel, podemos usar **herencia** para **evitar duplicar** todos los campos en todos los casos.
+
+#### `HeroBase` - la clase base
+
+Comencemos con un modelo `HeroBase` que tiene todos los **campos que son compartidos** por todos los modelos:
+
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
+
+#### `Hero` - el *modelo de tabla*
+
+Luego, crearemos `Hero`, el *modelo de tabla* real, con los **campos extra** que no siempre están en los otros modelos:
+
+* `id`
+* `secret_name`
+
+Debido a que `Hero` hereda de `HeroBase`, **también** tiene los **campos** declarados en `HeroBase`, por lo que todos los campos para `Hero` son:
+
+* `id`
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
+
+#### `HeroPublic` - el *modelo de datos* público
+
+A continuación, creamos un modelo `HeroPublic`, este es el que será **devuelto** a los clientes de la API.
+
+Tiene los mismos campos que `HeroBase`, por lo que no incluirá `secret_name`.
+
+Por fin, la identidad de nuestros héroes está protegida! 🥷
+
+También vuelve a declarar `id: int`. Al hacer esto, estamos haciendo un **contrato** con los clientes de la API, para que siempre puedan esperar que el `id` esté allí y sea un `int` (nunca será `None`).
+
+/// tip | Consejo
+
+Tener el modelo de retorno asegurando que un valor siempre esté disponible y siempre sea `int` (no `None`) es muy útil para los clientes de la API, pueden escribir código mucho más simple teniendo esta certeza.
+
+Además, los **clientes generados automáticamente** tendrán interfaces más simples, para que los desarrolladores que se comuniquen con tu API puedan tener una experiencia mucho mejor trabajando con tu API. 😎
+
+///
+
+Todos los campos en `HeroPublic` son los mismos que en `HeroBase`, con `id` declarado como `int` (no `None`):
+
+* `id`
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
+
+#### `HeroCreate` - el *modelo de datos* para crear un héroe
+
+Ahora creamos un modelo `HeroCreate`, este es el que **validará** los datos de los clientes.
+
+Tiene los mismos campos que `HeroBase`, y también tiene `secret_name`.
+
+Ahora, cuando los clientes **crean un nuevo héroe**, enviarán el `secret_name`, se almacenará en la base de datos, pero esos nombres secretos no se devolverán en la API a los clientes.
+
+/// tip | Consejo
+
+Esta es la forma en la que manejarías **contraseñas**. Recíbelas, pero no las devuelvas en la API.
+
+También **hashea** los valores de las contraseñas antes de almacenarlos, **nunca los almacenes en texto plano**.
+
+///
+
+Los campos de `HeroCreate` son:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
+
+#### `HeroUpdate` - el *modelo de datos* para actualizar un héroe
+
+No teníamos una forma de **actualizar un héroe** en la versión anterior de la aplicación, pero ahora con **múltiples modelos**, podemos hacerlo. 🎉
+
+El *modelo de datos* `HeroUpdate` es algo especial, tiene **todos los mismos campos** que serían necesarios para crear un nuevo héroe, pero todos los campos son **opcionales** (todos tienen un valor por defecto). De esta forma, cuando actualices un héroe, puedes enviar solo los campos que deseas actualizar.
+
+Debido a que todos los **campos realmente cambian** (el tipo ahora incluye `None` y ahora tienen un valor por defecto de `None`), necesitamos **volver a declararlos**.
+
+Realmente no necesitamos heredar de `HeroBase` porque estamos volviendo a declarar todos los campos. Lo dejaré heredando solo por consistencia, pero esto no es necesario. Es más una cuestión de gusto personal. 🤷
+
+Los campos de `HeroUpdate` son:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
+
+### Crear con `HeroCreate` y devolver un `HeroPublic`
+
+Ahora que tenemos **múltiples modelos**, podemos actualizar las partes de la aplicación que los usan.
+
+Recibimos en la request un *modelo de datos* `HeroCreate`, y a partir de él, creamos un *modelo de tabla* `Hero`.
+
+Este nuevo *modelo de tabla* `Hero` tendrá los campos enviados por el cliente, y también tendrá un `id` generado por la base de datos.
+
+Luego devolvemos el mismo *modelo de tabla* `Hero` tal cual desde la función. Pero como declaramos el `response_model` con el *modelo de datos* `HeroPublic`, **FastAPI** usará `HeroPublic` para validar y serializar los datos.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
+
+/// tip | Consejo
+
+Ahora usamos `response_model=HeroPublic` en lugar de la **anotación de tipo de retorno** `-> HeroPublic` porque el valor que estamos devolviendo en realidad *no* es un `HeroPublic`.
+
+Si hubiéramos declarado `-> HeroPublic`, tu editor y linter se quejarían (con razón) de que estás devolviendo un `Hero` en lugar de un `HeroPublic`.
+
+Al declararlo en `response_model` le estamos diciendo a **FastAPI** que haga lo suyo, sin interferir con las anotaciones de tipo y la ayuda de tu editor y otras herramientas.
+
+///
+
+### Leer Heroes con `HeroPublic`
+
+Podemos hacer lo mismo que antes para **leer** `Hero`s, nuevamente, usamos `response_model=list[HeroPublic]` para asegurar que los datos se validen y serialicen correctamente.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
+
+### Leer Un Hero con `HeroPublic`
+
+Podemos **leer** un único héroe:
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
+
+### Actualizar un Hero con `HeroUpdate`
+
+Podemos **actualizar un héroe**. Para esto usamos una operación HTTP `PATCH`.
+
+Y en el código, obtenemos un `dict` con todos los datos enviados por el cliente, **solo los datos enviados por el cliente**, excluyendo cualquier valor que estaría allí solo por ser valores por defecto. Para hacerlo usamos `exclude_unset=True`. Este es el truco principal. 🪄
+
+Luego usamos `hero_db.sqlmodel_update(hero_data)` para actualizar el `hero_db` con los datos de `hero_data`.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
+
+### Eliminar un Hero de Nuevo
+
+**Eliminar** un héroe se mantiene prácticamente igual.
+
+No satisfaremos el deseo de refactorizar todo en este punto. 😅
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
+
+### Ejecutar la App de Nuevo
+
+Puedes ejecutar la aplicación de nuevo:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Si vas a la interfaz de `/docs` de la API, verás que ahora está actualizada, y no esperará recibir el `id` del cliente al crear un héroe, etc.
+
+
+
+
+
+## Resumen
+
+Puedes usar **SQLModel** para interactuar con una base de datos SQL y simplificar el código con *modelos de datos* y *modelos de tablas*.
+
+Puedes aprender mucho más en la documentación de **SQLModel**, hay un mini tutorial sobre el uso de SQLModel con **FastAPI**. 🚀
diff --git a/docs/es/docs/tutorial/static-files.md b/docs/es/docs/tutorial/static-files.md
new file mode 100644
index 000000000..6aefecc4b
--- /dev/null
+++ b/docs/es/docs/tutorial/static-files.md
@@ -0,0 +1,40 @@
+# Archivos Estáticos
+
+Puedes servir archivos estáticos automáticamente desde un directorio utilizando `StaticFiles`.
+
+## Usa `StaticFiles`
+
+* Importa `StaticFiles`.
+* "Monta" una instance de `StaticFiles()` en un path específico.
+
+{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
+
+/// note | Detalles Técnicos
+
+También podrías usar `from starlette.staticfiles import StaticFiles`.
+
+**FastAPI** proporciona el mismo `starlette.staticfiles` como `fastapi.staticfiles` solo como una conveniencia para ti, el desarrollador. Pero en realidad viene directamente de Starlette.
+
+///
+
+### Qué es "Montar"
+
+"Montar" significa agregar una aplicación completa "independiente" en un path específico, que luego se encargará de manejar todos los sub-paths.
+
+Esto es diferente a usar un `APIRouter`, ya que una aplicación montada es completamente independiente. El OpenAPI y la documentación de tu aplicación principal no incluirán nada de la aplicación montada, etc.
+
+Puedes leer más sobre esto en la [Guía de Usuario Avanzada](../advanced/index.md){.internal-link target=_blank}.
+
+## Detalles
+
+El primer `"/static"` se refiere al sub-path en el que esta "sub-aplicación" será "montada". Por lo tanto, cualquier path que comience con `"/static"` será manejado por ella.
+
+El `directory="static"` se refiere al nombre del directorio que contiene tus archivos estáticos.
+
+El `name="static"` le da un nombre que puede ser utilizado internamente por **FastAPI**.
+
+Todos estos parámetros pueden ser diferentes a "`static`", ajústalos según las necesidades y detalles específicos de tu propia aplicación.
+
+## Más info
+
+Para más detalles y opciones revisa la documentación de Starlette sobre Archivos Estáticos.
diff --git a/docs/es/docs/tutorial/testing.md b/docs/es/docs/tutorial/testing.md
new file mode 100644
index 000000000..62ad89d58
--- /dev/null
+++ b/docs/es/docs/tutorial/testing.md
@@ -0,0 +1,240 @@
+# Testing
+
+Gracias a Starlette, escribir pruebas para aplicaciones de **FastAPI** es fácil y agradable.
+
+Está basado en HTTPX, que a su vez está diseñado basado en Requests, por lo que es muy familiar e intuitivo.
+
+Con él, puedes usar pytest directamente con **FastAPI**.
+
+## Usando `TestClient`
+
+/// info | Información
+
+Para usar `TestClient`, primero instala `httpx`.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalarlo, por ejemplo:
+
+```console
+$ pip install httpx
+```
+
+///
+
+Importa `TestClient`.
+
+Crea un `TestClient` pasándole tu aplicación de **FastAPI**.
+
+Crea funciones con un nombre que comience con `test_` (esta es la convención estándar de `pytest`).
+
+Usa el objeto `TestClient` de la misma manera que con `httpx`.
+
+Escribe declaraciones `assert` simples con las expresiones estándar de Python que necesites revisar (otra vez, estándar de `pytest`).
+
+{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
+
+/// tip | Consejo
+
+Nota que las funciones de prueba son `def` normales, no `async def`.
+
+Y las llamadas al cliente también son llamadas normales, sin usar `await`.
+
+Esto te permite usar `pytest` directamente sin complicaciones.
+
+///
+
+/// note | Nota Técnica
+
+También podrías usar `from starlette.testclient import TestClient`.
+
+**FastAPI** proporciona el mismo `starlette.testclient` como `fastapi.testclient` solo por conveniencia para ti, el desarrollador. Pero proviene directamente de Starlette.
+
+///
+
+/// tip | Consejo
+
+Si quieres llamar a funciones `async` en tus pruebas además de enviar solicitudes a tu aplicación FastAPI (por ejemplo, funciones asincrónicas de bases de datos), echa un vistazo a las [Pruebas Asincrónicas](../advanced/async-tests.md){.internal-link target=_blank} en el tutorial avanzado.
+
+///
+
+## Separando pruebas
+
+En una aplicación real, probablemente tendrías tus pruebas en un archivo diferente.
+
+Y tu aplicación de **FastAPI** también podría estar compuesta de varios archivos/módulos, etc.
+
+### Archivo de aplicación **FastAPI**
+
+Digamos que tienes una estructura de archivos como se describe en [Aplicaciones Más Grandes](bigger-applications.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+```
+
+En el archivo `main.py` tienes tu aplicación de **FastAPI**:
+
+{* ../../docs_src/app_testing/main.py *}
+
+### Archivo de prueba
+
+Entonces podrías tener un archivo `test_main.py` con tus pruebas. Podría estar en el mismo paquete de Python (el mismo directorio con un archivo `__init__.py`):
+
+``` hl_lines="5"
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Debido a que este archivo está en el mismo paquete, puedes usar importaciones relativas para importar el objeto `app` desde el módulo `main` (`main.py`):
+
+{* ../../docs_src/app_testing/test_main.py hl[3] *}
+
+...y tener el código para las pruebas tal como antes.
+
+## Pruebas: ejemplo extendido
+
+Ahora extiende este ejemplo y añade más detalles para ver cómo escribir pruebas para diferentes partes.
+
+### Archivo de aplicación **FastAPI** extendido
+
+Continuemos con la misma estructura de archivos que antes:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Digamos que ahora el archivo `main.py` con tu aplicación de **FastAPI** tiene algunas otras **path operations**.
+
+Tiene una operación `GET` que podría devolver un error.
+
+Tiene una operación `POST` que podría devolver varios errores.
+
+Ambas *path operations* requieren un `X-Token` header.
+
+//// tab | Python 3.10+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.9+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an_py39/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an/main.py!}
+```
+
+////
+
+//// tab | Python 3.10+ sin Anotar
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+{!> ../../docs_src/app_testing/app_b_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+ sin Anotar
+
+/// tip | Consejo
+
+Prefiere usar la versión `Annotated` si es posible.
+
+///
+
+```Python
+{!> ../../docs_src/app_testing/app_b/main.py!}
+```
+
+////
+
+### Archivo de prueba extendido
+
+Podrías entonces actualizar `test_main.py` con las pruebas extendidas:
+
+{* ../../docs_src/app_testing/app_b/test_main.py *}
+
+Cada vez que necesites que el cliente pase información en el request y no sepas cómo, puedes buscar (Googlear) cómo hacerlo en `httpx`, o incluso cómo hacerlo con `requests`, dado que el diseño de HTTPX está basado en el diseño de Requests.
+
+Luego simplemente haces lo mismo en tus pruebas.
+
+Por ejemplo:
+
+* Para pasar un parámetro de *path* o *query*, añádelo a la URL misma.
+* Para pasar un cuerpo JSON, pasa un objeto de Python (por ejemplo, un `dict`) al parámetro `json`.
+* Si necesitas enviar *Form Data* en lugar de JSON, usa el parámetro `data` en su lugar.
+* Para pasar *headers*, usa un `dict` en el parámetro `headers`.
+* Para *cookies*, un `dict` en el parámetro `cookies`.
+
+Para más información sobre cómo pasar datos al backend (usando `httpx` o el `TestClient`) revisa la documentación de HTTPX.
+
+/// info | Información
+
+Ten en cuenta que el `TestClient` recibe datos que pueden ser convertidos a JSON, no modelos de Pydantic.
+
+Si tienes un modelo de Pydantic en tu prueba y quieres enviar sus datos a la aplicación durante las pruebas, puedes usar el `jsonable_encoder` descrito en [Codificador Compatible con JSON](encoder.md){.internal-link target=_blank}.
+
+///
+
+## Ejecútalo
+
+Después de eso, solo necesitas instalar `pytest`.
+
+Asegúrate de crear un [entorno virtual](../virtual-environments.md){.internal-link target=_blank}, activarlo y luego instalarlo, por ejemplo:
+
+
diff --git a/docs/es/docs/virtual-environments.md b/docs/es/docs/virtual-environments.md
new file mode 100644
index 000000000..71d450e09
--- /dev/null
+++ b/docs/es/docs/virtual-environments.md
@@ -0,0 +1,842 @@
+# Entornos Virtuales
+
+Cuando trabajas en proyectos de Python probablemente deberías usar un **entorno virtual** (o un mecanismo similar) para aislar los paquetes que instalas para cada proyecto.
+
+/// info | Información
+
+Si ya sabes sobre entornos virtuales, cómo crearlos y usarlos, podrías querer saltar esta sección. 🤓
+
+///
+
+/// tip | Consejo
+
+Un **entorno virtual** es diferente de una **variable de entorno**.
+
+Una **variable de entorno** es una variable en el sistema que puede ser usada por programas.
+
+Un **entorno virtual** es un directorio con algunos archivos en él.
+
+///
+
+/// info | Información
+
+Esta página te enseñará cómo usar **entornos virtuales** y cómo funcionan.
+
+Si estás listo para adoptar una **herramienta que gestiona todo** por ti (incluyendo la instalación de Python), prueba uv.
+
+///
+
+## Crea un Proyecto
+
+Primero, crea un directorio para tu proyecto.
+
+Lo que normalmente hago es crear un directorio llamado `code` dentro de mi directorio de usuario.
+
+Y dentro de eso creo un directorio por proyecto.
+
+
+
+```console
+// Ve al directorio principal
+$ cd
+// Crea un directorio para todos tus proyectos de código
+$ mkdir code
+// Entra en ese directorio de código
+$ cd code
+// Crea un directorio para este proyecto
+$ mkdir awesome-project
+// Entra en ese directorio del proyecto
+$ cd awesome-project
+```
+
+
+
+## Crea un Entorno Virtual
+
+Cuando empiezas a trabajar en un proyecto de Python **por primera vez**, crea un entorno virtual **dentro de tu proyecto**.
+
+/// tip | Consejo
+
+Solo necesitas hacer esto **una vez por proyecto**, no cada vez que trabajas.
+
+///
+
+//// tab | `venv`
+
+Para crear un entorno virtual, puedes usar el módulo `venv` que viene con Python.
+
+
+
+```console
+$ python -m venv .venv
+```
+
+
+
+/// details | Qué significa ese comando
+
+* `python`: usa el programa llamado `python`
+* `-m`: llama a un módulo como un script, indicaremos cuál módulo a continuación
+* `venv`: usa el módulo llamado `venv` que normalmente viene instalado con Python
+* `.venv`: crea el entorno virtual en el nuevo directorio `.venv`
+
+///
+
+////
+
+//// tab | `uv`
+
+Si tienes instalado `uv`, puedes usarlo para crear un entorno virtual.
+
+
+
+```console
+$ uv venv
+```
+
+
+
+/// tip | Consejo
+
+Por defecto, `uv` creará un entorno virtual en un directorio llamado `.venv`.
+
+Pero podrías personalizarlo pasando un argumento adicional con el nombre del directorio.
+
+///
+
+////
+
+Ese comando crea un nuevo entorno virtual en un directorio llamado `.venv`.
+
+/// details | `.venv` u otro nombre
+
+Podrías crear el entorno virtual en un directorio diferente, pero hay una convención de llamarlo `.venv`.
+
+///
+
+## Activa el Entorno Virtual
+
+Activa el nuevo entorno virtual para que cualquier comando de Python que ejecutes o paquete que instales lo utilicen.
+
+/// tip | Consejo
+
+Haz esto **cada vez** que inicies una **nueva sesión de terminal** para trabajar en el proyecto.
+
+///
+
+//// tab | Linux, macOS
+
+
+
+////
+
+/// tip | Consejo
+
+Cada vez que instales un **nuevo paquete** en ese entorno, **activa** el entorno de nuevo.
+
+Esto asegura que si usas un programa de **terminal (CLI)** instalado por ese paquete, uses el de tu entorno virtual y no cualquier otro que podría estar instalado globalmente, probablemente con una versión diferente a la que necesitas.
+
+///
+
+## Verifica que el Entorno Virtual esté Activo
+
+Verifica que el entorno virtual esté activo (el comando anterior funcionó).
+
+/// tip | Consejo
+
+Esto es **opcional**, pero es una buena forma de **revisar** que todo está funcionando como se esperaba y estás usando el entorno virtual que pretendes.
+
+///
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+Si muestra el binario de `python` en `.venv/bin/python`, dentro de tu proyecto (en este caso `awesome-project`), entonces funcionó. 🎉
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+Si muestra el binario de `python` en `.venv\Scripts\python`, dentro de tu proyecto (en este caso `awesome-project`), entonces funcionó. 🎉
+
+////
+
+## Actualiza `pip`
+
+/// tip | Consejo
+
+Si usas `uv` usarías eso para instalar cosas en lugar de `pip`, por lo que no necesitas actualizar `pip`. 😎
+
+///
+
+Si estás usando `pip` para instalar paquetes (viene por defecto con Python), deberías **actualizarlo** a la última versión.
+
+Muchos errores exóticos al instalar un paquete se resuelven simplemente actualizando `pip` primero.
+
+/// tip | Consejo
+
+Normalmente harías esto **una vez**, justo después de crear el entorno virtual.
+
+///
+
+Asegúrate de que el entorno virtual esté activo (con el comando anterior) y luego ejecuta:
+
+
+
+## Añade `.gitignore`
+
+Si estás usando **Git** (deberías), añade un archivo `.gitignore` para excluir todo en tu `.venv` de Git.
+
+/// tip | Consejo
+
+Si usaste `uv` para crear el entorno virtual, ya lo hizo por ti, puedes saltarte este paso. 😎
+
+///
+
+/// tip | Consejo
+
+Haz esto **una vez**, justo después de crear el entorno virtual.
+
+///
+
+
+
+/// details | Qué significa ese comando
+
+* `echo "*"`: "imprimirá" el texto `*` en el terminal (la siguiente parte cambia eso un poco)
+* `>`: cualquier cosa impresa en el terminal por el comando a la izquierda de `>` no debería imprimirse, sino escribirse en el archivo que va a la derecha de `>`
+* `.gitignore`: el nombre del archivo donde debería escribirse el texto
+
+Y `*` para Git significa "todo". Así que, ignorará todo en el directorio `.venv`.
+
+Ese comando creará un archivo `.gitignore` con el contenido:
+
+```gitignore
+*
+```
+
+///
+
+## Instala Paquetes
+
+Después de activar el entorno, puedes instalar paquetes en él.
+
+/// tip | Consejo
+
+Haz esto **una vez** al instalar o actualizar los paquetes que necesita tu proyecto.
+
+Si necesitas actualizar una versión o agregar un nuevo paquete, **harías esto de nuevo**.
+
+///
+
+### Instala Paquetes Directamente
+
+Si tienes prisa y no quieres usar un archivo para declarar los requisitos de paquetes de tu proyecto, puedes instalarlos directamente.
+
+/// tip | Consejo
+
+Es una (muy) buena idea poner los paquetes y las versiones que necesita tu programa en un archivo (por ejemplo, `requirements.txt` o `pyproject.toml`).
+
+///
+
+//// tab | `pip`
+
+
+
+////
+
+/// details | `requirements.txt`
+
+Un `requirements.txt` con algunos paquetes podría verse así:
+
+```requirements.txt
+fastapi[standard]==0.113.0
+pydantic==2.8.0
+```
+
+///
+
+## Ejecuta Tu Programa
+
+Después de activar el entorno virtual, puedes ejecutar tu programa, y usará el Python dentro de tu entorno virtual con los paquetes que instalaste allí.
+
+
+
+## Configura Tu Editor
+
+Probablemente usarías un editor, asegúrate de configurarlo para que use el mismo entorno virtual que creaste (probablemente lo autodetectará) para que puedas obtener autocompletado y errores en línea.
+
+Por ejemplo:
+
+* VS Code
+* PyCharm
+
+/// tip | Consejo
+
+Normalmente solo tendrías que hacer esto **una vez**, cuando crees el entorno virtual.
+
+///
+
+## Desactiva el Entorno Virtual
+
+Una vez que hayas terminado de trabajar en tu proyecto, puedes **desactivar** el entorno virtual.
+
+
+
+```console
+$ deactivate
+```
+
+
+
+De esta manera, cuando ejecutes `python` no intentará ejecutarse desde ese entorno virtual con los paquetes instalados allí.
+
+## Listo para Trabajar
+
+Ahora estás listo para empezar a trabajar en tu proyecto.
+
+/// tip | Consejo
+
+¿Quieres entender todo lo anterior?
+
+Continúa leyendo. 👇🤓
+
+///
+
+## Por qué Entornos Virtuales
+
+Para trabajar con FastAPI necesitas instalar Python.
+
+Después de eso, necesitarías **instalar** FastAPI y cualquier otro **paquete** que desees usar.
+
+Para instalar paquetes normalmente usarías el comando `pip` que viene con Python (o alternativas similares).
+
+Sin embargo, si solo usas `pip` directamente, los paquetes se instalarían en tu **entorno global de Python** (la instalación global de Python).
+
+### El Problema
+
+Entonces, ¿cuál es el problema de instalar paquetes en el entorno global de Python?
+
+En algún momento, probablemente terminarás escribiendo muchos programas diferentes que dependen de **diferentes paquetes**. Y algunos de estos proyectos en los que trabajas dependerán de **diferentes versiones** del mismo paquete. 😱
+
+Por ejemplo, podrías crear un proyecto llamado `philosophers-stone`, este programa depende de otro paquete llamado **`harry`, usando la versión `1`**. Así que, necesitas instalar `harry`.
+
+```mermaid
+flowchart LR
+ stone(philosophers-stone) -->|requires| harry-1[harry v1]
+```
+
+Luego, en algún momento después, creas otro proyecto llamado `prisoner-of-azkaban`, y este proyecto también depende de `harry`, pero este proyecto necesita **`harry` versión `3`**.
+
+```mermaid
+flowchart LR
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
+```
+
+Pero ahora el problema es, si instalas los paquetes globalmente (en el entorno global) en lugar de en un **entorno virtual local**, tendrás que elegir qué versión de `harry` instalar.
+
+Si deseas ejecutar `philosophers-stone` necesitarás primero instalar `harry` versión `1`, por ejemplo con:
+
+
+
+```console
+$ pip install "harry==1"
+```
+
+
+
+Y entonces terminarías con `harry` versión `1` instalada en tu entorno global de Python.
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[harry v1]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -->|requires| harry-1
+ end
+```
+
+Pero luego si deseas ejecutar `prisoner-of-azkaban`, necesitarás desinstalar `harry` versión `1` e instalar `harry` versión `3` (o simplemente instalar la versión `3` automáticamente desinstalaría la versión `1`).
+
+
+
+```console
+$ pip install "harry==3"
+```
+
+
+
+Y entonces terminarías con `harry` versión `3` instalada en tu entorno global de Python.
+
+Y si intentas ejecutar `philosophers-stone` de nuevo, hay una posibilidad de que **no funcione** porque necesita `harry` versión `1`.
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[harry v1]
+ style harry-1 fill:#ccc,stroke-dasharray: 5 5
+ harry-3[harry v3]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -.-x|⛔️| harry-1
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3
+ end
+```
+
+/// tip | Consejo
+
+Es muy común en los paquetes de Python intentar lo mejor para **evitar romper cambios** en **nuevas versiones**, pero es mejor estar seguro e instalar nuevas versiones intencionalmente y cuando puedas ejecutar las pruebas para verificar que todo está funcionando correctamente.
+
+///
+
+Ahora, imagina eso con **muchos** otros **paquetes** de los que dependen todos tus **proyectos**. Eso es muy difícil de manejar. Y probablemente terminarías ejecutando algunos proyectos con algunas **versiones incompatibles** de los paquetes, y sin saber por qué algo no está funcionando.
+
+Además, dependiendo de tu sistema operativo (por ejemplo, Linux, Windows, macOS), podría haber venido con Python ya instalado. Y en ese caso probablemente tenía algunos paquetes preinstalados con algunas versiones específicas **necesitadas por tu sistema**. Si instalas paquetes en el entorno global de Python, podrías terminar **rompiendo** algunos de los programas que vinieron con tu sistema operativo.
+
+## Dónde se Instalan los Paquetes
+
+Cuando instalas Python, crea algunos directorios con algunos archivos en tu computadora.
+
+Algunos de estos directorios son los encargados de tener todos los paquetes que instalas.
+
+Cuando ejecutas:
+
+
+
+```console
+// No ejecutes esto ahora, solo es un ejemplo 🤓
+$ pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+Eso descargará un archivo comprimido con el código de FastAPI, normalmente desde PyPI.
+
+También **descargará** archivos para otros paquetes de los que depende FastAPI.
+
+Luego, **extraerá** todos esos archivos y los pondrá en un directorio en tu computadora.
+
+Por defecto, pondrá esos archivos descargados y extraídos en el directorio que viene con tu instalación de Python, eso es el **entorno global**.
+
+## Qué son los Entornos Virtuales
+
+La solución a los problemas de tener todos los paquetes en el entorno global es usar un **entorno virtual para cada proyecto** en el que trabajas.
+
+Un entorno virtual es un **directorio**, muy similar al global, donde puedes instalar los paquetes para un proyecto.
+
+De esta manera, cada proyecto tendrá su propio entorno virtual (directorio `.venv`) con sus propios paquetes.
+
+```mermaid
+flowchart TB
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) --->|requires| harry-1
+ subgraph venv1[.venv]
+ harry-1[harry v1]
+ end
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --->|requires| harry-3
+ subgraph venv2[.venv]
+ harry-3[harry v3]
+ end
+ end
+ stone-project ~~~ azkaban-project
+```
+
+## Qué Significa Activar un Entorno Virtual
+
+Cuando activas un entorno virtual, por ejemplo con:
+
+//// tab | Linux, macOS
+
+
+
+////
+
+Ese comando creará o modificará algunas [variables de entorno](environment-variables.md){.internal-link target=_blank} que estarán disponibles para los siguientes comandos.
+
+Una de esas variables es la variable `PATH`.
+
+/// tip | Consejo
+
+Puedes aprender más sobre la variable de entorno `PATH` en la sección [Variables de Entorno](environment-variables.md#path-environment-variable){.internal-link target=_blank}.
+
+///
+
+Activar un entorno virtual agrega su path `.venv/bin` (en Linux y macOS) o `.venv\Scripts` (en Windows) a la variable de entorno `PATH`.
+
+Digamos que antes de activar el entorno, la variable `PATH` se veía así:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Eso significa que el sistema buscaría programas en:
+
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Windows\System32
+```
+
+Eso significa que el sistema buscaría programas en:
+
+* `C:\Windows\System32`
+
+////
+
+Después de activar el entorno virtual, la variable `PATH` se vería algo así:
+
+//// tab | Linux, macOS
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Eso significa que el sistema ahora comenzará a buscar primero los programas en:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin
+```
+
+antes de buscar en los otros directorios.
+
+Así que, cuando escribas `python` en el terminal, el sistema encontrará el programa Python en
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+y utilizará ese.
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
+```
+
+Eso significa que el sistema ahora comenzará a buscar primero los programas en:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts
+```
+
+antes de buscar en los otros directorios.
+
+Así que, cuando escribas `python` en el terminal, el sistema encontrará el programa Python en
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+y utilizará ese.
+
+////
+
+Un detalle importante es que pondrá el path del entorno virtual al **comienzo** de la variable `PATH`. El sistema lo encontrará **antes** que cualquier otro Python disponible. De esta manera, cuando ejecutes `python`, utilizará el Python **del entorno virtual** en lugar de cualquier otro `python` (por ejemplo, un `python` de un entorno global).
+
+Activar un entorno virtual también cambia un par de otras cosas, pero esta es una de las cosas más importantes que hace.
+
+## Verificando un Entorno Virtual
+
+Cuando revisas si un entorno virtual está activo, por ejemplo con:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+////
+
+Eso significa que el programa `python` que se utilizará es el que está **en el entorno virtual**.
+
+Usas `which` en Linux y macOS y `Get-Command` en Windows PowerShell.
+
+La forma en que funciona ese comando es que irá y revisará la variable de entorno `PATH`, pasando por **cada path en orden**, buscando el programa llamado `python`. Una vez que lo encuentre, te **mostrará el path** a ese programa.
+
+La parte más importante es que cuando llamas a `python`, ese es el exacto "`python`" que será ejecutado.
+
+Así que, puedes confirmar si estás en el entorno virtual correcto.
+
+/// tip | Consejo
+
+Es fácil activar un entorno virtual, obtener un Python, y luego **ir a otro proyecto**.
+
+Y el segundo proyecto **no funcionaría** porque estás usando el **Python incorrecto**, de un entorno virtual para otro proyecto.
+
+Es útil poder revisar qué `python` se está usando. 🤓
+
+///
+
+## Por qué Desactivar un Entorno Virtual
+
+Por ejemplo, podrías estar trabajando en un proyecto `philosophers-stone`, **activar ese entorno virtual**, instalar paquetes y trabajar con ese entorno.
+
+Y luego quieres trabajar en **otro proyecto** `prisoner-of-azkaban`.
+
+Vas a ese proyecto:
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+```
+
+
+
+Si no desactivas el entorno virtual para `philosophers-stone`, cuando ejecutes `python` en el terminal, intentará usar el Python de `philosophers-stone`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+$ python main.py
+
+// Error importando sirius, no está instalado 😱
+Traceback (most recent call last):
+ File "main.py", line 1, in
+ import sirius
+```
+
+
+
+Pero si desactivas el entorno virtual y activas el nuevo para `prisoner-of-askaban` entonces cuando ejecutes `python` utilizará el Python del entorno virtual en `prisoner-of-azkaban`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+// No necesitas estar en el directorio antiguo para desactivar, puedes hacerlo donde sea que estés, incluso después de ir al otro proyecto 😎
+$ deactivate
+
+// Activa el entorno virtual en prisoner-of-azkaban/.venv 🚀
+$ source .venv/bin/activate
+
+// Ahora cuando ejecutes python, encontrará el paquete sirius instalado en este entorno virtual ✨
+$ python main.py
+
+I solemnly swear 🐺
+```
+
+
+
+## Alternativas
+
+Esta es una guía simple para comenzar y enseñarte cómo funciona todo **por debajo**.
+
+Hay muchas **alternativas** para gestionar entornos virtuales, dependencias de paquetes (requisitos), proyectos.
+
+Una vez que estés listo y quieras usar una herramienta para **gestionar todo el proyecto**, dependencias de paquetes, entornos virtuales, etc. Te sugeriría probar uv.
+
+`uv` puede hacer muchas cosas, puede:
+
+* **Instalar Python** por ti, incluyendo diferentes versiones
+* Gestionar el **entorno virtual** para tus proyectos
+* Instalar **paquetes**
+* Gestionar **dependencias y versiones** de paquetes para tu proyecto
+* Asegurarse de que tengas un conjunto **exacto** de paquetes y versiones para instalar, incluidas sus dependencias, para que puedas estar seguro de que puedes ejecutar tu proyecto en producción exactamente igual que en tu computadora mientras desarrollas, esto se llama **locking**
+* Y muchas otras cosas
+
+## Conclusión
+
+Si leíste y comprendiste todo esto, ahora **sabes mucho más** sobre entornos virtuales que muchos desarrolladores por ahí. 🤓
+
+Conocer estos detalles probablemente te será útil en el futuro cuando estés depurando algo que parece complejo, pero sabrás **cómo funciona todo por debajo**. 😎
diff --git a/docs/es/llm-prompt.md b/docs/es/llm-prompt.md
new file mode 100644
index 000000000..3340dbc99
--- /dev/null
+++ b/docs/es/llm-prompt.md
@@ -0,0 +1,148 @@
+Translate to Spanish (español).
+
+Use the informal grammar (use "tú" instead of "usted").
+
+For instructions or titles in imperative, keep them in imperative, for example "Edit it" to "Edítalo".
+
+There are special blocks of notes, tips and others that look like:
+
+/// note
+
+To translate it, keep the same line and add the translation after a vertical bar:
+
+/// note | Nota
+
+Some examples:
+
+Source:
+
+/// tip
+
+Result:
+
+/// tip | Consejo
+
+Source:
+
+/// details | Preview
+
+Result:
+
+/// details | Vista previa
+
+Source:
+
+/// warning
+
+Result:
+
+/// warning | Advertencia
+
+Source:
+
+/// info
+
+Result:
+
+/// info | Información
+
+Source:
+
+/// note | Technical Details
+
+Result:
+
+/// note | Detalles Técnicos
+
+---
+
+For the next terms, use the following translations:
+
+* framework: framework (do not translate to "marco")
+* performance: rendimiento
+* program (verb): programar
+* code (verb): programar
+* type hints: anotaciones de tipos
+* type annotations: anotaciones de tipos
+* autocomplete: autocompletado
+* completion (in the context of autocompletion): autocompletado
+* feature: funcionalidad
+* sponsor: sponsor
+* host (in a podcast): host
+* request (as in HTTP request): request
+* response (as in HTTP response): response
+* path operation function: path operation function (do not translate to "función de operación de ruta")
+* path operation: path operation (do not translate to "operación de ruta")
+* path (as in URL path): path (do not translate to "ruta")
+* query (as in URL query): query (do not translate to "consulta")
+* cookie (as in HTTP cookie): cookie
+* header (as in HTTP header): header
+* form (as in HTML form): formulario
+* type checks: chequeo de tipos
+* parse: parse
+* parsing: parsing
+* marshall: marshall
+* library: paquete (do not translate to "biblioteca" or "librería")
+* instance: instance (do not translate to "instancia")
+* scratch the surface: tocar los conceptos básicos
+* string: string
+* bug: bug
+* docs: documentación (do not translate to "documentos")
+* cheat sheet: cheat sheet (do not translate to "chuleta")
+* key (as in key-value pair, dictionary key): clave
+* array (as in JSON array): array
+* API key: API key (do not translate to "clave API")
+* 100% test coverage: cobertura de tests del 100%
+* back and forth: de un lado a otro
+* I/O (as in "input and output"): I/O (do not translate to "E/S")
+* Machine Learning: Machine Learning (do not translate to "Aprendizaje Automático")
+* Deep Learning: Deep Learning (do not translate to "Aprendizaje Profundo")
+* callback hell: callback hell (do not translate to "infierno de callbacks")
+* tip: Consejo (do not translate to "tip")
+* check: Revisa (do not translate to "chequea" or "comprobación)
+* Cross-Origin Resource Sharing: Cross-Origin Resource Sharing (do not translate to "Compartición de Recursos de Origen Cruzado")
+* Release Notes: Release Notes (do not translate to "Notas de la Versión")
+* Semantic Versioning: Semantic Versioning (do not translate to "Versionado Semántico")
+* dependable: dependable (do not translate to "confiable" or "fiable")
+* list (as in Python list): list
+* context manager: context manager (do not translate to "gestor de contexto" or "administrador de contexto")
+* a little bit: un poquito
+* graph (data structure, as in "dependency graph"): grafo (do not translate to "gráfico")
+* form data: form data (do not translate to "datos de formulario" or "datos de form")
+* import (as in code import): import (do not translate to "importación")
+* JSON Schema: JSON Schema (do not translate to "Esquema JSON")
+* embed: embeber (do not translate to "incrustar")
+* request body: request body (do not translate to "cuerpo de la petición")
+* response body: response body (do not translate to "cuerpo de la respuesta")
+* cross domain: cross domain (do not translate to "dominio cruzado")
+* cross origin: cross origin (do not translate to "origen cruzado")
+* plugin: plugin (do not translate to "complemento" or "extensión")
+* plug-in: plug-in (do not translate to "complemento" or "extensión")
+* plug-ins: plug-ins (do not translate to "complementos" or "extensiones")
+* full stack: full stack (do not translate to "pila completa")
+* full-stack: full-stack (do not translate to "de pila completa")
+* stack: stack (do not translate to "pila")
+* loop (as in async loop): loop (do not translate to "bucle" or "ciclo")
+* hard dependencies: dependencias obligatorias (do not translate to "dependencias duras")
+* locking: locking (do not translate to "bloqueo")
+* testing (as in software testing): escribir pruebas (do not translate to "probar")
+* code base: code base (do not translate to "base de código")
+* default: por defecto (do not translate to "predeterminado")
+* default values: valores por defecto (do not translate to "valores predeterminados")
+* media type: media type (do not translate to "tipo de medio")
+* instantiate: crear un instance (do not translate to "instanciar")
+* OAuth2 Scopes: Scopes de OAuth2 (do not translate to "Alcances de OAuth2")
+* on the fly: sobre la marcha (do not translate to "al vuelo")
+* terminal: terminal (femenine, as in "la terminal")
+* terminals: terminales (plural femenine, as in "las terminales")
+* lifespan: lifespan (do not translate to "vida útil" or "tiempo de vida")
+* unload: quitar de memoria (do not translate to "descargar")
+* mount (noun): mount (do not translate to "montura")
+* mount (verb): montar
+* statement (as in code statement): statement (do not translate to "declaración" or "sentencia")
+* worker process: worker process (do not translate to "proceso trabajador" or "proceso de trabajo")
+* worker processes: worker processes (do not translate to "procesos trabajadores" or "procesos de trabajo")
+* worker: worker (do not translate to "trabajador")
+* load balancer: load balancer (do not translate to "balanceador de carga")
+* load balance: load balance (do not translate to "balancear carga")
+* self hosting: self hosting (do not translate to "auto alojamiento")
diff --git a/docs/fa/docs/advanced/sub-applications.md b/docs/fa/docs/advanced/sub-applications.md
index 5e4326776..de813b6cf 100644
--- a/docs/fa/docs/advanced/sub-applications.md
+++ b/docs/fa/docs/advanced/sub-applications.md
@@ -12,9 +12,7 @@
ابتدا برنامه اصلی سطح بالا، **FastAPI** و path operations آن را ایجاد کنید:
-```Python hl_lines="3 6-8"
-{!../../docs_src/sub_applications/tutorial001.py!}
-```
+{* ../../docs_src/sub_applications/tutorial001.py hl[3,6:8] *}
### زیر برنامه
@@ -22,17 +20,13 @@
این زیر برنامه فقط یکی دیگر از برنامه های استاندارد FastAPI است، اما این برنامه ای است که متصل می شود:
-```Python hl_lines="11 14-16"
-{!../../docs_src/sub_applications/tutorial001.py!}
-```
+{* ../../docs_src/sub_applications/tutorial001.py hl[11,14:16] *}
### اتصال زیر برنامه
در برنامه سطح بالا `app` اتصال زیر برنامه `subapi` در این نمونه `/subapi` در مسیر قرار میدهد و میشود:
-```Python hl_lines="11 19"
-{!../../docs_src/sub_applications/tutorial001.py!}
-```
+{* ../../docs_src/sub_applications/tutorial001.py hl[11,19] *}
### اسناد API خودکار را بررسی کنید
diff --git a/docs/fa/docs/index.md b/docs/fa/docs/index.md
index 6addce763..0aa0bec36 100644
--- a/docs/fa/docs/index.md
+++ b/docs/fa/docs/index.md
@@ -11,11 +11,11 @@
فریمورک FastAPI، کارایی بالا، یادگیری آسان، کدنویسی سریع، آماده برای استفاده در محیط پروداکشن
-
-////
-
-Si celui-ci montre le binaire `pip` à `env/bin/pip`, alors ça a fonctionné. 🎉
-
-
-
-/// tip
-
-Chaque fois que vous installez un nouveau paquet avec `pip` sous cet environnement, activez à nouveau l'environnement.
-
-Cela permet de s'assurer que si vous utilisez un programme terminal installé par ce paquet (comme `flit`), vous utilisez celui de votre environnement local et pas un autre qui pourrait être installé globalement.
-
-///
-
-### Flit
-
-**FastAPI** utilise Flit pour build, packager et publier le projet.
-
-Après avoir activé l'environnement comme décrit ci-dessus, installez `flit` :
-
-
-
-Réactivez maintenant l'environnement pour vous assurer que vous utilisez le "flit" que vous venez d'installer (et non un environnement global).
-
-Et maintenant, utilisez `flit` pour installer les dépendances de développement :
-
-//// tab | Linux, macOS
-
-
-
-////
-
-Il installera toutes les dépendances et votre FastAPI local dans votre environnement local.
-
-#### Utiliser votre FastAPI local
-
-Si vous créez un fichier Python qui importe et utilise FastAPI, et que vous l'exécutez avec le Python de votre environnement local, il utilisera votre code source FastAPI local.
-
-Et si vous mettez à jour le code source local de FastAPI, tel qu'il est installé avec `--symlink` (ou `--pth-file` sous Windows), lorsque vous exécutez à nouveau ce fichier Python, il utilisera la nouvelle version de FastAPI que vous venez d'éditer.
-
-De cette façon, vous n'avez pas à "installer" votre version locale pour pouvoir tester chaque changement.
-
-### Formatage
-
-Il existe un script que vous pouvez exécuter qui formatera et nettoiera tout votre code :
-
-
-
-```console
-$ bash scripts/format.sh
-```
-
-
-
-Il effectuera également un tri automatique de touts vos imports.
-
-Pour qu'il puisse les trier correctement, vous devez avoir FastAPI installé localement dans votre environnement, avec la commande dans la section ci-dessus en utilisant `--symlink` (ou `--pth-file` sous Windows).
-
-### Formatage des imports
-
-Il existe un autre script qui permet de formater touts les imports et de s'assurer que vous n'avez pas d'imports inutilisés :
-
-
-
-Comme il exécute une commande après l'autre et modifie et inverse de nombreux fichiers, il prend un peu plus de temps à s'exécuter, il pourrait donc être plus facile d'utiliser fréquemment `scripts/format.sh` et `scripts/format-imports.sh` seulement avant de commit.
-
-## Documentation
-
-Tout d'abord, assurez-vous que vous configurez votre environnement comme décrit ci-dessus, qui installera toutes les exigences.
-
-La documentation utilise MkDocs.
-
-Et il y a des outils/scripts supplémentaires en place pour gérer les traductions dans `./scripts/docs.py`.
-
-/// tip
-
-Vous n'avez pas besoin de voir le code dans `./scripts/docs.py`, vous l'utilisez simplement dans la ligne de commande.
-
-///
-
-Toute la documentation est au format Markdown dans le répertoire `./docs/fr/`.
-
-De nombreux tutoriels comportent des blocs de code.
-
-Dans la plupart des cas, ces blocs de code sont de véritables applications complètes qui peuvent être exécutées telles quelles.
-
-En fait, ces blocs de code ne sont pas écrits à l'intérieur du Markdown, ce sont des fichiers Python dans le répertoire `./docs_src/`.
-
-Et ces fichiers Python sont inclus/injectés dans la documentation lors de la génération du site.
-
-### Documentation pour les tests
-
-La plupart des tests sont en fait effectués par rapport aux exemples de fichiers sources dans la documentation.
-
-Cela permet de s'assurer que :
-
-* La documentation est à jour.
-* Les exemples de documentation peuvent être exécutés tels quels.
-* La plupart des fonctionnalités sont couvertes par la documentation, assurées par la couverture des tests.
-
-Au cours du développement local, un script build le site et vérifie les changements éventuels, puis il est rechargé en direct :
-
-
-
-Il servira la documentation sur `http://127.0.0.1:8008`.
-
-De cette façon, vous pouvez modifier la documentation/les fichiers sources et voir les changements en direct.
-
-#### Typer CLI (facultatif)
-
-Les instructions ici vous montrent comment utiliser le script à `./scripts/docs.py` avec le programme `python` directement.
-
-Mais vous pouvez également utiliser Typer CLI, et vous obtiendrez l'auto-complétion dans votre terminal pour les commandes après l'achèvement de l'installation.
-
-Si vous installez Typer CLI, vous pouvez installer la complétion avec :
-
-
-
-```console
-$ typer --install-completion
-
-zsh completion installed in /home/user/.bashrc.
-Completion will take effect once you restart the terminal.
-```
-
-
-
-### Apps et documentation en même temps
-
-Si vous exécutez les exemples avec, par exemple :
-
-
-
-```console
-$ uvicorn tutorial001:app --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-Comme Uvicorn utilisera par défaut le port `8000`, la documentation sur le port `8008` n'entrera pas en conflit.
-
-### Traductions
-
-L'aide aux traductions est TRÈS appréciée ! Et cela ne peut se faire sans l'aide de la communauté. 🌎 🚀
-
-Voici les étapes à suivre pour aider à la traduction.
-
-#### Conseils et lignes directrices
-
-* Vérifiez les pull requests existantes pour votre langue et ajouter des reviews demandant des changements ou les approuvant.
-
-/// tip
-
-Vous pouvez ajouter des commentaires avec des suggestions de changement aux pull requests existantes.
-
-Consultez les documents concernant l'ajout d'un review de pull request pour l'approuver ou demander des modifications.
-
-///
-
-* Vérifiez dans issues pour voir s'il y a une personne qui coordonne les traductions pour votre langue.
-
-* Ajoutez une seule pull request par page traduite. Il sera ainsi beaucoup plus facile pour les autres de l'examiner.
-
-Pour les langues que je ne parle pas, je vais attendre plusieurs autres reviews de la traduction avant de merge.
-
-* Vous pouvez également vérifier s'il existe des traductions pour votre langue et y ajouter une review, ce qui m'aidera à savoir si la traduction est correcte et je pourrai la fusionner.
-
-* Utilisez les mêmes exemples en Python et ne traduisez que le texte des documents. Vous n'avez pas besoin de changer quoi que ce soit pour que cela fonctionne.
-
-* Utilisez les mêmes images, noms de fichiers et liens. Vous n'avez pas besoin de changer quoi que ce soit pour que cela fonctionne.
-
-* Pour vérifier le code à 2 lettres de la langue que vous souhaitez traduire, vous pouvez utiliser le tableau Liste des codes ISO 639-1.
-
-#### Langue existante
-
-Disons que vous voulez traduire une page pour une langue qui a déjà des traductions pour certaines pages, comme l'espagnol.
-
-Dans le cas de l'espagnol, le code à deux lettres est `es`. Ainsi, le répertoire des traductions espagnoles se trouve à l'adresse `docs/es/`.
-
-/// tip
-
-La langue principale ("officielle") est l'anglais, qui se trouve à l'adresse "docs/en/".
-
-///
-
-Maintenant, lancez le serveur en live pour les documents en espagnol :
-
-
-
-```console
-// Use the command "live" and pass the language code as a CLI argument
-$ python ./scripts/docs.py live es
-
-[INFO] Serving on http://127.0.0.1:8008
-[INFO] Start watching changes
-[INFO] Start detecting changes
-```
-
-
-
-Vous pouvez maintenant aller sur http://127.0.0.1:8008 et voir vos changements en direct.
-
-Si vous regardez le site web FastAPI docs, vous verrez que chaque langue a toutes les pages. Mais certaines pages ne sont pas traduites et sont accompagnées d'une notification concernant la traduction manquante.
-
-Mais si vous le gérez localement de cette manière, vous ne verrez que les pages déjà traduites.
-
-Disons maintenant que vous voulez ajouter une traduction pour la section [Features](features.md){.internal-link target=_blank}.
-
-* Copiez le fichier à :
-
-```
-docs/en/docs/features.md
-```
-
-* Collez-le exactement au même endroit mais pour la langue que vous voulez traduire, par exemple :
-
-```
-docs/es/docs/features.md
-```
-
-/// tip
-
-Notez que le seul changement dans le chemin et le nom du fichier est le code de langue, qui passe de `en` à `es`.
-
-///
-
-* Ouvrez maintenant le fichier de configuration de MkDocs pour l'anglais à
-
-```
-docs/en/docs/mkdocs.yml
-```
-
-* Trouvez l'endroit où cette `docs/features.md` se trouve dans le fichier de configuration. Quelque part comme :
-
-```YAML hl_lines="8"
-site_name: FastAPI
-# More stuff
-nav:
-- FastAPI: index.md
-- Languages:
- - en: /
- - es: /es/
-- features.md
-```
-
-* Ouvrez le fichier de configuration MkDocs pour la langue que vous éditez, par exemple :
-
-```
-docs/es/docs/mkdocs.yml
-```
-
-* Ajoutez-le à l'endroit exact où il se trouvait pour l'anglais, par exemple :
-
-```YAML hl_lines="8"
-site_name: FastAPI
-# More stuff
-nav:
-- FastAPI: index.md
-- Languages:
- - en: /
- - es: /es/
-- features.md
-```
-
-Assurez-vous que s'il y a d'autres entrées, la nouvelle entrée avec votre traduction est exactement dans le même ordre que dans la version anglaise.
-
-Si vous allez sur votre navigateur, vous verrez que maintenant les documents montrent votre nouvelle section. 🎉
-
-Vous pouvez maintenant tout traduire et voir à quoi cela ressemble au fur et à mesure que vous enregistrez le fichier.
-
-#### Nouvelle langue
-
-Disons que vous voulez ajouter des traductions pour une langue qui n'est pas encore traduite, pas même quelques pages.
-
-Disons que vous voulez ajouter des traductions pour le Créole, et que ce n'est pas encore dans les documents.
-
-En vérifiant le lien ci-dessus, le code pour "Créole" est `ht`.
-
-L'étape suivante consiste à exécuter le script pour générer un nouveau répertoire de traduction :
-
-
-
-```console
-// Use the command new-lang, pass the language code as a CLI argument
-$ python ./scripts/docs.py new-lang ht
-
-Successfully initialized: docs/ht
-Updating ht
-Updating en
-```
-
-
-
-Vous pouvez maintenant vérifier dans votre éditeur de code le répertoire nouvellement créé `docs/ht/`.
-
-/// tip
-
-Créez une première demande d'extraction à l'aide de cette fonction, afin de configurer la nouvelle langue avant d'ajouter des traductions.
-
-Ainsi, d'autres personnes peuvent vous aider à rédiger d'autres pages pendant que vous travaillez sur la première. 🚀
-
-///
-
-Commencez par traduire la page principale, `docs/ht/index.md`.
-
-Vous pouvez ensuite continuer avec les instructions précédentes, pour une "langue existante".
-
-##### Nouvelle langue non prise en charge
-
-Si, lors de l'exécution du script du serveur en direct, vous obtenez une erreur indiquant que la langue n'est pas prise en charge, quelque chose comme :
-
-```
- raise TemplateNotFound(template)
-jinja2.exceptions.TemplateNotFound: partials/language/xx.html
-```
-
-Cela signifie que le thème ne supporte pas cette langue (dans ce cas, avec un faux code de 2 lettres de `xx`).
-
-Mais ne vous inquiétez pas, vous pouvez définir la langue du thème en anglais et ensuite traduire le contenu des documents.
-
-Si vous avez besoin de faire cela, modifiez le fichier `mkdocs.yml` pour votre nouvelle langue, il aura quelque chose comme :
-
-```YAML hl_lines="5"
-site_name: FastAPI
-# More stuff
-theme:
- # More stuff
- language: xx
-```
-
-Changez cette langue de `xx` (de votre code de langue) à `fr`.
-
-Vous pouvez ensuite relancer le serveur live.
-
-#### Prévisualisez le résultat
-
-Lorsque vous utilisez le script à `./scripts/docs.py` avec la commande `live`, il n'affiche que les fichiers et les traductions disponibles pour la langue courante.
-
-Mais une fois que vous avez terminé, vous pouvez tester le tout comme il le ferait en ligne.
-
-Pour ce faire, il faut d'abord construire tous les documents :
-
-
-
-```console
-// Use the command "build-all", this will take a bit
-$ python ./scripts/docs.py build-all
-
-Updating es
-Updating en
-Building docs for: en
-Building docs for: es
-Successfully built docs for: es
-Copying en index.md to README.md
-```
-
-
-
-Cela génère tous les documents à `./docs_build/` pour chaque langue. Cela inclut l'ajout de tout fichier dont la traduction est manquante, avec une note disant que "ce fichier n'a pas encore de traduction". Mais vous n'avez rien à faire avec ce répertoire.
-
-Ensuite, il construit tous ces sites MkDocs indépendants pour chaque langue, les combine, et génère le résultat final à `./site/`.
-
-Ensuite, vous pouvez servir cela avec le commandement `serve`:
-
-
-
-```console
-// Use the command "serve" after running "build-all"
-$ python ./scripts/docs.py serve
-
-Warning: this is a very simple server. For development, use mkdocs serve instead.
-This is here only to preview a site with translations already built.
-Make sure you run the build-all command first.
-Serving at: http://127.0.0.1:8008
-```
-
-
-
-## Tests
-
-Il existe un script que vous pouvez exécuter localement pour tester tout le code et générer des rapports de couverture en HTML :
-
-
-
-Cette commande génère un répertoire `./htmlcov/`, si vous ouvrez le fichier `./htmlcov/index.html` dans votre navigateur, vous pouvez explorer interactivement les régions de code qui sont couvertes par les tests, et remarquer s'il y a une région manquante.
diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md
index 695429008..d25f7a939 100644
--- a/docs/fr/docs/index.md
+++ b/docs/fr/docs/index.md
@@ -12,7 +12,7 @@
+
+---
+
+**Dokumentasi**: https://fastapi.tiangolo.com
+
+**Kode Sumber**: https://github.com/fastapi/fastapi
+
+---
+
+FastAPI adalah *framework* *web* moderen, cepat (performa-tinggi) untuk membangun API dengan Python berdasarkan tipe petunjuk Python.
+
+Fitur utama FastAPI:
+
+* **Cepat**: Performa sangat tinggi, setara **NodeJS** dan **Go** (berkat Starlette dan Pydantic). [Salah satu *framework* Python tercepat yang ada](#performa).
+* **Cepat untuk coding**: Meningkatkan kecepatan pengembangan fitur dari 200% sampai 300%. *
+* **Sedikit bug**: Mengurangi hingga 40% kesalahan dari manusia (pemrogram). *
+* **Intuitif**: Dukungan editor hebat. Penyelesaian di mana pun. Lebih sedikit *debugging*.
+* **Mudah**: Dibuat mudah digunakan dan dipelajari. Sedikit waktu membaca dokumentasi.
+* **Ringkas**: Mengurasi duplikasi kode. Beragam fitur dari setiap deklarasi parameter. Lebih sedikit *bug*.
+* **Handal**: Dapatkan kode siap-digunakan. Dengan dokumentasi otomatis interaktif.
+* **Standar-resmi**: Berdasarkan (kompatibel dengan ) standar umum untuk API: OpenAPI (sebelumnya disebut Swagger) dan JSON Schema.
+
+* estimasi berdasarkan pengujian tim internal pengembangan applikasi siap pakai.
+
+## Sponsor
+
+
+
+{% if sponsors %}
+{% for sponsor in sponsors.gold -%}
+
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+
+{% endfor %}
+{% endif %}
+
+
+
+Sponsor lainnya
+
+## Opini
+
+"_[...] Saya banyak menggunakan **FastAPI** sekarang ini. [...] Saya berencana menggunakannya di semua tim servis ML Microsoft. Beberapa dari mereka sudah mengintegrasikan dengan produk inti *Windows** dan sebagian produk **Office**._"
+
+
+
+---
+
+"_Jujur, apa yang anda buat sangat solid dan berkualitas. Ini adalah yang saya inginkan di **Hug** - sangat menginspirasi melihat seseorang membuat ini._"
+
+
+
+---
+
+"_Jika anda ingin mempelajari **framework moderen** untuk membangun REST API, coba **FastAPI** [...] cepat, mudah digunakan dan dipelajari [...]_"
+
+"_Kami sudah pindah ke **FastAPI** untuk **API** kami [...] Saya pikir kamu juga akan suka [...]_"
+
+
+
+---
+"_Jika anda ingin membuat API Python siap pakai, saya merekomendasikan **FastAPI**. FastAPI **didesain indah**, **mudah digunakan** dan **sangat scalable**, FastAPI adalah **komponen kunci** di strategi pengembangan API pertama kami dan mengatur banyak otomatisasi dan service seperti TAC Engineer kami._"
+
+
+
+---
+
+## **Typer**, CLI FastAPI
+
+
+
+Jika anda mengembangkan app CLI yang digunakan di terminal bukan sebagai API web, kunjungi **Typer**.
+
+**Typer** adalah saudara kecil FastAPI. Dan ditujukan sebagai **CLI FastAPI**. ⌨️ 🚀
+
+## Prayarat
+
+FastAPI berdiri di pundak raksasa:
+
+* Starlette untuk bagian web.
+* Pydantic untuk bagian data.
+
+## Instalasi
+
+Buat dan aktifkan virtual environment kemudian *install* FastAPI:
+
+
+
+**Catatan**: Pastikan anda menulis `"fastapi[standard]"` dengan tanda petik untuk memastikan bisa digunakan di semua *terminal*.
+
+## Contoh
+
+### Buat app
+
+* Buat file `main.py` dengan:
+
+```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}
+```
+
+
+Atau gunakan async def...
+
+Jika kode anda menggunakan `async` / `await`, gunakan `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}
+```
+
+**Catatan**:
+
+Jika anda tidak paham, kunjungi _"Panduan cepat"_ bagian `async` dan `await` di dokumentasi.
+
+
+
+### Jalankan
+
+Jalankan *server* dengan:
+
+
+
+```console
+$ fastapi dev main.py
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [2248755] using WatchFiles
+INFO: Started server process [2248757]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+
+Mengenai perintah fastapi dev main.py...
+
+Perintah `fastapi dev` membaca file `main.py`, memeriksa app **FastAPI** di dalamnya, dan menjalan server dengan Uvicorn.
+
+Secara otomatis, `fastapi dev` akan mengaktifkan *auto-reload* untuk pengembangan lokal.
+
+Informasi lebih lanjut kunjungi Dokumen FastAPI CLI.
+
+
+
+### Periksa
+
+Buka *browser* di http://127.0.0.1:8000/items/5?q=somequery.
+
+Anda akan melihat respon JSON berikut:
+
+```JSON
+{"item_id": 5, "q": "somequery"}
+```
+
+Anda telah membuat API:
+
+* Menerima permintaan HTTP di _path_ `/` dan `/items/{item_id}`.
+* Kedua _paths_ menerima operasi `GET` (juga disebut _metode_ HTTP).
+* _path_ `/items/{item_id}` memiliki _parameter path_ `item_id` yang harus berjenis `int`.
+* _path_ `/items/{item_id}` memiliki _query parameter_ `q` berjenis `str`.
+
+### Dokumentasi API interaktif
+
+Sekarang kunjungi http://127.0.0.1:8000/docs.
+
+Anda akan melihat dokumentasi API interaktif otomatis (dibuat oleh Swagger UI):
+
+
+
+### Dokumentasi API alternatif
+
+Kemudian kunjungi http://127.0.0.1:8000/redoc.
+
+Anda akan melihat dokumentasi alternatif otomatis (dibuat oleh ReDoc):
+
+
+
+## Contoh upgrade
+
+Sekarang ubah `main.py` untuk menerima struktur permintaan `PUT`.
+
+Deklarasikan struktur menggunakan tipe standar Python, berkat 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 `fastapi dev` akan otomatis memuat kembali.
+
+### Upgrade dokumentasi API interaktif
+
+Kunjungi http://127.0.0.1:8000/docs.
+
+* Dokumentasi API interaktif akan otomatis diperbarui, termasuk kode yang baru:
+
+
+
+* Klik tombol "Try it out", anda dapat mengisi parameter dan langsung berinteraksi dengan API:
+
+
+
+* Kemudian klik tombol "Execute", tampilan pengguna akan berkomunikasi dengan API, mengirim parameter, mendapatkan dan menampilkan hasil ke layar:
+
+
+
+### Upgrade dokumentasi API alternatif
+
+Kunjungi http://127.0.0.1:8000/redoc.
+
+* Dokumentasi alternatif akan menampilkan parameter *query* dan struktur *request*:
+
+
+
+### Ringkasan
+
+Singkatnya, anda mendeklarasikan **sekali** jenis parameter, struktur, dll. sebagai parameter fungsi.
+
+Anda melakukannya dengan tipe standar moderen Python.
+
+Anda tidak perlu belajar sintaksis, metode, *classs* baru dari *library* tertentu, dll.
+
+Cukup **Python** standar.
+
+Sebagai contoh untuk `int`:
+
+```Python
+item_id: int
+```
+
+atau untuk model lebih rumit `Item`:
+
+```Python
+item: Item
+```
+
+...dengan sekali deklarasi anda mendapatkan:
+
+* Dukungan editor, termasuk:
+ * Pelengkapan kode.
+ * Pengecekan tipe.
+* Validasi data:
+ * Kesalahan otomatis dan jelas ketika data tidak sesuai.
+ * Validasi hingga untuk object JSON bercabang mendalam.
+* Konversi input data: berasal dari jaringan ke data dan tipe Python. Membaca dari:
+ * JSON.
+ * Parameter path.
+ * Parameter query.
+ * Cookie.
+ * Header.
+ * Form.
+ * File.
+* Konversi output data: konversi data Python ke tipe jaringan data (seperti JSON):
+ * Konversi tipe Python (`str`, `int`, `float`, `bool`, `list`, dll).
+ * Objek `datetime`.
+ * Objek `UUID`.
+ * Model database.
+ * ...dan banyak lagi.
+* Dokumentasi interaktif otomatis, termasuk 2 alternatif tampilan pengguna:
+ * Swagger UI.
+ * ReDoc.
+
+---
+
+Kembali ke kode contoh sebelumnya, **FastAPI** akan:
+
+* Validasi apakah terdapat `item_id` di *path* untuk permintaan `GET` dan `PUT` requests.
+* Validasi apakah `item_id` berjenit `int` untuk permintaan `GET` dan `PUT`.
+ * Jika tidak, klien akan melihat pesan kesalahan jelas.
+* Periksa jika ada parameter *query* opsional bernama `q` (seperti `http://127.0.0.1:8000/items/foo?q=somequery`) untuk permintaan `GET`.
+ * Karena parameter `q` dideklarasikan dengan `= None`, maka bersifat opsional.
+ * Tanpa `None` maka akan menjadi wajib ada (seperti struktur di kondisi dengan `PUT`).
+* Untuk permintaan `PUT` `/items/{item_id}`, membaca struktur sebagai JSON:
+ * Memeriksa terdapat atribut wajib `name` harus berjenis `str`.
+ * Memeriksa terdapat atribut wajib`price` harus berjenis `float`.
+ * Memeriksa atribut opsional `is_offer`, harus berjenis `bool`, jika ada.
+ * Semua ini juga sama untuk objek json yang bersarang mendalam.
+* Konversi dari dan ke JSON secara otomatis.
+* Dokumentasi segalanya dengan OpenAPI, dengan menggunakan:
+ * Sistem dokumentasi interaktif.
+ * Sistem otomatis penghasil kode, untuk banyak bahasa.
+* Menyediakan 2 tampilan dokumentasi web interaktif dengan langsung.
+
+---
+
+Kita baru menyentuh permukaannya saja, tetapi anda sudah mulai paham gambaran besar cara kerjanya.
+
+Coba ubah baris:
+
+```Python
+ return {"item_name": item.name, "item_id": item_id}
+```
+
+...dari:
+
+```Python
+ ... "item_name": item.name ...
+```
+
+...menjadi:
+
+```Python
+ ... "item_price": item.price ...
+```
+
+...anda akan melihat kode editor secara otomatis melengkapi atributnya dan tahu tipe nya:
+
+
+
+Untuk contoh lengkap termasuk fitur lainnya, kunjungi Tutorial - Panduan Pengguna.
+
+**Peringatan spoiler**: tutorial - panduan pengguna termasuk:
+
+* Deklarasi **parameter** dari tempat berbeda seperti: **header**, **cookie**, **form field** and **file**.
+* Bagaimana mengatur **batasan validasi** seperti `maximum_length`atau `regex`.
+* Sistem **Dependency Injection** yang hebat dan mudah digunakan.
+* Keamanan dan autentikasi, termasuk dukungan ke **OAuth2** dengan **JWT token** dan autentikasi **HTTP Basic**.
+* Teknik lebih aju (tetapi mudah dipakai untuk deklarasi **model JSON bersarang ke dalam** (berkat Pydantic).
+* Integrasi **GraphQL** dengan Strawberry dan library lainnya.
+* Fitur lainnya (berkat Starlette) seperti:
+ * **WebSocket**
+ * Test yang sangat mudah berdasarkan HTTPX dan `pytest`
+ * **CORS**
+ * **Cookie Session**
+ * ...dan lainnya.
+
+## Performa
+
+Tolok ukur Independent TechEmpower mendapati aplikasi **FastAPI** berjalan menggunakan Uvicorn sebagai salah satu framework Python tercepat yang ada, hanya di bawah Starlette dan Uvicorn itu sendiri (digunakan di internal FastAPI). (*)
+
+Penjelasan lebih lanjut, lihat bagian Tolok ukur.
+
+## Dependensi
+
+FastAPI bergantung pada Pydantic dan Starlette.
+
+### Dependensi `standar`
+
+Ketika anda meng-*install* FastAPI dengan `pip install "fastapi[standard]"`, maka FastAPI akan menggunakan sekumpulan dependensi opsional `standar`:
+
+Digunakan oleh Pydantic:
+
+* email-validator - untuk validasi email.
+
+Digunakan oleh Starlette:
+
+* httpx - Dibutuhkan jika anda menggunakan `TestClient`.
+* jinja2 - Dibutuhkan jika anda menggunakan konfigurasi template bawaan.
+* python-multipart - Dibutuhkan jika anda menggunakan form dukungan "parsing", dengan `request.form()`.
+
+Digunakan oleh FastAPI / Starlette:
+
+* uvicorn - untuk server yang memuat dan melayani aplikasi anda. Termasuk `uvicorn[standard]`, yang memasukan sejumlah dependensi (misal `uvloop`) untuk needed melayani dengan performa tinggi.
+* `fastapi-cli` - untuk menyediakan perintah `fastapi`.
+
+### Tanpda dependensi `standard`
+
+Jika anda tidak ingin menambahkan dependensi opsional `standard`, anda dapat menggunakan `pip install fastapi` daripada `pip install "fastapi[standard]"`.
+
+### Dependensi Opsional Tambahan
+
+Ada beberapa dependensi opsional yang bisa anda install.
+
+Dependensi opsional tambahan Pydantic:
+
+* pydantic-settings - untuk manajemen setting.
+* pydantic-extra-types - untuk tipe tambahan yang digunakan dengan Pydantic.
+
+Dependensi tambahan opsional FastAPI:
+
+* orjson - Diperlukan jika anda akan menggunakan`ORJSONResponse`.
+* ujson - Diperlukan jika anda akan menggunakan `UJSONResponse`.
+
+## Lisensi
+
+Project terlisensi dengan lisensi MIT.
diff --git a/docs/id/docs/tutorial/first-steps.md b/docs/id/docs/tutorial/first-steps.md
new file mode 100644
index 000000000..9b461507d
--- /dev/null
+++ b/docs/id/docs/tutorial/first-steps.md
@@ -0,0 +1,332 @@
+# Langkah Pertama
+
+File FastAPI yang paling sederhana bisa seperti berikut:
+
+{* ../../docs_src/first_steps/tutorial001.py *}
+
+Salin file tersebut ke `main.py`.
+
+Jalankan di server:
+
+
+
+```console
+$ fastapi dev main.py
+INFO Using path main.py
+INFO Resolved absolute path /home/user/code/awesomeapp/main.py
+INFO Searching for package file structure from directories with __init__.py files
+INFO Importing from /home/user/code/awesomeapp
+
+ ╭─ Python module file ─╮
+ │ │
+ │ 🐍 main.py │
+ │ │
+ ╰──────────────────────╯
+
+INFO Importing module main
+INFO Found importable FastAPI app
+
+ ╭─ Importable FastAPI app ─╮
+ │ │
+ │ from main import app │
+ │ │
+ ╰──────────────────────────╯
+
+INFO Using import string main:app
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+INFO: Started reloader process [2265862] using WatchFiles
+INFO: Started server process [2265873]
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+
+
+Di output, terdapat sebaris pesan:
+
+```hl_lines="4"
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+Baris tersebut menunjukan URL dimana app aktif di komputer anda.
+
+
+### Mencoba aplikasi
+
+Buka browser di http://127.0.0.1:8000.
+
+Anda akan melihat response JSON sebagai berikut:
+
+```JSON
+{"message": "Hello World"}
+```
+
+### Dokumen API interaktif
+
+Sekarang kunjungi http://127.0.0.1:8000/docs.
+
+Anda akan melihat dokumentasi API interaktif otomatis (dibuat oleh Swagger UI):
+
+
+
+### Dokumen API alternatif
+
+Dan sekarang, kunjungi http://127.0.0.1:8000/redoc.
+
+Anda akan melihat dokumentasi alternatif otomatis (dibuat oleh ReDoc):
+
+
+
+### OpenAPI
+
+**FastAPI** membuat sebuah "schema" dimana semua API anda menggunakan standar **OpenAPI** untuk mendefinisikan API.
+
+#### "Schema"
+
+"schema" adalah suatu definisi atau deskripsi dari sesuatu. Bukan kode yang mengimplementasi definisi tersebut. Ini hanyalah sebuah deskripsi abstrak.
+
+#### "schema" API
+
+Dalam hal ini, OpenAPI adalah spesifikasi yang menunjukan bagaimana untuk mendefinisikan sebuah skema di API anda.
+
+Definisi skema ini termasuk jalur API anda, parameter yang bisa diterima, dll.
+
+#### "schema" Data
+
+Istilah "schema" bisa juga merujuk ke struktur data, seperti konten JSON.
+
+Dalam kondisi ini, ini berarti attribut JSON dan tipe data yang dimiliki, dll.
+
+#### Schema OpenAPI and JSON
+
+"schema" OpenAPI mendefinisikan skema API dari API yang anda buat. Skema tersebut termasuk definisi (atau "schema") dari data yang dikirim atau diterima oleh API dari **JSON Schema**, skema data standar JSON.
+
+#### Lihat `openapi.json`
+
+Jika anda penasaran bagaimana skema OpenAPI polos seperti apa, FastAPI secara otomatis membuat JSON (schema) dengan deksripsi API anda.
+
+anda bisa melihatnya di: http://127.0.0.1:8000/openapi.json.
+
+Anda akan melihat JSON yang dimulai seperti:
+
+```JSON
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "FastAPI",
+ "version": "0.1.0"
+ },
+ "paths": {
+ "/items/": {
+ "get": {
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+
+
+
+...
+```
+
+#### Kegunaan OpenAPI
+
+Skema OpenAPI adalah tulang punggung dua sistem dokumentasi API interaktif yang ada di FastAPI.
+
+Ada banyak alternatif sistem dokumentasi lainnya yang semuanya berdasarkan OpenAPI. Anda bisa menambahkannya ke aplikasi **FastAPI** anda.
+
+Anda juga bisa menggunakan OpenAPI untuk membuat kode secara otomatis, untuk klien yang menggunakan API anda. Sebagai contoh, frontend, aplikasi mobile atau IoT.
+
+## Ringkasan, secara bertahap
+
+### Langkah 1: impor `FastAPI`
+
+{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
+
+`FastAPI` adalah class Python yang menyediakan semua fungsionalitas API anda.
+
+/// note | Detail Teknis
+
+`FastAPI` adalah class turunan langsung dari `Starlette`.
+
+Anda bisa menggunakan semua fungsionalitas Starlette dengan `FastAPI` juga.
+
+///
+
+### Langkah 2: buat "instance" dari `FastAPI`
+
+{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
+
+Di sini variabel `app` akan menjadi sebuah "instance" dari class `FastAPI`.
+
+Ini akan menjadi gerbang utama untuk membuat semua API anda.
+
+### Langkah 3: Buat *operasi path*
+
+#### Path
+
+"Path" atau jalur di sini merujuk ke bagian URL terakhir dimulai dari `/` pertama.
+
+Sehingga, URL seperti:
+
+```
+https://example.com/items/foo
+```
+
+...path-nya adalah:
+
+```
+/items/foo
+```
+
+/// info
+
+"path" juga biasa disebut "endpoint" atau "route".
+
+///
+
+ketika membuat API, "path" adalah jalan utama untuk memisahkan "concern" dan "resources".
+
+#### Operasi
+
+"Operasi" di sini merujuk ke salah satu dari metode HTTP berikut.
+
+Salah satu dari:
+
+* `POST`
+* `GET`
+* `PUT`
+* `DELETE`
+
+...dan operasi lainnya yang unik:
+
+* `OPTIONS`
+* `HEAD`
+* `PATCH`
+* `TRACE`
+
+Dalam protokol HTTP, anda bisa berkomunikasi ke setiap path menggunakan satu (atau lebih) metode di atas.
+
+---
+
+Ketika membuat API, anda umumnya menggunakan metode HTTP tertentu untuk proses tertentu.
+
+Umumnya menggunakan:
+
+* `POST`: untuk membuat data.
+* `GET`: untuk membaca data.
+* `PUT`: untuk memperbarui data.
+* `DELETE`: untuk menghapus data.
+
+Sehingga, di OpanAPI, setiap metode HTTP ini disebut sebuah "operasi".
+
+Kita akan menyebut mereka juga "**operasi**".
+
+#### Mendefinisikan *dekorator operasi path*
+
+{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
+
+`@app.get("/")` memberitahu **FastAPI** bahwa fungsi di bawahnya mengurusi request yang menuju ke:
+
+* path `/`
+* menggunakan operasi get
+
+/// info | `@decorator` Info
+
+Sintaksis `@sesuatu` di Python disebut "dekorator".
+
+Dekorator ditempatkan di atas fungsi. Seperti sebuah topi cantik (Saya pikir istilah ini berasal dari situ).
+
+"dekorator" memanggil dan bekerja dengan fungsi yang ada di bawahnya
+
+Pada kondisi ini, dekorator ini memberi tahu **FastAPI** bahwa fungsi di bawah nya berhubungan dengan **path** `/` dengan **operasi** `get`.
+
+Sehingga disebut **dekorator operasi path**.
+
+///
+
+Operasi lainnya yang bisa digunakan:
+
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+
+Dan operasi unik lainnya:
+
+* `@app.options()`
+* `@app.head()`
+* `@app.patch()`
+* `@app.trace()`
+
+/// tip | Tips
+
+Jika anda bisa menggunakan operasi apa saja (metode HTTP).
+
+**FastAPI** tidak mengharuskan anda menggunakan operasi tertentu.
+
+Informasi di sini hanyalah sebagai panduan, bukan keharusan.
+
+Sebagai contoh, ketika menggunakan GraphQL, semua operasi umumnya hanya menggunakan `POST`.
+
+///
+
+### Langkah 4: mendefinisikan **fungsi operasi path**
+
+Ini "**fungsi operasi path**" kita:
+
+* **path**: adalah `/`.
+* **operasi**: adalah `get`.
+* **fungsi**: adalah fungsi yang ada di bawah dekorator (di bawah `@app.get("/")`).
+
+{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
+
+Ini adalah fungsi Python.
+
+Fungsi ini dipanggil **FastAPI** setiap kali menerima request ke URL "`/`" dengan operasi `GET`.
+
+Di kondisi ini, ini adalah sebuah fungsi `async`.
+
+---
+
+Anda bisa mendefinisikan fungsi ini sebagai fungsi normal daripada `async def`:
+
+{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
+
+/// note | Catatan
+
+Jika anda tidak tahu perbedaannya, kunjungi [Async: *"Panduan cepat"*](../async.md#in-a-hurry){.internal-link target=_blank}.
+
+///
+
+### Langkah 5: hasilkan konten
+
+{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
+
+Anda bisa menghasilkan `dict`, `list`, nilai singular seperti `str`, `int`, dll.
+
+Anda juga bisa menghasilkan model Pydantic (anda akan belajar mengenai ini nanti).
+
+Ada banyak objek dan model yang secara otomatis dikonversi ke JSON (termasuk ORM, dll). Anda bisa menggunakan yang anda suka, kemungkinan sudah didukung.
+
+## Ringkasan
+
+* Impor `FastAPI`.
+* Buat sebuah instance `app`.
+* Tulis **dekorator operasi path** menggunakan dekorator seperti `@app.get("/")`.
+* Definisikan **fungsi operasi path**; sebagai contoh, `def root(): ...`.
+* Jalankan server development dengan perintah `fastapi dev`.
diff --git a/docs/id/docs/tutorial/path-params.md b/docs/id/docs/tutorial/path-params.md
new file mode 100644
index 000000000..7c24de4d3
--- /dev/null
+++ b/docs/id/docs/tutorial/path-params.md
@@ -0,0 +1,258 @@
+# Parameter Path
+
+"parameter" atau "variabel" path didefinisikan dengan sintaksis Python format string:
+
+{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
+
+Nilai parameter path `item_id` akan dikirim ke fungsi sebagai argument `item_id`:
+
+Jika anda menjalankan contoh berikut dan kunjungi http://127.0.0.1:8000/items/foo, anda akan melihat respon:
+
+```JSON
+{"item_id":"foo"}
+```
+
+## Parameter path dengan tipe data
+
+Tipe data parameter path bisa didefinisikan di dalam fungsi, menggunakan anotasi tipe data standar Python:
+
+{* ../../docs_src/path_params/tutorial002.py hl[7] *}
+
+Dalam hal ini `item_id` didefinisikan sebagai `int`.
+
+/// check | Periksa
+
+Penyunting kode anda bisa membantu periksa di dalam fungsi seperti pemeriksaan kesalahan, kelengkapan kode, dll.
+
+///
+
+## Konversi data
+
+Jika contoh berikut dijalankan dan diakses browser melalui http://127.0.0.1:8000/items/3, anda akan melihat respon:
+
+```JSON
+{"item_id":3}
+```
+
+/// check | Periksa
+
+Perhatikan nilai fungsi yang diterima (dan dihasilkan) adalah `3`, sebagai `int` di Python, dan bukan string `"3"`.
+
+Sehingga dengan deklarasi tipe data **FastAPI** memberikan request otomatis "parsing".
+
+///
+
+## Validasi Data
+
+Tetapi jika di browser anda akses http://127.0.0.1:8000/items/foo, anda akan melihat pesan kesalahan HTTP:
+
+```JSON
+{
+ "detail": [
+ {
+ "type": "int_parsing",
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "Input should be a valid integer, unable to parse string as an integer",
+ "input": "foo",
+ "url": "https://errors.pydantic.dev/2.1/v/int_parsing"
+ }
+ ]
+}
+```
+
+Karena parameter path `item_id` bernilai `"foo"` yang bukan tipe data `int`.
+
+Kesalahan yang sama akan muncul jika menggunakan `float` daripada `int`, seperti di: http://127.0.0.1:8000/items/4.2
+
+/// check | Periksa
+
+Dengan deklarasi tipe data Python, **FastAPI** melakukan validasi data.
+
+Perhatikan kesalahan tersebut juga menjelaskan validasi apa yang tidak sesuai.
+
+Validasi ini sangat membantu ketika mengembangkan dan men-*debug* kode yang berhubungan dengan API anda.
+
+///
+
+## Dokumentasi
+
+Ketika anda membuka browser di http://127.0.0.1:8000/docs, anda melihat dokumentasi API interaktif otomatis berikut:
+
+
+
+/// check | Periksa
+
+Dengan deklarasi tipe data Python yang sama, **FastAPI** membuat dokumentasi interaktif otomatis (terintegrasi Swagger UI).
+
+Perhatikan parameter path dideklarasikan sebagai integer.
+
+///
+
+## Keuntungan basis-standar, dokumentasi alternatif
+
+Karena skema yang dibuat berasal dari standar OpenAPI, maka banyak alat lain yang kompatibel.
+
+Sehingga **FastAPI** menyediakan dokumentasi alternatif (menggunakan ReDoc), yang bisa diakses di http://127.0.0.1:8000/redoc:
+
+
+
+Cara yang sama untuk menggunakan tools kompatibel lainnya. Termasuk alat membuat kode otomatis untuk banyak bahasa.
+
+## Pydantic
+
+Semua validasi data dikerjakan di belakang layar oleh Pydantic, sehingga anda mendapatkan banyak kemudahan. Anda juga tahu proses ini akan ditangani dengan baik.
+
+Anda bisa mendeklarasikan tipe data dengan `str`, `float`, `bool` dan banyak tipe data kompleks lainnya.
+
+Beberapa tipe di atas akan dibahas pada bab berikutnya tutorial ini.
+
+## Urutan berpengaruh
+
+Ketika membuat *operasi path*, anda bisa menghadapi kondisi dimana *path* nya sudah tetap.
+
+Seperti `/users/me`, untuk mendapatkan data user yang sedang aktif.
+
+Kemudian anda bisa memiliki path `/users/{user_id}` untuk mendapatkan data user tertentu melalui user ID.
+
+karena *operasi path* dievaluasi melalui urutan, anda harus memastikan path untuk `/users/me` dideklarasikan sebelum `/user/{user_id}`:
+
+{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
+
+Sebaliknya, path `/users/{user_id}` juga akan sesuai dengan `/users/me`, "menganggap" menerima parameter `user_id` dengan nilai `"me"`.
+
+Serupa, anda juga tidak bisa mendefinisikan operasi path:
+
+{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *}
+
+Path pertama akan selalu digunakan karena path sesuai dengan yang pertama.
+
+## Nilai terdefinisi
+
+Jika ada *operasi path* yang menerima *parameter path*, tetapi anda ingin nilai valid *parameter path* sudah terdefinisi, anda bisa menggunakan standar Python `Enum`.
+
+### Membuat class `Enum`
+
+Import `Enum` dan buat *sub-class* warisan dari `str` dan `Enum`.
+
+Dengan warisan dari `str` dokumen API mengetahui nilai nya harus berjenis `string` supaya bisa digunakan dengan benar.
+
+Kemudian buat atribut *class* dengan nilai tetap *string* yang benar:
+
+{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
+
+/// info
+
+Enumerasi (atau enum) tersedia di Python sejak versi 3.4.
+
+///
+
+/// tip | Tips
+
+"AlxexNet", "ResNet", dan "LeNet" adalah nama model *Machine Learning*.
+
+///
+
+### Mendeklarasikan *parameter path*
+
+Kemudian buat *parameter path* dengan tipe anotasi menggunakan *class* enum dari (`ModelName`)
+
+{* ../../docs_src/path_params/tutorial005.py hl[16] *}
+
+### Periksa dokumentasi
+
+Karena nilai yang tersedia untuk *parameter path* telah terdefinisi, dokumen interatik bisa memunculkan:
+
+
+
+### Bekerja dengan *enumarasi* Python
+
+Nilai *parameter path* akan menjadi *anggota enumerasi*.
+
+#### Membandingkan *anggota enumerasi*
+
+Anda bisa membandingkan parameter *path* dengan *anggota enumerasi* di enum `ModelName` yang anda buat:
+
+{* ../../docs_src/path_params/tutorial005.py hl[17] *}
+
+#### Mendapatkan *nilai enumerasi*
+
+Anda bisa mendapatkan nilai (`str` dalam kasus ini) menggunakan `model_name.value`, atau secara umum `anggota_enum_anda.value`:
+
+{* ../../docs_src/path_params/tutorial005.py hl[20] *}
+
+/// tip | Tips
+
+Anda bisa mengakses nilai `"lenet"` dnegan `ModelName.lenet.value`.
+
+///
+
+#### Menghasilkan *anggota enumerasi*
+
+Anda bisa menghasilkan *anggota enumerasi* dari *operasi path* bahkan di body JSON bersarang (contoh `dict`).
+
+They will be converted to their corresponding values (strings in this case) before returning them to the client:
+
+{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
+
+Klien akan mendapatkan respon JSON seperti berikut:
+
+```JSON
+{
+ "model_name": "alexnet",
+ "message": "Deep Learning FTW!"
+}
+```
+
+## Parameter path berisi path
+
+Misalkan terdapat *operasi path* dengan path `/files/{file_path}`.
+
+Tetapi anda memerlukan `file_path` itu berisi *path*, seperti like `home/johndoe/myfile.txt`.
+
+Sehingga URL untuk file tersebut akan seperti: `/files/home/johndoe/myfile.txt`.
+
+### Dukungan OpenAPI
+
+OpenAPI tidak bisa mendeklarasikan *parameter path* berisi *path* di dalamnya, karena menyebabkan kondisi yang sulit di*test* dan didefinisikan.
+
+Tetapi, di **FastAPI** anda tetap bisa melakukannya dengan menggunakan *tools* internal dari Starlette.
+
+Dan dokumentasi tetap berfungsi walaupun tidak menambahkan keterangan bahwa parameter harus berisi *path*.
+
+### Konverter path
+
+Melalui Starlette anda bisa mendeklarasikan *parameter path* berisi *path* dengan URL seperti:
+
+```
+/files/{file_path:path}
+```
+
+Dikondisi ini nama parameter adalah `file_path` dan bagian terakhir `:path` menginformasikan parameter harus sesuai dengan setiap *path*.
+
+Sehingga anda bisa menggunakan:
+
+{* ../../docs_src/path_params/tutorial004.py hl[6] *}
+
+/// tip | Tips
+
+Anda mungkin perlu parameter berisi `/home/johndoe/myfile.txt` di awali garis belakang (`/`).
+
+Di kondisi ini, URL nya menjadi: `/files//home/johndoe/myfile.txt`, dengan dua garis belakang (`//`) di antara `files` dan `home`.
+
+///
+
+## Ringkasan
+
+Di **FastAPI** dengan menggunakan deklarasi tipe Python standar, pendek, intuitif, anda mendapatkan:
+
+* Dukungan editor: pemeriksaan kesalahan, autocompletion, dll.
+* "Parsing" data.
+* Validasi data.
+* Annotasi API dan dokumentasi otomatis.
+
+Semua itu anda hanya perlu mendeklarasikan sekali saja.
+
+Ini adalah salah satu keunggulan **FastAPI** dibandingkan dengan *framework* lainnya (selain dari performa Python *native*c)
diff --git a/docs/id/docs/tutorial/static-files.md b/docs/id/docs/tutorial/static-files.md
new file mode 100644
index 000000000..b55f31394
--- /dev/null
+++ b/docs/id/docs/tutorial/static-files.md
@@ -0,0 +1,40 @@
+# Berkas Statis
+
+Anda dapat menyajikan berkas statis secara otomatis dari sebuah direktori menggunakan `StaticFiles`.
+
+## Penggunaan `StaticFiles`
+
+* Mengimpor `StaticFiles`.
+* "Mount" representatif `StaticFiles()` di jalur spesifik.
+
+{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
+
+/// note | Detail Teknis
+
+Anda dapat pula menggunakan `from starlette.staticfiles import StaticFiles`.
+
+**FastAPI** menyediakan `starlette.staticfiles` sama seperti `fastapi.staticfiles` sebagai kemudahan pada Anda, yaitu para pengembang. Tetapi ini asli berasal langsung dari Starlette.
+
+///
+
+### Apa itu "Mounting"
+
+"Mounting" dimaksud menambah aplikasi "independen" secara lengkap di jalur spesifik, kemudian menangani seluruh sub-jalur.
+
+Hal ini berbeda dari menggunakan `APIRouter` karena aplikasi yang dimount benar-benar independen. OpenAPI dan dokumentasi dari aplikasi utama Anda tak akan menyertakan apa pun dari aplikasi yang dimount, dst.
+
+Anda dapat mempelajari mengenai ini dalam [Panduan Pengguna Lanjutan](../advanced/index.md){.internal-link target=_blank}.
+
+## Detail
+
+Terhadap `"/static"` pertama mengacu pada sub-jalur yang akan menjadi tempat "sub-aplikasi" ini akan "dimount". Maka, jalur apa pun yang dimulai dengan `"/static"` akan ditangani oleh sub-jalur tersebut.
+
+Terhadap `directory="static"` mengacu pada nama direktori yang berisi berkas statis Anda.
+
+Terhadap `name="static"` ialah nama yang dapat digunakan secara internal oleh **FastAPI**.
+
+Seluruh parameter ini dapat berbeda dari sekadar "`static`", sesuaikan parameter dengan keperluan dan detail spesifik akan aplikasi Anda.
+
+## Info lanjutan
+
+Sebagai detail dan opsi tambahan lihat dokumentasi Starlette perihal Berkas Statis.
diff --git a/docs/it/docs/index.md b/docs/it/docs/index.md
index 8a1039bc5..dc8f5b846 100644
--- a/docs/it/docs/index.md
+++ b/docs/it/docs/index.md
@@ -4,15 +4,19 @@
FastAPI framework, alte prestazioni, facile da imparare, rapido da implementare, pronto per il rilascio in produzione
-
-```console
-$ typer --install-completion
-
-zsh completion installed in /home/user/.bashrc.
-Completion will take effect once you restart the terminal.
-```
-
-
-
-### アプリとドキュメントを同時に
-
-以下の様にサンプルを実行すると:
-
-
-
-```console
-$ uvicorn tutorial001:app --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-```console
-// 「build-all」コマンドは少し時間がかかります。
-$ python ./scripts/docs.py build-all
-
-Updating es
-Updating en
-Building docs for: en
-Building docs for: es
-Successfully built docs for: es
-Copying en index.md to README.md
-```
-
-
-
-```console
-// 「build-all」コマンドの実行の後に、「serve」コマンドを使います
-$ python ./scripts/docs.py serve
-
-Warning: this is a very simple server. For development, use mkdocs serve instead.
-This is here only to preview a site with translations already built.
-Make sure you run the build-all command first.
-Serving at: http://127.0.0.1:8008
-```
-
-
+
+```console
+// You could create an env var MY_NAME with
+$ export MY_NAME="Wade Wilson"
+
+// Then you could use it with other programs, like
+$ echo "Hello $MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+
+```console
+// Create an env var MY_NAME
+$ $Env:MY_NAME = "Wade Wilson"
+
+// Use it with other programs, like
+$ echo "Hello $Env:MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+```console
+// Here we don't set the env var yet
+$ python main.py
+
+// As we didn't set the env var, we get the default value
+
+Hello World from Python
+
+// But if we create an environment variable first
+$ export MY_NAME="Wade Wilson"
+
+// And then call the program again
+$ python main.py
+
+// Now it can read the environment variable
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Here we don't set the env var yet
+$ python main.py
+
+// As we didn't set the env var, we get the default value
+
+Hello World from Python
+
+// But if we create an environment variable first
+$ $Env:MY_NAME = "Wade Wilson"
+
+// And then call the program again
+$ python main.py
+
+// Now it can read the environment variable
+
+Hello Wade Wilson from Python
+```
+
+
+
+```console
+// Create an env var MY_NAME in line for this program call
+$ MY_NAME="Wade Wilson" python main.py
+
+// Now it can read the environment variable
+
+Hello Wade Wilson from Python
+
+// The env var no longer exists afterwards
+$ python main.py
+
+Hello World from Python
+```
+
+
+
+```console
+// Go to the home directory
+$ cd
+// Create a directory for all your code projects
+$ mkdir code
+// Enter into that code directory
+$ cd code
+// Create a directory for this project
+$ mkdir awesome-project
+// Enter into that project directory
+$ cd awesome-project
+```
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎
+$ deactivate
+
+// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀
+$ source .venv/bin/activate
+
+// Now when you run python, it will find the package sirius installed in this virtual environment ✨
+$ python main.py
+
+I solemnly swear 🐺
+```
+
+
+
+## 代替手段
+
+これは、あらゆる仕組みを**根本から**学ぶためのシンプルな入門ガイドです。
+
+仮想環境、パッケージの依存関係(requirements)、プロジェクトの管理には、多くの**代替手段**があります。
+
+準備が整い、パッケージの依存関係、仮想環境など**プロジェクト全体の管理**ツールを使いたいと考えたら、uv を試してみることをおすすめします。
+
+`uv` では以下のような多くのことができます:
+
+* 異なるバージョンも含めた**Python のインストール**
+* プロジェクトごとの**仮想環境**の管理
+* **パッケージ**のインストール
+* プロジェクトのパッケージの**依存関係やバージョン**の管理
+* パッケージとそのバージョンの、依存関係を含めた**厳密な**組み合わせを保持し、これによって、本番環境で、開発環境と全く同じようにプロジェクトを実行できる(これは**locking**と呼ばれます)
+* その他のさまざまな機能
+
+## まとめ
+
+ここまで読みすべて理解したなら、世間の多くの開発者と比べて、仮想環境について**あなたはより多くのことを知っています**。🤓
+
+これらの詳細を知ることは、将来、複雑に見える何かのデバッグにきっと役立つでしょう。しかし、その頃には、あなたは**そのすべての動作を根本から**理解しているでしょう。😎
diff --git a/docs/ko/docs/advanced/additional-status-codes.md b/docs/ko/docs/advanced/additional-status-codes.md
new file mode 100644
index 000000000..da06cb778
--- /dev/null
+++ b/docs/ko/docs/advanced/additional-status-codes.md
@@ -0,0 +1,41 @@
+# 추가 상태 코드
+
+기본적으로 **FastAPI**는 응답을 `JSONResponse`를 사용하여 반환하며, *경로 작업(path operation)*에서 반환한 내용을 해당 `JSONResponse` 안에 넣어 반환합니다.
+
+기본 상태 코드 또는 *경로 작업*에서 설정한 상태 코드를 사용합니다.
+
+## 추가 상태 코드
+
+기본 상태 코드와 별도로 추가 상태 코드를 반환하려면 `JSONResponse`와 같이 `Response`를 직접 반환하고 추가 상태 코드를 직접 설정할 수 있습니다.
+
+예를 들어 항목을 업데이트할 수 있는 *경로 작업*이 있고 성공 시 200 “OK”의 HTTP 상태 코드를 반환한다고 가정해 보겠습니다.
+
+하지만 새로운 항목을 허용하기를 원할 것입니다. 항목이 이전에 존재하지 않았다면 이를 생성하고 HTTP 상태 코드 201 "Created"를 반환합니다.
+
+이를 위해서는 `JSONResponse`를 가져와서 원하는 `status_code`를 설정하여 콘텐츠를 직접 반환합니다:
+
+{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
+
+/// warning | 경고
+
+위의 예제처럼 `Response`를 직접 반환하면 바로 반환됩니다.
+
+모델 등과 함께 직렬화되지 않습니다.
+
+원하는 데이터가 있는지, 값이 유효한 JSON인지 확인합니다(`JSONResponse`를 사용하는 경우).
+
+///
+
+/// note | 기술적 세부 정보
+
+`from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
+
+**FastAPI**는 개발자 여러분을 위한 편의성으로 `fastapi.responses`와 동일한 `starlette.responses`를 제공합니다. 그러나 사용 가능한 응답의 대부분은 Starlette에서 직접 제공됩니다. `status` 또한 마찬가지입니다.
+
+///
+
+## OpenAPI 및 API 문서
+
+추가 상태 코드와 응답을 직접 반환하는 경우, FastAPI는 반환할 내용을 미리 알 수 있는 방법이 없기 때문에 OpenAPI 스키마(API 문서)에 포함되지 않습니다.
+
+하지만 다음을 사용하여 코드에 이를 문서화할 수 있습니다: [추가 응답](additional-responses.md){.internal-link target=_blank}.
diff --git a/docs/ko/docs/advanced/advanced-dependencies.md b/docs/ko/docs/advanced/advanced-dependencies.md
index aa5a332f8..7fa043fa3 100644
--- a/docs/ko/docs/advanced/advanced-dependencies.md
+++ b/docs/ko/docs/advanced/advanced-dependencies.md
@@ -18,35 +18,7 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법
이를 위해 `__call__` 메서드를 선언합니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="12"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | 참고
-
-가능하다면 `Annotated` 버전을 사용하는 것이 좋습니다.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
이 경우, **FastAPI**는 추가 매개변수와 하위 의존성을 확인하기 위해 `__call__`을 사용하게 되며,
나중에 *경로 연산 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다.
@@ -55,35 +27,7 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법
이제 `__init__`을 사용하여 의존성을 "매개변수화"할 수 있는 인스턴스의 매개변수를 선언할 수 있습니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="8"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | 참고
-
-가능하다면 `Annotated` 버전을 사용하는 것이 좋습니다.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
이 경우, **FastAPI**는 `__init__`에 전혀 관여하지 않으며, 우리는 이 메서드를 코드에서 직접 사용하게 됩니다.
@@ -91,35 +35,7 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법
다음과 같이 이 클래스의 인스턴스를 생성할 수 있습니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="18"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | 참고
-
-가능하다면 `Annotated` 버전을 사용하는 것이 좋습니다.
-
-///
-
-```Python hl_lines="16"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
이렇게 하면 `checker.fixed_content` 속성에 `"bar"`라는 값을 담아 의존성을 "매개변수화"할 수 있습니다.
@@ -136,35 +52,7 @@ checker(q="somequery")
...그리고 이때 반환되는 값을 *경로 연산 함수*의 `fixed_content_included` 매개변수로 전달합니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="22"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="21"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | 참고
-
-가능하다면 `Annotated` 버전을 사용하는 것이 좋습니다.
-
-///
-
-```Python hl_lines="20"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
/// tip | 참고
diff --git a/docs/ko/docs/advanced/async-tests.md b/docs/ko/docs/advanced/async-tests.md
new file mode 100644
index 000000000..37dfe2979
--- /dev/null
+++ b/docs/ko/docs/advanced/async-tests.md
@@ -0,0 +1,108 @@
+# 비동기 테스트 코드 작성
+
+이전 장에서 `TestClient` 를 이용해 **FastAPI** 어플리케이션 테스트를 작성하는 법을 배우셨을텐데요.
+지금까지는 `async` 키워드 사용없이 동기 함수의 테스트 코드를 작성하는 법만 익혔습니다.
+
+하지만 비동기 함수를 사용하여 테스트 코드를 작성하는 것은 매우 유용할 수 있습니다.
+예를 들면 데이터베이스에 비동기로 쿼리하는 경우를 생각해봅시다.
+FastAPI 애플리케이션에 요청을 보내고, 비동기 데이터베이스 라이브러리를 사용하여 백엔드가 데이터베이스에 올바르게 데이터를 기록했는지 확인하고 싶을 때가 있을 겁니다.
+
+이런 경우의 테스트 코드를 어떻게 비동기로 작성하는지 알아봅시다.
+
+## pytest.mark.anyio
+
+앞에서 작성한 테스트 함수에서 비동기 함수를 호출하고 싶다면, 테스트 코드도 비동기 함수여야합니다.
+AnyIO는 특정 테스트 함수를 비동기 함수로 호출 할 수 있는 깔끔한 플러그인을 제공합니다.
+
+
+## HTTPX
+
+**FastAPI** 애플리케이션이 `async def` 대신 `def` 키워드로 선언된 함수를 사용하더라도, 내부적으로는 여전히 `비동기` 애플리케이션입니다.
+
+`TestClient`는 pytest 표준을 사용하여 비동기 FastAPI 애플리케이션을 일반적인 `def` 테스트 함수 내에서 호출할 수 있도록 내부에서 마술을 부립니다. 하지만 이 마술은 비동기 함수 내부에서 사용할 때는 더 이상 작동하지 않습니다. 테스트를 비동기로 실행하면, 더 이상 테스트 함수 내부에서 `TestClient`를 사용할 수 없습니다.
+
+`TestClient`는 HTTPX를 기반으로 하고 있으며, 다행히 이를 직접 사용하여 API를 테스트할 수 있습니다.
+
+## 예시
+
+간단한 예시를 위해 [더 큰 어플리케이션 만들기](../ko/tutorial/bigger-applications.md){.internal-link target=_blank} 와 [테스트](../ko/tutorial/testing.md){.internal-link target=_blank}:에서 다룬 파일 구조와 비슷한 형태를 확인해봅시다:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+ `main.py`는 아래와 같아야 합니다:
+
+{* ../../docs_src/async_tests/main.py *}
+
+`test_main.py` 파일은 `main.py`에 대한 테스트가 있을 텐데, 다음과 같을 수 있습니다:
+
+{* ../../docs_src/async_tests/test_main.py *}
+
+## 실행하기
+
+아래의 명령어로 테스트 코드를 실행합니다:
+
+
+
+```console
+$ pytest
+
+---> 100%
+```
+
+
+
+## 자세히 보기
+
+`@pytest.mark.anyio` 마커는 pytest에게 이 테스트 함수가 비동기로 호출되어야 함을 알려줍니다:
+
+{* ../../docs_src/async_tests/test_main.py hl[7] *}
+
+/// tip | 팁
+
+테스트 함수가 이제 `TestClient`를 사용할 때처럼 단순히 `def`가 아니라 `async def`로 작성된 점에 주목해주세요.
+
+///
+
+그 다음에 `AsyncClient` 로 앱을 만들고 비동기 요청을 `await` 키워드로 보낼 수 있습니다:
+
+{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
+
+위의 코드는:
+
+```Python
+response = client.get('/')
+```
+
+`TestClient` 에 요청을 보내던 것과 동일합니다.
+
+/// tip | 팁
+
+새로운 `AsyncClient`를 사용할 때 async/await를 사용하고 있다는 점에 주목하세요. 이 요청은 비동기적으로 처리됩니다.
+
+///
+
+/// warning | 경고
+
+만약의 어플리케이션이 Lifespan 이벤트에 의존성을 갖고 있다면 `AsyncClient` 가 이러한 이벤트를 실행시키지 않습니다.
+`AsyncClient` 가 테스트를 실행시켰다는 것을 확인하기 위해
+`LifespanManager` from florimondmanca/asgi-lifespan.확인해주세요.
+
+
+///
+
+## 그 외의 비동기 함수 호출
+
+테스트 함수가 이제 비동기 함수이므로, FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 호출하고 `await` 키워드를 사용 할 수 있습니다.
+
+/// tip | 팁
+
+테스트에 비동기 함수 호출을 통합할 때 (예: MongoDB의 MotorClient를 사용할 때) `RuntimeError: Task attached to a different loop` 오류가 발생한다면, 이벤트 루프가 필요한 객체는 반드시 비동기 함수 내에서만 인스턴스화해야 한다는 점을 주의하세요!
+예를 들어 `@app.on_event("startup")` 콜백 내에서 인스턴스화하는 것이 좋습니다.
+
+///
diff --git a/docs/ko/docs/advanced/custom-response.md b/docs/ko/docs/advanced/custom-response.md
new file mode 100644
index 000000000..2001956fa
--- /dev/null
+++ b/docs/ko/docs/advanced/custom-response.md
@@ -0,0 +1,313 @@
+# 사용자 정의 응답 - HTML, Stream, 파일, 기타
+
+기본적으로, **FastAPI** 응답을 `JSONResponse`를 사용하여 반환합니다.
+
+이를 재정의 하려면 [응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 본 것처럼 `Response`를 직접 반환하면 됩니다.
+
+그러나 `Response` (또는 `JSONResponse`와 같은 하위 클래스)를 직접 반환하면, 데이터가 자동으로 변환되지 않으며 (심지어 `response_model`을 선언했더라도), 문서화가 자동으로 생성되지 않습니다(예를 들어, 생성된 OpenAPI의 일부로 HTTP 헤더 `Content-Type`에 특정 "미디어 타입"을 포함하는 경우).
+
+하지만 *경로 작업 데코레이터*에서 `response_class` 매개변수를 사용하여 원하는 `Response`(예: 모든 `Response` 하위 클래스)를 선언할 수도 있습니다.
+
+*경로 작업 함수*에서 반환하는 내용은 해당 `Response`안에 포함됩니다.
+
+그리고 만약 그 `Response`가 `JSONResponse`와 `UJSONResponse`의 경우 처럼 JSON 미디어 타입(`application/json`)을 가지고 있다면, *경로 작업 데코레이터*에서 선언한 Pydantic의 `response_model`을 사용해 자동으로 변환(및 필터링) 됩니다.
+
+/// note | 참고
+
+미디어 타입이 없는 응답 클래스를 사용하는 경우, FastAPI는 응답에 내용이 없을 것으로 예상하므로 생성된 OpenAPI 문서에서 응답 형식을 문서화하지 않습니다.
+
+///
+
+## `ORJSONResponse` 사용하기
+
+예를 들어, 성능을 극대화하려는 경우, orjson을 설치하여 사용하고 응답을 `ORJSONResponse`로 설정할 수 있습니다.
+
+사용하고자 하는 `Response` 클래스(하위 클래스)를 임포트한 후, **경로 작업 데코레이터*에서 선언하세요.
+
+대규모 응답의 경우, 딕셔너리를 반환하는 것보다 `Response`를 반환하는 것이 훨씬 빠릅니다.
+
+이유는 기본적으로, FastAPI가 내부의 모든 항목을 검사하고 JSON으로 직렬화할 수 있는지 확인하기 때문입니다. 이는 사용자 안내서에서 설명된 [JSON 호환 가능 인코더](../tutorial/encoder.md){.internal-link target=_blank}를 사용하는 방식과 동일합니다. 이를 통해 데이터베이스 모델과 같은 **임의의 객체**를 반환할 수 있습니다.
+
+하지만 반환하는 내용이 **JSON으로 직렬화 가능**하다고 확신하는 경우, 해당 내용을 응답 클래스에 직접 전달할 수 있으며, FastAPI가 반환 내용을 `jsonable_encoder`를 통해 처리한 뒤 응답 클래스에 전달하는 오버헤드를 피할 수 있습니다.
+
+{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
+
+/// info | 정보
+
+`response_class` 매개변수는 응답의 "미디어 타입"을 정의하는 데에도 사용됩니다.
+
+이 경우, HTTP 헤더 `Content-Type`은 `application/json`으로 설정됩니다.
+
+그리고 이는 OpenAPI에 그대로 문서화됩니다.
+
+///
+
+/// tip | 팁
+
+`ORJSONResponse`는 FastAPI에서만 사용할 수 있고 Starlette에서는 사용할 수 없습니다.
+
+///
+
+## HTML 응답
+
+**FastAPI**에서 HTML 응답을 직접 반환하려면 `HTMLResponse`를 사용하세요.
+
+* `HTMLResponse`를 임포트 합니다.
+* *경로 작업 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다.
+
+{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
+
+/// info | 정보
+
+`response_class` 매개변수는 응답의 "미디어 타입"을 정의하는 데에도 사용됩니다.
+
+이 경우, HTTP 헤더 `Content-Type`은 `text/html`로 설정됩니다.
+
+그리고 이는 OpenAPI에 그대로 문서화 됩니다.
+
+///
+
+### `Response` 반환하기
+
+[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 본 것 처럼, *경로 작업*에서 응답을 직접 반환하여 재정의할 수도 있습니다.
+
+위의 예제와 동일하게 `HTMLResponse`를 반환하는 코드는 다음과 같을 수 있습니다:
+
+{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
+
+/// warning | 경고
+
+*경로 작업 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를들어, `Content-Type`이 문서화되지 않음) 자동 대화형 문서에서도 표시되지 않습니다.
+
+///
+
+/// info | 정보
+
+물론 실제 `Content-Type` 헤더, 상태 코드 등은 반환된 `Response` 객체에서 가져옵니다.
+
+///
+
+### OpenAPI에 문서화하고 `Response` 재정의 하기
+
+함수 내부에서 응답을 재정의하면서 동시에 OpenAPI에서 "미디어 타입"을 문서화하고 싶다면, `response_class` 매게변수를 사용하면서 `Response` 객체를 반환할 수 있습니다.
+
+이 경우 `response_class`는 OpenAPI *경로 작업*을 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `Response`가 그대로 사용됩니다.
+
+### `HTMLResponse`직접 반환하기
+
+예를 들어, 다음과 같이 작성할 수 있습니다:
+
+{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
+
+이 예제에서, `generate_html_response()` 함수는 HTML을 `str`로 반환하는 대신 이미 `Response`를 생성하고 반환합니다.
+
+`generate_html_response()`를 호출한 결과를 반환함으로써, 기본적인 **FastAPI** 기본 동작을 재정의 하는 `Response`를 이미 반환하고 있습니다.
+
+하지만 `response_class`에 `HTMLResponse`를 함께 전달했기 때문에, FastAPI는 이를 OpenAPI 및 대화형 문서에서 `text/html`로 HTML을 문서화 하는 방법을 알 수 있습니다.
+
+
+
+## 사용 가능한 응답들
+
+다음은 사용할 수 있는 몇가지 응답들 입니다.
+
+`Response`를 사용하여 다른 어떤 것도 반환 할수 있으며, 직접 하위 클래스를 만들 수도 있습니다.
+
+/// note | 기술 세부사항
+
+`from starlette.responses import HTMLResponse`를 사용할 수도 있습니다.
+
+**FastAPI**는 개발자인 여러분의 편의를 위해 `starlette.responses`를 `fastapi.responses`로 제공 하지만, 대부분의 사용 가능한 응답은 Starlette에서 직접 가져옵니다.
+
+///
+
+### `Response`
+
+기본 `Response` 클래스는 다른 모든 응답 클래스의 부모 클래스 입니다.
+
+이 클래스를 직접 반환할 수 있습니다.
+
+다음 매개변수를 받을 수 있습니다:
+
+* `content` - `str` 또는 `bytes`.
+* `status_code` - HTTP 상태코드를 나타내는 `int`.
+* `headers` - 문자열로 이루어진 `dict`.
+* `media_type` - 미디어 타입을 나타내는 `str` 예: `"text/html"`.
+
+FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포함시킵니다. 또한 `media_type`에 기반하여 `Content-Type` 헤더를 포함하며, 텍스트 타입의 경우 문자 집합을 추가 합니다.
+
+{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
+
+### `HTMLResponse`
+
+텍스트 또는 바이트를 받아 HTML 응답을 반환합니다. 위에서 설명한 내용과 같습니다.
+
+### `PlainTextResponse`
+
+텍스트 또는 바이트를 받아 일반 텍스트 응답을 반환합니다.
+
+{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}
+
+### `JSONResponse`
+
+데이터를 받아 `application/json`으로 인코딩된 응답을 반환합니다.
+
+이는 위에서 설명했듯이 **FastAPI**에서 기본적으로 사용되는 응답 형식입니다.
+
+### `ORJSONResponse`
+
+ `orjson`을 사용하여 빠른 JSON 응답을 제공하는 대안입니다. 위에서 설명한 내용과 같습니다.
+
+/// info | 정보
+
+이를 사용하려면 `orjson`을 설치해야합니다. 예: `pip install orjson`.
+
+///
+
+### `UJSONResponse`
+
+`ujson`을 사용한 또 다른 JSON 응답 형식입니다.
+
+/// info | 정보
+
+이 응답을 사용하려면 `ujson`을 설치해야합니다. 예: 'pip install ujson`.
+
+///
+
+/// warning | 경고
+
+`ujson` 은 일부 예외 경우를 처리하는 데 있어 Python 내장 구현보다 덜 엄격합니다.
+
+///
+
+{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
+
+/// tip | 팁
+
+`ORJSONResponse`가 더 빠른 대안일 가능성이 있습니다.
+
+///
+
+### `RedirectResponse`
+
+HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 307(임시 리디렉션)으로 설정됩니다.
+
+`RedirectResponse`를 직접 반환할 수 있습니다.
+
+{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
+
+---
+
+또는 `response_class` 매개변수에서 사용할 수도 있습니다:
+
+
+{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *}
+
+이 경우, *경로 작업* 함수에서 URL을 직접 반환할 수 있습니다.
+
+이 경우, 사용되는 `status_code`는 `RedirectResponse`의 기본값인 `307` 입니다.
+
+---
+
+`status_code` 매개변수를 `response_class` 매개변수와 함께 사용할 수도 있습니다:
+
+{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *}
+
+### `StreamingResponse`
+
+비동기 제너레이터 또는 일반 제너레이터/이터레이터를 받아 응답 본문을 스트리밍 합니다.
+
+{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
+
+#### 파일과 같은 객체를 사용한 `StreamingResponse`
+
+파일과 같은 객체(예: `open()`으로 반환된 객체)가 있는 경우, 해당 파일과 같은 객체를 반복(iterate)하는 제너레이터 함수를 만들 수 있습니다.
+
+이 방식으로, 파일 전체를 메모리에 먼저 읽어들일 필요 없이, 제너레이터 함수를 `StreamingResponse`에 전달하여 반환할 수 있습니다.
+
+이 방식은 클라우드 스토리지, 비디오 처리 등의 다양한 라이브러리와 함께 사용할 수 있습니다.
+
+{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}
+
+1. 이것이 제너레이터 함수입니다. `yield` 문을 포함하고 있으므로 "제너레이터 함수"입니다.
+2. `with` 블록을 사용함으로써, 제너레이터 함수가 완료된 후 파일과 같은 객체가 닫히도록 합니다. 즉, 응답 전송이 끝난 후 닫힙니다.
+3. 이 `yield from`은 함수가 `file_like`라는 객체를 반복(iterate)하도록 합니다. 반복된 각 부분은 이 제너레이터 함수(`iterfile`)에서 생성된 것처럼 `yield` 됩니다.
+
+ 이렇게 하면 "생성(generating)" 작업을 내부적으로 다른 무언가에 위임하는 제너레이터 함수가 됩니다.
+
+ 이 방식을 사용하면 `with` 블록 안에서 파일을 열 수 있어, 작업이 완료된 후 파일과 같은 객체가 닫히는 것을 보장할 수 있습니다.
+
+/// tip | 팁
+
+여기서 표준 `open()`을 사용하고 있기 때문에 `async`와 `await`를 지원하지 않습니다. 따라서 경로 작업은 일반 `def`로 선언합니다.
+
+///
+
+### `FileResponse`
+
+파일을 비동기로 스트리밍하여 응답합니다.
+
+다른 응답 유형과는 다른 인수를 사용하여 객체를 생성합니다:
+
+* `path` - 스트리밍할 파일의 경로.
+* `headers` - 딕셔너리 형식의 사용자 정의 헤더.
+* `media_type` - 미디어 타입을 나타내는 문자열. 설정되지 않은 경우 파일 이름이나 경로를 사용하여 추론합니다.
+* `filename` - 설정된 경우 응답의 `Content-Disposition`에 포함됩니다.
+
+파일 응답에는 적절한 `Content-Length`, `Last-Modified`, 및 `ETag` 헤더가 포함됩니다.
+
+{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}
+
+또한 `response_class` 매개변수를 사용할 수도 있습니다:
+
+{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *}
+
+이 경우, 경로 작업 함수에서 파일 경로를 직접 반환할 수 있습니다.
+
+## 사용자 정의 응답 클래스
+
+`Response`를 상속받아 사용자 정의 응답 클래스를 생성하고 사용할 수 있습니다.
+
+예를 들어, 포함된 `ORJSONResponse` 클래스에서 사용되지 않는 설정으로 orjson을 사용하고 싶다고 가정해봅시다.
+
+만약 들여쓰기 및 포맷된 JSON을 반환하고 싶다면, `orjson.OPT_INDENT_2` 옵션을 사용할 수 있습니다.
+
+`CustomORJSONResponse`를 생성할 수 있습니다. 여기서 핵심은 `Response.render(content)` 메서드를 생성하여 내용을 `bytes`로 반환하는 것입니다:
+
+{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *}
+
+이제 다음 대신:
+
+```json
+{"message": "Hello World"}
+```
+
+이 응답은 이렇게 반환됩니다:
+
+```json
+{
+ "message": "Hello World"
+}
+```
+
+물론 JSON 포맷팅보다 더 유용하게 활용할 방법을 찾을 수 있을 것입니다. 😉
+
+## 기본 응답 클래스
+
+**FastAPI** 클래스 객체 또는 `APIRouter`를 생성할 때 기본적으로 사용할 응답 클래스를 지정할 수 있습니다.
+
+이를 정의하는 매개변수는 `default_response_class`입니다.
+
+아래 예제에서 **FastAPI**는 모든 경로 작업에서 기본적으로 `JSONResponse` 대신 `ORJSONResponse`를 사용합니다.
+
+{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
+
+/// tip | 팁
+
+여전히 이전처럼 *경로 작업*에서 `response_class`를 재정의할 수 있습니다.
+
+///
+
+## 추가 문서화
+
+OpenAPI에서 `responses`를 사용하여 미디어 타입 및 기타 세부 정보를 선언할 수도 있습니다: [OpenAPI에서 추가 응답](additional-responses.md){.internal-link target=_blank}.
diff --git a/docs/ko/docs/advanced/events.md b/docs/ko/docs/advanced/events.md
index 273c9a479..5f8fe0f1e 100644
--- a/docs/ko/docs/advanced/events.md
+++ b/docs/ko/docs/advanced/events.md
@@ -1,57 +1,165 @@
-# 이벤트: startup과 shutdown
+# Lifespan 이벤트
-필요에 따라 응용 프로그램이 시작되기 전이나 종료될 때 실행되는 이벤트 핸들러(함수)를 정의할 수 있습니다.
+애플리케이션 **시작 전**에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, **애플리케이션이 요청을 받기 시작하기 전**에 실행된다는 의미입니다.
-이 함수들은 `async def` 또는 평범하게 `def`으로 선언할 수 있습니다.
+마찬가지로, 애플리케이션이 **종료될 때** 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다.
-/// warning | 경고
+이 코드가 애플리케이션이 **요청을 받기 시작하기 전에** 실행되고, 요청 처리가 끝난 후 **종료 직전에** 실행되기 때문에 전체 애플리케이션의 **수명(Lifespan)**을 다룹니다. (잠시 후 "수명"이라는 단어가 중요해집니다 😉)
+
+이 방법은 전체 애플리케이션에서 사용해야 하는 **자원**을 설정하거나 요청 간에 **공유되는** 자원을 설정하고, 또는 그 후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유되는 머신러닝 모델을 로드하는 경우입니다.
+
+
+## 사용 사례
+
+먼저 **사용 사례**를 예로 들어보고, 이를 어떻게 해결할 수 있는지 살펴보겠습니다.
+
+우리가 요청을 처리하기 위해 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖
+
+이 모델들은 요청 간에 공유되므로, 요청마다 모델이 하나씩 있는 것이 아니라, 여러 요청에서 동일한 모델을 사용합니다.
+
+모델을 로드하는 데 **상당한 시간이 걸린다고 상상해 봅시다**, 왜냐하면 모델이 **디스크에서 많은 데이터를 읽어야** 하기 때문입니다. 따라서 모든 요청에 대해 모델을 매번 로드하고 싶지 않습니다.
+
+모듈/파일의 최상위에서 모델을 로드할 수도 있지만, 그러면 **모델을 로드하는데** 시간이 걸리기 때문에, 단순한 자동화된 테스트를 실행할 때도 모델이 로드될 때까지 기다려야 해서 **테스트 속도가 느려집니다**.
+
+이 문제를 해결하려고 하는 것입니다. 요청을 처리하기 전에 모델을 로드하되, 애플리케이션이 요청을 받기 시작하기 직전에만 로드하고, 코드가 로드되는 동안은 로드하지 않도록 하겠습니다.
+
+## Lifespan
+
+`FastAPI` 애플리케이션의 `lifespan` 매개변수와 "컨텍스트 매니저"를 사용하여 *시작*과 *종료* 로직을 정의할 수 있습니다. (컨텍스트 매니저가 무엇인지 잠시 후에 설명드리겠습니다.)
+
+예제를 통해 시작하고, 그 후에 자세히 살펴보겠습니다.
+
+우리는 `yield`를 사용하여 비동기 함수 `lifespan()`을 다음과 같이 생성합니다:
+
+{* ../../docs_src/events/tutorial003.py hl[16,19] *}
-이벤트 핸들러는 주 응용 프로그램에서만 작동합니다. [하위 응용 프로그램 - 마운트](./sub-applications.md){.internal-link target=_blank}에서는 작동하지 않습니다.
+여기서 우리는 모델을 로드하는 비싼 *시작* 작업을 시뮬레이션하고 있습니다. `yield` 앞에서 (가짜) 모델 함수를 머신러닝 모델이 담긴 딕셔너리에 넣습니다. 이 코드는 **애플리케이션이 요청을 받기 시작하기 전**, *시작* 동안에 실행됩니다.
+
+그리고 `yield` 직후에는 모델을 언로드합니다. 이 코드는 **애플리케이션이 요청 처리 완료 후**, *종료* 직전에 실행됩니다. 예를 들어, 메모리나 GPU와 같은 자원을 해제하는 작업을 할 수 있습니다.
+
+/// tip | 팁
+
+`shutdown`은 애플리케이션을 **종료**할 때 발생합니다.
+
+새로운 버전을 시작해야 하거나, 그냥 실행을 멈추고 싶을 수도 있습니다. 🤷
///
-## `startup` 이벤트
+### Lifespan 함수
-응용 프로그램을 시작하기 전에 실행하려는 함수를 "startup" 이벤트로 선언합니다:
+먼저 주목할 점은, `yield`를 사용하여 비동기 함수(async function)를 정의하고 있다는 것입니다. 이는 `yield`를 사용한 의존성과 매우 유사합니다.
-```Python hl_lines="8"
-{!../../docs_src/events/tutorial001.py!}
-```
+{* ../../docs_src/events/tutorial003.py hl[14:19] *}
+
+함수의 첫 번째 부분, 즉 `yield` 이전의 코드는 애플리케이션이 시작되기 **전에** 실행됩니다.
+
+그리고 `yield` 이후의 부분은 애플리케이션이 완료된 후 **나중에** 실행됩니다.
-이 경우 `startup` 이벤트 핸들러 함수는 단순히 몇 가지 값으로 구성된 `dict` 형식의 "데이터베이스"를 초기화합니다.
+### 비동기 컨텍스트 매니저
-하나 이상의 이벤트 핸들러 함수를 추가할 수도 있습니다.
+함수를 확인해보면, `@asynccontextmanager`로 장식되어 있습니다.
-그리고 응용 프로그램은 모든 `startup` 이벤트 핸들러가 완료될 때까지 요청을 받지 않습니다.
+이것은 함수를 "**비동기 컨텍스트 매니저**"라고 불리는 것으로 변환시킵니다.
-## `shutdown` 이벤트
+{* ../../docs_src/events/tutorial003.py hl[1,13] *}
-응용 프로그램이 종료될 때 실행하려는 함수를 추가하려면 `"shutdown"` 이벤트로 선언합니다:
+파이썬에서 **컨텍스트 매니저**는 `with` 문에서 사용할 수 있는 것입니다. 예를 들어, `open()`은 컨텍스트 매니저로 사용할 수 있습니다:
-```Python hl_lines="6"
-{!../../docs_src/events/tutorial002.py!}
+```Python
+with open("file.txt") as file:
+ file.read()
```
+최근 버전의 파이썬에서는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다:
-이 예제에서 `shutdown` 이벤트 핸들러 함수는 `"Application shutdown"`이라는 텍스트가 적힌 `log.txt` 파일을 추가할 것입니다.
+```Python
+async with lifespan(app):
+ await do_stuff()
+```
+
+컨텍스트 매니저나 위와 같은 비동기 컨텍스트 매니저를 만들면, `with` 블록에 들어가기 전에 `yield` 이전의 코드가 실행되고, `with` 블록을 벗어난 후에는 `yield` 이후의 코드가 실행됩니다.
+
+위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 사용하도록 합니다.
+
+`FastAPI` 애플리케이션의 `lifespan` 매개변수는 **비동기 컨텍스트 매니저**를 받기 때문에, 새로운 `lifespan` 비동기 컨텍스트 매니저를 FastAPI에 전달할 수 있습니다.
+
+{* ../../docs_src/events/tutorial003.py hl[22] *}
+
+## 대체 이벤트 (사용 중단)
+
+/// warning | 경고
+
+*시작*과 *종료*를 처리하는 권장 방법은 위에서 설명한 대로 `FastAPI` 애플리케이션의 `lifespan` 매개변수를 사용하는 것입니다. `lifespan` 매개변수를 제공하면 `startup`과 `shutdown` 이벤트 핸들러는 더 이상 호출되지 않습니다. `lifespan`을 사용할지, 모든 이벤트를 사용할지 선택해야 하며 둘 다 사용할 수는 없습니다.
+
+이 부분은 건너뛰셔도 좋습니다.
+
+///
+
+*시작*과 *종료* 동안 실행될 이 로직을 정의하는 대체 방법이 있습니다.
+
+애플리케이션이 시작되기 전에 또는 종료될 때 실행해야 하는 이벤트 핸들러(함수)를 정의할 수 있습니다.
+
+이 함수들은 `async def` 또는 일반 `def`로 선언할 수 있습니다.
+
+### `startup` 이벤트
+
+애플리케이션이 시작되기 전에 실행되어야 하는 함수를 추가하려면, `"startup"` 이벤트로 선언합니다:
+
+{* ../../docs_src/events/tutorial001.py hl[8] *}
+
+이 경우, `startup` 이벤트 핸들러 함수는 "database"라는 항목(단지 `dict`)을 일부 값으로 초기화합니다.
+
+여러 개의 이벤트 핸들러 함수를 추가할 수 있습니다.
+
+애플리케이션은 모든 `startup` 이벤트 핸들러가 완료될 때까지 요청을 받기 시작하지 않습니다.
+
+### `shutdown` 이벤트
+
+애플리케이션이 종료될 때 실행되어야 하는 함수를 추가하려면, `"shutdown"` 이벤트로 선언합니다:
+
+{* ../../docs_src/events/tutorial002.py hl[6] *}
+
+여기서, `shutdown` 이벤트 핸들러 함수는 `"Application shutdown"`이라는 텍스트를 `log.txt` 파일에 기록합니다.
/// info | 정보
-`open()` 함수에서 `mode="a"`는 "추가"를 의미합니다. 따라서 이미 존재하는 파일의 내용을 덮어쓰지 않고 새로운 줄을 추가합니다.
+`open()` 함수에서 `mode="a"`는 "추가"를 의미하므로, 파일에 있는 기존 내용은 덮어쓰지 않고 새로운 줄이 추가됩니다.
///
/// tip | 팁
-이 예제에서는 파일과 상호작용 하기 위해 파이썬 표준 함수인 `open()`을 사용하고 있습니다.
+이 경우, 우리는 표준 파이썬 `open()` 함수를 사용하여 파일과 상호작용하고 있습니다.
+
+따라서 I/O(입출력) 작업이 포함되어 있어 디스크에 기록되는 것을 "기다리는" 과정이 필요합니다.
-따라서 디스크에 데이터를 쓰기 위해 "대기"가 필요한 I/O (입력/출력) 작업을 수행합니다.
+하지만 `open()`은 `async`와 `await`를 사용하지 않습니다.
-그러나 `open()`은 `async`와 `await`을 사용하지 않기 때문에 이벤트 핸들러 함수는 `async def`가 아닌 표준 `def`로 선언하고 있습니다.
+그래서 우리는 이벤트 핸들러 함수를 `async def` 대신 일반 `def`로 선언합니다.
///
+### `startup`과 `shutdown`을 함께 사용
+
+*시작*과 *종료* 로직이 연결될 가능성이 높습니다. 예를 들어, 무언가를 시작한 후 끝내거나, 자원을 획득한 후 해제하는 등의 작업을 할 수 있습니다.
+
+이러한 작업을 별도의 함수로 처리하면 서로 로직이나 변수를 공유하지 않기 때문에 더 어려워집니다. 값들을 전역 변수에 저장하거나 비슷한 트릭을 사용해야 할 수 있습니다.
+
+그렇기 때문에 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다.
+
+## 기술적 세부사항
+
+호기심 많은 분들을 위한 기술적인 세부사항입니다. 🤓
+
+ASGI 기술 사양에 따르면, 이는 Lifespan Protocol의 일부이며, `startup`과 `shutdown`이라는 이벤트를 정의합니다.
+
/// info | 정보
-이벤트 핸들러에 관한 내용은 Starlette 이벤트 문서에서 추가로 확인할 수 있습니다.
+Starlette의 `lifespan` 핸들러에 대해 더 읽고 싶다면 Starlette의 Lifespan 문서에서 확인할 수 있습니다.
+
+이 문서에는 코드의 다른 영역에서 사용할 수 있는 lifespan 상태를 처리하는 방법도 포함되어 있습니다.
///
+
+## 서브 애플리케이션
+
+🚨 이 lifespan 이벤트(`startup`과 `shutdown`)는 메인 애플리케이션에 대해서만 실행되며, [서브 애플리케이션 - Mounts](sub-applications.md){.internal-link target=_blank}에는 실행되지 않음을 유의하세요.
diff --git a/docs/ko/docs/advanced/middlewares.md b/docs/ko/docs/advanced/middlewares.md
new file mode 100644
index 000000000..c00aedeaf
--- /dev/null
+++ b/docs/ko/docs/advanced/middlewares.md
@@ -0,0 +1,96 @@
+# 고급 미들웨어
+
+메인 튜토리얼에서 [Custom Middleware](../tutorial/middleware.md){.internal-link target=_blank}를 응용프로그램에 추가하는 방법을 읽으셨습니다.
+
+그리고 [CORS with the `CORSMiddleware`](){.internal-link target=_blank}하는 방법도 보셨습니다.
+
+이 섹션에서는 다른 미들웨어들을 사용하는 방법을 알아보겠습니다.
+
+## ASGI 미들웨어 추가하기
+
+**FastAPI**는 Starlette을 기반으로 하고 있으며, ASGI 사양을 구현하므로 ASGI 미들웨어를 사용할 수 있습니다.
+
+미들웨어가 FastAPI나 Starlette용으로 만들어지지 않아도 ASGI 사양을 준수하는 한 동작할 수 있습니다.
+
+일반적으로 ASGI 미들웨어는 첫 번째 인수로 ASGI 앱을 받는 클래스들입니다.
+
+따라서 타사 ASGI 미들웨어 문서에서 일반적으로 다음과 같이 사용하도록 안내할 것입니다.
+
+```Python
+from unicorn import UnicornMiddleware
+
+app = SomeASGIApp()
+
+new_app = UnicornMiddleware(app, some_config="rainbow")
+```
+
+하지만 내부 미들웨어가 서버 오류를 처리하고 사용자 정의 예외 처리기가 제대로 작동하도록 하는 더 간단한 방법을 제공하는 FastAPI(실제로는 Starlette)가 있습니다.
+
+이를 위해 `app.add_middleware()`를 사용합니다(CORS의 예에서와 같이).
+
+```Python
+from fastapi import FastAPI
+from unicorn import UnicornMiddleware
+
+app = FastAPI()
+
+app.add_middleware(UnicornMiddleware, some_config="rainbow")
+```
+
+`app.add_middleware()`는 첫 번째 인수로 미들웨어 클래스와 미들웨어에 전달할 추가 인수를 받습니다.
+
+## 통합 미들웨어
+
+**FastAPI**에는 일반적인 사용 사례를 위한 여러 미들웨어가 포함되어 있으며, 사용 방법은 다음에서 살펴보겠습니다.
+
+/// note | 기술 세부 사항
+
+다음 예제에서는 `from starlette.middleware.something import SomethingMiddleware`를 사용할 수도 있습니다.
+
+**FastAPI**는 개발자의 편의를 위해 `fastapi.middleware`에 여러 미들웨어를 제공합니다. 그러나 사용 가능한 대부분의 미들웨어는 Starlette에서 직접 제공합니다.
+
+///
+
+## `HTTPSRedirectMiddleware`
+
+들어오는 모든 요청이 `https` 또는 `wss`여야 합니다.
+
+`http` 또는 `ws`로 들어오는 모든 요청은 대신 보안 체계로 리디렉션됩니다.
+
+{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *}
+
+## `TrustedHostMiddleware`
+
+HTTP 호스트 헤더 공격을 방지하기 위해 모든 수신 요청에 올바르게 설정된 `Host` 헤더를 갖도록 강제합니다.
+
+{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *}
+
+다음 인수가 지원됩니다:
+
+* `allowed_hosts` - 호스트 이름으로 허용해야 하는 도메인 이름 목록입니다. 일치하는 하위 도메인에 대해 `*.example.com`과 같은 와일드카드 도메인이 지원됩니다. 모든 호스트 이름을 허용하려면 `allowed_hosts=[“*”]`를 사용하거나 미들웨어를 생략하세요.
+
+수신 요청의 유효성이 올바르게 확인되지 않으면 `400`이라는 응답이 전송됩니다.
+
+## `GZipMiddleware`
+
+`Accept-Encoding` 헤더에 `“gzip”`이 포함된 모든 요청에 대해 GZip 응답을 처리합니다.
+
+미들웨어는 표준 응답과 스트리밍 응답을 모두 처리합니다.
+
+{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *}
+
+지원되는 인수는 다음과 같습니다:
+
+* `minimum_size` - 이 최소 크기(바이트)보다 작은 응답은 GZip하지 않습니다. 기본값은 `500`입니다.
+* `compresslevel` - GZip 압축 중에 사용됩니다. 1에서 9 사이의 정수입니다. 기본값은 `9`입니다. 값이 낮을수록 압축 속도는 빨라지지만 파일 크기는 커지고, 값이 높을수록 압축 속도는 느려지지만 파일 크기는 작아집니다.
+
+## 기타 미들웨어
+
+다른 많은 ASGI 미들웨어가 있습니다.
+
+예를 들어:
+
+유비콘의 `ProxyHeadersMiddleware`>
+MessagePack
+
+사용 가능한 다른 미들웨어를 확인하려면 스타렛의 미들웨어 문서 및 ASGI Awesome List를 참조하세요.
diff --git a/docs/ko/docs/advanced/response-change-status-code.md b/docs/ko/docs/advanced/response-change-status-code.md
index f3cdd2ba5..1ba9aa3cc 100644
--- a/docs/ko/docs/advanced/response-change-status-code.md
+++ b/docs/ko/docs/advanced/response-change-status-code.md
@@ -20,9 +20,7 @@
그리고 이 *임시* 응답 객체에서 `status_code`를 설정할 수 있습니다.
-```Python hl_lines="1 9 12"
-{!../../docs_src/response_change_status_code/tutorial001.py!}
-```
+{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *}
그리고 평소처럼 원하는 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
diff --git a/docs/ko/docs/advanced/response-cookies.md b/docs/ko/docs/advanced/response-cookies.md
index f762e94b5..327f20afe 100644
--- a/docs/ko/docs/advanced/response-cookies.md
+++ b/docs/ko/docs/advanced/response-cookies.md
@@ -6,9 +6,7 @@
그런 다음 해당 *임시* 응답 객체에서 쿠키를 설정할 수 있습니다.
-```Python hl_lines="1 8-9"
-{!../../docs_src/response_cookies/tutorial002.py!}
-```
+{* ../../docs_src/response_cookies/tutorial002.py hl[1,8:9] *}
그런 다음 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
@@ -25,9 +23,7 @@
이를 위해 [Response를 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 설명한 대로 응답을 생성할 수 있습니다.
그런 다음 쿠키를 설정하고 반환하면 됩니다:
-```Python hl_lines="1 18"
-{!../../docs_src/response_directly/tutorial002.py!}
-```
+{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
/// tip
`Response` 매개변수를 사용하지 않고 응답을 직접 반환하는 경우, FastAPI는 이를 직접 반환한다는 점에 유의하세요.
diff --git a/docs/ko/docs/advanced/response-directly.md b/docs/ko/docs/advanced/response-directly.md
index aedebff9d..08d63c43c 100644
--- a/docs/ko/docs/advanced/response-directly.md
+++ b/docs/ko/docs/advanced/response-directly.md
@@ -34,9 +34,7 @@ Pydantic 모델로 데이터 변환을 수행하지 않으며, 내용을 다른
이러한 경우, 데이터를 응답에 전달하기 전에 `jsonable_encoder`를 사용하여 변환할 수 있습니다:
-```Python hl_lines="6-7 21-22"
-{!../../docs_src/response_directly/tutorial001.py!}
-```
+{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
/// note | 기술적 세부 사항
@@ -55,9 +53,7 @@ Pydantic 모델로 데이터 변환을 수행하지 않으며, 내용을 다른
XML 내용을 문자열에 넣고, 이를 `Response`에 넣어 반환할 수 있습니다:
-```Python hl_lines="1 18"
-{!../../docs_src/response_directly/tutorial002.py!}
-```
+{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
## 참고 사항
`Response`를 직접 반환할 때, 그 데이터는 자동으로 유효성 검사되거나, 변환(직렬화)되거나, 문서화되지 않습니다.
diff --git a/docs/ko/docs/advanced/response-headers.md b/docs/ko/docs/advanced/response-headers.md
index 974a06969..e8abe0be2 100644
--- a/docs/ko/docs/advanced/response-headers.md
+++ b/docs/ko/docs/advanced/response-headers.md
@@ -6,9 +6,7 @@
그런 다음, 여러분은 해당 *임시* 응답 객체에서 헤더를 설정할 수 있습니다.
-```Python hl_lines="1 7-8"
-{!../../docs_src/response_headers/tutorial002.py!}
-```
+{* ../../docs_src/response_headers/tutorial002.py hl[1,7:8] *}
그 후, 일반적으로 사용하듯이 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
@@ -24,9 +22,7 @@
[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 설명한 대로 응답을 생성하고, 헤더를 추가 매개변수로 전달하세요.
-```Python hl_lines="10-12"
-{!../../docs_src/response_headers/tutorial001.py!}
-```
+{* ../../docs_src/response_headers/tutorial001.py hl[10:12] *}
/// note | 기술적 세부사항
diff --git a/docs/ko/docs/advanced/sub-applications.md b/docs/ko/docs/advanced/sub-applications.md
new file mode 100644
index 000000000..c5835de15
--- /dev/null
+++ b/docs/ko/docs/advanced/sub-applications.md
@@ -0,0 +1,67 @@
+# 하위 응용프로그램 - 마운트
+
+만약 각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 응용프로그램이 필요하다면, 메인 어플리케이션에 하나 (또는 그 이상의) 하위-응용프로그램(들)을 “마운트"해서 사용할 수 있습니다.
+
+## **FastAPI** 응용프로그램 마운트
+
+“마운트"이란 완전히 “독립적인" 응용프로그램을 특정 경로에 추가하여 해당 하위 응용프로그램에서 선언된 *경로 동작*을 통해 해당 경로 아래에 있는 모든 작업들을 처리할 수 있도록 하는 것을 의미합니다.
+
+### 최상단 응용프로그램
+
+먼저, 메인, 최상단의 **FastAPI** 응용프로그램과 이것의 *경로 동작*을 생성합니다:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *}
+
+### 하위 응용프로그램
+
+다음으로, 하위 응용프로그램과 이것의 *경로 동작*을 생성합니다:
+
+이 하위 응용프로그램은 또 다른 표준 FastAPI 응용프로그램입니다. 다만 이것은 “마운트”될 것입니다:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *}
+
+### 하위 응용프로그램 마운트
+
+최상단 응용프로그램, `app`에 하위 응용프로그램, `subapi`를 마운트합니다.
+
+이 예시에서, 하위 응용프로그램션은 `/subapi` 경로에 마운트 될 것입니다:
+
+{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *}
+
+### 자동으로 생성된 API 문서 확인
+
+이제, `uvicorn`으로 메인 응용프로그램을 실행하십시오. 당신의 파일이 `main.py`라면, 이렇게 실행합니다:
+
+
+
+```console
+$ uvicorn main:app --reload
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+그리고 http://127.0.0.1:8000/docs에서 문서를 여십시오.
+
+메인 응용프로그램의 *경로 동작*만을 포함하는, 메인 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다:
+
+
+
+다음으로, http://127.0.0.1:8000/subapi/docs에서 하위 응용프로그램의 문서를 여십시오.
+
+하위 경로 접두사 `/subapi` 아래에 선언된 *경로 동작* 을 포함하는, 하위 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다:
+
+
+
+두 사용자 인터페이스 중 어느 하나를 사용해야하는 경우, 브라우저는 특정 응용프로그램 또는 하위 응용프로그램과 각각 통신할 수 있기 때문에 올바르게 동작할 것입니다.
+
+### 기술적 세부사항: `root_path`
+
+위에 설명된 것과 같이 하위 응용프로그램을 마운트하는 경우, FastAPI는 `root_path`라고 하는 ASGI 명세의 매커니즘을 사용하여 하위 응용프로그램에 대한 마운트 경로 통신을 처리합니다.
+
+이를 통해, 하위 응용프로그램은 문서 UI를 위해 경로 접두사를 사용해야 한다는 사실을 인지합니다.
+
+하위 응용프로그램에도 역시 다른 하위 응용프로그램을 마운트하는 것이 가능하며 FastAPI가 모든 `root_path` 들을 자동적으로 처리하기 때문에 모든 것은 올바르게 동작할 것입니다.
+
+`root_path`와 이것을 사용하는 방법에 대해서는 [프록시의 뒷단](./behind-a-proxy.md){.internal-link target=_blank} 섹션에서 배울 수 있습니다.
diff --git a/docs/ko/docs/advanced/templates.md b/docs/ko/docs/advanced/templates.md
new file mode 100644
index 000000000..4cb4cbe0d
--- /dev/null
+++ b/docs/ko/docs/advanced/templates.md
@@ -0,0 +1,127 @@
+# 템플릿
+
+**FastAPI**와 함께 원하는 어떤 템플릿 엔진도 사용할 수 있습니다.
+
+일반적인 선택은 Jinja2로, Flask와 다른 도구에서도 사용됩니다.
+
+설정을 쉽게 할 수 있는 유틸리티가 있으며, 이를 **FastAPI** 애플리케이션에서 직접 사용할 수 있습니다(Starlette 제공).
+
+## 의존성 설치
+
+가상 환경을 생성하고(virtual environment{.internal-link target=_blank}), 활성화한 후 jinja2를 설치해야 합니다:
+
+
+
+
+## 사용하기 `Jinja2Templates`
+
+* `Jinja2Templates`를 가져옵니다.
+* 나중에 재사용할 수 있는 `templates` 객체를 생성합니다.
+* 템플릿을 반환할 경로 작업에 `Request` 매개변수를 선언합니다.
+* 생성한 `templates`를 사용하여 `TemplateResponse`를 렌더링하고 반환합니다. 템플릿의 이름, 요청 객체 및 Jinja2 템플릿 내에서 사용될 키-값 쌍이 포함된 "컨텍스트" 딕셔너리도 전달합니다.
+
+
+```Python hl_lines="4 11 15-18"
+{!../../docs_src/templates/tutorial001.py!}
+```
+
+/// note | 참고
+
+FastAPI 0.108.0 이전과 Starlette 0.29.0에서는 `name`이 첫 번째 매개변수였습니다.
+
+또한 이전 버전에서는 `request` 객체가 Jinja2의 컨텍스트에서 키-값 쌍의 일부로 전달되었습니다.
+
+///
+
+/// tip | 팁
+
+`response_class=HTMLResponse`를 선언하면 문서 UI 응답이 HTML임을 알 수 있습니다.
+
+///
+
+/// note | 기술 세부 사항
+`from starlette.templating import Jinja2Templates`를 사용할 수도 있습니다.
+
+**FastAPI**는 개발자를 위한 편리함으로 `fastapi.templating` 대신 `starlette.templating`을 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 옵니다. `Request` 및 `StaticFiles`도 마찬가지입니다.
+///
+
+## 템플릿 작성하기
+
+그런 다음 `templates/item.html`에 템플릿을 작성할 수 있습니다. 예를 들면:
+
+```jinja hl_lines="7"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+### 템플릿 컨텍스트 값
+
+다음과 같은 HTML에서:
+
+{% raw %}
+
+```jinja
+Item ID: {{ id }}
+```
+
+{% endraw %}
+
+...이는 전달한 "컨텍스트" `dict`에서 가져온 `id`를 표시합니다:
+
+```Python
+{"id": id}
+```
+
+예를 들어, ID가 `42`일 경우, 이는 다음과 같이 렌더링됩니다:
+
+```html
+Item ID: 42
+```
+
+### 템플릿 `url_for` 인수
+
+템플릿 내에서 `url_for()`를 사용할 수도 있으며, 이는 *경로 작업 함수*에서 사용될 인수와 동일한 인수를 받습니다.
+
+따라서 다음과 같은 부분에서:
+
+{% raw %}
+
+```jinja
+
+```
+
+{% endraw %}
+
+...이는 *경로 작업 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다.
+
+예를 들어, ID가 `42`일 경우, 이는 다음과 같이 렌더링됩니다:
+```html
+
+```
+
+## 템플릿과 정적 파일
+
+템플릿 내에서 `url_for()`를 사용할 수 있으며, 예를 들어 `name="static"`으로 마운트한 `StaticFiles`와 함께 사용할 수 있습니다.
+
+```jinja hl_lines="4"
+{!../../docs_src/templates/templates/item.html!}
+```
+
+이 예제에서는 `static/styles.css`에 있는 CSS 파일에 연결될 것입니다:
+
+```CSS hl_lines="4"
+{!../../docs_src/templates/static/styles.css!}
+```
+
+그리고 `StaticFiles`를 사용하고 있으므로, 해당 CSS 파일은 **FastAPI** 애플리케이션에서 `/static/styles.css` URL로 자동 제공됩니다.
+
+## 더 많은 세부 사항
+
+템플릿 테스트를 포함한 더 많은 세부 사항은 Starlette의 템플릿 문서를 확인하세요.
diff --git a/docs/ko/docs/advanced/testing-dependencies.md b/docs/ko/docs/advanced/testing-dependencies.md
new file mode 100644
index 000000000..780e19431
--- /dev/null
+++ b/docs/ko/docs/advanced/testing-dependencies.md
@@ -0,0 +1,53 @@
+# 테스트 의존성 오버라이드
+
+## 테스트 중 의존성 오버라이드하기
+
+테스트를 진행하다 보면 의존성을 오버라이드해야 하는 경우가 있습니다.
+
+원래 의존성을 실행하고 싶지 않을 수도 있습니다(또는 그 의존성이 가지고 있는 하위 의존성까지도 실행되지 않길 원할 수 있습니다).
+
+대신, 테스트 동안(특정 테스트에서만) 사용될 다른 의존성을 제공하고, 원래 의존성이 사용되던 곳에서 사용할 수 있는 값을 제공하기를 원할 수 있습니다.
+
+### 사용 사례: 외부 서비스
+
+예를 들어, 외부 인증 제공자를 호출해야 하는 경우를 생각해봅시다.
+
+토큰을 보내면 인증된 사용자를 반환합니다.
+
+제공자는 요청당 요금을 부과할 수 있으며, 테스트를 위해 고정된 모의 사용자가 있는 경우보다 호출하는 데 시간이 더 걸릴 수 있습니다.
+
+외부 제공자를 한 번만 테스트하고 싶을 수도 있지만 테스트를 실행할 때마다 반드시 호출할 필요는 없습니다.
+
+이 경우 해당 공급자를 호출하는 종속성을 오버라이드하고 테스트에 대해서만 모의 사용자를 반환하는 사용자 지정 종속성을 사용할 수 있습니다.
+
+### `app.dependency_overrides` 속성 사용하기
+
+이런 경우를 위해 **FastAPI** 응용 프로그램에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다.
+
+테스트를 위해 의존성을 오버라이드하려면, 원래 의존성(함수)을 키로 설정하고 오버라이드할 의존성(다른 함수)을 값으로 설정합니다.
+
+그럼 **FastAPI**는 원래 의존성 대신 오버라이드된 의존성을 호출합니다.
+
+{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}
+
+/// tip | 팁
+
+**FastAPI** 애플리케이션 어디에서든 사용된 의존성에 대해 오버라이드를 설정할 수 있습니다.
+
+원래 의존성은 *경로 동작 함수*, *경로 동작 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다.
+
+FastAPI는 여전히 이를 오버라이드할 수 있습니다.
+
+///
+
+그런 다음, `app.dependency_overrides`를 빈 `dict`로 설정하여 오버라이드를 재설정(제거)할 수 있습니다:
+
+```python
+app.dependency_overrides = {}
+```
+
+/// tip | 팁
+
+특정 테스트에서만 의존성을 오버라이드하고 싶다면, 테스트 시작 시(테스트 함수 내부) 오버라이드를 설정하고 테스트 종료 시(테스트 함수 끝부분) 재설정하면 됩니다.
+
+///
diff --git a/docs/ko/docs/advanced/testing-events.md b/docs/ko/docs/advanced/testing-events.md
index dc082412a..502762f23 100644
--- a/docs/ko/docs/advanced/testing-events.md
+++ b/docs/ko/docs/advanced/testing-events.md
@@ -2,6 +2,4 @@
테스트에서 이벤트 핸들러(`startup` 및 `shutdown`)를 실행해야 하는 경우, `with` 문과 함께 `TestClient`를 사용할 수 있습니다.
-```Python hl_lines="9-12 20-24"
-{!../../docs_src/app_testing/tutorial003.py!}
-```
+{* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *}
diff --git a/docs/ko/docs/advanced/testing-websockets.md b/docs/ko/docs/advanced/testing-websockets.md
index f1580c3c3..9f3b4a451 100644
--- a/docs/ko/docs/advanced/testing-websockets.md
+++ b/docs/ko/docs/advanced/testing-websockets.md
@@ -4,9 +4,7 @@
이를 위해 `with` 문에서 `TestClient`를 사용하여 WebSocket에 연결합니다:
-```Python hl_lines="27-31"
-{!../../docs_src/app_testing/tutorial002.py!}
-```
+{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *}
/// note | 참고
diff --git a/docs/ko/docs/advanced/using-request-directly.md b/docs/ko/docs/advanced/using-request-directly.md
index 027ea9fad..bfa4fa4db 100644
--- a/docs/ko/docs/advanced/using-request-directly.md
+++ b/docs/ko/docs/advanced/using-request-directly.md
@@ -29,9 +29,7 @@
이를 위해서는 요청에 직접 접근해야 합니다.
-```Python hl_lines="1 7-8"
-{!../../docs_src/using_request_directly/tutorial001.py!}
-```
+{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *}
*경로 작동 함수* 매개변수를 `Request` 타입으로 선언하면 **FastAPI**가 해당 매개변수에 `Request` 객체를 전달하는 것을 알게 됩니다.
diff --git a/docs/ko/docs/advanced/websockets.md b/docs/ko/docs/advanced/websockets.md
new file mode 100644
index 000000000..fa60a428b
--- /dev/null
+++ b/docs/ko/docs/advanced/websockets.md
@@ -0,0 +1,186 @@
+# WebSockets
+
+여러분은 **FastAPI**에서 WebSockets를 사용할 수 있습니다.
+
+## `WebSockets` 설치
+
+[가상 환경](../virtual-environments.md){.internal-link target=_blank)를 생성하고 활성화한 다음, `websockets`를 설치하세요:
+
+
+
+## WebSockets 클라이언트
+
+### 프로덕션 환경에서
+
+여러분의 프로덕션 시스템에서는 React, Vue.js 또는 Angular와 같은 최신 프레임워크로 생성된 프런트엔드를 사용하고 있을 가능성이 높습니다.
+
+백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다.
+
+또는 네이티브 코드로 WebSocket 백엔드와 직접 통신하는 네이티브 모바일 응용 프로그램을 가질 수도 있습니다.
+
+혹은 WebSocket 엔드포인트와 통신할 수 있는 다른 방법이 있을 수도 있습니다.
+
+---
+
+하지만 이번 예제에서는 일부 자바스크립트를 포함한 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다.
+
+물론, 이는 최적의 방법이 아니며 프로덕션 환경에서는 사용하지 않을 것입니다.
+
+프로덕션 환경에서는 위에서 설명한 옵션 중 하나를 사용하는 것이 좋습니다.
+
+그러나 이는 WebSockets의 서버 측에 집중하고 동작하는 예제를 제공하는 가장 간단한 방법입니다:
+
+{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
+
+## `websocket` 생성하기
+
+**FastAPI** 응용 프로그램에서 `websocket`을 생성합니다:
+
+{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *}
+
+/// note | 기술적 세부사항
+
+`from starlette.websockets import WebSocket`을 사용할 수도 있습니다.
+
+**FastAPI**는 개발자를 위한 편의를 위해 동일한 `WebSocket`을 직접 제공합니다. 하지만 이는 Starlette에서 가져옵니다.
+
+///
+
+## 메시지를 대기하고 전송하기
+
+WebSocket 경로에서 메시지를 대기(`await`)하고 전송할 수 있습니다.
+
+{* ../../docs_src/websockets/tutorial001.py hl[48:52] *}
+
+여러분은 이진 데이터, 텍스트, JSON 데이터를 받을 수 있고 전송할 수 있습니다.
+
+## 시도해보기
+
+파일 이름이 `main.py`라고 가정하고 응용 프로그램을 실행합니다:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+브라우저에서 http://127.0.0.1:8000을 열어보세요.
+
+간단한 페이지가 나타날 것입니다:
+
+
+
+입력창에 메시지를 입력하고 전송할 수 있습니다:
+
+
+
+**FastAPI** WebSocket 응용 프로그램이 응답을 돌려줄 것입니다:
+
+
+
+여러 메시지를 전송(그리고 수신)할 수 있습니다:
+
+
+
+모든 메시지는 동일한 WebSocket 연결을 사용합니다.
+
+## `Depends` 및 기타 사용하기
+
+WebSocket 엔드포인트에서 `fastapi`에서 다음을 가져와 사용할 수 있습니다:
+
+* `Depends`
+* `Security`
+* `Cookie`
+* `Header`
+* `Path`
+* `Query`
+
+이들은 다른 FastAPI 엔드포인트/*경로 작동*과 동일하게 동작합니다:
+
+{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
+
+/// info | 정보
+
+WebSocket에서는 `HTTPException`을 발생시키는 것이 적합하지 않습니다. 대신 `WebSocketException`을 발생시킵니다.
+
+명세서에 정의된 유효한 코드를 사용하여 종료 코드를 설정할 수 있습니다.
+
+///
+
+### 종속성을 가진 WebSockets 테스트
+
+파일 이름이 `main.py`라고 가정하고 응용 프로그램을 실행합니다:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+브라우저에서 http://127.0.0.1:8000을 열어보세요.
+
+다음과 같은 값을 설정할 수 있습니다:
+
+* 경로에 사용된 "Item ID".
+* 쿼리 매개변수로 사용된 "Token".
+
+/// tip | 팁
+
+쿼리 `token`은 종속성에 의해 처리됩니다.
+
+///
+
+이제 WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다:
+
+
+
+## 연결 해제 및 다중 클라이언트 처리
+
+WebSocket 연결이 닫히면, `await websocket.receive_text()`가 `WebSocketDisconnect` 예외를 발생시킵니다. 이를 잡아 처리할 수 있습니다:
+
+{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
+
+테스트해보기:
+
+* 여러 브라우저 탭에서 앱을 엽니다.
+* 각 탭에서 메시지를 작성합니다.
+* 한 탭을 닫아보세요.
+
+`WebSocketDisconnect` 예외가 발생하며, 다른 모든 클라이언트가 다음과 같은 메시지를 수신합니다:
+
+```
+Client #1596980209979 left the chat
+```
+
+/// tip | 팁
+
+위 응용 프로그램은 여러 WebSocket 연결에 메시지를 브로드캐스트하는 방법을 보여주는 간단한 예제입니다.
+
+그러나 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동합니다.
+
+FastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구를 찾고 있다면, encode/broadcaster를 확인하세요.
+
+///
+
+## 추가 정보
+
+다음 옵션에 대한 자세한 내용을 보려면 Starlette의 문서를 확인하세요:
+
+* `WebSocket` 클래스.
+* 클래스 기반 WebSocket 처리.
diff --git a/docs/ko/docs/advanced/wsgi.md b/docs/ko/docs/advanced/wsgi.md
index 87aabf203..3e9de3e6c 100644
--- a/docs/ko/docs/advanced/wsgi.md
+++ b/docs/ko/docs/advanced/wsgi.md
@@ -12,9 +12,7 @@
그 후, 해당 경로에 마운트합니다.
-```Python hl_lines="2-3 23"
-{!../../docs_src/wsgi/tutorial001.py!}
-```
+{* ../../docs_src/wsgi/tutorial001.py hl[2:3,23] *}
## 확인하기
diff --git a/docs/ko/docs/help-fastapi.md b/docs/ko/docs/help-fastapi.md
index 932952b4a..06435d4bb 100644
--- a/docs/ko/docs/help-fastapi.md
+++ b/docs/ko/docs/help-fastapi.md
@@ -1,162 +1,269 @@
-* # FastAPI 지원 - 도움말 받기
+# FastAPI 지원 - 도움 받기
- **FastAPI** 가 마음에 드시나요?
+**FastAPI** 가 마음에 드시나요?
- FastAPI, 다른 사용자, 개발자를 응원하고 싶으신가요?
+FastAPI, 다른 사용자, 개발자를 응원하고 싶으신가요?
- 혹은 **FastAPI** 에 대해 도움이 필요하신가요?
+혹은 **FastAPI** 에 대해 도움이 필요하신가요?
- 아주 간단하게 응원할 수 있습니다 (몇 번의 클릭만으로).
+아주 간단하게 응원할 수 있습니다 (몇 번의 클릭만으로).
- 또한 도움을 받을 수 있는 방법도 몇 가지 있습니다.
+또한 도움을 받을 수 있는 방법도 몇 가지 있습니다.
- ## 뉴스레터 구독
+## 뉴스레터 구독
- [**FastAPI와 친구** 뉴스레터](https://github.com/fastapi/fastapi/blob/master/newsletter)를 구독하여 최신 정보를 유지할 수 있습니다{.internal-link target=_blank}:
+[**FastAPI and friends** 뉴스레터](newsletter.md){.internal-link target=\_blank}를 구독하여 최신 정보를 유지할 수 있습니다:
- - FastAPI 와 그 친구들에 대한 뉴스 🚀
- - 가이드 📝
- - 특징 ✨
- - 획기적인 변화 🚨
- - 팁과 요령 ✅
+* FastAPI and friends에 대한 뉴스 🚀
+* 가이드 📝
+* 기능 ✨
+* 획기적인 변화 🚨
+* 팁과 요령 ✅
- ## 트위터에서 FastAPI 팔로우하기
+## 트위터에서 FastAPI 팔로우하기
- [Follow @fastapi on **Twitter**](https://twitter.com/fastapi) 를 팔로우하여 **FastAPI** 에 대한 최신 뉴스를 얻을 수 있습니다. 🐦
+**Twitter**의 @fastapi를 팔로우하여 **FastAPI** 에 대한 최신 뉴스를 얻을 수 있습니다. 🐦
- ## Star **FastAPI** in GitHub
+## Star **FastAPI** in GitHub
- GitHub에서 FastAPI에 "star"를 붙일 수 있습니다(오른쪽 상단의 star 버튼을 클릭): https://github.com/fastapi/fastapi. ⭐️
+GitHub에서 FastAPI에 "star"를 붙일 수 있습니다 (오른쪽 상단의 star 버튼을 클릭): https://github.com/fastapi/fastapi. ⭐️
- 스타를 늘림으로써, 다른 사용자들이 좀 더 쉽게 찾을 수 있고, 많은 사람들에게 유용한 것임을 나타낼 수 있습니다.
+스타를 늘림으로써, 다른 사용자들이 좀 더 쉽게 찾을 수 있고, 많은 사람들에게 유용한 것임을 나타낼 수 있습니다.
- ## GitHub 저장소에서 릴리즈 확인
+## GitHub 저장소에서 릴리즈 확인
- GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): https://github.com/fastapi/fastapi. 👀
+GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): https://github.com/fastapi/fastapi. 👀
- 여기서 "Releases only"을 선택할 수 있습니다.
+여기서 "Releases only"을 선택할 수 있습니다.
- 이렇게하면, **FastAPI** 의 버그 수정 및 새로운 기능의 구현 등의 새로운 자료 (최신 버전)이 있을 때마다 (이메일) 통지를 받을 수 있습니다.
+이렇게하면, **FastAPI** 의 버그 수정 및 새로운 기능의 구현 등의 새로운 자료 (최신 버전)이 있을 때마다 (이메일) 통지를 받을 수 있습니다.
- ## 개발자와의 연결
+## 개발자와의 연결
- 개발자인 [me (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com/) 와 연락을 취할 수 있습니다.
+개발자(Sebastián Ramírez / `tiangolo`)와 연락을 취할 수 있습니다.
- 여러분은 할 수 있습니다:
+여러분은 할 수 있습니다:
- - [**GitHub**에서 팔로우하기](https://github.com/tiangolo).
- - 당신에게 도움이 될 저의 다른 오픈소스 프로젝트를 확인하십시오.
- - 새로운 오픈소스 프로젝트를 만들었을 때 확인하려면 팔로우 하십시오.
+* **GitHub**에서 팔로우하기..
+ * 당신에게 도움이 될 저의 다른 오픈소스 프로젝트를 확인하십시오.
+ * 새로운 오픈소스 프로젝트를 만들었을 때 확인하려면 팔로우 하십시오.
+* **Twitter** 또는 Mastodon에서 팔로우하기.
+ * FastAPI의 사용 용도를 알려주세요 (그것을 듣는 것을 좋아합니다).
+ * 발표나 새로운 툴 출시 소식을 받아보십시오.
+ * **Twitter**의 @fastapi를 팔로우 (별도 계정에서) 할 수 있습니다.
+* **LinkedIn**에서 팔로우하기..
+ * 새로운 툴의 발표나 출시 소식을 받아보십시오. (단, Twitter를 더 자주 사용합니다 🤷♂).
+* **Dev.to** 또는 **Medium**에서 제가 작성한 내용을 읽어 보십시오 (또는 팔로우).
+ * 다른 기사나 아이디어들을 읽고, 제가 만들어왔던 툴에 대해서도 읽으십시오.
+ * 새로운 기사를 읽기 위해 팔로우 하십시오.
- - [**Twitter**에서 팔로우하기](https://twitter.com/tiangolo).
- - FastAPI의 사용 용도를 알려주세요 (그것을 듣는 것을 좋아합니다).
- - 발표 또는 새로운 툴 출시할 때 들으십시오.
- - [follow @fastapi on Twitter](https://twitter.com/fastapi) (별도 계정에서) 할 수 있습니다.
+## **FastAPI**에 대한 트윗
- - [**Linkedin**에서의 연결](https://www.linkedin.com/in/tiangolo/).
- - 새로운 툴의 발표나 릴리스를 들을 수 있습니다 (단, Twitter를 더 자주 사용합니다 🤷♂).
+**FastAPI**에 대해 트윗 하고 FastAPI가 마음에 드는 이유를 알려주세요. 🎉
- - [**Dev.to**](https://dev.to/tiangolo) 또는 [**Medium**](https://medium.com/@tiangolo)에서 제가 작성한 내용을 읽어 보십시오(또는 팔로우).
- - 다른 기사나 아이디어들을 읽고, 제가 만들어왔던 툴에 대해서도 읽으십시오.
- - 새로운 기사를 읽기 위해 팔로우 하십시오.
+**FastAPI**가 어떻게 사용되고 있는지, 어떤 점이 마음에 들었는지, 어떤 프로젝트/회사에서 사용하고 있는지 등에 대해 듣고 싶습니다.
- ## **FastAPI**에 대한 트윗
+## FastAPI에 투표하기
- [**FastAPI**에 대해 트윗](https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) 하고 FastAPI가 마음에 드는 이유를 알려주세요. 🎉
+* Slant에서 **FastAPI** 에 대해 투표하십시오.
+* AlternativeTo에서 **FastAPI** 에 대해 투표하십시오.
+* StackShare에서 **FastAPI** 에 대해 투표하십시오.
- **FastAPI**가 어떻게 사용되고 있는지, 어떤 점이 마음에 들었는지, 어떤 프로젝트/회사에서 사용하고 있는지 등에 대해 듣고 싶습니다.
+## GitHub의 이슈로 다른사람 돕기
- ## FastAPI에 투표하기
+다른 사람들의 질문에 도움을 줄 수 있습니다:
- - [Slant에서 **FastAPI** 에 대해 투표하십시오](https://www.slant.co/options/34241/~fastapi-review).
- - [AlternativeTo**FastAPI** 에 대해 투표하십시오](https://alternativeto.net/software/fastapi/).
+* GitHub 디스커션
+* GitHub 이슈
- ## GitHub의 이슈로 다른사람 돕기
+많은 경우, 여러분은 이미 그 질문에 대한 답을 알고 있을 수도 있습니다. 🤓
- [존재하는 이슈](https://github.com/fastapi/fastapi/issues)를 확인하고 그것을 시도하고 도와줄 수 있습니다. 대부분의 경우 이미 답을 알고 있는 질문입니다. 🤓
+만약 많은 사람들의 문제를 도와준다면, 공식적인 [FastAPI 전문가](fastapi-people.md#fastapi-experts){.internal-link target=\_blank} 가 될 것입니다. 🎉
- 많은 사람들의 문제를 도와준다면, 공식적인 [FastAPI 전문가](https://github.com/fastapi/fastapi/blob/master/docs/en/docs/fastapi-people.md#experts) 가 될 수 있습니다{.internal-link target=_blank}. 🎉
+가장 중요한 점은: 친절하려고 노력하는 것입니다. 사람들은 좌절감을 안고 오며, 많은 경우 최선의 방식으로 질문하지 않을 수도 있습니다. 하지만 최대한 친절하게 대하려고 노력하세요. 🤗
- ## GitHub 저장소 보기
+**FastAPI** 커뮤니티의 목표는 친절하고 환영하는 것입니다. 동시에, 괴롭힘이나 무례한 행동을 받아들이지 마세요. 우리는 서로를 돌봐야 합니다.
- GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): https://github.com/fastapi/fastapi. 👀
+---
- "Releases only" 대신 "Watching"을 선택하면 다른 사용자가 새로운 issue를 생성할 때 알림이 수신됩니다.
+다른 사람들의 질문 (디스커션 또는 이슈에서) 해결을 도울 수 있는 방법은 다음과 같습니다.
- 그런 다음 이런 issues를 해결 할 수 있도록 도움을 줄 수 있습니다.
+### 질문 이해하기
- ## 이슈 생성하기
+* 질문하는 사람이 가진 **목적**과 사용 사례를 이해할 수 있는지 확인하세요.
- GitHub 저장소에 [새로운 이슈 생성](https://github.com/fastapi/fastapi/issues/new/choose) 을 할 수 있습니다, 예를들면 다음과 같습니다:
+* 질문 (대부분은 질문입니다)이 **명확**한지 확인하세요.
- - **질문**을 하거나 **문제**에 대해 질문합니다.
- - 새로운 **기능**을 제안 합니다.
+* 많은 경우, 사용자가 가정한 해결책에 대한 질문을 하지만, 더 **좋은** 해결책이 있을 수 있습니다. 문제와 사용 사례를 더 잘 이해하면 더 나은 **대안적인 해결책**을 제안할 수 있습니다.
- **참고**: 만약 이슈를 생성한다면, 저는 여러분에게 다른 사람들을 도와달라고 부탁할 것입니다. 😉
+* 질문을 이해할 수 없다면, 더 **자세한 정보**를 요청하세요.
- ## Pull Request를 만드십시오
+### 문제 재현하기
- Pull Requests를 이용하여 소스코드에 [컨트리뷰트](https://github.com/fastapi/fastapi/blob/master/docs/en/docs/contributing.md){.internal-link target=_blank} 할 수 있습니다. 예를 들면 다음과 같습니다:
+대부분의 경우, 질문은 질문자의 **원본 코드**와 관련이 있습니다.
- - 문서에서 찾은 오타를 수정할 때.
+많은 경우, 코드의 일부만 복사해서 올리지만, 그것만으로는 **문제를 재현**하기에 충분하지 않습니다.
- - FastAPI를 [편집하여](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml) 작성했거나 찾은 문서, 비디오 또는 팟캐스트를 공유할 때.
+* 질문자에게 최소한의 재현 가능한 예제를 제공해달라고 요청하세요. 이렇게 하면 코드를 **복사-붙여넣기**하여 직접 실행하고, 동일한 오류나 동작을 확인하거나 사용 사례를 더 잘 이해할 수 있습니다.
- - 해당 섹션의 시작 부분에 링크를 추가했는지 확인하십시오.
+* 너그러운 마음이 든다면, 문제 설명만을 기반으로 직접 **예제를 만들어**볼 수도 있습니다. 하지만, 이는 시간이 많이 걸릴 수 있으므로, 먼저 질문을 명확히 해달라고 요청하는 것이 좋습니다.
- - 당신의 언어로 [문서 번역하는데](https://github.com/fastapi/fastapi/blob/master/docs/en/docs/contributing.md#translations){.internal-link target=_blank} 기여할 때.
+### 해결책 제안하기
- - 또한 다른 사용자가 만든 번역을 검토하는데 도움을 줄 수도 있습니다.
+* 질문을 충분히 이해한 후에는 가능한 **답변**을 제공할 수 있습니다.
- - 새로운 문서의 섹션을 제안할 때.
+* 많은 경우, 질문자의 **근본적인 문제나 사용 사례**를 이해하는 것이 중요합니다. 그들이 시도하는 방법보다 더 나은 해결책이 있을 수 있기 때문입니다.
- - 기존 문제/버그를 수정할 때.
+### 해결 요청하기
- - 새로운 feature를 추가할 때.
+질문자가 답변을 확인하고 나면, 당신이 문제를 해결했을 가능성이 높습니다. 축하합니다, **당신은 영웅입니다**! 🦸
- ## 채팅에 참여하십시오
+* 이제 문제를 해결했다면, 질문자에게 다음을 요청할 수 있습니다.
- 👥 [디스코드 채팅 서버](https://discord.gg/VQjSZaeJmf) 👥 에 가입하고 FastAPI 커뮤니티에서 다른 사람들과 어울리세요.
+ * GitHub 디스커션에서: 댓글을 **답변**으로 표시하도록 요청하세요.
+ * GitHub 이슈에서: 이슈를 **닫아달라고** 요청하세요.
- /// tip
+## GitHub 저장소 보기
- 질문이 있는 경우, [GitHub 이슈 ](https://github.com/fastapi/fastapi/issues/new/choose) 에서 질문하십시오, [FastAPI 전문가](https://github.com/fastapi/fastapi/blob/master/docs/en/docs/fastapi-people.md#experts) 의 도움을 받을 가능성이 높습니다{.internal-link target=_blank} .
+GitHub에서 FastAPI를 "watch"할 수 있습니다 (오른쪽 상단 watch 버튼을 클릭): https://github.com/fastapi/fastapi. 👀
- ///
+"Releases only" 대신 "Watching"을 선택하면, 새로운 이슈나 질문이 생성될 때 알림을 받을 수 있습니다. 또한, 특정하게 새로운 이슈, 디스커션, PR 등만 알림 받도록 설정할 수도 있습니다.
- ```
- 다른 일반적인 대화에서만 채팅을 사용하십시오.
- ```
+그런 다음 이런 이슈들을 해결 할 수 있도록 도움을 줄 수 있습니다.
- 기존 [지터 채팅](https://gitter.im/fastapi/fastapi) 이 있지만 채널과 고급기능이 없어서 대화를 하기가 조금 어렵기 때문에 지금은 디스코드가 권장되는 시스템입니다.
+## 이슈 생성하기
- ### 질문을 위해 채팅을 사용하지 마십시오
+GitHub 저장소에 새로운 이슈 생성을 할 수 있습니다, 예를들면 다음과 같습니다:
- 채팅은 더 많은 "자유로운 대화"를 허용하기 때문에, 너무 일반적인 질문이나 대답하기 어려운 질문을 쉽게 질문을 할 수 있으므로, 답변을 받지 못할 수 있습니다.
+* **질문**을 하거나 **문제**에 대해 질문합니다.
+* 새로운 **기능**을 제안 합니다.
- GitHub 이슈에서의 템플릿은 올바른 질문을 작성하도록 안내하여 더 쉽게 좋은 답변을 얻거나 질문하기 전에 스스로 문제를 해결할 수도 있습니다. 그리고 GitHub에서는 시간이 조금 걸리더라도 항상 모든 것에 답할 수 있습니다. 채팅 시스템에서는 개인적으로 그렇게 할 수 없습니다. 😅
+**참고**: 만약 이슈를 생성한다면, 저는 여러분에게 다른 사람들을 도와달라고 부탁할 것입니다. 😉
- 채팅 시스템에서의 대화 또한 GitHub에서 처럼 쉽게 검색할 수 없기 때문에 대화 중에 질문과 답변이 손실될 수 있습니다. 그리고 GitHub 이슈에 있는 것만 [FastAPI 전문가](https://github.com/fastapi/fastapi/blob/master/docs/en/docs/fastapi-people.md#experts)가 되는 것으로 간주되므로{.internal-link target=_blank} , GitHub 이슈에서 더 많은 관심을 받을 것입니다.
+## Pull Requests 리뷰하기
- 반면, 채팅 시스템에는 수천 명의 사용자가 있기 때문에, 거의 항상 대화 상대를 찾을 가능성이 높습니다. 😄
+다른 사람들의 pull request를 리뷰하는 데 도움을 줄 수 있습니다.
- ## 개발자 스폰서가 되십시오
+다시 한번 말하지만, 최대한 친절하게 리뷰해 주세요. 🤗
- [GitHub 스폰서](https://github.com/sponsors/tiangolo) 를 통해 개발자를 경제적으로 지원할 수 있습니다.
+---
- 감사하다는 말로 커피를 ☕️ 한잔 사줄 수 있습니다. 😄
+Pull Rrquest를 리뷰할 때 고려해야 할 사항과 방법은 다음과 같습니다:
- 또한 FastAPI의 실버 또는 골드 스폰서가 될 수 있습니다. 🏅🎉
+### 문제 이해하기
- ## FastAPI를 강화하는 도구의 스폰서가 되십시오
+* 먼저, 해당 pull request가 해결하려는 **문제를 이해하는지** 확인하세요. GitHub 디스커션 또는 이슈에서 더 긴 논의가 있었을 수도 있습니다.
- 문서에서 보았듯이, FastAPI는 Starlette과 Pydantic 라는 거인의 어깨에 타고 있습니다.
+* Pull request가 필요하지 않을 가능성도 있습니다. **다른 방식**으로 문제를 해결할 수 있다면, 그 방법을 제안하거나 질문할 수 있습니다.
- 다음의 스폰서가 될 수 있습니다
+### 스타일에 너무 신경 쓰지 않기
- - [Samuel Colvin (Pydantic)](https://github.com/sponsors/samuelcolvin)
- - [Encode (Starlette, Uvicorn)](https://github.com/sponsors/encode)
+* 커밋 메시지 스타일 같은 것에 너무 신경 쓰지 않아도 됩니다. 저는 직접 커밋을 수정하여 squash and merge를 수행할 것입니다.
- ------
+* 코드 스타일 규칙도 걱정할 필요 없습니다. 이미 자동화된 도구들이 이를 검사하고 있습니다.
- 감사합니다! 🚀
+스타일이나 일관성 관련 요청이 필요한 경우, 제가 직접 요청하거나 필요한 변경 사항을 추가 커밋으로 수정할 것입니다.
+
+### 코드 확인하기
+
+* 코드를 읽고, **논리적으로 타당**한지 확인한 후 로컬에서 실행하여 문제가 해결되는지 확인하세요.
+
+* 그런 다음, 확인했다고 **댓글**을 남겨 주세요. 그래야 제가 검토했음을 알 수 있습니다.
+
+/// info
+
+불행히도, 제가 단순히 여러 개의 승인만으로 PR을 신뢰할 수는 없습니다.
+
+3개, 5개 이상의 승인이 달린 PR이 실제로는 깨져 있거나, 버그가 있거나, 주장하는 문제를 해결하지 못하는 경우가 여러 번 있었습니다. 😅
+
+따라서, 정말로 코드를 읽고 실행한 뒤, 댓글로 확인 내용을 남겨 주는 것이 매우 중요합니다. 🤓
+
+///
+
+* PR을 더 단순하게 만들 수 있다면 그렇게 요청할 수 있지만, 너무 까다로울 필요는 없습니다. 주관적인 견해가 많이 있을 수 있기 때문입니다 (그리고 저도 제 견해가 있을 거예요 🙈). 따라서 핵심적인 부분에 집중하는 것이 좋습니다.
+
+### 테스트
+
+* PR에 **테스트**가 포함되어 있는지 확인하는 데 도움을 주세요.
+
+* PR을 적용하기 전에 테스트가 **실패**하는지 확인하세요. 🚨
+
+* PR을 적용한 후 테스트가 **통과**하는지 확인하세요. ✅
+
+* 많은 PR에는 테스트가 없습니다. 테스트를 추가하도록 **상기**시켜줄 수도 있고, 직접 테스트를 **제안**할 수도 있습니다. 이는 시간이 많이 소요되는 부분 중 하나이며, 그 부분을 많이 도와줄 수 있습니다.
+
+* 그리고 시도한 내용을 댓글로 남겨주세요. 그러면 제가 확인했다는 걸 알 수 있습니다. 🤓
+
+## Pull Request를 만드십시오
+
+Pull Requests를 이용하여 소스코드에 [컨트리뷰트](contributing.md){.internal-link target=\_blank} 할 수 있습니다. 예를 들면 다음과 같습니다:
+
+* 문서에서 발견한 오타를 수정할 때.
+* FastAPI 관련 문서, 비디오 또는 팟캐스트를 작성했거나 발견하여 이 파일을 편집하여 공유할 때.
+ * 해당 섹션의 시작 부분에 링크를 추가해야 합니다.
+* 당신의 언어로 [문서 번역하는데](contributing.md#translations){.internal-link target=\_blank} 기여할 때.
+ * 다른 사람이 작성한 번역을 검토하는 것도 도울 수 있습니다.
+* 새로운 문서의 섹션을 제안할 때.
+* 기존 문제/버그를 수정할 때.
+ * 테스트를 반드시 추가해야 합니다.
+* 새로운 feature를 추가할 때.
+ * 테스트를 반드시 추가해야 합니다.
+ * 관련 문서가 필요하다면 반드시 추가해야 합니다.
+
+## FastAPI 유지 관리에 도움 주기
+
+**FastAPI**의 유지 관리를 도와주세요! 🤓
+
+할 일이 많고, 그 중 대부분은 **여러분**이 할 수 있습니다.
+
+지금 할 수 있는 주요 작업은:
+
+* [GitHub에서 다른 사람들의 질문에 도움 주기](#github_1){.internal-link target=_blank} (위의 섹션을 참조하세요).
+* [Pull Request 리뷰하기](#pull-requests){.internal-link target=_blank} (위의 섹션을 참조하세요).
+
+이 두 작업이 **가장 많은 시간을 소모**하는 일입니다. 그것이 FastAPI 유지 관리의 주요 작업입니다.
+
+이 작업을 도와주신다면, **FastAPI 유지 관리에 도움을 주는 것**이며 그것이 **더 빠르고 더 잘 발전하는 것**을 보장하는 것입니다. 🚀
+
+## 채팅에 참여하십시오
+
+👥 디스코드 채팅 서버 👥 에 가입하고 FastAPI 커뮤니티에서 다른 사람들과 어울리세요.
+
+/// tip
+
+질문이 있는 경우, GitHub 디스커션 에서 질문하십시오, [FastAPI Experts](fastapi-people.md#fastapi-experts){.internal-link target=_blank} 의 도움을 받을 가능성이 높습니다.
+
+다른 일반적인 대화에서만 채팅을 사용하십시오.
+
+///
+
+### 질문을 위해 채팅을 사용하지 마십시오
+
+채팅은 더 많은 "자유로운 대화"를 허용하기 때문에, 너무 일반적인 질문이나 대답하기 어려운 질문을 쉽게 질문을 할 수 있으므로, 답변을 받지 못할 수 있습니다.
+
+GitHub 이슈에서의 템플릿은 올바른 질문을 작성하도록 안내하여 더 쉽게 좋은 답변을 얻거나 질문하기 전에 스스로 문제를 해결할 수도 있습니다. 그리고 GitHub에서는 시간이 조금 걸리더라도 항상 모든 것에 답할 수 있습니다. 채팅 시스템에서는 개인적으로 그렇게 할 수 없습니다. 😅
+
+채팅 시스템에서의 대화 또한 GitHub에서 처럼 쉽게 검색할 수 없기 때문에 대화 중에 질문과 답변이 손실될 수 있습니다. 그리고 GitHub 이슈에 있는 것만 [FastAPI Expert](fastapi-people.md#fastapi-experts){.internal-link target=_blank}가 되는 것으로 간주되므로, GitHub 이슈에서 더 많은 관심을 받을 것입니다.
+
+반면, 채팅 시스템에는 수천 명의 사용자가 있기 때문에, 거의 항상 대화 상대를 찾을 가능성이 높습니다. 😄
+
+## 개발자 스폰서가 되십시오
+
+GitHub 스폰서 를 통해 개발자를 경제적으로 지원할 수 있습니다.
+
+감사하다는 말로 커피를 ☕️ 한잔 사줄 수 있습니다. 😄
+
+또한 FastAPI의 실버 또는 골드 스폰서가 될 수 있습니다. 🏅🎉
+
+## FastAPI를 강화하는 도구의 스폰서가 되십시오
+
+문서에서 보았듯이, FastAPI는 Starlette과 Pydantic 라는 거인의 어깨에 타고 있습니다.
+
+다음의 스폰서가 될 수 있습니다
+
+* Samuel Colvin (Pydantic)
+* Encode (Starlette, Uvicorn)
+
+---
+
+감사합니다! 🚀
diff --git a/docs/ko/docs/how-to/configure-swagger-ui.md b/docs/ko/docs/how-to/configure-swagger-ui.md
new file mode 100644
index 000000000..5a57342cf
--- /dev/null
+++ b/docs/ko/docs/how-to/configure-swagger-ui.md
@@ -0,0 +1,70 @@
+# Swagger UI 구성
+
+추가적인 Swagger UI 매개변수를 구성할 수 있습니다.
+
+구성을 하려면, `FastAPI()` 앱 객체를 생성할 때 또는 `get_swagger_ui_html()` 함수에 `swagger_ui_parameters` 인수를 전달하십시오.
+
+`swagger_ui_parameters`는 Swagger UI에 직접 전달된 구성을 포함하는 딕셔너리를 받습니다.
+
+FastAPI는 이 구성을 **JSON** 형식으로 변환하여 JavaScript와 호환되도록 합니다. 이는 Swagger UI에서 필요로 하는 형식입니다.
+
+## 구문 강조 비활성화
+
+예를 들어, Swagger UI에서 구문 강조 기능을 비활성화할 수 있습니다.
+
+설정을 변경하지 않으면, 기본적으로 구문 강조 기능이 활성화되어 있습니다:
+
+
+
+그러나 `syntaxHighlight`를 `False`로 설정하여 구문 강조 기능을 비활성화할 수 있습니다:
+
+{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *}
+
+...그럼 Swagger UI에서 더 이상 구문 강조 기능이 표시되지 않습니다:
+
+
+
+## 테마 변경
+
+동일한 방식으로 `"syntaxHighlight.theme"` 키를 사용하여 구문 강조 테마를 설정할 수 있습니다 (중간에 점이 포함된 것을 참고하십시오).
+
+{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *}
+
+이 설정은 구문 강조 색상 테마를 변경합니다:
+
+
+
+## 기본 Swagger UI 매개변수 변경
+
+FastAPI는 대부분의 사용 사례에 적합한 몇 가지 기본 구성 매개변수를 포함하고 있습니다.
+
+기본 구성에는 다음이 포함됩니다:
+
+{* ../../fastapi/openapi/docs.py ln[8:23] hl[17:23] *}
+
+`swagger_ui_parameters` 인수에 다른 값을 설정하여 이러한 기본값 중 일부를 재정의할 수 있습니다.
+
+예를 들어, `deepLinking`을 비활성화하려면 `swagger_ui_parameters`에 다음 설정을 전달할 수 있습니다:
+
+{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *}
+
+## 기타 Swagger UI 매개변수
+
+사용할 수 있는 다른 모든 구성 옵션을 확인하려면, Swagger UI 매개변수에 대한 공식 문서를 참조하십시오.
+
+## JavaScript 전용 설정
+
+Swagger UI는 **JavaScript 전용** 객체(예: JavaScript 함수)로 다른 구성을 허용하기도 합니다.
+
+FastAPI는 이러한 JavaScript 전용 `presets` 설정을 포함하고 있습니다:
+
+```JavaScript
+presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIBundle.SwaggerUIStandalonePreset
+]
+```
+
+이들은 문자열이 아닌 **JavaScript** 객체이므로 Python 코드에서 직접 전달할 수 없습니다.
+
+이와 같은 JavaScript 전용 구성을 사용해야 하는 경우, 위의 방법 중 하나를 사용하여 모든 Swagger UI 경로 작업을 재정의하고 필요한 JavaScript를 수동으로 작성할 수 있습니다.
diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md
index 8b00d90bc..0df2000fa 100644
--- a/docs/ko/docs/index.md
+++ b/docs/ko/docs/index.md
@@ -11,15 +11,18 @@
FastAPI 프레임워크, 고성능, 간편한 학습, 빠른 코드 작성, 준비된 프로덕션
---
diff --git a/docs/ko/docs/openapi-webhooks.md b/docs/ko/docs/openapi-webhooks.md
new file mode 100644
index 000000000..96339aa96
--- /dev/null
+++ b/docs/ko/docs/openapi-webhooks.md
@@ -0,0 +1,55 @@
+# OpenAPI 웹훅(Webhooks)
+
+API **사용자**에게 특정 **이벤트**가 발생할 때 *그들*의 앱(시스템)에 요청을 보내 **알림**을 전달할 수 있다는 것을 알리고 싶은 경우가 있습니다.
+
+즉, 일반적으로 사용자가 API에 요청을 보내는 것과는 반대로, **API**(또는 앱)가 **사용자의 시스템**(그들의 API나 앱)으로 **요청을 보내는** 상황을 의미합니다.
+
+이를 흔히 **웹훅(Webhook)**이라고 부릅니다.
+
+## 웹훅 스텝
+
+**코드에서** 웹훅으로 보낼 메시지, 즉 요청의 **바디(body)**를 정의하는 것이 일반적인 프로세스입니다.
+
+앱에서 해당 요청이나 이벤트를 전송할 **시점**을 정의합니다.
+
+**사용자**는 앱이 해당 요청을 보낼 **URL**을 정의합니다. (예: 웹 대시보드에서 설정)
+
+웹훅의 URL을 등록하는 방법과 이러한 요청을 실제로 전송하는 코드에 대한 모든 로직은 여러분에게 달려 있습니다. 원하는대로 **고유의 코드**를 작성하면 됩니다.
+
+## **FastAPI**와 OpenAPI로 웹훅 문서화하기
+
+**FastAPI**를 사용하여 OpenAPI와 함께 웹훅의 이름, 앱이 보낼 수 있는 HTTP 작업 유형(예: `POST`, `PUT` 등), 그리고 보낼 요청의 **바디**를 정의할 수 있습니다.
+
+이를 통해 사용자가 **웹훅** 요청을 수신할 **API 구현**을 훨씬 쉽게 할 수 있으며, 경우에 따라 사용자 API 코드의 일부를 자동 생성할 수도 있습니다.
+
+/// info
+
+웹훅은 OpenAPI 3.1.0 이상에서 지원되며, FastAPI `0.99.0` 이상 버전에서 사용할 수 있습니다.
+
+///
+
+## 웹훅이 포함된 앱 만들기
+
+**FastAPI** 애플리케이션을 만들 때, `webhooks` 속성을 사용하여 *웹훅*을 정의할 수 있습니다. 이는 `@app.webhooks.post()`와 같은 방식으로 *경로(path) 작업*을 정의하는 것과 비슷합니다.
+
+{* ../../docs_src/openapi_webhooks/tutorial001.py hl[9:13,36:53] *}
+
+이렇게 정의한 웹훅은 **OpenAPI** 스키마와 자동 **문서화 UI**에 표시됩니다.
+
+/// info
+
+`app.webhooks` 객체는 사실 `APIRouter`일 뿐이며, 여러 파일로 앱을 구성할 때 사용하는 것과 동일한 타입입니다.
+
+///
+
+웹훅에서는 실제 **경로(path)** (예: `/items/`)를 선언하지 않는 점에 유의해야 합니다. 여기서 전달하는 텍스트는 **식별자**로, 웹훅의 이름(이벤트 이름)입니다. 예를 들어, `@app.webhooks.post("new-subscription")`에서 웹훅 이름은 `new-subscription`입니다.
+
+이는 실제 **URL 경로**는 **사용자**가 다른 방법(예: 웹 대시보드)을 통해 지정하도록 기대되기 때문입니다.
+
+### 문서 확인하기
+
+이제 앱을 시작하고 http://127.0.0.1:8000/docs로 이동해 봅시다.
+
+문서에서 기존 *경로 작업*뿐만 아니라 **웹훅**도 표시된 것을 확인할 수 있습니다:
+
+
diff --git a/docs/ko/docs/python-types.md b/docs/ko/docs/python-types.md
index 7cc98ba76..18d4b341e 100644
--- a/docs/ko/docs/python-types.md
+++ b/docs/ko/docs/python-types.md
@@ -22,9 +22,8 @@
간단한 예제부터 시작해봅시다:
-```Python
-{!../../docs_src/python_types/tutorial001.py!}
-```
+{* ../../docs_src/python_types/tutorial001.py *}
+
이 프로그램을 실행한 결과값:
@@ -38,9 +37,8 @@ John Doe
* `title()`로 각 첫 문자를 대문자로 변환시킵니다.
* 두 단어를 중간에 공백을 두고 연결합니다.
-```Python hl_lines="2"
-{!../../docs_src/python_types/tutorial001.py!}
-```
+{* ../../docs_src/python_types/tutorial001.py hl[2] *}
+
### 코드 수정
@@ -82,9 +80,8 @@ John Doe
이게 "타입 힌트"입니다:
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial002.py!}
-```
+{* ../../docs_src/python_types/tutorial002.py hl[1] *}
+
타입힌트는 다음과 같이 기본 값을 선언하는 것과는 다릅니다:
@@ -112,9 +109,8 @@ John Doe
아래 함수를 보면, 이미 타입 힌트가 적용되어 있는 걸 볼 수 있습니다:
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial003.py!}
-```
+{* ../../docs_src/python_types/tutorial003.py hl[1] *}
+
편집기가 변수의 타입을 알고 있기 때문에, 자동완성 뿐 아니라 에러도 확인할 수 있습니다:
@@ -122,9 +118,8 @@ John Doe
이제 고쳐야하는 걸 알기 때문에, `age`를 `str(age)`과 같이 문자열로 바꾸게 됩니다:
-```Python hl_lines="2"
-{!../../docs_src/python_types/tutorial004.py!}
-```
+{* ../../docs_src/python_types/tutorial004.py hl[2] *}
+
## 타입 선언
@@ -143,9 +138,8 @@ John Doe
* `bool`
* `bytes`
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial005.py!}
-```
+{* ../../docs_src/python_types/tutorial005.py hl[1] *}
+
### 타입 매개변수를 활용한 Generic(제네릭) 타입
@@ -161,9 +155,8 @@ John Doe
`typing`에서 `List`(대문자 `L`)를 import 합니다.
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial006.py!}
-```
+{* ../../docs_src/python_types/tutorial006.py hl[1] *}
+
콜론(`:`) 문법을 이용하여 변수를 선언합니다.
@@ -171,9 +164,8 @@ John Doe
이때 배열은 내부 타입을 포함하는 타입이기 때문에 대괄호 안에 넣어줍니다.
-```Python hl_lines="4"
-{!../../docs_src/python_types/tutorial006.py!}
-```
+{* ../../docs_src/python_types/tutorial006.py hl[4] *}
+
/// tip | 팁
@@ -199,9 +191,8 @@ John Doe
`tuple`과 `set`도 동일하게 선언할 수 있습니다.
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial007.py!}
-```
+{* ../../docs_src/python_types/tutorial007.py hl[1,4] *}
+
이 뜻은 아래와 같습니다:
@@ -216,9 +207,8 @@ John Doe
두 번째 매개변수는 `dict`의 값(value)입니다.
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial008.py!}
-```
+{* ../../docs_src/python_types/tutorial008.py hl[1,4] *}
+
이 뜻은 아래와 같습니다:
@@ -255,15 +245,13 @@ John Doe
이름(name)을 가진 `Person` 클래스가 있다고 해봅시다.
-```Python hl_lines="1-3"
-{!../../docs_src/python_types/tutorial010.py!}
-```
+{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
+
그렇게 하면 변수를 `Person`이라고 선언할 수 있게 됩니다.
-```Python hl_lines="6"
-{!../../docs_src/python_types/tutorial010.py!}
-```
+{* ../../docs_src/python_types/tutorial010.py hl[6] *}
+
그리고 역시나 모든 에디터 도움을 받게 되겠죠.
@@ -283,9 +271,8 @@ John Doe
Pydantic 공식 문서 예시:
-```Python
-{!../../docs_src/python_types/tutorial011.py!}
-```
+{* ../../docs_src/python_types/tutorial011.py *}
+
/// info | 정보
diff --git a/docs/ko/docs/resources/index.md b/docs/ko/docs/resources/index.md
new file mode 100644
index 000000000..e804dd4d5
--- /dev/null
+++ b/docs/ko/docs/resources/index.md
@@ -0,0 +1,3 @@
+# 리소스
+
+추가 리소스, 외부 링크, 기사 등. ✈️
diff --git a/docs/ko/docs/tutorial/background-tasks.md b/docs/ko/docs/tutorial/background-tasks.md
index 376c52524..a2c4abbd9 100644
--- a/docs/ko/docs/tutorial/background-tasks.md
+++ b/docs/ko/docs/tutorial/background-tasks.md
@@ -15,9 +15,7 @@ FastAPI에서는 응답을 반환한 후에 실행할 백그라운드 작업을
먼저 아래와 같이 `BackgroundTasks`를 임포트하고, `BackgroundTasks`를 _경로 작동 함수_ 에서 매개변수로 가져오고 정의합니다.
-```Python hl_lines="1 13"
-{!../../docs_src/background_tasks/tutorial001.py!}
-```
+{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
**FastAPI** 는 `BackgroundTasks` 개체를 생성하고, 매개 변수로 전달합니다.
@@ -33,17 +31,13 @@ FastAPI에서는 응답을 반환한 후에 실행할 백그라운드 작업을
그리고 이 작업은 `async`와 `await`를 사용하지 않으므로 일반 `def` 함수로 선언합니다.
-```Python hl_lines="6-9"
-{!../../docs_src/background_tasks/tutorial001.py!}
-```
+{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
## 백그라운드 작업 추가
_경로 작동 함수_ 내에서 작업 함수를 `.add_task()` 함수 통해 _백그라운드 작업_ 개체에 전달합니다.
-```Python hl_lines="14"
-{!../../docs_src/background_tasks/tutorial001.py!}
-```
+{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
`.add_task()` 함수는 다음과 같은 인자를 받습니다 :
@@ -57,21 +51,7 @@ _경로 작동 함수_ 내에서 작업 함수를 `.add_task()` 함수 통해 _
**FastAPI**는 각 경우에 수행할 작업과 동일한 개체를 내부적으로 재사용하기에, 모든 백그라운드 작업이 함께 병합되고 나중에 백그라운드에서 실행됩니다.
-//// tab | Python 3.6 and above
-
-```Python hl_lines="13 15 22 25"
-{!> ../../docs_src/background_tasks/tutorial002.py!}
-```
-
-////
-
-//// tab | Python 3.10 and above
-
-```Python hl_lines="11 13 20 23"
-{!> ../../docs_src/background_tasks/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/background_tasks/tutorial002.py hl[13,15,22,25] *}
이 예제에서는 응답이 반환된 후에 `log.txt` 파일에 메시지가 기록됩니다.
@@ -97,8 +77,6 @@ FastAPI에서 `BackgroundTask`를 단독으로 사용하는 것은 여전히 가
RabbitMQ 또는 Redis와 같은 메시지/작업 큐 시스템 보다 복잡한 구성이 필요한 경향이 있지만, 여러 작업 프로세스를 특히 여러 서버의 백그라운드에서 실행할 수 있습니다.
-예제를 보시려면 [프로젝트 생성기](../project-generation.md){.internal-link target=\_blank} 를 참고하세요. 해당 예제에는 이미 구성된 `Celery`가 포함되어 있습니다.
-
그러나 동일한 FastAPI 앱에서 변수 및 개체에 접근해야햐는 작은 백그라운드 수행이 필요한 경우 (예 : 알림 이메일 보내기) 간단하게 `BackgroundTasks`를 사용해보세요.
## 요약
diff --git a/docs/ko/docs/tutorial/body-fields.md b/docs/ko/docs/tutorial/body-fields.md
index f6532f369..4708e7099 100644
--- a/docs/ko/docs/tutorial/body-fields.md
+++ b/docs/ko/docs/tutorial/body-fields.md
@@ -6,57 +6,7 @@
먼저 이를 임포트해야 합니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="2"
-{!> ../../docs_src/body_fields/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
/// warning | 경고
@@ -68,57 +18,7 @@
그 다음 모델 어트리뷰트와 함께 `Field`를 사용할 수 있습니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="11-14"
-{!> ../../docs_src/body_fields/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="11-14"
-{!> ../../docs_src/body_fields/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="12-15"
-{!> ../../docs_src/body_fields/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="9-12"
-{!> ../../docs_src/body_fields/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="11-14"
-{!> ../../docs_src/body_fields/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
`Field`는 `Query`, `Path`와 `Body`와 같은 방식으로 동작하며, 모두 같은 매개변수들 등을 가집니다.
diff --git a/docs/ko/docs/tutorial/body-multiple-params.md b/docs/ko/docs/tutorial/body-multiple-params.md
index 569ff016e..edf892dfa 100644
--- a/docs/ko/docs/tutorial/body-multiple-params.md
+++ b/docs/ko/docs/tutorial/body-multiple-params.md
@@ -10,9 +10,7 @@
또한, 기본 값을 `None`으로 설정해 본문 매개변수를 선택사항으로 선언할 수 있습니다.
-```Python hl_lines="19-21"
-{!../../docs_src/body_multiple_params/tutorial001.py!}
-```
+{* ../../docs_src/body_multiple_params/tutorial001.py hl[19:21] *}
/// note | 참고
@@ -35,9 +33,7 @@
하지만, 다중 본문 매개변수 역시 선언할 수 있습니다. 예. `item`과 `user`:
-```Python hl_lines="22"
-{!../../docs_src/body_multiple_params/tutorial002.py!}
-```
+{* ../../docs_src/body_multiple_params/tutorial002.py hl[22] *}
이 경우에, **FastAPI**는 이 함수 안에 한 개 이상의 본문 매개변수(Pydantic 모델인 두 매개변수)가 있다고 알 것입니다.
@@ -79,9 +75,7 @@ FastAPI는 요청을 자동으로 변환해, 매개변수의 `item`과 `user`를
하지만, **FastAPI**의 `Body`를 사용해 다른 본문 키로 처리하도록 제어할 수 있습니다:
-```Python hl_lines="23"
-{!../../docs_src/body_multiple_params/tutorial003.py!}
-```
+{* ../../docs_src/body_multiple_params/tutorial003.py hl[23] *}
이 경우에는 **FastAPI**는 본문을 이와 같이 예측할 것입니다:
@@ -110,9 +104,7 @@ FastAPI는 요청을 자동으로 변환해, 매개변수의 `item`과 `user`를
기본적으로 단일 값은 쿼리 매개변수로 해석되므로, 명시적으로 `Query`를 추가할 필요가 없고, 아래처럼 할 수 있습니다:
-```Python hl_lines="27"
-{!../../docs_src/body_multiple_params/tutorial004.py!}
-```
+{* ../../docs_src/body_multiple_params/tutorial004.py hl[27] *}
이렇게:
@@ -134,9 +126,7 @@ Pydantic 모델 `Item`의 `item`을 본문 매개변수로 오직 한개만 갖
하지만, 만약 모델 내용에 `item `키를 가진 JSON으로 예측하길 원한다면, 추가적인 본문 매개변수를 선언한 것처럼 `Body`의 특별한 매개변수인 `embed`를 사용할 수 있습니다:
-```Python hl_lines="17"
-{!../../docs_src/body_multiple_params/tutorial005.py!}
-```
+{* ../../docs_src/body_multiple_params/tutorial005.py hl[17] *}
아래 처럼:
diff --git a/docs/ko/docs/tutorial/body-nested-models.md b/docs/ko/docs/tutorial/body-nested-models.md
index e9b1d2e18..ebd7b3ba6 100644
--- a/docs/ko/docs/tutorial/body-nested-models.md
+++ b/docs/ko/docs/tutorial/body-nested-models.md
@@ -5,9 +5,7 @@
어트리뷰트를 서브타입으로 정의할 수 있습니다. 예를 들어 파이썬 `list`는:
-```Python hl_lines="14"
-{!../../docs_src/body_nested_models/tutorial001.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial001.py hl[14] *}
이는 `tags`를 항목 리스트로 만듭니다. 각 항목의 타입을 선언하지 않더라도요.
@@ -19,9 +17,7 @@
먼저, 파이썬 표준 `typing` 모듈에서 `List`를 임포트합니다:
-```Python hl_lines="1"
-{!../../docs_src/body_nested_models/tutorial002.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
### 타입 매개변수로 `List` 선언
@@ -42,9 +38,7 @@ my_list: List[str]
마찬가지로 예제에서 `tags`를 구체적으로 "문자열의 리스트"로 만들 수 있습니다:
-```Python hl_lines="14"
-{!../../docs_src/body_nested_models/tutorial002.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial002.py hl[14] *}
## 집합 타입
@@ -54,9 +48,7 @@ my_list: List[str]
그렇다면 `Set`을 임포트 하고 `tags`를 `str`의 `set`으로 선언할 수 있습니다:
-```Python hl_lines="1 14"
-{!../../docs_src/body_nested_models/tutorial003.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial003.py hl[1,14] *}
덕분에 중복 데이터가 있는 요청을 수신하더라도 고유한 항목들의 집합으로 변환됩니다.
@@ -78,17 +70,13 @@ Pydantic 모델의 각 어트리뷰트는 타입을 갖습니다.
예를 들어, `Image` 모델을 선언할 수 있습니다:
-```Python hl_lines="9-11"
-{!../../docs_src/body_nested_models/tutorial004.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial004.py hl[9:11] *}
### 서브모듈을 타입으로 사용
그리고 어트리뷰트의 타입으로 사용할 수 있습니다:
-```Python hl_lines="20"
-{!../../docs_src/body_nested_models/tutorial004.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial004.py hl[20] *}
이는 **FastAPI**가 다음과 유사한 본문을 기대한다는 것을 의미합니다:
@@ -121,9 +109,7 @@ Pydantic 모델의 각 어트리뷰트는 타입을 갖습니다.
예를 들어 `Image` 모델 안에 `url` 필드를 `str` 대신 Pydantic의 `HttpUrl`로 선언할 수 있습니다:
-```Python hl_lines="4 10"
-{!../../docs_src/body_nested_models/tutorial005.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial005.py hl[4,10] *}
이 문자열이 유효한 URL인지 검사하고 JSON 스키마/OpenAPI로 문서화 됩니다.
@@ -131,9 +117,7 @@ Pydantic 모델의 각 어트리뷰트는 타입을 갖습니다.
`list`, `set` 등의 서브타입으로 Pydantic 모델을 사용할 수도 있습니다:
-```Python hl_lines="20"
-{!../../docs_src/body_nested_models/tutorial006.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial006.py hl[20] *}
아래와 같은 JSON 본문으로 예상(변환, 검증, 문서화 등을)합니다:
@@ -171,9 +155,7 @@ Pydantic 모델의 각 어트리뷰트는 타입을 갖습니다.
단독으로 깊게 중첩된 모델을 정의할 수 있습니다:
-```Python hl_lines="9 14 20 23 27"
-{!../../docs_src/body_nested_models/tutorial007.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial007.py hl[9,14,20,23,27] *}
/// info | 정보
@@ -191,9 +173,7 @@ images: List[Image]
이를 아래처럼:
-```Python hl_lines="15"
-{!../../docs_src/body_nested_models/tutorial008.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial008.py hl[15] *}
## 어디서나 편집기 지원
@@ -223,9 +203,7 @@ Pydantic 모델 대신에 `dict`를 직접 사용하여 작업할 경우, 이러
이 경우, `float` 값을 가진 `int` 키가 있는 모든 `dict`를 받아들입니다:
-```Python hl_lines="15"
-{!../../docs_src/body_nested_models/tutorial009.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial009.py hl[15] *}
/// tip | 팁
diff --git a/docs/ko/docs/tutorial/body.md b/docs/ko/docs/tutorial/body.md
index 9e614ef1c..b3914fa4b 100644
--- a/docs/ko/docs/tutorial/body.md
+++ b/docs/ko/docs/tutorial/body.md
@@ -22,21 +22,7 @@
먼저 `pydantic`에서 `BaseModel`를 임포트해야 합니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="2"
-{!> ../../docs_src/body/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
## 여러분의 데이터 모델 만들기
@@ -44,21 +30,7 @@
모든 어트리뷰트에 대해 표준 파이썬 타입을 사용합니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="5-9"
-{!> ../../docs_src/body/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="7-11"
-{!> ../../docs_src/body/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
쿼리 매개변수를 선언할 때와 같이, 모델 어트리뷰트가 기본 값을 가지고 있어도 이는 필수가 아닙니다. 그외에는 필수입니다. 그저 `None`을 사용하여 선택적으로 만들 수 있습니다.
@@ -86,21 +58,7 @@
여러분의 *경로 작동*에 추가하기 위해, 경로 매개변수 그리고 쿼리 매개변수에서 선언했던 것과 같은 방식으로 선언하면 됩니다.
-//// tab | Python 3.10+
-
-```Python hl_lines="16"
-{!> ../../docs_src/body/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="18"
-{!> ../../docs_src/body/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
...그리고 만들어낸 모델인 `Item`으로 타입을 선언합니다.
@@ -167,21 +125,7 @@
함수 안에서 모델 객체의 모든 어트리뷰트에 직접 접근 가능합니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/body/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="21"
-{!> ../../docs_src/body/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial002_py310.py hl[19] *}
## 요청 본문 + 경로 매개변수
@@ -189,21 +133,7 @@
**FastAPI**는 경로 매개변수와 일치하는 함수 매개변수가 **경로에서 가져와야 한다**는 것을 인지하며, Pydantic 모델로 선언된 그 함수 매개변수는 **요청 본문에서 가져와야 한다**는 것을 인지할 것입니다.
-//// tab | Python 3.10+
-
-```Python hl_lines="15-16"
-{!> ../../docs_src/body/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="17-18"
-{!> ../../docs_src/body/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
## 요청 본문 + 경로 + 쿼리 매개변수
@@ -211,21 +141,7 @@
**FastAPI**는 각각을 인지하고 데이터를 옳바른 위치에 가져올 것입니다.
-//// tab | Python 3.10+
-
-```Python hl_lines="16"
-{!> ../../docs_src/body/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="18"
-{!> ../../docs_src/body/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
함수 매개변수는 다음을 따라서 인지하게 됩니다:
diff --git a/docs/ko/docs/tutorial/cookie-param-models.md b/docs/ko/docs/tutorial/cookie-param-models.md
new file mode 100644
index 000000000..e7eef0b1d
--- /dev/null
+++ b/docs/ko/docs/tutorial/cookie-param-models.md
@@ -0,0 +1,76 @@
+# 쿠키 매개변수 모델
+
+관련있는 **쿠키**들의 그룹이 있는 경우, **Pydantic 모델**을 생성하여 선언할 수 있습니다. 🍪
+
+이를 통해 **여러 위치**에서 **모델을 재사용** 할 수 있고 모든 매개변수에 대한 유효성 검사 및 메타데이터를 한 번에 선언할 수도 있습니다. 😍
+
+/// note | 참고
+
+이 기능은 FastAPI 버전 `0.115.0` 이후부터 지원됩니다. 🤓
+
+///
+
+/// tip | 팁
+
+동일한 기술이 `Query`, `Cookie`, 그리고 `Header`에 적용됩니다. 😎
+
+///
+
+## Pydantic 모델을 사용한 쿠키
+
+**Pydantic 모델**에 필요한 **쿠키** 매개변수를 선언한 다음, 해당 매개변수를 `Cookie`로 선언합니다:
+
+{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
+
+**FastAPI**는 요청에서 받은 **쿠키**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.
+
+## 문서 확인하기
+
+문서 UI `/docs`에서 정의한 쿠키를 볼 수 있습니다:
+
+
+
+
+
+/// info | 정보
+
+명심하세요, 내부적으로 **브라우저는 쿠키를 특별한 방식으로 처리**하기 때문에 **자바스크립트**가 쉽게 쿠키를 건드릴 수 **없습니다**.
+
+`/docs`에서 **API 문서 UI**로 이동하면 *경로 작업*에 대한 쿠키의 **문서**를 볼 수 있습니다.
+
+하지만 아무리 **데이터를 입력**하고 "실행(Execute)"을 클릭해도, 문서 UI는 **자바스크립트**로 작동하기 때문에 쿠키는 전송되지 않고, 아무 값도 쓰지 않은 것처럼 **오류** 메시지를 보게 됩니다.
+
+///
+
+## 추가 쿠키 금지하기
+
+일부 특별한 사용 사례(흔하지는 않겠지만)에서는 수신하려는 쿠키를 **제한**할 수 있습니다.
+
+이제 API는 자신의 쿠키 동의를 제어할 수 있는 권한을 갖게 되었습니다. 🤪🍪
+
+Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다:
+
+{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *}
+
+클라이언트가 **추가 쿠키**를 보내려고 시도하면, **오류** 응답을 받게 됩니다.
+
+API가 거부하는데도 동의를 얻기 위해 애쓰는 불쌍한 쿠키 배너(팝업)들. 🍪
+
+예를 들어, 클라이언트가 `good-list-please` 값으로 `santa_tracker` 쿠키를 보내려고 하면 클라이언트는 `santa_tracker` 쿠키가 허용되지 않는다는 **오류** 응답을 받게 됩니다:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["cookie", "santa_tracker"],
+ "msg": "Extra inputs are not permitted",
+ "input": "good-list-please",
+ }
+ ]
+}
+```
+
+## 요약
+
+**Pydantic 모델**을 사용하여 **FastAPI**에서 **쿠키**를 선언할 수 있습니다. 😍
diff --git a/docs/ko/docs/tutorial/cookie-params.md b/docs/ko/docs/tutorial/cookie-params.md
index 427539210..fba756d49 100644
--- a/docs/ko/docs/tutorial/cookie-params.md
+++ b/docs/ko/docs/tutorial/cookie-params.md
@@ -6,57 +6,7 @@
먼저 `Cookie`를 임포트합니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
## `Cookie` 매개변수 선언
@@ -64,57 +14,7 @@
첫 번째 값은 기본값이며, 추가 검증이나 어노테이션 매개변수 모두 전달할 수 있습니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/cookie_params/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/cookie_params/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/cookie_params/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/cookie_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
/// note | 기술 세부사항
diff --git a/docs/ko/docs/tutorial/cors.md b/docs/ko/docs/tutorial/cors.md
index 0222e6258..1ef5a7480 100644
--- a/docs/ko/docs/tutorial/cors.md
+++ b/docs/ko/docs/tutorial/cors.md
@@ -46,9 +46,7 @@
* 특정한 HTTP 메소드(`POST`, `PUT`) 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 메소드.
* 특정한 HTTP 헤더 또는 와일드카드 `"*"` 를 사용한 모든 HTTP 헤더.
-```Python hl_lines="2 6-11 13-19"
-{!../../docs_src/cors/tutorial001.py!}
-```
+{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
`CORSMiddleware` 에서 사용하는 기본 매개변수는 제한적이므로, 브라우저가 교차-도메인 상황에서 특정한 출처, 메소드, 헤더 등을 사용할 수 있도록 하려면 이들을 명시적으로 허용해야 합니다.
diff --git a/docs/ko/docs/tutorial/debugging.md b/docs/ko/docs/tutorial/debugging.md
index fcb68b565..e42f1ba88 100644
--- a/docs/ko/docs/tutorial/debugging.md
+++ b/docs/ko/docs/tutorial/debugging.md
@@ -6,9 +6,7 @@
FastAPI 애플리케이션에서 `uvicorn`을 직접 임포트하여 실행합니다
-```Python hl_lines="1 15"
-{!../../docs_src/debugging/tutorial001.py!}
-```
+{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
### `__name__ == "__main__"` 에 대하여
diff --git a/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md
index 41e48aefc..3e5cdcc8c 100644
--- a/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -6,21 +6,7 @@
이전 예제에서, 우리는 의존성(의존 가능한) 함수에서 `딕셔너리`객체를 반환하고 있었습니다:
-//// tab | 파이썬 3.6 이상
-
-```Python hl_lines="9"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="7"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001.py hl[9] *}
우리는 *경로 작동 함수*의 매개변수 `commons`에서 `딕셔너리` 객체를 얻습니다.
@@ -81,57 +67,15 @@ FastAPI가 실질적으로 확인하는 것은 "호출 가능성"(함수, 클래
그래서, 우리는 위 예제에서의 `common_paramenters` 의존성을 클래스 `CommonQueryParams`로 바꿀 수 있습니다.
-//// tab | 파이썬 3.6 이상
-
-```Python hl_lines="11-15"
-{!> ../../docs_src/dependencies/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="9-13"
-{!> ../../docs_src/dependencies/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial002.py hl[11:15] *}
클래스의 인스턴스를 생성하는 데 사용되는 `__init__` 메서드에 주목하기 바랍니다:
-//// tab | 파이썬 3.6 이상
-
-```Python hl_lines="12"
-{!> ../../docs_src/dependencies/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="10"
-{!> ../../docs_src/dependencies/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial002.py hl[12] *}
...이전 `common_parameters`와 동일한 매개변수를 가집니다:
-//// tab | 파이썬 3.6 이상
-
-```Python hl_lines="9"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="6"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001.py hl[9] *}
이 매개변수들은 **FastAPI**가 의존성을 "해결"하기 위해 사용할 것입니다
@@ -147,21 +91,7 @@ FastAPI가 실질적으로 확인하는 것은 "호출 가능성"(함수, 클래
이제 아래의 클래스를 이용해서 의존성을 정의할 수 있습니다.
-//// tab | 파이썬 3.6 이상
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial002.py hl[19] *}
**FastAPI**는 `CommonQueryParams` 클래스를 호출합니다. 이것은 해당 클래스의 "인스턴스"를 생성하고 그 인스턴스는 함수의 매개변수 `commons`로 전달됩니다.
@@ -200,21 +130,7 @@ commons = Depends(CommonQueryParams)
..전체적인 코드는 아래와 같습니다:
-//// tab | 파이썬 3.6 이상
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial003.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial003_py310.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial003.py hl[19] *}
그러나 자료형을 선언하면 에디터가 매개변수 `commons`로 전달될 것이 무엇인지 알게 되고, 이를 통해 코드 완성, 자료형 확인 등에 도움이 될 수 있으므로 권장됩니다.
@@ -248,21 +164,7 @@ commons: CommonQueryParams = Depends()
아래에 같은 예제가 있습니다:
-//// tab | 파이썬 3.6 이상
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial004.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial004_py310.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial004.py hl[19] *}
...이렇게 코드를 단축하여도 **FastAPI**는 무엇을 해야하는지 알고 있습니다.
diff --git a/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
index fab636b7f..4a3854cef 100644
--- a/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
+++ b/docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -14,35 +14,7 @@
`Depends()`로 된 `list`이어야합니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="18"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
이러한 의존성들은 기존 의존성들과 같은 방식으로 실행/해결됩니다. 그러나 값은 (무엇이든 반환한다면) *경로 작동 함수*에 제공되지 않습니다.
@@ -72,69 +44,13 @@
(헤더같은) 요청 요구사항이나 하위-의존성을 선언할 수 있습니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="8 13"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="7 12"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="6 11"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
### 오류 발생시키기
다음 의존성은 기존 의존성과 동일하게 예외를 `raise`를 일으킬 수 있습니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="10 15"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9 14"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="8 13"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
### 값 반환하기
@@ -142,35 +58,7 @@
그래서 이미 다른 곳에서 사용된 (값을 반환하는) 일반적인 의존성을 재사용할 수 있고, 비록 값은 사용되지 않지만 의존성은 실행될 것입니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="11 16"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10 15"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="9 14"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
## *경로 작동* 모음에 대한 의존성
diff --git a/docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md
new file mode 100644
index 000000000..ff174937d
--- /dev/null
+++ b/docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -0,0 +1,275 @@
+# yield를 사용하는 의존성
+
+FastAPI는 작업 완료 후 추가 단계를 수행하는 의존성을 지원합니다.
+
+이를 구현하려면 `return` 대신 `yield`를 사용하고, 추가로 실행할 단계 (코드)를 그 뒤에 작성하세요.
+
+/// tip | 팁
+
+각 의존성마다 `yield`는 한 번만 사용해야 합니다.
+
+///
+
+/// note | 기술 세부사항
+
+다음과 함께 사용할 수 있는 모든 함수:
+
+* `@contextlib.contextmanager` 또는
+* `@contextlib.asynccontextmanager`
+
+는 **FastAPI**의 의존성으로 사용할 수 있습니다.
+
+사실, FastAPI는 내부적으로 이 두 데코레이터를 사용합니다.
+
+///
+
+## `yield`를 사용하는 데이터베이스 의존성
+
+예를 들어, 이 기능을 사용하면 데이터베이스 세션을 생성하고 작업이 끝난 후에 세션을 종료할 수 있습니다.
+
+응답을 생성하기 전에는 `yield`문을 포함하여 그 이전의 코드만이 실행됩니다:
+
+{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *}
+
+yield된 값은 *경로 작업* 및 다른 의존성들에 주입되는 값 입니다:
+
+{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
+
+`yield`문 다음의 코드는 응답을 생성한 후 보내기 전에 실행됩니다:
+
+{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *}
+
+/// tip | 팁
+
+`async` 함수와 일반 함수 모두 사용할 수 있습니다.
+
+**FastAPI**는 일반 의존성과 마찬가지로 각각의 함수를 올바르게 처리할 것입니다.
+
+///
+
+## `yield`와 `try`를 사용하는 의존성
+
+`yield`를 사용하는 의존성에서 `try` 블록을 사용한다면, 의존성을 사용하는 도중 발생한 모든 예외를 받을 수 있습니다.
+
+예를 들어, 다른 의존성이나 *경로 작업*의 중간에 데이터베이스 트랜잭션 "롤백"이 발생하거나 다른 오류가 발생한다면, 해당 예외를 의존성에서 받을 수 있습니다.
+
+따라서, 의존성 내에서 `except SomeException`을 사용하여 특정 예외를 처리할 수 있습니다.
+
+마찬가지로, `finally`를 사용하여 예외 발생 여부와 관계 없이 종료 단계까 실행되도록 할 수 있습니다.
+
+{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *}
+
+## `yield`를 사용하는 하위 의존성
+
+모든 크기와 형태의 하위 의존성과 하위 의존성의 "트리"도 가질 수 있으며, 이들 모두가 `yield`를 사용할 수 있습니다.
+
+**FastAPI**는 `yield`를 사용하는 각 의존성의 "종료 코드"가 올바른 순서로 실행되도록 보장합니다.
+
+예를 들어, `dependency_c`는 `dependency_b`에 의존할 수 있고, `dependency_b`는 `dependency_a`에 의존할 수 있습니다.
+
+{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
+
+이들 모두는 `yield`를 사용할 수 있습니다.
+
+이 경우 `dependency_c`는 종료 코드를 실행하기 위해, `dependency_b`의 값 (여기서는 `dep_b`로 명명)이 여전히 사용 가능해야 합니다.
+
+그리고, `dependency_b`는 종료 코드를 위해 `dependency_a`의 값 (여기서는 `dep_a`로 명명) 이 사용 가능해야 합니다.
+
+{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
+
+같은 방식으로, `yield`를 사용하는 의존성과 `return`을 사용하는 의존성을 함께 사용할 수 있으며, 이들 중 일부가 다른 것들에 의존할 수 있습니다.
+
+그리고 `yield`를 사용하는 다른 여러 의존성을 필요로 하는 단일 의존성을 가질 수도 있습니다.
+
+원하는 의존성을 원하는 대로 조합할 수 있습니다.
+
+**FastAPI**는 모든 것이 올바른 순서로 실행되도록 보장합니다.
+
+/// note | 기술 세부사항
+
+파이썬의 Context Managers 덕분에 이 기능이 작동합니다.
+
+**FastAPI**는 이를 내부적으로 컨텍스트 관리자를 사용하여 구현합니다.
+
+///
+
+## `yield`와 `HTTPException`를 사용하는 의존성
+
+`yield`와 `try` 블록이 있는 의존성을 사용하여 예외를 처리할 수 있다는 것을 알게 되었습니다.
+
+같은 방식으로, `yield` 이후의 종료 코드에서 `HTTPException`이나 유사한 예외를 발생시킬 수 있습니다.
+
+/// tip | 팁
+
+이는 다소 고급 기술이며, 대부분의 경우 경로 연산 함수 등 나머지 애플리케이션 코드 내부에서 예외 (`HTTPException` 포함)를 발생시킬 수 있으므로 실제로는 필요하지 않을 것입니다.
+
+하지만 필요한 경우 사용할 수 있습니다. 🤓
+
+///
+
+{* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *}
+
+예외를 처리하고(또는 추가로 다른 `HTTPException`을 발생시키기 위해) 사용할 수 있는 또 다른 방법은 [사용자 정의 예외 처리기](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}를 생성하는 것 입니다.
+
+## `yield`와 `except`를 사용하는 의존성
+
+`yield`를 사용하는 의존성에서 `except`를 사용하여 예외를 포착하고 예외를 다시 발생시키지 않거나 (또는 새 예외를 발생시키지 않으면), FastAPI는 해당 예외가 발생했는지 알 수 없습니다. 이는 일반적인 Python 방식과 동일합니다:
+
+{* ../../docs_src/dependencies/tutorial008c_an_py39.py hl[15:16] *}
+
+이 경우, `HTTPException`이나 유사한 예외를 발생시키지 않기 때문에 클라이언트는 HTTP 500 Internal Server Error 응답을 보게 되지만, 서버는 어떤 오류가 발생했는지에 대한 **로그**나 다른 표시를 전혀 가지지 않게 됩니다. 😱
+
+### `yield`와 `except`를 사용하는 의존성에서 항상 `raise` 하기
+
+`yield`가 있는 의존성에서 예외를 잡았을 때는 `HTTPException`이나 유사한 예외를 새로 발생시키지 않는 한, 반드시 원래의 예외를 다시 발생시켜야 합니다.
+
+`raise`를 사용하여 동일한 예외를 다시 발생시킬 수 있습니다:
+
+{* ../../docs_src/dependencies/tutorial008d_an_py39.py hl[17] *}
+
+이제 클라이언트는 동일한 *HTTP 500 Internal Server Error* 오류 응답을 받게 되지만, 서버 로그에는 사용자 정의 예외인 `InternalError"가 기록됩니다. 😎
+
+## `yield`를 사용하는 의존성의 실행 순서
+
+실행 순서는 아래 다이어그램과 거의 비슷합니다. 시간은 위에서 아래로 흐릅니다. 그리고 각 열은 상호 작용하거나 코드를 실행하는 부분 중 하나입니다.
+
+```mermaid
+sequenceDiagram
+
+participant client as Client
+participant handler as Exception handler
+participant dep as Dep with yield
+participant operation as Path Operation
+participant tasks as Background tasks
+
+ Note over client,operation: Can raise exceptions, including HTTPException
+ client ->> dep: Start request
+ Note over dep: Run code up to yield
+ opt raise Exception
+ dep -->> handler: Raise Exception
+ handler -->> client: HTTP error response
+ end
+ dep ->> operation: Run dependency, e.g. DB session
+ opt raise
+ operation -->> dep: Raise Exception (e.g. HTTPException)
+ opt handle
+ dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
+ end
+ handler -->> client: HTTP error response
+ end
+
+ operation ->> client: Return response to client
+ Note over client,operation: Response is already sent, can't change it anymore
+ opt Tasks
+ operation -->> tasks: Send background tasks
+ end
+ opt Raise other exception
+ tasks -->> tasks: Handle exceptions in the background task code
+ end
+```
+
+/// info | 정보
+
+클라이언트에 **하나의 응답** 만 전송됩니다. 이는 오류 응답 중 하나일 수도 있고,*경로 작업*에서 생성된 응답일 수도 있습니다.
+
+이러한 응답 중 하나가 전송된 후에는 다른 응답을 보낼 수 없습니다.
+
+///
+
+/// tip | 팁
+
+이 다이어그램은 `HTTPException`을 보여주지만, `yield`를 사용하는 의존성에서 처리한 예외나 [사용자 정의 예외처리기](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.를 사용하여 처리한 다른 예외도 발생시킬 수 있습니다.
+
+어떤 예외가 발생하든, `HTTPException`을 포함하여 yield를 사용하는 의존성으로 전달됩니다. 대부분의 경우 예외를 다시 발생시키거나 새로운 예외를 발생시켜야 합니다.
+
+///
+
+## `yield`, `HTTPException`, `except` 및 백그라운드 작업을 사용하는 의존성
+
+/// warning | 경고
+
+이러한 기술적 세부 사항은 대부분 필요하지 않으므로 이 섹션을 건너뛰고 아래에서 계속 진행해도 됩니다.
+
+이러한 세부 정보는 주로 FastAPI 0.106.0 이전 버전에서 `yield`가 있는 의존성의 리소스를 백그라운드 작업에서 사용했던 경우메 유용합니다.
+
+///
+
+### `yield`와 `except`를 사용하는 의존성, 기술 세부사항
+
+FastAPI 0.110.0 이전에는 `yield`가 포함된 의존성을 사용한 후 해당 의존성에서 `except`가 포함된 예외를 캡처하고 다시 예외를 발생시키지 않으면 예외가 자동으로 예외 핸들러 또는 내부 서버 오류 핸들러로 발생/전달되었습니다.
+
+이는 처리기 없이 전달된 예외(내부 서버 오류)에서 처리되지 않은 메모리 소비를 수정하고 일반 파이썬 코드의 동작과 일치하도록 하기 위해 0.110.0 버전에서 변경되었습니다.
+
+### 백그라운드 작업과 `yield`를 사용하는 의존성, 기술 세부사항
+
+FastAPI 0.106.0 이전에는 `yield` 이후에 예외를 발생시키는 것이 불가능했습니다. `yield`가 있는 의존성 종료 코드는 응답이 전송된 이후에 실행되었기 때문에, [예외 처리기](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}가 이미 실행된 상태였습니다.
+
+이는 주로 백그라운드 작업 내에서 의존성에서 "yield된" 동일한 객체를 사용할 수 있도록 하기 위해 이런 방식으로 설계되었습니다. 종료 코드는 백그라운드 작업이 완료된 후에 실행되었기 때문입니다
+
+하지만 이렇게 하면 리소스를 불필요하게 양보한 의존성(예: 데이터베이스 연결)에서 보유하면서 응답이 네트워크를 통해 이동할 때까지 기다리는 것을 의미하기 때문에 FastAPI 0.106.0에서 변경되었습니다.
+
+/// tip | 팁
+
+또한 백그라운드 작업은 일반적으로 자체 리소스(예: 자체 데이터베이스 연결)를 사용하여 별도로 처리해야 하는 독립적인 로직 집합입니다.
+
+따라서 이렇게 하면 코드가 더 깔끔해집니다.
+
+///
+
+만약 이전에 이러한 동작에 의존했다면, 이제는 백그라운드 작업 내부에서 백그라운드 작업을 위한 리소스를 생성하고, `yield`가 있는 의존성의 리소스에 의존하지 않는 데이터만 내부적으로 사용해야합니다.
+
+예를 들어, 동일한 데이터베이스 세션을 사용하는 대신, 백그라운드 작업 내부에서 새로운 데이터베이스 세션을 생성하고 이 새로운 세션을 사용하여 데이터베이스에서 객체를 가져와야 합니다. 그리고 데이터베이스 객체를 백그라운드 작업 함수의 매개변수로 직접 전달하는 대신, 해당 객체의 ID를 전달한 다음 백그라운드 작업 함수 내부에서 객체를 다시 가져와야 합니다
+
+## 컨텍스트 관리자
+
+### "컨텍스트 관리자"란?
+
+"컨텍스트 관리자"는 Python에서 `with` 문에서 사용할 수 있는 모든 객체를 의미합니다.
+
+예를 들어, `with`를 사용하여 파일을 읽을 수 있습니다:
+
+```Python
+with open("./somefile.txt") as f:
+ contents = f.read()
+ print(contents)
+```
+
+내부적으로 `open("./somefile.txt")` 는 "컨텍스트 관리자(Context Manager)"라고 불리는 객체를 생성합니다.
+
+`with` 블록이 끝나면, 예외가 발생했더라도 파일을 닫도록 보장합니다.
+
+`yield`가 있는 의존성을 생성하면 **FastAPI**는 내부적으로 이를 위한 컨텍스트 매니저를 생성하고 다른 관련 도구들과 결합합니다.
+
+### `yield`를 사용하는 의존성에서 컨텍스트 관리자 사용하기
+
+/// warning | 경고
+
+이것은 어느 정도 "고급" 개념입니다.
+
+**FastAPI**를 처음 시작하는 경우 지금은 이 부분을 건너뛰어도 좋습니다.
+
+///
+
+Python에서는 다음을 통해 컨텍스트 관리자를 생성할 수 있습니다. 두 가지 메서드가 있는 클래스를 생성합니다: `__enter__()` and `__exit__()`.
+
+**FastAPI**의 `yield`가 있는 의존성 내에서
+`with` 또는 `async with`문을 사용하여 이들을 활용할 수 있습니다:
+
+{* ../../docs_src/dependencies/tutorial010.py hl[1:9,13] *}
+
+/// tip | 팁
+
+컨텍스트 관리자를 생성하는 또 다른 방법은 다음과 같습니다:
+
+* `@contextlib.contextmanager` 또는
+* `@contextlib.asynccontextmanager`
+
+이들은 단일 `yield`가 있는 함수를 꾸미는 데 사용합니다.
+
+이것이 **FastAPI**가 `yield`가 있는 의존성을 위해 내부적으로 사용하는 방식입니다.
+
+하지만 FastAPI 의존성에는 이러한 데코레이터를 사용할 필요가 없습니다(그리고 사용해서도 안됩니다).
+
+FastAPI가 내부적으로 이를 처리해 줄 것입니다.
+
+///
diff --git a/docs/ko/docs/tutorial/dependencies/global-dependencies.md b/docs/ko/docs/tutorial/dependencies/global-dependencies.md
index 0ad8b55fd..0d0e7684d 100644
--- a/docs/ko/docs/tutorial/dependencies/global-dependencies.md
+++ b/docs/ko/docs/tutorial/dependencies/global-dependencies.md
@@ -6,35 +6,7 @@
그런 경우에, 애플리케이션의 모든 *경로 작동*에 적용될 것입니다:
-//// tab | Python 3.9+
-
-```Python hl_lines="16"
-{!> ../../docs_src/dependencies/tutorial012_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="16"
-{!> ../../docs_src/dependencies/tutorial012_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="15"
-{!> ../../docs_src/dependencies/tutorial012.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *}
그리고 [*경로 작동 데코레이터*에 `dependencies` 추가하기](dependencies-in-path-operation-decorators.md){.internal-link target=_blank}에 대한 아이디어는 여전히 적용되지만 여기에서는 앱에 있는 모든 *경로 작동*에 적용됩니다.
diff --git a/docs/ko/docs/tutorial/dependencies/index.md b/docs/ko/docs/tutorial/dependencies/index.md
index 1aba6e787..b35a41e37 100644
--- a/docs/ko/docs/tutorial/dependencies/index.md
+++ b/docs/ko/docs/tutorial/dependencies/index.md
@@ -31,57 +31,7 @@
*경로 작동 함수*가 가질 수 있는 모든 매개변수를 갖는 단순한 함수입니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="8-9"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="8-11"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9-12"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="6-7"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="8-11"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
이게 다입니다.
@@ -113,113 +63,13 @@ FastAPI는 0.95.0 버전부터 `Annotated`에 대한 지원을 (그리고 이를
### `Depends` 불러오기
-//// tab | Python 3.10+
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
### "의존자"에 의존성 명시하기
*경로 작동 함수*의 매개변수로 `Body`, `Query` 등을 사용하는 방식과 같이 새로운 매개변수로 `Depends`를 사용합니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="13 18"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="15 20"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="16 21"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="11 16"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ Annotated가 없는 경우
-
-/// tip | 팁
-
-가능하다면 `Annotated`가 달린 버전을 권장합니다.
-
-///
-
-```Python hl_lines="15 20"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
비록 `Body`, `Query` 등을 사용하는 것과 같은 방식으로 여러분의 함수의 매개변수에 있는 `Depends`를 사용하지만, `Depends`는 약간 다르게 작동합니다.
@@ -276,29 +126,7 @@ commons: Annotated[dict, Depends(common_parameters)]
하지만 `Annotated`를 사용하고 있기에, `Annotated` 값을 변수에 저장하고 여러 장소에서 사용할 수 있습니다:
-//// tab | Python 3.10+
-
-```Python hl_lines="12 16 21"
-{!> ../../docs_src/dependencies/tutorial001_02_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="14 18 23"
-{!> ../../docs_src/dependencies/tutorial001_02_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="15 19 24"
-{!> ../../docs_src/dependencies/tutorial001_02_an.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
/// tip | 팁
diff --git a/docs/ko/docs/tutorial/encoder.md b/docs/ko/docs/tutorial/encoder.md
index 52277f258..4323957f4 100644
--- a/docs/ko/docs/tutorial/encoder.md
+++ b/docs/ko/docs/tutorial/encoder.md
@@ -20,9 +20,7 @@ JSON 호환 가능 데이터만 수신하는 `fake_db` 데이터베이스가 존
Pydantic 모델과 같은 객체를 받고 JSON 호환 가능한 버전으로 반환합니다:
-```Python hl_lines="5 22"
-{!../../docs_src/encoder/tutorial001.py!}
-```
+{* ../../docs_src/encoder/tutorial001.py hl[5,22] *}
이 예시는 Pydantic 모델을 `dict`로, `datetime` 형식을 `str`로 변환합니다.
diff --git a/docs/ko/docs/tutorial/extra-data-types.md b/docs/ko/docs/tutorial/extra-data-types.md
index 8baaa64fc..4a41ba0dc 100644
--- a/docs/ko/docs/tutorial/extra-data-types.md
+++ b/docs/ko/docs/tutorial/extra-data-types.md
@@ -55,108 +55,8 @@
위의 몇몇 자료형을 매개변수로 사용하는 *경로 작동* 예시입니다.
-//// tab | Python 3.10+
-
-```Python hl_lines="1 3 12-16"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 3 12-16"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="1 3 13-17"
-{!> ../../docs_src/extra_data_types/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="1 2 11-15"
-{!> ../../docs_src/extra_data_types/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="1 2 12-16"
-{!> ../../docs_src/extra_data_types/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
함수 안의 매개변수가 그들만의 데이터 자료형을 가지고 있으며, 예를 들어, 다음과 같이 날짜를 조작할 수 있음을 참고하십시오:
-//// tab | Python 3.10+
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="19-20"
-{!> ../../docs_src/extra_data_types/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="17-18"
-{!> ../../docs_src/extra_data_types/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Prefer to use the `Annotated` version if possible.
-
-///
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/extra_data_types/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
diff --git a/docs/ko/docs/tutorial/extra-models.md b/docs/ko/docs/tutorial/extra-models.md
new file mode 100644
index 000000000..8e4559061
--- /dev/null
+++ b/docs/ko/docs/tutorial/extra-models.md
@@ -0,0 +1,223 @@
+# 추가 모델
+
+지난 예제에 이어서, 연관된 모델을 여러개 갖는 것은 흔한 일입니다.
+
+특히 사용자 모델의 경우에 그러한데, 왜냐하면:
+
+* **입력 모델** 은 비밀번호를 가져야 합니다.
+* **출력 모델** 은 비밀번호를 가지면 안됩니다.
+* **데이터베이스 모델** 은 해시처리된 비밀번호를 가질 것입니다.
+
+/// danger | 위험
+
+절대 사용자의 비밀번호를 평문으로 저장하지 마세요. 항상 이후에 검증 가능한 "안전한 해시(secure hash)"로 저장하세요.
+
+만약 이게 무엇인지 모르겠다면, [security chapters](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.에서 비밀번호 해시에 대해 배울 수 있습니다.
+
+///
+
+## 다중 모델
+
+아래는 비밀번호 필드와 해당 필드가 사용되는 위치를 포함하여, 각 모델들이 어떤 형태를 가질 수 있는지 전반적인 예시입니다:
+
+{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
+
+
+/// info | 정보
+
+Pydantic v1에서는 해당 메서드가 `.dict()`로 불렸으며, Pydantic v2에서는 `.model_dump()`로 이름이 변경되었습니다. `.dict()`는 여전히 지원되지만 더 이상 권장되지 않습니다.
+
+여기에서 사용하는 예제는 Pydantic v1과의 호환성을 위해 `.dict()`를 사용하지만, Pydantic v2를 사용할 수 있다면 `.model_dump()`를 사용하는 것이 좋습니다.
+
+///
+
+### `**user_in.dict()` 에 대하여
+
+#### Pydantic의 `.dict()`
+
+`user_in`은 Pydantic 모델 클래스인 `UserIn`입니다.
+
+Pydantic 모델은 모델 데이터를 포함한 `dict`를 반환하는 `.dict()` 메서드를 제공합니다.
+
+따라서, 다음과 같이 Pydantic 객체 `user_in`을 생성할 수 있습니다:
+
+```Python
+user_in = UserIn(username="john", password="secret", email="john.doe@example.com")
+```
+
+그 다음, 다음과 같이 호출합니다:
+
+```Python
+user_dict = user_in.dict()
+```
+
+이제 변수 `user_dict`에 데이터가 포함된 `dict`를 가지게 됩니다(이는 Pydantic 모델 객체가 아닌 `dict`입니다).
+
+그리고 다음과 같이 호출하면:
+
+```Python
+print(user_dict)
+```
+
+Python의 `dict`가 다음과 같이 출력됩니다:
+
+```Python
+{
+ 'username': 'john',
+ 'password': 'secret',
+ 'email': 'john.doe@example.com',
+ 'full_name': None,
+}
+```
+
+#### `dict` 언패킹(Unpacking)
+
+`user_dict`와 같은 `dict`를 함수(또는 클래스)에 `**user_dict`로 전달하면, Python은 이를 "언팩(unpack)"합니다. 이 과정에서 `user_dict`의 키와 값을 각각 키-값 인자로 직접 전달합니다.
+
+따라서, 위에서 생성한 `user_dict`를 사용하여 다음과 같이 작성하면:
+
+```Python
+UserInDB(**user_dict)
+```
+
+다음과 같은 결과를 생성합니다:
+
+```Python
+UserInDB(
+ username="john",
+ password="secret",
+ email="john.doe@example.com",
+ full_name=None,
+)
+```
+
+혹은 더 정확히 말하자면, `user_dict`를 직접 사용하는 것은, 나중에 어떤 값이 추가되더라도 아래와 동일한 효과를 냅니다:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+)
+```
+
+#### 다른 모델 데이터로 새 Pydantic 모델 생성
+
+위의 예제에서 `user_in.dict()`로부터 `user_dict`를 생성한 것처럼, 아래 코드는:
+
+```Python
+user_dict = user_in.dict()
+UserInDB(**user_dict)
+```
+
+다음과 동일합니다:
+
+```Python
+UserInDB(**user_in.dict())
+```
+
+...왜냐하면 `user_in.dict()`는 `dict`이며, 이를 `**`로 Python이 "언팩(unpack)"하도록 하여 `UserInDB`에 전달하기 때문입니다.
+
+따라서, 다른 Pydantic 모델의 데이터를 사용하여 새로운 Pydantic 모델을 생성할 수 있습니다.
+
+#### `dict` 언패킹(Unpacking)과 추가 키워드
+
+그리고 다음과 같이 추가 키워드 인자 `hashed_password=hashed_password`를 추가하면:
+
+```Python
+UserInDB(**user_in.dict(), hashed_password=hashed_password)
+```
+
+다음과 같은 결과를 생성합니다:
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ password = user_dict["password"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ hashed_password = hashed_password,
+)
+```
+
+/// warning | 경고
+
+추가적으로 제공된 함수 `fake_password_hasher`와 `fake_save_user`는 데이터 흐름을 시연하기 위한 예제일 뿐이며, 실제 보안을 제공하지 않습니다.
+
+///
+
+## 중복 줄이기
+
+코드 중복을 줄이는 것은 **FastAPI**의 핵심 아이디어 중 하나입니다.
+
+코드 중복은 버그, 보안 문제, 코드 비동기화 문제(한 곳은 업데이트되었지만 다른 곳은 업데이트되지 않는 문제) 등의 가능성을 증가시킵니다.
+
+그리고 이 모델들은 많은 데이터를 공유하면서 속성 이름과 타입을 중복하고 있습니다.
+
+더 나은 방법이 있습니다.
+
+`UserBase` 모델을 선언하여 다른 모델들의 기본(base)으로 사용할 수 있습니다. 그런 다음 이 모델을 상속받아 속성과 타입 선언(유형 선언, 검증 등)을 상속하는 서브클래스를 만들 수 있습니다.
+
+모든 데이터 변환, 검증, 문서화 등은 정상적으로 작동할 것입니다.
+
+이렇게 하면 각 모델 간의 차이점만 선언할 수 있습니다(평문 `password`가 있는 경우, `hashed_password`만 있는 경우, 혹은 비밀번호가 없는 경우):
+
+{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
+
+## `Union` 또는 `anyOf`
+
+두 가지 이상의 타입을 포함하는 `Union`으로 응답을 선언할 수 있습니다. 이는 응답이 그 중 하나의 타입일 수 있음을 의미합니다.
+
+OpenAPI에서는 이를 `anyOf`로 정의합니다.
+
+이를 위해 표준 Python 타입 힌트인 `typing.Union`을 사용할 수 있습니다:
+
+/// note | 참고
+
+`Union`을 정의할때는 더 구체적인 타입을 먼저 포함하고, 덜 구체적인 타입을 그 뒤에 나열해야합니다. 아래 예제에서는 `Union[PlaneItem, CarItem]` 를 보면, 더 구체적인 `PlaneItem`이 `CarItem`보다 앞에 위치합니다.
+
+///
+
+{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
+
+
+### Python 3.10에서 `Union`
+
+위의 예제에서는 `response_model` 인자 값으로 `Union[PlaneItem, CarItem]`을 전달합니다.
+
+이 경우, 이를 **타입 어노테이션(type annotation)** 이 아닌 **인자 값(argument value)** 으로 전달하고 있기 때문에 Python 3.10에서도 `Union`을 사용해야 합니다.
+
+만약 타입 어노테이션에 사용한다면, 다음과 같이 수직 막대(|)를 사용할 수 있습니다:
+
+```Python
+some_variable: PlaneItem | CarItem
+```
+
+하지만 이를 `response_model=PlaneItem | CarItem`과 같이 할당하면 에러가 발생합니다. 이는 Python이 이를 타입 어노테이션으로 해석하지 않고, `PlaneItem`과 `CarItem` 사이의 **잘못된 연산(invalid operation)**을 시도하기 때문입니다
+
+## 모델 리스트
+
+마찬가지로, 객체 리스트 형태의 응답을 선언할 수도 있습니다.
+
+이를 위해 표준 Python의 `typing.List`를 사용하세요(또는 Python 3.9 이상에서는 단순히 `list`를 사용할 수 있습니다):
+
+{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
+
+
+## 임의의 `dict` 응답
+
+Pydantic 모델을 사용하지 않고, 키와 값의 타입만 선언하여 평범한 임의의 `dict`로 응답을 선언할 수도 있습니다.
+
+이는 Pydantic 모델에 필요한 유효한 필드/속성 이름을 사전에 알 수 없는 경우에 유용합니다.
+
+이 경우, `typing.Dict`를 사용할 수 있습니다(또는 Python 3.9 이상에서는 단순히 `dict`를 사용할 수 있습니다):
+
+{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
+
+
+## 요약
+
+여러 Pydantic 모델을 사용하고, 각 경우에 맞게 자유롭게 상속하세요.
+
+엔터티가 서로 다른 "상태"를 가져야 하는 경우, 엔터티당 단일 데이터 모델을 사용할 필요는 없습니다. 예를 들어, 사용자 "엔터티"가 `password`, `password_hash`, 또는 비밀번호가 없는 상태를 포함할 수 있는 경우처럼 말입니다.
diff --git a/docs/ko/docs/tutorial/first-steps.md b/docs/ko/docs/tutorial/first-steps.md
index 4a689b74a..174f00d46 100644
--- a/docs/ko/docs/tutorial/first-steps.md
+++ b/docs/ko/docs/tutorial/first-steps.md
@@ -2,9 +2,7 @@
가장 단순한 FastAPI 파일은 다음과 같이 보일 것입니다:
-```Python
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py *}
위 코드를 `main.py`에 복사합니다.
@@ -133,9 +131,7 @@ API와 통신하는 클라이언트(프론트엔드, 모바일, IoT 애플리케
### 1 단계: `FastAPI` 임포트
-```Python hl_lines="1"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
`FastAPI`는 당신의 API를 위한 모든 기능을 제공하는 파이썬 클래스입니다.
@@ -149,9 +145,7 @@ API와 통신하는 클라이언트(프론트엔드, 모바일, IoT 애플리케
### 2 단계: `FastAPI` "인스턴스" 생성
-```Python hl_lines="3"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
여기에서 `app` 변수는 `FastAPI` 클래스의 "인스턴스"가 됩니다.
@@ -171,9 +165,7 @@ $ uvicorn main:app --reload
아래처럼 앱을 만든다면:
-```Python hl_lines="3"
-{!../../docs_src/first_steps/tutorial002.py!}
-```
+{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
이를 `main.py` 파일에 넣고, `uvicorn`을 아래처럼 호출해야 합니다:
@@ -250,9 +242,7 @@ API를 설계할 때 일반적으로 특정 행동을 수행하기 위해 특정
#### *경로 작동 데코레이터* 정의
-```Python hl_lines="6"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
`@app.get("/")`은 **FastAPI**에게 바로 아래에 있는 함수가 다음으로 이동하는 요청을 처리한다는 것을 알려줍니다.
@@ -306,9 +296,7 @@ API를 설계할 때 일반적으로 특정 행동을 수행하기 위해 특정
* **작동**: 은 `get`입니다.
* **함수**: 는 "데코레이터" 아래에 있는 함수입니다 (`@app.get("/")` 아래).
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
이것은 파이썬 함수입니다.
@@ -320,9 +308,7 @@ URL "`/`"에 대한 `GET` 작동을 사용하는 요청을 받을 때마다 **Fa
`async def`을 이용하는 대신 일반 함수로 정의할 수 있습니다:
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial003.py!}
-```
+{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note | 참고
@@ -332,9 +318,7 @@ URL "`/`"에 대한 `GET` 작동을 사용하는 요청을 받을 때마다 **Fa
### 5 단계: 콘텐츠 반환
-```Python hl_lines="8"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
`dict`, `list`, 단일값을 가진 `str`, `int` 등을 반환할 수 있습니다.
diff --git a/docs/ko/docs/tutorial/header-param-models.md b/docs/ko/docs/tutorial/header-param-models.md
new file mode 100644
index 000000000..bab7291e3
--- /dev/null
+++ b/docs/ko/docs/tutorial/header-param-models.md
@@ -0,0 +1,56 @@
+# 헤더 매개변수 모델
+
+관련 있는 **헤더 매개변수** 그룹이 있는 경우, **Pydantic 모델**을 생성하여 선언할 수 있습니다.
+
+이를 통해 **여러 위치**에서 **모델을 재사용** 할 수 있고 모든 매개변수에 대한 유효성 검사 및 메타데이터를 한 번에 선언할 수도 있습니다. 😎
+
+/// note | 참고
+
+이 기능은 FastAPI 버전 `0.115.0` 이후부터 지원됩니다. 🤓
+
+///
+
+## Pydantic 모델을 사용한 헤더 매개변수
+
+**Pydantic 모델**에 필요한 **헤더 매개변수**를 선언한 다음, 해당 매개변수를 `Header`로 선언합니다:
+
+{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
+
+**FastAPI**는 요청에서 받은 **헤더**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.
+
+## 문서 확인하기
+
+문서 UI `/docs`에서 필요한 헤더를 볼 수 있습니다:
+
+
+
+
+
+## 추가 헤더 금지하기
+
+일부 특별한 사용 사례(흔하지는 않겠지만)에서는 수신하려는 헤더를 **제한**할 수 있습니다.
+
+Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다:
+
+{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}
+
+클라이언트가 **추가 헤더**를 보내려고 시도하면, **오류** 응답을 받게 됩니다.
+
+예를 들어, 클라이언트가 `plumbus` 값으로 `tool` 헤더를 보내려고 하면, 클라이언트는 헤더 매개변수 `tool`이 허용 되지 않는다는 **오류** 응답을 받게 됩니다:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["header", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus",
+ }
+ ]
+}
+```
+
+## 요약
+
+**Pydantic 모델**을 사용하여 **FastAPI**에서 **헤더**를 선언할 수 있습니다. 😎
diff --git a/docs/ko/docs/tutorial/header-params.md b/docs/ko/docs/tutorial/header-params.md
index 972f52a33..7379eb2a0 100644
--- a/docs/ko/docs/tutorial/header-params.md
+++ b/docs/ko/docs/tutorial/header-params.md
@@ -6,9 +6,7 @@
먼저 `Header`를 임포트합니다:
-```Python hl_lines="3"
-{!../../docs_src/header_params/tutorial001.py!}
-```
+{* ../../docs_src/header_params/tutorial001.py hl[3] *}
## `Header` 매개변수 선언
@@ -16,9 +14,7 @@
첫 번째 값은 기본값이며, 추가 검증이나 어노테이션 매개변수 모두 전달할 수 있습니다:
-```Python hl_lines="9"
-{!../../docs_src/header_params/tutorial001.py!}
-```
+{* ../../docs_src/header_params/tutorial001.py hl[9] *}
/// note | 기술 세부사항
@@ -50,9 +46,7 @@
만약 언더스코어를 하이픈으로 자동 변환을 비활성화해야 할 어떤 이유가 있다면, `Header`의 `convert_underscores` 매개변수를 `False`로 설정하십시오:
-```Python hl_lines="10"
-{!../../docs_src/header_params/tutorial002.py!}
-```
+{* ../../docs_src/header_params/tutorial002.py hl[10] *}
/// warning | 경고
@@ -70,9 +64,7 @@
예를 들어, 두 번 이상 나타날 수 있는 `X-Token`헤더를 선언하려면, 다음과 같이 작성합니다:
-```Python hl_lines="9"
-{!../../docs_src/header_params/tutorial003.py!}
-```
+{* ../../docs_src/header_params/tutorial003.py hl[9] *}
다음과 같은 두 개의 HTTP 헤더를 전송하여 해당 *경로* 와 통신할 경우:
diff --git a/docs/ko/docs/tutorial/metadata.md b/docs/ko/docs/tutorial/metadata.md
index 87531152c..a50dfa2e7 100644
--- a/docs/ko/docs/tutorial/metadata.md
+++ b/docs/ko/docs/tutorial/metadata.md
@@ -1,4 +1,3 @@
-
# 메타데이터 및 문서화 URL
**FastAPI** 응용 프로그램에서 다양한 메타데이터 구성을 사용자 맞춤 설정할 수 있습니다.
@@ -19,9 +18,7 @@ OpenAPI 명세 및 자동화된 API 문서 UI에 사용되는 다음 필드를
다음과 같이 설정할 수 있습니다:
-```Python hl_lines="3-16 19-32"
-{!../../docs_src/metadata/tutorial001.py!}
-```
+{* ../../docs_src/metadata/tutorial001.py hl[3:16,19:32] *}
/// tip
@@ -39,9 +36,7 @@ OpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info`에 `identifier`를 URL 대
예:
-```Python hl_lines="31"
-{!../../docs_src/metadata/tutorial001_1.py!}
-```
+{* ../../docs_src/metadata/tutorial001_1.py hl[31] *}
## 태그에 대한 메타데이터
@@ -61,9 +56,7 @@ OpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info`에 `identifier`를 URL 대
`users` 및 `items`에 대한 태그 예시와 함께 메타데이터를 생성하고 이를 `openapi_tags` 매개변수로 전달해 보겠습니다:
-```Python hl_lines="3-16 18"
-{!../../docs_src/metadata/tutorial004.py!}
-```
+{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *}
설명 안에 마크다운을 사용할 수 있습니다. 예를 들어 "login"은 굵게(**login**) 표시되고, "fancy"는 기울임꼴(_fancy_)로 표시됩니다.
@@ -77,9 +70,7 @@ OpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info`에 `identifier`를 URL 대
`tags` 매개변수를 *경로 작동* 및 `APIRouter`와 함께 사용하여 태그에 할당할 수 있습니다:
-```Python hl_lines="21 26"
-{!../../docs_src/metadata/tutorial004.py!}
-```
+{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
/// info
@@ -107,9 +98,7 @@ OpenAPI 구조는 기본적으로 `/openapi.json`에서 제공됩니다.
예를 들어, 이를 `/api/v1/openapi.json`에 제공하도록 설정하려면:
-```Python hl_lines="3"
-{!../../docs_src/metadata/tutorial002.py!}
-```
+{* ../../docs_src/metadata/tutorial002.py hl[3] *}
OpenAPI 구조를 완전히 비활성화하려면 `openapi_url=None`으로 설정할 수 있으며, 이를 사용하여 문서화 사용자 인터페이스도 비활성화됩니다.
@@ -126,6 +115,4 @@ OpenAPI 구조를 완전히 비활성화하려면 `openapi_url=None`으로 설
예를 들어, Swagger UI를 `/documentation`에서 제공하고 ReDoc을 비활성화하려면:
-```Python hl_lines="3"
-{!../../docs_src/metadata/tutorial003.py!}
-```
+{* ../../docs_src/metadata/tutorial003.py hl[3] *}
diff --git a/docs/ko/docs/tutorial/middleware.md b/docs/ko/docs/tutorial/middleware.md
index 0547066f1..3cd752a0e 100644
--- a/docs/ko/docs/tutorial/middleware.md
+++ b/docs/ko/docs/tutorial/middleware.md
@@ -31,9 +31,7 @@
* 그런 다음, *경로 작업*에 의해 생성된 `response` 를 반환합니다.
* `response`를 반환하기 전에 추가로 `response`를 수정할 수 있습니다.
-```Python hl_lines="8-9 11 14"
-{!../../docs_src/middleware/tutorial001.py!}
-```
+{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
/// tip | 팁
@@ -59,9 +57,7 @@
예를 들어, 요청을 수행하고 응답을 생성하는데 까지 걸린 시간 값을 가지고 있는 `X-Process-Time` 같은 사용자 정의 헤더를 추가할 수 있습니다.
-```Python hl_lines="10 12-13"
-{!../../docs_src/middleware/tutorial001.py!}
-```
+{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
## 다른 미들웨어
diff --git a/docs/ko/docs/tutorial/path-operation-configuration.md b/docs/ko/docs/tutorial/path-operation-configuration.md
index 75a9c71ce..81914182a 100644
--- a/docs/ko/docs/tutorial/path-operation-configuration.md
+++ b/docs/ko/docs/tutorial/path-operation-configuration.md
@@ -16,9 +16,7 @@
하지만 각 코드의 의미를 모른다면, `status`에 있는 단축 상수들을 사용할수 있습니다:
-```Python hl_lines="3 17"
-{!../../docs_src/path_operation_configuration/tutorial001.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial001.py hl[3,17] *}
각 상태 코드들은 응답에 사용되며, OpenAPI 스키마에 추가됩니다.
@@ -34,9 +32,7 @@
(보통 단일 `str`인) `str`로 구성된 `list`와 함께 매개변수 `tags`를 전달하여, `경로 작동`에 태그를 추가할 수 있습니다:
-```Python hl_lines="17 22 27"
-{!../../docs_src/path_operation_configuration/tutorial002.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial002.py hl[17,22,27] *}
전달된 태그들은 OpenAPI의 스키마에 추가되며, 자동 문서 인터페이스에서 사용됩니다:
@@ -46,9 +42,7 @@
`summary`와 `description`을 추가할 수 있습니다:
-```Python hl_lines="20-21"
-{!../../docs_src/path_operation_configuration/tutorial003.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial003.py hl[20:21] *}
## 독스트링으로 만든 기술
@@ -56,9 +50,7 @@
마크다운 문법으로 독스트링을 작성할 수 있습니다, 작성된 마크다운 형식의 독스트링은 (마크다운의 들여쓰기를 고려하여) 올바르게 화면에 출력됩니다.
-```Python hl_lines="19-27"
-{!../../docs_src/path_operation_configuration/tutorial004.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial004.py hl[19:27] *}
이는 대화형 문서에서 사용됩니다:
@@ -68,9 +60,7 @@
`response_description` 매개변수로 응답에 관한 설명을 명시할 수 있습니다:
-```Python hl_lines="21"
-{!../../docs_src/path_operation_configuration/tutorial005.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial005.py hl[21] *}
/// info | 정보
@@ -92,9 +82,7 @@ OpenAPI는 각 *경로 작동*이 응답에 관한 설명을 요구할 것을
단일 *경로 작동*을 없애지 않고 지원중단을 해야한다면, `deprecated` 매개변수를 전달하면 됩니다.
-```Python hl_lines="16"
-{!../../docs_src/path_operation_configuration/tutorial006.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *}
대화형 문서에 지원중단이라고 표시됩니다.
diff --git a/docs/ko/docs/tutorial/path-params-numeric-validations.md b/docs/ko/docs/tutorial/path-params-numeric-validations.md
index 736f2dc1d..f21c9290e 100644
--- a/docs/ko/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/ko/docs/tutorial/path-params-numeric-validations.md
@@ -6,9 +6,7 @@
먼저 `fastapi`에서 `Path`를 임포트합니다:
-```Python hl_lines="3"
-{!../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial001.py hl[3] *}
## 메타데이터 선언
@@ -16,9 +14,7 @@
예를 들어, `title` 메타데이터 값을 경로 매개변수 `item_id`에 선언하려면 다음과 같이 입력할 수 있습니다:
-```Python hl_lines="10"
-{!../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial001.py hl[10] *}
/// note | 참고
@@ -46,9 +42,7 @@
따라서 함수를 다음과 같이 선언 할 수 있습니다:
-```Python hl_lines="7"
-{!../../docs_src/path_params_numeric_validations/tutorial002.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
## 필요한 경우 매개변수 정렬하기, 트릭
@@ -58,9 +52,7 @@
파이썬은 `*`으로 아무런 행동도 하지 않지만, 따르는 매개변수들은 kwargs로도 알려진 키워드 인자(키-값 쌍)여야 함을 인지합니다. 기본값을 가지고 있지 않더라도 그렇습니다.
-```Python hl_lines="7"
-{!../../docs_src/path_params_numeric_validations/tutorial003.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
## 숫자 검증: 크거나 같음
@@ -68,9 +60,7 @@
여기서 `ge=1`인 경우, `item_id`는 `1`보다 "크거나(`g`reater) 같은(`e`qual)" 정수형 숫자여야 합니다.
-```Python hl_lines="8"
-{!../../docs_src/path_params_numeric_validations/tutorial004.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial004.py hl[8] *}
## 숫자 검증: 크거나 같음 및 작거나 같음
@@ -79,9 +69,7 @@
* `gt`: 크거나(`g`reater `t`han)
* `le`: 작거나 같은(`l`ess than or `e`qual)
-```Python hl_lines="9"
-{!../../docs_src/path_params_numeric_validations/tutorial005.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial005.py hl[9] *}
## 숫자 검증: 부동소수, 크거나 및 작거나
@@ -93,9 +81,7 @@
lt 역시 마찬가지입니다.
-```Python hl_lines="11"
-{!../../docs_src/path_params_numeric_validations/tutorial006.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial006.py hl[11] *}
## 요약
diff --git a/docs/ko/docs/tutorial/path-params.md b/docs/ko/docs/tutorial/path-params.md
index 21808e2ca..b72787e0b 100644
--- a/docs/ko/docs/tutorial/path-params.md
+++ b/docs/ko/docs/tutorial/path-params.md
@@ -2,9 +2,7 @@
파이썬의 포맷 문자열 리터럴에서 사용되는 문법을 이용하여 경로 "매개변수" 또는 "변수"를 선언할 수 있습니다:
-```Python hl_lines="6-7"
-{!../../docs_src/path_params/tutorial001.py!}
-```
+{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
경로 매개변수 `item_id`의 값은 함수의 `item_id` 인자로 전달됩니다.
@@ -18,9 +16,7 @@
파이썬 표준 타입 어노테이션을 사용하여 함수에 있는 경로 매개변수의 타입을 선언할 수 있습니다:
-```Python hl_lines="7"
-{!../../docs_src/path_params/tutorial002.py!}
-```
+{* ../../docs_src/path_params/tutorial002.py hl[7] *}
위의 예시에서, `item_id`는 `int`로 선언되었습니다.
@@ -121,9 +117,7 @@
*경로 작동*은 순차적으로 실행되기 때문에 `/users/{user_id}` 이전에 `/users/me`를 먼저 선언해야 합니다:
-```Python hl_lines="6 11"
-{!../../docs_src/path_params/tutorial003.py!}
-```
+{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
그렇지 않으면 `/users/{user_id}`는 `/users/me` 요청 또한 매개변수 `user_id`의 값이 `"me"`인 것으로 "생각하게" 됩니다.
@@ -139,9 +133,7 @@
가능한 값들에 해당하는 고정된 값의 클래스 어트리뷰트들을 만듭니다:
-```Python hl_lines="1 6-9"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
/// info | 정보
@@ -159,9 +151,7 @@
생성한 열거형 클래스(`ModelName`)를 사용하는 타입 어노테이션으로 *경로 매개변수*를 만듭니다:
-```Python hl_lines="16"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[16] *}
### 문서 확인
@@ -177,17 +167,13 @@
열거형 `ModelName`의 *열거형 멤버*를 비교할 수 있습니다:
-```Python hl_lines="17"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[17] *}
#### *열거형 값* 가져오기
`model_name.value` 또는 일반적으로 `your_enum_member.value`를 이용하여 실제 값(위 예시의 경우 `str`)을 가져올 수 있습니다:
-```Python hl_lines="20"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[20] *}
/// tip | 팁
@@ -201,9 +187,7 @@
클라이언트에 반환하기 전에 해당 값(이 경우 문자열)으로 변환됩니다:
-```Python hl_lines="18 21 23"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
클라이언트는 아래의 JSON 응답을 얻습니다:
@@ -242,9 +226,7 @@ Starlette의 옵션을 직접 이용하여 다음과 같은 URL을 사용함으
따라서 다음과 같이 사용할 수 있습니다:
-```Python hl_lines="6"
-{!../../docs_src/path_params/tutorial004.py!}
-```
+{* ../../docs_src/path_params/tutorial004.py hl[6] *}
/// tip | 팁
diff --git a/docs/ko/docs/tutorial/query-param-models.md b/docs/ko/docs/tutorial/query-param-models.md
new file mode 100644
index 000000000..2ca65a331
--- /dev/null
+++ b/docs/ko/docs/tutorial/query-param-models.md
@@ -0,0 +1,68 @@
+# 쿼리 매개변수 모델
+
+연관된 쿼리 **매개변수** 그룹이 있다면 **Pydantic 모델** 을 사용해 선언할 수 있습니다.
+
+이렇게 하면 **여러 곳**에서 **모델을 재사용**할 수 있을 뿐만 아니라, 매개변수에 대한 검증 및 메타데이터도 한 번에 선언할 수 있습니다. 😎
+
+/// note | 참고
+
+이 기능은 FastAPI 버전 `0.115.0`부터 제공됩니다. 🤓
+
+///
+
+## 쿼리 매개변수와 Pydantic 모델
+
+필요한 **쿼리 매개변수**를 **Pydantic 모델** 안에 선언한 다음, 모델을 `Query`로 선언합니다.
+
+{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
+
+**FastAPI**는 요청의 **쿼리 매개변수**에서 **각 필드**의 데이터를 **추출**해 정의한 Pydantic 모델로 제공합니다.
+
+## 문서 확인하기
+
+`/docs` 경로의 API 문서에서 매개변수를 확인할 수 있습니다.
+
+
+
+
+
+## 추가 쿼리 매개변수 금지
+
+몇몇의 특이한 경우에 (흔치 않지만), 허용할 쿼리 매개변수를 **제한**해야할 수 있습니다.
+
+Pydantic 모델 설정에서 `extra` 필드를 `forbid` 로 설정할 수 있습니다.
+
+{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
+
+만약 클라이언트가 쿼리 매개변수로 **추가적인** 데이터를 보내려고 하면, 클라이언트는 **에러** 응답을 받게 됩니다.
+
+예를 들어, 아래와 같이 만약 클라이언트가 `tool` 쿼리 매개변수에 `plumbus` 라는 값을 추가해서 보내려고 하면,
+
+```http
+https://example.com/items/?limit=10&tool=plumbus
+```
+
+클라이언트는 쿼리 매개변수 `tool` 이 허용되지 않는다는 **에러** 응답을 받게 됩니다.
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["query", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus"
+ }
+ ]
+}
+```
+
+## 요약
+
+**FastAPI** 에서 **쿼리 매개변수** 를 선언할 때 **Pydantic 모델** 을 사용할 수 있습니다. 😎
+
+/// tip | 팁
+
+스포일러 경고: Pydantic 모델을 쿠키와 헤더에도 적용할 수 있습니다. 이에 대해서는 이후 튜토리얼에서 다룰 예정입니다. 🤫
+
+///
diff --git a/docs/ko/docs/tutorial/query-params-str-validations.md b/docs/ko/docs/tutorial/query-params-str-validations.md
index 71f884e83..f2ca453ac 100644
--- a/docs/ko/docs/tutorial/query-params-str-validations.md
+++ b/docs/ko/docs/tutorial/query-params-str-validations.md
@@ -4,9 +4,7 @@
이 응용 프로그램을 예로 들어보겠습니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params_str_validations/tutorial001.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial001.py hl[9] *}
쿼리 매개변수 `q`는 `Optional[str]` 자료형입니다. 즉, `str` 자료형이지만 `None` 역시 될 수 있음을 뜻하고, 실제로 기본값은 `None`이기 때문에 FastAPI는 이 매개변수가 필수가 아니라는 것을 압니다.
@@ -26,17 +24,13 @@ FastAPI는 `q`의 기본값이 `= None`이기 때문에 필수가 아님을 압
이를 위해 먼저 `fastapi`에서 `Query`를 임포트합니다:
-```Python hl_lines="3"
-{!../../docs_src/query_params_str_validations/tutorial002.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial002.py hl[3] *}
## 기본값으로 `Query` 사용
이제 `Query`를 매개변수의 기본값으로 사용하여 `max_length` 매개변수를 50으로 설정합니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params_str_validations/tutorial002.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial002.py hl[9] *}
기본값 `None`을 `Query(None)`으로 바꿔야 하므로, `Query`의 첫 번째 매개변수는 기본값을 정의하는 것과 같은 목적으로 사용됩니다.
@@ -86,17 +80,13 @@ q: str = Query(None, max_length=50)
매개변수 `min_length` 또한 추가할 수 있습니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params_str_validations/tutorial003.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial003.py hl[9] *}
## 정규식 추가
매개변수와 일치해야 하는 정규표현식을 정의할 수 있습니다:
-```Python hl_lines="10"
-{!../../docs_src/query_params_str_validations/tutorial004.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial004.py hl[10] *}
이 특정 정규표현식은 전달 받은 매개변수 값을 검사합니다:
@@ -114,9 +104,7 @@ q: str = Query(None, max_length=50)
`min_length`가 `3`이고, 기본값이 `"fixedquery"`인 쿼리 매개변수 `q`를 선언해봅시다:
-```Python hl_lines="7"
-{!../../docs_src/query_params_str_validations/tutorial005.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial005.py hl[7] *}
/// note | 참고
@@ -146,9 +134,7 @@ q: Optional[str] = Query(None, min_length=3)
그래서 `Query`를 필수값으로 만들어야 할 때면, 첫 번째 인자로 `...`를 사용할 수 있습니다:
-```Python hl_lines="7"
-{!../../docs_src/query_params_str_validations/tutorial006.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial006.py hl[7] *}
/// info | 정보
@@ -164,9 +150,7 @@ q: Optional[str] = Query(None, min_length=3)
예를 들어, URL에서 여러번 나오는 `q` 쿼리 매개변수를 선언하려면 다음과 같이 작성할 수 있습니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params_str_validations/tutorial011.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial011.py hl[9] *}
아래와 같은 URL을 사용합니다:
@@ -201,9 +185,7 @@ http://localhost:8000/items/?q=foo&q=bar
그리고 제공된 값이 없으면 기본 `list` 값을 정의할 수도 있습니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params_str_validations/tutorial012.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial012.py hl[9] *}
아래로 이동한다면:
@@ -226,9 +208,7 @@ http://localhost:8000/items/
`List[str]` 대신 `list`를 직접 사용할 수도 있습니다:
-```Python hl_lines="7"
-{!../../docs_src/query_params_str_validations/tutorial013.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial013.py hl[7] *}
/// note | 참고
@@ -254,15 +234,11 @@ http://localhost:8000/items/
`title`을 추가할 수 있습니다:
-```Python hl_lines="10"
-{!../../docs_src/query_params_str_validations/tutorial007.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial007.py hl[10] *}
그리고 `description`도 추가할 수 있습니다:
-```Python hl_lines="13"
-{!../../docs_src/query_params_str_validations/tutorial008.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial008.py hl[13] *}
## 별칭 매개변수
@@ -282,9 +258,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
이럴 경우 `alias`를 선언할 수 있으며, 해당 별칭은 매개변수 값을 찾는 데 사용됩니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params_str_validations/tutorial009.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial009.py hl[9] *}
## 매개변수 사용하지 않게 하기
@@ -294,9 +268,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
그렇다면 `deprecated=True` 매개변수를 `Query`로 전달합니다:
-```Python hl_lines="18"
-{!../../docs_src/query_params_str_validations/tutorial010.py!}
-```
+{* ../../docs_src/query_params_str_validations/tutorial010.py hl[18] *}
문서가 아래와 같이 보일겁니다:
diff --git a/docs/ko/docs/tutorial/query-params.md b/docs/ko/docs/tutorial/query-params.md
index 7fa3e8c53..d5b9837c4 100644
--- a/docs/ko/docs/tutorial/query-params.md
+++ b/docs/ko/docs/tutorial/query-params.md
@@ -2,9 +2,7 @@
경로 매개변수의 일부가 아닌 다른 함수 매개변수를 선언하면 "쿼리" 매개변수로 자동 해석합니다.
-```Python hl_lines="9"
-{!../../docs_src/query_params/tutorial001.py!}
-```
+{* ../../docs_src/query_params/tutorial001.py hl[9] *}
쿼리는 URL에서 `?` 후에 나오고 `&`으로 구분되는 키-값 쌍의 집합입니다.
@@ -63,9 +61,7 @@ http://127.0.0.1:8000/items/?skip=20
같은 방법으로 기본값을 `None`으로 설정하여 선택적 매개변수를 선언할 수 있습니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params/tutorial002.py!}
-```
+{* ../../docs_src/query_params/tutorial002.py hl[9] *}
이 경우 함수 매개변수 `q`는 선택적이며 기본값으로 `None` 값이 됩니다.
@@ -87,9 +83,7 @@ FastAPI는 `q`가 `= None`이므로 선택적이라는 것을 인지합니다.
`bool` 형으로 선언할 수도 있고, 아래처럼 변환됩니다:
-```Python hl_lines="9"
-{!../../docs_src/query_params/tutorial003.py!}
-```
+{* ../../docs_src/query_params/tutorial003.py hl[9] *}
이 경우, 아래로 이동하면:
@@ -132,9 +126,7 @@ http://127.0.0.1:8000/items/foo?short=yes
매개변수들은 이름으로 감지됩니다:
-```Python hl_lines="8 10"
-{!../../docs_src/query_params/tutorial004.py!}
-```
+{* ../../docs_src/query_params/tutorial004.py hl[8,10] *}
## 필수 쿼리 매개변수
@@ -144,9 +136,7 @@ http://127.0.0.1:8000/items/foo?short=yes
그러나 쿼리 매개변수를 필수로 만들려면 단순히 기본값을 선언하지 않으면 됩니다:
-```Python hl_lines="6-7"
-{!../../docs_src/query_params/tutorial005.py!}
-```
+{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
여기 쿼리 매개변수 `needy`는 `str`형인 필수 쿼리 매개변수입니다.
@@ -190,9 +180,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
그리고 물론, 일부 매개변수는 필수로, 다른 일부는 기본값을, 또 다른 일부는 선택적으로 선언할 수 있습니다:
-```Python hl_lines="10"
-{!../../docs_src/query_params/tutorial006.py!}
-```
+{* ../../docs_src/query_params/tutorial006.py hl[10] *}
위 예시에서는 3가지 쿼리 매개변수가 있습니다:
diff --git a/docs/ko/docs/tutorial/request-files.md b/docs/ko/docs/tutorial/request-files.md
index ca0f43978..9162b353c 100644
--- a/docs/ko/docs/tutorial/request-files.md
+++ b/docs/ko/docs/tutorial/request-files.md
@@ -16,17 +16,13 @@
`fastapi` 에서 `File` 과 `UploadFile` 을 임포트 합니다:
-```Python hl_lines="1"
-{!../../docs_src/request_files/tutorial001.py!}
-```
+{* ../../docs_src/request_files/tutorial001.py hl[1] *}
## `File` 매개변수 정의
`Body` 및 `Form` 과 동일한 방식으로 파일의 매개변수를 생성합니다:
-```Python hl_lines="7"
-{!../../docs_src/request_files/tutorial001.py!}
-```
+{* ../../docs_src/request_files/tutorial001.py hl[7] *}
/// info | 정보
@@ -54,9 +50,7 @@ File의 본문을 선언할 때, 매개변수가 쿼리 매개변수 또는 본
`File` 매개변수를 `UploadFile` 타입으로 정의합니다:
-```Python hl_lines="12"
-{!../../docs_src/request_files/tutorial001.py!}
-```
+{* ../../docs_src/request_files/tutorial001.py hl[12] *}
`UploadFile` 을 사용하는 것은 `bytes` 과 비교해 다음과 같은 장점이 있습니다:
@@ -142,9 +136,7 @@ HTML의 폼들(``)이 서버에 데이터를 전송하는 방식은
이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다:
-```Python hl_lines="10 15"
-{!../../docs_src/request_files/tutorial002.py!}
-```
+{* ../../docs_src/request_files/tutorial002.py hl[10,15] *}
선언한대로, `bytes` 의 `list` 또는 `UploadFile` 들을 전송받을 것입니다.
diff --git a/docs/ko/docs/tutorial/request-form-models.md b/docs/ko/docs/tutorial/request-form-models.md
new file mode 100644
index 000000000..3316a93d5
--- /dev/null
+++ b/docs/ko/docs/tutorial/request-form-models.md
@@ -0,0 +1,78 @@
+# 폼 모델
+
+FastAPI에서 **Pydantic 모델**을 이용하여 **폼 필드**를 선언할 수 있습니다.
+
+/// info | 정보
+
+폼(Form)을 사용하려면, 먼저 `python-multipart`를 설치하세요.
+
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, 아래와 같이 설치할 수 있습니다:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+/// note | 참고
+
+이 기능은 FastAPI 버전 `0.113.0` 이후부터 지원됩니다. 🤓
+
+///
+
+## Pydantic 모델을 사용한 폼
+
+**폼 필드**로 받고 싶은 필드를 **Pydantic 모델**로 선언한 다음, 매개변수를 `Form`으로 선언하면 됩니다:
+
+{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+
+**FastAPI**는 요청에서 받은 **폼 데이터**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.
+
+## 문서 확인하기
+
+문서 UI `/docs`에서 확인할 수 있습니다:
+
+
+
+
+
+## 추가 폼 필드 금지하기
+
+일부 특별한 사용 사례(흔하지는 않겠지만)에서는 Pydantic 모델에서 정의한 폼 필드를 **제한**하길 원할 수도 있습니다. 그리고 **추가** 필드를 **금지**할 수도 있습니다.
+
+/// note | 참고
+
+이 기능은 FastAPI 버전 `0.114.0` 이후부터 지원됩니다. 🤓
+
+///
+
+Pydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다:
+
+{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+
+클라이언트가 추가 데이터를 보내려고 하면 **오류** 응답을 받게 됩니다.
+
+예를 들어, 클라이언트가 폼 필드를 보내려고 하면:
+
+* `username`: `Rick`
+* `password`: `Portal Gun`
+* `extra`: `Mr. Poopybutthole`
+
+`extra` 필드가 허용되지 않는다는 오류 응답을 받게 됩니다:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["body", "extra"],
+ "msg": "Extra inputs are not permitted",
+ "input": "Mr. Poopybutthole"
+ }
+ ]
+}
+```
+
+## 요약
+
+Pydantic 모델을 사용하여 FastAPI에서 폼 필드를 선언할 수 있습니다. 😎
diff --git a/docs/ko/docs/tutorial/request-forms-and-files.md b/docs/ko/docs/tutorial/request-forms-and-files.md
index 75bca9f15..dc1bda21a 100644
--- a/docs/ko/docs/tutorial/request-forms-and-files.md
+++ b/docs/ko/docs/tutorial/request-forms-and-files.md
@@ -12,17 +12,13 @@
## `File` 및 `Form` 업로드
-```Python hl_lines="1"
-{!../../docs_src/request_forms_and_files/tutorial001.py!}
-```
+{* ../../docs_src/request_forms_and_files/tutorial001.py hl[1] *}
## `File` 및 `Form` 매개변수 정의
`Body` 및 `Query`와 동일한 방식으로 파일과 폼의 매개변수를 생성합니다:
-```Python hl_lines="8"
-{!../../docs_src/request_forms_and_files/tutorial001.py!}
-```
+{* ../../docs_src/request_forms_and_files/tutorial001.py hl[8] *}
파일과 폼 필드는 폼 데이터 형식으로 업로드되어 파일과 폼 필드로 전달됩니다.
diff --git a/docs/ko/docs/tutorial/request-forms.md b/docs/ko/docs/tutorial/request-forms.md
new file mode 100644
index 000000000..5ca17b0d6
--- /dev/null
+++ b/docs/ko/docs/tutorial/request-forms.md
@@ -0,0 +1,74 @@
+# 폼 데이터
+
+JSON 대신 폼 필드를 받아야 하는 경우 `Form`을 사용할 수 있습니다.
+
+/// info | 정보
+
+폼을 사용하려면, 먼저 `python-multipart`를 설치하세요.
+
+[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, 아래와 같이 설치할 수 있습니다:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+## `Form` 임포트하기
+
+`fastapi`에서 `Form`을 임포트합니다:
+
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+
+## `Form` 매개변수 정의하기
+
+`Body` 또는 `Query`와 동일한 방식으로 폼 매개변수를 만듭니다:
+
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+
+예를 들어, OAuth2 사양을 사용할 수 있는 방법 중 하나("패스워드 플로우"라고 함)로 `username`과 `password`를 폼 필드로 보내야 합니다.
+
+사양에서는 필드 이름이 `username` 및 `password`로 정확하게 명명되어야 하고, JSON이 아닌 폼 필드로 전송해야 합니다.
+
+`Form`을 사용하면 유효성 검사, 예제, 별칭(예: `username` 대신 `user-name`) 등을 포함하여 `Body`(및 `Query`, `Path`, `Cookie`)와 동일한 구성을 선언할 수 있습니다.
+
+/// info | 정보
+
+`Form`은 `Body`에서 직접 상속되는 클래스입니다.
+
+///
+
+/// tip | 팁
+
+폼 본문을 선언할 때, 폼이 없으면 매개변수가 쿼리 매개변수나 본문(JSON) 매개변수로 해석(interpret)되기 때문에 `Form`을 명시적으로 사용해야 합니다.
+
+///
+
+## "폼 필드"에 대해
+
+HTML 폼(``)이 데이터를 서버로 보내는 방식은 일반적으로 해당 데이터에 대해 "특수" 인코딩을 사용하며, 이는 JSON과 다릅니다.
+
+**FastAPI**는 JSON 대신 올바른 위치에서 해당 데이터를 읽습니다.
+
+/// note | 기술 세부사항
+
+폼의 데이터는 일반적으로 "미디어 유형(media type)" `application/x-www-form-urlencoded`를 사용하여 인코딩합니다.
+
+그러나 폼에 파일이 포함된 경우, `multipart/form-data`로 인코딩합니다. 다음 장에서 파일 처리에 대해 읽을 겁니다.
+
+
+이러한 인코딩 및 폼 필드에 대해 더 읽고 싶다면, POST에 대한 MDN 웹 문서를 참조하세요.
+
+///
+
+/// warning | 경고
+
+*경로 작업*에서 여러 `Form` 매개변수를 선언할 수 있지만, JSON으로 수신할 것으로 예상되는 `Body` 필드와 함께 선언할 수 없습니다. 요청 본문은 `application/json` 대신에 `application/x-www-form-urlencoded`를 사용하여 인코딩되기 때문입니다.
+
+이는 **FastAPI**의 제한 사항이 아니며 HTTP 프로토콜의 일부입니다.
+
+///
+
+## 요약
+
+폼 데이터 입력 매개변수를 선언하려면 `Form`을 사용하세요.
diff --git a/docs/ko/docs/tutorial/response-model.md b/docs/ko/docs/tutorial/response-model.md
index 6ba9654d6..a71d649f9 100644
--- a/docs/ko/docs/tutorial/response-model.md
+++ b/docs/ko/docs/tutorial/response-model.md
@@ -8,9 +8,7 @@
* `@app.delete()`
* 기타.
-```Python hl_lines="17"
-{!../../docs_src/response_model/tutorial001.py!}
-```
+{* ../../docs_src/response_model/tutorial001.py hl[17] *}
/// note | 참고
@@ -41,15 +39,11 @@ FastAPI는 이 `response_model`를 사용하여:
여기서 우리는 평문 비밀번호를 포함하는 `UserIn` 모델을 선언합니다:
-```Python hl_lines="9 11"
-{!../../docs_src/response_model/tutorial002.py!}
-```
+{* ../../docs_src/response_model/tutorial002.py hl[9,11] *}
그리고 이 모델을 사용하여 입력을 선언하고 같은 모델로 출력을 선언합니다:
-```Python hl_lines="17-18"
-{!../../docs_src/response_model/tutorial002.py!}
-```
+{* ../../docs_src/response_model/tutorial002.py hl[17:18] *}
이제 브라우저가 비밀번호로 사용자를 만들 때마다 API는 응답으로 동일한 비밀번호를 반환합니다.
@@ -67,21 +61,15 @@ FastAPI는 이 `response_model`를 사용하여:
대신 평문 비밀번호로 입력 모델을 만들고 해당 비밀번호 없이 출력 모델을 만들 수 있습니다:
-```Python hl_lines="9 11 16"
-{!../../docs_src/response_model/tutorial003.py!}
-```
+{* ../../docs_src/response_model/tutorial003.py hl[9,11,16] *}
여기서 *경로 작동 함수*가 비밀번호를 포함하는 동일한 입력 사용자를 반환할지라도:
-```Python hl_lines="24"
-{!../../docs_src/response_model/tutorial003.py!}
-```
+{* ../../docs_src/response_model/tutorial003.py hl[24] *}
...`response_model`을 `UserOut` 모델로 선언했기 때문에 비밀번호를 포함하지 않습니다:
-```Python hl_lines="22"
-{!../../docs_src/response_model/tutorial003.py!}
-```
+{* ../../docs_src/response_model/tutorial003.py hl[22] *}
따라서 **FastAPI**는 출력 모델에서 선언하지 않은 모든 데이터를 (Pydantic을 사용하여) 필터링합니다.
@@ -99,9 +87,7 @@ FastAPI는 이 `response_model`를 사용하여:
응답 모델은 아래와 같이 기본값을 가질 수 있습니다:
-```Python hl_lines="11 13-14"
-{!../../docs_src/response_model/tutorial004.py!}
-```
+{* ../../docs_src/response_model/tutorial004.py hl[11,13:14] *}
* `description: Optional[str] = None`은 기본값으로 `None`을 갖습니다.
* `tax: float = 10.5`는 기본값으로 `10.5`를 갖습니다.
@@ -115,9 +101,7 @@ FastAPI는 이 `response_model`를 사용하여:
*경로 작동 데코레이터* 매개변수를 `response_model_exclude_unset=True`로 설정 할 수 있습니다:
-```Python hl_lines="24"
-{!../../docs_src/response_model/tutorial004.py!}
-```
+{* ../../docs_src/response_model/tutorial004.py hl[24] *}
이러한 기본값은 응답에 포함되지 않고 실제로 설정된 값만 포함됩니다.
@@ -207,9 +191,7 @@ Pydantic 모델이 하나만 있고 출력에서 일부 데이터를 제
///
-```Python hl_lines="31 37"
-{!../../docs_src/response_model/tutorial005.py!}
-```
+{* ../../docs_src/response_model/tutorial005.py hl[31,37] *}
/// tip | 팁
@@ -223,9 +205,7 @@ Pydantic 모델이 하나만 있고 출력에서 일부 데이터를 제
`list` 또는 `tuple` 대신 `set`을 사용하는 법을 잊었더라도, FastAPI는 `set`으로 변환하고 정상적으로 작동합니다:
-```Python hl_lines="31 37"
-{!../../docs_src/response_model/tutorial006.py!}
-```
+{* ../../docs_src/response_model/tutorial006.py hl[31,37] *}
## 요약
diff --git a/docs/ko/docs/tutorial/response-status-code.md b/docs/ko/docs/tutorial/response-status-code.md
index 8e3a16645..bcaf7843b 100644
--- a/docs/ko/docs/tutorial/response-status-code.md
+++ b/docs/ko/docs/tutorial/response-status-code.md
@@ -8,9 +8,7 @@
* `@app.delete()`
* 기타
-```Python hl_lines="6"
-{!../../docs_src/response_status_code/tutorial001.py!}
-```
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
/// note | 참고
@@ -76,9 +74,7 @@ HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다
상기 예시 참고:
-```Python hl_lines="6"
-{!../../docs_src/response_status_code/tutorial001.py!}
-```
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
`201` 은 "생성됨"를 의미하는 상태 코드입니다.
@@ -86,9 +82,7 @@ HTTP는 세자리의 숫자 상태 코드를 응답의 일부로 전송합니다
`fastapi.status` 의 편의 변수를 사용할 수 있습니다.
-```Python hl_lines="1 6"
-{!../../docs_src/response_status_code/tutorial002.py!}
-```
+{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
이것은 단순히 작업을 편리하게 하기 위한 것으로, HTTP 상태 코드와 동일한 번호를 갖고있지만, 이를 사용하면 편집기의 자동완성 기능을 사용할 수 있습니다:
diff --git a/docs/ko/docs/tutorial/security/get-current-user.md b/docs/ko/docs/tutorial/security/get-current-user.md
index cf550735a..98ef3885e 100644
--- a/docs/ko/docs/tutorial/security/get-current-user.md
+++ b/docs/ko/docs/tutorial/security/get-current-user.md
@@ -2,9 +2,7 @@
이전 장에서 (의존성 주입 시스템을 기반으로 한)보안 시스템은 *경로 작동 함수*에서 `str`로 `token`을 제공했습니다:
-```Python hl_lines="10"
-{!../../docs_src/security/tutorial001.py!}
-```
+{* ../../docs_src/security/tutorial001.py hl[10] *}
그러나 아직도 유용하지 않습니다.
@@ -16,21 +14,7 @@
Pydantic을 사용하여 본문을 선언하는 것과 같은 방식으로 다른 곳에서 사용할 수 있습니다.
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="5 12-16"
-{!> ../../docs_src/security/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="3 10-14"
-{!> ../../docs_src/security/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial002.py hl[5,12:16] *}
## `get_current_user` 의존성 생성하기
@@ -42,61 +26,19 @@ Pydantic을 사용하여 본문을 선언하는 것과 같은 방식으로 다
이전에 *경로 작동*에서 직접 수행했던 것과 동일하게 새 종속성 `get_current_user`는 하위 종속성 `oauth2_scheme`에서 `str`로 `token`을 수신합니다.
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="25"
-{!> ../../docs_src/security/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="23"
-{!> ../../docs_src/security/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial002.py hl[25] *}
## 유저 가져오기
`get_current_user`는 토큰을 `str`로 취하고 Pydantic `User` 모델을 반환하는 우리가 만든 (가짜) 유틸리티 함수를 사용합니다.
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="19-22 26-27"
-{!> ../../docs_src/security/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="17-20 24-25"
-{!> ../../docs_src/security/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial002.py hl[19:22,26:27] *}
## 현재 유저 주입하기
이제 *경로 작동*에서 `get_current_user`와 동일한 `Depends`를 사용할 수 있습니다.
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="31"
-{!> ../../docs_src/security/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="29"
-{!> ../../docs_src/security/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial002.py hl[31] *}
Pydantic 모델인 `User`로 `current_user`의 타입을 선언하는 것을 알아야 합니다.
@@ -150,21 +92,7 @@ Pydantic 모델인 `User`로 `current_user`의 타입을 선언하는 것을 알
그리고 이 수천 개의 *경로 작동*은 모두 3줄 정도로 줄일 수 있습니다.
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="30-32"
-{!> ../../docs_src/security/tutorial002.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="28-30"
-{!> ../../docs_src/security/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial002.py hl[30:32] *}
## 요약
diff --git a/docs/ko/docs/tutorial/security/oauth2-jwt.md b/docs/ko/docs/tutorial/security/oauth2-jwt.md
new file mode 100644
index 000000000..d8bac8346
--- /dev/null
+++ b/docs/ko/docs/tutorial/security/oauth2-jwt.md
@@ -0,0 +1,273 @@
+# 패스워드 해싱을 이용한 OAuth2, JWT 토큰을 사용하는 Bearer 인증
+
+모든 보안 흐름을 구성했으므로, 이제 JWT 토큰과 패스워드 해싱을 사용해 애플리케이션을 안전하게 만들 것입니다.
+
+이 코드는 실제로 애플리케이션에서 패스워드를 해싱하여 DB에 저장하는 등의 작업에 활용할 수 있습니다.
+
+이전 장에 이어서 시작해 봅시다.
+
+## JWT
+
+JWT 는 "JSON Web Tokens" 을 의미합니다.
+
+JSON 객체를 공백이 없는 긴 문자열로 인코딩하는 표준이며, 다음과 같은 형태입니다:
+
+```
+eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
+```
+
+JWT는 암호화되지 않아 누구든지 토큰에서 정보를 복원할 수 있습니다.
+
+하지만 JWT는 서명되어 있습니다. 그래서 자신이 발급한 토큰을 받았을 때, 실제로 자신이 발급한게 맞는지 검증할 수 있습니다.
+
+만료 기간이 일주일인 토큰을 발행했다고 가정해 봅시다. 다음 날 사용자가 토큰을 가져왔을 때, 그 사용자가 시스템에 여전히 로그인되어 있다는 것을 알 수 있습니다.
+
+일주일 뒤에는 토큰이 만료될 것이고, 사용자는 인가되지 않아 새 토큰을 받기 위해 다시 로그인해야 할 것입니다. 만약 사용자(또는 제3자)가 토큰을 수정하거나 만료일을 변경하면, 서명이 일치하지 않기 때문에 알아챌 수 있을 것입니다.
+
+만약 JWT 토큰을 다뤄보고, 작동 방식도 알아보고 싶다면 https://jwt.io 을 확인하십시오.
+
+## `PyJWT` 설치
+
+파이썬으로 JWT 토큰을 생성하고 검증하려면 `PyJWT` 를 설치해야 합니다.
+
+[가상환경](../../virtual-environments.md){.internal-link target=_blank} 을 만들고 활성화한 다음 `pyjwt` 를 설치하십시오:
+
+
+
+/// info | 참고
+
+RSA나 ECDSA 같은 전자 서명 알고리즘을 사용하려면, `pyjwt[crypto]`라는 암호화 라이브러리 의존성을 설치해야 합니다.
+
+더 자세한 내용은 PyJWT 설치 에서 확인할 수 있습니다.
+
+///
+
+## 패스워드 해싱
+
+"해싱(Hashing)"은 어떤 내용(여기서는 패스워드)을 해석할 수 없는 일련의 바이트 집합(단순 문자열)으로 변환하는 것을 의미합니다.
+
+동일한 내용(똑같은 패스워드)을 해싱하면 동일한 문자열을 얻습니다.
+
+하지만 그 문자열을 다시 패스워드로 되돌릴 수는 없습니다.
+
+### 패스워드를 해싱하는 이유
+
+데이터베이스를 탈취당하더라도, 침입자는 사용자의 평문 패스워드 대신 해시 값만 얻을 수 있습니다.
+
+따라서 침입자는 훔친 사용자 패스워드를 다른 시스템에서 활용할 수 없습니다. (대다수 사용자가 여러 시스템에서 동일한 패스워드를 사용하기 때문에 평문 패스워드가 유출되면 위험합니다.)
+
+## `passlib` 설치
+
+PassLib는 패스워드 해시를 다루는 훌륭한 파이썬 패키지입니다.
+
+많은 안전한 해시 알고리즘과 도구들을 지원합니다.
+
+추천하는 알고리즘은 "Bcrypt"입니다.
+
+[가상환경](../../virtual-environments.md){.internal-link target=_blank} 을 만들고 활성화한 다음 PassLib와 Bcrypt를 설치하십시오:
+
+
+
+/// tip | 팁
+
+`passlib`를 사용하여, **Django**, **Flask** 의 보안 플러그인이나 다른 도구로 생성한 패스워드를 읽을 수 있도록 설정할 수도 있습니다.
+
+예를 들자면, FastAPI 애플리케이션과 Django 애플리케이션이 같은 데이터베이스에서 데이터를 공유할 수 있습니다. 또는 같은 데이터베이스를 사용하여 Django 애플리케이션을 점진적으로 마이그레이션 할 수도 있습니다.
+
+그리고 사용자는 FastAPI 애플리케이션과 Django 애플리케이션에 동시에 로그인할 수 있습니다.
+
+///
+
+## 패스워드의 해시와 검증
+
+필요한 도구를 `passlib`에서 임포트합니다.
+
+PassLib "컨텍스트(context)"를 생성합니다. 이것은 패스워드를 해싱하고 검증하는데 사용합니다.
+
+/// tip | 팁
+
+PassLib 컨텍스트는 다양한 해싱 알고리즘을 사용할 수 있는 기능을 제공하며, 더 이상 사용이 권장되지 않는 오래된 해싱 알고리즘을 검증하는 기능도 포함되어 있습니다.
+
+예를 들어, 다른 시스템(Django 같은)에서 생성한 패스워드를 읽고 검증할 수 있으며, 새로운 패스워드를 Bcrypt 같은 다른 알고리즘으로 해싱할 수도 있습니다.
+
+그리고 동시에 그런 모든 알고리즘과 호환성을 유지합니다.
+
+///
+
+사용자로부터 받은 패스워드를 해싱하는 유틸리티 함수를 생성합니다.
+
+그리고 받은 패스워드가 저장된 해시와 일치하는지 검증하는 또 다른 유틸리티 함수도 생성합니다.
+
+그리고 사용자를 인증하고 반환하는 또 다른 함수도 생성합니다.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+
+/// note
+
+새로운 (가짜) 데이터베이스 `fake_users_db`를 확인하면, 해시 처리된 패스워드가 어떻게 생겼는지 볼 수 있습니다: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
+
+///
+
+## JWT 토큰 처리
+
+설치된 모듈을 임포트 합니다.
+
+JWT 토큰 서명에 사용될 임의의 비밀키를 생성합니다.
+
+안전한 임의의 비밀키를 생성하려면 다음 명령어를 사용하십시오:
+
+
+
+그리고 생성한 비밀키를 복사해 변수 `SECRET_KEY`에 대입합니다. (이 예제의 변수 값을 그대로 사용하지 마십시오.)
+
+JWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITHM` 을 생성하고 `"HS256"` 으로 설정합니다.
+
+토큰 만료 기간을 위한 변수를 생성합니다.
+
+응답을 위한 토큰 엔드포인트에 사용될 Pydantic 모델을 정의합니다.
+
+새 액세스 토큰을 생성하기 위한 유틸리티 함수를 생성합니다.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+
+## 의존성 수정
+
+`get_current_user` 함수를 이전과 동일한 토큰을 받도록 수정하되, 이번에는 JWT 토큰을 사용하도록 합니다.
+
+받은 토큰을 디코딩하여 검증한 후 현재 사용자를 반환합니다.
+
+토큰이 유효하지 않다면 HTTP 오류를 반환합니다.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+
+## `/token` 경로 작업 수정
+
+토큰의 만료 시각을 설정하기 위해 `timedelta` 를 생성합니다.
+
+실제 JWT 액세스 토큰을 생성하여 반환합니다.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+
+### JWT "주체(subject)" `sub`에 대한 기술 세부 사항
+
+JWT 명세에 따르면 토큰의 주체를 포함하는 `sub`라는 키가 있습니다.
+
+사용 여부는 선택사항이지만, 사용자의 식별 정보를 저장할 수 있으므로 여기서는 이를 사용합니다.
+
+JWT는 사용자를 식별하고 사용자가 API를 직접 사용할 수 있도록 허용하는 것 외에도 다른 용도로 사용될 수도 있습니다.
+
+예를 들어 "자동차"나 "블로그 게시물"을 식별하는 데 사용할 수 있습니다.
+
+그리고 "자동차를 운전하다"나 "블로그 게시물을 수정하다"처럼 해당 엔터티에 대한 권한을 추가할 수 있습니다.
+
+그 후 이 JWT 토큰을 사용자(또는 봇)에게 제공하면, 그들은 계정을 따로 만들 필요 없이 API가 생성한 JWT 토큰만으로 작업(자동차 운전 또는 블로그 게시물 편집)을 수행할 수 있습니다.
+
+이러한 개념을 활용하면 JWT는 훨씬 더 복잡한 시나리오에도 사용할 수 있습니다.
+
+이 경우 여러 엔터티가 동일한 ID를 가질 수 있습니다. 예를 들어 foo라는 ID를 가진 사용자, 자동차, 블로그 게시물이 있을 수 있습니다.
+
+그래서 ID 충돌을 방지하기 위해, 사용자의 JWT 토큰을 생성할 때 접두사로 `sub` 키를 추가할 수 있습니다. 예를 들어 `username:` 을 붙이는 방식입니다. 이 예제에서는 `sub` 값이 `username:johndoe`이 될 수 있습니다.
+
+가장 중요한 점은 `sub` 키는 전체 애플리케이션에서 고유한 식별자가 되어야 하며 문자열이어야 한다는 점입니다.
+
+## 확인해봅시다
+
+서버를 실행하고 문서로 이동하십시오: http://127.0.0.1:8000/docs.
+
+다음과 같은 사용자 인터페이스를 볼 수 있습니다:
+
+
+
+이전과 같은 방법으로 애플리케이션에 인증하십시오.
+
+다음 인증 정보를 사용하십시오:
+
+Username: `johndoe`
+Password: `secret`
+
+/// check
+
+코드 어디에도 평문 패스워드 "`secret`" 이 없다는 점에 유의하십시오. 해시된 버전만 있습니다.
+
+///
+
+
+
+`/users/me/` 를 호출하면 다음과 같은 응답을 얻을 수 있습니다:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false
+}
+```
+
+
+
+개발자 도구를 열어보면 전송된 데이터에 토큰만 포함된 것을 확인할 수 있습니다. 패스워드는 사용자를 인증하고 액세스 토큰을 받기 위한 첫 번째 요청에만 전송되며, 이후에는 전송되지 않습니다:
+
+
+
+/// note
+
+`Bearer `로 시작하는 `Authorization` 헤더에 주목하십시오.
+
+///
+
+## `scopes` 의 고급 사용법
+
+OAuth2는 "스코프(scopes)" 라는 개념을 갖고 있습니다.
+
+이를 사용하여 JWT 토큰에 특정 권한 집합을 추가할 수 있습니다.
+
+그 후 이 토큰을 사용자에게 직접 제공하거나 제3자에게 제공하여, 특정 제한사항 하에있는 API와 통신하도록 할 수 있습니다.
+
+**FastAPI** 에서의 사용 방법과 통합 방식은 **심화 사용자 안내서** 에서 자세히 배울 수 있습니다.
+
+## 요약
+
+지금까지 살펴본 내용을 바탕으로, OAuth2와 JWT 같은 표준을 사용하여 안전한 **FastAPI** 애플리케이션을 만들 수 있습니다.
+
+거의 모든 프레임워크에서 보안 처리는 상당히 복잡한 주제입니다.
+
+이를 단순화하는 많은 패키지는 데이터 모델, 데이터베이스, 사용 가능한 기능들에 대해 여러 제약이 있습니다. 그리고 지나치게 단순화하는 일부 패키지들은 심각한 보안 결함을 가질 수도 있습니다.
+
+---
+
+**FastAPI** 는 어떤 데이터베이스, 데이터 모델, 도구도 강요하지 않습니다.
+
+프로젝트에 가장 적합한 것을 선택할 수 있는 유연성을 제공합니다.
+
+그리고 `passlib` 와 `PyJWT` 처럼 잘 관리되고 널리 사용되는 패키지들을 바로 사용할 수 있습니다. **FastAPI** 는 외부 패키지 통합을 위해 복잡한 메커니즘이 필요하지 않기 때문입니다.
+
+그러나 유연성, 견고성, 보안성을 해치지 않으면서 과정을 단순화할 수 있는 도구들을 제공합니다.
+
+그리고 OAuth2와 같은 표준 프로토콜을 비교적 간단한 방법으로 구현하고 사용할 수 있습니다.
+
+더 세분화된 권한 체계를 위해 OAuth2의 "스코프"를 사용하는 방법은 **심화 사용자 안내서**에서 더 자세히 배울 수 있습니다. OAuth2의 스코프는 제3자 애플리케이션이 사용자를 대신해 그들의 API와 상호작용하도록 권한을 부여하기 위해, Facebook, Google, GitHub, Microsoft, Twitter 등의 많은 대형 인증 제공업체들이 사용하는 메커니즘입니다.
diff --git a/docs/ko/docs/tutorial/security/simple-oauth2.md b/docs/ko/docs/tutorial/security/simple-oauth2.md
index fd18c1d47..f10c4f588 100644
--- a/docs/ko/docs/tutorial/security/simple-oauth2.md
+++ b/docs/ko/docs/tutorial/security/simple-oauth2.md
@@ -32,7 +32,7 @@ OAuth2는 (우리가 사용하고 있는) "패스워드 플로우"을 사용할
* `instagram_basic`은 페이스북/인스타그램에서 사용합니다.
* `https://www.googleapis.com/auth/drive`는 Google에서 사용합니다.
-/// 정보
+/// info | 정보
OAuth2에서 "범위"는 필요한 특정 권한을 선언하는 문자열입니다.
@@ -52,21 +52,7 @@ OAuth2의 경우 문자열일 뿐입니다.
먼저 `OAuth2PasswordRequestForm`을 가져와 `/token`에 대한 *경로 작동*에서 `Depends`의 의존성으로 사용합니다.
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="4 76"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="2 74"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003.py hl[4,76] *}
`OAuth2PasswordRequestForm`은 다음을 사용하여 폼 본문을 선언하는 클래스 의존성입니다:
@@ -75,7 +61,7 @@ OAuth2의 경우 문자열일 뿐입니다.
* `scope`는 선택적인 필드로 공백으로 구분된 문자열로 구성된 큰 문자열입니다.
* `grant_type`(선택적으로 사용).
-/// 팁
+/// tip | 팁
OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type` 필드를 *요구*하지만 `OAuth2PasswordRequestForm`은 이를 강요하지 않습니다.
@@ -86,7 +72,7 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type`
* `client_id`(선택적으로 사용) (예제에서는 필요하지 않습니다).
* `client_secret`(선택적으로 사용) (예제에서는 필요하지 않습니다).
-/// 정보
+/// info | 정보
`OAuth2PasswordRequestForm`은 `OAuth2PasswordBearer`와 같이 **FastAPI**에 대한 특수 클래스가 아닙니다.
@@ -100,7 +86,7 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type`
### 폼 데이터 사용하기
-/// 팁
+/// tip | 팁
종속성 클래스 `OAuth2PasswordRequestForm`의 인스턴스에는 공백으로 구분된 긴 문자열이 있는 `scope` 속성이 없고 대신 전송된 각 범위에 대한 실제 문자열 목록이 있는 `scopes` 속성이 있습니다.
@@ -114,21 +100,7 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type`
오류의 경우 `HTTPException` 예외를 사용합니다:
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="3 77-79"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="1 75-77"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003.py hl[3,77:79] *}
### 패스워드 확인하기
@@ -154,21 +126,13 @@ OAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type`
따라서 해커는 다른 시스템에서 동일한 암호를 사용하려고 시도할 수 없습니다(많은 사용자가 모든 곳에서 동일한 암호를 사용하므로 이는 위험할 수 있습니다).
-//// tab | P파이썬 3.7 이상
+//// tab | 파이썬 3.7 이상
-```Python hl_lines="80-83"
-{!> ../../docs_src/security/tutorial003.py!}
-```
+{* ../../docs_src/security/tutorial003.py hl[80:83] *}
////
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="78-81"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003_py310.py hl[78:81] *}
#### `**user_dict`에 대해
@@ -186,7 +150,7 @@ UserInDB(
)
```
-/// 정보
+/// info | 정보
`**user_dict`에 대한 자세한 설명은 [**추가 모델** 문서](../extra-models.md#about-user_indict){.internal-link target=_blank}를 다시 읽어봅시다.
@@ -202,7 +166,7 @@ UserInDB(
이 간단한 예제에서는 완전히 안전하지 않고, 동일한 `username`을 토큰으로 반환합니다.
-/// 팁
+/// tip | 팁
다음 장에서는 패스워드 해싱 및 JWT 토큰을 사용하여 실제 보안 구현을 볼 수 있습니다.
@@ -210,23 +174,9 @@ UserInDB(
///
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="85"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
+{* ../../docs_src/security/tutorial003.py hl[85] *}
-```Python hl_lines="83"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
-
-/// 팁
+/// tip | 팁
사양에 따라 이 예제와 동일하게 `access_token` 및 `token_type`이 포함된 JSON을 반환해야 합니다.
@@ -250,23 +200,9 @@ UserInDB(
따라서 엔드포인트에서는 사용자가 존재하고 올바르게 인증되었으며 활성 상태인 경우에만 사용자를 얻습니다:
-//// tab | 파이썬 3.7 이상
-
-```Python hl_lines="58-66 69-72 90"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
-
-//// tab | 파이썬 3.10 이상
-
-```Python hl_lines="55-64 67-70 88"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003.py hl[58:66,69:72,90] *}
-/// 정보
+/// info | 정보
여기서 반환하는 값이 `Bearer`인 추가 헤더 `WWW-Authenticate`도 사양의 일부입니다.
diff --git a/docs/ko/docs/tutorial/sql-databases.md b/docs/ko/docs/tutorial/sql-databases.md
new file mode 100644
index 000000000..58c7017d6
--- /dev/null
+++ b/docs/ko/docs/tutorial/sql-databases.md
@@ -0,0 +1,360 @@
+# SQL (관계형) 데이터베이스
+
+**FastAPI**에서 SQL(관계형) 데이터베이스 사용은 필수가 아닙니다. 여러분이 원하는 **어떤 데이터베이스든** 사용할 수 있습니다.
+
+여기서는 SQLModel을 사용하는 예제를 살펴보겠습니다.
+
+**SQLModel**은 SQLAlchemy와 Pydantic을 기반으로 구축되었습니다.SQLModel은 **SQL 데이터베이스**를 사용하는 FastAPI 애플리케이션에 완벽히 어울리도록 **FastAPI**의 제작자가 설계한 도구입니다.
+
+/// tip | 팁
+
+다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는 "ORM"이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎
+
+///
+
+SQLModel은 SQLAlchemy를 기반으로 하므로, SQLAlchemy에서 **지원하는 모든 데이터베이스**를 손쉽게 사용할 수 있습니다(SQLModel에서도 동일하게 지원됩니다). 예를 들면:
+
+* PostgreSQL
+* MySQL
+* SQLite
+* Oracle
+* Microsoft SQL Server 등.
+
+이 예제에서는 **SQLite**를 사용합니다. SQLite는 단일 파일을 사용하고 파이썬에서 기본적으로 지원하기 때문입니다. 따라서 이 예제를 그대로 복사하여 실행할 수 있습니다.
+
+나중에 실제 프로덕션 애플리케이션에서는 **PostgreSQL**과 같은 데이터베이스 서버를 사용하는 것이 좋습니다.
+
+/// tip | 팁
+
+**FastAPI**와 **PostgreSQL**를 포함하여 프론트엔드와 다양한 도구를 제공하는 공식 프로젝트 생성기가 있습니다: https://github.com/fastapi/full-stack-fastapi-template
+
+///
+
+이 튜토리얼은 매우 간단하고 짧습니다. 데이터베이스 기본 개념, SQL, 또는 더 복잡한 기능에 대해 배우고 싶다면, SQLModel 문서를 참고하세요.
+
+## `SQLModel` 설치하기
+
+먼저, [가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, `sqlmodel`을 설치하세요:
+
+
+
+## 단일 모델로 애플리케이션 생성하기
+
+우선 단일 **SQLModel** 모델을 사용하여 애플리케이션의 가장 간단한 첫 번째 버전을 생성해보겠습니다.
+
+이후 **다중 모델**을 추가하여 보안과 유연성을 강화할 것입니다. 🤓
+
+### 모델 생성하기
+
+`SQLModel`을 가져오고 데이터베이스 모델을 생성합니다:
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
+
+`Hero` 클래스는 Pydantic 모델과 매우 유사합니다 (실제로 내부적으로 *Pydantic 모델이기도 합니다*).
+
+몇 가지 차이점이 있습니다:
+
+* `table=True`는 SQLModel에 이 모델이 *테이블 모델*이며, 단순한 데이터 모델이 아니라 SQL 데이터베이스의 **테이블**을 나타낸다는 것을 알려줍니다. (다른 일반적인 Pydantic 클래스처럼) 단순한 *데이터 모델*이 아닙니다.
+
+* `Field(primary_key=True)`는 SQLModel에 `id`가 SQL 데이터베이스의 **기본 키**임을 알려줍니다 (SQL 기본 키에 대한 자세한 내용은 SQLModel 문서를 참고하세요).
+
+ `int | None` 유형으로 설정하면, SQLModel은 해당 열이 SQL 데이터베이스에서 `INTEGER` 유형이며 `NULLABLE` 값이어야 한다는 것을 알 수 있습니다.
+
+* `Field(index=True)`는 SQLModel에 해당 열에 대해 **SQL 인덱스**를 생성하도록 지시합니다. 이를 통해 데이터베이스에서 이 열으로 필터링된 데이터를 읽을 때 더 빠르게 조회할 수 있습니다.
+
+ SQLModel은 `str`으로 선언된 항목이 SQL 데이터베이스에서 `TEXT` (또는 데이터베이스에 따라 `VARCHAR`) 유형의 열로 저장된다는 것을 인식합니다.
+
+### 엔진 생성하기
+
+SQLModel의 `engine` (내부적으로는 SQLAlchemy `engine`)은 데이터베이스에 대한 **연결을 유지**하는 역할을 합니다.
+
+**하나의 단일 engine 객체**를 통해 코드 전체에서 동일한 데이터베이스에 연결할 수 있습니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
+
+`check_same_thread=False`를 사용하면 FastAPI에서 여러 스레드에서 동일한 SQLite 데이터베이스를 사용할 수 있습니다. 이는 **하나의 단일 요청**이 **여러 스레드**를 사용할 수 있기 때문에 필요합니다(예: 의존성에서 사용되는 경우).
+
+걱정하지 마세요. 코드가 구조화된 방식으로 인해, 이후에 **각 요청마다 단일 SQLModel *세션*을 사용**하도록 보장할 것입니다. 실제로 그것이 `check_same_thread`가 하려는 것입니다.
+
+### 테이블 생성하기
+
+그 다음 `SQLModel.metadata.create_all(engine)`을 사용하여 모든 *테이블 모델*의 **테이블을 생성**하는 함수를 추가합니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
+
+### 세션 의존성 생성하기
+
+**`Session`**은 **메모리에 객체**를 저장하고 데이터에 필요한 모든 변경 사항을 추적한 후, **`engine`을 통해** 데이터베이스와 통신합니다.
+
+`yield`를 사용해 FastAPI의 **의존성**을 생성하여 각 요청마다 새로운 `Session`을 제공합니다. 이는 요청당 하나의 세션만 사용되도록 보장합니다. 🤓
+
+그런 다음 이 의존성을 사용하는 코드를 간소화하기 위해 `Annotated` 의존성 `SessionDep`을 생성합니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
+
+### 시작 시 데이터베이스 테이블 생성하기
+
+애플리케이션 시작 시 데이터베이스 테이블을 생성합니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
+
+여기서는 애플리케이션 시작 이벤트 시 테이블을 생성합니다.
+
+프로덕션 환경에서는 애플리케이션을 시작하기 전에 실행되는 마이그레이션 스크립트를 사용할 가능성이 높습니다. 🤓
+
+/// tip | 팁
+
+SQLModel은 Alembic을 감싸는 마이그레이션 유틸리티를 제공할 예정입니다. 하지만 현재 Alembic을 직접 사용할 수 있습니다.
+
+///
+
+### Hero 생성하기
+
+각 SQLModel 모델은 Pydantic 모델이기도 하므로, Pydantic 모델을 사용할 수 있는 **타입 어노테이**션에서 동일하게 사용할 수 있습니다.
+
+예를 들어, 파라미터를 `Hero` 타입으로 선언하면 **JSON 본문**에서 값을 읽어옵니다.
+
+마찬가지로, 함수의 **반환 타입**으로 선언하면 해당 데이터의 구조가 자동으로 생성되는 API 문서의 UI에 나타납니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
+
+
+
+여기서 `SessionDep` 의존성 (즉, `Session`)을 사용하여 새로운 `Hero`를 `Session` 인스턴스에 추가하고, 데이터베이스에 변경 사항을 커밋하고, `hero` 데이터의 최신 상태를 갱신한 다음 이를 반환합니다.
+
+### Heroes 조회하기
+
+`select()`를 사용하여 데이터베이스에서 `Hero`를 **조회**할 수 있습니다. 결과에 페이지네이션을 적용하기 위해 `limit`와 `offset`을 포함할 수 있습니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
+
+### 단일 Hero 조회하기
+
+단일 `Hero`를 **조회**할 수도 있습니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
+
+### Hero 삭제하기
+
+`Hero`를 **삭제**하는 것도 가능합니다.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
+
+### 애플리케이션 실행하기
+
+애플리케이션을 실행하려면 다음 명령을 사용합니다:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+그런 다음 `/docs` UI로 이동하면, **FastAPI**가 해당 **model들**을 사용하여 API **문서를 생성**하는 것으르 확인할 수 있습니다. 또한 이 모델들은 데이터를 직렬화하고 검증하는 데에도 사용됩니다.
+
+
+
+
+
+## 여러 모델로 애플리케이션 업데이트
+
+이제 애플리케이션을 약간 **리팩토링**하여 **보안**과 **유연성**을 개선해 보겠습니다.
+
+이전 애플리케이션의 UI를 보면, 지금까지는 클라이언트가 생성할 `Hero`의 `id`를 직접 지정할 수 있다는 것을 알 수 있습니다. 😱
+
+이는 허용되어선 안 됩니다. 클라이언트가 이미 데이터베이스에 저장된 `id`를 덮어쓸 위험이 있기 때문입니다. `id`는 **백엔드** 또는 **데이터베이스**가 결정해야 하며, **클라이언트**가 결정해서는 안 됩니다.
+
+또한 hero의 `secret_name`을 생성하긴 했지만, 지금까지는 이 값을 어디에서나 반환하고 있습니다. 이는 그다지 **비밀스럽지** 않습니다... 😅
+
+이러한 문제를 해결하기 위해 몇 가지 **추가 모델**을 추가할 것입니다. 바로 여기서 SQLModel이 빛을 발하게 됩니다. ✨
+
+### 여러 모델 생성하기
+
+**SQLModel**에서 `table=True`가 설정된 모델 클래스는 **테이블 모델**입니다.
+
+`table=True`가 없는 모델 클래스는 **데이터 모델**로, 이는 실제로 몇 가지 추가 기능이 포함된 Pydantic 모델에 불과합니다. 🤓
+
+SQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중복 선언하지 않아도** 됩니다.
+
+#### `HeroBase` - 기본 클래스
+
+모든 모델에서 **공유되는 필드**를 가진 `HeroBase` 모델을 시작해 봅시다:
+
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
+
+#### `Hero` - *테이블 모델*
+
+다음으로 실제 *테이블 모델*인 `Hero`를 생성합니다. 이 모델은 다른 모델에는 항상 포함되는 건 아닌 **추가 필드**를 포함합니다:
+
+* `id`
+* `secret_name`
+
+`Hero`는 `HeroBase`를 상속하므로 `HeroBase`에 선언된 필드도 포함합니다. 따라서 `Hero`는 다음 **필드들도** 가지게 됩니다:
+
+* `id`
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
+
+#### `HeroPublic` - 공개 *데이터 모델*
+
+다음으로 `HeroPublic` 모델을 생성합니다. 이 모델은 API 클라이언트에 **반환**되는 모델입니다.
+
+`HeroPublic`은 `HeroBase`와 동일한 필드를 가지며, `secret_name`은 포함하지 않습니다.
+
+마침내 우리의 heroes의 정체가 보호됩니다! 🥷
+
+또한 `id: int`를 다시 선언합니다. 이를 통해, API 클라이언트와 **계약**을 맺어 `id`가 항상 존재하며 항상 `int` 타입이라는 것을 보장합니다(`None`이 될 수 없습니다).
+
+/// tip | 팁
+
+반환 모델이 값이 항상 존재하고 항상 `int`(`None`이 아님)를 보장하는 것은 API 클라이언트에게 매우 유용합니다. 이를 통해 API와 통신하는 개발자가 훨씬 더 간단한 코드를 작성할 수 있습니다.
+
+또한 **자동으로 생성된 클라이언트**는 더 단순한 인터페이스를 제공하므로, API와 소통하는 개발자들이 훨씬 수월하게 작업할 수 있습니다. 😎
+
+///
+
+`HeroPublic`의 모든 필드는 `HeroBase`와 동일하며, `id`는 `int`로 선언됩니다(`None`이 아님):
+
+* `id`
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
+
+#### `HeroCreate` - hero 생성용 *데이터 모델*
+
+이제 `HeroCreate` 모델을 생성합니다. 이 모델은 클라이언트로부터 받은 데이터를 **검증**하는 역할을 합니다.
+
+`HeroCreate`는 `HeroBase와` 동일한 필드를 가지며, 추가로 `secret_name을` 포함합니다.
+
+클라이언트가 **새 hero을 생성**할 때 `secret_name`을 보내고, 이는 데이터베이스에 저장되지만, 해당 비밀 이름은 API를 통해 클라이언트에게 반환되지 않습니다.
+
+/// tip | 팁
+
+이 방식은 **비밀번호**를 처리하는 방법과 동일합니다. 비밀번호를 받지만, 이를 API에서 반환하지는 않습니다.
+
+비밀번호 값을 저장하기 전에 **해싱**하여 저장하고, **평문으로 저장하지 마십시오**.
+
+///
+
+`HeroCreate`의 필드는 다음과 같습니다:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
+
+#### `HeroUpdate` - hero 수정용 *데이터 모델*
+
+이전 애플리케이션에서는 **hero를 수정**할 방법이 없었지만, 이제 **다중 모델**을 통해 수정 기능을 추가할 수 있습니다. 🎉
+
+`HeroUpdate` *데이터 모델*은 약간 특별한데, 새 hero을 생성할 때 필요한 **모든 동일한 필드**를 가지지만, 모든 필드가 **선택적**(기본값이 있음)입니다. 이렇게 하면 hero을 수정할 때 수정하려는 필드만 보낼 수 있습니다.
+
+모든 **필드가 변경되기** 때문에(타입이 `None`을 포함하고, 기본값이 `None`으로 설정됨), 모든 필드를 **다시 선언**해야 합니다.
+
+엄밀히 말하면 `HeroBase`를 상속할 필요는 없습니다. 모든 필드를 다시 선언하기 때문입니다. 일관성을 위해 상속을 유지하긴 했지만, 필수는 아닙니다. 이는 개인적인 취향의 문제입니다. 🤷
+
+`HeroUpdate`의 필드는 다음과 같습니다:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
+
+### `HeroCreate`로 생성하고 `HeroPublic` 반환하기
+
+이제 **다중 모델**을 사용하므로 애플리케이션의 관련 부분을 업데이트할 수 있습니다.
+
+요청에서 `HeroCreate` *데이터 모델*을 받아 이를 기반으로 `Hero` *테이블 모델*을 생성합니다.
+
+이 새 *테이블 모델* `Hero`는 클라이언트에서 보낸 필드를 가지며, 데이터베이스에서 생성된 `id`도 포함합니다.
+
+그런 다음 함수를 통해 동일한 *테이블 모델* `Hero`를 반환합니다. 하지만 `response_model`로 `HeroPublic` *데이터 모델*을 선언했기 때문에, **FastAPI**는 `HeroPublic`을 사용하여 데이터를 검증하고 직렬화합니다.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
+
+/// tip | 팁
+
+이제 **반환 타입 주석** `-> HeroPublic` 대신 `response_model=HeroPublic`을 사용합니다. 반환하는 값이 실제로 `HeroPublic`이 *아니기* 때문입니다.
+
+만약 `-> HeroPublic`으로 선언했다면, 에디터와 린터에서 반환값이 `HeroPublic`이 아니라 `Hero`라고 경고했을 것입니다. 이는 적절한 경고입니다.
+
+`response_model`에 선언함으로써 **FastAPI**가 이를 처리하도록 하고, 타입 어노테이션과 에디터 및 다른 도구의 도움에는 영향을 미치지 않도록 설정합니다.
+
+///
+
+### `HeroPublic`으로 Heroes 조회하기
+
+이전과 동일하게 `Hero`를 **조회**할 수 있습니다. 이번에도 `response_model=list[HeroPublic]`을 사용하여 데이터가 올바르게 검증되고 직렬화되도록 보장합니다.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
+
+### `HeroPublic`으로 단일 Hero 조회하기
+
+단일 hero을 **조회**할 수도 있습니다:
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
+
+### `HeroUpdate`로 Hero 수정하기
+
+**hero를 수정**할 수도 있습니다. 이를 위해 HTTP `PATCH` 작업을 사용합니다.
+
+코드에서는 클라이언트가 보낸 데이터를 딕셔너리 형태(`dict`)로 가져옵니다. 이는 **클라이언트가 보낸 데이터만 포함**하며, 기본값으로 들어가는 값은 제외합니다. 이를 위해 `exclude_unset=True`를 사용합니다. 이것이 주요 핵심입니다. 🪄
+
+그런 다음, `hero_db.sqlmodel_update(hero_data)`를 사용하여 `hero_data`의 데이터를 `hero_db`에 업데이트합니다.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
+
+### Hero 다시 삭제하기
+
+hero **삭제**는 이전과 거의 동일합니다.
+
+이번에는 모든 것을 리팩토링하고 싶은 욕구를 만족시키지 못할 것 같습니다. 😅
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
+
+### 애플리케이션 다시 실행하기
+
+다음 명령을 사용해 애플리케이션을 다시 실행할 수 있습니다:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+`/docs` API UI로 이동하면 업데이트된 것을 확인할 수 있습니다. 클라이언트가 영웅을 생성할 때 `id`를 제공할 필요가 없게 되는 등의 변화도 보입니다.
+
+
+
+
+
+## 요약
+
+**SQLModel**을 사용하여 SQL 데이터베이스와 상호작용하고, *데이터 모델* 및 *테이블 모델*로 코드를 간소화할 수 있습니다.
+
+더 많은 내용을 배우고 싶다면, **SQLModel** 문서를 참고하세요. SQLModel을 **FastAPI**와 함께 사용하는 것에 대한 더 긴 미니 튜토리얼도 제공합니다. 🚀
diff --git a/docs/ko/docs/tutorial/static-files.md b/docs/ko/docs/tutorial/static-files.md
index af785f206..9db5e1c67 100644
--- a/docs/ko/docs/tutorial/static-files.md
+++ b/docs/ko/docs/tutorial/static-files.md
@@ -7,9 +7,7 @@
* `StaticFiles` 임포트합니다.
* 특정 경로에 `StaticFiles()` 인스턴스를 "마운트" 합니다.
-```Python hl_lines="2 6"
-{!../../docs_src/static_files/tutorial001.py!}
-```
+{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
/// note | 기술적 세부사항
diff --git a/docs/ko/docs/tutorial/testing.md b/docs/ko/docs/tutorial/testing.md
new file mode 100644
index 000000000..a483cbf00
--- /dev/null
+++ b/docs/ko/docs/tutorial/testing.md
@@ -0,0 +1,243 @@
+# 테스팅
+
+Starlette 덕분에 **FastAPI** 를 테스트하는 일은 쉽고 즐거운 일이 되었습니다.
+
+Starlette는 HTTPX를 기반으로 하며, 이는 Requests를 기반으로 설계되었기 때문에 매우 친숙하고 직관적입니다.
+
+이를 사용하면 FastAPI에서 pytest를 직접 사용할 수 있습니다.
+
+## `TestClient` 사용하기
+
+/// info | 정보
+
+`TestClient` 사용하려면, 우선 `httpx` 를 설치해야 합니다.
+
+[virtual environment](../virtual-environments.md){.internal-link target=_blank} 를 만들고, 활성화 시킨 뒤에 설치하세요. 예시:
+
+```console
+$ pip install httpx
+```
+
+///
+
+`TestClient` 를 임포트하세요.
+
+**FastAPI** 어플리케이션을 전달하여 `TestClient` 를 만드세요.
+
+이름이 `test_` 로 시작하는 함수를 만드세요(`pytest` 의 표준적인 관례입니다).
+
+`httpx` 를 사용하는 것과 같은 방식으로 `TestClient` 객체를 사용하세요.
+
+표준적인 파이썬 문법을 이용하여 확인이 필요한 곳에 간단한 `assert` 문장을 작성하세요(역시 표준적인 `pytest` 관례입니다).
+
+{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
+
+/// tip | 팁
+
+테스트를 위한 함수는 `async def` 가 아니라 `def` 로 작성됨에 주의하세요.
+
+그리고 클라이언트에 대한 호출도 `await` 를 사용하지 않는 일반 호출입니다.
+
+이렇게 하여 복잡한 과정 없이 `pytest` 를 직접적으로 사용할 수 있습니다.
+
+///
+
+/// note | 기술 세부사항
+
+`from starlette.testclient import TestClient` 역시 사용할 수 있습니다.
+
+**FastAPI** 는 개발자의 편의를 위해 `starlette.testclient` 를 `fastapi.testclient` 로도 제공할 뿐입니다. 이는 단지 `Starlette` 에서 직접 가져오는지의 차이일 뿐입니다.
+
+///
+
+/// tip | 팁
+
+FastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서 `async` 함수를 호출하고 싶다면 (예: 비동기 데이터베이스 함수), 심화 튜토리얼의 [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} 를 참조하세요.
+
+///
+
+## 테스트 분리하기
+
+실제 애플리케이션에서는 테스트를 별도의 파일로 나누는 경우가 많습니다.
+
+
+그리고 **FastAPI** 애플리케이션도 여러 파일이나 모듈 등으로 구성될 수 있습니다.
+
+### **FastAPI** app 파일
+
+[Bigger Applications](bigger-applications.md){.internal-link target=_blank} 에 묘사된 파일 구조를 가지고 있는 것으로 가정해봅시다.
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+```
+
+`main.py` 파일 안에 **FastAPI** app 을 만들었습니다:
+
+{* ../../docs_src/app_testing/main.py *}
+
+### 테스트 파일
+
+테스트를 위해 `test_main.py` 라는 파일을 생성할 수 있습니다. 이 파일은 동일한 Python 패키지(즉, `__init__.py` 파일이 있는 동일한 디렉터리)에 위치할 수 있습니다.
+
+``` hl_lines="5"
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+파일들이 동일한 패키지에 위치해 있으므로, 상대 참조를 사용하여 `main` 에서 `app` 객체를 임포트 해올 수 있습니다.
+
+{* ../../docs_src/app_testing/test_main.py hl[3] *}
+
+
+...그리고 이전에 작성했던 것과 같은 테스트 코드를 작성할 수 있습니다.
+
+## 테스트: 확장된 예시
+
+이제 위의 예시를 확장하고 더 많은 세부 사항을 추가하여 다양한 부분을 어떻게 테스트하는지 살펴보겠습니다.
+
+### 확장된 FastAPI 애플리케이션 파일
+
+이전과 같은 파일 구조를 계속 사용해 보겠습니다.
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+이제 **FastAPI** 앱이 있는 `main.py` 파일에 몇 가지 다른 **경로 작업** 이 추가된 경우를 생각해봅시다.
+
+단일 오류를 반환할 수 있는 `GET` 작업이 있습니다.
+
+여러 다른 오류를 반환할 수 있는 `POST` 작업이 있습니다.
+
+두 *경로 작업* 모두 `X-Token` 헤더를 요구합니다.
+
+//// tab | Python 3.10+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.9+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an_py39/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an/main.py!}
+```
+
+////
+
+//// tab | Python 3.10+ non-Annotated
+
+/// tip | 팁
+
+될 수 있으면 `Annotated` 버전 사용을 권장합나다.
+
+///
+
+```Python
+{!> ../../docs_src/app_testing/app_b_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+ non-Annotated
+
+/// tip | 팁
+
+될 수 있으면 `Annotated` 버전 사용을 권장합나다.
+
+///
+
+```Python
+{!> ../../docs_src/app_testing/app_b/main.py!}
+```
+
+////
+
+### 확장된 테스트 파일
+
+이제는 `test_main.py` 를 확장된 테스트들로 수정할 수 있습니다:
+
+{* ../../docs_src/app_testing/app_b/test_main.py *}
+
+
+클라이언트가 요청에 정보를 전달해야 하는데 방법을 모르겠다면, `httpx`에서 해당 작업을 수행하는 방법을 검색(Google)하거나, `requests`에서의 방법을 검색해보세요. HTTPX는 Requests의 디자인을 기반으로 설계되었습니다.
+
+그 후, 테스트에서도 동일하게 적용하면 됩니다.
+
+예시:
+
+* *경로* 혹은 *쿼리* 매개변수를 전달하려면, URL 자체에 추가한다.
+* JSON 본문을 전달하려면, 파이썬 객체 (예를들면 `dict`) 를 `json` 파라미터로 전달한다.
+* JSON 대신 *폼 데이터* 를 보내야한다면, `data` 파라미터를 대신 전달한다.
+* *헤더* 를 전달하려면, `headers` 파라미터에 `dict` 를 전달한다.
+* *쿠키* 를 전달하려면, `cookies` 파라미터에 `dict` 를 전달한다.
+
+백엔드로 데이터를 어떻게 보내는지 정보를 더 얻으려면 (`httpx` 혹은 `TestClient` 를 이용해서) HTTPX documentation 를 확인하세요.
+
+/// info | 정보
+
+`TestClient` 는 Pydantic 모델이 아니라 JSON 으로 변환될 수 있는 데이터를 받습니다.
+
+만약 테스트중 Pydantic 모델을 어플리케이션으로에 보내고 싶다면, [JSON 호환 가능 인코더](encoder.md){.internal-link target=_blank} 에 설명되어 있는 `jsonable_encoder` 를 사용할 수 있습니다.
+
+///
+
+## 실행하기
+
+테스트 코드를 작성하고, `pytest` 를 설치해야합니다.
+
+[virtual environment](../virtual-environments.md){.internal-link target=_blank} 를 만들고, 활성화 시킨 뒤에 설치하세요. 예시:
+
+
diff --git a/docs/ko/docs/virtual-environments.md b/docs/ko/docs/virtual-environments.md
new file mode 100644
index 000000000..0d10c3200
--- /dev/null
+++ b/docs/ko/docs/virtual-environments.md
@@ -0,0 +1,846 @@
+# 가상 환경
+
+Python 프로젝트를 작업할 때는 **가상 환경** (또는 이와 유사한 도구)을 사용하는 것이 좋습니다. 각 프로젝트 마다 설치하는 패키지를 분리하여 관리할 수 있습니다.
+
+/// info | 정보
+
+이미 가상 환경에 대해 잘 알고 있다면, 이 섹션은 건너 뛰어도 괜찮습니다. 🤓
+
+///
+
+/// tip | 팁
+
+**가상 환경(Virtual Environment)** 은 **환경 변수(Environment Variable)** 와 다릅니다.
+
+**환경 변수**는 시스템에 존재하며, 프로그램이 사용할 수 있는 변수입니다.
+
+**가상 환경**은 몇몇 파일로 구성된 하나의 디렉터리입니다.
+
+///
+
+/// info | 정보
+
+이 페이지에서는 **가상 환경**의 사용 방법과 작동 방식을 설명합니다.
+
+만약 **모든 것을 관리해주는 도구** (Python 설치까지 포함)를 사용하고 싶다면 uv를 사용해보세요.
+
+///
+
+## 프로젝트 생성
+
+먼저, 프로젝트를 위한 디렉터리를 하나 생성합니다.
+
+보통 사용자 홈 디렉터리 안에 `code`라는 디렉터리를 만들고, 그 안에 프로젝트마다 하나씩 디렉터리를 만들어 관리합니다.
+
+
+
+```console
+// 홈 디렉터리로 이동
+$ cd
+// 모든 코드 프로젝트를 위한 디렉터리 생성
+$ mkdir code
+// code 디렉터리로 이동
+$ cd code
+// 이번 프로젝트를 위한 디렉터리 생성
+$ mkdir awesome-project
+// 해당 프로젝트 디렉터리로 이동
+$ cd awesome-project
+```
+
+
+
+## 가상 환경 생성
+
+Python 프로젝트를 **처음 시작할 때**, 가상 환경을 **프로젝트 내부**에 생성합니다.
+
+/// tip | 팁
+
+이 작업은 **프로젝트를 처음 설정할 때 한번만** 해주면 됩니다. 이후 작업할 때 반복할 필요는 없습니다.
+
+///
+
+//// tab | `venv`
+
+Python 표준 라이브러리에 포함된 venv 모듈을 사용해 가상 환경을 생성할 수 있습니다.
+
+
+
+```console
+$ python -m venv .venv
+```
+
+
+
+/// details | 명령어 상세 설명
+
+* `python`: `python` 프로그램을 실행합니다.
+* `-m`: 특정 모듈을 스크립트처럼 실행합니다. 대상 모듈을 바로 뒤에 지정합니다.
+* `venv`: Python 표준 라이브러리에 포함된 `venv` 모듈을 실행합니다.
+* `.venv`: 가상 환경을 `.venv` 디렉터리에 생성합니다.
+
+///
+
+////
+
+//// tab | `uv`
+
+`uv`가 설치되어 있다면, uv를 통해 가상 환경을 생성할 수 있습니다.
+
+
+
+```console
+$ uv venv
+```
+
+
+
+/// tip | 팁
+
+`uv`는 기본적으로 `.venv` 디렉터리에 가상 환경을 생성합니다.
+
+별도로 디렉터리 이름을 추가 인자로 넘겨 주면 경로를 지정 할 수 있습니다.
+
+///
+
+////
+
+해당 명령어는 `.venv` 디렉터리에 새로운 가상 환경을 생성합니다.
+
+/// details | `.venv` 또는 다른 이름
+
+가상 환경을 다른 디렉터리에 생성할 수도 있지만, 관례적으로 `.venv` 디렉터리 이름을 사용합니다.
+
+///
+
+## 가상 환경 활성화
+
+이후 실행하는 Python 명령어와 패키지 설치가 가상 환경을 따르도록, 가상 환경을 활성화하세요.
+
+/// tip | 팁
+
+**터미널을 새로 열고** 프로젝트 작업을 시작할 때는, **항상 이 작업을** 해주세요.
+
+///
+
+//// tab | Linux, macOS
+
+
+
+////
+
+/// tip | 팁
+
+가상 환경에 새로운 패키지를 설치할 때마다, 해당 환경을 다시 활성화하세요.
+
+이렇게 하면 해당 패키지로 설치된 **터미널(CLI) 프로그램**을 사용할 때, 전역에 설치된 다른 버전이 아니라, 가상 환경 안에 설치된 정확한 버전을 사용합니다.
+
+///
+
+## 가상 환경이 활성화 여부 확인
+
+가상 환경이 활성화되었는지 확인합니다. (이전 명령어가 제대로 작동했는지 확인합니다).
+
+/// tip | 팁
+
+이 단계는 **선택 사항**이지만, 모든 것이 예상대로 작동하고 있는지, 그리고 의도한 가상 환경이 활성화 되었는 지 **확인**하는 좋은 방법입니다.
+
+///
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+`python` 위치가 프로젝트 내부(이 예시에서는 `awesome-project`)의 `.venv/bin/python` 경로로 표시된다면 성공입니다. 🎉
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+`python` 위치가 프로젝트 내부(이 예시에서는 `awesome-project`)의 `.venv\bin\python` 경로로 표시된다면 성공입니다. 🎉
+
+////
+
+## pip 업그레이드
+
+/// tip | 팁
+
+`uv`를 사용한다면, `pip` 대신 `uv`로 패키지를 설치하게 되므로 `pip`을 업그레이드할 필요가 없습니다. 😎
+
+///
+
+`pip`을 사용하여 패키지를 설치하는 경우 (Python 표준 라이브러리에 포함되어 있습니다), **최신 버전으로 업그레이드**하는 것이 좋습니다.
+
+패키지 설치 중 발생하는 다양하고 특이한 에러들은 `pip` 업그레이드로 쉽게 해결되는 경우가 많습니다.
+
+/// tip | 팁
+
+이 작업은 보통 가상 환경을 생성한 **직후 한 번만** 하면 됩니다.
+
+///
+
+가상 환경이 활성화된 상태인지 확인한 후(앞서 설명한 명령어 사용), 아래 명령어를 실행하세요:
+
+
+
+## `.gitignore` 추가하기
+
+**Git**을 사용하고 있다면 (사용하는 것이 좋습니다), `.gitignore` 파일을 추가해서 `.venv` 디렉터리 전체를 Git에서 제외하세요.
+
+/// tip | 팁
+
+`uv`를 사용해 가상 환경을 생성했다면, 이미 이 작업이 자동으로 처리되어 있으므로 이 단계는 건너뛰어도 됩니다. 😎
+
+///
+
+/// tip | 팁
+
+이 작업도 마찬가지로, 가상 환경을 생성한 **직후 한 번만** 하면 됩니다.
+
+///
+
+
+
+/// details | 명령어 상세 설명
+
+* `echo "*"`: 터미널에 `*` 텍스트를 "출력"합니다 (다음 설명에서 조금 바뀝니다)
+* `>`: 왼쪽 명령어의 출력 내용을 터미널에 출력하지 않고, 오른쪽에 지정된 파일로 **기록(write)** 하라는 의미입니다.
+* `.gitignore`: 출력된 텍스트가 기록될 파일 이름입니다.
+
+그리고 Git에서 `*`는 "모든 것"을 의미합니다. 따라서 `.venv` 디렉터리 안의 모든 것을 무시하게 됩니다.
+
+이 명령어는 다음과 같은 내용을 가진 `.gitignore` 파일을 생성합니다:
+
+
+```gitignore
+*
+```
+
+///
+
+## 패키지 설치
+
+가상 환경을 활성화한 후, 그 안에 필요한 패키지들을 설치할 수 있습니다.
+
+/// tip | 팁
+
+프로젝트에서 필요한 패키지를 설치하거나 업그레이드할 때는 이 작업을 **한 번만** 하면 됩니다.
+
+만약 특정 패키지의 버전을 업그레이드하거나, 새로운 패키지를 추가할 필요가 생기면 **다시 이 작업을 반복**하면 됩니다.
+
+///
+
+### 패키지 직접 설치
+
+급하게 작업하거나, 프로젝트에 필요한 패키지 목록을 따로 파일로 관리하고 싶지 않은 경우, 패키지를 직접 설치할 수도 있습니다.
+
+/// tip | 팁
+
+패키지 이름과 버전 정보를 파일에 정리해두는 것(예: `requirements.txt` 또는 `pyproject.toml`)은 (매우) 좋은 생각입니다.
+
+///
+
+//// tab | `pip`
+
+
+
+////
+
+/// details | `requirements.txt`
+
+다음은 몇 가지 패키지를 포함한 `requirements.txt`의 예시입니다:
+
+```requirements.txt
+fastapi[standard]==0.113.0
+pydantic==2.8.0
+```
+
+///
+
+## 프로그램 실행
+
+가상 환경을 활성화한 후에는 프로그램을 실행할 수 있습니다. 이때 해당 가상 환경에 설치된 Python과 패키지들이 사용됩니다.
+
+
+
+## 에디터 설정
+
+에디터를 사용할 경우, 앞서 만든 가상 환경을 사용하도록 설정하는 것이 좋습니다. (대부분의 에디터는 자동으로 감지하기도 합니다.)
+이렇게 하면 자동 완성 기능이나 코드 내 오류 표시 기능을 제대로 사용할 수 있습니다.
+
+예시:
+
+* VS Code
+* PyCharm
+
+/// tip | 팁
+
+이 설정은 보통 가상 환경을 **처음 만들었을 때 한 번만** 해주면 됩니다.
+
+///
+
+## 가상 환경 비활성화
+
+프로젝트 작업이 끝났다면, 가상 환경을 **비활성화**할 수 있습니다.
+
+
+
+```console
+$ deactivate
+```
+
+
+
+이렇게 하면 이후에 `python` 명령어를 실행했을 때, 가상 환경의 Python이나 그 안에 설치된 패키지들을 사용하지 않게 됩니다.
+
+## 이제 작업할 준비가 되었습니다
+
+이제 프로젝트 작업을 시작할 준비가 완료되었습니다.
+
+
+/// tip | 팁
+
+위 내용을 더 깊이 이해하고 싶으신가요?
+
+그렇다면 계속 읽어 주세요. 👇🤓
+
+///
+
+## 가상 환경을 왜 사용하는가
+
+FastAPI를 사용하려면 먼저 Python을 설치해야 합니다.
+
+그 후에는 FastAPI와 함께 사용할 **기타 패키지들**을 **설치**해야 합니다.
+
+패키지를 설치할 때 보통 Python에 기본 포함된 `pip` 명령어(또는 유사한 도구)를 사용합니다.
+
+하지만 `pip`을 그냥 직접 사용하면, 해당 패키지들은 **전역 Python 환경**(시스템 전체에 설치된 Python)에 설치됩니다.
+
+### 문제점
+
+그렇다면, 전역 Python 환경에 패키지를 설치하면 어떤 문제가 발생할까요?
+
+어느 시점이 되면, **서로 다른 패키지들**에 의존하는 여러 개의 프로그램을 작성하게 될 것입니다. 그리고 이들 중 일부는 **같은 패키지의 서로 다른 버전**을 필요로 할 수 있습니다. 😱
+
+예를 들어, `마법사의 돌(philosophers-stone)` 프로젝트를 만들었다고 가정해봅시다. 이 프로그램은 `해리 포터(harry)`라는 패키지의 `v1` 버전을 **의존**합니다. 따라서 `harry`를 설치해야 합니다.
+
+```mermaid
+flowchart LR
+ stone(philosophers-stone) -->|requires| harry-1[harry v1]
+```
+
+그런데 나중에 `아즈카반의 죄수(prisoner-of-azkaban)`이라는 또 다른 프로젝트를 만들게 되었고, 이 프로젝트도 역시 `harry` 패키지를 사용합니다. 그런데 이 프로젝트는 `harry`의 `v3` 버전이 필요합니다.
+
+```mermaid
+flowchart LR
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
+```
+
+하지만 이제 문제가 생깁니다. 로컬 가상 환경 대신에 전역 환경에 패키지를 설치하게 되면, 어떤 버전의 `harry`를 설치할지를 선택해야 하기 때문입니다.
+
+예를 들어, `마법사의 돌(philosophers-stone)`을 실행하고 싶다면 먼저 `harry` `v1` 버전을 다음과 같이 설치 해야 합니다:
+
+
+
+```console
+$ pip install "harry==1"
+```
+
+
+
+그러면 결국 전역 Python 환경에는 `harry` `v1`버전이 설치된 상태가 됩니다.
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[harry v1]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -->|requires| harry-1
+ end
+```
+
+하지만 이제 `아즈카반의 죄수(prisoner-of-azkaban)`을 실행하고 싶다면, `harry` `v1`버전을 제거하고 `harry` `v3`버전을 설치해야 합니다. (또는 단순히 `v3`버전을 설치하는 것만으로도 기존의 `v1`버전이 자동으로 제거됩니다.)
+
+
+
+```console
+$ pip install "harry==3"
+```
+
+
+
+그렇게 하면 이제 전역 Python 환경에는 `harry` `v3`버전이 설치된 상태가 됩니다.
+
+그리고 다시 `마법사의 돌(philosophers-stone)`을 실행하려고 하면, **작동하지** 않을 수 있습니다. 왜냐하면 이 프로그램은 `harry` `v1`버전을 필요로 하기 때문입니다.
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[harry v1]
+ style harry-1 fill:#ccc,stroke-dasharray: 5 5
+ harry-3[harry v3]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -.-x|⛔️| harry-1
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3
+ end
+```
+
+/// tip | 팁
+
+Python 패키지들은 **새 버전**에서 **호환성 문제(breaking changes)**가 발생하지 않도록 최대한 노력하는 것이 일반적입니다. 하지만 그래도 안전하게 작업하려면, 테스트를 실행해보면서 새 버전을 의도적으로 설치하는 것이 좋습니다.
+
+///
+
+이제, 이런 일이 여러분의 **모든 프로젝트**가 사용하는 **수많은 패키지들**에서 동시에 발생한다고 상상해보세요. 이는 매우 관리하기 어려우며, 결국 **서로 호환되지 않는 버전**의 패키지로 프로젝트를 실행하게 될 가능성이 높고, 그로 인해 어떤 문제가 왜 발생하는지 알 수 없게 될 수 있습니다.
+
+또한 사용하는 운영체제(Linux, Windows, macOS 등)에 따라 Python이 **미리 설치되어 있을 수도** 있습니다. 이런 경우에는 운영체제의 동작에 필요한 특정 버전의 패키지들이 함께 설치되어 있을 수 있습니다. 이 상태에서 전역 Python 환경에 임의의 패키지를 설치하면, 운영체제에 포함된 프로그램 일부가 **깨질 위험**도 있습니다.
+
+## 패키지들은 어디에 설치되는가
+
+Python을 설치하면, 컴퓨터에 여러 디렉터리와 파일들이 생성됩니다.
+
+이 중 일부 디렉터리는 사용자가 설치한 패키지들을 보관하는 역할을 합니다.
+
+예를 들어, 아래 명령어를 실행하면:
+
+
+
+```console
+// 지금 실행하지 않아도 됩니다, 그냥 예제일 뿐이에요 🤓
+$ pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+해당 명령어는 FastAPI 코드를 포함한 압축 파일을 다운로드합니다. 이 파일은 보통 PyPI에서 받아옵니다.
+
+또한 FastAPI가 의존하는 다른 패키지들도 함께 **다운로드**됩니다.
+
+그리고 그 모든 파일들을 **압축 해제**한 뒤, 컴퓨터의 특정 디렉터리에 저장합니다.
+
+기본적으로 이 파일들은 Python이 설치된 디렉터리 안, 즉 **전역 환경**에 내의 디렉터리에 저장됩니다.
+
+## 가상 환경이란
+
+전역 환경에 모든 패키지를 설치하면서 발생하는 문제에 대한 해결책은, 작업하는 **각 프로젝트마다 가상 환경**을 사용하는 것입니다.
+
+가상 환경은 전역 환경과 매우 유사한 하나의 **디렉터리**이며, 그 안에 해당 프로젝트를 위한 패키지들을 설치할 수 있습니다.
+
+이렇게 하면 각 프로젝트는 자체적인 가상 환경(`.venv` 디렉터리)을 가지게 되며, 그 안에 해당 프로젝트 전용 패키지들을 보유하게 됩니다.
+
+
+```mermaid
+flowchart TB
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) --->|requires| harry-1
+ subgraph venv1[.venv]
+ harry-1[harry v1]
+ end
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --->|requires| harry-3
+ subgraph venv2[.venv]
+ harry-3[harry v3]
+ end
+ end
+ stone-project ~~~ azkaban-project
+```
+
+## 가상 환경 활성화 의미
+
+가상 환경을 활성화한다는 것은, 예를 들어 다음과 같은 명령어를 실행하는 것을 의미합니다:
+
+//// tab | Linux, macOS
+
+
+
+////
+
+이 명령어는 이후에 실행될 명령어에서 사용될 [환경 변수](environment-variables.md){.internal-link target=_blank} 몇 개를 생성하거나 수정합니다.
+
+이 변수들 중 하나가 바로 `PATH` 변수입니다.
+
+/// tip | 팁
+
+`PATH` 환경 변수에 대해 더 알고 싶다면 [환경 변수 문서의 PATH 환경 변수 섹션](environment-variables.md#path-environment-variable){.internal-link target=_blank}을 참고하세요.
+
+///
+
+가상 환경을 활성화하면, 가상 환경의 경로인 `.venv/bin` (Linux와 macOS) 또는 `.venv\Scripts`(Windows)를 `PATH` 환경 변수에 추가됩니다.
+
+예를 들어, 가상 환경을 활성화하기 전의 `PATH` 변수는 다음과 같았다고 가정해봅시다:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+시스템은 다음 경로들에서 프로그램을 찾게 됩니다:
+
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Windows\System32
+```
+
+시스템은 다음 경로들에서 프로그램을 찾게 됩니다:
+
+* `C:\Windows\System32`
+
+////
+
+가상 환경을 활성화한 후에는, `PATH` 변수는 다음과 같은 형태가 됩니다:
+
+//// tab | Linux, macOS
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+시스템은 가장 먼저 다음 경로에서 프로그램을 찾기 시작합니다:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin
+```
+
+그 후에 다른 디렉터리들을 탐색합니다.
+
+따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에 있는 Python 프로그램을 찾게 됩니다:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+그리고 해당 Python을 사용하게 됩니다.
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
+```
+
+시스템은 가장 먼저 다음 경로에서 프로그램을 찾기 시작합니다:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts
+```
+
+그 후에 다른 디렉터리들을 탐색합니다.
+
+따라서 터미널에 `python`을 입력하면, 시스템은 다음 경로에 있는 Python 프로그램을 찾게 됩니다:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+그리고 해당 Python을 사용하게 됩니다.
+
+////
+
+중요한 세부 사항 중 하나는, 가상 환경의 경로가 `PATH` 변수의 가장 **앞**에 추가된다는 점입니다. 시스템은 사용 가능한 다른 Python들보다 **먼저** 이 경로를 찾습니다. 그래서 터미널에서 `python`을 실행하면, 전역 환경의 Python이 아닌 **가상 환경에 있는** Python이 사용됩니다. (예: 전역 환경에 설치된 `python`이 있더라도 그보다 우선합니다.)
+
+가상 환경을 활성화하면 이 외에도 몇 가지 다른 것들이 변경되지만, 이는 그중에서도 가장 중요한 변화 중 하나입니다.
+
+## 가상 환경 확인하기
+
+가상 환경이 활성화 되었는지 확인하려면, 아래 명령어를 사용할 수 있습니다:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+////
+
+즉, 현재 사용되는 `python` 프로그램은 **가상 환경 내부에 있는 것**입니다.
+
+Linux와 macOS에서는 `which`, Windows PowerShell에서는 `Get-Command` 명령어를 사용합니다.
+
+이 명령어는 `PATH` 환경 변수에 지정된 경로들을 **순서대로 탐색**하면서 `python`이라는 이름의 프로그램을 찾습니다.
+찾는 즉시, 해당 프로그램의 **경로를 출력**합니다.
+
+중요한 점은 터미널에서 `python`을 실행했을 때, 실제로 실행되는 "`python`"이 어떤 것인지 정확히 알 수 있다는 것입니다.
+
+따라서 현재 올바른 가상 환경에 있는지 확인할 수 있습니다.
+
+/// tip | 팁
+
+하나의 가상 환경을 활성화한 뒤, 해당 Python을 가진 상태에서 **또 다른 프로젝트**로 이동하는 것은 흔히 발생합니다.
+
+하지만 이때 이전 프로젝트의 가상 환경에 있는 **잘못된 Python 실행 파일**을 사용하게 되어 새 프로젝트가 **정상 작동하지 않을 수 있습니다.**
+
+그래서 현재 어떤 `python`이 사용되고 있는지 확인할 수 있는 능력은 매우 유용합니다. 🤓
+
+///
+
+## 가상 환경을 비활성화하는 이유
+
+예를 들어 `마법사의 돌(philosophers-stone)`이라는 프로젝트에서 작업 중이라고 해보겠습니다. 이때 해당 **가상 환경을 활성화**하고, 필요한 패키지를 설치하며 작업을 진행합니다.
+
+그런데 이제는 **다른 프로젝트**인 `아즈카반의 죄수(prisoner-of-azkaban)`을 작업하고 싶어졌습니다.
+
+그래서 그 프로젝트 디렉터리로 이동합니다:
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+```
+
+
+
+만약 `마법사의 돌(philosophers-stone)`의 가상 환경을 비활성화하지 않았다면, 터미널에서 `python`을 실행할 때 여전히 `마법사의 돌(philosophers-stone)` 가상 환경의 Python을 사용하게 됩니다.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+$ python main.py
+
+// sirius를 임포트하는 데 실패했습니다. 설치되어 있지 않아요 😱
+Traceback (most recent call last):
+ File "main.py", line 1, in
+ import sirius
+```
+
+
+
+하지만 `마법사의 돌(philosophers-stone)`의 가상 환경을 비활성화한 다음, `아즈카반의 죄수(prisoner-of-azkaban)` 프로젝트의 가상 환경을 활성화하면, 이제 `python` 명령어는 `아즈카반의 죄수(prisoner-of-azkaban)` 가상 환경의 Python을 사용하게 됩니다.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+// 이전 디렉터리에 있을 필요 없이, 어디서든 가상 환경을 비활성화할 수 있습니다. 다른 프로젝트 디렉터리로 이동한 후에도 괜찮아요 😎
+$ deactivate
+
+// prisoner-of-azkaban/.venv 가상 환경을 활성화합니다 🚀
+$ source .venv/bin/activate
+
+// 이제 python을 실행하면, 이 가상 환경에 설치된 sirius 패키지를 찾게 됩니다 ✨
+$ python main.py
+
+못된 짓을 꾸미고 있음을 엄숙히 맹세합니다.🧙
+ImportError는 이제 없습니다. 🐺
+```
+
+
+
+## 대안들
+
+이 문서는 여러분이 Python 프로젝트를 시작하고, **그 내부에서** 어떻게 돌아가는지 알려주는 간단한 가이드입니다.
+
+가상 환경, 패키지 의존성(Requirements), 프로젝트를 관리하는 방법에는 이 외에도 다양한 **대안**들이 존재합니다.
+
+만약 준비가 되었다면, **프로젝트 전체**, 패키지 의존성, 가상 환경 등을 통합적으로 **관리**할 수 있는 도구를 써보는 것도 좋습니다. 그럴 때 추천하는 도구가 바로 uv입니다.
+
+`uv`는 다양한 기능을 지원합니다:
+
+* 다양한 버전의 **Python 설치**
+* 각 프로젝트 별 **가상 환경 관리**
+* **패키지 설치**
+* 프로젝트의 **의존성과 버전** 관리
+* 설치된 패키지들과 그 버전을 **정확히 고정(lock)**해서,개발 환경과 운영 환경이 완전히 동일하게 작동할 수 있도록 보장
+* 이 외에도 다양한 기능을 지원
+
+## 결론
+
+여기까지 모두 읽고 이해했다면, 이제 많은 개발자들보다 가상 환경을 **훨씬 더 깊이 있게 이해**하게 되셨습니다. 🤓
+
+이런 세부적인 내용을 알고 있으면, 언젠가 복잡해 보이는 문제를 디버깅할 때 분명히 큰 도움이 될 것입니다. 이제는 **이 모든 것들이 내부에서 어떻게 작동하는지** 알고 있기 때문입니다. 😎
diff --git a/docs/nl/docs/index.md b/docs/nl/docs/index.md
index d88bb7771..32b20e31e 100644
--- a/docs/nl/docs/index.md
+++ b/docs/nl/docs/index.md
@@ -12,7 +12,7 @@
---
diff --git a/docs/pt/docs/advanced/additional-responses.md b/docs/pt/docs/advanced/additional-responses.md
index 58e75ad93..1060d18af 100644
--- a/docs/pt/docs/advanced/additional-responses.md
+++ b/docs/pt/docs/advanced/additional-responses.md
@@ -26,9 +26,7 @@ O **FastAPI** pegará este modelo, gerará o esquema JSON dele e incluirá no lo
Por exemplo, para declarar um outro retorno com o status code `404` e um modelo do Pydantic chamado `Message`, você pode escrever:
-```Python hl_lines="18 22"
-{!../../docs_src/additional_responses/tutorial001.py!}
-```
+{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *}
/// note | Nota
@@ -177,9 +175,7 @@ Você pode utilizar o mesmo parâmetro `responses` para adicionar diferentes med
Por exemplo, você pode adicionar um media type adicional de `image/png`, declarando que a sua *operação de caminho* pode retornar um objeto JSON (com o media type `application/json`) ou uma imagem PNG:
-```Python hl_lines="19-24 28"
-{!../../docs_src/additional_responses/tutorial002.py!}
-```
+{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *}
/// note | Nota
@@ -207,9 +203,7 @@ Por exemplo, você pode declarar um retorno com o código de status `404` que ut
E um retorno com o código de status `200` que utiliza o seu `response_model`, porém inclui um `example` customizado:
-```Python hl_lines="20-31"
-{!../../docs_src/additional_responses/tutorial003.py!}
-```
+{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *}
Isso será combinado e incluído em seu OpenAPI, e disponibilizado na documentação da sua API:
@@ -243,9 +237,7 @@ Você pode utilizar essa técnica para reutilizar alguns retornos predefinidos n
Por exemplo:
-```Python hl_lines="13-17 26"
-{!../../docs_src/additional_responses/tutorial004.py!}
-```
+{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *}
## Mais informações sobre retornos OpenAPI
diff --git a/docs/pt/docs/advanced/additional-status-codes.md b/docs/pt/docs/advanced/additional-status-codes.md
index 5fe970d2a..06d619151 100644
--- a/docs/pt/docs/advanced/additional-status-codes.md
+++ b/docs/pt/docs/advanced/additional-status-codes.md
@@ -14,57 +14,7 @@ Mas você também deseja aceitar novos itens. E quando os itens não existiam, e
Para conseguir isso, importe `JSONResponse` e retorne o seu conteúdo diretamente, definindo o `status_code` que você deseja:
-//// tab | Python 3.10+
-
-```Python hl_lines="4 25"
-{!> ../../docs_src/additional_status_codes/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="4 25"
-{!> ../../docs_src/additional_status_codes/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4 26"
-{!> ../../docs_src/additional_status_codes/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Dica
-
-Faça uso da versão `Annotated` quando possível.
-
-///
-
-```Python hl_lines="2 23"
-{!> ../../docs_src/additional_status_codes/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Faça uso da versão `Annotated` quando possível.
-
-///
-
-```Python hl_lines="4 25"
-{!> ../../docs_src/additional_status_codes/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
/// warning | Aviso
diff --git a/docs/pt/docs/advanced/advanced-dependencies.md b/docs/pt/docs/advanced/advanced-dependencies.md
index 52fe121f9..f57abba61 100644
--- a/docs/pt/docs/advanced/advanced-dependencies.md
+++ b/docs/pt/docs/advanced/advanced-dependencies.md
@@ -18,35 +18,7 @@ Não propriamente a classe (que já é um chamável), mas a instância desta cla
Para fazer isso, nós declaramos o método `__call__`:
-//// tab | Python 3.9+
-
-```Python hl_lines="12"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira utilizar a versão `Annotated` se possível.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
Neste caso, o `__call__` é o que o **FastAPI** utilizará para verificar parâmetros adicionais e sub dependências, e isso é o que será chamado para passar o valor ao parâmetro na sua *função de operação de rota* posteriormente.
@@ -54,35 +26,7 @@ Neste caso, o `__call__` é o que o **FastAPI** utilizará para verificar parâm
E agora, nós podemos utilizar o `__init__` para declarar os parâmetros da instância que podemos utilizar para "parametrizar" a dependência:
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="8"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira utilizar a versão `Annotated` se possível.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *}
Neste caso, o **FastAPI** nunca tocará ou se importará com o `__init__`, nós vamos utilizar diretamente em nosso código.
@@ -90,35 +34,7 @@ Neste caso, o **FastAPI** nunca tocará ou se importará com o `__init__`, nós
Nós poderíamos criar uma instância desta classe com:
-//// tab | Python 3.9+
-
-```Python hl_lines="18"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira utilizar a versão `Annotated` se possível.
-
-///
-
-```Python hl_lines="16"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *}
E deste modo nós podemos "parametrizar" a nossa dependência, que agora possui `"bar"` dentro dele, como o atributo `checker.fixed_content`.
@@ -134,35 +50,7 @@ checker(q="somequery")
...e passar o que quer que isso retorne como valor da dependência em nossa *função de operação de rota* como o parâmetro `fixed_content_included`:
-//// tab | Python 3.9+
-
-```Python hl_lines="22"
-{!> ../../docs_src/dependencies/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="21"
-{!> ../../docs_src/dependencies/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira utilizar a versão `Annotated` se possível.
-
-///
-
-```Python hl_lines="20"
-{!> ../../docs_src/dependencies/tutorial011.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
/// tip | Dica
diff --git a/docs/pt/docs/advanced/async-tests.md b/docs/pt/docs/advanced/async-tests.md
index 8fae97298..a2b79426c 100644
--- a/docs/pt/docs/advanced/async-tests.md
+++ b/docs/pt/docs/advanced/async-tests.md
@@ -32,15 +32,11 @@ Para um exemplos simples, vamos considerar uma estrutura de arquivos semelhante
O arquivo `main.py` teria:
-```Python
-{!../../docs_src/async_tests/main.py!}
-```
+{* ../../docs_src/async_tests/main.py *}
O arquivo `test_main.py` teria os testes para para o arquivo `main.py`, ele poderia ficar assim:
-```Python
-{!../../docs_src/async_tests/test_main.py!}
-```
+{* ../../docs_src/async_tests/test_main.py *}
## Executá-lo
@@ -60,9 +56,7 @@ $ pytest
O marcador `@pytest.mark.anyio` informa ao pytest que esta função de teste deve ser invocada de maneira assíncrona:
-```Python hl_lines="7"
-{!../../docs_src/async_tests/test_main.py!}
-```
+{* ../../docs_src/async_tests/test_main.py hl[7] *}
/// tip | Dica
@@ -72,9 +66,7 @@ Note que a função de teste é `async def` agora, no lugar de apenas `def` como
Então podemos criar um `AsyncClient` com a aplicação, e enviar requisições assíncronas para ela utilizando `await`.
-```Python hl_lines="9-12"
-{!../../docs_src/async_tests/test_main.py!}
-```
+{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
Isso é equivalente a:
diff --git a/docs/pt/docs/advanced/benchmarks.md b/docs/pt/docs/advanced/benchmarks.md
deleted file mode 100644
index 72ef1e444..000000000
--- a/docs/pt/docs/advanced/benchmarks.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# Benchmarks
-
-Benchmarks independentes da TechEmpower mostram que aplicações **FastAPI** rodando com o Uvicorn como um dos frameworks Python mais rápidos disponíveis, ficando atrás apenas do Starlette e Uvicorn (utilizado internamente pelo FastAPI).
-
-Porém, ao verificar benchmarks e comparações você deve prestar atenção ao seguinte:
-
-## Benchmarks e velocidade
-
-Quando você verifica os benchmarks, é comum ver diversas ferramentas de diferentes tipos comparados como se fossem equivalentes.
-
-Especificamente, para ver o Uvicorn, Starlette e FastAPI comparados entre si (entre diversas outras ferramentas).
-
-Quanto mais simples o problema resolvido pela ferramenta, melhor será a performance. E a maioria das análises não testa funcionalidades adicionais que são oferecidas pela ferramenta.
-
-A hierarquia é:
-
-* **Uvicorn**: um servidor ASGI
- * **Starlette**: (utiliza Uvicorn) um microframework web
- * **FastAPI**: (utiliza Starlette) um microframework para APIs com diversas funcionalidades adicionais para a construção de APIs, com validação de dados, etc.
-
-* **Uvicorn**:
- * Terá a melhor performance, pois não possui muito código além do próprio servidor.
- * Você não escreveria uma aplicação utilizando o Uvicorn diretamente. Isso significaria que o seu código teria que incluir pelo menos todo o código fornecido pelo Starlette (ou o **FastAPI**). E caso você fizesse isso, a sua aplicação final teria a mesma sobrecarga que teria se utilizasse um framework, minimizando o código e os bugs.
- * Se você está comparando o Uvicorn, compare com os servidores de aplicação Daphne, Hypercorn, uWSGI, etc.
-* **Starlette**:
- * Terá o melhor desempenho, depois do Uvicorn. Na verdade, o Starlette utiliza o Uvicorn para rodar. Portanto, ele pode ficar mais "devagar" que o Uvicorn apenas por ter que executar mais código.
- * Mas ele fornece as ferramentas para construir aplicações web simples, com roteamento baseado em caminhos, etc.
- * Se você está comparando o Starlette, compare-o com o Sanic, Flask, Django, etc. Frameworks web (ou microframeworks).
-* **FastAPI**:
- * Da mesma forma que o Starlette utiliza o Uvicorn e não consegue ser mais rápido que ele, o **FastAPI** utiliza o Starlette, portanto, ele não consegue ser mais rápido que ele.
- * O FastAPI provê mais funcionalidades em cima do Starlette. Funcionalidades que você quase sempre precisará quando estiver construindo APIs, como validação de dados e serialização. E ao utilizá-lo, você obtém documentação automática sem custo nenhum (a documentação automática sequer adiciona sobrecarga nas aplicações rodando, pois ela é gerada na inicialização).
- * Caso você não utilize o FastAPI e faz uso do Starlette diretamente (ou outra ferramenta, como o Sanic, Flask, Responder, etc) você mesmo teria que implementar toda a validação de dados e serialização. Então, a sua aplicação final ainda teria a mesma sobrecarga caso estivesse usando o FastAPI. E em muitos casos, validação de dados e serialização é a maior parte do código escrito em aplicações.
- * Então, ao utilizar o FastAPI, você está economizando tempo de programação, evitando bugs, linhas de código, e provavelmente terá a mesma performance (ou até melhor) do que teria caso você não o utilizasse (já que você teria que implementar tudo no seu código).
- * Se você está comparando o FastAPI, compare-o com frameworks de aplicações web (ou conjunto de ferramentas) que oferecem validação de dados, serialização e documentação, como por exemplo o Flask-apispec, NestJS, Molten, etc. Frameworks que possuem validação integrada de dados, serialização e documentação.
diff --git a/docs/pt/docs/advanced/custom-response.md b/docs/pt/docs/advanced/custom-response.md
index 5f673d7ce..a0bcc2b97 100644
--- a/docs/pt/docs/advanced/custom-response.md
+++ b/docs/pt/docs/advanced/custom-response.md
@@ -30,9 +30,7 @@ Isso ocorre por que, por padrão, o FastAPI irá verificar cada item dentro do d
Mas se você tem certeza que o conteúdo que você está retornando é **serializável com JSON**, você pode passá-lo diretamente para a classe de resposta e evitar o trabalho extra que o FastAPI teria ao passar o conteúdo pelo `jsonable_encoder` antes de passar para a classe de resposta.
-```Python hl_lines="2 7"
-{!../../docs_src/custom_response/tutorial001b.py!}
-```
+{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
/// info | Informação
@@ -57,9 +55,7 @@ Para retornar uma resposta com HTML diretamente do **FastAPI**, utilize `HTMLRes
* Importe `HTMLResponse`
* Passe `HTMLResponse` como o parâmetro de `response_class` do seu *decorador de operação de rota*.
-```Python hl_lines="2 7"
-{!../../docs_src/custom_response/tutorial002.py!}
-```
+{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
/// info | Informação
@@ -77,9 +73,7 @@ Como visto em [Retornando uma Resposta Diretamente](response-directly.md){.inter
O mesmo exemplo de antes, retornando uma `HTMLResponse`, poderia parecer com:
-```Python hl_lines="2 7 19"
-{!../../docs_src/custom_response/tutorial003.py!}
-```
+{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
/// warning | Aviso
@@ -103,9 +97,7 @@ A `response_class` será usada apenas para documentar o OpenAPI da *operação d
Por exemplo, poderia ser algo como:
-```Python hl_lines="7 21 23"
-{!../../docs_src/custom_response/tutorial004.py!}
-```
+{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
Neste exemplo, a função `generate_html_response()` já cria e retorna uma `Response` em vez de retornar o HTML em uma `str`.
@@ -144,9 +136,7 @@ Ela aceita os seguintes parâmetros:
O FastAPI (Starlette, na verdade) irá incluir o cabeçalho Content-Length automaticamente. Ele também irá incluir o cabeçalho Content-Type, baseado no `media_type` e acrescentando uma codificação para tipos textuais.
-```Python hl_lines="1 18"
-{!../../docs_src/response_directly/tutorial002.py!}
-```
+{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
### `HTMLResponse`
@@ -156,9 +146,7 @@ Usa algum texto ou sequência de bytes e retorna uma resposta HTML. Como você l
Usa algum texto ou sequência de bytes para retornar uma resposta de texto não formatado.
-```Python hl_lines="2 7 9"
-{!../../docs_src/custom_response/tutorial005.py!}
-```
+{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}
### `JSONResponse`
@@ -192,9 +180,7 @@ Essa resposta requer a instalação do pacote `ujson`, com o comando `pip instal
///
-```Python hl_lines="2 7"
-{!../../docs_src/custom_response/tutorial001.py!}
-```
+{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
/// tip | Dica
@@ -208,17 +194,13 @@ Retorna um redirecionamento HTTP. Utiliza o código de status 307 (Redirecioname
Você pode retornar uma `RedirectResponse` diretamente:
-```Python hl_lines="2 9"
-{!../../docs_src/custom_response/tutorial006.py!}
-```
+{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
---
Ou você pode utilizá-la no parâmetro `response_class`:
-```Python hl_lines="2 7 9"
-{!../../docs_src/custom_response/tutorial006b.py!}
-```
+{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *}
Se você fizer isso, então você pode retornar a URL diretamente da sua *função de operação de rota*
@@ -228,17 +210,13 @@ Neste caso, o `status_code` utilizada será o padrão de `RedirectResponse`, que
Você também pode utilizar o parâmetro `status_code` combinado com o parâmetro `response_class`:
-```Python hl_lines="2 7 9"
-{!../../docs_src/custom_response/tutorial006c.py!}
-```
+{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *}
### `StreamingResponse`
Recebe uma gerador assíncrono ou um gerador/iterador comum e retorna o corpo da requisição continuamente (stream).
-```Python hl_lines="2 14"
-{!../../docs_src/custom_response/tutorial007.py!}
-```
+{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
#### Utilizando `StreamingResponse` com objetos semelhantes a arquivos
@@ -279,15 +257,11 @@ Recebe um conjunto de argumentos do construtor diferente dos outros tipos de res
Respostas de Arquivos incluem o tamanho do arquivo, data da última modificação e ETags apropriados, nos cabeçalhos `Content-Length`, `Last-Modified` e `ETag`, respectivamente.
-```Python hl_lines="2 10"
-{!../../docs_src/custom_response/tutorial009.py!}
-```
+{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}
Você também pode usar o parâmetro `response_class`:
-```Python hl_lines="2 8 10"
-{!../../docs_src/custom_response/tutorial009b.py!}
-```
+{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *}
Nesse caso, você pode retornar o caminho do arquivo diretamente da sua *função de operação de rota*.
@@ -301,9 +275,7 @@ Vamos supor também que você queira retornar um JSON indentado e formatado, ent
Você poderia criar uma classe `CustomORJSONResponse`. A principal coisa a ser feita é sobrecarregar o método render da classe Response, `Response.render(content)`, que retorna o conteúdo em bytes, para retornar o conteúdo que você deseja:
-```Python hl_lines="9-14 17"
-{!../../docs_src/custom_response/tutorial009c.py!}
-```
+{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *}
Agora em vez de retornar:
@@ -329,9 +301,7 @@ O padrão que define isso é o `default_response_class`.
No exemplo abaixo, o **FastAPI** irá utilizar `ORJSONResponse` por padrão, em todas as *operações de rota*, em vez de `JSONResponse`.
-```Python hl_lines="2 4"
-{!../../docs_src/custom_response/tutorial010.py!}
-```
+{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
/// tip | Dica
diff --git a/docs/pt/docs/advanced/dataclasses.md b/docs/pt/docs/advanced/dataclasses.md
index af603ada7..600c8c268 100644
--- a/docs/pt/docs/advanced/dataclasses.md
+++ b/docs/pt/docs/advanced/dataclasses.md
@@ -4,9 +4,7 @@ FastAPI é construído em cima do **Pydantic**, e eu tenho mostrado como usar mo
Mas o FastAPI também suporta o uso de `dataclasses` da mesma forma:
-```Python hl_lines="1 7-12 19-20"
-{!../../docs_src/dataclasses/tutorial001.py!}
-```
+{* ../../docs_src/dataclasses/tutorial001.py hl[1,7:12,19:20] *}
Isso ainda é suportado graças ao **Pydantic**, pois ele tem suporte interno para `dataclasses`.
@@ -34,9 +32,7 @@ Mas se você tem um monte de dataclasses por aí, este é um truque legal para u
Você também pode usar `dataclasses` no parâmetro `response_model`:
-```Python hl_lines="1 7-13 19"
-{!../../docs_src/dataclasses/tutorial002.py!}
-```
+{* ../../docs_src/dataclasses/tutorial002.py hl[1,7:13,19] *}
A dataclass será automaticamente convertida para uma dataclass Pydantic.
diff --git a/docs/pt/docs/advanced/events.md b/docs/pt/docs/advanced/events.md
index 783dbfc83..504b6db57 100644
--- a/docs/pt/docs/advanced/events.md
+++ b/docs/pt/docs/advanced/events.md
@@ -31,9 +31,7 @@ Vamos iniciar com um exemplo e ver isso detalhadamente.
Nós criamos uma função assíncrona chamada `lifespan()` com `yield` como este:
-```Python hl_lines="16 19"
-{!../../docs_src/events/tutorial003.py!}
-```
+{* ../../docs_src/events/tutorial003.py hl[16,19] *}
Aqui nós estamos simulando a *inicialização* custosa do carregamento do modelo colocando a (falsa) função de modelo no dicionário com modelos de _machine learning_ antes do `yield`. Este código será executado **antes** da aplicação **começar a receber requisições**, durante a *inicialização*.
@@ -51,9 +49,7 @@ Talvez você precise inicializar uma nova versão, ou apenas cansou de executá-
A primeira coisa a notar, é que estamos definindo uma função assíncrona com `yield`. Isso é muito semelhante à Dependências com `yield`.
-```Python hl_lines="14-19"
-{!../../docs_src/events/tutorial003.py!}
-```
+{* ../../docs_src/events/tutorial003.py hl[14:19] *}
A primeira parte da função, antes do `yield`, será executada **antes** da aplicação inicializar.
@@ -65,9 +61,7 @@ Se você verificar, a função está decorada com um `@asynccontextmanager`.
Que converte a função em algo chamado de "**Gerenciador de Contexto Assíncrono**".
-```Python hl_lines="1 13"
-{!../../docs_src/events/tutorial003.py!}
-```
+{* ../../docs_src/events/tutorial003.py hl[1,13] *}
Um **gerenciador de contexto** em Python é algo que você pode usar em uma declaração `with`, por exemplo, `open()` pode ser usado como um gerenciador de contexto:
@@ -89,9 +83,7 @@ No nosso exemplo de código acima, nós não usamos ele diretamente, mas nós pa
O parâmetro `lifespan` da aplicação `FastAPI` usa um **Gerenciador de Contexto Assíncrono**, então nós podemos passar nosso novo gerenciador de contexto assíncrono do `lifespan` para ele.
-```Python hl_lines="22"
-{!../../docs_src/events/tutorial003.py!}
-```
+{* ../../docs_src/events/tutorial003.py hl[22] *}
## Eventos alternativos (deprecados)
@@ -113,9 +105,7 @@ Essas funções podem ser declaradas com `async def` ou `def` normal.
Para adicionar uma função que deve rodar antes da aplicação iniciar, declare-a com o evento `"startup"`:
-```Python hl_lines="8"
-{!../../docs_src/events/tutorial001.py!}
-```
+{* ../../docs_src/events/tutorial001.py hl[8] *}
Nesse caso, a função de manipulação de evento `startup` irá inicializar os itens do "banco de dados" (só um `dict`) com alguns valores.
@@ -127,9 +117,7 @@ E sua aplicação não irá começar a receber requisições até que todos os m
Para adicionar uma função que deve ser executada quando a aplicação estiver encerrando, declare ela com o evento `"shutdown"`:
-```Python hl_lines="6"
-{!../../docs_src/events/tutorial002.py!}
-```
+{* ../../docs_src/events/tutorial002.py hl[6] *}
Aqui, a função de manipulação de evento `shutdown` irá escrever uma linha de texto `"Application shutdown"` no arquivo `log.txt`.
diff --git a/docs/pt/docs/advanced/generate-clients.md b/docs/pt/docs/advanced/generate-clients.md
new file mode 100644
index 000000000..04d7c0071
--- /dev/null
+++ b/docs/pt/docs/advanced/generate-clients.md
@@ -0,0 +1,261 @@
+# Generate Clients
+
+Como o **FastAPI** é baseado na especificação **OpenAPI**, você obtém compatibilidade automática com muitas ferramentas, incluindo a documentação automática da API (fornecida pelo Swagger UI).
+
+Uma vantagem particular que nem sempre é óbvia é que você pode **gerar clientes** (às vezes chamados de **SDKs**) para a sua API, para muitas **linguagens de programação** diferentes.
+
+## Geradores de Clientes OpenAPI
+
+Existem muitas ferramentas para gerar clientes a partir do **OpenAPI**.
+
+Uma ferramenta comum é o OpenAPI Generator.
+
+Se voce está construindo um **frontend**, uma alternativa muito interessante é o openapi-ts.
+
+## Geradores de Clientes e SDKs - Patrocinadores
+
+Existem também alguns geradores de clientes e SDKs baseados na OpenAPI (FastAPI) **patrocinados por empresas**, em alguns casos eles podem oferecer **recursos adicionais** além de SDKs/clientes gerados de alta qualidade.
+
+Alguns deles também ✨ [**patrocinam o FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, isso garante o **desenvolvimento** contínuo e saudável do FastAPI e seu **ecossistema**.
+
+E isso mostra o verdadeiro compromisso deles com o FastAPI e sua **comunidade** (você), pois eles não apenas querem fornecer um **bom serviço**, mas também querem garantir que você tenha um **framework bom e saudável**, o FastAPI. 🙇
+
+Por exemplo, você pode querer experimentar:
+
+* Speakeasy
+* Stainless
+* liblab
+
+Existem também várias outras empresas que oferecem serviços semelhantes que você pode pesquisar e encontrar online. 🤓
+
+## Gerar um Cliente Frontend TypeScript
+
+Vamos começar com um aplicativo **FastAPI** simples:
+
+{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
+
+Note que as *operações de rota* definem os modelos que usam para o corpo da requisição e o corpo da resposta, usando os modelos `Item` e `ResponseMessage`.
+
+### Documentação da API
+
+Se você acessar a documentação da API, verá que ela tem os **schemas** para os dados a serem enviados nas requisições e recebidos nas respostas:
+
+
+
+Você pode ver esses schemas porque eles foram declarados com os modelos no app.
+
+Essas informações estão disponíveis no **OpenAPI schema** do app e são mostradas na documentação da API (pelo Swagger UI).
+
+E essas mesmas informações dos modelos que estão incluídas no OpenAPI são o que pode ser usado para **gerar o código do cliente**.
+
+### Gerar um Cliente TypeScript
+
+Agora que temos o app com os modelos, podemos gerar o código do cliente para o frontend.
+
+#### Instalar o `openapi-ts`
+
+Você pode instalar o `openapi-ts` no seu código frontend com:
+
+
+
+#### Gerar o Código do Cliente
+
+Para gerar o código do cliente, você pode usar a aplicação de linha de comando `openapi-ts` que agora está instalada.
+
+Como ela está instalada no projeto local, você provavelmente não conseguiria chamar esse comando diretamente, mas você o colocaria no seu arquivo `package.json`.
+
+Poderia ser assim:
+
+```JSON hl_lines="7"
+{
+ "name": "frontend-app",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "generate-client": "openapi-ts --input http://localhost:8000/openapi.json --output ./src/client --client axios"
+ },
+ "author": "",
+ "license": "",
+ "devDependencies": {
+ "@hey-api/openapi-ts": "^0.27.38",
+ "typescript": "^4.6.2"
+ }
+}
+```
+
+Depois de ter esse script NPM `generate-client` lá, você pode executá-lo com:
+
+
-
-Isso criará o diretório `./env/` com os binários Python e então você será capaz de instalar pacotes nesse ambiente isolado.
-
-### Ativar o ambiente
-
-Ative o novo ambiente com:
-
-//// tab | Linux, macOS
-
-
-
-////
-
-Se ele exibir o binário `pip` em `env/bin/pip` então funcionou. 🎉
-
-
-
-/// tip
-
-Toda vez que você instalar um novo pacote com `pip` nesse ambiente, ative o ambiente novamente.
-
-Isso garante que se você usar um programa instalado por aquele pacote, você utilizará aquele de seu ambiente local e não outro que possa estar instalado globalmente.
-
-///
-
-### pip
-
-Após ativar o ambiente como descrito acima:
-
-
-
-Isso irá instalar todas as dependências e seu FastAPI local em seu ambiente local.
-
-#### Usando seu FastAPI local
-
-Se você cria um arquivo Python que importa e usa FastAPI, e roda com Python de seu ambiente local, ele irá utilizar o código fonte de seu FastAPI local.
-
-E se você atualizar o código fonte do FastAPI local, como ele é instalado com `-e`, quando você rodar aquele arquivo Python novamente, ele irá utilizar a nova versão do FastAPI que você acabou de editar.
-
-Desse modo, você não tem que "instalar" sua versão local para ser capaz de testar cada mudança.
-
-### Formato
-
-Tem um arquivo que você pode rodar que irá formatar e limpar todo o seu código:
-
-
-
-```console
-$ bash scripts/format.sh
-```
-
-
-
-Ele irá organizar também todos os seus imports.
-
-Para que ele organize os imports corretamente, você precisa ter o FastAPI instalado localmente em seu ambiente, com o comando na seção acima usando `-e`.
-
-### Formato dos imports
-
-Tem outro _script_ que formata todos os imports e garante que você não tenha imports não utilizados:
-
-
-
-Como ele roda um comando após o outro, modificando e revertendo muitos arquivos, ele demora um pouco para concluir, então pode ser um pouco mais fácil utilizar `scripts/format.sh` frequentemente e `scripts/format-imports.sh` somente após "commitar uma branch".
-
-## Documentação
-
-Primeiro, tenha certeza de configurar seu ambiente como descrito acima, isso irá instalar todas as requisições.
-
-A documentação usa MkDocs.
-
-E existem ferramentas/_scripts_ extras para controlar as traduções em `./scripts/docs.py`.
-
-/// tip
-
-Você não precisa ver o código em `./scripts/docs.py`, você apenas o utiliza na linha de comando.
-
-///
-
-Toda a documentação está no formato Markdown no diretório `./docs/pt/`.
-
-Muitos dos tutoriais tem blocos de código.
-
-Na maioria dos casos, esse blocos de código são aplicações completas que podem ser rodadas do jeito que estão apresentados.
-
-De fato, esses blocos de código não estão escritos dentro do Markdown, eles são arquivos Python dentro do diretório `./docs_src/`.
-
-E esses arquivos Python são incluídos/injetados na documentação quando se gera o site.
-
-### Testes para Documentação
-
-A maioria dos testes na verdade rodam encima dos arquivos fonte na documentação.
-
-Isso ajuda a garantir:
-
-* Que a documentação esteja atualizada.
-* Que os exemplos da documentação possam ser rodadas do jeito que estão apresentadas.
-* A maior parte dos recursos é coberta pela documentação, garantida por cobertura de testes.
-
-Durante o desenvolvimento local, existe um _script_ que constrói o site e procura por quaisquer mudanças, carregando na hora:
-
-
-
-Isso irá servir a documentação em `http://127.0.0.1:8008`.
-
-Desse jeito, você poderá editar a documentação/arquivos fonte e ver as mudanças na hora.
-
-#### Typer CLI (opcional)
-
-As instruções aqui mostram como utilizar _scripts_ em `./scripts/docs.py` com o programa `python` diretamente.
-
-Mas você pode usar também Typer CLI, e você terá auto-completação para comandos no seu terminal após instalar o _completion_.
-
-Se você instalou Typer CLI, você pode instalar _completion_ com:
-
-
-
-```console
-$ typer --install-completion
-
-zsh completion installed in /home/user/.bashrc.
-Completion will take effect once you restart the terminal.
-```
-
-
-
-### Aplicações e documentação ao mesmo tempo
-
-Se você rodar os exemplos com, por exemplo:
-
-
-
-```console
-$ uvicorn tutorial001:app --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-como Uvicorn utiliza por padrão a porta `8000`, a documentação na porta `8008` não dará conflito.
-
-### Traduções
-
-Ajuda com traduções É MUITO apreciada! E essa tarefa não pode ser concluída sem a ajuda da comunidade. 🌎 🚀
-
-Aqui estão os passos para ajudar com as traduções.
-
-#### Dicas e orientações
-
-* Verifique sempre os _pull requests_ existentes para a sua linguagem e faça revisões das alterações e aprove elas.
-
-/// tip
-
-Você pode adicionar comentários com sugestões de alterações para _pull requests_ existentes.
-
-Verifique as documentações sobre adicionar revisão ao _pull request_ para aprovação ou solicitação de alterações.
-
-///
-
-* Verifique em _issues_ para ver se existe alguém coordenando traduções para a sua linguagem.
-
-* Adicione um único _pull request_ por página traduzida. Isso tornará muito mais fácil a revisão para as outras pessoas.
-
-Para as linguagens que eu não falo, vou esperar por várias pessoas revisarem a tradução antes de _mergear_.
-
-* Você pode verificar também se há traduções para sua linguagem e adicionar revisão para elas, isso irá me ajudar a saber que a tradução está correta e eu possa _mergear_.
-
-* Utilize os mesmos exemplos Python e somente traduza o texto na documentação. Você não tem que alterar nada no código para que funcione.
-
-* Utilize as mesmas imagens, nomes de arquivo e links. Você não tem que alterar nada disso para que funcione.
-
-* Para verificar o código de duas letras para a linguagem que você quer traduzir, você pode usar a Lista de códigos ISO 639-1.
-
-#### Linguagem existente
-
-Vamos dizer que você queira traduzir uma página para uma linguagem que já tenha traduções para algumas páginas, como o Espanhol.
-
-No caso do Espanhol, o código de duas letras é `es`. Então, o diretório para traduções em Espanhol está localizada em `docs/es/`.
-
-/// tip
-
-A principal ("oficial") linguagem é o Inglês, localizado em `docs/en/`.
-
-///
-
-Agora rode o _servidor ao vivo_ para as documentações em Espanhol:
-
-
-
-```console
-// Use o comando "live" e passe o código da linguagem como um argumento de linha de comando
-$ python ./scripts/docs.py live es
-
-[INFO] Serving on http://127.0.0.1:8008
-[INFO] Start watching changes
-[INFO] Start detecting changes
-```
-
-
-
-Agora você pode ir em http://127.0.0.1:8008 e ver suas mudanças ao vivo.
-
-Se você procurar no site da documentação do FastAPI, você verá que toda linguagem tem todas as páginas. Mas algumas páginas não estão traduzidas e tem notificação sobre a falta da tradução.
-
-Mas quando você rodar localmente como descrito acima, você somente verá as páginas que já estão traduzidas.
-
-Agora vamos dizer que você queira adicionar uma tradução para a seção [Recursos](features.md){.internal-link target=_blank}.
-
-* Copie o arquivo em:
-
-```
-docs/en/docs/features.md
-```
-
-* Cole ele exatamente no mesmo local mas para a linguagem que você quer traduzir, por exemplo:
-
-```
-docs/es/docs/features.md
-```
-
-/// tip
-
-Observe que a única mudança na rota é o código da linguagem, de `en` para `es`.
-
-///
-
-* Agora abra o arquivo de configuração MkDocs para Inglês em:
-
-```
-docs/en/docs/mkdocs.yml
-```
-
-* Procure o lugar onde `docs/features.md` está localizado no arquivo de configuração. Algum lugar como:
-
-```YAML hl_lines="8"
-site_name: FastAPI
-# Mais coisas
-nav:
-- FastAPI: index.md
-- Languages:
- - en: /
- - es: /es/
-- features.md
-```
-
-* Abra o arquivo de configuração MkDocs para a linguagem que você está editando, por exemplo:
-
-```
-docs/es/docs/mkdocs.yml
-```
-
-* Adicione no mesmo local que está no arquivo em Inglês, por exemplo:
-
-```YAML hl_lines="8"
-site_name: FastAPI
-# Mais coisas
-nav:
-- FastAPI: index.md
-- Languages:
- - en: /
- - es: /es/
-- features.md
-```
-
-Tenha certeza que se existem outras entradas, a nova entrada com sua tradução esteja exatamente na mesma ordem como na versão em Inglês.
-
-Se você for no seu navegador verá que agora a documentação mostra sua nova seção. 🎉
-
-Agora você poderá traduzir tudo e ver como está toda vez que salva o arquivo.
-
-#### Nova linguagem
-
-Vamos dizer que você queira adicionar traduções para uma linguagem que ainda não foi traduzida, nem sequer uma página.
-
-Vamos dizer que você queira adicionar tradução para Haitiano, e ainda não tenha na documentação.
-
-Verificando o link acima, o código para "Haitiano" é `ht`.
-
-O próximo passo é rodar o _script_ para gerar um novo diretório de tradução:
-
-
-
-```console
-// Use o comando new-lang, passe o código da linguagem como um argumento de linha de comando
-$ python ./scripts/docs.py new-lang ht
-
-Successfully initialized: docs/ht
-Updating ht
-Updating en
-```
-
-
-
-Agora você pode verificar em seu editor de código o mais novo diretório criado `docs/ht/`.
-
-/// tip
-
-Crie um primeiro _pull request_ com apenas isso, para iniciar a configuração da nova linguagem, antes de adicionar traduções.
-
-Desse modo outros poderão ajudar com outras páginas enquanto você trabalha na primeira. 🚀
-
-///
-
-Inicie traduzindo a página principal, `docs/ht/index.md`.
-
-Então você pode continuar com as instruções anteriores, para uma "Linguagem Existente".
-
-##### Nova linguagem não suportada
-
-Se quando rodar o _script_ do _servidor ao vivo_ você pega um erro sobre linguagem não suportada, alguma coisa como:
-
-```
- raise TemplateNotFound(template)
-jinja2.exceptions.TemplateNotFound: partials/language/xx.html
-```
-
-Isso significa que o tema não suporta essa linguagem (nesse caso, com um código falso de duas letras `xx`).
-
-Mas não se preocupe, você pode configurar o tema de linguagem para Inglês e então traduzir o conteúdo da documentação.
-
-Se você precisar fazer isso, edite o `mkdocs.yml` para sua nova linguagem, teremos algo como:
-
-```YAML hl_lines="5"
-site_name: FastAPI
-# Mais coisas
-theme:
- # Mais coisas
- language: xx
-```
-
-Altere essa linguagem de `xx` (do seu código de linguagem) para `en`.
-
-Então você poderá iniciar novamente o _servidor ao vivo_.
-
-#### Pré-visualize o resultado
-
-Quando você usa o _script_ em `./scripts/docs.py` com o comando `live` ele somente exibe os arquivos e traduções disponíveis para a linguagem atual.
-
-Mas uma vez que você tenha concluído, você poderá testar tudo como se parecesse _online_.
-
-Para fazer isso, primeiro construa toda a documentação:
-
-
-
-```console
-// Use o comando "build-all", isso leverá um tempinho
-$ python ./scripts/docs.py build-all
-
-Updating es
-Updating en
-Building docs for: en
-Building docs for: es
-Successfully built docs for: es
-Copying en index.md to README.md
-```
-
-
-
-Isso gera toda a documentação em `./docs_build/` para cada linguagem. Isso inclui a adição de quaisquer arquivos com tradução faltando, com uma nota dizendo que "esse arquivo ainda não tem tradução". Mas você não tem que fazer nada com esse diretório.
-
-Então ele constrói todos aqueles _sites_ independentes MkDocs para cada linguagem, combina eles, e gera a saída final em `./site/`.
-
-Então você poderá "servir" eles com o comando `serve`:
-
-
-
-```console
-// Use o comando "serve" após rodar "build-all"
-$ python ./scripts/docs.py serve
-
-Warning: this is a very simple server. For development, use mkdocs serve instead.
-This is here only to preview a site with translations already built.
-Make sure you run the build-all command first.
-Serving at: http://127.0.0.1:8008
-```
-
-
-
-## Testes
-
-Tem um _script_ que você pode rodar localmente para testar todo o código e gerar relatórios de cobertura em HTML:
-
-
-
-Esse comando gera um diretório `./htmlcov/`, se você abrir o arquivo `./htmlcov/index.html` no seu navegador, poderá explorar interativamente as regiões de código que estão cobertas pelos testes, e observar se existe alguma região faltando.
-
-### Testes no seu editor
-
-Se você quer usar os testes integrados em seu editor adicione `./docs_src` na sua variável `PYTHONPATH`.
-
-Por exemplo, no VS Code você pode criar um arquivo `.env` com:
-
-```env
-PYTHONPATH=./docs_src
-```
diff --git a/docs/pt/docs/deployment/concepts.md b/docs/pt/docs/deployment/concepts.md
index 8cf70d0b4..014ca3797 100644
--- a/docs/pt/docs/deployment/concepts.md
+++ b/docs/pt/docs/deployment/concepts.md
@@ -216,7 +216,7 @@ Este Processo de Gerenciador provavelmente seria o que escutaria na **porta** no
Esses processos de trabalho seriam aqueles que executariam seu aplicativo, eles executariam os cálculos principais para receber uma **solicitação** e retornar uma **resposta**, e carregariam qualquer coisa que você colocasse em variáveis na RAM.
-
+
E, claro, a mesma máquina provavelmente teria **outros processos** em execução, além do seu aplicativo.
diff --git a/docs/pt/docs/deployment/https.md b/docs/pt/docs/deployment/https.md
index 9a13977ec..904d04eaa 100644
--- a/docs/pt/docs/deployment/https.md
+++ b/docs/pt/docs/deployment/https.md
@@ -14,38 +14,186 @@ Para aprender o básico de HTTPS de uma perspectiva do usuário, verifique SNI.
- * Esta extensão SNI permite que um único servidor (com um único endereço IP) tenha vários certificados HTTPS e atenda a vários domínios / aplicativos HTTPS.
- * Para que isso funcione, um único componente (programa) em execução no servidor, ouvindo no endereço IP público, deve ter todos os certificados HTTPS no servidor.
-* Depois de obter uma conexão segura, o protocolo de comunicação ainda é HTTP.
- * Os conteúdos são criptografados, embora sejam enviados com o protocolo HTTP.
+ * No entanto, existe uma **solução** para isso.
+* Há uma **extensão** para o protocolo **TLS** (aquele que lida com a criptografia no nível TCP, antes do HTTP) chamado **SNI**.
+ * Esta extensão SNI permite que um único servidor (com um **único endereço IP**) tenha **vários certificados HTTPS** e atenda a **vários domínios / aplicativos HTTPS**.
+ * Para que isso funcione, um **único** componente (programa) em execução no servidor, ouvindo no **endereço IP público**, deve ter **todos os certificados HTTPS** no servidor.
+* **Depois** de obter uma conexão segura, o protocolo de comunicação **ainda é HTTP**.
+ * Os conteúdos são **criptografados**, embora sejam enviados com o **protocolo HTTP**.
-É uma prática comum ter um programa/servidor HTTP em execução no servidor (máquina, host, etc.) e gerenciar todas as partes HTTPS: enviando as solicitações HTTP descriptografadas para o aplicativo HTTP real em execução no mesmo servidor (a aplicação **FastAPI**, neste caso), pegue a resposta HTTP do aplicativo, criptografe-a usando o certificado apropriado e envie-a de volta ao cliente usando HTTPS. Este servidor é frequentemente chamado de TLS Termination Proxy.
+É uma prática comum ter um **programa/servidor HTTP** em execução no servidor (máquina, host, etc.) e **gerenciar todas as partes HTTPS**: **recebendo as requisições encriptadas**, enviando as **solicitações HTTP descriptografadas** para o aplicativo HTTP real em execução no mesmo servidor (a aplicação **FastAPI**, neste caso), pegue a **resposta HTTP** do aplicativo, **criptografe-a** usando o **certificado HTTPS** apropriado e envie-a de volta ao cliente usando **HTTPS**. Este servidor é frequentemente chamado de **Proxy de Terminação TLS**.
+
+Algumas das opções que você pode usar como Proxy de Terminação TLS são:
+
+* Traefik (que também pode gerenciar a renovação de certificados)
+* Caddy (que também pode gerenciar a renovação de certificados)
+* Nginx
+* HAProxy
## Let's Encrypt
-Antes de Let's Encrypt, esses certificados HTTPS eram vendidos por terceiros confiáveis.
+Antes de Let's Encrypt, esses **certificados HTTPS** eram vendidos por terceiros confiáveis.
O processo de aquisição de um desses certificados costumava ser complicado, exigia bastante papelada e os certificados eram bastante caros.
-Mas então Let's Encrypt foi criado.
+Mas então o **Let's Encrypt** foi criado.
-Ele é um projeto da Linux Foundation que fornece certificados HTTPS gratuitamente. De forma automatizada. Esses certificados usam toda a segurança criptográfica padrão e têm vida curta (cerca de 3 meses), então a segurança é realmente melhor por causa de sua vida útil reduzida.
+Ele é um projeto da Linux Foundation que fornece **certificados HTTPS gratuitamente** . De forma automatizada. Esses certificados usam toda a segurança criptográfica padrão e têm vida curta (cerca de 3 meses), então a **segurança é, na verdade, melhor** por causa de sua vida útil reduzida.
Os domínios são verificados com segurança e os certificados são gerados automaticamente. Isso também permite automatizar a renovação desses certificados.
-A ideia é automatizar a aquisição e renovação desses certificados, para que você tenha HTTPS seguro, de graça e para sempre.
+A ideia é automatizar a aquisição e renovação desses certificados, para que você tenha **HTTPS seguro, de graça e para sempre**.
+
+## HTTPS para Desenvolvedores
+
+Aqui está um exemplo de como uma API HTTPS poderia ser estruturada, passo a passo, com foco principal nas ideias relevantes para desenvolvedores.
+
+### Nome do domínio
+
+A etapa inicial provavelmente seria **adquirir** algum **nome de domínio**. Então, você iria configurá-lo em um servidor DNS (possivelmente no mesmo provedor em nuvem).
+
+Você provavelmente usaria um servidor em nuvem (máquina virtual) ou algo parecido, e ele teria fixed **Endereço IP público**.
+
+No(s) servidor(es) DNS, você configuraria um registro (`registro A`) para apontar **seu domínio** para o **endereço IP público do seu servidor**.
+
+Você provavelmente fará isso apenas uma vez, na primeira vez em que tudo estiver sendo configurado.
+
+/// tip | Dica
+
+Essa parte do Nome do Domínio se dá muito antes do HTTPS, mas como tudo depende do domínio e endereço IP público, vale a pena mencioná-la aqui.
+
+///
+
+### DNS
+
+Agora vamos focar em todas as partes que realmente fazem parte do HTTPS.
+
+Primeiro, o navegador iria verificar com os **servidores DNS** qual o **IP do domínio**, nesse caso, `someapp.example.com`.
+
+Os servidores DNS iriam informar o navegador para utilizar algum **endereço IP** específico. Esse seria o endereço IP público em uso no seu servidor, que você configurou nos servidores DNS.
+
+
+
+### Início do Handshake TLS
+
+O navegador então irá comunicar-se com esse endereço IP na **porta 443** (a porta HTTPS).
+
+A primeira parte dessa comunicação é apenas para estabelecer a conexão entre o cliente e o servidor e para decidir as chaves criptográficas a serem utilizadas, etc.
+
+
+
+Esse interação entre o cliente e o servidor para estabelecer uma conexão TLS é chamada de **Handshake TLS**.
+
+### TLS com a Extensão SNI
+
+**Apenas um processo** no servidor pode se conectar a uma **porta** em um **endereço IP**. Poderiam existir outros processos conectados em outras portas desse mesmo endereço IP, mas apenas um para cada combinação de endereço IP e porta.
+
+TLS (HTTPS) usa a porta `443` por padrão. Então essa é a porta que precisamos.
+
+Como apenas um único processo pode se comunicar com essa porta, o processo que faria isso seria o **Proxy de Terminação TLS**.
+
+O Proxy de Terminação TLS teria acesso a um ou mais **certificados TLS** (certificados HTTPS).
+
+Utilizando a **extensão SNI** discutida acima, o Proxy de Terminação TLS iria checar qual dos certificados TLS (HTTPS) disponíveis deve ser usado para essa conexão, utilizando o que corresponda ao domínio esperado pelo cliente.
+
+Nesse caso, ele usaria o certificado para `someapp.example.com`.
+
+
+
+O cliente já **confia** na entidade que gerou o certificado TLS (nesse caso, o Let's Encrypt, mas veremos sobre isso mais tarde), então ele pode **verificar** que o certificado é válido.
+
+Então, utilizando o certificado, o cliente e o Proxy de Terminação TLS **decidem como encriptar** o resto da **comunicação TCP**. Isso completa a parte do **Handshake TLS**.
+
+Após isso, o cliente e o servidor possuem uma **conexão TCP encriptada**, que é provida pelo TLS. E então eles podem usar essa conexão para começar a **comunicação HTTP** propriamente dita.
+
+E isso resume o que é **HTTPS**, apenas **HTTP** simples dentro de uma **conexão TLS segura** em vez de uma conexão TCP pura (não encriptada).
+
+/// tip | Dica
+
+Percebe que a encriptação da comunicação acontece no **nível do TCP**, não no nível do HTTP.
+
+///
+
+### Solicitação HTTPS
+
+Agora que o cliente e servidor (especialmente o navegador e o Proxy de Terminação TLS) possuem uma **conexão TCP encriptada**, eles podem iniciar a **comunicação HTTP**.
+
+Então, o cliente envia uma **solicitação HTTPS**. Que é apenas uma solicitação HTTP sobre uma conexão TLS encriptada.
+
+
+
+### Desencriptando a Solicitação
+
+O Proxy de Terminação TLS então usaria a encriptação combinada para **desencriptar a solicitação**, e transmitiria a **solicitação básica (desencriptada)** para o processo executando a aplicação (por exemplo, um processo com Uvicorn executando a aplicação FastAPI).
+
+
+
+### Resposta HTTP
+
+A aplicação processaria a solicitação e retornaria uma **resposta HTTP básica (não encriptada)** para o Proxy de Terminação TLS.
+
+
+
+### Resposta HTTPS
+
+O Proxy de Terminação TLS iria **encriptar a resposta** utilizando a criptografia combinada anteriormente (que foi definida com o certificado para `someapp.example.com`), e devolveria para o navegador.
+
+No próximo passo, o navegador verifica que a resposta é válida e encriptada com a chave criptográfica correta, etc. E depois **desencripta a resposta** e a processa.
+
+
+
+O cliente (navegador) saberá que a resposta vem do servidor correto por que ela usa a criptografia que foi combinada entre eles usando o **certificado HTTPS** anterior.
+
+### Múltiplas Aplicações
+
+Podem existir **múltiplas aplicações** em execução no mesmo servidor (ou servidores), por exemplo: outras APIs ou um banco de dados.
+
+Apenas um processo pode estar vinculado a um IP e porta (o Proxy de Terminação TLS, por exemplo), mas outras aplicações/processos também podem estar em execução no(s) servidor(es), desde que não tentem usar a mesma **combinação de IP público e porta**.
+
+
+
+Dessa forma, o Proxy de Terminação TLS pode gerenciar o HTTPS e os certificados de **múltiplos domínios**, para múltiplas aplicações, e então transmitir as requisições para a aplicação correta em cada caso.
+
+### Renovação de Certificados
+
+Em algum momento futuro, cada certificado irá **expirar** (aproximadamente 3 meses após a aquisição).
+
+E então, haverá outro programa (em alguns casos pode ser o próprio Proxy de Terminação TLS) que irá interagir com o Let's Encrypt e renovar o(s) certificado(s).
+
+
+
+Os **certificados TLS** são **associados com um nome de domínio**, e não a um endereço IP.
+
+Então para renovar os certificados, o programa de renovação precisa **provar** para a autoridade (Let's Encrypt) que ele realmente **possui e controla esse domínio**>
+
+Para fazer isso, e acomodar as necessidades de diferentes aplicações, existem diferentes opções para esse programa. Algumas escolhas populares são:
+
+* **Modificar alguns registros DNS**
+ * Para isso, o programa de renovação precisa ter suporte as APIs do provedor DNS, então, dependendo do provedor DNS que você utilize, isso pode ou não ser uma opção viável.
+* **Executar como um servidor** (ao menos durante o processo de aquisição do certificado) no endereço IP público associado com o domínio.
+ * Como dito anteriormente, apenas um processo pode estar ligado a uma porta e IP específicos.
+ * Essa é uma dos motivos que fazem utilizar o mesmo Proxy de Terminação TLS para gerenciar a renovação de certificados ser tão útil.
+ * Caso contrário, você pode ter que parar a execução do Proxy de Terminação TLS momentaneamente, inicializar o programa de renovação para renovar os certificados, e então reiniciar o Proxy de Terminação TLS. Isso não é o ideal, já que sua(s) aplicação(ões) não vão estar disponíveis enquanto o Proxy de Terminação TLS estiver desligado.
+
+Todo esse processo de renovação, enquanto o aplicativo ainda funciona, é uma das principais razões para preferir um **sistema separado para gerenciar HTTPS** com um Proxy de Terminação TLS em vez de usar os certificados TLS no servidor da aplicação diretamente (e.g. com o Uvicorn).
+
+## Recapitulando
+
+Possuir **HTTPS** habilitado na sua aplicação é bastante importante, e até **crítico** na maioria dos casos. A maior parte do esforço que você tem que colocar sobre o HTTPS como desenvolvedor está em **entender esses conceitos** e como eles funcionam.
+
+Mas uma vez que você saiba o básico de **HTTPS para desenvolvedores**, você pode combinar e configurar diferentes ferramentas facilmente para gerenciar tudo de uma forma simples.
+
+Em alguns dos próximos capítulos, eu mostrarei para você vários exemplos concretos de como configurar o **HTTPS** para aplicações **FastAPI**. 🔒
diff --git a/docs/pt/docs/deployment/manually.md b/docs/pt/docs/deployment/manually.md
index 237f4f8b9..46e580807 100644
--- a/docs/pt/docs/deployment/manually.md
+++ b/docs/pt/docs/deployment/manually.md
@@ -7,45 +7,33 @@ Em resumo, utilize o comando `fastapi run` para inicializar sua aplicação Fast
```console
-$ fastapi run main.py
-INFO Using path main.py
-INFO Resolved absolute path /home/user/code/awesomeapp/main.py
-INFO Searching for package file structure from directories with __init__.py files
-INFO Importing from /home/user/code/awesomeapp
-
- ╭─ Python module file ─╮
- │ │
- │ 🐍 main.py │
- │ │
- ╰──────────────────────╯
-
-INFO Importing module main
-INFO Found importable FastAPI app
-
- ╭─ Importable FastAPI app ─╮
- │ │
- │ from main import app │
- │ │
- ╰──────────────────────────╯
-
-INFO Using import string main:app
-
- ╭─────────── FastAPI CLI - Production mode ───────────╮
- │ │
- │ Serving at: http://0.0.0.0:8000 │
- │ │
- │ API docs: http://0.0.0.0:8000/docs │
- │ │
- │ Running in production mode, for development use: │
- │ │
- │ fastapi dev │
- │ │
- ╰─────────────────────────────────────────────────────╯
-
-INFO: Started server process [2306215]
-INFO: Waiting for application startup.
-INFO: Application startup complete.
-INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
+$ fastapi run main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories
+ with __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with
+ the following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Started server process [2306215]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Uvicorn running on http://0.0.0.0:8000(Press CTRL+C
+ to quit)
```
diff --git a/docs/pt/docs/deployment/server-workers.md b/docs/pt/docs/deployment/server-workers.md
index 63eda56b4..a0db1bea4 100644
--- a/docs/pt/docs/deployment/server-workers.md
+++ b/docs/pt/docs/deployment/server-workers.md
@@ -36,56 +36,43 @@ Se você usar o comando `fastapi`:
```console
-$
fastapi run --workers 4 main.py
-INFO Using path main.py
-INFO Resolved absolute path /home/user/code/awesomeapp/main.py
-INFO Searching for package file structure from directories with __init__.py files
-INFO Importing from /home/user/code/awesomeapp
-
- ╭─ Python module file ─╮
- │ │
- │ 🐍 main.py │
- │ │
- ╰──────────────────────╯
-
-INFO Importing module main
-INFO Found importable FastAPI app
-
- ╭─ Importable FastAPI app ─╮
- │ │
- │ from main import app │
- │ │
- ╰──────────────────────────╯
-
-INFO Using import string main:app
-
- ╭─────────── FastAPI CLI - Production mode ───────────╮
- │ │
- │ Serving at: http://0.0.0.0:8000 │
- │ │
- │ API docs: http://0.0.0.0:8000/docs │
- │ │
- │ Running in production mode, for development use: │
- │ │
- │ fastapi dev │
- │ │
- ╰─────────────────────────────────────────────────────╯
-
-INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
-INFO: Started parent process [27365]
-INFO: Started server process [27368]
-INFO: 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.
-
+$ fastapi run --workers 4 main.py
+
+ FastAPI Starting production server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
+
+ Logs:
+
+ INFO Uvicorn running on http://0.0.0.0:8000(Press CTRL+C to
+ quit)
+ INFO Started parent process [27365]
+ INFO Started server process [27368]
+ INFO Started server process [27369]
+ INFO Started server process [27370]
+ INFO Started server process [27367]
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
```
diff --git a/docs/pt/docs/how-to/conditional-openapi.md b/docs/pt/docs/how-to/conditional-openapi.md
index 675b812e6..6b44e9c81 100644
--- a/docs/pt/docs/how-to/conditional-openapi.md
+++ b/docs/pt/docs/how-to/conditional-openapi.md
@@ -29,9 +29,7 @@ Você pode usar facilmente as mesmas configurações do Pydantic para configurar
Por exemplo:
-```Python hl_lines="6 11"
-{!../../docs_src/conditional_openapi/tutorial001.py!}
-```
+{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *}
Aqui declaramos a configuração `openapi_url` com o mesmo padrão de `"/openapi.json"`.
diff --git a/docs/pt/docs/how-to/configure-swagger-ui.md b/docs/pt/docs/how-to/configure-swagger-ui.md
index 58bb1557c..915b2b5c5 100644
--- a/docs/pt/docs/how-to/configure-swagger-ui.md
+++ b/docs/pt/docs/how-to/configure-swagger-ui.md
@@ -18,9 +18,7 @@ Sem alterar as configurações, o destaque de sintaxe é habilitado por padrão:
Mas você pode desabilitá-lo definindo `syntaxHighlight` como `False`:
-```Python hl_lines="3"
-{!../../docs_src/configure_swagger_ui/tutorial001.py!}
-```
+{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *}
...e então o Swagger UI não mostrará mais o destaque de sintaxe:
@@ -30,9 +28,7 @@ Mas você pode desabilitá-lo definindo `syntaxHighlight` como `False`:
Da mesma forma que você pode definir o tema de destaque de sintaxe com a chave `"syntaxHighlight.theme"` (observe que há um ponto no meio):
-```Python hl_lines="3"
-{!../../docs_src/configure_swagger_ui/tutorial002.py!}
-```
+{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *}
Essa configuração alteraria o tema de cores de destaque de sintaxe:
@@ -44,17 +40,13 @@ O FastAPI inclui alguns parâmetros de configuração padrão apropriados para a
Inclui estas configurações padrão:
-```Python
-{!../../fastapi/openapi/docs.py[ln:7-23]!}
-```
+{* ../../fastapi/openapi/docs.py ln[7:23] *}
Você pode substituir qualquer um deles definindo um valor diferente no argumento `swagger_ui_parameters`.
Por exemplo, para desabilitar `deepLinking` você pode passar essas configurações para `swagger_ui_parameters`:
-```Python hl_lines="3"
-{!../../docs_src/configure_swagger_ui/tutorial003.py!}
-```
+{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *}
## Outros parâmetros da UI do Swagger
diff --git a/docs/pt/docs/how-to/custom-docs-ui-assets.md b/docs/pt/docs/how-to/custom-docs-ui-assets.md
index 00dd144c9..b7de6c8bd 100644
--- a/docs/pt/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/pt/docs/how-to/custom-docs-ui-assets.md
@@ -18,9 +18,7 @@ O primeiro passo é desativar a documentação automática, pois por padrão, el
Para desativá-los, defina suas URLs como `None` ao criar seu aplicativo `FastAPI`:
-```Python hl_lines="8"
-{!../../docs_src/custom_docs_ui/tutorial001.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *}
### Incluir a documentação personalizada
@@ -36,9 +34,7 @@ Você pode reutilizar as funções internas do FastAPI para criar as páginas HT
E de forma semelhante para o ReDoc...
-```Python hl_lines="2-6 11-19 22-24 27-33"
-{!../../docs_src/custom_docs_ui/tutorial001.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *}
/// tip | Dica
@@ -54,9 +50,7 @@ Swagger UI lidará com isso nos bastidores para você, mas ele precisa desse aux
Agora, para poder testar se tudo funciona, crie uma *operação de rota*:
-```Python hl_lines="36-38"
-{!../../docs_src/custom_docs_ui/tutorial001.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *}
### Teste
@@ -104,7 +98,7 @@ Você provavelmente pode clicar com o botão direito em cada link e selecionar u
E o **ReDoc** usa os arquivos:
-* `redoc.standalone.js`
+* `redoc.standalone.js`
Depois disso, sua estrutura de arquivos deve se parecer com:
@@ -124,9 +118,7 @@ Depois disso, sua estrutura de arquivos deve se parecer com:
* Importe `StaticFiles`.
* "Monte" a instância `StaticFiles()` em um caminho específico.
-```Python hl_lines="7 11"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *}
### Teste os arquivos estáticos
@@ -137,14 +129,8 @@ Você deverá ver um arquivo JavaScript muito longo para o **ReDoc**.
Esse arquivo pode começar com algo como:
```JavaScript
-/*!
- * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
- * -------------------------------------------------------------
- * Version: "2.0.0-rc.18"
- * Repo: https://github.com/Redocly/redoc
- */
-!function(e,t){"object"==typeof exports&&"object"==typeof m
-
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
```
@@ -158,9 +144,7 @@ Da mesma forma que ao usar um CDN personalizado, o primeiro passo é desativar a
Para desativá-los, defina suas URLs como `None` ao criar seu aplicativo `FastAPI`:
-```Python hl_lines="9"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *}
### Incluir a documentação personalizada para arquivos estáticos
@@ -176,9 +160,7 @@ Novamente, você pode reutilizar as funções internas do FastAPI para criar as
E de forma semelhante para o ReDoc...
-```Python hl_lines="2-6 14-22 25-27 30-36"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *}
/// tip | Dica
@@ -194,9 +176,7 @@ Swagger UI lidará com isso nos bastidores para você, mas ele precisa desse aux
Agora, para poder testar se tudo funciona, crie uma *operação de rota*:
-```Python hl_lines="39-41"
-{!../../docs_src/custom_docs_ui/tutorial002.py!}
-```
+{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *}
### Teste a UI de Arquivos Estáticos
diff --git a/docs/pt/docs/how-to/custom-request-and-route.md b/docs/pt/docs/how-to/custom-request-and-route.md
index 64325eed9..8f432f6fe 100644
--- a/docs/pt/docs/how-to/custom-request-and-route.md
+++ b/docs/pt/docs/how-to/custom-request-and-route.md
@@ -42,9 +42,7 @@ Se não houver `gzip` no cabeçalho, ele não tentará descomprimir o corpo.
Dessa forma, a mesma classe de rota pode lidar com requisições comprimidas ou não comprimidas.
-```Python hl_lines="8-15"
-{!../../docs_src/custom_request_and_route/tutorial001.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial001.py hl[8:15] *}
### Criar uma classe `GzipRoute` personalizada
@@ -56,9 +54,7 @@ Esse método retorna uma função. E essa função é o que irá receber uma req
Aqui nós usamos para criar um `GzipRequest` a partir da requisição original.
-```Python hl_lines="18-26"
-{!../../docs_src/custom_request_and_route/tutorial001.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial001.py hl[18:26] *}
/// note | Detalhes Técnicos
@@ -96,26 +92,18 @@ Também podemos usar essa mesma abordagem para acessar o corpo da requisição e
Tudo que precisamos fazer é manipular a requisição dentro de um bloco `try`/`except`:
-```Python hl_lines="13 15"
-{!../../docs_src/custom_request_and_route/tutorial002.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial002.py hl[13,15] *}
Se uma exceção ocorrer, a instância `Request` ainda estará em escopo, então podemos ler e fazer uso do corpo da requisição ao lidar com o erro:
-```Python hl_lines="16-18"
-{!../../docs_src/custom_request_and_route/tutorial002.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial002.py hl[16:18] *}
## Classe `APIRoute` personalizada em um router
você também pode definir o parametro `route_class` de uma `APIRouter`;
-```Python hl_lines="26"
-{!../../docs_src/custom_request_and_route/tutorial003.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial003.py hl[26] *}
Nesse exemplo, as *operações de rota* sob o `router` irão usar a classe `TimedRoute` personalizada, e terão um cabeçalho extra `X-Response-Time` na resposta com o tempo que levou para gerar a resposta:
-```Python hl_lines="13-20"
-{!../../docs_src/custom_request_and_route/tutorial003.py!}
-```
+{* ../../docs_src/custom_request_and_route/tutorial003.py hl[13:20] *}
diff --git a/docs/pt/docs/how-to/extending-openapi.md b/docs/pt/docs/how-to/extending-openapi.md
index 40917325b..b4785edc1 100644
--- a/docs/pt/docs/how-to/extending-openapi.md
+++ b/docs/pt/docs/how-to/extending-openapi.md
@@ -1,4 +1,3 @@
-
# Extendendo o OpenAPI
Existem alguns casos em que pode ser necessário modificar o esquema OpenAPI gerado.
@@ -44,25 +43,19 @@ Por exemplo, vamos adicionar documentação do Strawberry.
diff --git a/docs/pt/docs/how-to/separate-openapi-schemas.md b/docs/pt/docs/how-to/separate-openapi-schemas.md
index 50d321d4c..291b0e163 100644
--- a/docs/pt/docs/how-to/separate-openapi-schemas.md
+++ b/docs/pt/docs/how-to/separate-openapi-schemas.md
@@ -10,123 +10,13 @@ Vamos ver como isso funciona e como alterar se for necessário.
Digamos que você tenha um modelo Pydantic com valores padrão, como este:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-7]!}
-
-# Code below omitted 👇
-```
-
-
-👀 Visualização completa do arquivo
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-9]!}
-
-# Code below omitted 👇
-```
-
-
-👀 Visualização completa do arquivo
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-9]!}
-
-# Code below omitted 👇
-```
-
-
-👀 Visualização completa do arquivo
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
-```
-
-
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}
### Modelo para Entrada
Se você usar esse modelo como entrada, como aqui:
-//// tab | Python 3.10+
-
-```Python hl_lines="14"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-15]!}
-
-# Code below omitted 👇
-```
-
-
-👀 Visualização completa do arquivo
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="16"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-17]!}
-
-# Code below omitted 👇
-```
-
-
-👀 Visualização completa do arquivo
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
-```
-
-
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="16"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-17]!}
-
-# Code below omitted 👇
-```
-
-
-👀 Visualização completa do arquivo
-
-```Python
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
-```
-
-
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}
... então o campo `description` não será obrigatório. Porque ele tem um valor padrão de `None`.
@@ -142,29 +32,7 @@ Você pode confirmar que na documentação, o campo `description` não tem um **
Mas se você usar o mesmo modelo como saída, como aqui:
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="21"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="21"
-{!> ../../docs_src/separate_openapi_schemas/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}
... então, como `description` tem um valor padrão, se você **não retornar nada** para esse campo, ele ainda terá o **valor padrão**.
@@ -223,29 +91,7 @@ O suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.
///
-//// tab | Python 3.10+
-
-```Python hl_lines="10"
-{!> ../../docs_src/separate_openapi_schemas/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="12"
-{!> ../../docs_src/separate_openapi_schemas/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="12"
-{!> ../../docs_src/separate_openapi_schemas/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}
### Mesmo Esquema para Modelos de Entrada e Saída na Documentação
diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md
index bc23114dc..9f08d5224 100644
--- a/docs/pt/docs/index.md
+++ b/docs/pt/docs/index.md
@@ -11,15 +11,18 @@
Framework FastAPI, alta performance, fácil de aprender, fácil de codar, pronto para produção
---
@@ -60,7 +63,7 @@ Os recursos chave são:
-Outros patrocinadores
+Outros patrocinadores
## Opiniões
@@ -70,6 +73,18 @@ Os recursos chave são:
---
+"_Nós adotamos a biblioteca **FastAPI** para iniciar um servidor **REST** que pode ser consultado para obter **previsões**. [para o Ludwig]_"
+
+
Piero Molino, Yaroslav Dudin, e Sai Sumanth Miryala - Uber(ref)
+
+---
+
+"_A **Netflix** tem o prazer de anunciar o lançamento open-source do nosso framework de orquestração de **gerenciamento de crises**: **Dispatch**! [criado com **FastAPI**]_"
+
+
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix(ref)
+
+---
+
"*Estou extremamente entusiasmado com o **FastAPI**. É tão divertido!*"
@@ -90,9 +105,9 @@ Os recursos chave são:
---
-"*Nós adotamos a biblioteca **FastAPI** para criar um servidor **REST** que possa ser chamado para obter **predições**. [para o Ludwig]*"
+"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**. Ele se tornou um **componente chave** para a nossa estratégia API first de desenvolvimento e está impulsionando diversas automações e serviços, como o nosso Virtual TAC Engineer._"
-
Piero Molino, Yaroslav Dudin e Sai Sumanth Miryala - Uber(ref)
-
-Você também precisará de um servidor ASGI para produção, tal como Uvicorn ou Hypercorn.
+Crie e ative um ambiente virtual, e então instale o FastAPI:
+**Nota**: Certifique-se de que você colocou `"fastapi[standard]"` com aspas, para garantir que funcione em todos os terminais.
+
## Exemplo
### Crie
@@ -184,7 +191,7 @@ async def read_item(item_id: int, q: Union[str, None] = None):
**Nota**:
-Se você não sabe, verifique a seção _"In a hurry?"_ sobre `async` e `await` nas docs.
+Se você não sabe, verifique a seção _"Com pressa?"_ sobre `async` e `await` nas docs.
@@ -195,11 +202,24 @@ Rode o servidor com:
```console
-$ uvicorn main:app --reload
-
+$ fastapi dev main.py
+
+ ╭────────── FastAPI CLI - Development mode ───────────╮
+ │ │
+ │ Serving at: http://127.0.0.1:8000 │
+ │ │
+ │ API docs: http://127.0.0.1:8000/docs │
+ │ │
+ │ Running in development mode, for production use: │
+ │ │
+ │ fastapi run │
+ │ │
+ ╰─────────────────────────────────────────────────────╯
+
+INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-INFO: Started reloader process [28720]
-INFO: Started server process [28722]
+INFO: Started reloader process [2248755] using WatchFiles
+INFO: Started server process [2248757]
INFO: Waiting for application startup.
INFO: Application startup complete.
```
@@ -207,13 +227,13 @@ INFO: Application startup complete.
+
+/// info | Informação
+
+Se você pretente utilizar algoritmos de assinatura digital como o RSA ou o ECDSA, você deve instalar a dependência da biblioteca de criptografia `pyjwt[crypto]`.
+
+Você pode ler mais sobre isso na documentação de instalação do PyJWT.
+
+///
+
+## Hashing de senhas
+
+"Hashing" significa converter algum conteúdo (uma senha neste caso) em uma sequência de bytes (apenas uma string) que parece um monte de caracteres sem sentido.
+
+Sempre que você passar exatamente o mesmo conteúdo (exatamente a mesma senha), você obterá exatamente o mesmo resultado.
+
+Mas não é possível converter os caracteres sem sentido de volta para a senha original.
+
+### Por que usar hashing de senhas
+
+Se o seu banco de dados for roubado, o invasor não terá as senhas em texto puro dos seus usuários, apenas os hashes.
+
+Então, o invasor não poderá tentar usar essas senhas em outro sistema (como muitos usuários utilizam a mesma senha em vários lugares, isso seria perigoso).
+
+## Instalar o `passlib`
+
+O PassLib é uma excelente biblioteca Python para lidar com hashes de senhas.
+
+Ele suporta muitos algoritmos de hashing seguros e utilitários para trabalhar com eles.
+
+O algoritmo recomendado é o "Bcrypt".
+
+Certifique-se de criar um [ambiente virtual](../../virtual-environments.md){.internal-link target=_blank}, ativá-lo e então instalar o PassLib com Bcrypt:
+
+
+
+/// tip | Dica
+
+Com o `passlib`, você poderia até configurá-lo para ser capaz de ler senhas criadas pelo **Django**, um plug-in de segurança do **Flask** ou muitos outros.
+
+Assim, você poderia, por exemplo, compartilhar os mesmos dados de um aplicativo Django em um banco de dados com um aplicativo FastAPI. Ou migrar gradualmente uma aplicação Django usando o mesmo banco de dados.
+
+E seus usuários poderiam fazer login tanto pela sua aplicação Django quanto pela sua aplicação **FastAPI**, ao mesmo tempo.
+
+///
+
+## Criar o hash e verificar as senhas
+
+Importe as ferramentas que nós precisamos de `passlib`.
+
+Crie um "contexto" do PassLib. Este será usado para criar o hash e verificar as senhas.
+
+/// tip | Dica
+
+O contexto do PassLib também possui funcionalidades para usar diferentes algoritmos de hashing, incluindo algoritmos antigos que estão obsoletos, apenas para permitir verificá-los, etc.
+
+Por exemplo, você poderia usá-lo para ler e verificar senhas geradas por outro sistema (como Django), mas criar o hash de novas senhas com um algoritmo diferente, como o Bcrypt.
+
+E ser compatível com todos eles ao mesmo tempo.
+
+///
+
+Crie uma função utilitária para criar o hash de uma senha fornecida pelo usuário.
+
+E outra função utilitária para verificar se uma senha recebida corresponde ao hash armazenado.
+
+E outra para autenticar e retornar um usuário.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+
+/// note | Nota
+
+Se você verificar o novo banco de dados (falso) `fake_users_db`, você verá como o hash da senha se parece agora: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
+
+///
+
+## Manipular tokens JWT
+
+Importe os módulos instalados.
+
+Crie uma chave secreta aleatória que será usada para assinar os tokens JWT.
+
+Para gerar uma chave secreta aleatória e segura, use o comando:
+
+
+
+E copie a saída para a variável `SECRET_KEY` (não use a do exemplo).
+
+Crie uma variável `ALGORITHM` com o algoritmo usado para assinar o token JWT e defina como `"HS256"`.
+
+Crie uma variável para a expiração do token.
+
+Defina um modelo Pydantic que será usado no endpoint de token para a resposta.
+
+Crie uma função utilitária para gerar um novo token de acesso.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+
+## Atualize as dependências
+
+Atualize `get_current_user` para receber o mesmo token de antes, mas desta vez, usando tokens JWT.
+
+Decodifique o token recebido, verifique-o e retorne o usuário atual.
+
+Se o token for inválido, retorne um erro HTTP imediatamente.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+
+## Atualize a *operação de rota* `/token`
+
+Crie um `timedelta` com o tempo de expiração do token.
+
+Crie um token de acesso JWT real e o retorne.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+
+### Detalhes técnicos sobre o "sujeito" `sub` do JWT
+
+A especificação JWT diz que existe uma chave `sub`, com o sujeito do token.
+
+É opcional usá-la, mas é onde você colocaria a identificação do usuário, então nós estamos usando aqui.
+
+O JWT pode ser usado para outras coisas além de identificar um usuário e permitir que ele execute operações diretamente na sua API.
+
+Por exemplo, você poderia identificar um "carro" ou uma "postagem de blog".
+
+Depois, você poderia adicionar permissões sobre essa entidade, como "dirigir" (para o carro) ou "editar" (para o blog).
+
+E então, poderia dar esse token JWT para um usuário (ou bot), e ele poderia usá-lo para realizar essas ações (dirigir o carro ou editar o blog) sem sequer precisar ter uma conta, apenas com o token JWT que sua API gerou para isso.
+
+Usando essas ideias, o JWT pode ser usado para cenários muito mais sofisticados.
+
+Nesses casos, várias dessas entidades poderiam ter o mesmo ID, digamos `foo` (um usuário `foo`, um carro `foo` e uma postagem de blog `foo`).
+
+Então, para evitar colisões de ID, ao criar o token JWT para o usuário, você poderia prefixar o valor da chave `sub`, por exemplo, com `username:`. Assim, neste exemplo, o valor de `sub` poderia ser: `username:johndoe`.
+
+O importante a se lembrar é que a chave `sub` deve ter um identificador único em toda a aplicação e deve ser uma string.
+
+## Testando
+
+Execute o servidor e vá para a documentação: http://127.0.0.1:8000/docs.
+
+Você verá a interface de usuário assim:
+
+
+
+Autorize a aplicação da mesma maneira que antes.
+
+Usando as credenciais:
+
+Username: `johndoe`
+Password: `secret`
+
+/// check | Verifique
+
+Observe que em nenhuma parte do código está a senha em texto puro "`secret`", nós temos apenas o hash.
+
+///
+
+
+
+Chame o endpoint `/users/me/`, você receberá o retorno como:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false
+}
+```
+
+
+
+Se você abrir as ferramentas de desenvolvedor, poderá ver que os dados enviados incluem apenas o token. A senha é enviada apenas na primeira requisição para autenticar o usuário e obter o token de acesso, mas não é enviada nas próximas requisições:
+
+
+
+/// note | Nota
+
+Perceba que o cabeçalho `Authorization`, com o valor que começa com `Bearer `.
+
+///
+
+## Uso avançado com `scopes`
+
+O OAuth2 tem a noção de "scopes" (escopos).
+
+Você pode usá-los para adicionar um conjunto específico de permissões a um token JWT.
+
+Então, você pode dar este token diretamente a um usuário ou a uma terceira parte para interagir com sua API com um conjunto de restrições.
+
+Você pode aprender como usá-los e como eles são integrados ao **FastAPI** mais adiante no **Guia Avançado do Usuário**.
+
+
+## Recapitulação
+
+Com o que você viu até agora, você pode configurar uma aplicação **FastAPI** segura usando padrões como OAuth2 e JWT.
+
+Em quase qualquer framework, lidar com a segurança se torna rapidamente um assunto bastante complexo.
+
+Muitos pacotes que simplificam bastante isso precisam fazer muitas concessões com o modelo de dados, o banco de dados e os recursos disponíveis. E alguns desses pacotes que simplificam demais na verdade têm falhas de segurança subjacentes.
+
+---
+
+O **FastAPI** não faz nenhuma concessão com nenhum banco de dados, modelo de dados ou ferramenta.
+
+Ele oferece toda a flexibilidade para você escolher as opções que melhor se ajustam ao seu projeto.
+
+E você pode usar diretamente muitos pacotes bem mantidos e amplamente utilizados, como `passlib` e `PyJWT`, porque o **FastAPI** não exige mecanismos complexos para integrar pacotes externos.
+
+Mas ele fornece as ferramentas para simplificar o processo o máximo possível, sem comprometer a flexibilidade, robustez ou segurança.
+
+E você pode usar e implementar protocolos padrão seguros, como o OAuth2, de uma maneira relativamente simples.
+
+Você pode aprender mais no **Guia Avançado do Usuário** sobre como usar os "scopes" do OAuth2 para um sistema de permissões mais refinado, seguindo esses mesmos padrões. O OAuth2 com scopes é o mecanismo usado por muitos provedores grandes de autenticação, como o Facebook, Google, GitHub, Microsoft, Twitter, etc. para autorizar aplicativos de terceiros a interagir com suas APIs em nome de seus usuários.
diff --git a/docs/pt/docs/tutorial/security/simple-oauth2.md b/docs/pt/docs/tutorial/security/simple-oauth2.md
index 4e55f8c25..1cf05785e 100644
--- a/docs/pt/docs/tutorial/security/simple-oauth2.md
+++ b/docs/pt/docs/tutorial/security/simple-oauth2.md
@@ -52,57 +52,7 @@ Agora vamos usar os utilitários fornecidos pelo **FastAPI** para lidar com isso
Primeiro, importe `OAuth2PasswordRequestForm` e use-o como uma dependência com `Depends` na *operação de rota* para `/token`:
-//// tab | Python 3.10+
-
-```Python hl_lines="4 78"
-{!> ../../docs_src/security/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="4 78"
-{!> ../../docs_src/security/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4 79"
-{!> ../../docs_src/security/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="2 74"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="4 76"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
`OAuth2PasswordRequestForm` é uma dependência de classe que declara um corpo de formulário com:
@@ -150,57 +100,7 @@ Se não existir tal usuário, retornaremos um erro dizendo "Incorrect username o
Para o erro, usamos a exceção `HTTPException`:
-//// tab | Python 3.10+
-
-```Python hl_lines="3 79-81"
-{!> ../../docs_src/security/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="3 79-81"
-{!> ../../docs_src/security/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3 80-82"
-{!> ../../docs_src/security/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="1 75-77"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="3 77-79"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}
### Confira a password (senha)
@@ -226,57 +126,7 @@ Se o seu banco de dados for roubado, o ladrão não terá as senhas em texto sim
Assim, o ladrão não poderá tentar usar essas mesmas senhas em outro sistema (como muitos usuários usam a mesma senha em todos os lugares, isso seria perigoso).
-//// tab | Python 3.10+
-
-```Python hl_lines="82-85"
-{!> ../../docs_src/security/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="82-85"
-{!> ../../docs_src/security/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="83-86"
-{!> ../../docs_src/security/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="78-81"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="80-83"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}
#### Sobre `**user_dict`
@@ -318,57 +168,7 @@ Mas, por enquanto, vamos nos concentrar nos detalhes específicos de que precisa
///
-//// tab | Python 3.10+
-
-```Python hl_lines="87"
-{!> ../../docs_src/security/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="87"
-{!> ../../docs_src/security/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="88"
-{!> ../../docs_src/security/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="83"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="85"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}
/// tip | Dica
@@ -394,57 +194,7 @@ Ambas as dependências retornarão apenas um erro HTTP se o usuário não existi
Portanto, em nosso endpoint, só obteremos um usuário se o usuário existir, tiver sido autenticado corretamente e estiver ativo:
-//// tab | Python 3.10+
-
-```Python hl_lines="58-66 69-74 94"
-{!> ../../docs_src/security/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="58-66 69-74 94"
-{!> ../../docs_src/security/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="59-67 70-75 95"
-{!> ../../docs_src/security/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="56-64 67-70 88"
-{!> ../../docs_src/security/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Dica
-
-Prefira usar a versão `Annotated`, se possível.
-
-///
-
-```Python hl_lines="58-66 69-72 90"
-{!> ../../docs_src/security/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
/// info | Informação
diff --git a/docs/pt/docs/tutorial/static-files.md b/docs/pt/docs/tutorial/static-files.md
index aba4b8221..0660078f4 100644
--- a/docs/pt/docs/tutorial/static-files.md
+++ b/docs/pt/docs/tutorial/static-files.md
@@ -7,9 +7,7 @@ Você pode servir arquivos estáticos automaticamente de um diretório usando `S
* Importe `StaticFiles`.
* "Monte" uma instância de `StaticFiles()` em um caminho específico.
-```Python hl_lines="2 6"
-{!../../docs_src/static_files/tutorial001.py!}
-```
+{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
/// note | Detalhes técnicos
diff --git a/docs/pt/docs/tutorial/testing.md b/docs/pt/docs/tutorial/testing.md
index 4f8eaa299..8eb2f29b7 100644
--- a/docs/pt/docs/tutorial/testing.md
+++ b/docs/pt/docs/tutorial/testing.md
@@ -30,9 +30,7 @@ Use o objeto `TestClient` da mesma forma que você faz com `httpx`.
Escreva instruções `assert` simples com as expressões Python padrão que você precisa verificar (novamente, `pytest` padrão).
-```Python hl_lines="2 12 15-18"
-{!../../docs_src/app_testing/tutorial001.py!}
-```
+{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
/// tip | Dica
@@ -78,9 +76,7 @@ Digamos que você tenha uma estrutura de arquivo conforme descrito em [Aplicativ
No arquivo `main.py` você tem seu aplicativo **FastAPI**:
-```Python
-{!../../docs_src/app_testing/main.py!}
-```
+{* ../../docs_src/app_testing/main.py *}
### Arquivo de teste
@@ -96,9 +92,7 @@ Então você poderia ter um arquivo `test_main.py` com seus testes. Ele poderia
Como esse arquivo está no mesmo pacote, você pode usar importações relativas para importar o objeto `app` do módulo `main` (`main.py`):
-```Python hl_lines="3"
-{!../../docs_src/app_testing/test_main.py!}
-```
+{* ../../docs_src/app_testing/test_main.py hl[3] *}
...e ter o código para os testes como antes.
@@ -182,9 +176,7 @@ Prefira usar a versão `Annotated` se possível.
Você pode então atualizar `test_main.py` com os testes estendidos:
-```Python
-{!> ../../docs_src/app_testing/app_b/test_main.py!}
-```
+{* ../../docs_src/app_testing/app_b/test_main.py *}
Sempre que você precisar que o cliente passe informações na requisição e não souber como, você pode pesquisar (no Google) como fazer isso no `httpx`, ou até mesmo como fazer isso com `requests`, já que o design do HTTPX é baseado no design do Requests.
diff --git a/docs/ru/docs/advanced/async-tests.md b/docs/ru/docs/advanced/async-tests.md
new file mode 100644
index 000000000..7849ad109
--- /dev/null
+++ b/docs/ru/docs/advanced/async-tests.md
@@ -0,0 +1,99 @@
+# Асинхронное тестирование
+
+Вы уже видели как тестировать **FastAPI** приложение, используя имеющийся класс `TestClient`. К этому моменту вы видели только как писать тесты в синхронном стиле без использования `async` функций.
+
+Возможность использования асинхронных функций в ваших тестах может быть полезнa, когда, например, вы асинхронно обращаетесь к вашей базе данных. Представьте, что вы хотите отправить запросы в ваше FastAPI приложение, а затем при помощи асинхронной библиотеки для работы с базой данных удостовериться, что ваш бекэнд корректно записал данные в базу данных.
+
+Давайте рассмотрим, как мы можем это реализовать.
+
+## pytest.mark.anyio
+
+Если мы хотим вызывать асинхронные функции в наших тестах, то наши тестовые функции должны быть асинхронными. AnyIO предоставляет для этого отличный плагин, который позволяет нам указывать, какие тестовые функции должны вызываться асинхронно.
+
+## HTTPX
+
+Даже если **FastAPI** приложение использует обычные функции `def` вместо `async def`, это все равно `async` приложение 'под капотом'.
+
+Чтобы работать с асинхронным FastAPI приложением в ваших обычных тестовых функциях `def`, используя стандартный pytest, `TestClient` внутри себя делает некоторую магию. Но эта магия перестает работать, когда мы используем его внутри асинхронных функций. Запуская наши тесты асинхронно, мы больше не можем использовать `TestClient` внутри наших тестовых функций.
+
+`TestClient` основан на HTTPX, и, к счастью, мы можем использовать его (`HTTPX`) напрямую для тестирования API.
+
+## Пример
+
+В качестве простого примера, давайте рассмотрим файловую структуру, схожую с описанной в [Большие приложения](../tutorial/bigger-applications.md){.internal-link target=_blank} и [Тестирование](../tutorial/testing.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Файл `main.py`:
+
+{* ../../docs_src/async_tests/main.py *}
+
+Файл `test_main.py` содержит тесты для `main.py`, теперь он может выглядеть так:
+
+{* ../../docs_src/async_tests/test_main.py *}
+
+## Запуск тестов
+
+Вы можете запустить свои тесты как обычно:
+
+
+
+```console
+$ pytest
+
+---> 100%
+```
+
+
+
+## Подробнее
+
+Маркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно:
+
+{* ../../docs_src/async_tests/test_main.py hl[7] *}
+
+/// tip | Подсказка
+
+Обратите внимание, что тестовая функция теперь `async def` вместо простого `def`, как это было при использовании `TestClient`.
+
+///
+
+Затем мы можем создать `AsyncClient` со ссылкой на приложение и посылать асинхронные запросы, используя `await`.
+
+{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
+
+Это эквивалентно следующему:
+
+```Python
+response = client.get('/')
+```
+
+...которое мы использовали для отправки наших запросов с `TestClient`.
+
+/// tip | Подсказка
+
+Обратите внимание, что мы используем async/await с `AsyncClient` - запрос асинхронный.
+
+///
+
+/// warning | Внимание
+
+Если ваше приложение полагается на lifespan события, то `AsyncClient` не запустит эти события. Чтобы обеспечить их срабатывание используйте `LifespanManager` из florimondmanca/asgi-lifespan.
+
+///
+
+## Вызов других асинхронных функций
+
+Теперь тестовая функция стала асинхронной, поэтому внутри нее вы можете вызывать также и другие `async` функции, не связанные с отправлением запросов в ваше FastAPI приложение. Как если бы вы вызывали их в любом другом месте вашего кода.
+
+/// tip | Подсказка
+
+Если вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании MongoDB's MotorClient), то не забывайте инициализировать объекты, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `'@app.on_event("startup")` callback.
+
+///
diff --git a/docs/ru/docs/advanced/response-cookies.md b/docs/ru/docs/advanced/response-cookies.md
new file mode 100644
index 000000000..e04ff577c
--- /dev/null
+++ b/docs/ru/docs/advanced/response-cookies.md
@@ -0,0 +1,48 @@
+
+# Cookies в ответе
+
+## Использование параметра `Response`
+
+Вы можете объявить параметр типа `Response` в вашей функции эндпоинта.
+
+Затем установить cookies в этом временном объекте ответа.
+
+{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *}
+
+После этого можно вернуть любой объект, как и раньше (например, `dict`, объект модели базы данных и так далее).
+
+Если вы указали `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта.
+
+**FastAPI** извлечет cookies (а также заголовки и коды состояния) из временного ответа и включит их в окончательный ответ, содержащий ваше возвращаемое значение, отфильтрованное через `response_model`.
+
+Вы также можете объявить параметр типа Response в зависимостях и устанавливать cookies (и заголовки) там.
+
+## Возвращение `Response` напрямую
+
+Вы также можете установить cookies, если возвращаете `Response` напрямую в вашем коде.
+
+Для этого создайте объект `Response`, как описано в разделе [Возвращение ответа напрямую](response-directly.md){.target=_blank}.
+
+Затем установите cookies и верните этот объект:
+
+{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *}
+
+/// tip | Примечание
+Имейте в виду, что если вы возвращаете ответ напрямую, вместо использования параметра `Response`, **FastAPI** отправит его без дополнительной обработки.
+
+Убедитесь, что ваши данные имеют корректный тип. Например, они должны быть совместимы с JSON, если вы используете `JSONResponse`.
+
+Также убедитесь, что вы не отправляете данные, которые должны были быть отфильтрованы через `response_model`.
+///
+
+### Дополнительная информация
+
+/// note | Технические детали
+Вы также можете использовать `from starlette.responses import Response` или `from starlette.responses import JSONResponse`.
+
+**FastAPI** предоставляет `fastapi.responses`, которые являются теми же объектами, что и `starlette.responses`, просто для удобства. Однако большинство доступных типов ответов поступает непосредственно из **Starlette**.
+
+Для установки заголовков и cookies `Response` используется часто, поэтому **FastAPI** также предоставляет его через `fastapi.responses`.
+///
+
+Чтобы увидеть все доступные параметры и настройки, ознакомьтесь с документацией Starlette.
diff --git a/docs/ru/docs/advanced/websockets.md b/docs/ru/docs/advanced/websockets.md
new file mode 100644
index 000000000..bc9dfcbff
--- /dev/null
+++ b/docs/ru/docs/advanced/websockets.md
@@ -0,0 +1,186 @@
+# Веб-сокеты
+
+Вы можете использовать веб-сокеты в **FastAPI**.
+
+## Установка `WebSockets`
+
+Убедитесь, что [виртуальная среда](../virtual-environments.md){.internal-link target=_blank} создана, активируйте её и установите `websockets`:
+
+
+
+## Клиент WebSockets
+
+### Рабочее приложение
+
+Скорее всего, в вашей реальной продуктовой системе есть фронтенд, реализованный при помощи современных фреймворков React, Vue.js или Angular.
+
+И наверняка для взаимодействия с бекендом через веб-сокеты вы будете использовать средства фронтенда.
+
+Также у вас может быть нативное мобильное приложение, коммуницирующее непосредственно с веб-сокетами на бекенд-сервере.
+
+Либо вы можете сделать какой-либо другой способ взаимодействия с веб-сокетами.
+
+---
+
+Но для этого примера мы воспользуемся очень простым HTML документом с небольшими вставками JavaScript кода.
+
+Конечно же это неоптимально, и на практике так делать не стоит.
+
+В реальных приложениях стоит воспользоваться одним из вышеупомянутых способов.
+
+Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб-сокетов и получить рабочий код:
+
+{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
+
+## Создание `websocket`
+
+Создайте `websocket` в своем **FastAPI** приложении:
+
+{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *}
+
+/// note | Технические детали
+
+Вы также можете использовать `from starlette.websockets import WebSocket`.
+
+**FastAPI** напрямую предоставляет тот же самый `WebSocket` просто для удобства. На самом деле это `WebSocket` из Starlette.
+
+///
+
+## Ожидание и отправка сообщений
+
+Через эндпоинт веб-сокета вы можете получать и отправлять сообщения.
+
+{* ../../docs_src/websockets/tutorial001.py hl[48:52] *}
+
+Вы можете получать и отправлять двоичные, текстовые и JSON данные.
+
+## Проверка в действии
+
+Если ваш файл называется `main.py`, то запустите приложение командой:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Откройте браузер по адресу http://127.0.0.1:8000.
+
+Вы увидите следующую простенькую страницу:
+
+
+
+Вы можете набирать сообщения в поле ввода и отправлять их:
+
+
+
+И ваше **FastAPI** приложение с веб-сокетами ответит:
+
+
+
+Вы можете отправлять и получать множество сообщений:
+
+
+
+И все они будут использовать одно и то же веб-сокет соединение.
+
+## Использование `Depends` и не только
+
+Вы можете импортировать из `fastapi` и использовать в эндпоинте вебсокета:
+
+* `Depends`
+* `Security`
+* `Cookie`
+* `Header`
+* `Path`
+* `Query`
+
+Они работают так же, как и в других FastAPI эндпоинтах/*операциях пути*:
+
+{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
+
+/// info | Примечание
+
+В веб-сокете вызывать `HTTPException` не имеет смысла. Вместо этого нужно использовать `WebSocketException`.
+
+Закрывающий статус код можно использовать из valid codes defined in the specification.
+
+///
+
+### Веб-сокеты с зависимостями: проверка в действии
+
+Если ваш файл называется `main.py`, то запустите приложение командой:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Откройте браузер по адресу http://127.0.0.1:8000.
+
+Там вы можете задать:
+
+* "Item ID", используемый в пути.
+* "Token", используемый как query-параметр.
+
+/// tip | Подсказка
+
+Обратите внимание, что query-параметр `token` будет обработан в зависимости.
+
+///
+
+Теперь вы можете подключиться к веб-сокету и начинать отправку и получение сообщений:
+
+
+
+## Обработка отключений и работа с несколькими клиентами
+
+Если веб-сокет соединение закрыто, то `await websocket.receive_text()` вызовет исключение `WebSocketDisconnect`, которое можно поймать и обработать как в этом примере:
+
+{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
+
+Чтобы воспроизвести пример:
+
+* Откройте приложение в нескольких вкладках браузера.
+* Отправьте из них сообщения.
+* Затем закройте одну из вкладок.
+
+Это вызовет исключение `WebSocketDisconnect`, и все остальные клиенты получат следующее сообщение:
+
+```
+Client #1596980209979 left the chat
+```
+
+/// tip | Примечание
+
+Приложение выше - это всего лишь простой минимальный пример, демонстрирующий обработку и передачу сообщений нескольким веб-сокет соединениям.
+
+Но имейте в виду, что это будет работать только в одном процессе и только пока он активен, так как всё обрабатывается в простом списке в оперативной памяти.
+
+Если нужно что-то легко интегрируемое с FastAPI, но более надежное и с поддержкой Redis, PostgreSQL или другого, то можно воспользоваться encode/broadcaster.
+
+///
+
+## Дополнительная информация
+
+Для более глубокого изучения темы воспользуйтесь документацией Starlette:
+
+* The `WebSocket` class.
+* Class-based WebSocket handling.
diff --git a/docs/ru/docs/contributing.md b/docs/ru/docs/contributing.md
deleted file mode 100644
index 67034ad03..000000000
--- a/docs/ru/docs/contributing.md
+++ /dev/null
@@ -1,496 +0,0 @@
-# Участие в разработке фреймворка
-
-Возможно, для начала Вам стоит ознакомиться с основными способами [помочь FastAPI или получить помощь](help-fastapi.md){.internal-link target=_blank}.
-
-## Разработка
-
-Если Вы уже склонировали репозиторий и знаете, что Вам нужно более глубокое погружение в код фреймворка, то здесь представлены некоторые инструкции по настройке виртуального окружения.
-
-### Виртуальное окружение с помощью `venv`
-
-Находясь в нужной директории, Вы можете создать виртуальное окружение при помощи Python модуля `venv`.
-
-
-
-```console
-$ python -m venv env
-```
-
-
-
-Эта команда создаст директорию `./env/` с бинарными (двоичными) файлами Python, а затем Вы сможете скачивать и устанавливать необходимые библиотеки в изолированное виртуальное окружение.
-
-### Активация виртуального окружения
-
-Активируйте виртуально окружение командой:
-
-//// tab | Linux, macOS
-
-
-
-////
-
-Если в терминале появится ответ, что бинарник `pip` расположен по пути `.../env/bin/pip`, значит всё в порядке. 🎉
-
-Во избежание ошибок в дальнейших шагах, удостоверьтесь, что в Вашем виртуальном окружении установлена последняя версия `pip`:
-
-
-
-/// tip | Подсказка
-
-Каждый раз, перед установкой новой библиотеки в виртуальное окружение при помощи `pip`, не забудьте активировать это виртуальное окружение.
-
-Это гарантирует, что если Вы используете библиотеку, установленную этим пакетом, то Вы используете библиотеку из Вашего локального окружения, а не любую другую, которая может быть установлена глобально.
-
-///
-
-### pip
-
-После активации виртуального окружения, как было указано ранее, введите следующую команду:
-
-
-
-Это установит все необходимые зависимости в локальное окружение для Вашего локального FastAPI.
-
-#### Использование локального FastAPI
-
-Если Вы создаёте Python файл, который импортирует и использует FastAPI,а затем запускаете его интерпретатором Python из Вашего локального окружения, то он будет использовать код из локального FastAPI.
-
-И, так как при вводе вышеупомянутой команды был указан флаг `-e`, если Вы измените код локального FastAPI, то при следующем запуске этого файла, он будет использовать свежую версию локального FastAPI, который Вы только что изменили.
-
-Таким образом, Вам не нужно "переустанавливать" Вашу локальную версию, чтобы протестировать каждое изменение.
-
-### Форматировние
-
-Скачанный репозиторий содержит скрипт, который может отформатировать и подчистить Ваш код:
-
-
-
-```console
-$ bash scripts/format.sh
-```
-
-
-
-Заодно он упорядочит Ваши импорты.
-
-Чтобы он сортировал их правильно, необходимо, чтобы FastAPI был установлен локально в Вашей среде, с помощью команды из раздела выше, использующей флаг `-e`.
-
-## Документация
-
-Прежде всего, убедитесь, что Вы настроили своё окружение, как описано выше, для установки всех зависимостей.
-
-Документация использует MkDocs.
-
-Также существуют дополнительные инструменты/скрипты для работы с переводами в `./scripts/docs.py`.
-
-/// tip | Подсказка
-
-Нет необходимости заглядывать в `./scripts/docs.py`, просто используйте это в командной строке.
-
-///
-
-Вся документация имеет формат Markdown и расположена в директории `./docs/en/`.
-
-Многие руководства содержат блоки кода.
-
-В большинстве случаев эти блоки кода представляют собой вполне законченные приложения, которые можно запускать как есть.
-
-На самом деле, эти блоки кода не написаны внутри Markdown, это Python файлы в директории `./docs_src/`.
-
-И эти Python файлы включаются/вводятся в документацию при создании сайта.
-
-### Тестирование документации
-
-
-Фактически, большинство тестов запускаются с примерами исходных файлов в документации.
-
-Это помогает убедиться, что:
-
-* Документация находится в актуальном состоянии.
-* Примеры из документации могут быть запущены как есть.
-* Большинство функций описаны в документации и покрыты тестами.
-
-Существует скрипт, который во время локальной разработки создаёт сайт и проверяет наличие любых изменений, перезагружая его в реальном времени:
-
-
-
-Он запустит сайт документации по адресу: `http://127.0.0.1:8008`.
-
-
-Таким образом, Вы сможете редактировать файлы с документацией или кодом и наблюдать изменения вживую.
-
-#### Typer CLI (опционально)
-
-
-Приведенная ранее инструкция показала Вам, как запускать скрипт `./scripts/docs.py` непосредственно через интерпретатор `python` .
-
-Но также можно использовать Typer CLI, что позволит Вам воспользоваться автозаполнением команд в Вашем терминале.
-
-Если Вы установили Typer CLI, то для включения функции автозаполнения, введите эту команду:
-
-
-
-```console
-$ typer --install-completion
-
-zsh completion installed in /home/user/.bashrc.
-Completion will take effect once you restart the terminal.
-```
-
-
-
-### Приложения и документация одновременно
-
-Если Вы запускаете приложение, например так:
-
-
-
-```console
-$ uvicorn tutorial001:app --reload
-
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-```
-
-
-
-По умолчанию Uvicorn будет использовать порт `8000` и не будет конфликтовать с сайтом документации, использующим порт `8008`.
-
-### Переводы на другие языки
-
-Помощь с переводами ценится КРАЙНЕ ВЫСОКО! И переводы не могут быть сделаны без помощи сообщества. 🌎 🚀
-
-Ниже приведены шаги, как помочь с переводами.
-
-#### Подсказки и инструкции
-
-* Проверьте существующие пул-реквесты для Вашего языка. Добавьте отзывы с просьбой внести изменения, если они необходимы, или одобрите их.
-
-/// tip | Подсказка
-
-Вы можете добавлять комментарии с предложениями по изменению в существующие пул-реквесты.
-
-Ознакомьтесь с документацией о добавлении отзыва к пул-реквесту, чтобы утвердить его или запросить изменения.
-
-///
-
-* Проверьте проблемы и вопросы, чтобы узнать, есть ли кто-то, координирующий переводы для Вашего языка.
-
-* Добавляйте один пул-реквест для каждой отдельной переведённой страницы. Это значительно облегчит другим его просмотр.
-
-Для языков, которые я не знаю, прежде чем добавить перевод в основную ветку, я подожду пока несколько других участников сообщества проверят его.
-
-* Вы также можете проверить, есть ли переводы для Вашего языка и добавить к ним отзыв, который поможет мне убедиться в правильности перевода. Тогда я смогу объединить его с основной веткой.
-
-* Используйте те же самые примеры кода Python. Переводите только текст документации. Вам не нужно ничего менять, чтобы эти примеры работали.
-
-* Используйте те же самые изображения, имена файлов и ссылки. Вы не должны менять ничего для сохранения работоспособности.
-
-* Чтобы узнать 2-буквенный код языка, на который Вы хотите сделать перевод, Вы можете воспользоваться таблицей Список кодов языков ISO 639-1.
-
-#### Существующий язык
-
-Допустим, Вы хотите перевести страницу на язык, на котором уже есть какие-то переводы, например, на испанский.
-
-Кодом испанского языка является `es`. А значит директория для переводов на испанский язык: `docs/es/`.
-
-/// tip | Подсказка
-
-Главный ("официальный") язык - английский, директория для него `docs/en/`.
-
-///
-
-Вы можете запустить сервер документации на испанском:
-
-
-
-```console
-// Используйте команду "live" и передайте код языка в качестве аргумента командной строки
-$ python ./scripts/docs.py live es
-
-[INFO] Serving on http://127.0.0.1:8008
-[INFO] Start watching changes
-[INFO] Start detecting changes
-```
-
-
-
-Теперь Вы можете перейти по адресу: http://127.0.0.1:8008 и наблюдать вносимые Вами изменения вживую.
-
-
-Если Вы посмотрите на сайт документации FastAPI, то увидите, что все страницы есть на каждом языке. Но некоторые страницы не переведены и имеют уведомление об отсутствующем переводе.
-
-Но когда Вы запускаете сайт локально, Вы видите только те страницы, которые уже переведены.
-
-
-Предположим, что Вы хотите добавить перевод страницы [Основные свойства](features.md){.internal-link target=_blank}.
-
-* Скопируйте файл:
-
-```
-docs/en/docs/features.md
-```
-
-* Вставьте его точно в то же место, но в директорию языка, на который Вы хотите сделать перевод, например:
-
-```
-docs/es/docs/features.md
-```
-
-/// tip | Подсказка
-
-Заметьте, что в пути файла мы изменили только код языка с `en` на `es`.
-
-///
-
-* Теперь откройте файл конфигурации MkDocs для английского языка, расположенный тут:
-
-```
-docs/en/mkdocs.yml
-```
-
-* Найдите в файле конфигурации место, где расположена строка `docs/features.md`. Похожее на это:
-
-```YAML hl_lines="8"
-site_name: FastAPI
-# More stuff
-nav:
-- FastAPI: index.md
-- Languages:
- - en: /
- - es: /es/
-- features.md
-```
-
-* Откройте файл конфигурации MkDocs для языка, на который Вы переводите, например:
-
-```
-docs/es/mkdocs.yml
-```
-
-* Добавьте строку `docs/features.md` точно в то же место, как и в случае для английского, как-то так:
-
-```YAML hl_lines="8"
-site_name: FastAPI
-# More stuff
-nav:
-- FastAPI: index.md
-- Languages:
- - en: /
- - es: /es/
-- features.md
-```
-
-Убедитесь, что при наличии других записей, новая запись с Вашим переводом находится точно в том же порядке, что и в английской версии.
-
-Если Вы зайдёте в свой браузер, то увидите, что в документации стал отображаться Ваш новый раздел.🎉
-
-Теперь Вы можете переводить эту страницу и смотреть, как она выглядит при сохранении файла.
-
-#### Новый язык
-
-Допустим, Вы хотите добавить перевод для языка, на который пока что не переведена ни одна страница.
-
-Скажем, Вы решили сделать перевод для креольского языка, но его еще нет в документации.
-
-Перейдите в таблицу кодов языков по ссылке указанной выше, где найдёте, что кодом креольского языка является `ht`.
-
-Затем запустите скрипт, генерирующий директорию для переводов на новые языки:
-
-
-
-```console
-// Используйте команду new-lang и передайте код языка в качестве аргумента командной строки
-$ python ./scripts/docs.py new-lang ht
-
-Successfully initialized: docs/ht
-Updating ht
-Updating en
-```
-
-
-
-После чего Вы можете проверить в своем редакторе кода, что появился новый каталог `docs/ht/`.
-
-/// tip | Подсказка
-
-Создайте первый пул-реквест, который будет содержать только пустую директорию для нового языка, прежде чем добавлять переводы.
-
-Таким образом, другие участники могут переводить другие страницы, пока Вы работаете над одной. 🚀
-
-///
-
-Начните перевод с главной страницы `docs/ht/index.md`.
-
-В дальнейшем можно действовать, как указано в предыдущих инструкциях для "существующего языка".
-
-##### Новый язык не поддерживается
-
-Если при запуске скрипта `./scripts/docs.py live` Вы получаете сообщение об ошибке, что язык не поддерживается, что-то вроде:
-
-```
- raise TemplateNotFound(template)
-jinja2.exceptions.TemplateNotFound: partials/language/xx.html
-```
-
-Сие означает, что тема не поддерживает этот язык (в данном случае с поддельным 2-буквенным кодом `xx`).
-
-Но не стоит переживать. Вы можете установить языком темы английский, а затем перевести текст документации.
-
-Если возникла такая необходимость, отредактируйте `mkdocs.yml` для Вашего нового языка. Это будет выглядеть как-то так:
-
-```YAML hl_lines="5"
-site_name: FastAPI
-# More stuff
-theme:
- # More stuff
- language: xx
-```
-
-Измените `xx` (код Вашего языка) на `en` и перезапустите сервер.
-
-#### Предпросмотр результата
-
-Когда Вы запускаете скрипт `./scripts/docs.py` с командой `live`, то будут показаны файлы и переводы для указанного языка.
-
-Но когда Вы закончите, то можете посмотреть, как это будет выглядеть по-настоящему.
-
-Для этого сначала создайте всю документацию:
-
-
-
-```console
-// Используйте команду "build-all", это займёт немного времени
-$ python ./scripts/docs.py build-all
-
-Updating es
-Updating en
-Building docs for: en
-Building docs for: es
-Successfully built docs for: es
-Copying en index.md to README.md
-```
-
-
-
-Скрипт сгенерирует `./docs_build/` для каждого языка. Он добавит все файлы с отсутствующими переводами с пометкой о том, что "у этого файла еще нет перевода". Но Вам не нужно ничего делать с этим каталогом.
-
-Затем он создаст независимые сайты MkDocs для каждого языка, объединит их и сгенерирует конечный результат на `./site/`.
-
-После чего Вы сможете запустить сервер со всеми языками командой `serve`:
-
-
-
-```console
-// Используйте команду "serve" после того, как отработает команда "build-all"
-$ python ./scripts/docs.py serve
-
-Warning: this is a very simple server. For development, use mkdocs serve instead.
-This is here only to preview a site with translations already built.
-Make sure you run the build-all command first.
-Serving at: http://127.0.0.1:8008
-```
-
-
-
-## Тесты
-
-Также в репозитории есть скрипт, который Вы можете запустить локально, чтобы протестировать весь код и сгенерировать отчеты о покрытии тестами в HTML:
-
-
-
-Эта команда создаст директорию `./htmlcov/`, в которой будет файл `./htmlcov/index.html`. Открыв его в Вашем браузере, Вы можете в интерактивном режиме изучить, все ли части кода охвачены тестами.
diff --git a/docs/ru/docs/deployment/concepts.md b/docs/ru/docs/deployment/concepts.md
index 7cdc29526..acfa1f4fe 100644
--- a/docs/ru/docs/deployment/concepts.md
+++ b/docs/ru/docs/deployment/concepts.md
@@ -216,7 +216,7 @@
Каждый из этих процессов будет запускать ваше приложение для обработки полученного **запроса** и возвращения вычисленного **ответа** и они будут использовать оперативную память.
-
+
Безусловно, на этом же сервере будут работать и **другие процессы**, которые не относятся к вашему приложению.
diff --git a/docs/ru/docs/deployment/docker.md b/docs/ru/docs/deployment/docker.md
index 31da01b78..c72f67172 100644
--- a/docs/ru/docs/deployment/docker.md
+++ b/docs/ru/docs/deployment/docker.md
@@ -58,7 +58,7 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
## Образы контейнеров
-Docker является одним оз основных инструментов для создания **образов** и **контейнеров** и управления ими.
+Docker является одним из основных инструментов для создания **образов** и **контейнеров** и управления ими.
Существует общедоступный Docker Hub с подготовленными **официальными образами** многих инструментов, окружений, баз данных и приложений.
@@ -87,7 +87,7 @@ Docker является одним оз основных инструменто
Когда **контейнер** запущен, он будет выполнять прописанные в нём команды и программы. Но вы можете изменить его так, чтоб он выполнял другие команды и программы.
-Контейнер буде работать до тех пор, пока выполняется его **главный процесс** (команда или программа).
+Контейнер будет работать до тех пор, пока выполняется его **главный процесс** (команда или программа).
В контейнере обычно выполняется **только один процесс**, но от его имени можно запустить другие процессы, тогда в этом же в контейнере будет выполняться **множество процессов**.
@@ -215,7 +215,7 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
Опция `--upgrade` указывает `pip` обновить библиотеки, емли они уже установлены.
- Ка и в предыдущем шаге с копированием файла, этот шаг также будет использовать **кэш Docker** в случае отсутствия изменений.
+ Как и в предыдущем шаге с копированием файла, этот шаг также будет использовать **кэш Docker** в случае отсутствия изменений.
Использование кэша, особенно на этом шаге, позволит вам **сэкономить** кучу времени при повторной сборке образа, так как зависимости будут сохранены в кеше, а не **загружаться и устанавливаться каждый раз**.
diff --git a/docs/ru/docs/deployment/https.md b/docs/ru/docs/deployment/https.md
index 85c4cce60..d8877a9a1 100644
--- a/docs/ru/docs/deployment/https.md
+++ b/docs/ru/docs/deployment/https.md
@@ -92,7 +92,7 @@
DNS-сервера присылают браузеру определённый **IP-адрес**, тот самый публичный IP-адрес вашего сервера, который вы указали в ресурсной "записи А" при настройке.
-
+
### Рукопожатие TLS
@@ -100,7 +100,7 @@ DNS-сервера присылают браузеру определённый
Первым шагом будет установление соединения между клиентом (браузером) и сервером и выбор криптографического ключа (для шифрования).
-
+
Эта часть клиент-серверного взаимодействия устанавливает TLS-соединение и называется **TLS-рукопожатием**.
@@ -118,7 +118,7 @@ DNS-сервера присылают браузеру определённый
То есть будет выбран сертификат для домена `someapp.example.com`.
-
+
Клиент уже **доверяет** тому, кто выдал этот TLS-сертификат (в нашем случае - Let's Encrypt, но мы ещё обсудим это), потому может **проверить**, действителен ли полученный от сервера сертификат.
@@ -140,19 +140,19 @@ DNS-сервера присылают браузеру определённый
Так клиент отправляет **HTTPS-запрос**. То есть обычный HTTP-запрос, но через зашифрованное TLS-содинение.
-
+
### Расшифровка запроса
Прокси-сервер, используя согласованный с клиентом ключ, расшифрует полученный **зашифрованный запрос** и передаст **обычный (незашифрованный) HTTP-запрос** процессу, запускающему приложение (например, процессу Uvicorn запускающему приложение FastAPI).
-
+
### HTTP-ответ
Приложение обработает запрос и вернёт **обычный (незашифрованный) HTTP-ответ** прокси-серверу.
-
+
### HTTPS-ответ
@@ -160,7 +160,7 @@ DNS-сервера присылают браузеру определённый
Наконец, браузер проверит ответ, в том числе, что тот зашифрован с нужным ключом, **расшифрует его** и обработает.
-
+
Клиент (браузер) знает, что ответ пришёл от правильного сервера, так как использует методы шифрования, согласованные ими раннее через **HTTPS-сертификат**.
@@ -171,7 +171,7 @@ DNS-сервера присылают браузеру определённый
Напомню, что только один процесс (например, прокси-сервер) может прослушивать определённый порт определённого IP-адреса.
Но другие процессы и приложения тоже могут работать на этом же сервере (серверах), если они не пытаются использовать уже занятую **комбинацию IP-адреса и порта** (сокет).
-
+
Таким образом, сервер завершения TLS может обрабатывать HTTPS-запросы и использовать сертификаты для **множества доменов** или приложений и передавать запросы правильным адресатам (другим приложениям).
@@ -181,7 +181,7 @@ DNS-сервера присылают браузеру определённый
Когда это произойдёт, можно запустить другую программу, которая подключится к Let's Encrypt и обновит сертификат(ы). Существуют прокси-серверы, которые могут сделать это действие самостоятельно.
-
+
**TLS-сертификаты** не привязаны к IP-адресу, но **связаны с именем домена**.
diff --git a/docs/ru/docs/fastapi-cli.md b/docs/ru/docs/fastapi-cli.md
new file mode 100644
index 000000000..c0be4a5df
--- /dev/null
+++ b/docs/ru/docs/fastapi-cli.md
@@ -0,0 +1,75 @@
+# FastAPI CLI
+
+**FastAPI CLI** это программа командной строки, которую вы можете использовать для запуска вашего FastAPI приложения, для управления FastAPI-проектом, а также для многих других вещей.
+
+`fastapi-cli` устанавливается вместе со стандартным пакетом FastAPI (при запуске команды `pip install "fastapi[standard]"`). Данный пакет предоставляет доступ к программе `fastapi` через терминал.
+
+Чтобы запустить приложение FastAPI в режиме разработки, вы можете использовать команду `fastapi dev`:
+
+
+
+```console
+$ fastapi dev main.py
+
+ FastAPI Starting development server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://127.0.0.1:8000
+ server Documentation at http://127.0.0.1:8000/docs
+
+ tip Running in development mode, for production use:
+ fastapi run
+
+ Logs:
+
+ INFO Will watch for changes in these directories:
+ ['/home/user/code/awesomeapp']
+ INFO Uvicorn running on http://127.0.0.1:8000(Press CTRL+C to
+ quit)
+ INFO Started reloader process [383138] using WatchFiles
+ INFO Started server process [383153]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+```
+
+
+
+Приложение командной строки `fastapi` это и есть **FastAPI CLI**.
+
+FastAPI CLI берет путь к вашей Python-программе (напр. `main.py`) и автоматически находит объект `FastAPI` (обычно это `app`), затем определяет правильный процесс импорта и запускает сервер приложения.
+
+Для работы в production окружении вместо `fastapi dev` нужно использовать `fastapi run`. 🚀
+
+Внутри **FastAPI CLI** используется Uvicorn, высокопроизводительный, готовый к работе в production сервер ASGI. 😎
+
+## `fastapi dev`
+
+Вызов `fastapi dev` запускает режим разработки.
+
+По умолчанию включена автоматическая перезагрузка (**auto-reload**), благодаря этому при изменении кода происходит перезагрузка сервера приложения. Эта установка требует значительных ресурсов и делает систему менее стабильной. Используйте её только при разработке. Приложение слушает входящие подключения на IP `127.0.0.1`. Это IP адрес вашей машины, предназначенный для внутренних коммуникаций (`localhost`).
+
+## `fastapi run`
+
+Вызов `fastapi run` по умолчанию запускает FastAPI в режиме production.
+
+По умолчанию функция перезагрузки **auto-reload** отключена. Приложение слушает входящие подключения на IP `0.0.0.0`, т.е. на всех доступных адресах компьютера. Таким образом, приложение будет находиться в публичном доступе для любого, кто может подсоединиться к вашей машине. Продуктовые приложения запускаются именно так, например, с помощью контейнеров.
+
+В большинстве случаев вы будете (и должны) использовать прокси-сервер ("termination proxy"), который будет поддерживать HTTPS поверх вашего приложения. Всё будет зависеть от того, как вы развертываете приложение: за вас это либо сделает ваш провайдер, либо вам придется сделать настройки самостоятельно.
+
+/// tip | Подсказка
+
+Вы можете больше узнать об этом в документации по развертыванию приложений [deployment documentation](deployment/index.md){.internal-link target=_blank}.
+
+///
diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md
index 5ebe1494b..a9546cf1e 100644
--- a/docs/ru/docs/index.md
+++ b/docs/ru/docs/index.md
@@ -12,10 +12,10 @@
+
+```console
+$ fastapi dev app/main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Откройте документацию по адресу http://127.0.0.1:8000/docs.
+
+Вы увидите автоматическую API документацию. Она включает в себя маршруты из суб-модулей, используя верные маршруты, префиксы и теги:
+
+
+
+## Подключение существующего маршрута через новый префикс (`prefix`)
+
+Вы можете использовать `.include_router()` несколько раз с одним и тем же маршрутом, применив различные префиксы.
+
+Это может быть полезным, если нужно предоставить доступ к одному и тому же API через различные префиксы, например, `/api/v1` и `/api/latest`.
+
+Это продвинутый способ, который вам может и не пригодится. Мы приводим его на случай, если вдруг вам это понадобится.
+
+## Включение одного маршрутизатора (`APIRouter`) в другой
+
+Точно так же, как вы включаете `APIRouter` в приложение `FastAPI`, вы можете включить `APIRouter` в другой `APIRouter`:
+
+```Python
+router.include_router(other_router)
+```
+
+Удостоверьтесь, что вы сделали это до того, как подключить маршрутизатор (`router`) к вашему `FastAPI` приложению, и *эндпоинты* маршрутизатора `other_router` были также подключены.
diff --git a/docs/ru/docs/tutorial/body-fields.md b/docs/ru/docs/tutorial/body-fields.md
index 0c4cbb09c..5ed5f59fc 100644
--- a/docs/ru/docs/tutorial/body-fields.md
+++ b/docs/ru/docs/tutorial/body-fields.md
@@ -6,21 +6,7 @@
Сначала вы должны импортировать его:
-//// tab | Python 3.10+
-
-```Python hl_lines="2"
-{!> ../../docs_src/body_fields/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_fields/tutorial001_py310.py hl[2] *}
/// warning | Внимание
@@ -32,21 +18,7 @@
Вы можете использовать функцию `Field` с атрибутами модели:
-//// tab | Python 3.10+
-
-```Python hl_lines="9-12"
-{!> ../../docs_src/body_fields/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11-14"
-{!> ../../docs_src/body_fields/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_fields/tutorial001_py310.py hl[9:12] *}
Функция `Field` работает так же, как `Query`, `Path` и `Body`, у неё такие же параметры и т.д.
diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md
index 594e1dbca..9300aa1bd 100644
--- a/docs/ru/docs/tutorial/body-multiple-params.md
+++ b/docs/ru/docs/tutorial/body-multiple-params.md
@@ -8,57 +8,7 @@
Вы также можете объявить параметры тела запроса как необязательные, установив значение по умолчанию, равное `None`:
-//// tab | Python 3.10+
-
-```Python hl_lines="18-20"
-{!> ../../docs_src/body_multiple_params/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="18-20"
-{!> ../../docs_src/body_multiple_params/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="19-21"
-{!> ../../docs_src/body_multiple_params/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать `Annotated` версию, если это возможно.
-
-///
-
-```Python hl_lines="17-19"
-{!> ../../docs_src/body_multiple_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать версию с `Annotated`, если это возможно.
-
-///
-
-```Python hl_lines="19-21"
-{!> ../../docs_src/body_multiple_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
/// note | Заметка
@@ -81,21 +31,7 @@
Но вы также можете объявить множество параметров тела запроса, например `item` и `user`:
-//// tab | Python 3.10+
-
-```Python hl_lines="20"
-{!> ../../docs_src/body_multiple_params/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="22"
-{!> ../../docs_src/body_multiple_params/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
В этом случае **FastAPI** заметит, что в функции есть более одного параметра тела (два параметра, которые являются моделями Pydantic).
@@ -136,57 +72,7 @@
Но вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела запроса, используя `Body`:
-//// tab | Python 3.10+
-
-```Python hl_lines="23"
-{!> ../../docs_src/body_multiple_params/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="23"
-{!> ../../docs_src/body_multiple_params/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="24"
-{!> ../../docs_src/body_multiple_params/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать `Annotated` версию, если это возможно.
-
-///
-
-```Python hl_lines="20"
-{!> ../../docs_src/body_multiple_params/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать `Annotated` версию, если это возможно.
-
-///
-
-```Python hl_lines="22"
-{!> ../../docs_src/body_multiple_params/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
В этом случае, **FastAPI** будет ожидать тело запроса в формате:
@@ -226,57 +112,7 @@ q: str | None = None
Например:
-//// tab | Python 3.10+
-
-```Python hl_lines="27"
-{!> ../../docs_src/body_multiple_params/tutorial004_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="27"
-{!> ../../docs_src/body_multiple_params/tutorial004_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="28"
-{!> ../../docs_src/body_multiple_params/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать `Annotated` версию, если это возможно.
-
-///
-
-```Python hl_lines="25"
-{!> ../../docs_src/body_multiple_params/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать `Annotated` версию, если это возможно.
-
-///
-
-```Python hl_lines="27"
-{!> ../../docs_src/body_multiple_params/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[27] *}
/// info | Информация
@@ -298,57 +134,7 @@ item: Item = Body(embed=True)
так же, как в этом примере:
-//// tab | Python 3.10+
-
-```Python hl_lines="17"
-{!> ../../docs_src/body_multiple_params/tutorial005_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="17"
-{!> ../../docs_src/body_multiple_params/tutorial005_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="18"
-{!> ../../docs_src/body_multiple_params/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать `Annotated` версию, если это возможно.
-
-///
-
-```Python hl_lines="15"
-{!> ../../docs_src/body_multiple_params/tutorial005_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать `Annotated` версию, если это возможно.
-
-///
-
-```Python hl_lines="17"
-{!> ../../docs_src/body_multiple_params/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
В этом случае **FastAPI** будет ожидать тело запроса в формате:
diff --git a/docs/ru/docs/tutorial/body-nested-models.md b/docs/ru/docs/tutorial/body-nested-models.md
index 9abd4f432..430092892 100644
--- a/docs/ru/docs/tutorial/body-nested-models.md
+++ b/docs/ru/docs/tutorial/body-nested-models.md
@@ -6,21 +6,7 @@
Вы можете определять атрибут как подтип. Например, тип `list` в Python:
-//// tab | Python 3.10+
-
-```Python hl_lines="12"
-{!> ../../docs_src/body_nested_models/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="14"
-{!> ../../docs_src/body_nested_models/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
Это приведёт к тому, что обьект `tags` преобразуется в список, несмотря на то что тип его элементов не объявлен.
@@ -34,9 +20,7 @@
Но в версиях Python до 3.9 (начиная с 3.6) сначала вам необходимо импортировать `List` из стандартного модуля `typing` в Python:
-```Python hl_lines="1"
-{!> ../../docs_src/body_nested_models/tutorial002.py!}
-```
+{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
### Объявление `list` с указанием типов для вложенных элементов
@@ -65,29 +49,7 @@ my_list: List[str]
Таким образом, в нашем примере мы можем явно указать тип данных для поля `tags` как "список строк":
-//// tab | Python 3.10+
-
-```Python hl_lines="12"
-{!> ../../docs_src/body_nested_models/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="14"
-{!> ../../docs_src/body_nested_models/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="14"
-{!> ../../docs_src/body_nested_models/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
## Типы множеств
@@ -97,29 +59,7 @@ my_list: List[str]
Тогда мы можем обьявить поле `tags` как множество строк:
-//// tab | Python 3.10+
-
-```Python hl_lines="12"
-{!> ../../docs_src/body_nested_models/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="14"
-{!> ../../docs_src/body_nested_models/tutorial003_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="1 14"
-{!> ../../docs_src/body_nested_models/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
С помощью этого, даже если вы получите запрос с повторяющимися данными, они будут преобразованы в множество уникальных элементов.
@@ -141,57 +81,13 @@ my_list: List[str]
Например, мы можем определить модель `Image`:
-//// tab | Python 3.10+
-
-```Python hl_lines="7-9"
-{!> ../../docs_src/body_nested_models/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9-11"
-{!> ../../docs_src/body_nested_models/tutorial004_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9-11"
-{!> ../../docs_src/body_nested_models/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
### Использование вложенной модели в качестве типа
Также мы можем использовать эту модель как тип атрибута:
-//// tab | Python 3.10+
-
-```Python hl_lines="18"
-{!> ../../docs_src/body_nested_models/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="20"
-{!> ../../docs_src/body_nested_models/tutorial004_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="20"
-{!> ../../docs_src/body_nested_models/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
Это означает, что **FastAPI** будет ожидать тело запроса, аналогичное этому:
@@ -224,29 +120,7 @@ my_list: List[str]
Например, так как в модели `Image` у нас есть поле `url`, то мы можем объявить его как тип `HttpUrl` из модуля Pydantic вместо типа `str`:
-//// tab | Python 3.10+
-
-```Python hl_lines="2 8"
-{!> ../../docs_src/body_nested_models/tutorial005_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="4 10"
-{!> ../../docs_src/body_nested_models/tutorial005_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4 10"
-{!> ../../docs_src/body_nested_models/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
Строка будет проверена на соответствие допустимому URL-адресу и задокументирована в JSON схему / OpenAPI.
@@ -254,29 +128,7 @@ my_list: List[str]
Вы также можете использовать модели Pydantic в качестве типов вложенных в `list`, `set` и т.д:
-//// tab | Python 3.10+
-
-```Python hl_lines="18"
-{!> ../../docs_src/body_nested_models/tutorial006_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="20"
-{!> ../../docs_src/body_nested_models/tutorial006_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="20"
-{!> ../../docs_src/body_nested_models/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
Такая реализация будет ожидать (конвертировать, валидировать, документировать и т.д) JSON-содержимое в следующем формате:
@@ -314,29 +166,7 @@ my_list: List[str]
Вы можете определять модели с произвольным уровнем вложенности:
-//// tab | Python 3.10+
-
-```Python hl_lines="7 12 18 21 25"
-{!> ../../docs_src/body_nested_models/tutorial007_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9 14 20 23 27"
-{!> ../../docs_src/body_nested_models/tutorial007_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9 14 20 23 27"
-{!> ../../docs_src/body_nested_models/tutorial007.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
/// info | Информация
@@ -360,21 +190,7 @@ images: list[Image]
например так:
-//// tab | Python 3.9+
-
-```Python hl_lines="13"
-{!> ../../docs_src/body_nested_models/tutorial008_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="15"
-{!> ../../docs_src/body_nested_models/tutorial008.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
## Универсальная поддержка редактора
@@ -404,21 +220,7 @@ images: list[Image]
В этом случае вы принимаете `dict`, пока у него есть ключи типа `int` со значениями типа `float`:
-//// tab | Python 3.9+
-
-```Python hl_lines="7"
-{!> ../../docs_src/body_nested_models/tutorial009_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/body_nested_models/tutorial009.py!}
-```
-
-////
+{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
/// tip | Совет
diff --git a/docs/ru/docs/tutorial/body-updates.md b/docs/ru/docs/tutorial/body-updates.md
index c80952f70..99f475a41 100644
--- a/docs/ru/docs/tutorial/body-updates.md
+++ b/docs/ru/docs/tutorial/body-updates.md
@@ -6,29 +6,7 @@
Вы можете использовать функцию `jsonable_encoder` для преобразования входных данных в JSON, так как нередки случаи, когда работать можно только с простыми типами данных (например, для хранения в NoSQL-базе данных).
-//// tab | Python 3.10+
-
-```Python hl_lines="28-33"
-{!> ../../docs_src/body_updates/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="30-35"
-{!> ../../docs_src/body_updates/tutorial001_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="30-35"
-{!> ../../docs_src/body_updates/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}
`PUT` используется для получения данных, которые должны полностью заменить существующие данные.
@@ -74,29 +52,7 @@
В результате будет сгенерирован словарь, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию. Затем вы можете использовать это для создания словаря только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:
-//// tab | Python 3.10+
-
-```Python hl_lines="32"
-{!> ../../docs_src/body_updates/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="34"
-{!> ../../docs_src/body_updates/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="34"
-{!> ../../docs_src/body_updates/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}
### Использование параметра `update` в Pydantic
@@ -104,29 +60,7 @@
Например, `stored_item_model.copy(update=update_data)`:
-//// tab | Python 3.10+
-
-```Python hl_lines="33"
-{!> ../../docs_src/body_updates/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="35"
-{!> ../../docs_src/body_updates/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="35"
-{!> ../../docs_src/body_updates/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
### Кратко о частичном обновлении
@@ -143,29 +77,7 @@
* Сохранить данные в своей БД.
* Вернуть обновленную модель.
-//// tab | Python 3.10+
-
-```Python hl_lines="28-35"
-{!> ../../docs_src/body_updates/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="30-37"
-{!> ../../docs_src/body_updates/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="30-37"
-{!> ../../docs_src/body_updates/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}
/// tip | Подсказка
diff --git a/docs/ru/docs/tutorial/body.md b/docs/ru/docs/tutorial/body.md
index 62927f0d1..2c9110226 100644
--- a/docs/ru/docs/tutorial/body.md
+++ b/docs/ru/docs/tutorial/body.md
@@ -22,9 +22,7 @@
Первое, что вам необходимо сделать, это импортировать `BaseModel` из пакета `pydantic`:
-```Python hl_lines="4"
-{!../../docs_src/body/tutorial001.py!}
-```
+{* ../../docs_src/body/tutorial001.py hl[4] *}
## Создание вашей собственной модели
@@ -32,9 +30,7 @@
Используйте аннотации типов Python для всех атрибутов:
-```Python hl_lines="7-11"
-{!../../docs_src/body/tutorial001.py!}
-```
+{* ../../docs_src/body/tutorial001.py hl[7:11] *}
Также как и при описании параметров запроса, когда атрибут модели имеет значение по умолчанию, он является необязательным. Иначе он обязателен. Используйте `None`, чтобы сделать его необязательным без использования конкретных значений по умолчанию.
@@ -62,9 +58,7 @@
Чтобы добавить параметр к вашему *обработчику*, объявите его также, как вы объявляли параметры пути или параметры запроса:
-```Python hl_lines="18"
-{!../../docs_src/body/tutorial001.py!}
-```
+{* ../../docs_src/body/tutorial001.py hl[18] *}
...и укажите созданную модель в качестве типа параметра, `Item`.
@@ -131,9 +125,7 @@
Внутри функции вам доступны все атрибуты объекта модели напрямую:
-```Python hl_lines="21"
-{!../../docs_src/body/tutorial002.py!}
-```
+{* ../../docs_src/body/tutorial002.py hl[21] *}
## Тело запроса + параметры пути
@@ -141,9 +133,7 @@
**FastAPI** распознает, какие параметры функции соответствуют параметрам пути и должны быть **получены из пути**, а какие параметры функции, объявленные как модели Pydantic, должны быть **получены из тела запроса**.
-```Python hl_lines="17-18"
-{!../../docs_src/body/tutorial003.py!}
-```
+{* ../../docs_src/body/tutorial003.py hl[17:18] *}
## Тело запроса + параметры пути + параметры запроса
@@ -151,9 +141,7 @@
**FastAPI** распознает каждый из них и возьмет данные из правильного источника.
-```Python hl_lines="18"
-{!../../docs_src/body/tutorial004.py!}
-```
+{* ../../docs_src/body/tutorial004.py hl[18] *}
Параметры функции распознаются следующим образом:
diff --git a/docs/ru/docs/tutorial/cookie-param-models.md b/docs/ru/docs/tutorial/cookie-param-models.md
new file mode 100644
index 000000000..3a57443bb
--- /dev/null
+++ b/docs/ru/docs/tutorial/cookie-param-models.md
@@ -0,0 +1,76 @@
+# Модели параметров cookie
+
+Если у вас есть группа **cookies**, которые связаны между собой, вы можете создать **Pydantic-модель** для их объявления. 🍪
+
+Это позволит вам **переиспользовать модель** в **разных местах**, а также объявить проверки и метаданные сразу для всех параметров. 😎
+
+/// note | Заметка
+
+Этот функционал доступен с версии `0.115.0`. 🤓
+
+///
+
+/// tip | Совет
+
+Такой же подход применяется для `Query`, `Cookie`, и `Header`. 😎
+
+///
+
+## Pydantic-модель для cookies
+
+Объявите параметры **cookie**, которые вам нужны, в **Pydantic-модели**, а затем объявите параметр как `Cookie`:
+
+{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
+
+**FastAPI** **извлечёт** данные для **каждого поля** из **cookies**, полученных в запросе, и выдаст вам объявленную Pydantic-модель.
+
+## Проверка сгенерированной документации
+
+Вы можете посмотреть объявленные cookies в графическом интерфейсе Документации по пути `/docs`:
+
+
+
+
+
+/// info | Дополнительная информация
+
+Имейте в виду, что, поскольку **браузеры обрабатывают cookies** особым образом и под капотом, они **не** позволят **JavaScript** легко получить доступ к ним.
+
+Если вы перейдёте к **графическому интерфейсу документации API** по пути `/docs`, то сможете увидеть **документацию** по cookies для ваших *операций путей*.
+
+Но даже если вы **заполните данные** и нажмёте "Execute", поскольку графический интерфейс Документации работает с **JavaScript**, cookies не будут отправлены, и вы увидите сообщение об **ошибке** как будто не указывали никаких значений.
+
+///
+
+## Запрет дополнительных cookies
+
+В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** cookies, которые вы хотите получать.
+
+Теперь ваш API сам решает, принимать ли cookies. 🤪🍪
+
+Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) любые дополнительные (`extra`) поля:
+
+{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *}
+
+Если клиент попробует отправить **дополнительные cookies**, то в ответ он получит **ошибку**.
+
+Бедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы API его отклонил. 🍪
+
+Например, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что cookie `santa_tracker` не разрешён:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["cookie", "santa_tracker"],
+ "msg": "Extra inputs are not permitted",
+ "input": "good-list-please"
+ }
+ ]
+}
+```
+
+## Заключение
+
+Вы можете использовать **Pydantic-модели** для объявления **cookies** в **FastAPI**. 😎
diff --git a/docs/ru/docs/tutorial/cookie-params.md b/docs/ru/docs/tutorial/cookie-params.md
index 88533f7f8..d1ed943d7 100644
--- a/docs/ru/docs/tutorial/cookie-params.md
+++ b/docs/ru/docs/tutorial/cookie-params.md
@@ -6,21 +6,7 @@
Сначала импортируйте `Cookie`:
-//// tab | Python 3.10+
-
-```Python hl_lines="1"
-{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/cookie_params/tutorial001_py310.py hl[1] *}
## Объявление параметров `Cookie`
@@ -28,21 +14,7 @@
Первое значение - это значение по умолчанию, вы можете передать все дополнительные параметры проверки или аннотации:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/cookie_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/cookie_params/tutorial001_py310.py hl[7] *}
/// note | Технические детали
diff --git a/docs/ru/docs/tutorial/cors.md b/docs/ru/docs/tutorial/cors.md
index 622cd5a98..e8bf04576 100644
--- a/docs/ru/docs/tutorial/cors.md
+++ b/docs/ru/docs/tutorial/cors.md
@@ -46,9 +46,7 @@
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
-```Python hl_lines="2 6-11 13-19"
-{!../../docs_src/cors/tutorial001.py!}
-```
+{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
`CORSMiddleware` использует для параметров "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
diff --git a/docs/ru/docs/tutorial/debugging.md b/docs/ru/docs/tutorial/debugging.md
index 0feeaa20c..05806f087 100644
--- a/docs/ru/docs/tutorial/debugging.md
+++ b/docs/ru/docs/tutorial/debugging.md
@@ -6,9 +6,7 @@
В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую:
-```Python hl_lines="1 15"
-{!../../docs_src/debugging/tutorial001.py!}
-```
+{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
### Описание `__name__ == "__main__"`
diff --git a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md
index 486ff9ea9..8037872b9 100644
--- a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md
+++ b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md
@@ -6,57 +6,7 @@
В предыдущем примере мы возвращали `словарь` из нашей зависимости:
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="11"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="12"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="11"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}
Но затем мы получаем `словарь` в параметре `commons` *функции операции пути*. И мы знаем, что редакторы не могут обеспечить достаточную поддержку для `словаря`, поскольку они не могут знать их ключи и типы значений.
@@ -117,165 +67,15 @@ fluffy = Cat(name="Mr Fluffy")
Теперь мы можем изменить зависимость `common_parameters`, указанную выше, на класс `CommonQueryParams`:
-//// tab | Python 3.10+
-
-```Python hl_lines="11-15"
-{!> ../../docs_src/dependencies/tutorial002_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="11-15"
-{!> ../../docs_src/dependencies/tutorial002_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="12-16"
-{!> ../../docs_src/dependencies/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9-13"
-{!> ../../docs_src/dependencies/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="11-15"
-{!> ../../docs_src/dependencies/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}
Обратите внимание на метод `__init__`, используемый для создания экземпляра класса:
-//// tab | Python 3.10+
-
-```Python hl_lines="12"
-{!> ../../docs_src/dependencies/tutorial002_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="12"
-{!> ../../docs_src/dependencies/tutorial002_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="13"
-{!> ../../docs_src/dependencies/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/dependencies/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="12"
-{!> ../../docs_src/dependencies/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}
...имеет те же параметры, что и ранее используемая функция `common_parameters`:
-//// tab | Python 3.10+
-
-```Python hl_lines="8"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="10"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="6"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}
Эти параметры и будут использоваться **FastAPI** для "решения" зависимости.
@@ -291,57 +91,7 @@ fluffy = Cat(name="Mr Fluffy")
Теперь вы можете объявить свою зависимость, используя этот класс.
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial002_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial002_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="20"
-{!> ../../docs_src/dependencies/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}
**FastAPI** вызывает класс `CommonQueryParams`. При этом создается "экземпляр" этого класса, который будет передан в качестве параметра `commons` в вашу функцию.
@@ -435,57 +185,7 @@ commons = Depends(CommonQueryParams)
...как тут:
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="20"
-{!> ../../docs_src/dependencies/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}
Но объявление типа приветствуется, так как в этом случае ваш редактор будет знать, что будет передано в качестве параметра `commons`, и тогда он сможет помочь вам с автодополнением, проверкой типов и т.д:
@@ -572,57 +272,7 @@ commons: CommonQueryParams = Depends()
Аналогичный пример будет выглядеть следующим образом:
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial004_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial004_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="20"
-{!> ../../docs_src/dependencies/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}
...и **FastAPI** будет знать, что делать.
diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
index 305ce46cb..0e4eb95be 100644
--- a/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
+++ b/docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md
@@ -14,39 +14,11 @@
Это должен быть `list` состоящий из `Depends()`:
-//// tab | Python 3.9+
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="18"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 без Annotated
-
-/// подсказка
-
-Рекомендуется использовать версию с Annotated, если возможно.
-
-///
-
-```Python hl_lines="17"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[19] *}
Зависимости из dependencies выполнятся так же, как и обычные зависимости. Но их значения (если они были) не будут переданы в *функцию операции пути*.
-/// подсказка
+/// tip | Подсказка
Некоторые редакторы кода определяют неиспользуемые параметры функций и подсвечивают их как ошибку.
@@ -56,7 +28,7 @@
///
-/// дополнительная | информация
+/// info | Примечание
В этом примере мы используем выдуманные пользовательские заголовки `X-Key` и `X-Token`.
@@ -72,69 +44,13 @@
Они могут объявлять требования к запросу (например заголовки) или другие подзависимости:
-//// tab | Python 3.9+
-
-```Python hl_lines="8 13"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="7 12"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 без Annotated
-
-/// подсказка
-
-Рекомендуется использовать версию с Annotated, если возможно.
-
-///
-
-```Python hl_lines="6 11"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[8,13] *}
### Вызов исключений
Зависимости из dependencies могут вызывать исключения с помощью `raise`, как и обычные зависимости:
-//// tab | Python 3.9+
-
-```Python hl_lines="10 15"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9 14"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 без Annotated
-
-/// подсказка
-
-Рекомендуется использовать версию с Annotated, если возможно.
-
-///
-
-```Python hl_lines="8 13"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[10,15] *}
### Возвращаемые значения
@@ -142,35 +58,7 @@
Таким образом, вы можете переиспользовать обычную зависимость (возвращающую значение), которую вы уже используете где-то в другом месте, и хотя значение не будет использоваться, зависимость будет выполнена:
-//// tab | Python 3.9+
-
-```Python hl_lines="11 16"
-{!> ../../docs_src/dependencies/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10 15"
-{!> ../../docs_src/dependencies/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 без Annotated
-
-/// подсказка
-
-Рекомендуется использовать версию с Annotated, если возможно.
-
-///
-
-```Python hl_lines="9 14"
-{!> ../../docs_src/dependencies/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial006_an_py39.py hl[11,16] *}
## Dependencies для группы *операций путей*
diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md
index 83f8ec0d2..e64f6777c 100644
--- a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md
+++ b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md
@@ -29,21 +29,15 @@ FastAPI поддерживает зависимости, которые выпо
Перед созданием ответа будет выполнен только код до и включая `yield`.
-```Python hl_lines="2-4"
-{!../../docs_src/dependencies/tutorial007.py!}
-```
+{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *}
Полученное значение и есть то, что будет внедрено в функцию операции пути и другие зависимости:
-```Python hl_lines="4"
-{!../../docs_src/dependencies/tutorial007.py!}
-```
+{* ../../docs_src/dependencies/tutorial007.py hl[4] *}
Код, следующий за оператором `yield`, выполняется после доставки ответа:
-```Python hl_lines="5-6"
-{!../../docs_src/dependencies/tutorial007.py!}
-```
+{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *}
/// tip | Подсказка
@@ -63,9 +57,7 @@ FastAPI поддерживает зависимости, которые выпо
Таким же образом можно использовать `finally`, чтобы убедиться, что обязательные шаги при выходе выполнены, независимо от того, было ли исключение или нет.
-```Python hl_lines="3 5"
-{!../../docs_src/dependencies/tutorial007.py!}
-```
+{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *}
## Подзависимости с `yield`
@@ -75,35 +67,7 @@ FastAPI поддерживает зависимости, которые выпо
Например, `dependency_c` может иметь зависимость от `dependency_b`, а `dependency_b` от `dependency_a`:
-//// tab | Python 3.9+
-
-```Python hl_lines="6 14 22"
-{!> ../../docs_src/dependencies/tutorial008_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="5 13 21"
-{!> ../../docs_src/dependencies/tutorial008_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="4 12 20"
-{!> ../../docs_src/dependencies/tutorial008.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[6,14,22] *}
И все они могут использовать `yield`.
@@ -111,35 +75,7 @@ FastAPI поддерживает зависимости, которые выпо
И, в свою очередь, `dependency_b` нуждается в том, чтобы значение из `dependency_a` (здесь `dep_a`) было доступно для ее завершающего кода.
-//// tab | Python 3.9+
-
-```Python hl_lines="18-19 26-27"
-{!> ../../docs_src/dependencies/tutorial008_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="17-18 25-26"
-{!> ../../docs_src/dependencies/tutorial008_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="16-17 24-25"
-{!> ../../docs_src/dependencies/tutorial008.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial008_an_py39.py hl[18:19,26:27] *}
Точно так же можно иметь часть зависимостей с `yield`, часть с `return`, и какие-то из них могут зависеть друг от друга.
@@ -303,9 +239,7 @@ with open("./somefile.txt") as f:
Вы также можете использовать их внутри зависимостей **FastAPI** с `yield`, используя операторы
`with` или `async with` внутри функции зависимости:
-```Python hl_lines="1-9 13"
-{!../../docs_src/dependencies/tutorial010.py!}
-```
+{* ../../docs_src/dependencies/tutorial010.py hl[1:9,13] *}
/// tip | Подсказка
diff --git a/docs/ru/docs/tutorial/dependencies/global-dependencies.md b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
index a4dfeb8ac..5d2e70f6e 100644
--- a/docs/ru/docs/tutorial/dependencies/global-dependencies.md
+++ b/docs/ru/docs/tutorial/dependencies/global-dependencies.md
@@ -6,35 +6,7 @@
В этом случае они будут применяться ко всем *операциям пути* в приложении:
-//// tab | Python 3.9+
-
-```Python hl_lines="16"
-{!> ../../docs_src/dependencies/tutorial012_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="16"
-{!> ../../docs_src/dependencies/tutorial012_an.py!}
-```
-
-////
-
-//// tab | Python 3.8 non-Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать 'Annotated' версию, если это возможно.
-
-///
-
-```Python hl_lines="15"
-{!> ../../docs_src/dependencies/tutorial012.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *}
Все способы [добавления зависимостей в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.
diff --git a/docs/ru/docs/tutorial/dependencies/index.md b/docs/ru/docs/tutorial/dependencies/index.md
index b6cf7c780..28790bd5a 100644
--- a/docs/ru/docs/tutorial/dependencies/index.md
+++ b/docs/ru/docs/tutorial/dependencies/index.md
@@ -29,57 +29,7 @@
Давайте для начала сфокусируемся на зависимостях.
Это просто функция, которая может принимать все те же параметры, что и *функции обработки пути*:
-//// tab | Python 3.10+
-
-```Python hl_lines="8-9"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="8-11"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9-12"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Подсказка
-
-Настоятельно рекомендуем использовать `Annotated` версию насколько это возможно.
-
-///
-
-```Python hl_lines="6-7"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Подсказка
-
-Настоятельно рекомендуем использовать `Annotated` версию насколько это возможно.
-
-///
-
-```Python hl_lines="8-11"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}
**И всё.**
@@ -111,113 +61,13 @@
### Import `Depends`
-//// tab | Python 3.10+
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Подсказка
-
-Настоятельно рекомендуем использовать `Annotated` версию насколько это возможно.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Подсказка
-
-Настоятельно рекомендуем использовать `Annotated` версию насколько это возможно.
-
-///
-
-```Python hl_lines="3"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}
### Объявите зависимость в "зависимом"
Точно так же, как вы использовали `Body`, `Query` и т.д. с вашей *функцией обработки пути* для параметров, используйте `Depends` с новым параметром:
-//// tab | Python 3.10+
-
-```Python hl_lines="13 18"
-{!> ../../docs_src/dependencies/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="15 20"
-{!> ../../docs_src/dependencies/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="16 21"
-{!> ../../docs_src/dependencies/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Подсказка
-
-Настоятельно рекомендуем использовать `Annotated` версию насколько это возможно.
-
-///
-
-```Python hl_lines="11 16"
-{!> ../../docs_src/dependencies/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Подсказка
-
-Настоятельно рекомендуем использовать `Annotated` версию насколько это возможно.
-
-///
-
-```Python hl_lines="15 20"
-{!> ../../docs_src/dependencies/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}
`Depends` работает немного иначе. Вы передаёте в `Depends` одиночный параметр, который будет похож на функцию.
@@ -270,29 +120,7 @@ commons: Annotated[dict, Depends(common_parameters)]
Но потому что мы используем `Annotated`, мы можем хранить `Annotated` значение в переменной и использовать его в нескольких местах:
-//// tab | Python 3.10+
-
-```Python hl_lines="12 16 21"
-{!> ../../docs_src/dependencies/tutorial001_02_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="14 18 23"
-{!> ../../docs_src/dependencies/tutorial001_02_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="15 19 24"
-{!> ../../docs_src/dependencies/tutorial001_02_an.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}
/// tip | Подсказка
diff --git a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md
index 0e8cb20e7..5e8de0c4a 100644
--- a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md
+++ b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md
@@ -10,57 +10,7 @@
Можно создать первую зависимость следующим образом:
-//// tab | Python 3.10+
-
-```Python hl_lines="8-9"
-{!> ../../docs_src/dependencies/tutorial005_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="8-9"
-{!> ../../docs_src/dependencies/tutorial005_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="9-10"
-{!> ../../docs_src/dependencies/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.10 без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="6-7"
-{!> ../../docs_src/dependencies/tutorial005_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6 без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="8-9"
-{!> ../../docs_src/dependencies/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}
Она объявляет необязательный параметр запроса `q` как строку, а затем возвращает его.
@@ -70,57 +20,7 @@
Затем можно создать еще одну функцию зависимости, которая в то же время содержит внутри себя первую зависимость (таким образом, она тоже является "зависимой"):
-//// tab | Python 3.10+
-
-```Python hl_lines="13"
-{!> ../../docs_src/dependencies/tutorial005_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="13"
-{!> ../../docs_src/dependencies/tutorial005_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="14"
-{!> ../../docs_src/dependencies/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.10 без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="11"
-{!> ../../docs_src/dependencies/tutorial005_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6 без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="13"
-{!> ../../docs_src/dependencies/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}
Остановимся на объявленных параметрах:
@@ -133,57 +33,7 @@
Затем мы можем использовать зависимость вместе с:
-//// tab | Python 3.10+
-
-```Python hl_lines="23"
-{!> ../../docs_src/dependencies/tutorial005_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="23"
-{!> ../../docs_src/dependencies/tutorial005_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="24"
-{!> ../../docs_src/dependencies/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.10 без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="19"
-{!> ../../docs_src/dependencies/tutorial005_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6 без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="22"
-{!> ../../docs_src/dependencies/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}
/// info | Дополнительная информация
diff --git a/docs/ru/docs/tutorial/encoder.md b/docs/ru/docs/tutorial/encoder.md
index 523644ac8..4ed5039b3 100644
--- a/docs/ru/docs/tutorial/encoder.md
+++ b/docs/ru/docs/tutorial/encoder.md
@@ -20,21 +20,7 @@
Она принимает объект, например, модель Pydantic, и возвращает его версию, совместимую с JSON:
-//// tab | Python 3.10+
-
-```Python hl_lines="4 21"
-{!> ../../docs_src/encoder/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="5 22"
-{!> ../../docs_src/encoder/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
В данном примере она преобразует Pydantic модель в `dict`, а `datetime` - в `str`.
diff --git a/docs/ru/docs/tutorial/extra-data-types.md b/docs/ru/docs/tutorial/extra-data-types.md
index 82cb0ff7a..6d6d4aa9f 100644
--- a/docs/ru/docs/tutorial/extra-data-types.md
+++ b/docs/ru/docs/tutorial/extra-data-types.md
@@ -55,36 +55,8 @@
Вот пример *операции пути* с параметрами, который демонстрирует некоторые из вышеперечисленных типов.
-//// tab | Python 3.8 и выше
-
-```Python hl_lines="1 3 12-16"
-{!> ../../docs_src/extra_data_types/tutorial001.py!}
-```
-
-////
-
-//// tab | Python 3.10 и выше
-
-```Python hl_lines="1 2 11-15"
-{!> ../../docs_src/extra_data_types/tutorial001_py310.py!}
-```
-
-////
+{* ../../docs_src/extra_data_types/tutorial001.py hl[1,3,12:16] *}
Обратите внимание, что параметры внутри функции имеют свой естественный тип данных, и вы, например, можете выполнять обычные манипуляции с датами, такие как:
-//// tab | Python 3.8 и выше
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/extra_data_types/tutorial001.py!}
-```
-
-////
-
-//// tab | Python 3.10 и выше
-
-```Python hl_lines="17-18"
-{!> ../../docs_src/extra_data_types/tutorial001_py310.py!}
-```
-
-////
+{* ../../docs_src/extra_data_types/tutorial001.py hl[18:19] *}
diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md
index 241f70779..5b51aa402 100644
--- a/docs/ru/docs/tutorial/extra-models.md
+++ b/docs/ru/docs/tutorial/extra-models.md
@@ -20,21 +20,7 @@
Ниже изложена основная идея того, как могут выглядеть эти модели с полями для паролей, а также описаны места, где они используются:
-//// tab | Python 3.10+
-
-```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
-{!> ../../docs_src/extra_models/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
-{!> ../../docs_src/extra_models/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
### Про `**user_in.dict()`
@@ -168,21 +154,7 @@ UserInDB(
В этом случае мы можем определить только различия между моделями (с `password` в чистом виде, с `hashed_password` и без пароля):
-//// tab | Python 3.10+
-
-```Python hl_lines="7 13-14 17-18 21-22"
-{!> ../../docs_src/extra_models/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9 15-16 19-20 23-24"
-{!> ../../docs_src/extra_models/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}
## `Union` или `anyOf`
@@ -198,21 +170,7 @@ UserInDB(
///
-//// tab | Python 3.10+
-
-```Python hl_lines="1 14-15 18-20 33"
-{!> ../../docs_src/extra_models/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="1 14-15 18-20 33"
-{!> ../../docs_src/extra_models/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
### `Union` в Python 3.10
@@ -234,21 +192,7 @@ some_variable: PlaneItem | CarItem
Для этого используйте `typing.List` из стандартной библиотеки Python (или просто `list` в Python 3.9 и выше):
-//// tab | Python 3.9+
-
-```Python hl_lines="18"
-{!> ../../docs_src/extra_models/tutorial004_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="1 20"
-{!> ../../docs_src/extra_models/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
## Ответ с произвольным `dict`
@@ -258,21 +202,7 @@ some_variable: PlaneItem | CarItem
В этом случае вы можете использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше):
-//// tab | Python 3.9+
-
-```Python hl_lines="6"
-{!> ../../docs_src/extra_models/tutorial005_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="1 8"
-{!> ../../docs_src/extra_models/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
## Резюме
diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md
index 309f26c4f..cb3d19a71 100644
--- a/docs/ru/docs/tutorial/first-steps.md
+++ b/docs/ru/docs/tutorial/first-steps.md
@@ -2,9 +2,7 @@
Самый простой FastAPI файл может выглядеть так:
-```Python
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py *}
Скопируйте в файл `main.py`.
@@ -133,9 +131,7 @@ OpenAPI описывает схему API. Эта схема содержит о
### Шаг 1: импортируйте `FastAPI`
-```Python hl_lines="1"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
`FastAPI` это класс в Python, который предоставляет всю функциональность для API.
@@ -149,9 +145,7 @@ OpenAPI описывает схему API. Эта схема содержит о
### Шаг 2: создайте экземпляр `FastAPI`
-```Python hl_lines="3"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
Переменная `app` является экземпляром класса `FastAPI`.
@@ -171,9 +165,7 @@ $ uvicorn main:app --reload
Если создать такое приложение:
-```Python hl_lines="3"
-{!../../docs_src/first_steps/tutorial002.py!}
-```
+{* ../../docs_src/first_steps/tutorial002.py hl[3] *}
И поместить его в `main.py`, тогда вызов `uvicorn` будет таким:
@@ -250,9 +242,7 @@ https://example.com/items/foo
#### Определите *декоратор операции пути (path operation decorator)*
-```Python hl_lines="6"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
Декоратор `@app.get("/")` указывает **FastAPI**, что функция, прямо под ним, отвечает за обработку запросов, поступающих по адресу:
@@ -306,9 +296,7 @@ https://example.com/items/foo
* **операция**: `get`.
* **функция**: функция ниже "декоратора" (ниже `@app.get("/")`).
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
Это обычная Python функция.
@@ -320,9 +308,7 @@ https://example.com/items/foo
Вы также можете определить ее как обычную функцию вместо `async def`:
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial003.py!}
-```
+{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note | Технические детали
@@ -332,9 +318,7 @@ https://example.com/items/foo
### Шаг 5: верните результат
-```Python hl_lines="8"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.
diff --git a/docs/ru/docs/tutorial/handling-errors.md b/docs/ru/docs/tutorial/handling-errors.md
index a06644376..c596abe1f 100644
--- a/docs/ru/docs/tutorial/handling-errors.md
+++ b/docs/ru/docs/tutorial/handling-errors.md
@@ -25,9 +25,7 @@
### Импортируйте `HTTPException`
-```Python hl_lines="1"
-{!../../docs_src/handling_errors/tutorial001.py!}
-```
+{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
### Вызовите `HTTPException` в своем коде
@@ -41,9 +39,7 @@
В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:
-```Python hl_lines="11"
-{!../../docs_src/handling_errors/tutorial001.py!}
-```
+{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
### Возвращаемый ответ
@@ -81,9 +77,7 @@
Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки:
-```Python hl_lines="14"
-{!../../docs_src/handling_errors/tutorial002.py!}
-```
+{* ../../docs_src/handling_errors/tutorial002.py hl[14] *}
## Установка пользовательских обработчиков исключений
@@ -95,9 +89,7 @@
Можно добавить собственный обработчик исключений с помощью `@app.exception_handler()`:
-```Python hl_lines="5-7 13-18 24"
-{!../../docs_src/handling_errors/tutorial003.py!}
-```
+{* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *}
Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`.
@@ -135,9 +127,7 @@
Обработчик исключения получит объект `Request` и исключение.
-```Python hl_lines="2 14-16"
-{!../../docs_src/handling_errors/tutorial004.py!}
-```
+{* ../../docs_src/handling_errors/tutorial004.py hl[2,14:16] *}
Теперь, если перейти к `/items/foo`, то вместо стандартной JSON-ошибки с:
@@ -188,9 +178,7 @@ path -> item_id
Например, для этих ошибок можно вернуть обычный текстовый ответ вместо JSON:
-```Python hl_lines="3-4 9-11 22"
-{!../../docs_src/handling_errors/tutorial004.py!}
-```
+{* ../../docs_src/handling_errors/tutorial004.py hl[3:4,9:11,22] *}
/// note | Технические детали
@@ -206,9 +194,7 @@ path -> item_id
Вы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д.
-```Python hl_lines="14"
-{!../../docs_src/handling_errors/tutorial005.py!}
-```
+{* ../../docs_src/handling_errors/tutorial005.py hl[14] *}
Теперь попробуйте отправить недействительный элемент, например:
@@ -266,8 +252,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
Если вы хотите использовать исключение вместе с теми же обработчиками исключений по умолчанию из **FastAPI**, вы можете импортировать и повторно использовать обработчики исключений по умолчанию из `fastapi.exception_handlers`:
-```Python hl_lines="2-5 15 21"
-{!../../docs_src/handling_errors/tutorial006.py!}
-```
+{* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *}
В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.
diff --git a/docs/ru/docs/tutorial/header-param-models.md b/docs/ru/docs/tutorial/header-param-models.md
new file mode 100644
index 000000000..4f54e3e15
--- /dev/null
+++ b/docs/ru/docs/tutorial/header-param-models.md
@@ -0,0 +1,72 @@
+# Модели Header-параметров
+
+Если у вас есть группа связанных **header-параметров**, то вы можете объединить их в одну **Pydantic-модель**.
+
+Это позволит вам **переиспользовать модель** в **разных местах**, а также задать валидацию и метаданные сразу для всех параметров. 😎
+
+/// note | Заметка
+
+Этот функционал доступен в FastAPI начиная с версии `0.115.0`. 🤓
+
+///
+
+## Header-параметры в виде Pydantic-модели
+
+Объявите нужные **header-параметры** в **Pydantic-модели** и затем аннотируйте параметр как `Header`:
+
+{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
+
+**FastAPI** **извлечёт** данные для **каждого поля** из **заголовков** запроса и выдаст заданную вами Pydantic-модель.
+
+## Проверьте документацию
+
+Вы можете посмотреть нужные header-параметры в графическом интерфейсе сгенерированной документации по пути `/docs`:
+
+
+
+
+
+## Как запретить дополнительные заголовки
+
+В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** заголовки, которые вы хотите получать.
+
+Вы можете использовать возможности конфигурации Pydantic-модели для того, чтобы запретить (`forbid`) любые дополнительные (`extra`) поля:
+
+{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}
+
+Если клиент попробует отправить **дополнительные заголовки**, то в ответ он получит **ошибку**.
+
+Например, если клиент попытается отправить заголовок `tool` со значением `plumbus`, то в ответ он получит ошибку, сообщающую ему, что header-параметр `tool` не разрешен:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["header", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus",
+ }
+ ]
+}
+```
+
+## Как отключить автоматическое преобразование подчеркиваний
+
+Как и в случае с обычными заголовками, если у вас в именах параметров имеются символы подчеркивания, они **автоматически преобразовываются в дефис**.
+
+Например, если в коде есть header-параметр `save_data`, то ожидаемый HTTP-заголовок будет `save-data` и именно так он будет отображаться в документации.
+
+Если по каким-то причинам вам нужно отключить данное автоматическое преобразование, это можно сделать и для Pydantic-моделей для header-параметров.
+
+{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}
+
+/// warning | Внимание
+
+Перед тем как устанавливать для параметра `convert_underscores` значение `False`, имейте в виду, что некоторые HTTP-прокси и серверы не разрешают использовать заголовки с символами подчеркивания.
+
+///
+
+## Резюме
+
+Вы можете использовать **Pydantic-модели** для объявления **header-параметров** в **FastAPI**. 😎
diff --git a/docs/ru/docs/tutorial/header-params.md b/docs/ru/docs/tutorial/header-params.md
index 904709b04..e892cfc07 100644
--- a/docs/ru/docs/tutorial/header-params.md
+++ b/docs/ru/docs/tutorial/header-params.md
@@ -6,57 +6,7 @@
Сперва импортируйте `Header`:
-//// tab | Python 3.10+
-
-```Python hl_lines="3"
-{!> ../../docs_src/header_params/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/header_params/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3"
-{!> ../../docs_src/header_params/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/header_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="3"
-{!> ../../docs_src/header_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
## Объявление параметров `Header`
@@ -64,57 +14,7 @@
Первое значение является значением по умолчанию, вы можете передать все дополнительные параметры валидации или аннотации:
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/header_params/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/header_params/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/header_params/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/header_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/header_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
/// note | Технические детали
@@ -146,57 +46,7 @@
Если по какой-либо причине вам необходимо отключить автоматическое преобразование подчеркиваний в дефисы, установите для параметра `convert_underscores` в `Header` значение `False`:
-//// tab | Python 3.10+
-
-```Python hl_lines="10"
-{!> ../../docs_src/header_params/tutorial002_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="11"
-{!> ../../docs_src/header_params/tutorial002_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="12"
-{!> ../../docs_src/header_params/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="8"
-{!> ../../docs_src/header_params/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/header_params/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
/// warning | Внимание
@@ -214,71 +64,7 @@
Например, чтобы объявить заголовок `X-Token`, который может появляться более одного раза, вы можете написать:
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/header_params/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/header_params/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/header_params/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/header_params/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/header_params/tutorial003_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/header_params/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
Если вы взаимодействуете с этой *операцией пути*, отправляя два HTTP-заголовка, таких как:
diff --git a/docs/ru/docs/tutorial/metadata.md b/docs/ru/docs/tutorial/metadata.md
index ae739a043..f07073508 100644
--- a/docs/ru/docs/tutorial/metadata.md
+++ b/docs/ru/docs/tutorial/metadata.md
@@ -17,9 +17,7 @@
Вы можете задать их следующим образом:
-```Python hl_lines="3-16 19-31"
-{!../../docs_src/metadata/tutorial001.py!}
-```
+{* ../../docs_src/metadata/tutorial001.py hl[3:16,19:31] *}
/// tip | Подсказка
@@ -51,9 +49,7 @@
Создайте метаданные для ваших тегов и передайте их в параметре `openapi_tags`:
-```Python hl_lines="3-16 18"
-{!../../docs_src/metadata/tutorial004.py!}
-```
+{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *}
Помните, что вы можете использовать Markdown внутри описания, к примеру "login" будет отображен жирным шрифтом (**login**) и "fancy" будет отображаться курсивом (_fancy_).
@@ -66,9 +62,7 @@
### Используйте собственные теги
Используйте параметр `tags` с вашими *операциями пути* (и `APIRouter`ами), чтобы присвоить им различные теги:
-```Python hl_lines="21 26"
-{!../../docs_src/metadata/tutorial004.py!}
-```
+{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
/// info | Дополнительная информация
@@ -96,9 +90,7 @@
К примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`:
-```Python hl_lines="3"
-{!../../docs_src/metadata/tutorial002.py!}
-```
+{* ../../docs_src/metadata/tutorial002.py hl[3] *}
Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые его использует.
@@ -115,6 +107,4 @@
К примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc:
-```Python hl_lines="3"
-{!../../docs_src/metadata/tutorial003.py!}
-```
+{* ../../docs_src/metadata/tutorial003.py hl[3] *}
diff --git a/docs/ru/docs/tutorial/middleware.md b/docs/ru/docs/tutorial/middleware.md
new file mode 100644
index 000000000..845e881e1
--- /dev/null
+++ b/docs/ru/docs/tutorial/middleware.md
@@ -0,0 +1,74 @@
+# Middleware (Промежуточный слой)
+
+Вы можете добавить промежуточный слой (middleware) в **FastAPI** приложение.
+
+"Middleware" это функция, которая выполняется с каждым запросом до его обработки какой-либо конкретной *операцией пути*.
+А также с каждым ответом перед его возвращением.
+
+
+* Она принимает каждый поступающий **запрос**.
+* Может что-то сделать с этим **запросом** или выполнить любой нужный код.
+* Затем передает **запрос** для последующей обработки (какой-либо *операцией пути*).
+* Получает **ответ** (от *операции пути*).
+* Может что-то сделать с этим **ответом** или выполнить любой нужный код.
+* И возвращает **ответ**.
+
+/// note | Технические детали
+
+Если у вас есть зависимости с `yield`, то код выхода (код после `yield`) будет выполняться *после* middleware.
+
+Если у вас имеются некие фоновые задачи (см. документацию), то они будут запущены после middleware.
+
+///
+
+## Создание middleware
+
+Для создания middleware используйте декоратор `@app.middleware("http")`.
+
+Функция middleware получает:
+
+* `request` (объект запроса).
+* Функцию `call_next`, которая получает `request` в качестве параметра.
+ * Эта функция передаёт `request` соответствующей *операции пути*.
+ * Затем она возвращает ответ `response`, сгенерированный *операцией пути*.
+* Также имеется возможность видоизменить `response`, перед тем как его вернуть.
+
+{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
+
+/// tip | Примечание
+
+Имейте в виду, что можно добавлять свои собственные заголовки при помощи префикса 'X-'.
+
+Если же вы хотите добавить собственные заголовки, которые клиент сможет увидеть в браузере, то вам потребуется добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md){.internal-link target=_blank}), используя параметр `expose_headers`, см. документацию Starlette's CORS docs.
+
+///
+
+/// note | Технические детали
+
+Вы также можете использовать `from starlette.requests import Request`.
+
+**FastAPI** предоставляет такой доступ для удобства разработчиков. Но, на самом деле, это `Request` из Starlette.
+
+///
+
+### До и после `response`
+
+Вы можете добавить код, использующий `request` до передачи его какой-либо *операции пути*.
+
+А также после формирования `response`, до того, как вы его вернёте.
+
+Например, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа:
+
+{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
+
+/// tip | Примечание
+
+Мы используем `time.perf_counter()` вместо `time.time()` для обеспечения большей точности наших примеров. 🤓
+
+///
+
+## Другие middleware
+
+О других middleware вы можете узнать больше в разделе [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
+
+В следующем разделе вы можете прочитать, как настроить CORS с помощью middleware.
diff --git a/docs/ru/docs/tutorial/path-operation-configuration.md b/docs/ru/docs/tutorial/path-operation-configuration.md
index ac12b7084..af471ca69 100644
--- a/docs/ru/docs/tutorial/path-operation-configuration.md
+++ b/docs/ru/docs/tutorial/path-operation-configuration.md
@@ -16,29 +16,7 @@
Но если вы не помните, для чего нужен каждый числовой код, вы можете использовать сокращенные константы в параметре `status`:
-//// tab | Python 3.10+
-
-```Python hl_lines="1 15"
-{!> ../../docs_src/path_operation_configuration/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="3 17"
-{!> ../../docs_src/path_operation_configuration/tutorial001_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3 17"
-{!> ../../docs_src/path_operation_configuration/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}
Этот код состояния будет использован в ответе и будет добавлен в схему OpenAPI.
@@ -54,29 +32,7 @@
Вы можете добавлять теги к вашим *операциям пути*, добавив параметр `tags` с `list` заполненным `str`-значениями (обычно в нём только одна строка):
-//// tab | Python 3.10+
-
-```Python hl_lines="15 20 25"
-{!> ../../docs_src/path_operation_configuration/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="17 22 27"
-{!> ../../docs_src/path_operation_configuration/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="17 22 27"
-{!> ../../docs_src/path_operation_configuration/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}
Они будут добавлены в схему OpenAPI и будут использованы в автоматической документации интерфейса:
@@ -90,37 +46,13 @@
**FastAPI** поддерживает это так же, как и в случае с обычными строками:
-```Python hl_lines="1 8-10 13 18"
-{!../../docs_src/path_operation_configuration/tutorial002b.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial002b.py hl[1,8:10,13,18] *}
## Краткое и развёрнутое содержание
Вы можете добавить параметры `summary` и `description`:
-//// tab | Python 3.10+
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/path_operation_configuration/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="20-21"
-{!> ../../docs_src/path_operation_configuration/tutorial003_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="20-21"
-{!> ../../docs_src/path_operation_configuration/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
## Описание из строк документации
@@ -128,29 +60,7 @@
Вы можете использовать Markdown в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации).
-//// tab | Python 3.10+
-
-```Python hl_lines="17-25"
-{!> ../../docs_src/path_operation_configuration/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="19-27"
-{!> ../../docs_src/path_operation_configuration/tutorial004_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="19-27"
-{!> ../../docs_src/path_operation_configuration/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}
Он будет использован в интерактивной документации:
@@ -160,29 +70,7 @@
Вы можете указать описание ответа с помощью параметра `response_description`:
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/path_operation_configuration/tutorial005_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="21"
-{!> ../../docs_src/path_operation_configuration/tutorial005_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="21"
-{!> ../../docs_src/path_operation_configuration/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
/// info | Дополнительная информация
@@ -204,9 +92,7 @@ OpenAPI указывает, что каждой *операции пути* не
Если вам необходимо пометить *операцию пути* как устаревшую, при этом не удаляя её, передайте параметр `deprecated`:
-```Python hl_lines="16"
-{!../../docs_src/path_operation_configuration/tutorial006.py!}
-```
+{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *}
Он будет четко помечен как устаревший в интерактивной документации:
diff --git a/docs/ru/docs/tutorial/path-params-numeric-validations.md b/docs/ru/docs/tutorial/path-params-numeric-validations.md
index ed19576a2..dca267f78 100644
--- a/docs/ru/docs/tutorial/path-params-numeric-validations.md
+++ b/docs/ru/docs/tutorial/path-params-numeric-validations.md
@@ -6,57 +6,7 @@
Сначала импортируйте `Path` из `fastapi`, а также импортируйте `Annotated`:
-//// tab | Python 3.10+
-
-```Python hl_lines="1 3"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 3"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3-4"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="3"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
/// info | Информация
@@ -74,57 +24,7 @@
Например, чтобы указать значение метаданных `title` для path-параметра `item_id`, вы можете написать:
-//// tab | Python 3.10+
-
-```Python hl_lines="10"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="8"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/path_params_numeric_validations/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
/// note | Примечание
@@ -174,21 +74,7 @@ Path-параметр всегда является обязательным, п
Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете `Query()` или `Path()` в качестве значения по умолчанию для параметра функции.
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/path_params_numeric_validations/tutorial002_an.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py hl[10] *}
## Задайте нужный вам порядок параметров, полезные приёмы
@@ -213,29 +99,13 @@ Path-параметр всегда является обязательным, п
Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как kwargs, даже если у них нет значений по умолчанию.
-```Python hl_lines="7"
-{!../../docs_src/path_params_numeric_validations/tutorial003.py!}
-```
+{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
### Лучше с `Annotated`
Имейте в виду, что если вы используете `Annotated`, то, поскольку вы не используете значений по умолчанию для параметров функции, то у вас не возникнет подобной проблемы и вам не придётся использовать `*`.
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/path_params_numeric_validations/tutorial003_an.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
## Валидация числовых данных: больше или равно
@@ -243,35 +113,7 @@ Python не будет ничего делать с `*`, но он будет з
В этом примере при указании `ge=1`, параметр `item_id` должен быть больше или равен `1` ("`g`reater than or `e`qual").
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/path_params_numeric_validations/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="8"
-{!> ../../docs_src/path_params_numeric_validations/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
## Валидация числовых данных: больше и меньше или равно
@@ -280,35 +122,7 @@ Python не будет ничего делать с `*`, но он будет з
* `gt`: больше (`g`reater `t`han)
* `le`: меньше или равно (`l`ess than or `e`qual)
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/path_params_numeric_validations/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/path_params_numeric_validations/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
## Валидация числовых данных: числа с плавающей точкой, больше и меньше
@@ -320,35 +134,7 @@ Python не будет ничего делать с `*`, но он будет з
То же самое справедливо и для lt.
-//// tab | Python 3.9+
-
-```Python hl_lines="13"
-{!> ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="12"
-{!> ../../docs_src/path_params_numeric_validations/tutorial006_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="11"
-{!> ../../docs_src/path_params_numeric_validations/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
## Резюме
diff --git a/docs/ru/docs/tutorial/path-params.md b/docs/ru/docs/tutorial/path-params.md
index ba23ba5ea..5c2d82a65 100644
--- a/docs/ru/docs/tutorial/path-params.md
+++ b/docs/ru/docs/tutorial/path-params.md
@@ -2,9 +2,7 @@
Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python:
-```Python hl_lines="6-7"
-{!../../docs_src/path_params/tutorial001.py!}
-```
+{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
Значение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`.
@@ -18,9 +16,7 @@
Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python.
-```Python hl_lines="7"
-{!../../docs_src/path_params/tutorial002.py!}
-```
+{* ../../docs_src/path_params/tutorial002.py hl[7] *}
Здесь, `item_id` объявлен типом `int`.
@@ -122,17 +118,13 @@
Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`:
-```Python hl_lines="6 11"
-{!../../docs_src/path_params/tutorial003.py!}
-```
+{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`.
Аналогично, вы не можете переопределить операцию с путем:
-```Python hl_lines="6 11"
-{!../../docs_src/path_params/tutorial003b.py!}
-```
+{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *}
Первый будет выполняться всегда, так как путь совпадает первым.
@@ -148,9 +140,7 @@
Затем создайте атрибуты класса с фиксированными допустимыми значениями:
-```Python hl_lines="1 6-9"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
/// info | Дополнительная информация
@@ -168,9 +158,7 @@
Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее:
-```Python hl_lines="16"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[16] *}
### Проверьте документацию
@@ -186,17 +174,13 @@
Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`:
-```Python hl_lines="17"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[17] *}
#### Получение *значения перечисления*
Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`:
-```Python hl_lines="20"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[20] *}
/// tip | Подсказка
@@ -210,9 +194,7 @@
Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту:
-```Python hl_lines="18 21 23"
-{!../../docs_src/path_params/tutorial005.py!}
-```
+{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
Вы отправите клиенту такой JSON-ответ:
```JSON
@@ -250,9 +232,7 @@ OpenAPI не поддерживает способов объявления *п
Можете использовать так:
-```Python hl_lines="6"
-{!../../docs_src/path_params/tutorial004.py!}
-```
+{* ../../docs_src/path_params/tutorial004.py hl[6] *}
/// tip | Подсказка
diff --git a/docs/ru/docs/tutorial/query-param-models.md b/docs/ru/docs/tutorial/query-param-models.md
new file mode 100644
index 000000000..4d76d09e8
--- /dev/null
+++ b/docs/ru/docs/tutorial/query-param-models.md
@@ -0,0 +1,68 @@
+# Модели Query-Параметров
+
+Если у вас есть группа связанных **query-параметров**, то вы можете объединить их в одну **Pydantic-модель**.
+
+Это позволит вам **переиспользовать модель** в **разных местах**, устанавливать валидаторы и метаданные, в том числе для сразу всех параметров, в одном месте. 😎
+
+/// note | Заметка
+
+Этот функционал доступен с версии `0.115.0`. 🤓
+
+///
+
+## Pydantic-Модель для Query-Параметров
+
+Объявите нужные **query-параметры** в **Pydantic-модели**, а после аннотируйте параметр как `Query`:
+
+{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
+
+**FastAPI извлечёт** данные соответствующие **каждому полю модели** из **query-параметров** запроса и выдаст вам объявленную Pydantic-модель заполненную ими.
+
+## Проверьте Сгенерированную Документацию
+
+Вы можете посмотреть query-параметры в графическом интерфейсе сгенерированной документации по пути `/docs`:
+
+
+
+
+
+## Запретить Дополнительные Query-Параметры
+
+В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** query-параметры, которые вы хотите получить.
+
+Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) все дополнительные (`extra`) поля.
+
+{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
+
+Если клиент попробует отправить **дополнительные** данные в **query-параметрах**, то в ответ он получит **ошибку**.
+
+Например, если клиент попытается отправить query-параметр `tool` с значением `plumbus`, в виде:
+
+```http
+https://example.com/items/?limit=10&tool=plumbus
+```
+
+То в ответ он получит **ошибку**, сообщающую ему, что query-параметр `tool` не разрешен:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["query", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus"
+ }
+ ]
+}
+```
+
+## Заключение
+
+Вы можете использовать **Pydantic-модели** для объявления **query-параметров** в **FastAPI**. 😎
+
+/// tip | Совет
+
+Спойлер: вы также можете использовать Pydantic-модели для группировки кук (cookies) и заголовков (headers), но об этом вы прочитаете позже. 🤫
+
+///
diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md
index f76570ce8..13b7015db 100644
--- a/docs/ru/docs/tutorial/query-params-str-validations.md
+++ b/docs/ru/docs/tutorial/query-params-str-validations.md
@@ -4,21 +4,7 @@
Давайте рассмотрим следующий пример:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
Query-параметр `q` имеет тип `Union[str, None]` (или `str | None` в Python 3.10). Это означает, что входной параметр будет типа `str`, но может быть и `None`. Ещё параметр имеет значение по умолчанию `None`, из-за чего FastAPI определит параметр как необязательный.
@@ -113,21 +99,7 @@ q: Annotated[Union[str, None]] = None
Теперь, когда у нас есть `Annotated`, где мы можем добавить больше метаданных, добавим `Query` со значением параметра `max_length` равным 50:
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial002_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial002_an.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
Обратите внимание, что значение по умолчанию всё ещё `None`, так что параметр остаётся необязательным.
@@ -151,21 +123,7 @@ q: Annotated[Union[str, None]] = None
Вот как вы могли бы использовать `Query()` в качестве значения по умолчанию параметра вашей функции, установив для параметра `max_length` значение 50:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
В таком случае (без использования `Annotated`), мы заменили значение по умолчанию с `None` на `Query()` в функции. Теперь нам нужно установить значение по умолчанию для query-параметра `Query(default=None)`, что необходимо для тех же целей, как когда ранее просто указывалось значение по умолчанию (по крайней мере, для FastAPI).
@@ -265,113 +223,13 @@ q: str = Query(default="rick")
Вы также можете добавить параметр `min_length`:
-//// tab | Python 3.10+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11"
-{!> ../../docs_src/query_params_str_validations/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
## Регулярные выражения
Вы можете определить регулярное выражение, которому должен соответствовать параметр:
-//// tab | Python 3.10+
-
-```Python hl_lines="11"
-{!> ../../docs_src/query_params_str_validations/tutorial004_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="11"
-{!> ../../docs_src/query_params_str_validations/tutorial004_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="12"
-{!> ../../docs_src/query_params_str_validations/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="11"
-{!> ../../docs_src/query_params_str_validations/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
Данное регулярное выражение проверяет, что полученное значение параметра:
@@ -389,35 +247,7 @@ q: str = Query(default="rick")
Например, вы хотите для параметра запроса `q` указать, что он должен состоять минимум из 3 символов (`min_length=3`) и иметь значение по умолчанию `"fixedquery"`:
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial005_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="8"
-{!> ../../docs_src/query_params_str_validations/tutorial005_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
/// note | Технические детали
@@ -459,711 +289,157 @@ q: Union[str, None] = Query(default=None, min_length=3)
В таком случае, чтобы сделать query-параметр `Query` обязательным, вы можете просто не указывать значение по умолчанию:
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial006_an_py39.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
-//// tab | Python 3.8+
+### Обязательный параметр с `None`
-```Python hl_lines="8"
-{!> ../../docs_src/query_params_str_validations/tutorial006_an.py!}
-```
+Вы можете определить, что параметр может принимать `None`, но всё ещё является обязательным. Это может потребоваться для того, чтобы пользователи явно указали параметр, даже если его значение будет `None`.
-////
+Чтобы этого добиться, вам нужно определить `None` как валидный тип для параметра запроса, но также указать `default=...`:
-//// tab | Python 3.8+ без Annotated
+{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
/// tip | Подсказка
-Рекомендуется использовать версию с `Annotated` если возможно.
+Pydantic, мощь которого используется в FastAPI для валидации и сериализации, имеет специальное поведение для `Optional` или `Union[Something, None]` без значения по умолчанию. Вы можете узнать об этом больше в документации Pydantic, раздел Обязательные Опциональные поля.
///
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial006.py!}
-```
-
-/// tip | Подсказка
-
-Обратите внимание, что даже когда `Query()` используется как значение по умолчанию для параметра функции, мы не передаём `default=None` в `Query()`.
-
-Лучше будет использовать версию с `Annotated`. 😉
-
-///
+## Множество значений для query-параметра
-////
+Для query-параметра `Query` можно указать, что он принимает список значений (множество значений).
-### Обязательный параметр с Ellipsis (`...`)
+Например, query-параметр `q` может быть указан в URL несколько раз. И если вы ожидаете такой формат запроса, то можете указать это следующим образом:
-Альтернативный способ указать обязательность параметра запроса - это указать параметр `default` через многоточие `...`:
+{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
-//// tab | Python 3.9+
+Затем, получив такой URL:
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!}
+```
+http://localhost:8000/items/?q=foo&q=bar
```
-////
+вы бы получили несколько значений (`foo` и `bar`), которые относятся к параметру `q`, в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
-//// tab | Python 3.8+
+Таким образом, ответ на этот URL будет:
-```Python hl_lines="8"
-{!> ../../docs_src/query_params_str_validations/tutorial006b_an.py!}
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
```
-////
-
-//// tab | Python 3.8+ без Annotated
-
/// tip | Подсказка
-Рекомендуется использовать версию с `Annotated` если возможно.
+Чтобы объявить query-параметр типом `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
///
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial006b.py!}
-```
-
-////
-
-/// info | Дополнительная информация
-
-Если вы ранее не сталкивались с `...`: это специальное значение, часть языка Python и называется "Ellipsis".
-
-Используется в Pydantic и FastAPI для определения, что значение требуется обязательно.
-
-///
+Интерактивная документация API будет обновлена соответствующим образом, где будет разрешено множество значений:
-Таким образом, **FastAPI** определяет, что параметр является обязательным.
+
-### Обязательный параметр с `None`
+### Query-параметр со множеством значений по умолчанию
-Вы можете определить, что параметр может принимать `None`, но всё ещё является обязательным. Это может потребоваться для того, чтобы пользователи явно указали параметр, даже если его значение будет `None`.
+Вы также можете указать тип `list` со списком значений по умолчанию на случай, если вам их не предоставят:
-Чтобы этого добиться, вам нужно определить `None` как валидный тип для параметра запроса, но также указать `default=...`:
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
-//// tab | Python 3.10+
+Если вы перейдёте по ссылке:
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py!}
+```
+http://localhost:8000/items/
```
-////
-
-//// tab | Python 3.9+
+значение по умолчанию для `q` будет: `["foo", "bar"]` и ответом для вас будет:
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!}
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
```
-////
-
-//// tab | Python 3.8+
+#### Использование `list`
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial006c_an.py!}
-```
+Вы также можете использовать `list` напрямую вместо `List[str]` (или `list[str]` в Python 3.9+):
-////
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
-//// tab | Python 3.10+ без Annotated
+/// note | Технические детали
-/// tip | Подсказка
+Запомните, что в таком случае, FastAPI не будет проверять содержимое списка.
-Рекомендуется использовать версию с `Annotated` если возможно.
+Например, для List[int] список будет провалидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет.
///
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial006c_py310.py!}
-```
+## Больше метаданных
-////
+Вы можете добавить больше информации об query-параметре.
-//// tab | Python 3.8+ без Annotated
+Указанная информация будет включена в генерируемую OpenAPI документацию и использована в пользовательском интерфейсе и внешних инструментах.
-/// tip | Подсказка
+/// note | Технические детали
+
+Имейте в виду, что разные инструменты могут иметь разные уровни поддержки OpenAPI.
-Рекомендуется использовать версию с `Annotated` если возможно.
+Некоторые из них могут не отображать (на данный момент) всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке.
///
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial006c.py!}
-```
-
-////
+Вы можете указать название query-параметра, используя параметр `title`:
-/// tip | Подсказка
+{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
-Pydantic, мощь которого используется в FastAPI для валидации и сериализации, имеет специальное поведение для `Optional` или `Union[Something, None]` без значения по умолчанию. Вы можете узнать об этом больше в документации Pydantic, раздел Обязательные Опциональные поля.
+Добавить описание, используя параметр `description`:
-///
+{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
-### Использование Pydantic's `Required` вместо Ellipsis (`...`)
+## Псевдонимы параметров
-Если вас смущает `...`, вы можете использовать `Required` из Pydantic:
+Представьте, что вы хотите использовать query-параметр с названием `item-query`.
-//// tab | Python 3.9+
+Например:
-```Python hl_lines="4 10"
-{!> ../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!}
```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="2 9"
-{!> ../../docs_src/query_params_str_validations/tutorial006d_an.py!}
+http://127.0.0.1:8000/items/?item-query=foobaritems
```
-////
+Но `item-query` является невалидным именем переменной в Python.
-//// tab | Python 3.8+ без Annotated
+Наиболее похожее валидное имя `item_query`.
-/// tip | Подсказка
+Но вам всё равно необходим `item-query`...
-Рекомендуется использовать версию с `Annotated` если возможно.
+Тогда вы можете объявить `псевдоним`, и этот псевдоним будет использоваться для поиска значения параметра запроса:
-///
+{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
-```Python hl_lines="2 8"
-{!> ../../docs_src/query_params_str_validations/tutorial006d.py!}
-```
+## Устаревшие параметры
-////
+Предположим, вы больше не хотите использовать какой-либо параметр.
-/// tip | Подсказка
+Вы решили оставить его, потому что клиенты всё ещё им пользуются. Но вы хотите отобразить это в документации как устаревший функционал.
-Запомните, когда вам необходимо объявить query-параметр обязательным, вы можете просто не указывать параметр `default`. Таким образом, вам редко придётся использовать `...` или `Required`.
+Тогда для `Query` укажите параметр `deprecated=True`:
-///
+{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
-## Множество значений для query-параметра
+В документации это будет отображено следующим образом:
-Для query-параметра `Query` можно указать, что он принимает список значений (множество значений).
+
-Например, query-параметр `q` может быть указан в URL несколько раз. И если вы ожидаете такой формат запроса, то можете указать это следующим образом:
-
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial011_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial011_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial011_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial011_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial011_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial011.py!}
-```
-
-////
-
-Затем, получив такой URL:
-
-```
-http://localhost:8000/items/?q=foo&q=bar
-```
-
-вы бы получили несколько значений (`foo` и `bar`), которые относятся к параметру `q`, в виде Python `list` внутри вашей *функции обработки пути*, в *параметре функции* `q`.
-
-Таким образом, ответ на этот URL будет:
-
-```JSON
-{
- "q": [
- "foo",
- "bar"
- ]
-}
-```
-
-/// tip | Подсказка
-
-Чтобы объявить query-параметр типом `list`, как в примере выше, вам нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.
-
-///
-
-Интерактивная документация API будет обновлена соответствующим образом, где будет разрешено множество значений:
-
-
-
-### Query-параметр со множеством значений по умолчанию
-
-Вы также можете указать тип `list` со списком значений по умолчанию на случай, если вам их не предоставят:
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial012_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial012_an.py!}
-```
-
-////
-
-//// tab | Python 3.9+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial012_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial012.py!}
-```
-
-////
-
-Если вы перейдёте по ссылке:
-
-```
-http://localhost:8000/items/
-```
-
-значение по умолчанию для `q` будет: `["foo", "bar"]` и ответом для вас будет:
-
-```JSON
-{
- "q": [
- "foo",
- "bar"
- ]
-}
-```
-
-#### Использование `list`
-
-Вы также можете использовать `list` напрямую вместо `List[str]` (или `list[str]` в Python 3.9+):
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial013_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="8"
-{!> ../../docs_src/query_params_str_validations/tutorial013_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial013.py!}
-```
-
-////
-
-/// note | Технические детали
-
-Запомните, что в таком случае, FastAPI не будет проверять содержимое списка.
-
-Например, для List[int] список будет провалидирован (и задокументирован) на содержание только целочисленных элементов. Но для простого `list` такой проверки не будет.
-
-///
-
-## Больше метаданных
-
-Вы можете добавить больше информации об query-параметре.
-
-Указанная информация будет включена в генерируемую OpenAPI документацию и использована в пользовательском интерфейсе и внешних инструментах.
-
-/// note | Технические детали
-
-Имейте в виду, что разные инструменты могут иметь разные уровни поддержки OpenAPI.
-
-Некоторые из них могут не отображать (на данный момент) всю заявленную дополнительную информацию, хотя в большинстве случаев отсутствующая функция уже запланирована к разработке.
-
-///
-
-Вы можете указать название query-параметра, используя параметр `title`:
-
-//// tab | Python 3.10+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial007_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial007_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11"
-{!> ../../docs_src/query_params_str_validations/tutorial007_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="8"
-{!> ../../docs_src/query_params_str_validations/tutorial007_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial007.py!}
-```
-
-////
-
-Добавить описание, используя параметр `description`:
-
-//// tab | Python 3.10+
-
-```Python hl_lines="14"
-{!> ../../docs_src/query_params_str_validations/tutorial008_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="14"
-{!> ../../docs_src/query_params_str_validations/tutorial008_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="15"
-{!> ../../docs_src/query_params_str_validations/tutorial008_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="11"
-{!> ../../docs_src/query_params_str_validations/tutorial008_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="13"
-{!> ../../docs_src/query_params_str_validations/tutorial008.py!}
-```
-
-////
-
-## Псевдонимы параметров
-
-Представьте, что вы хотите использовать query-параметр с названием `item-query`.
-
-Например:
-
-```
-http://127.0.0.1:8000/items/?item-query=foobaritems
-```
-
-Но `item-query` является невалидным именем переменной в Python.
-
-Наиболее похожее валидное имя `item_query`.
-
-Но вам всё равно необходим `item-query`...
-
-Тогда вы можете объявить `псевдоним`, и этот псевдоним будет использоваться для поиска значения параметра запроса:
-
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial009_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial009_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial009_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params_str_validations/tutorial009_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params_str_validations/tutorial009.py!}
-```
-
-////
-
-## Устаревшие параметры
-
-Предположим, вы больше не хотите использовать какой-либо параметр.
-
-Вы решили оставить его, потому что клиенты всё ещё им пользуются. Но вы хотите отобразить это в документации как устаревший функционал.
-
-Тогда для `Query` укажите параметр `deprecated=True`:
-
-//// tab | Python 3.10+
-
-```Python hl_lines="19"
-{!> ../../docs_src/query_params_str_validations/tutorial010_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="19"
-{!> ../../docs_src/query_params_str_validations/tutorial010_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="20"
-{!> ../../docs_src/query_params_str_validations/tutorial010_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="16"
-{!> ../../docs_src/query_params_str_validations/tutorial010_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="18"
-{!> ../../docs_src/query_params_str_validations/tutorial010.py!}
-```
-
-////
-
-В документации это будет отображено следующим образом:
-
-
-
-## Исключить из OpenAPI
+## Исключить из OpenAPI
Чтобы исключить query-параметр из генерируемой OpenAPI схемы (а также из системы автоматической генерации документации), укажите в `Query` параметр `include_in_schema=False`:
-//// tab | Python 3.10+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial014_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial014_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11"
-{!> ../../docs_src/query_params_str_validations/tutorial014_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="8"
-{!> ../../docs_src/query_params_str_validations/tutorial014_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать версию с `Annotated` если возможно.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params_str_validations/tutorial014.py!}
-```
-
-////
+{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
## Резюме
diff --git a/docs/ru/docs/tutorial/query-params.md b/docs/ru/docs/tutorial/query-params.md
index 2c697224c..547d9831d 100644
--- a/docs/ru/docs/tutorial/query-params.md
+++ b/docs/ru/docs/tutorial/query-params.md
@@ -2,9 +2,7 @@
Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры.
-```Python hl_lines="9"
-{!../../docs_src/query_params/tutorial001.py!}
-```
+{* ../../docs_src/query_params/tutorial001.py hl[9] *}
Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.
@@ -63,21 +61,7 @@ http://127.0.0.1:8000/items/?skip=20
Аналогично, вы можете объявлять необязательные query-параметры, установив их значение по умолчанию, равное `None`:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
В этом случае, параметр `q` будет не обязательным и будет иметь значение `None` по умолчанию.
@@ -91,21 +75,7 @@ http://127.0.0.1:8000/items/?skip=20
Вы также можете объявлять параметры с типом `bool`, которые будут преобразованы соответственно:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/query_params/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/query_params/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
В этом случае, если вы сделаете запрос:
@@ -148,21 +118,7 @@ http://127.0.0.1:8000/items/foo?short=yes
Они будут обнаружены по именам:
-//// tab | Python 3.10+
-
-```Python hl_lines="6 8"
-{!> ../../docs_src/query_params/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="8 10"
-{!> ../../docs_src/query_params/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
## Обязательные query-параметры
@@ -172,9 +128,7 @@ http://127.0.0.1:8000/items/foo?short=yes
Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию:
-```Python hl_lines="6-7"
-{!../../docs_src/query_params/tutorial005.py!}
-```
+{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`.
@@ -218,21 +172,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
Конечно, вы можете определить некоторые параметры как обязательные, некоторые - со значением по умполчанию, а некоторые - полностью необязательные:
-//// tab | Python 3.10+
-
-```Python hl_lines="8"
-{!> ../../docs_src/query_params/tutorial006_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/query_params/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
В этом примере, у нас есть 3 параметра запроса:
diff --git a/docs/ru/docs/tutorial/request-files.md b/docs/ru/docs/tutorial/request-files.md
index 836d6efed..2cfa4e1dc 100644
--- a/docs/ru/docs/tutorial/request-files.md
+++ b/docs/ru/docs/tutorial/request-files.md
@@ -16,69 +16,13 @@
Импортируйте `File` и `UploadFile` из модуля `fastapi`:
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/request_files/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="1"
-{!> ../../docs_src/request_files/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/request_files/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
## Определите параметры `File`
Создайте параметры `File` так же, как вы это делаете для `Body` или `Form`:
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/request_files/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="8"
-{!> ../../docs_src/request_files/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/request_files/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
/// info | Дополнительная информация
@@ -106,35 +50,7 @@
Определите параметр файла с типом `UploadFile`:
-//// tab | Python 3.9+
-
-```Python hl_lines="14"
-{!> ../../docs_src/request_files/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="13"
-{!> ../../docs_src/request_files/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="12"
-{!> ../../docs_src/request_files/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
Использование `UploadFile` имеет ряд преимуществ перед `bytes`:
@@ -217,91 +133,13 @@ contents = myfile.file.read()
Вы можете сделать загрузку файла необязательной, используя стандартные аннотации типов и установив значение по умолчанию `None`:
-//// tab | Python 3.10+
-
-```Python hl_lines="9 17"
-{!> ../../docs_src/request_files/tutorial001_02_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9 17"
-{!> ../../docs_src/request_files/tutorial001_02_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="10 18"
-{!> ../../docs_src/request_files/tutorial001_02_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="7 15"
-{!> ../../docs_src/request_files/tutorial001_02_py310.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="9 17"
-{!> ../../docs_src/request_files/tutorial001_02.py!}
-```
-
-////
+{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
## `UploadFile` с дополнительными метаданными
Вы также можете использовать `File()` вместе с `UploadFile`, например, для установки дополнительных метаданных:
-//// tab | Python 3.9+
-
-```Python hl_lines="9 15"
-{!> ../../docs_src/request_files/tutorial001_03_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="8 14"
-{!> ../../docs_src/request_files/tutorial001_03_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="7 13"
-{!> ../../docs_src/request_files/tutorial001_03.py!}
-```
-
-////
+{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
## Загрузка нескольких файлов
@@ -311,49 +149,7 @@ contents = myfile.file.read()
Для этого необходимо объявить список `bytes` или `UploadFile`:
-//// tab | Python 3.9+
-
-```Python hl_lines="10 15"
-{!> ../../docs_src/request_files/tutorial002_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="11 16"
-{!> ../../docs_src/request_files/tutorial002_an.py!}
-```
-
-////
-
-//// tab | Python 3.9+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="8 13"
-{!> ../../docs_src/request_files/tutorial002_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="10 15"
-{!> ../../docs_src/request_files/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
Вы получите, как и было объявлено, список `list` из `bytes` или `UploadFile`.
@@ -369,49 +165,7 @@ contents = myfile.file.read()
Так же, как и раньше, вы можете использовать `File()` для задания дополнительных параметров, даже для `UploadFile`:
-//// tab | Python 3.9+
-
-```Python hl_lines="11 18-20"
-{!> ../../docs_src/request_files/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="12 19-21"
-{!> ../../docs_src/request_files/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.9+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="9 16"
-{!> ../../docs_src/request_files/tutorial003_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="11 18"
-{!> ../../docs_src/request_files/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
## Резюме
diff --git a/docs/ru/docs/tutorial/request-form-models.md b/docs/ru/docs/tutorial/request-form-models.md
new file mode 100644
index 000000000..1034ed27f
--- /dev/null
+++ b/docs/ru/docs/tutorial/request-form-models.md
@@ -0,0 +1,78 @@
+# Модели форм
+
+Вы можете использовать **Pydantic-модели** для объявления **полей форм** в FastAPI.
+
+/// info | Дополнительная информация
+
+Чтобы использовать формы, сначала установите `python-multipart`.
+
+Убедитесь, что вы создали и активировали [виртуальное окружение](../virtual-environments.md){.internal-link target=_blank}, а затем установите пакет, например:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+/// note | Заметка
+
+Этот функционал доступен с версии `0.113.0`. 🤓
+
+///
+
+## Pydantic-модель для формы
+
+Вам просто нужно объявить **Pydantic-модель** с полями, которые вы хотите получить как **поля формы**, а затем объявить параметр как `Form`:
+
+{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+
+**FastAPI** **извлечёт** данные для **каждого поля** из **данных формы** в запросе и выдаст вам объявленную Pydantic-модель.
+
+## Проверка сгенерированной документации
+
+Вы можете посмотреть поля формы в графическом интерфейсе Документации по пути `/docs`:
+
+
+
+
+
+## Запрет дополнительных полей формы
+
+В некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** поля формы только теми, которые объявлены в Pydantic-модели. И **запретить** любые **дополнительные** поля.
+
+/// note | Заметка
+
+Этот функционал доступен с версии `0.114.0`. 🤓
+
+///
+
+Вы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) все дополнительные (`extra`) поля:
+
+{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+
+Если клиент попробует отправить дополнительные данные, то в ответ он получит **ошибку**.
+
+Например, если клиент попытается отправить поля формы:
+
+* `username`: `Rick`
+* `password`: `Portal Gun`
+* `extra`: `Mr. Poopybutthole`
+
+То в ответ он получит **ошибку**, сообщающую ему, что поле `extra` не разрешено:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["body", "extra"],
+ "msg": "Extra inputs are not permitted",
+ "input": "Mr. Poopybutthole"
+ }
+ ]
+}
+```
+
+## Заключение
+
+Вы можете использовать Pydantic-модели для объявления полей форм в FastAPI. 😎
diff --git a/docs/ru/docs/tutorial/request-forms-and-files.md b/docs/ru/docs/tutorial/request-forms-and-files.md
index fd98ec953..116c0cdb1 100644
--- a/docs/ru/docs/tutorial/request-forms-and-files.md
+++ b/docs/ru/docs/tutorial/request-forms-and-files.md
@@ -12,69 +12,13 @@
## Импортируйте `File` и `Form`
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/request_forms_and_files/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="1"
-{!> ../../docs_src/request_forms_and_files/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/request_forms_and_files/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
## Определите параметры `File` и `Form`
Создайте параметры файла и формы таким же образом, как для `Body` или `Query`:
-//// tab | Python 3.9+
-
-```Python hl_lines="10-12"
-{!> ../../docs_src/request_forms_and_files/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.6+
-
-```Python hl_lines="9-11"
-{!> ../../docs_src/request_forms_and_files/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.6+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="8"
-{!> ../../docs_src/request_forms_and_files/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
Файлы и поля формы будут загружены в виде данных формы, и вы получите файлы и поля формы.
diff --git a/docs/ru/docs/tutorial/request-forms.md b/docs/ru/docs/tutorial/request-forms.md
index cd17613de..b33ea044b 100644
--- a/docs/ru/docs/tutorial/request-forms.md
+++ b/docs/ru/docs/tutorial/request-forms.md
@@ -14,69 +14,13 @@
Импортируйте `Form` из `fastapi`:
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/request_forms/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="1"
-{!> ../../docs_src/request_forms/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать 'Annotated' версию, если это возможно.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/request_forms/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
## Определение параметров `Form`
Создайте параметры формы так же, как это делается для `Body` или `Query`:
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/request_forms/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="8"
-{!> ../../docs_src/request_forms/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Рекомендуется использовать 'Annotated' версию, если это возможно.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/request_forms/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
Например, в одном из способов использования спецификации OAuth2 (называемом "потоком пароля") требуется отправить `username` и `password` в виде полей формы.
diff --git a/docs/ru/docs/tutorial/response-model.md b/docs/ru/docs/tutorial/response-model.md
index c55be38ef..b3c29281c 100644
--- a/docs/ru/docs/tutorial/response-model.md
+++ b/docs/ru/docs/tutorial/response-model.md
@@ -4,29 +4,7 @@
FastAPI позволяет использовать **аннотации типов** таким же способом, как и для ввода данных в **параметры** функции, вы можете использовать модели Pydantic, списки, словари, скалярные типы (такие, как int, bool и т.д.).
-//// tab | Python 3.10+
-
-```Python hl_lines="16 21"
-{!> ../../docs_src/response_model/tutorial001_01_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="18 23"
-{!> ../../docs_src/response_model/tutorial001_01_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="18 23"
-{!> ../../docs_src/response_model/tutorial001_01.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
FastAPI будет использовать этот возвращаемый тип для:
@@ -59,29 +37,7 @@ FastAPI будет использовать этот возвращаемый т
* `@app.delete()`
* и др.
-//// tab | Python 3.10+
-
-```Python hl_lines="17 22 24-27"
-{!> ../../docs_src/response_model/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="17 22 24-27"
-{!> ../../docs_src/response_model/tutorial001_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="17 22 24-27"
-{!> ../../docs_src/response_model/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}
/// note | Технические детали
@@ -113,21 +69,7 @@ FastAPI будет использовать значение `response_model` д
Здесь мы объявили модель `UserIn`, которая хранит пользовательский пароль в открытом виде:
-//// tab | Python 3.10+
-
-```Python hl_lines="7 9"
-{!> ../../docs_src/response_model/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9 11"
-{!> ../../docs_src/response_model/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}
/// info | Информация
@@ -139,21 +81,7 @@ FastAPI будет использовать значение `response_model` д
Далее мы используем нашу модель в аннотациях типа как для аргумента функции, так и для выходного значения:
-//// tab | Python 3.10+
-
-```Python hl_lines="16"
-{!> ../../docs_src/response_model/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="18"
-{!> ../../docs_src/response_model/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}
Теперь всякий раз, когда клиент создает пользователя с паролем, API будет возвращать его пароль в ответе.
@@ -171,57 +99,15 @@ FastAPI будет использовать значение `response_model` д
Вместо этого мы можем создать входную модель, хранящую пароль в открытом виде и выходную модель без пароля:
-//// tab | Python 3.10+
-
-```Python hl_lines="9 11 16"
-{!> ../../docs_src/response_model/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9 11 16"
-{!> ../../docs_src/response_model/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}
В таком случае, даже несмотря на то, что наша *функция операции пути* возвращает тот же самый объект пользователя с паролем, полученным на вход:
-//// tab | Python 3.10+
-
-```Python hl_lines="24"
-{!> ../../docs_src/response_model/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="24"
-{!> ../../docs_src/response_model/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}
...мы указали в `response_model` модель `UserOut`, в которой отсутствует поле, содержащее пароль - и он будет исключен из ответа:
-//// tab | Python 3.10+
-
-```Python hl_lines="22"
-{!> ../../docs_src/response_model/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="22"
-{!> ../../docs_src/response_model/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}
Таким образом **FastAPI** позаботится о фильтрации ответа и исключит из него всё, что не указано в выходной модели (при помощи Pydantic).
@@ -245,21 +131,7 @@ FastAPI будет использовать значение `response_model` д
И в таких случаях мы можем использовать классы и наследование, чтобы пользоваться преимуществами **аннотаций типов** и получать более полную статическую проверку типов. Но при этом все так же получать **фильтрацию ответа** от FastAPI.
-//// tab | Python 3.10+
-
-```Python hl_lines="7-10 13-14 18"
-{!> ../../docs_src/response_model/tutorial003_01_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9-13 15-16 20"
-{!> ../../docs_src/response_model/tutorial003_01.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}
Таким образом, мы получаем поддержку редактора кода и mypy в части типов, сохраняя при этом фильтрацию данных от FastAPI.
@@ -301,9 +173,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
Самый частый сценарий использования - это [возвращать Response напрямую, как описано в расширенной документации](../advanced/response-directly.md){.internal-link target=_blank}.
-```Python hl_lines="8 10-11"
-{!> ../../docs_src/response_model/tutorial003_02.py!}
-```
+{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *}
Это поддерживается FastAPI по-умолчанию, т.к. аннотация проставлена в классе (или подклассе) `Response`.
@@ -313,9 +183,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
Вы также можете указать подкласс `Response` в аннотации типа:
-```Python hl_lines="8-9"
-{!> ../../docs_src/response_model/tutorial003_03.py!}
-```
+{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *}
Это сработает, потому что `RedirectResponse` является подклассом `Response` и FastAPI автоматически обработает этот простейший случай.
@@ -325,21 +193,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
То же самое произошло бы, если бы у вас было что-то вроде Union различных типов и один или несколько из них не являлись бы допустимыми типами для Pydantic. Например, такой вариант приведет к ошибке 💥:
-//// tab | Python 3.10+
-
-```Python hl_lines="8"
-{!> ../../docs_src/response_model/tutorial003_04_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/response_model/tutorial003_04.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}
...такой код вызовет ошибку, потому что в аннотации указан неподдерживаемый Pydantic тип. А также этот тип не является классом или подклассом `Response`.
@@ -351,21 +205,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
В таком случае, вы можете отключить генерацию модели ответа, указав `response_model=None`:
-//// tab | Python 3.10+
-
-```Python hl_lines="7"
-{!> ../../docs_src/response_model/tutorial003_05_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="9"
-{!> ../../docs_src/response_model/tutorial003_05.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}
Тогда FastAPI не станет генерировать модель ответа и вы сможете сохранить такую аннотацию типа, которая вам требуется, никак не влияя на работу FastAPI. 🤓
@@ -373,29 +213,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
Модель ответа может иметь значения по умолчанию, например:
-//// tab | Python 3.10+
-
-```Python hl_lines="9 11-12"
-{!> ../../docs_src/response_model/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="11 13-14"
-{!> ../../docs_src/response_model/tutorial004_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11 13-14"
-{!> ../../docs_src/response_model/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}
* `description: Union[str, None] = None` (или `str | None = None` в Python 3.10), где `None` является значением по умолчанию.
* `tax: float = 10.5`, где `10.5` является значением по умолчанию.
@@ -409,29 +227,7 @@ FastAPI совместно с Pydantic выполнит некоторую ма
Установите для *декоратора операции пути* параметр `response_model_exclude_unset=True`:
-//// tab | Python 3.10+
-
-```Python hl_lines="22"
-{!> ../../docs_src/response_model/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="24"
-{!> ../../docs_src/response_model/tutorial004_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="24"
-{!> ../../docs_src/response_model/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}
и тогда значения по умолчанию не будут включены в ответ. В нем будут только те поля, значения которых фактически были установлены.
@@ -520,21 +316,7 @@ FastAPI достаточно умен (на самом деле, это засл
///
-//// tab | Python 3.10+
-
-```Python hl_lines="29 35"
-{!> ../../docs_src/response_model/tutorial005_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="31 37"
-{!> ../../docs_src/response_model/tutorial005.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}
/// tip | Подсказка
@@ -548,21 +330,7 @@ FastAPI достаточно умен (на самом деле, это засл
Если вы забыли про `set` и использовали структуру `list` или `tuple`, FastAPI автоматически преобразует этот объект в `set`, чтобы обеспечить корректную работу:
-//// tab | Python 3.10+
-
-```Python hl_lines="29 35"
-{!> ../../docs_src/response_model/tutorial006_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="31 37"
-{!> ../../docs_src/response_model/tutorial006.py!}
-```
-
-////
+{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}
## Резюме
diff --git a/docs/ru/docs/tutorial/response-status-code.md b/docs/ru/docs/tutorial/response-status-code.md
index f08b15379..b46f656f3 100644
--- a/docs/ru/docs/tutorial/response-status-code.md
+++ b/docs/ru/docs/tutorial/response-status-code.md
@@ -8,9 +8,7 @@
* `@app.delete()`
* и других.
-```Python hl_lines="6"
-{!../../docs_src/response_status_code/tutorial001.py!}
-```
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
/// note | Примечание
@@ -76,9 +74,7 @@ FastAPI знает об этом и создаст документацию Open
Рассмотрим предыдущий пример еще раз:
-```Python hl_lines="6"
-{!../../docs_src/response_status_code/tutorial001.py!}
-```
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
`201` – это код статуса "Создано".
@@ -86,9 +82,7 @@ FastAPI знает об этом и создаст документацию Open
Для удобства вы можете использовать переменные из `fastapi.status`.
-```Python hl_lines="1 6"
-{!../../docs_src/response_status_code/tutorial002.py!}
-```
+{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
Они содержат те же числовые значения, но позволяют использовать подсказки редактора для выбора кода статуса:
diff --git a/docs/ru/docs/tutorial/schema-extra-example.md b/docs/ru/docs/tutorial/schema-extra-example.md
index daa264afc..f17b24349 100644
--- a/docs/ru/docs/tutorial/schema-extra-example.md
+++ b/docs/ru/docs/tutorial/schema-extra-example.md
@@ -8,21 +8,7 @@
Вы можете объявить ключ `example` для модели Pydantic, используя класс `Config` и переменную `schema_extra`, как описано в Pydantic документации: Настройка схемы:
-//// tab | Python 3.10+
-
-```Python hl_lines="13-21"
-{!> ../../docs_src/schema_extra_example/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="15-23"
-{!> ../../docs_src/schema_extra_example/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:21] *}
Эта дополнительная информация будет включена в **JSON Schema** выходных данных для этой модели, и она будет использоваться в документации к API.
@@ -40,21 +26,7 @@
Вы можете использовать это, чтобы добавить аргумент `example` для каждого поля:
-//// tab | Python 3.10+
-
-```Python hl_lines="2 8-11"
-{!> ../../docs_src/schema_extra_example/tutorial002_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4 10-13"
-{!> ../../docs_src/schema_extra_example/tutorial002.py!}
-```
-
-////
+{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
/// warning | Внимание
@@ -80,57 +52,7 @@
Здесь мы передаём аргумент `example`, как пример данных ожидаемых в параметре `Body()`:
-//// tab | Python 3.10+
-
-```Python hl_lines="22-27"
-{!> ../../docs_src/schema_extra_example/tutorial003_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="22-27"
-{!> ../../docs_src/schema_extra_example/tutorial003_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="23-28"
-{!> ../../docs_src/schema_extra_example/tutorial003_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать версию с `Annotated`, если это возможно.
-
-///
-
-```Python hl_lines="18-23"
-{!> ../../docs_src/schema_extra_example/tutorial003_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать версию с `Annotated`, если это возможно.
-
-///
-
-```Python hl_lines="20-25"
-{!> ../../docs_src/schema_extra_example/tutorial003.py!}
-```
-
-////
+{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:27] *}
### Аргумент "example" в UI документации
@@ -151,57 +73,7 @@
* `value`: Это конкретный пример, который отображается, например, в виде типа `dict`.
* `externalValue`: альтернатива параметру `value`, URL-адрес, указывающий на пример. Хотя это может не поддерживаться таким же количеством инструментов разработки и тестирования API, как параметр `value`.
-//// tab | Python 3.10+
-
-```Python hl_lines="23-49"
-{!> ../../docs_src/schema_extra_example/tutorial004_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="23-49"
-{!> ../../docs_src/schema_extra_example/tutorial004_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="24-50"
-{!> ../../docs_src/schema_extra_example/tutorial004_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать версию с `Annotated`, если это возможно.
-
-///
-
-```Python hl_lines="19-45"
-{!> ../../docs_src/schema_extra_example/tutorial004_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip | Заметка
-
-Рекомендуется использовать версию с `Annotated`, если это возможно.
-
-///
-
-```Python hl_lines="21-47"
-{!> ../../docs_src/schema_extra_example/tutorial004.py!}
-```
-
-////
+{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:49] *}
### Аргумент "examples" в UI документации
diff --git a/docs/ru/docs/tutorial/security/first-steps.md b/docs/ru/docs/tutorial/security/first-steps.md
index 484dfceff..375c2d7f6 100644
--- a/docs/ru/docs/tutorial/security/first-steps.md
+++ b/docs/ru/docs/tutorial/security/first-steps.md
@@ -20,35 +20,7 @@
Скопируйте пример в файл `main.py`:
-//// tab | Python 3.9+
-
-```Python
-{!> ../../docs_src/security/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python
-{!> ../../docs_src/security/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python
-{!> ../../docs_src/security/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial001_an_py39.py *}
## Запуск
@@ -152,35 +124,7 @@ OAuth2 был разработан для того, чтобы бэкэнд ил
При создании экземпляра класса `OAuth2PasswordBearer` мы передаем в него параметр `tokenUrl`. Этот параметр содержит URL, который клиент (фронтенд, работающий в браузере пользователя) будет использовать для отправки `имени пользователя` и `пароля` с целью получения токена.
-//// tab | Python 3.9+
-
-```Python hl_lines="8"
-{!> ../../docs_src/security/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="7"
-{!> ../../docs_src/security/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="6"
-{!> ../../docs_src/security/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}
/// tip | Подсказка
@@ -218,35 +162,7 @@ oauth2_scheme(some, parameters)
Теперь вы можете передать ваш `oauth2_scheme` в зависимость с помощью `Depends`.
-//// tab | Python 3.9+
-
-```Python hl_lines="12"
-{!> ../../docs_src/security/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="11"
-{!> ../../docs_src/security/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.8+ без Annotated
-
-/// tip | Подсказка
-
-Предпочтительнее использовать версию с аннотацией, если это возможно.
-
-///
-
-```Python hl_lines="10"
-{!> ../../docs_src/security/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
Эта зависимость будет предоставлять `строку`, которая присваивается параметру `token` в *функции операции пути*.
@@ -266,7 +182,7 @@ oauth2_scheme(some, parameters)
Если он не видит заголовка `Authorization` или значение не имеет токена `Bearer`, то в ответ будет выдана ошибка с кодом состояния 401 (`UNAUTHORIZED`).
-Для возврата ошибки даже не нужно проверять, существует ли токен. Вы можете быть уверены, что если ваша функция будет выполнилась, то в этом токене есть `строка`.
+Для возврата ошибки даже не нужно проверять, существует ли токен. Вы можете быть уверены, что если ваша функция была выполнена, то в этом токене есть `строка`.
Проверить это можно уже сейчас в интерактивной документации:
diff --git a/docs/ru/docs/tutorial/security/get-current-user.md b/docs/ru/docs/tutorial/security/get-current-user.md
new file mode 100644
index 000000000..05eb290d7
--- /dev/null
+++ b/docs/ru/docs/tutorial/security/get-current-user.md
@@ -0,0 +1,99 @@
+# Данные текущего пользователя
+
+В предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции, обрабатывающей эндпоинт,* `токен` в виде `строки`:
+
+{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}
+
+Это пока что не слишком нам полезно. Давайте изменим код так, чтобы он возвращал нам данные пользователя, отправившего запрос.
+
+## Создание модели пользователя
+
+Сначала создадим Pydantic-модель пользователя.
+
+Точно так же, как мы использовали Pydantic для объявления тел запросов, мы можем использовать его где угодно:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}
+
+## Создание зависимости `get_current_user`
+
+Давайте создадим зависимость `get_current_user`.
+
+Помните, что у зависимостей могут быть подзависимости?
+
+`get_current_user` как раз будет иметь подзависимость `oauth2_scheme`, которую мы создали ранее.
+
+Аналогично тому, как мы делали это ранее в *обработчике эндпоинта* наша новая зависимость `get_current_user` будет получать `token` в виде `строки` от подзависимости `oauth2_scheme`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}
+
+## Получение данных пользователя
+
+`get_current_user` будет использовать созданную нами (ненастоящую) служебную функцию, которая принимает токен в виде `строки` и возвращает нашу Pydantic-модель `User`:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}
+
+## Внедрение зависимости текущего пользователя
+
+Теперь мы можем использовать тот же `Depends` с нашей зависимостью `get_current_user` в *функции обрабатывающей эндпоинт*:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}
+
+Обратите внимание, что мы объявляем тип переменной `current_user` как Pydantic-модель `User`.
+
+Это поможет выполнить внутри функции все проверки автозаполнения и типа.
+
+/// tip | Подсказка
+Возможно, вы помните, что тело запроса также объявляется с помощью Pydantic-моделей.
+
+В этом месте у **FastAPI** не возникнет проблем, потому что вы используете `Depends`.
+///
+
+/// check | Заметка
+То, как устроена эта система зависимостей, позволяет нам иметь различные зависимости, которые возвращают модель `User`.
+
+Мы не ограничены наличием только одной зависимости, которая может возвращать данные такого типа.
+///
+
+## Другие модели
+
+Теперь вы можете получать информацию о текущем пользователе непосредственно в *функции обрабатывающей эндпоинт* и работать с механизмами безопасности на уровне **Внедрения Зависимостей**, используя `Depends`.
+
+Причем для обеспечения требований безопасности можно использовать любую модель или данные (в данном случае - Pydantic-модель `User`).
+
+Но вы не ограничены использованием какой-то конкретной моделью данных, классом или типом.
+
+Вы хотите использовать в модели `id` и `email`, а `username` вам не нужен? Ну разумеется. Воспользуйтесь тем же инструментарием.
+
+Вам нужны только `строки`? Или только `словари`? Или непосредственно экземпляр модели класса базы данных? Все это работает точно также.
+
+У вас нет пользователей, которые входят в ваше приложение, а только роботы, боты или другие системы, у которых есть только токен доступа? Опять же, все работает одинаково.
+
+Просто используйте любую модель, любой класс, любую базу данных, которые нужны для вашего приложения. Система внедрения зависимостей **FastAPI** поможет вам в этом.
+
+## Размер кода
+
+Этот пример может показаться многословным. Следует иметь в виду, что в одном файле мы смешиваем безопасность, модели данных, служебные функции и *эндпоинты*.
+
+Но вот ключевой момент:
+
+Все, что касается безопасности и внедрения зависимостей, пишется один раз.
+
+И вы можете сделать его настолько сложным, насколько захотите. И все это будет написано только один раз, в одном месте, со всей своей гибкостью.
+
+И у вас могут быть тысячи конечных точек (*эндпоинтов*), использующих одну и ту же систему безопасности.
+
+И все они (или любая их часть по вашему желанию) могут воспользоваться преимуществами повторного использования этих зависимостей или любых других зависимостей, которые вы создадите.
+
+И все эти тысячи *эндпоинтов* могут составлять всего 3 строки:
+
+{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}
+
+## Резюме
+
+Теперь вы можете получать данные о текущем пользователе непосредственно в своей *функции обработчике эндпоинта*.
+
+Мы уже на полпути к этому.
+
+Осталось лишь добавить *эндпоинт* для отправки пользователем/клиентом своих `имени пользователя` и `пароля`.
+
+Это будет рассмотрено в следующем разделе.
diff --git a/docs/ru/docs/tutorial/security/oauth2-jwt.md b/docs/ru/docs/tutorial/security/oauth2-jwt.md
new file mode 100644
index 000000000..1195fad21
--- /dev/null
+++ b/docs/ru/docs/tutorial/security/oauth2-jwt.md
@@ -0,0 +1,261 @@
+# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами
+
+Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены JWT и безопасное хеширование паролей.
+
+Этот код можно реально использовать в своем приложении, сохранять хэши паролей в базе данных и т.д.
+
+Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе.
+
+## Про JWT
+
+JWT означает "JSON Web Tokens".
+
+Это стандарт для кодирования JSON-объекта в виде длинной строки без пробелов. Выглядит это следующим образом:
+
+```
+eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
+```
+
+Он не зашифрован, поэтому любой человек может восстановить информацию из его содержимого.
+
+Но он подписан. Следовательно, когда вы получаете токен, который вы эмитировали (выдавали), вы можете убедиться, что это именно вы его эмитировали.
+
+Таким образом, можно создать токен со сроком действия, скажем, 1 неделя. А когда пользователь вернется на следующий день с тем же токеном, вы будете знать, что он все еще авторизирован в вашей системе.
+
+Через неделю срок действия токена истечет, пользователь не будет авторизован и ему придется заново входить в систему, чтобы получить новый токен. А если пользователь (или третье лицо) попытается модифицировать токен, чтобы изменить срок действия, вы сможете это обнаружить, поскольку подписи не будут совпадать.
+
+Если вы хотите поиграть с JWT-токенами и посмотреть, как они работают, посмотрите https://jwt.io.
+
+## Установка `PyJWT`
+
+Нам необходимо установить `pyjwt` для генерации и проверки JWT-токенов на языке Python.
+
+Убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md){.internal-link target=_blank}, активируйте его, а затем установите `pyjwt`:
+
+
+
+/// info | Дополнительная информация
+Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`.
+
+Подробнее об этом можно прочитать в документации по установке PyJWT.
+///
+
+## Хеширование паролей
+
+"Хеширование" означает преобразование некоторого содержимого (в данном случае пароля) в последовательность байтов (просто строку), которая выглядит как тарабарщина.
+
+Каждый раз, когда вы передаете точно такое же содержимое (точно такой же пароль), вы получаете точно такую же тарабарщину.
+
+Но преобразовать тарабарщину обратно в пароль невозможно.
+
+### Для чего нужно хеширование паролей
+
+Если ваша база данных будет украдена, то вор не получит пароли пользователей в открытом виде, а только их хэши.
+
+Таким образом, вор не сможет использовать этот пароль в другой системе (поскольку многие пользователи везде используют один и тот же пароль, это было бы опасно).
+
+## Установка `passlib`
+
+PassLib - это отличный пакет Python для работы с хэшами паролей.
+
+Он поддерживает множество безопасных алгоритмов хеширования и утилит для работы с ними.
+
+Рекомендуемый алгоритм - "Bcrypt".
+
+Убедитесь, что вы создали и активировали виртуальное окружение, и затем установите PassLib вместе с Bcrypt:
+
+
+
+/// tip | Подсказка
+С помощью `passlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками.
+
+Таким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных.
+
+При этом пользователи смогут одновременно входить в систему как из приложения Django, так и из приложения **FastAPI**.
+///
+
+## Хеширование и проверка паролей
+
+Импортируйте необходимые инструменты из `passlib`.
+
+Создайте "контекст" PassLib. Именно он будет использоваться для хэширования и проверки паролей.
+
+/// tip | Подсказка
+Контекст PassLib также имеет функциональность для использования различных алгоритмов хеширования, в том числе и устаревших, только для возможности их проверки и т.д.
+
+Например, вы можете использовать его для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Bcrypt.
+
+И при этом быть совместимым со всеми этими системами.
+///
+
+Создайте служебную функцию для хэширования пароля, поступающего от пользователя.
+
+А затем создайте другую - для проверки соответствия полученного пароля и хранимого хэша.
+
+И еще одну - для аутентификации и возврата пользователя.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *}
+
+/// note | Технические детали
+Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`.
+///
+
+## Работа с JWT токенами
+
+Импортируйте установленные модули.
+
+Создайте случайный секретный ключ, который будет использоваться для подписи JWT-токенов.
+
+Для генерации безопасного случайного секретного ключа используйте команду:
+
+
+
+И скопируйте полученный результат в переменную `SECRET_KEY` (не используйте тот, что в примере).
+
+Создайте переменную `ALGORITHM` с алгоритмом, используемым для подписи JWT-токена, и установите для нее значение `"HS256"`.
+
+Создайте переменную для срока действия токена.
+
+Определите Pydantic Model, которая будет использоваться для формирования ответа на запрос на получение токена.
+
+Создайте служебную функцию для генерации нового токена доступа.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *}
+
+## Обновление зависимостей
+
+Обновите `get_current_user` для получения того же токена, что и раньше, но на этот раз с использованием JWT-токенов.
+
+Декодируйте полученный токен, проверьте его и верните текущего пользователя.
+
+Если токен недействителен, то сразу же верните HTTP-ошибку.
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *}
+
+## Обновление *операции пути* `/token`
+
+Создайте `timedelta` со временем истечения срока действия токена.
+
+Создайте реальный токен доступа JWT и верните его
+
+{* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *}
+
+### Технические подробности о JWT ключе `sub`
+
+В спецификации JWT говорится, что существует ключ `sub`, содержащий субъект токена.
+
+Его использование необязательно, но это именно то место, куда вы должны поместить идентификатор пользователя, и поэтому мы здесь его и используем.
+
+JWT может использоваться и для других целей, помимо идентификации пользователя и предоставления ему возможности выполнять операции непосредственно в вашем API.
+
+Например, вы могли бы определить "автомобиль" или "запись в блоге".
+
+Затем вы могли бы добавить права доступа к этой сущности, например "управлять" (для автомобиля) или "редактировать" (для блога).
+
+Затем вы могли бы передать этот JWT-токен пользователю (или боту), и они использовали бы его для выполнения определенных действий (управление автомобилем или редактирование запись в блоге), даже не имея учетной записи, просто используя JWT-токен, сгенерированный вашим API.
+
+Используя эти идеи, JWT можно применять для гораздо более сложных сценариев.
+
+В отдельных случаях несколько сущностей могут иметь один и тот же идентификатор, скажем, `foo` (пользователь `foo`, автомобиль `foo` и запись в блоге `foo`).
+
+Поэтому, чтобы избежать коллизий идентификаторов, при создании JWT-токена для пользователя можно добавить префикс `username` к значению ключа `sub`. Таким образом, в данном примере значение `sub` было бы `username:johndoe`.
+
+Важно помнить, что ключ `sub` должен иметь уникальный идентификатор для всего приложения и представлять собой строку.
+
+## Проверка в действии
+
+Запустите сервер и перейдите к документации: http://127.0.0.1:8000/docs.
+
+Вы увидите пользовательский интерфейс вида:
+
+
+
+Пройдите авторизацию так же, как делали раньше.
+
+Используя учетные данные пользователя:
+
+Username: `johndoe`
+Password: `secret`
+
+/// check | Заметка
+Обратите внимание, что нигде в коде не используется открытый текст пароля "`secret`", мы используем только его хэшированную версию.
+///
+
+
+
+Вызвав эндпоинт `/users/me/`, вы получите ответ в виде:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false
+}
+```
+
+
+
+Если открыть инструменты разработчика, то можно увидеть, что передаваемые данные включают только токен, пароль передается только в первом запросе для аутентификации пользователя и получения токена доступа, но не в последующих:
+
+
+
+/// note | Техническая информация
+Обратите внимание на заголовок `Authorization`, значение которого начинается с `Bearer`.
+///
+
+## Продвинутое использование `scopes`
+
+В OAuth2 существует понятие "диапазоны" ("`scopes`").
+
+С их помощью можно добавить определенный набор разрешений к JWT-токену.
+
+Затем вы можете передать этот токен непосредственно пользователю или третьей стороне для взаимодействия с вашим API с определенным набором ограничений.
+
+О том, как их использовать и как они интегрированы в **FastAPI**, читайте далее в **Руководстве пользователя**.
+
+## Резюме
+
+С учетом того, что вы видели до сих пор, вы можете создать безопасное приложение **FastAPI**, используя такие стандарты, как OAuth2 и JWT.
+
+Практически в любом фреймворке работа с безопасностью довольно быстро превращается в сложную тему.
+
+Многие пакеты, сильно упрощающие эту задачу, вынуждены идти на многочисленные компромиссы с моделью данных, с базой данных и с доступным функционалом. Некоторые из этих пакетов, которые пытаются уж слишком все упростить, имеют даже "дыры" в системе безопасности.
+
+---
+
+**FastAPI** не делает уступок ни одной базе данных, модели данных или инструментарию.
+
+Он предоставляет вам полную свободу действий, позволяя выбирать то, что лучше всего подходит для вашего проекта.
+
+Вы можете напрямую использовать многие хорошо поддерживаемые и широко распространенные пакеты, такие как `passlib` и `PyJWT`, поскольку **FastAPI** не требует сложных механизмов для интеграции внешних пакетов.
+
+Напротив, он предоставляет инструменты, позволяющие максимально упростить этот процесс без ущерба для гибкости, надежности и безопасности.
+
+При этом вы можете использовать и реализовывать безопасные стандартные протоколы, такие как OAuth2, относительно простым способом.
+
+В **Руководстве пользователя** вы можете узнать больше о том, как использовать "диапазоны" ("`scopes`") OAuth2 для создания более точно настроенной системы разрешений в соответствии с теми же стандартами. OAuth2 с диапазонами - это механизм, используемый многими крупными провайдерами сервиса аутентификации, такими как Facebook, Google, GitHub, Microsoft, Twitter и др., для авторизации сторонних приложений на взаимодействие с их API от имени их пользователей.
diff --git a/docs/ru/docs/tutorial/security/simple-oauth2.md b/docs/ru/docs/tutorial/security/simple-oauth2.md
new file mode 100644
index 000000000..9732265cc
--- /dev/null
+++ b/docs/ru/docs/tutorial/security/simple-oauth2.md
@@ -0,0 +1,272 @@
+# Простая авторизация по протоколу OAuth2 с токеном типа Bearer
+
+Теперь, отталкиваясь от предыдущей главы, добавим недостающие части, чтобы получить безопасную систему.
+
+## Получение `имени пользователя` и `пароля`
+
+Для получения `имени пользователя` и `пароля` мы будем использовать утилиты безопасности **FastAPI**.
+
+Протокол OAuth2 определяет, что при использовании "аутентификации по паролю" (которую мы и используем) клиент/пользователь должен передавать поля `username` и `password` в полях формы.
+
+В спецификации сказано, что поля должны быть названы именно так. Поэтому `user-name` или `email` работать не будут.
+
+Но не волнуйтесь, вы можете показать его конечным пользователям во фронтенде в том виде, в котором хотите.
+
+А ваши модели баз данных могут использовать любые другие имена.
+
+Но при авторизации согласно спецификации, требуется использовать именно эти имена, что даст нам возможность воспользоваться встроенной системой документации API.
+
+В спецификации также указано, что `username` и `password` должны передаваться в виде данных формы (так что никакого JSON здесь нет).
+
+### Oбласть видимости (scope)
+
+В спецификации также говорится, что клиент может передать еще одно поле формы "`scope`".
+
+Имя поля формы - `scope` (в единственном числе), но на самом деле это длинная строка, состоящая из отдельных областей видимости (scopes), разделенных пробелами.
+
+Каждая "область видимости" (scope) - это просто строка (без пробелов).
+
+Обычно они используются для указания уровней доступа, например:
+
+* `users:read` или `users:write` являются распространенными примерами.
+* `instagram_basic` используется Facebook / Instagram.
+* `https://www.googleapis.com/auth/drive` используется компанией Google.
+
+/// info | Дополнительнаяя информация
+В OAuth2 "scope" - это просто строка, которая уточняет уровень доступа.
+
+Не имеет значения, содержит ли он другие символы, например `:`, или является ли он URL.
+
+Эти детали зависят от конкретной реализации.
+
+Для OAuth2 это просто строки.
+///
+
+## Код получения `имени пользователя` и `пароля`
+
+Для решения задачи давайте воспользуемся утилитами, предоставляемыми **FastAPI**.
+
+### `OAuth2PasswordRequestForm`
+
+Сначала импортируйте `OAuth2PasswordRequestForm` и затем используйте ее как зависимость с `Depends` в *эндпоинте* `/token`:
+
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}
+
+`OAuth2PasswordRequestForm` - это класс для использования в качестве зависимости для *функции обрабатывающей эндпоинт*, который определяет тело формы со следующими полями:
+
+* `username`.
+* `password`.
+* Необязательное поле `scope` в виде большой строки, состоящей из строк, разделенных пробелами.
+* Необязательное поле `grant_type`.
+
+/// tip | Подсказка
+По спецификации OAuth2 поле `grant_type` является обязательным и содержит фиксированное значение `password`, но `OAuth2PasswordRequestForm` не обеспечивает этого.
+
+Если вам необходимо использовать `grant_type`, воспользуйтесь `OAuth2PasswordRequestFormStrict` вместо `OAuth2PasswordRequestForm`.
+///
+
+* Необязательное поле `client_id` (в нашем примере он не нужен).
+* Необязательное поле `client_secret` (в нашем примере он не нужен).
+
+/// info | Дополнительная информация
+Форма `OAuth2PasswordRequestForm` не является специальным классом для **FastAPI**, как `OAuth2PasswordBearer`.
+
+`OAuth2PasswordBearer` указывает **FastAPI**, что это схема безопасности. Следовательно, она будет добавлена в OpenAPI.
+
+Но `OAuth2PasswordRequestForm` - это всего лишь класс зависимости, который вы могли бы написать самостоятельно или вы могли бы объявить параметры `Form` напрямую.
+
+Но, поскольку это распространённый вариант использования, он предоставляется **FastAPI** напрямую, просто чтобы облегчить задачу.
+///
+
+### Использование данных формы
+
+/// tip | Подсказка
+В экземпляре зависимого класса `OAuth2PasswordRequestForm` атрибут `scope`, состоящий из одной длинной строки, разделенной пробелами, заменен на атрибут `scopes`, состоящий из списка отдельных строк, каждая из которых соответствует определенному уровню доступа.
+
+В данном примере мы не используем `scopes`, но если вам это необходимо, то такая функциональность имеется.
+///
+
+Теперь получим данные о пользователе из (ненастоящей) базы данных, используя `username` из поля формы.
+
+Если такого пользователя нет, то мы возвращаем ошибку "неверное имя пользователя или пароль".
+
+Для ошибки мы используем исключение `HTTPException`:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}
+
+### Проверка пароля
+
+На данный момент у нас есть данные о пользователе из нашей базы данных, но мы еще не проверили пароль.
+
+Давайте сначала поместим эти данные в модель Pydantic `UserInDB`.
+
+Ни в коем случае нельзя сохранять пароли в открытом виде, поэтому мы будем использовать (пока что ненастоящую) систему хеширования паролей.
+
+Если пароли не совпадают, мы возвращаем ту же ошибку.
+
+#### Хеширование паролей
+
+"Хеширование" означает: преобразование некоторого содержимого (в данном случае пароля) в последовательность байтов (просто строку), которая выглядит как тарабарщина.
+
+Каждый раз, когда вы передаете точно такое же содержимое (точно такой же пароль), вы получаете точно такую же тарабарщину.
+
+Но преобразовать тарабарщину обратно в пароль невозможно.
+
+##### Зачем использовать хеширование паролей
+
+Если ваша база данных будет украдена, то у вора не будет паролей пользователей в открытом виде, только хэши.
+
+Таким образом, вор не сможет использовать эти же пароли в другой системе (поскольку многие пользователи используют одни и те же пароли повсеместно, это было бы опасно).
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}
+
+#### Про `**user_dict`
+
+`UserInDB(**user_dict)` означает:
+
+*Передавать ключи и значения `user_dict` непосредственно в качестве аргументов ключ-значение, что эквивалентно:*
+
+```Python
+UserInDB(
+ username = user_dict["username"],
+ email = user_dict["email"],
+ full_name = user_dict["full_name"],
+ disabled = user_dict["disabled"],
+ hashed_password = user_dict["hashed_password"],
+)
+```
+
+/// info | Дополнительная информация
+Более полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user_indict){.internal-link target=_blank}.
+///
+
+## Возврат токена
+
+Ответ эндпоинта `token` должен представлять собой объект в формате JSON.
+
+Он должен иметь `token_type`. В нашем случае, поскольку мы используем токены типа "Bearer", тип токена должен быть "`bearer`".
+
+И в нем должна быть строка `access_token`, содержащая наш токен доступа.
+
+В этом простом примере мы нарушим все правила безопасности, и будем считать, что имя пользователя (username) полностью соответствует токену (token)
+
+/// tip | Подсказка
+В следующей главе мы рассмотрим реальную защищенную реализацию с хешированием паролей и токенами JWT.
+
+Но пока давайте остановимся на необходимых нам деталях.
+///
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}
+
+/// tip | Подсказка
+Согласно спецификации, вы должны возвращать JSON с `access_token` и `token_type`, как в данном примере.
+
+Это то, что вы должны сделать сами в своем коде и убедиться, что вы используете эти JSON-ключи.
+
+Это практически единственное, что нужно не забывать делать самостоятельно, чтобы следовать требованиям спецификации.
+
+Все остальное за вас сделает **FastAPI**.
+///
+
+## Обновление зависимостей
+
+Теперь мы обновим наши зависимости.
+
+Мы хотим получить значение `current_user` *только* если этот пользователь активен.
+
+Поэтому мы создаем дополнительную зависимость `get_current_active_user`, которая, в свою очередь, использует в качестве зависимости `get_current_user`.
+
+Обе эти зависимости просто вернут HTTP-ошибку, если пользователь не существует или неактивен.
+
+Таким образом, в нашем эндпоинте мы получим пользователя только в том случае, если он существует, правильно аутентифицирован и активен:
+
+{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}
+
+/// info | Дополнительная информация
+Дополнительный заголовок `WWW-Authenticate` со значением `Bearer`, который мы здесь возвращаем, также является частью спецификации.
+
+Ответ сервера с HTTP-кодом 401 "UNAUTHORIZED" должен также возвращать заголовок `WWW-Authenticate`.
+
+В случае с bearer-токенами (наш случай) значение этого заголовка должно быть `Bearer`.
+
+На самом деле этот дополнительный заголовок можно пропустить и все будет работать.
+
+Но он приведён здесь для соответствия спецификации.
+
+Кроме того, могут существовать инструменты, которые ожидают его и могут использовать, и это может быть полезно для вас или ваших пользователей сейчас или в будущем.
+
+В этом и заключается преимущество стандартов...
+///
+
+## Посмотим как это работает
+
+Откроем интерактивную документацию: http://127.0.0.1:8000/docs.
+
+### Аутентификация
+
+Нажмите кнопку "Авторизация".
+
+Используйте учётные данные:
+
+Пользователь: `johndoe`
+
+Пароль: `secret`
+
+
+
+После авторизации в системе вы увидите следующее:
+
+
+
+### Получение собственных пользовательских данных
+
+Теперь, используя операцию `GET` с путем `/users/me`, вы получите данные пользователя, например:
+
+```JSON
+{
+ "username": "johndoe",
+ "email": "johndoe@example.com",
+ "full_name": "John Doe",
+ "disabled": false,
+ "hashed_password": "fakehashedsecret"
+}
+```
+
+
+
+Если щелкнуть на значке замка и выйти из системы, а затем попытаться выполнить ту же операцию ещё раз, то будет выдана ошибка HTTP 401:
+
+```JSON
+{
+ "detail": "Not authenticated"
+}
+```
+
+### Неактивный пользователь
+
+Теперь попробуйте пройти аутентификацию с неактивным пользователем:
+
+Пользователь: `alice`
+
+Пароль: `secret2`
+
+И попробуйте использовать операцию `GET` с путем `/users/me`.
+
+Вы получите ошибку "Inactive user", как тут:
+
+```JSON
+{
+ "detail": "Inactive user"
+}
+```
+
+## Резюме
+
+Теперь у вас есть инструменты для реализации полноценной системы безопасности на основе `имени пользователя` и `пароля` для вашего API.
+
+Используя эти средства, можно сделать систему безопасности совместимой с любой базой данных, с любым пользователем или моделью данных.
+
+ Единственным недостатком нашей системы является то, что она всё ещё не защищена.
+
+В следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены JWT.
diff --git a/docs/ru/docs/tutorial/sql-databases.md b/docs/ru/docs/tutorial/sql-databases.md
new file mode 100644
index 000000000..b127e44d5
--- /dev/null
+++ b/docs/ru/docs/tutorial/sql-databases.md
@@ -0,0 +1,358 @@
+# SQL (реляционные) базы данных
+
+**FastAPI** не требует использования реляционной базы данных. Вы можете воспользоваться любой базой данных, которой хотите.
+
+В этом разделе мы продемонстрируем, как работать с SQLModel.
+
+Библиотека **SQLModel** построена на основе SQLAlchemy и Pydantic. Она была разработана автором **FastAPI** специально для приложений на основе FastAPI, которые используют **реляционные базы данных**.
+
+/// tip | Подсказка
+
+Вы можете воспользоваться любой библиотекой для работы с реляционными (SQL) или нереляционными (NoSQL) базами данных. (Их ещё называют **ORM** библиотеками). FastAPI не принуждает вас к использованию чего-либо конкретного. 😎
+
+///
+
+В основе SQLModel лежит SQLAlchemy, поэтому вы спокойно можете использовать любую базу данных, поддерживаемую SQLAlchemy (и, соответственно, поддерживаемую SQLModel), например:
+
+* PostgreSQL
+* MySQL
+* SQLite
+* Oracle
+* Microsoft SQL Server, и т.д.
+
+В данном примере мы будем использовать базу данных **SQLite**, т.к. она состоит из единственного файла и поддерживается встроенными библиотеками Python. Таким образом, вы сможете скопировать данный пример и запустить его как он есть.
+
+В дальнейшем, для продакшн-версии вашего приложения, возможно, вам стоит использовать серверную базу данных, например, **PostgreSQL**.
+
+/// tip | Подсказка
+
+Существует официальный генератор проектов на **FastAPI** и **PostgreSQL**, который также включает frontend и дополнительные инструменты https://github.com/fastapi/full-stack-fastapi-template
+
+///
+
+Это очень простое и короткое руководство, поэтому, если вы хотите узнать о базах данных в целом, об SQL, разобраться с более продвинутым функционалом, то воспользуйтесь документацией SQLModel.
+
+## Установка `SQLModel`
+
+Создайте виртуальное окружение [virtual environment](../virtual-environments.md){.internal-link target=_blank}, активируйте его и установите `sqlmodel`:
+
+
+
+## Создание приложения с единственной моделью
+
+Мы начнем с создания наиболее простой первой версии нашего приложения с одной единственной моделью **SQLModel**.
+
+В дальнейшем с помощью **дополнительных моделей** мы его улучшим и сделаем более безопасным и универсальным. 🤓
+
+### Создание моделей
+
+Импортируйте `SQLModel` и создайте модель базы данных:
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}
+
+Класс `Hero` очень напоминает модель Pydantic (фактически, под капотом, *это и есть модель Pydantic*).
+
+Но есть и некоторые различия
+
+* `table=True` для SQLModel означает, что это *модель-таблица*, которая должна представлять **таблицу** в реляционной базе данных. Это не просто *модель данных* (в отличие от обычного класса в Pydantic).
+
+* `Field(primary_key=True)` для SQLModel означает, что поле `id` является первичным ключом в таблице базы данных (вы можете подробнее узнать о первичных ключах баз данных в документации по SQLModel).
+
+ Тип `int | None` сигнализирует для SQLModel, что столбец таблицы базы данных должен иметь тип `INTEGER`, или иметь пустое значение `NULL`.
+
+* `Field(index=True)` для SQLModel означает, что нужно создать **SQL индекс** для данного столбца. Это обеспечит более быстрый поиск при чтении данных, отфильтрованных по данному столбцу.
+
+ SQLModel будет знать, что данные типа `str`, будут представлены в базе данных как `TEXT` (или `VARCHAR`, в зависимости от типа базы данных).
+
+### Создание соединения с базой данных (Engine)
+
+В SQLModel объект соединения `engine` (по сути это `Engine` из SQLAlchemy) **содержит пул соединений** к базе данных.
+
+Для обеспечения всех подключений приложения к одной базе данных нужен только один объект соединения `engine`.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}
+
+Использование настройки `check_same_thread=False` позволяет FastAPI использовать одну и ту же SQLite базу данных в различных потоках (threads). Это необходимо, когда **один запрос** использует **более одного потока** (например, в зависимостях).
+
+Не беспокойтесь, учитывая структуру кода, мы позже позаботимся о том, чтобы использовать **отдельную SQLModel-сессию на каждый отдельный запрос**, это как раз то, что пытается обеспечить `check_same_thread`.
+
+### Создание таблиц
+
+Далее мы добавляем функцию, использующую `SQLModel.metadata.create_all(engine)`, для того, чтобы создать **таблицы** для каждой из **моделей таблицы**.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}
+
+### Создание зависимости Session
+
+Сессия базы данных (**`Session`**) хранит **объекты в памяти** и отслеживает любые необходимые изменения в данных, а затем **использует `engine`** для коммуникации с базой данных.
+
+Мы создадим FastAPI-**зависимость** с помощью `yield`, которая будет создавать новую сессию (Session) для каждого запроса. Это как раз и обеспечит использование отдельной сессии на каждый отдельный запрос. 🤓
+
+Затем мы создадим объявленную (`Annotated`) зависимость `SessionDep`. Мы сделаем это для того, чтобы упростить остальной код, который будет использовать эту зависимость.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *}
+
+### Создание таблиц базы данных при запуске приложения
+
+Мы будем создавать таблицы базы данных при запуске приложения.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}
+
+В данном примере мы создаем таблицы при наступлении события запуска приложения.
+
+В продуктовом приложении вы, скорее всего, будете использовать скрипт для миграции базы данных, который выполняется перед запуском приложения. 🤓
+
+/// tip | Подсказка
+
+В SQLModel будут включены утилиты миграции, входящие в состав Alembic, но на данный момент вы просто можете использовать
+Alembic напрямую.
+
+///
+
+### Создание героя (Hero)
+
+Каждая модель в SQLModel является также моделью Pydantic, поэтому вы можете использовать её при **объявлении типов**, точно также, как и модели Pydantic.
+
+Например, при объявлении параметра типа `Hero`, она будет считана из **тела JSON**.
+
+Точно также, вы можете использовать её при объявлении типа значения, возвращаемого функцией, и тогда структурированные данные будут отображены через пользовательский интерфейс автоматически сгенерированной документации FastAPI.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}
+
+Мы используем зависимость `SessionDep` (сессию базы данных) для того, чтобы добавить нового героя `Hero` в объект сессии (`Session`), сохранить изменения в базе данных, обновить данные героя и затем вернуть их.
+
+### Чтение данных о героях
+
+Мы можем **читать** данные героев из базы данных с помощью `select()`. Мы можем включить `limit` и `offset` для постраничного считывания результатов.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}
+
+### Чтение данных отдельного героя
+
+Мы можем прочитать данные отдельного героя (`Hero`).
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}
+
+### Удаление данных героя
+
+Мы также можем удалить героя `Hero` из базы данных.
+
+{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}
+
+### Запуск приложения
+
+Вы можете запустить приложение следующим образом:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Далее перейдите в пользовательский интерфейс API `/docs`. Вы увидите, что **FastAPI** использует модели для создания документации API. Эти же модели используются для сериализации и проверки данных.
+
+
+
+
+
+## Добавление в приложение дополнительных (вспомогательных) моделей
+
+Теперь давайте проведём **рефакторинг** нашего приложения, чтобы сделать его более безопасным и более универсальным.
+
+Обратите внимание, что на данном этапе наше приложение позволяет на уровне клиента определять `id` создаваемого героя (`Hero`). 😱
+
+Мы не можем этого допустить, т.к. существует риск переписать уже присвоенные `id` в базе данных. Присвоение `id` должно происходить **на уровне бэкэнда (backend)** или **на уровне базы данных**, но никак **не на уровне клиента**.
+
+Кроме того, мы создаем секретное имя `secret_name` для героя, но пока что, мы возвращаем его повсеместно, и это слабо напоминает **секретность**... 😅
+
+Мы поправим это с помощью нескольких дополнительных (вспомогательных) моделей. Вот где SQLModel по-настоящему покажет себя. ✨
+
+### Создание дополнительных моделей
+
+В **SQLModel**, любая модель с параметром `table=True` является **моделью таблицы**.
+
+Любая модель, не содержащая `table=True` является **моделью данных**, это по сути обычные модели Pydantic (с несколько расширенным функционалом). 🤓
+
+С помощью SQLModel мы можем использовать **наследование**, что поможет нам **избежать дублирования** всех полей.
+
+#### Базовый класс `HeroBase`
+
+Давайте начнём с модели `HeroBase`, которая содержит поля, общие для всех моделей:
+
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}
+
+#### Модель таблицы `Hero`
+
+Далее давайте создадим **модель таблицы** `Hero` с дополнительными полями, которых может не быть в других моделях:
+
+* `id`
+* `secret_name`
+
+Модель `Hero` наследует от `HeroBase`, и поэтому включает также поля из `HeroBase`. Таким образом, все поля, содержащиеся в `Hero`, будут следующими:
+
+* `id`
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}
+
+#### Публичная модель данных `HeroPublic`
+
+Далее мы создадим модель `HeroPublic`. Мы будем возвращать её клиентам API.
+
+Она включает в себя те же поля, что и `HeroBase`, и, соответственно, поле `secret_name` в ней отсутствует.
+
+Наконец-то личность наших героев защищена! 🥷
+
+В модели `HeroPublic` также объявляется поле `id: int`. Мы как бы заключаем договоренность с API клиентом, на то, что передаваемые данные всегда должны содержать поле `id`, и это поле должно содержать целое число (и никогда не содержать `None`).
+
+/// tip | Подсказка
+
+Модель ответа, гарантирующая наличие поля со значением типа `int` (не `None`), очень полезна при разработке API клиентов. Определенность в передаваемых данных может обеспечить написание более простого кода.
+
+Также **автоматически генерируемые клиенты** будут иметь более простой интерфейс. И в результате жизнь разработчиков, использующих ваш API, станет значительно легче. 😎
+
+///
+
+`HeroPublic` содержит все поля `HeroBase`, а также поле `id`, объявленное как `int` (не `None`):
+
+* `id`
+* `name`
+* `age`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}
+
+#### Модель для создания героя `HeroCreate`
+
+Сейчас мы создадим модель `HeroCreate`. Эта модель будет использоваться для проверки данных, переданных клиентом.
+
+Она содержит те же поля, что и `HeroBase`, а также поле `secret_name`.
+
+Теперь, при создании нового героя, клиенты будут передавать секретное имя `secret_name`, которое будет сохранено в базе данных, но не будет возвращено в ответе API клиентам.
+
+/// tip | Подсказка
+
+Вот как нужно работать с **паролями**: получайте их, но не возвращайте их через API.
+
+Также хэшируйте значения паролей перед тем, как их сохранить. Ни в коем случае не храните пароли в открытом виде, как обычный текст.
+
+///
+
+Поля модели `HeroCreate`:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}
+
+#### Модель для обновления данных героя `HeroUpdate`
+
+В предыдущих версиях нашей программы мы не могли обновить данные героя, теперь, воспользовавшись дополнительными моделями, мы сможем это сделать. 🎉
+
+Модель данных `HeroUpdate` в некотором смысле особенная. Она содержит все те же поля, что и модель создания героя, но все поля модели являются **необязательными**. (Все они имеют значение по умолчанию.) Таким образом, при обновлении данных героя, вам достаточно передать только те поля, которые требуют изменения.
+
+Поскольку **все поля по сути меняются** (теперь тип каждого поля допускает значение `None` и значение по умолчанию `None`), мы должны их **объявить заново**.
+
+Фактически, нам не нужно наследоваться от `HeroBase`, потому что мы будем заново объявлять все поля. Я оставлю наследование просто для поддержания общего стиля, но оно (наследование) здесь необязательно. 🤷
+
+Поля `HeroUpdate`:
+
+* `name`
+* `age`
+* `secret_name`
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}
+
+### Создание героя с помощью `HeroCreate` и возвращение результатов с помощью `HeroPublic`
+
+Теперь, когда у нас есть дополнительные модели, мы можем обновить те части приложения, которые их используют.
+
+Вместе c запросом на создание героя мы получаем объект данных `HeroCreate`, и создаем на его основе объект модели таблицы `Hero`.
+
+Созданный объект *модели таблицы* `Hero` будет иметь все поля, переданные клиентом, а также поле `id`, сгенерированное базой данных.
+
+Далее функция вернёт объект *модели таблицы* `Hero`. Но поскольку, мы объявили `HeroPublic` как модель ответа, то **FastAPI** будет использовать именно её для проверки и сериализации данных.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}
+
+/// tip | Подсказка
+
+Теперь мы используем модель ответа `response_model=HeroPublic`, вместо того, чтобы объявить тип возвращаемого значения как `-> HeroPublic`. Мы это делаем потому, что тип возвращаемого значения не относится к `HeroPublic`.
+
+Если бы мы объявили тип возвращаемого значения как `-> HeroPublic`, то редактор и линтер начали бы ругаться (и вполне справедливо), что возвращаемое значение принадлежит типу `Hero`, а совсем не `HeroPublic`.
+
+Объявляя модель ответа в `response_model`, мы как бы говорим **FastAPI**: делай свое дело, не вмешиваясь в аннотацию типов и не полагаясь на помощь редактора или других инструментов.
+
+///
+
+### Чтение данных героев с помощью `HeroPublic`
+
+Мы можем проделать то же самое **для чтения данных** героев. Мы применим модель ответа `response_model=list[HeroPublic]`, и тем самым обеспечим правильную проверку и сериализацию данных.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}
+
+### Чтение данных отдельного героя с помощью `HeroPublic`
+
+Мы можем **прочитать** данные отдельного героя:
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}
+
+### Обновление данных героя с помощью `HeroUpdate`
+
+Мы можем **обновить данные героя**. Для этого мы воспользуемся HTTP методом `PATCH`.
+
+В коде мы получаем объект словаря `dict` с данными, переданными клиентом (т.е. **только c данными, переданными клиентом**, исключая любые значения, которые могли бы быть там только потому, что они являются значениями по умолчанию). Для того чтобы сделать это, мы воспользуемся опцией `exclude_unset=True`. В этом главная хитрость. 🪄
+
+Затем мы применим `hero_db.sqlmodel_update(hero_data)`, и обновим `hero_db`, использовав данные `hero_data`.
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}
+
+### Удалим героя ещё раз
+
+Операция **удаления** героя практически не меняется.
+
+В данном случае желание *`отрефакторить всё`* остаётся неудовлетворенным. 😅
+
+{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}
+
+### Снова запустим приложение
+
+Вы можете снова запустить приложение:
+
+
+
+```console
+$ fastapi dev main.py
+
+INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
+```
+
+
+
+Если вы перейдете в пользовательский интерфейс API `/docs`, то вы увидите, что он был обновлен, и больше не принимает параметра `id` от клиента при создании нового героя, и т.д.
+
+
+
+
+
+## Резюме
+
+Вы можете использовать **SQLModel** для взаимодействия с реляционными базами данных, а также для упрощения работы с **моделями данных** и **моделями таблиц**.
+
+Вы можете узнать гораздо больше информации в документации по **SQLModel**. Там вы найдете более подробное мини-руководство по использованию SQLModel с **FastAPI**. 🚀
diff --git a/docs/ru/docs/tutorial/static-files.md b/docs/ru/docs/tutorial/static-files.md
index 0287fb017..c06eb858b 100644
--- a/docs/ru/docs/tutorial/static-files.md
+++ b/docs/ru/docs/tutorial/static-files.md
@@ -7,9 +7,7 @@
* Импортируйте `StaticFiles`.
* "Примонтируйте" экземпляр `StaticFiles()` с указанием определенной директории.
-```Python hl_lines="2 6"
-{!../../docs_src/static_files/tutorial001.py!}
-```
+{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
/// note | Технические детали
diff --git a/docs/ru/docs/tutorial/testing.md b/docs/ru/docs/tutorial/testing.md
index 0485ef801..2c0f93d48 100644
--- a/docs/ru/docs/tutorial/testing.md
+++ b/docs/ru/docs/tutorial/testing.md
@@ -26,9 +26,7 @@
Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`).
-```Python hl_lines="2 12 15-18"
-{!../../docs_src/app_testing/tutorial001.py!}
-```
+{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
/// tip | Подсказка
@@ -74,9 +72,7 @@
Здесь файл `main.py` является "точкой входа" в Ваше приложение и содержит инициализацию Вашего приложения **FastAPI**:
-```Python
-{!../../docs_src/app_testing/main.py!}
-```
+{* ../../docs_src/app_testing/main.py *}
### Файл тестов
@@ -92,9 +88,8 @@
Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:
-```Python hl_lines="3"
-{!../../docs_src/app_testing/test_main.py!}
-```
+{* ../../docs_src/app_testing/test_main.py hl[3] *}
+
...и писать дальше тесты, как и раньше.
@@ -178,9 +173,8 @@
Теперь обновим файл `test_main.py`, добавив в него тестов:
-```Python
-{!> ../../docs_src/app_testing/app_b/test_main.py!}
-```
+{* ../../docs_src/app_testing/app_b/test_main.py *}
+
Если Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: "Как передать информацию в запросе с помощью `httpx`", можно даже спросить: "Как передать информацию в запросе с помощью `requests`", поскольку дизайн HTTPX основан на дизайне Requests.
diff --git a/docs/ru/docs/virtual-environments.md b/docs/ru/docs/virtual-environments.md
new file mode 100644
index 000000000..777adaf22
--- /dev/null
+++ b/docs/ru/docs/virtual-environments.md
@@ -0,0 +1,839 @@
+# Виртуальная среда
+
+При работе с проектами в Python рекомендуется использовать **виртуальную среду разработки** (или какой-нибудь другой подобный механизм). Это нужно для того, чтобы изолировать устанавливаемые пакеты для каждого отдельного проекта.
+
+/// info | Дополнительная информация
+
+Если вы уже знакомы с виртуальными средами разработки, знаете как их создавать и использовать, то вы можете свободно пропустить данный раздел. 🤓
+
+///
+
+/// tip | Подсказка
+
+**Виртуальная среда** и **переменная окружения** это две разные вещи.
+
+**Переменная окружения** это системная переменная, которую могут использовать программы.
+
+**Виртуальная среда** это папка, содержащая файлы.
+
+///
+
+/// info | Дополнительная информация
+
+В этом разделе мы научим вас пользоваться виртуальными средами разработки и расскажем, как они работают.
+
+Если же вы готовы воспользоваться инструментом, **который умеет управлять всем, что касается Python-проектов**,
+(включая установку Python), то попробуйте uv.
+
+///
+
+## Создание проекта
+
+В первую очередь, создайте директорию для вашего проекта.
+
+Я обычно создаю папку под названием `code` внутри моего домашнего каталога `/home/user`.
+
+Затем внутри данной папки я создаю отдельную директорию под каждый свой проект.
+
+
+
+```console
+// Перейдите в домашний каталог
+$ cd
+// Создайте отдельную папку под все будущие программные проекты (code)
+$ mkdir code
+// Войдите в директорию code
+$ cd code
+// Создайте директрорию под данный проект (awesome-project)
+$ mkdir awesome-project
+// Перейдите в созданную директорию проекта
+$ cd awesome-project
+```
+
+
+
+## Создание виртуальной среды разработки
+
+Начиная работу с Python-проектом, сразу же создавайте виртуальную среду разработки
+**внутри вашего проекта**.
+
+/// tip | Подсказка
+
+Виртуальная среда разработки создается один раз, и в дальнейшем, работая с проектом, этого больше делать не придется.
+
+///
+
+//// tab | `venv`
+
+Для создания виртуальной среды вы можете воспользоваться модулем `venv`, который является частью встроенной библиотеки Python.
+
+
+
+```console
+$ python -m venv .venv
+```
+
+
+
+/// details | Что делает эта команда?
+
+* `python`: использовать программу под именем `python`
+* `-m`: вызывать модуль как скрипт, в следующей инструкции мы скажем какой именно модуль вызвать
+* `venv`: использовать модуль под названием `venv`, который обычно устанавливается вместе с Python
+* `.venv`: создать виртуальную среду разработки в новой директории `.venv`
+
+///
+
+////
+
+//// tab | `uv`
+
+Если вы установили `uv`, то вы можете им воспользоваться для создания виртуальной среды разработки.
+
+
+
+```console
+$ uv venv
+```
+
+
+
+/// tip | Подсказка
+
+По умолчанию `uv` создаст виртуальную среду разработки в папке под названием `.venv`.
+
+Но вы можете это изменить, передав дополнительный аргумент с именем директории.
+
+///
+
+////
+
+Данная команда создаст новую виртуальную среду разработки в папке `.venv`.
+
+/// details | `.venv` или другое имя?
+
+Вы можете поместить виртуальную среду разработки в папку с другим именем, но традиционным (конвенциональным) названием является `.venv` .
+
+///
+
+## Активация виртуальной среды разработки
+
+Активируйте виртуальную среду разработки, и тогда любая запускаемая Python-команда или устанавливаемый пакет будут ее использовать.
+
+/// tip | Подсказка
+
+При работе над проектом делайте это **каждый раз** при запуске **новой сессии в терминале**.
+
+///
+
+//// tab | Linux, macOS
+
+
+
+////
+
+## Проверка активации виртуальной среды
+
+Проверьте, активна ли виртуальная среда (удостоверимся, что предыдущая команда сработала).
+
+/// tip | Подсказка
+
+Убедитесь в том, что все работает так, как нужно и вы используете именно ту виртуальную среду разработки, которую нужно. Делать это необязательно, но желательно.
+
+///
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+Если данная команда показывает, что исполняемый файл `python` (`.venv\bin\python`), находится внутри виртуальной среды вашего проекта (у нас это `awesome-project`), значит все отработало как нужно. 🎉
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+Если данная команда показывает, что исполняемый файл `python` (`.venv\Scripts\python`), находится внутри виртуальной среды вашего проекта (у нас это `awesome-project`), значит все отработало как нужно. 🎉
+
+////
+
+## Обновление `pip`
+
+/// tip | Подсказка
+
+Если вы используете `uv`, то вы должны будете его использовать для установки пакетов вместо `pip`, поэтому обновлять `pip` вам ненужно. 😎
+
+///
+
+Если для установки пакетов вы используете `pip` (он устанавливается по умолчанию вместе с Python), то обновите `pip` до последней версии.
+
+Большинство экзотических ошибок, возникающих при установке пакетов, устраняется предварительным обновлением `pip`.
+
+/// tip | Подсказка
+
+Обычно это делается только один раз, сразу после создания виртуальной среды разработки.
+
+///
+
+Убедитесь в том, что виртуальная среда активирована (с помощью вышеуказанной команды) и запустите следующую команду:
+
+
+
+## Добавление `.gitignore`
+
+Если вы используете **Git** (а вы должны его использовать), то добавьте файл `.gitignore` и исключите из Git всё, что находится в папке `.venv`.
+
+/// tip | Подсказка
+
+Если для создания виртуальной среды вы используете `uv`, то для вас все уже сделано и вы можете пропустить этот шаг. 😎
+
+///
+
+/// tip | Подсказка
+
+Это делается один раз, сразу после создания виртуальной среды разработки.
+
+///
+
+
+
+/// details | Что делает эта команда?
+
+* `echo "*"`: напечатать `*` в консоли (следующий шаг это слегка изменит)
+* `>`: все что находится слева от `>` не печатать в консоль, но записать в файл находящийся справа от `>`
+* `.gitignore`: имя файла, в который нужно записать текст.
+
+`*` в Git означает "всё". Т.е. будет проигнорировано всё, что содержится в папке `.venv`.
+
+Данная команда создаст файл `.gitignore` следующего содержания:
+
+```gitignore
+*
+```
+
+///
+
+## Установка пакетов
+
+После установки виртуальной среды, вы можете устанавливать в нее пакеты.
+
+/// tip | Подсказка
+
+Сделайте это **один раз**, при установке или обновлении пакетов, нужных вашему проекту.
+
+Если вам понадобится обновить версию пакета или добавить новый пакет, то вы должны будете **сделать это снова**.
+
+///
+
+### Установка пакетов напрямую
+
+Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, то вы можете установить их напрямую.
+
+/// tip | Подсказка
+
+Объявление пакетов, которые использует ваш проект, и их версий в отдельном файле (например, в `requirements.txt` или в `pyproject.toml`) - это отличная идея.
+
+///
+
+//// tab | `pip`
+
+
+
+////
+
+### Установка из `requirements.txt`
+
+Если у вас есть `requirements.txt`, то вы можете использовать его для установки пакетов.
+
+//// tab | `pip`
+
+
+
+////
+
+/// details | `requirements.txt`
+
+`requirements.txt` с парочкой пакетов внутри выглядит приблизительно так:
+
+```requirements.txt
+fastapi[standard]==0.113.0
+pydantic==2.8.0
+```
+
+///
+
+## Запуск программы
+
+После активации виртуальной среды разработки вы можете запустить свою программу и она будет использовать версию Python и пакеты, установленные в виртуальной среде.
+
+
+
+## Настройка редактора
+
+Вероятно, вы захотите воспользоваться редактором. Убедитесь, что вы настроили его на использование той самой виртуальной среды, которую вы создали. (Скорее всего, она автоматически будет обнаружена). Это позволит вам использовать авто-завершение и выделение ошибок в редакторе.
+
+Например:
+
+* VS Code
+* PyCharm
+
+/// tip | Подсказка
+
+Обычно это делается один раз, при создании виртуальной среды разработки.
+
+///
+
+## Деактивация виртуальной среды разработки
+
+По окончании работы над проектом вы можете деактивировать виртуальную среду.
+
+
+
+```console
+$ deactivate
+```
+
+
+
+Таким образом, при запуске `python`, будет использована версия `python` установленная глобально, а не из этой виртуальной среды вместе с установленными в ней пакетами.
+
+## Все готово к работе
+
+Теперь вы готовы к тому, чтобы начать работу над своим проектом.
+
+
+
+/// tip | Подсказка
+
+Хотите разобраться со всем, что написано выше?
+
+Продолжайте читать. 👇🤓
+
+///
+
+## Зачем использовать виртуальную среду?
+
+Для работы с FastAPI вам потребуется установить Python.
+
+После этого вам нужно будет **установить** FastAPI и другие **пакеты**, которые вы собираетесь использовать.
+
+Для установки пакетов обычно используют `pip`, который устанавливается вместе с Python (или же используют альтернативные решения).
+
+Тем не менее, если вы просто используете `pip` напрямую, то пакеты будут установлены в **глобальное Python-окружение** (глобально установленный Python).
+
+### Проблема
+
+Так в чем же проблема с установкой пакетов в глобальную среду Python?
+
+В какой-то момент вам, вероятно, придется писать множество разных программ, которые используют различные пакеты. 😱
+
+Например, вы создаете проект `philosophers-stone`, который зависит от пакета под названием **`harry`, версии `1`**. Таким образом, вам нужно установить `harry`.
+
+```mermaid
+flowchart LR
+ stone(philosophers-stone) -->|requires| harry-1[harry v1]
+```
+
+Затем, в какой-то момент, вы создаете другой проект под названием `prisoner-of-azkaban`, и этот проект тоже зависит от `harry`, но он уже использует **`harry` версии `3`**.
+
+```mermaid
+flowchart LR
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]
+```
+
+Проблема заключается в том, что при установке в глобальное окружение, а не в локальную виртуальную среду разработки, вам нужно будет выбирать, какую версию пакета `harry` устанавливать.
+
+Если вам нужен `philosophers-stone`, то вам нужно сначала установить `harry` версии `1`:
+
+
+
+```console
+$ pip install "harry==1"
+```
+
+
+
+И тогда в вашем глобальном окружении Python будет установлен `harry` версии `1`:
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[harry v1]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -->|requires| harry-1
+ end
+```
+
+Но если позднее вы захотите запустить `prisoner-of-azkaban`, то вам нужно будет удалить `harry` версии 1, и установить `harry` версии `3` (при установке пакета версии `3` поверх пакета версии `1`, пакет версии `1` удаляется автоматически).
+
+
+
+```console
+$ pip install "harry==3"
+```
+
+
+
+И тогда, в вашей глобальной среде окружения Python, будет установлен пакет `harry` версии `3`.
+
+И когда вы снова попытаетесь запустить `philosophers-stone`, то существует вероятность того, что он не будет работать, так как он использует `harry` версии `1`.
+
+```mermaid
+flowchart LR
+ subgraph global[global env]
+ harry-1[harry v1]
+ style harry-1 fill:#ccc,stroke-dasharray: 5 5
+ harry-3[harry v3]
+ end
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) -.-x|⛔️| harry-1
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --> |requires| harry-3
+ end
+```
+
+/// tip | Подсказка
+
+В пакетах Python очень часто стараются изо всех сил избегать внесения критических изменений в новые версии, но лучше перестраховаться и планово устанавливать новые версии, а затем запускать тесты, чтобы проверить, все ли работает правильно.
+
+///
+
+Теперь представьте, что это происходит со многими другими пакетами, которые используются в ваших проектах. С этим очень сложно справиться. И скорее всего, в конечном итоге вы будете запускать некоторые проекты с некоторыми несовместимыми зависимостями и не будете знать, почему что-то не работает.
+
+Кроме того, в зависимости от вашей операционной системы (напр. Linux, Windows, macOS), она может поставляться с уже установленным Python. Вероятно, что в этом случае в ней уже установлены системные пакеты определенных версий. Если вы устанавливаете пакеты глобально, то вы можете **поломать** программы, являющиеся частью ОС.
+
+## Куда устанавливаются пакеты?
+
+Когда вы устанавливаете Python, то на вашей машине создается некоторое количество директорий, содержащих некоторое количество файлов.
+
+Среди них есть каталоги, отвечающие за хранение всех устанавливаемых вами пакетов.
+
+Когда вы запустите команду:
+
+
+
+```console
+// Не запускайте эту команду, это просто пример 🤓
+$ pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+То будет скачан сжатый файл, содержащий код FastAPI, обычно скачивание происходит с PyPI.
+
+Также будут скачаны файлы, содержащие пакеты, которые использует FastAPI.
+
+Затем все файлы будут извлечены и помещены в директорию на вашем компьютере.
+
+По умолчанию эти файлы будут загружены и извлечены в один из каталогов установки Python, т.е. в глобальную среду.
+
+## Что такое виртуальная среда разработки?
+
+Решением проблемы размещения всех пакетов в глобальной среде будет использование отдельной виртуальной среды под каждый проект, над которым вы работаете.
+
+Виртуальная среда это обычная папка, очень похожая на глобальную, куда вы можете устанавливать пакеты для вашего проекта.
+
+Таким образом, каждый проект будет иметь свою отдельную виртуальную среду разработки (в директории `.venv`) вместе со своими пакетами.
+
+```mermaid
+flowchart TB
+ subgraph stone-project[philosophers-stone project]
+ stone(philosophers-stone) --->|requires| harry-1
+ subgraph venv1[.venv]
+ harry-1[harry v1]
+ end
+ end
+ subgraph azkaban-project[prisoner-of-azkaban project]
+ azkaban(prisoner-of-azkaban) --->|requires| harry-3
+ subgraph venv2[.venv]
+ harry-3[harry v3]
+ end
+ end
+ stone-project ~~~ azkaban-project
+```
+
+## Что означает активация виртуальной среды?
+
+Когда вы активируете виртуальную среду разработки, например, так:
+
+//// tab | Linux, macOS
+
+
+
+////
+
+
+Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для последующих команд.
+
+Одной из таких переменных является `PATH`.
+
+/// tip | Подсказка
+
+Вы можете узнать больше о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}.
+
+///
+
+При активации виртуальной среды путь `.venv/bin` (для Linux и macOS) или `.venv\Scripts` (для Windows) добавляется в переменную окружения `PATH`.
+
+Предположим, что до активации виртуальной среды переменная `PATH` выглядела так:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Это означает, что система ищет программы в следующих каталогах:
+
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Windows\System32
+```
+
+Это означает, что система ищет программы в:
+
+* `C:\Windows\System32`
+
+////
+
+После активации виртуальной среды переменная окружение `PATH` будет выглядеть примерно так:
+
+//// tab | Linux, macOS
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Это означает, что система теперь будет искать программы в:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin
+```
+
+прежде чем начать искать в других каталогах.
+
+Таким образом, когда вы введете в консоль `python`, система будет искать Python в
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+и будет использовать именно его.
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
+```
+
+Это означает, что система в первую очередь начнет искать программы в:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts
+```
+
+прежде чем начать искать в других директориях.
+
+Таким образом, если вы введете в консоль команду `python`, то система найдет Python в:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+и использует его.
+
+////
+
+Очень важной деталью является то, что путь к виртуальной среде будет помещен в самое начало переменной `PATH`. Система обнаружит данный путь к Python раньше, чем какой-либо другой. Таким образом, при запуске команды `python`, будет использован именно Python из виртуальной среды разработки, а не какой-нибудь другой (например, Python из глобальной среды)
+
+Активация виртуальной среды разработки также меняет и несколько других вещей, но данная функция является основной.
+
+## Проверка виртуальной среды
+
+Когда вы проверяете активна ли виртуальная среда разработки, например, так:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+////
+
+Это означает, что будет использоваться `python` **из виртуальной среды разработки**.
+
+Вы используете `which` для Linux и macOS и `Get-Command` для Windows PowerShell.
+
+Эта команда работает следующим образом: она проверяет переменную окружения `PATH`, проходя по очереди каждый указанный путь в поисках программы под названием `python`. И когда она её находит, то возвращает путь к данной программе.
+
+Основной момент при вызове команды `python` состоит в том, какой именно "`python`" будет запущен.
+
+Таким образом, вы можете убедиться, что используете правильную виртуальную среду разработки.
+
+/// tip | Подсказка
+
+Легко активировать одну виртуальную среду, вызвать один Python и **перейти к следующему проекту**.
+
+И следующий проект не будет работать потому, что вы используете **неправильный Python** из виртуальной среды другого проекта.
+
+Так что, будет нелишним проверить, какой `python` вы используете. 🤓
+
+///
+
+## Зачем деактивируют виртуальную среду?
+
+Предположим, что вы работаете над проектом `philosophers-stone`, **активируете виртуальную среду разработки**, устанавливаете пакеты и работаете с данной средой.
+
+И позже вам понадобилось поработать с **другим проектом** `prisoner-of-azkaban`.
+
+Вы переходите к этому проекту:
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+```
+
+
+
+Если вы не деактивировали виртуальное окружение проекта `philosophers-stone`, то при запуске `python` через консоль будет вызван Python из `philosophers-stone`
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+$ python main.py
+
+// Error importing sirius, it's not installed 😱
+Traceback (most recent call last):
+ File "main.py", line 1, in
+ import sirius
+```
+
+
+
+Но если вы деактивируете виртуальную среду разработки и активируете новую среду для `prisoner-of-askaban`, то вы тогда запустите Python из виртуального окружения `prisoner-of-azkaban`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+// Вам не требуется находится в старой директории для деактивации среды разработки, вы можете это сделать откуда угодно, даже из каталога другого проекта, в который вы перешли. 😎
+$ deactivate
+
+// Активируйте виртуальную среду разработки в prisoner-of-azkaban/.venv 🚀
+$ source .venv/bin/activate
+
+// Тепреь, когда вы запустите python, он найдет пакет sirius, установленный в виртуальной среде ✨
+$ python main.py
+
+Я торжественно клянусь в этом! 🐺
+```
+
+
+
+## Альтернативы
+
+Это простое руководство поможет вам начать работу и научит тому, как всё работает **изнутри**.
+
+Существует много альтернативных решений для работы с виртуальными средами разработки, с программными зависимостями, а также с проектами.
+
+Когда вы будете готовы использовать единый инструмент для управления проектом, программными зависимостями, виртуальными средами разработки и т.д., то я рекомендую вам попробовать uv.
+
+`uv` может очень многое. Он умеет:
+
+* **Устанавливать Python**, включая установку различных версий
+* Управлять средой виртуального окружения вашего проекта
+* Устанавливать **пакеты**
+* Управлять пакетами и их версиями внутри вашего проекта
+* Удостовериться, что вы используете **точный** набор пакетов и версий при установке, включая зависимости. Таким образом, вы можете быть уверенны, что проект, запускается в production, точно также, как и при разработке, этот механизм называется *locking*
+* Многие другие вещи
+
+## Заключение
+
+Если вы прочитали и поняли всё это, то теперь вы знаете **гораздо больше** о виртуальных средах разработки, чем многие другие разработчики. 🤓
+
+Скорее всего, знание этих деталей будет полезно вам в будущем. Когда вы будете отлаживать что-то, кажущееся сложным, вы будете знать, **как это работает под капотом**. 😎
diff --git a/docs/tr/docs/advanced/testing-websockets.md b/docs/tr/docs/advanced/testing-websockets.md
index 12b6ab60f..ddacca449 100644
--- a/docs/tr/docs/advanced/testing-websockets.md
+++ b/docs/tr/docs/advanced/testing-websockets.md
@@ -4,9 +4,7 @@ WebSockets testi yapmak için `TestClient`'ı kullanabilirsiniz.
Bu işlem için, `TestClient`'ı bir `with` ifadesinde kullanarak WebSocket'e bağlanabilirsiniz:
-```Python hl_lines="27-31"
-{!../../docs_src/app_testing/tutorial002.py!}
-```
+{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *}
/// note | Not
diff --git a/docs/tr/docs/advanced/wsgi.md b/docs/tr/docs/advanced/wsgi.md
index bc8da16df..00815a4b2 100644
--- a/docs/tr/docs/advanced/wsgi.md
+++ b/docs/tr/docs/advanced/wsgi.md
@@ -12,9 +12,7 @@ Ardından WSGI (örneğin Flask) uygulamanızı middleware ile sarmalayın.
Son olarak da bir yol altında bağlama işlemini gerçekleştirin.
-```Python hl_lines="2-3 23"
-{!../../docs_src/wsgi/tutorial001.py!}
-```
+{* ../../docs_src/wsgi/tutorial001.py hl[2:3,23] *}
## Kontrol Edelim
diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md
index 7ecaf1ba3..f666e2d06 100644
--- a/docs/tr/docs/index.md
+++ b/docs/tr/docs/index.md
@@ -12,7 +12,7 @@
+
+Програма командного рядка `fastapi` це **FastAPI CLI**.
+
+FastAPI CLI приймає шлях до Вашої Python програми (напр. `main.py`) і автоматично виявляє екземпляр `FastAPI` (зазвичай названий `app`), обирає коректний процес імпорту, а потім обслуговує його.
+
+Натомість, для запуску у продакшн використовуйте `fastapi run`. 🚀
+
+Всередині **FastAPI CLI** використовує Uvicorn, високопродуктивний, production-ready, ASGI cервер. 😎
+
+## `fastapi dev`
+
+Використання `fastapi dev` ініціює режим розробки.
+
+За замовчуванням, **автоматичне перезавантаження** увімкнене, автоматично перезавантажуючи сервер кожного разу, коли Ви змінюєте Ваш код. Це ресурсо-затратно, та може бути менш стабільним, ніж коли воно вимкнене. Ви повинні використовувати його тільки під час розробки. Воно також слухає IP-адресу `127.0.0.1`, що є IP Вашого девайсу для самостійної комунікації з самим собою (`localhost`).
+
+## `fastapi run`
+
+Виконання `fastapi run` запустить FastAPI у продакшн-режимі за замовчуванням.
+
+За замовчуванням, **автоматичне перезавантаження** вимкнене. Воно також прослуховує IP-адресу `0.0.0.0`, що означає всі доступні IP адреси, тим самим даючи змогу будь-кому комунікувати з девайсом. Так Ви зазвичай будете запускати його у продакшн, наприклад у контейнері.
+
+В більшості випадків Ви можете (і маєте) мати "termination proxy", який обробляє HTTPS для Вас, це залежить від способу розгортання вашого додатку, Ваш провайдер може зробити це для Вас, або Вам потрібно налаштувати його самостійно.
+
+/// tip
+
+Ви можете дізнатись більше про це у [документації про розгортування](deployment/index.md){.internal-link target=_blank}.
+
+///
diff --git a/docs/uk/docs/features.md b/docs/uk/docs/features.md
new file mode 100644
index 000000000..7d679d8ee
--- /dev/null
+++ b/docs/uk/docs/features.md
@@ -0,0 +1,189 @@
+# Функціональні можливості
+
+## Функціональні можливості FastAPI
+
+**FastAPI** надає вам такі можливості:
+
+### Використання відкритих стандартів
+
+* OpenAPI для створення API, включаючи оголошення шляхів, операцій, параметрів, тіл запитів, безпеки тощо.
+* Автоматична документація моделей даних за допомогою JSON Schema (оскільки OpenAPI базується саме на JSON Schema).
+* Розроблено на основі цих стандартів після ретельного аналізу, а не як додатковий рівень поверх основної архітектури.
+* Це також дає змогу автоматично **генерувати код клієнта** багатьма мовами.
+
+### Автоматична генерація документації
+
+Інтерактивна документація API та вебінтерфейс для його дослідження. Оскільки фреймворк базується на OpenAPI, є кілька варіантів, два з яких включені за замовчуванням.
+
+* Swagger UI — дозволяє інтерактивно переглядати API, викликати та тестувати його прямо у браузері.
+
+
+
+* Альтернативна документація API за допомогою ReDoc.
+
+
+
+### Тільки сучасний Python
+
+FastAPI використовує стандартні **типи Python** (завдяки Pydantic). Вам не потрібно вивчати новий синтаксис — лише стандартний сучасний Python.
+
+Якщо вам потрібне коротке нагадування про використання типів у Python (навіть якщо ви не використовуєте FastAPI), перегляньте короткий підручник: [Вступ до типів Python](python-types.md){.internal-link target=_blank}.
+
+Ось приклад стандартного Python-коду з типами:
+
+```Python
+from datetime import date
+from pydantic import BaseModel
+
+# Оголошення змінної як str
+# з підтримкою автодоповнення у редакторі
+def main(user_id: str):
+ return user_id
+
+# Модель Pydantic
+class User(BaseModel):
+ id: int
+ name: str
+ joined: date
+```
+
+Приклад використання цієї моделі:
+
+```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` означає:
+
+Передати ключі та значення словника `second_user_data` як аргументи у вигляді "ключ-значення", еквівалентно `User(id=4, name="Mary", joined="2018-11-30")`.
+
+///
+
+### Підтримка редакторів (IDE)
+
+Фреймворк спроєктований так, щоб бути легким і інтуїтивно зрозумілим. Усі рішення тестувалися у різних редакторах ще до початку розробки, щоб забезпечити найкращий досвід програмування.
+
+За результатами опитувань розробників Python однією з найпопулярніших функцій є "автодоповнення".
+
+**FastAPI** повністю підтримує автодоповнення у всіх місцях, тому вам рідко доведеться повертатися до документації.
+
+Приклад автодоповнення у редакторах:
+
+* у Visual Studio Code:
+
+
+
+* у PyCharm:
+
+
+
+### Короткий код
+FastAPI має розумні налаштування **за замовчуванням**, але всі параметри можна налаштовувати відповідно до ваших потреб. Однак за замовчуванням все "просто працює".
+
+### Валідація
+* Підтримка валідації для більшості (або всіх?) **типів даних Python**, зокрема:
+ * JSON-об'єктів (`dict`).
+ * JSON-списків (`list`) з визначенням типів елементів.
+ * Рядків (`str`) із мінімальною та максимальною довжиною.
+ * Чисел (`int`, `float`) з обмеженнями мінімальних та максимальних значень тощо.
+
+* Валідація складніших типів, таких як:
+ * URL.
+ * Email.
+ * UUID.
+ * ...та інші.
+
+Уся валідація виконується через надійний та перевірений **Pydantic**.
+
+### Безпека та автентифікація
+
+**FastAPI** підтримує вбудовану автентифікацію та авторизацію, без прив’язки до конкретних баз даних чи моделей даних.
+
+Підтримуються всі схеми безпеки OpenAPI, включаючи:
+
+* HTTP Basic.
+* **OAuth2** (також із підтримкою **JWT-токенів**). Див. підручник: [OAuth2 із JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
+* Ключі API в:
+ * Заголовках.
+ * Параметрах запиту.
+ * Cookies тощо.
+
+А також усі можливості безпеки від Starlette (зокрема **сесійні cookies**).
+
+Усі вони створені як багаторазові інструменти та компоненти, які легко інтегруються з вашими системами, сховищами даних, реляційними та NoSQL базами даних тощо.
+
+### Впровадження залежностей
+
+**FastAPI** містить надзвичайно просту у використанні, але потужну систему впровадження залежностей.
+
+* Залежності можуть мати власні залежності, утворюючи ієрархію або **"граф залежностей"**.
+* Усі залежності автоматично керуються фреймворком.
+* Усі залежності можуть отримувати дані з запитів і розширювати **обмеження операції за шляхом** та автоматичну документацію.
+* **Автоматична валідація** навіть для параметрів *операцій шляху*, визначених у залежностях.
+* Підтримка складних систем автентифікації користувачів, **з'єднань із базами даних** тощо.
+* **Жодних обмежень** щодо використання баз даних, фронтендів тощо, але водночас проста інтеграція з усіма ними.
+
+### Немає обмежень на "плагіни"
+
+Або іншими словами, вони не потрібні – просто імпортуйте та використовуйте необхідний код.
+
+Будь-яка інтеграція спроєктована настільки просто (з використанням залежностей), що ви можете створити "плагін" для свого застосунку всього у 2 рядках коду, використовуючи ту саму структуру та синтаксис, що й для ваших *операцій шляху*.
+
+### Протестовано
+
+* 100% покриття тестами.
+* 100% анотована типами кодова база.
+* Використовується у робочих середовищах.
+
+## Можливості Starlette
+
+**FastAPI** повністю сумісний із (та побудований на основі) Starlette. Тому будь-який додатковий код Starlette, який ви маєте, також працюватиме.
+
+**FastAPI** фактично є підкласом **Starlette**. Тому, якщо ви вже знайомі зі Starlette або використовуєте його, більшість функціональності працюватиме так само.
+
+З **FastAPI** ви отримуєте всі можливості **Starlette** (адже FastAPI — це, по суті, Starlette на стероїдах):
+
+* Разюча продуктивність. Це один із найшвидших фреймворків на Python, на рівні з **NodeJS** і **Go**.
+* Підтримка **WebSocket**.
+* Фонові задачі у процесі.
+* Події запуску та завершення роботи.
+* Клієнт для тестування, побудований на HTTPX.
+* Підтримка **CORS**, **GZip**, статичних файлів, потокових відповідей.
+* Підтримка **сесій** і **cookie**.
+* 100% покриття тестами.
+* 100% анотована типами кодова база.
+
+## Можливості Pydantic
+
+**FastAPI** повністю сумісний із (та побудований на основі) Pydantic. Тому будь-який додатковий код Pydantic, який ви маєте, також працюватиме.
+
+Включаючи зовнішні бібліотеки, побудовані також на Pydantic, такі як ORM, ODM для баз даних.
+
+Це також означає, що в багатьох випадках ви можете передати той самий об'єкт, який отримуєте з запиту, **безпосередньо в базу даних**, оскільки все автоматично перевіряється.
+
+Те ж саме відбувається й у зворотному напрямку — у багатьох випадках ви можете просто передати об'єкт, який отримуєте з бази даних, **безпосередньо клієнту**.
+
+З **FastAPI** ви отримуєте всі можливості **Pydantic** (адже FastAPI базується на Pydantic для обробки всіх даних):
+
+* **Ніякої плутанини** :
+ * Не потрібно вчити нову мову для визначення схем.
+ * Якщо ви знаєте типи Python, ви знаєте, як використовувати Pydantic.
+* Легко працює з вашим **IDE/лінтером/мозком**:
+ * Оскільки структури даних Pydantic є просто екземплярами класів, які ви визначаєте; автодоповнення, лінтинг, mypy і ваша інтуїція повинні добре працювати з вашими перевіреними даними.
+* Валідація **складних структур**:
+ * Використання ієрархічних моделей Pydantic. Python `typing`, `List` і `Dict` тощо.
+ * Валідатори дозволяють чітко і просто визначати, перевіряти й документувати складні схеми даних у вигляді JSON-схеми.
+ * Ви можете мати глибоко **вкладені JSON об'єкти** та перевірити та анотувати їх всі.
+* **Розширюваність**:
+ * Pydantic дозволяє визначати користувацькі типи даних або розширювати валідацію методами в моделі декоратором `validator`.
+* 100% покриття тестами.
diff --git a/docs/uk/docs/index.md b/docs/uk/docs/index.md
index 012bac2e2..b573ee259 100644
--- a/docs/uk/docs/index.md
+++ b/docs/uk/docs/index.md
@@ -6,7 +6,7 @@
-
+
diff --git a/docs/uk/docs/learn/index.md b/docs/uk/docs/learn/index.md
new file mode 100644
index 000000000..7f9f21e57
--- /dev/null
+++ b/docs/uk/docs/learn/index.md
@@ -0,0 +1,5 @@
+# Навчання
+
+У цьому розділі надані вступні та навчальні матеріали для вивчення FastAPI.
+
+Це можна розглядати як **книгу**, **курс**, або **офіційний** та рекомендований спосіб освоїти FastAPI. 😎
diff --git a/docs/uk/docs/python-types.md b/docs/uk/docs/python-types.md
index 573b5372c..676bafb15 100644
--- a/docs/uk/docs/python-types.md
+++ b/docs/uk/docs/python-types.md
@@ -22,9 +22,8 @@ Python підтримує додаткові "підказки типу" ("type
Давайте почнемо з простого прикладу:
-```Python
-{!../../docs_src/python_types/tutorial001.py!}
-```
+{* ../../docs_src/python_types/tutorial001.py *}
+
Виклик цієї програми виводить:
@@ -38,9 +37,8 @@ John Doe
* Конвертує кожну літеру кожного слова у верхній регістр за допомогою `title()`.
* Конкатенує їх разом із пробілом по середині.
-```Python hl_lines="2"
-{!../../docs_src/python_types/tutorial001.py!}
-```
+{* ../../docs_src/python_types/tutorial001.py hl[2] *}
+
### Редагуйте це
@@ -82,9 +80,8 @@ John Doe
Це "type hints":
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial002.py!}
-```
+{* ../../docs_src/python_types/tutorial002.py hl[1] *}
+
Це не те саме, що оголошення значень за замовчуванням, як це було б з:
@@ -112,9 +109,8 @@ John Doe
Перевірте цю функцію, вона вже має анотацію типу:
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial003.py!}
-```
+{* ../../docs_src/python_types/tutorial003.py hl[1] *}
+
Оскільки редактор знає типи змінних, ви не тільки отримаєте автозаповнення, ви також отримаєте перевірку помилок:
@@ -122,9 +118,8 @@ John Doe
Тепер ви знаєте, щоб виправити це, вам потрібно перетворити `age` у строку з допомогою `str(age)`:
-```Python hl_lines="2"
-{!../../docs_src/python_types/tutorial004.py!}
-```
+{* ../../docs_src/python_types/tutorial004.py hl[2] *}
+
## Оголошення типів
@@ -143,9 +138,8 @@ John Doe
* `bool`
* `bytes`
-```Python hl_lines="1"
-{!../../docs_src/python_types/tutorial005.py!}
-```
+{* ../../docs_src/python_types/tutorial005.py hl[1] *}
+
### Generic-типи з параметрами типів
@@ -406,15 +400,13 @@ John Doe
Скажімо, у вас є клас `Person` з імʼям:
-```Python hl_lines="1-3"
-{!../../docs_src/python_types/tutorial010.py!}
-```
+{* ../../docs_src/python_types/tutorial010.py hl[1:3] *}
+
Потім ви можете оголосити змінну типу `Person`:
-```Python hl_lines="6"
-{!../../docs_src/python_types/tutorial010.py!}
-```
+{* ../../docs_src/python_types/tutorial010.py hl[6] *}
+
І знову ж таки, ви отримуєте всю підтримку редактора:
diff --git a/docs/uk/docs/tutorial/background-tasks.md b/docs/uk/docs/tutorial/background-tasks.md
new file mode 100644
index 000000000..912ba8c2a
--- /dev/null
+++ b/docs/uk/docs/tutorial/background-tasks.md
@@ -0,0 +1,85 @@
+# Фонові задачі
+
+Ви можете створювати фонові задачі, які будуть виконуватися *після* повернення відповіді.
+
+Це корисно для операцій, які потрібно виконати після обробки запиту, але клієнту не обов’язково чекати завершення цієї операції перед отриманням відповіді.
+
+Приклади використання:
+
+* Надсилання email-сповіщень після виконання певної дії:
+ * Підключення до поштового сервера та надсилання листа може займати кілька секунд. Ви можете відразу повернути відповідь, а email відправити у фоні.
+* Обробка даних:
+ * Наприклад, якщо отримано файл, який потрібно обробити довготривалим процесом, можна повернути відповідь "Accepted" ("Прийнято", HTTP 202) і виконати обробку файлу у фоні.
+
+## Використання `BackgroundTasks`
+
+Спочатку імпортуйте `BackgroundTasks` і додайте його як параметр у Вашу *функцію операції шляху* (path operation function) до `BackgroundTasks`:
+
+{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *}
+
+**FastAPI** автоматично створить об'єкт `BackgroundTasks` і передасть його у цей параметр.
+
+
+## Створення функції задачі
+
+Створіть функцію, яка буде виконувати фонову задачу.
+
+Це звичайна функція, яка може отримувати параметри.
+
+Вона може бути асинхронною `async def` або звичайною `def` функцією – **FastAPI** обробить її правильно.
+
+У нашому випадку функція записує у файл (імітуючи надсилання email).
+
+І оскільки операція запису не використовує `async` та `await`, ми визначаємо функцію як звичайну `def`:
+
+{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *}
+
+## Додавання фонової задачі
+
+Усередині Вашої *функції обробки шляху*, передайте функцію задачі в об'єкт *background tasks*, використовуючи метод `.add_task()`:
+
+{* ../../docs_src/background_tasks/tutorial001.py hl[14] *}
+
+`.add_task()` приймає аргументи:
+
+* Функція задача, яка буде виконуватися у фоновому режимі (`write_notification`). Зверніть увагу, що передається обʼєкт без дужок.
+* Будь-яка послідовність аргументів, які потрібно передати у функцію завдання у відповідному порядку (`email`).
+* Будь-які іменовані аргументи, які потрібно передати у функцію задачу (`message="some notification"`).
+
+## Впровадження залежностей
+
+Використання `BackgroundTasks` також працює з системою впровадження залежностей. Ви можете оголосити параметр типу `BackgroundTasks` на різних рівнях: у *функції операції шляху*, у залежності (dependable), у під залежності тощо.
+
+**FastAPI** знає, як діяти в кожному випадку і як повторно використовувати один і той самий об'єкт, щоб усі фонові задачі були об’єднані та виконувалися у фоновому режимі після завершення основного запиту.
+
+{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
+
+У цьому прикладі повідомлення будуть записані у файл `log.txt` *після* того, як відповідь буде надіслана.
+
+Якщо у запиті був переданий query-параметр, він буде записаний у лог у фоновій задачі.
+
+А потім інша фонова задача, яка створюється у *функції операції шляху*, запише повідомлення з використанням path параметра `email`.
+
+## Технічні деталі
+
+Клас `BackgroundTasks` походить безпосередньо з `starlette.background`.
+
+Він імпортується безпосередньо у FastAPI, щоб Ви могли використовувати його з `fastapi` і випадково не імпортували `BackgroundTask` (без s в кінці) з `starlette.background`.
+
+Якщо використовувати лише `BackgroundTasks` (а не `BackgroundTask`), то його можна передавати як параметр у *функції операції шляху*, і **FastAPI** подбає про все інше, так само як і про використання об'єкта `Request`.
+
+Також можна використовувати `BackgroundTask` окремо в FastAPI, але для цього Вам доведеться створити об'єкт у коді та повернути Starlette `Response`, включаючи його.
+
+Детальніше можна почитати в офіційній документації Starlette про фонові задачі .
+
+## Застереження
+
+Якщо Вам потрібно виконувати складні фонові обчислення, і при цьому нема потреби запускати їх у тому ж процесі (наприклад, не потрібно спільного доступу до пам’яті чи змінних), можливо, варто скористатися більш потужними інструментами, такими як Celery.
+
+Такі інструменти зазвичай потребують складнішої конфігурації та менеджера черги повідомлень/завдань, наприклад, RabbitMQ або Redis. Однак вони дозволяють виконувати фонові задачі в кількох процесах і навіть на кількох серверах.
+
+Якщо ж Вам потрібно отримати доступ до змінних і об’єктів із тієї ж **FastAPI** - програми або виконувати невеликі фонові завдання (наприклад, надсилати сповіщення електронною поштою), достатньо просто використовувати `BackgroundTasks`.
+
+## Підсумок
+
+Імпортуйте та використовуйте `BackgroundTasks` як параметр у *функціях операції шляху* та залежностях, щоб додавати фонові задачі.
diff --git a/docs/uk/docs/tutorial/body-fields.md b/docs/uk/docs/tutorial/body-fields.md
index c286744a8..7ddd9d104 100644
--- a/docs/uk/docs/tutorial/body-fields.md
+++ b/docs/uk/docs/tutorial/body-fields.md
@@ -6,57 +6,7 @@
Спочатку вам потрібно імпортувати це:
-//// tab | Python 3.10+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Варто користуватись `Annotated` версією, якщо це можливо.
-
-///
-
-```Python hl_lines="2"
-{!> ../../docs_src/body_fields/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Варто користуватись `Annotated` версією, якщо це можливо.
-
-///
-
-```Python hl_lines="4"
-{!> ../../docs_src/body_fields/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}
/// warning
@@ -68,57 +18,7 @@
Ви можете використовувати `Field` з атрибутами моделі:
-//// tab | Python 3.10+
-
-```Python hl_lines="11-14"
-{!> ../../docs_src/body_fields/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="11-14"
-{!> ../../docs_src/body_fields/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="12-15"
-{!> ../../docs_src/body_fields/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Варто користуватись `Annotated` версією, якщо це можливо..
-
-///
-
-```Python hl_lines="9-12"
-{!> ../../docs_src/body_fields/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Варто користуватись `Annotated` версією, якщо це можливо..
-
-///
-
-```Python hl_lines="11-14"
-{!> ../../docs_src/body_fields/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}
`Field` працює так само, як `Query`, `Path` і `Body`, у нього такі самі параметри тощо.
diff --git a/docs/uk/docs/tutorial/body-multiple-params.md b/docs/uk/docs/tutorial/body-multiple-params.md
new file mode 100644
index 000000000..e2acf8a70
--- /dev/null
+++ b/docs/uk/docs/tutorial/body-multiple-params.md
@@ -0,0 +1,170 @@
+# Тіло запиту - Декілька параметрів
+
+Тепер, коли ми розглянули використання `Path` та `Query`, розгляньмо більш просунуті способи оголошення тіла запиту в **FastAPI**.
+
+## Змішування `Path`, `Query` та параметрів тіла запиту
+
+По-перше, звісно, Ви можете вільно змішувати оголошення параметрів `Path`, `Query` та тіла запиту, і **FastAPI** правильно їх обробить.
+
+Також Ви можете оголосити параметри тіла як необов’язкові, встановивши для них значення за замовчуванням `None`:
+
+{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
+
+/// note | Примітка
+
+Зверніть увагу, що в цьому випадку параметр `item`, який береться з тіла запиту, є необов'язковим, оскільки має значення за замовчуванням `None`.
+
+///
+
+## Декілька параметрів тіла запиту
+
+У попередньому прикладі *операція шляху* очікувала JSON з атрибутами `Item`, наприклад:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+Але Ви також можете оголосити декілька параметрів тіла, наприклад `item` та `user`:
+
+{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
+
+У цьому випадку **FastAPI** розпізнає, що є кілька параметрів тіла (два параметри є моделями Pydantic).
+
+Тому він використає назви параметрів як ключі (назви полів) у тілі запиту, очікуючи:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ }
+}
+```
+
+/// note | Примітка
+
+Зверніть увагу, що хоча `item` оголошено, так само як і раніше, тепер він очікується в тілі під ключем `item`.
+
+///
+
+**FastAPI** автоматично конвертує дані із запиту таким чином, щоб параметр `item` отримав свій вміст, і те ж саме стосується `user`.
+
+Він виконає валідацію складених даних і задокументує їх відповідним чином у схемі OpenAPI та в автоматичній документації.
+
+## Одиничні значення в тілі запиту
+
+Так само як є `Query` і `Path` для визначення додаткових даних для параметрів запиту та шляху, **FastAPI** надає еквівалентний `Body`.
+
+Наприклад, розширюючи попередню модель, Ви можете вирішити додати ще один ключ `importance` в те ж саме тіло запиту разом із `item` і `user`.
+
+Якщо Ви оголосите його як є, то, оскільки це одиничне значення, **FastAPI** припускатиме, що це параметр запиту (query parameter).
+
+Але Ви можете вказати **FastAPI** обробляти його як інший ключ тіла (body key), використовуючи `Body`:
+
+{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
+
+У цьому випадку **FastAPI** очікуватиме тіло запиту у такому вигляді:
+
+```JSON
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ },
+ "user": {
+ "username": "dave",
+ "full_name": "Dave Grohl"
+ },
+ "importance": 5
+}
+```
+Знову ж таки, **FastAPI** конвертуватиме типи даних, перевірятиме їх, створюватиме документацію тощо.
+
+## Декілька body та query параметрів
+
+Звісно, Ви можете оголошувати додаткові query параметри запиту, коли це необхідно, на додаток до будь-яких параметрів тіла запиту.
+
+Оскільки за замовчуванням окремі значення інтерпретуються як параметри запиту, Вам не потрібно явно додавати `Query`, можна просто використати:
+
+```Python
+q: Union[str, None] = None
+```
+
+Або в Python 3.10 та вище:
+
+```Python
+q: str | None = None
+```
+
+Наприклад:
+
+{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
+
+
+/// info | Інформація
+
+`Body` також має ті самі додаткові параметри валідації та метаданих, що й `Query`, `Path` та інші, які Ви побачите пізніше.
+
+///
+
+## Вкладений поодинокий параметр тіла запиту
+
+Припустимо, у вас є лише один параметр тіла запиту `item` з моделі Pydantic `Item`.
+
+За замовчуванням **FastAPI** очікуватиме, що тіло запиту міститиме вміст безпосередньо.
+
+Але якщо Ви хочете, щоб він очікував JSON з ключем `item`, а всередині — вміст моделі (так, як це відбувається при оголошенні додаткових параметрів тіла), Ви можете використати спеціальний параметр `Body` — `embed`:
+
+```Python
+item: Item = Body(embed=True)
+```
+
+як у прикладі:
+
+{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
+
+У цьому випадку **FastAPI** очікуватиме тіло запиту такого вигляду:
+
+```JSON hl_lines="2"
+{
+ "item": {
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+ }
+}
+```
+
+замість:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2
+}
+```
+
+## Підсумок
+
+Ви можете додавати кілька параметрів тіла до Вашої *функції операції шляху* (*path operation function*), навіть якщо запит може мати лише одне тіло.
+
+Але **FastAPI** обробить це, надасть Вам потрібні дані у функції, перевірить їх та задокументує коректну схему в *операції шляху*.
+
+Також Ви можете оголошувати окремі значення, які будуть отримані як частина тіла запиту.
+
+Крім того, Ви можете вказати **FastAPI** вбудовувати тіло в ключ, навіть якщо оголошено лише один параметр.
diff --git a/docs/uk/docs/tutorial/body-nested-models.md b/docs/uk/docs/tutorial/body-nested-models.md
new file mode 100644
index 000000000..abc33f2eb
--- /dev/null
+++ b/docs/uk/docs/tutorial/body-nested-models.md
@@ -0,0 +1,245 @@
+# Тіло запиту - Вкладені моделі
+
+З **FastAPI** Ви можете визначати, перевіряти, документувати та використовувати моделі, які можуть бути вкладені на будь-яку глибину (завдяки Pydantic).
+
+## Поля списку
+
+Ви можете визначити атрибут як підтип. Наприклад, Python-список (`list`):
+
+{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}
+
+Це зробить `tags` списком, хоча не визначається тип елементів списку.
+
+## Поля списку з параметром типу
+
+Але Python має специфічний спосіб оголошення списків з внутрішніми типами або "параметрами типу":
+### Імпортуємо `List` з модуля typing
+
+У Python 3.9 і вище можна використовувати стандартний `list` для оголошення таких типів, як ми побачимо нижче. 💡
+
+Але в Python версії до 3.9 (від 3.6 і вище) спочатку потрібно імпортувати `List` з модуля стандартної бібліотеки Python `typing`:
+
+{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *}
+
+### Оголошення `list` з параметром типу
+
+Щоб оголосити типи з параметрами типу (внутрішніми типами), такими як `list`, `dict`, `tuple`:
+
+* Якщо Ви використовуєте версію Python до 3.9, імпортуйте їх відповідну версію з модуля `typing`.
+* Передайте внутрішні типи як "параметри типу", використовуючи квадратні дужки: `[` and `]`.
+
+У Python 3.9 це буде виглядати так:
+
+```Python
+my_list: list[str]
+```
+
+У версіях Python до 3.9 це виглядає так:
+
+```Python
+from typing import List
+
+my_list: List[str]
+```
+
+Це стандартний синтаксис Python для оголошення типів.
+
+Використовуйте той самий стандартний синтаксис для атрибутів моделей з внутрішніми типами.
+
+Отже, у нашому прикладі, ми можемо зробити `tags` саме "списком рядків":
+
+{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}
+
+## Типи множин
+
+Але потім ми подумали, що теги не повинні повторюватися, вони, ймовірно, повинні бути унікальними рядками.
+
+І Python має спеціальний тип даних для множин унікальних елементів — це `set`.
+
+Тому ми можемо оголосити `tags` як множину рядків:
+
+{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}
+
+Навіть якщо Ви отримаєте запит з дубльованими даними, він буде перетворений у множину унікальних елементів.
+
+І коли Ви будете виводити ці дані, навіть якщо джерело містить дублікати, вони будуть виведені як множина унікальних елементів.
+
+І це буде анотовано/документовано відповідно.
+
+## Вкладені моделі
+
+Кожен атрибут моделі Pydantic має тип.
+
+Але цей тип сам може бути іншою моделлю Pydantic.
+
+Отже, Ви можете оголосити глибоко вкладені JSON "об'єкти" з конкретними іменами атрибутів, типами та перевірками.
+
+Усе це, вкладене без обмежень.
+
+### Визначення підмоделі
+
+Наприклад, ми можемо визначити модель `Image`:
+
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}
+
+### Використання підмоделі як типу
+
+А потім ми можемо використовувати її як тип атрибута:
+
+{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}
+
+Це означатиме, що **FastAPI** очікуватиме тіло запиту такого вигляду:
+
+```JSON
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": ["rock", "metal", "bar"],
+ "image": {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ }
+}
+```
+
+Завдяки такій декларації у **FastAPI** Ви отримуєте:
+
+* Підтримку в редакторі (автозавершення тощо), навіть для вкладених моделей
+* Конвертацію даних
+* Валідацію даних
+* Автоматичну документацію
+
+## Спеціальні типи та валідація
+
+Окрім звичайних типів, таких як `str`, `int`, `float`, та ін. Ви можете використовувати складніші типи, які наслідують `str`.
+
+Щоб побачити всі доступні варіанти, ознайомтеся з оглядом типів у Pydantic. Деякі приклади будуть у наступних розділах.
+
+Наприклад, у моделі `Image` є поле `url`, тому ми можемо оголосити його як `HttpUrl` від Pydantic замість `str`:
+
+{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}
+
+Рядок буде перевірено як дійсну URL-адресу і задокументовано в JSON Schema / OpenAPI як URL.
+
+## Атрибути зі списками підмоделей
+
+У Pydantic Ви можете використовувати моделі як підтипи для `list`, `set` тощо:
+
+{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}
+
+Це означає, що **FastAPI** буде очікувати (конвертувати, валідувати, документувати тощо) JSON тіло запиту у вигляді:
+
+```JSON hl_lines="11"
+{
+ "name": "Foo",
+ "description": "The pretender",
+ "price": 42.0,
+ "tax": 3.2,
+ "tags": [
+ "rock",
+ "metal",
+ "bar"
+ ],
+ "images": [
+ {
+ "url": "http://example.com/baz.jpg",
+ "name": "The Foo live"
+ },
+ {
+ "url": "http://example.com/dave.jpg",
+ "name": "The Baz"
+ }
+ ]
+}
+```
+
+/// info | Інформація
+
+Зверніть увагу, що тепер ключ `images` містить список об'єктів зображень.
+
+///
+
+## Глибоко вкладені моделі
+
+Ви можете визначати вкладені моделі довільної глибини:
+
+{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}
+
+/// info | Інформація
+
+Зверніть увагу, що в моделі `Offer` є список `Item`ів, які, своєю чергою, можуть мати необов'язковий список `Image`ів.
+
+///
+
+## Тіла запитів, що складаються зі списків
+
+Якщо верхній рівень JSON тіла, яке Ви очікуєте, є JSON `масивом` (у Python — `list`), Ви можете оголосити тип у параметрі функції, як і в моделях Pydantic:
+
+```Python
+images: List[Image]
+```
+або в Python 3.9 і вище:
+
+```Python
+images: list[Image]
+```
+
+наприклад:
+
+{* ../../docs_src/body_nested_models/tutorial008_py39.py hl[13] *}
+
+## Підтримка в редакторі всюди
+
+Ви отримаєте підтримку в редакторі всюди.
+
+Навіть для елементів у списках:
+
+
+
+Ви не змогли б отримати таку підтримку в редакторі, якби працювали напряму зі `dict`, а не з моделями Pydantic.
+
+Але Вам не потрібно турбуватися про це: вхідні dict'и автоматично конвертуються, а вихідні дані автоматично перетворюються в JSON.
+
+## Тіла з довільними `dict`
+
+Ви також можете оголосити тіло як `dict` з ключами одного типу та значеннями іншого типу.
+
+Це корисно, якщо Ви не знаєте наперед, які імена полів будуть дійсними (як у випадку з моделями Pydantic).
+
+Це буде корисно, якщо Ви хочете приймати ключі, які заздалегідь невідомі.
+
+---
+
+Це також зручно, якщо Ви хочете мати ключі іншого типу (наприклад, `int`).
+
+Ось що ми розглянемо далі.
+
+У цьому випадку Ви можете приймати будь-який `dict`, якщо його ключі — це `int`, а значення — `float`:
+
+{* ../../docs_src/body_nested_models/tutorial009_py39.py hl[7] *}
+
+/// tip | Порада
+
+Майте на увазі, що в JSON тілі ключі можуть бути лише рядками (`str`).
+
+Але Pydantic автоматично конвертує дані.
+
+Це означає, що навіть якщо клієнти вашого API надсилатимуть ключі у вигляді рядків, якщо вони містять цілі числа, Pydantic конвертує їх і проведе валідацію.
+
+Тобто `dict`, який Ви отримаєте як `weights`, матиме ключі типу `int` та значення типу `float`.
+
+///
+
+## Підсумок
+
+З **FastAPI** Ви маєте максимальну гнучкість завдяки моделям Pydantic, зберігаючи при цьому код простим, коротким та елегантним.
+
+А також отримуєте всі переваги:
+
+* Підтримка в редакторі (автодоповнення всюди!)
+* Конвертація даних (парсинг/сериалізація)
+* Валідація даних
+* Документація схем
+* Автоматичне створення документації
diff --git a/docs/uk/docs/tutorial/body.md b/docs/uk/docs/tutorial/body.md
index 1e4188831..38fed7bb8 100644
--- a/docs/uk/docs/tutorial/body.md
+++ b/docs/uk/docs/tutorial/body.md
@@ -22,21 +22,7 @@
Спочатку вам потрібно імпортувати `BaseModel` з `pydantic`:
-//// tab | Python 3.8 і вище
-
-```Python hl_lines="4"
-{!> ../../docs_src/body/tutorial001.py!}
-```
-
-////
-
-//// tab | Python 3.10 і вище
-
-```Python hl_lines="2"
-{!> ../../docs_src/body/tutorial001_py310.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial001.py hl[4] *}
## Створіть свою модель даних
@@ -44,21 +30,7 @@
Використовуйте стандартні типи Python для всіх атрибутів:
-//// tab | Python 3.8 і вище
-
-```Python hl_lines="7-11"
-{!> ../../docs_src/body/tutorial001.py!}
-```
-
-////
-
-//// tab | Python 3.10 і вище
-
-```Python hl_lines="5-9"
-{!> ../../docs_src/body/tutorial001_py310.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial001.py hl[7:11] *}
Так само, як і при оголошенні параметрів запиту, коли атрибут моделі має значення за замовчуванням, він не є обов’язковим. В іншому випадку це потрібно. Використовуйте `None`, щоб зробити його необов'язковим.
@@ -86,21 +58,7 @@
Щоб додати модель даних до вашої *операції шляху*, оголосіть її так само, як ви оголосили параметри шляху та запиту:
-//// tab | Python 3.8 і вище
-
-```Python hl_lines="18"
-{!> ../../docs_src/body/tutorial001.py!}
-```
-
-////
-
-//// tab | Python 3.10 і вище
-
-```Python hl_lines="16"
-{!> ../../docs_src/body/tutorial001_py310.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial001.py hl[18] *}
...і вкажіть її тип як модель, яку ви створили, `Item`.
@@ -167,21 +125,7 @@
Усередині функції ви можете отримати прямий доступ до всіх атрибутів об’єкта моделі:
-//// tab | Python 3.8 і вище
-
-```Python hl_lines="21"
-{!> ../../docs_src/body/tutorial002.py!}
-```
-
-////
-
-//// tab | Python 3.10 і вище
-
-```Python hl_lines="19"
-{!> ../../docs_src/body/tutorial002_py310.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial002.py hl[21] *}
## Тіло запиту + параметри шляху
@@ -189,21 +133,7 @@
**FastAPI** розпізнає, що параметри функції, які відповідають параметрам шляху, мають бути **взяті з шляху**, а параметри функції, які оголошуються як моделі Pydantic, **взяті з тіла запиту**.
-//// tab | Python 3.8 і вище
-
-```Python hl_lines="17-18"
-{!> ../../docs_src/body/tutorial003.py!}
-```
-
-////
-
-//// tab | Python 3.10 і вище
-
-```Python hl_lines="15-16"
-{!> ../../docs_src/body/tutorial003_py310.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial003.py hl[17:18] *}
## Тіло запиту + шлях + параметри запиту
@@ -211,21 +141,7 @@
**FastAPI** розпізнає кожен з них і візьме дані з потрібного місця.
-//// tab | Python 3.8 і вище
-
-```Python hl_lines="18"
-{!> ../../docs_src/body/tutorial004.py!}
-```
-
-////
-
-//// tab | Python 3.10 і вище
-
-```Python hl_lines="16"
-{!> ../../docs_src/body/tutorial004_py310.py!}
-```
-
-////
+{* ../../docs_src/body/tutorial004.py hl[18] *}
Параметри функції будуть розпізнаватися наступним чином:
diff --git a/docs/uk/docs/tutorial/cookie-param-models.md b/docs/uk/docs/tutorial/cookie-param-models.md
new file mode 100644
index 000000000..f070b6ac8
--- /dev/null
+++ b/docs/uk/docs/tutorial/cookie-param-models.md
@@ -0,0 +1,76 @@
+# Моделі для Cookie-параметрів
+
+Якщо у Вас є група **cookies** параметрів, які пов'язані між собою, Ви можете створити **Pydantic-модель**, щоб оголосити їх. 🍪
+
+Це дозволить Вам повторно **використовувати модель** у **різних місцях**, а також оголосити валідацію та метадані для всіх параметрів одночасно. 😎
+
+/// note | Нотатки
+
+Це підтримується з версії FastAPI `0.115.0`. 🤓
+
+///
+
+/// tip | Порада
+
+Ця ж техніка застосовується до `Query`, `Cookie`, та `Header`. 😎
+
+///
+
+## Cookie з Pydantic-моделлю
+
+Оголосіть **cookie-параметри**, які Вам потрібні, у **Pydantic-моделі**, а потім оголосіть параметр як `Cookie`:
+
+{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}
+
+**FastAPI** буде **витягувати** дані для **кожного поля** з **cookie** параметрів, отриманих у запиті, і передавати Вам Pydantic-модель, яку Ви визначили.
+
+## Перевірка у документації
+
+Ви можете побачити визначені cookie в інтерфейсі документації за адресою `/docs`:
+
+
+
+
+
+/// info | Інформація
+
+Майте на увазі, що оскільки **браузери обробляють cookie** особливим чином і "за лаштунками", вони **не** дозволяють **JavaScript** легко з ними працювати.
+
+Якщо Ви зайдете до **інтерфейсу документації API** за адресою `/docs`, Ви зможете побачити **документацію** для cookie у Ваших **операціях шляху**.
+
+Але навіть якщо Ви заповните дані й натиснете "Execute", оскільки інтерфейс документації працює з **JavaScript**, cookie не будуть відправлені, і Ви побачите **помилку**, ніби Ви не ввели жодних значень.
+
+///
+
+## Заборона додаткових cookie
+
+У деяких спеціальних випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** список cookie, які хочете отримувати.
+
+Ваша API тепер має можливість контролювати власну згоду на cookie. 🤪🍪
+
+Ви можете використовувати налаштування моделі Pydantic, щоб `заборонити` будь-які `додаткові` поля:
+
+{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *}
+
+Якщо клієнт спробує надіслати якісь **додаткові cookie**, він отримає відповідь з **помилкою**.
+
+Бідні банери cookie, які так старанно намагаються отримати Вашу згоду, щоб API її відхилила. 🍪
+
+Наприклад, якщо клієнт спробує надіслати cookie `santa_tracker` зі значенням `good-list-please`, він отримає відповідь з помилкою, яка повідомить, що cookie `santa_tracker` не дозволено:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["cookie", "santa_tracker"],
+ "msg": "Extra inputs are not permitted",
+ "input": "good-list-please",
+ }
+ ]
+}
+```
+
+## Підсумок
+
+Ви можете використовувати **Pydantic-моделі** для оголошення cookie у FastAPI. 😎
diff --git a/docs/uk/docs/tutorial/cookie-params.md b/docs/uk/docs/tutorial/cookie-params.md
index 229f81b63..b320645cb 100644
--- a/docs/uk/docs/tutorial/cookie-params.md
+++ b/docs/uk/docs/tutorial/cookie-params.md
@@ -6,57 +6,7 @@
Спочатку імпортуйте `Cookie`:
-//// tab | Python 3.10+
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="1"
-{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="3"
-{!> ../../docs_src/cookie_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}
## Визначення параметрів `Cookie`
@@ -64,57 +14,7 @@
Перше значення це значення за замовчуванням, ви можете також передати всі додаткові параметри валідації чи анотації:
-//// tab | Python 3.10+
-
-```Python hl_lines="9"
-{!> ../../docs_src/cookie_params/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="9"
-{!> ../../docs_src/cookie_params/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="10"
-{!> ../../docs_src/cookie_params/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="7"
-{!> ../../docs_src/cookie_params/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="9"
-{!> ../../docs_src/cookie_params/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}
/// note | Технічні Деталі
diff --git a/docs/uk/docs/tutorial/cors.md b/docs/uk/docs/tutorial/cors.md
new file mode 100644
index 000000000..95b204d0f
--- /dev/null
+++ b/docs/uk/docs/tutorial/cors.md
@@ -0,0 +1,89 @@
+# CORS (Обмін ресурсами між різними джерелами)
+
+CORS або "Обмін ресурсами між різними джерелами" є ситуація, коли фронтенд, що працює в браузері, містить JavaScript-код, який взаємодіє з бекендом, розташованим в іншому "джерелі" (origin).
+
+## Джерело (Origin)
+
+Джерело визначається комбінацією протоколу (`http`, `https`), домену (`myapp.com`, `localhost`, `localhost.tiangolo.com`), порту (`80`, `443`, `8080`).
+
+
+Наприклад, такі адреси вважаються різними джерелами:
+
+* `http://localhost`
+* `https://localhost`
+* `http://localhost:8080`
+
+Навіть якщо вони всі містять `localhost`, вони мають різні протоколи або порти, що робить їх окремими "джерелами".
+
+## Кроки
+
+Припустимо, що Ваш фронтенд працює в браузері на `http://localhost:8080`, а його JavaScript намагається відправити запит до бекенду, який працює на `http://localhost` (Оскільки ми не вказуємо порт, браузер за замовчуванням припускає порт `80`).
+
+Потім браузер надішле HTTP-запит `OPTIONS` до бекенду на порту `:80`, і якщо бекенд надішле відповідні заголовки, що дозволяють комунікацію з цього іншого джерела (`http://localhost:8080`), тоді браузер на порту `:8080` дозволить JavaScript у фронтенді надіслати свій запит до бекенду на порту `:80`.
+
+Щоб досягти цього, бекенд на порту `:80` повинен мати список "дозволених джерел".
+
+У цьому випадку список має містити `http://localhost:8080`, щоб фронтенд на порту `:8080` працював коректно.
+
+## Символьне підставляння
+
+Можна також оголосити список як `"*"` ("символьне підставляння"), що означає дозвіл для всіх джерел.
+
+Однак це дозволить лише певні типи комунікації, виключаючи все, що пов'язане з обліковими даними: Cookies, заголовки авторизації, такі як ті, що використовуються з Bearer токенами тощо.
+
+Тому для коректної роботи краще явно вказувати дозволені джерела.
+
+## Використання `CORSMiddleware`
+
+Ви можете налаштувати це у Вашому додатку **FastAPI** за допомогою `CORSMiddleware`.
+
+* Імпортуйте `CORSMiddleware`.
+* Створіть список дозволених джерел (у вигляді рядків).
+* Додайте його як "middleware" у Ваш додаток **FastAPI**.
+
+
+Також можна вказати, чи дозволяє Ваш бекенд:
+
+* Облікові дані (заголовки авторизації, сookies, тощо).
+* Конкретні HTTP-методи (`POST`, `PUT`) або всі за допомогою `"*"`
+* Конкретні HTTP-заголовки або всі за допомогою `"*"`.
+
+
+{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *}
+
+Параметри за замовчуванням у `CORSMiddleware` є досить обмеженими, тому Вам потрібно явно вказати конкретні джерела, методи або заголовки, щоб браузери могли використовувати їх у контексті запитів між різними доменами.
+
+
+Підтримуються такі аргументи:
+
+* `allow_origins` - Список джерел, яким дозволено здійснювати міждоменні запити. Наприклад `['https://example.org', 'https://www.example.org']`. Ви можете використовувати ['*'], щоб дозволити всі джерела.
+* `allow_origin_regex` - Рядок регулярного виразу для відповідності джерелам, яким дозволено здійснювати міждоменні запити. Наприклад, `'https://.*\.example\.org'`.
+* `allow_methods` - Список HTTP-методів, дозволених для міждоменних запитів. За замовчуванням `['GET']`. Ви можете використовувати `['*']`, щоб дозволити всі стандартні методи.
+* `allow_headers` - Список HTTP-заголовків, які підтримуються для міждоменних запитів. За замовчуванням `[]`. Ви можете використовувати `['*']`, щоб дозволити всі заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` і `Content-Type` завжди дозволені для простих CORS-запитів.
+* `allow_credentials` - Визначає, чи підтримуються файли cookie для міждоменних запитів. За замовчуванням `False`. Також, якщо потрібно дозволити обмін обліковими даними (`allow_credentials = True`), параметр `allow_origins` не може бути встановлений як `['*']`, необхідно вказати конкретні джерела.
+* `expose_headers` - Вказує, які заголовки відповіді повинні бути доступні для браузера. За замовчуванням `[]`.
+* `max_age` - Встановлює максимальний час (у секундах) для кешування CORS-відповідей у браузерах. За замовчуванням `600`.
+
+Цей middleware обробляє два типи HTTP-запитів...
+
+### Попередні CORS-запити (preflight requests)
+
+Це будь-які `OPTIONS` - запити, що містять заголовки `Origin` та `Access-Control-Request-Method`.
+
+У такому випадку middleware перехопить вхідний запит і відповість відповідними CORS-заголовками, повертаючи або `200`, або `400` для інформаційних цілей.
+
+### Прості запити
+
+Будь-які запити із заголовком `Origin`. У цьому випадку middleware пропустить запит як звичайний, але додасть відповідні CORS-заголовки у відповідь.
+
+## Додаткова інформація
+
+Більше про CORS можна дізнатися в документації Mozilla.
+
+/// note | Технічні деталі
+
+Також можна використовувати `from starlette.middleware.cors import CORSMiddleware`.
+
+**FastAPI** надає кілька middleware у `fastapi.middleware` для зручності розробників. Але більшість доступних middleware походять безпосередньо зі Starlette.
+
+///
diff --git a/docs/uk/docs/tutorial/debugging.md b/docs/uk/docs/tutorial/debugging.md
new file mode 100644
index 000000000..b0e5344f8
--- /dev/null
+++ b/docs/uk/docs/tutorial/debugging.md
@@ -0,0 +1,112 @@
+# Налагодження (Debugging)
+
+Ви можете під'єднати дебагер у Вашому редакторі коду, наприклад, у Visual Studio Code або PyCharm.
+
+## Виклик `uvicorn`
+
+У Вашому FastAPI-додатку імпортуйте та запустіть `uvicorn` безпосередньо:
+
+{* ../../docs_src/debugging/tutorial001.py hl[1,15] *}
+
+### Про `__name__ == "__main__"`
+
+Головна мета використання `__name__ == "__main__"` — це забезпечення виконання певного коду тільки тоді, коли файл запускається безпосередньо:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+але не виконується при його імпорті в інший файл, наприклад:
+
+```Python
+from myapp import app
+```
+
+#### Детальніше
+
+Припустимо, Ваш файл називається `myapp.py`.
+
+Якщо Ви запустите його так:
+
+
+
+```console
+$ python myapp.py
+```
+
+
+
+тоді внутрішня змінна `__name__`, яка створюється автоматично Python, матиме значення `"__main__"`.
+
+Отже, цей блок коду:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+буде виконаний.
+
+---
+
+Це не станеться, якщо Ви імпортуєте цей модуль (файл).
+
+Якщо у Вас є інший файл, наприклад `importer.py`, з наступним кодом:
+
+```Python
+from myapp import app
+
+# Додатковий код
+```
+
+У цьому випадку автоматично створена змінна у файлі `myapp.py` не матиме значення змінної `__name__` як `"__main__"`.
+
+Отже, рядок:
+
+```Python
+ uvicorn.run(app, host="0.0.0.0", port=8000)
+```
+
+не буде виконано.
+
+/// info | Інформація
+
+Більш детальну інформацію можна знайти в офіційній документації Python.
+
+///
+
+## Запуск коду з вашим дебагером
+
+Оскільки Ви запускаєте сервер Uvicorn безпосередньо з Вашого коду, Ви можете запустити вашу Python програму (ваш FastAPI додаток) безпосередньо з дебагера.
+
+---
+
+Наприклад, у Visual Studio Code Ви можете:
+
+* Перейдіть на вкладку "Debug".
+* Натисніть "Add configuration...".
+* Виберіть "Python"
+* Запустіть дебагер з опцією "`Python: Current File (Integrated Terminal)`".
+
+Це запустить сервер з Вашим **FastAPI** кодом, зупиниться на точках зупину тощо.
+
+Ось як це може виглядати:
+
+
+
+---
+Якщо Ви використовуєте PyCharm, ви можете:
+
+* Відкрити меню "Run".
+* Вибрати опцію "Debug...".
+* Потім з'явиться контекстне меню.
+* Вибрати файл для налагодження (у цьому випадку, `main.py`).
+
+Це запустить сервер з Вашим **FastAPI** кодом, зупиниться на точках зупину тощо.
+
+Ось як це може виглядати:
+
+
diff --git a/docs/uk/docs/tutorial/encoder.md b/docs/uk/docs/tutorial/encoder.md
index 77b0baf4d..f202c7989 100644
--- a/docs/uk/docs/tutorial/encoder.md
+++ b/docs/uk/docs/tutorial/encoder.md
@@ -20,21 +20,7 @@
Вона приймає об'єкт, такий як Pydantic model, і повертає його версію, сумісну з JSON:
-//// tab | Python 3.10+
-
-```Python hl_lines="4 21"
-{!> ../../docs_src/encoder/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="5 22"
-{!> ../../docs_src/encoder/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}
У цьому прикладі вона конвертує Pydantic model у `dict`, а `datetime` у `str`.
diff --git a/docs/uk/docs/tutorial/extra-data-types.md b/docs/uk/docs/tutorial/extra-data-types.md
index 5e6c364e4..5da942b6e 100644
--- a/docs/uk/docs/tutorial/extra-data-types.md
+++ b/docs/uk/docs/tutorial/extra-data-types.md
@@ -55,108 +55,8 @@
Ось приклад *path operation* з параметрами, використовуючи деякі з вищезазначених типів.
-//// tab | Python 3.10+
-
-```Python hl_lines="1 3 12-16"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 3 12-16"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="1 3 13-17"
-{!> ../../docs_src/extra_data_types/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="1 2 11-15"
-{!> ../../docs_src/extra_data_types/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="1 2 12-16"
-{!> ../../docs_src/extra_data_types/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}
Зверніть увагу, що параметри всередині функції мають свій звичайний тип даних, і ви можете, наприклад, виконувати звичайні маніпуляції з датами, такі як:
-//// tab | Python 3.10+
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py310.py!}
-```
-
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/extra_data_types/tutorial001_an_py39.py!}
-```
-
-////
-
-//// tab | Python 3.8+
-
-```Python hl_lines="19-20"
-{!> ../../docs_src/extra_data_types/tutorial001_an.py!}
-```
-
-////
-
-//// tab | Python 3.10+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="17-18"
-{!> ../../docs_src/extra_data_types/tutorial001_py310.py!}
-```
-
-////
-
-//// tab | Python 3.8+ non-Annotated
-
-/// tip
-
-Бажано використовувати `Annotated` версію, якщо це можливо.
-
-///
-
-```Python hl_lines="18-19"
-{!> ../../docs_src/extra_data_types/tutorial001.py!}
-```
-
-////
+{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}
diff --git a/docs/uk/docs/tutorial/first-steps.md b/docs/uk/docs/tutorial/first-steps.md
index 63fec207d..e910c4ccc 100644
--- a/docs/uk/docs/tutorial/first-steps.md
+++ b/docs/uk/docs/tutorial/first-steps.md
@@ -2,9 +2,7 @@
Найпростіший файл FastAPI може виглядати так:
-```Python
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py *}
Скопіюйте це до файлу `main.py`.
@@ -157,9 +155,7 @@ OpenAPI описує схему для вашого API. І ця схема вк
### Крок 1: імпортуємо `FastAPI`
-```Python hl_lines="1"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[1] *}
`FastAPI` це клас у Python, який надає всю функціональність для API.
@@ -173,9 +169,7 @@ OpenAPI описує схему для вашого API. І ця схема вк
### Крок 2: створюємо екземпляр `FastAPI`
-```Python hl_lines="3"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[3] *}
Змінна `app` є екземпляром класу `FastAPI`.
Це буде головна точка для створення і взаємодії з API.
@@ -242,9 +236,7 @@ https://example.com/items/foo
#### Визначте декоратор операції шляху (path operation decorator)
-```Python hl_lines="6"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[6] *}
Декоратор `@app.get("/")` вказує **FastAPI**, що функція нижче, відповідає за обробку запитів, які надходять до неї:
* шлях `/`
@@ -297,9 +289,7 @@ https://example.com/items/foo
* **операція**: це `get`.
* **функція**: це функція, яка знаходиться нижче "декоратора" (нижче `@app.get("/")`).
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[7] *}
Це звичайна функція Python.
@@ -311,9 +301,7 @@ FastAPI викликатиме її щоразу, коли отримає зап
Ви також можете визначити її як звичайну функцію замість `async def`:
-```Python hl_lines="7"
-{!../../docs_src/first_steps/tutorial003.py!}
-```
+{* ../../docs_src/first_steps/tutorial003.py hl[7] *}
/// note | Примітка
@@ -323,9 +311,7 @@ FastAPI викликатиме її щоразу, коли отримає зап
### Крок 5: поверніть результат
-```Python hl_lines="8"
-{!../../docs_src/first_steps/tutorial001.py!}
-```
+{* ../../docs_src/first_steps/tutorial001.py hl[8] *}
Ви можете повернути `dict`, `list`, а також окремі значення `str`, `int`, ітд.
diff --git a/docs/uk/docs/tutorial/handling-errors.md b/docs/uk/docs/tutorial/handling-errors.md
new file mode 100644
index 000000000..12a356cd0
--- /dev/null
+++ b/docs/uk/docs/tutorial/handling-errors.md
@@ -0,0 +1,255 @@
+# Обробка Помилок
+
+Є багато ситуацій, коли потрібно повідомити клієнта, який використовує Ваш API, про помилку.
+
+Цим клієнтом може бути браузер із фронтендом, код іншого розробника, IoT-пристрій тощо.
+
+Можливо, Вам потрібно повідомити клієнта, що:
+
+* У нього недостатньо прав для виконання цієї операції.
+* Він не має доступу до цього ресурсу.
+* Елемент, до якого він намагається отримати доступ, не існує.
+* тощо.
+
+У таких випадках зазвичай повертається **HTTP статус-код** в діапазоні **400** (від 400 до 499).
+
+Це схоже на HTTP статус-коди 200 (від 200 до 299). Ці "200" статус-коди означають, що запит пройшов успішно.
+
+Статус-коди в діапазоні 400 означають, що сталася помилка з боку клієнта.
+
+Пам'ятаєте всі ці помилки **404 Not Found** (і жарти про них)?
+
+## Використання `HTTPException`
+
+Щоб повернути HTTP-відповіді з помилками клієнту, використовуйте `HTTPException`.
+
+### Імпорт `HTTPException`
+
+{* ../../docs_src/handling_errors/tutorial001.py hl[1] *}
+
+### Використання `HTTPException` у коді
+
+`HTTPException` — це звичайна помилка Python із додатковими даними, які стосуються API.
+
+Оскільки це помилка Python, Ви не `повертаєте` його, а `генеруєте` (генеруєте помилку).
+
+Це також означає, що якщо Ви перебуваєте всередині допоміжної функції, яку викликаєте всередині своєї *функції операції шляху*, і там генеруєте `HTTPException`, всередині цієї допоміжної функції, то решта коду в *функції операції шляху* не буде виконана. Запит одразу завершиться, і HTTP-помилка з `HTTPException` буде надіслана клієнту.
+
+Перевага використання `генерації` (raise) помилки замість `повернення` значення (return) стане більш очевидним в розділі про Залежності та Безпеку.
+
+У цьому прикладі, якщо клієнт запитує елемент за ID, якого не існує, буде згенеровано помилку зі статус-кодом `404`:
+
+{* ../../docs_src/handling_errors/tutorial001.py hl[11] *}
+
+### Отримана відповідь
+
+Якщо клієнт робить запит за шляхом `http://example.com/items/foo` (де `item_id` `"foo"`), він отримає статус-код 200 і JSON відповідь:
+
+```JSON
+{
+ "item": "The Foo Wrestlers"
+}
+```
+
+Але якщо клієнт робить запит на `http://example.com/items/bar` (де `item_id` має не існуюче значення `"bar"`), то отримає статус-код 404 (помилка "не знайдено") та відповідь:
+
+```JSON
+{
+ "detail": "Item not found"
+}
+```
+
+/// tip | Порада
+
+Під час виклику `HTTPException` Ви можете передати будь-яке значення, яке може бути перетворене в JSON, як параметр `detail`, а не лише рядок (`str`).
+
+Ви можете передати `dict`, `list` тощо.
+
+Вони обробляються автоматично за допомогою **FastAPI** та перетворюються в JSON.
+
+///
+
+## Додавання власних заголовків
+
+Іноді потрібно додати власні заголовки до HTTP-помилки, наприклад, для певних типів безпеки.
+
+Ймовірно, Вам не доведеться використовувати це безпосередньо у своєму коді.
+
+Але якщо Вам знадобиться це для складного сценарію, Ви можете додати власні заголовки:
+
+{* ../../docs_src/handling_errors/tutorial002.py hl[14] *}
+
+## Встановлення власних обробників помилок
+
+Ви можете додати власні обробники помилок за допомогою тих самих утиліт обробки помилок зі Starlette.
+
+Припустимо, у Вас є власний обʼєкт помилки `UnicornException`, яке Ви (або бібліотека, яку Ви використовуєте) може `згенерувати` (`raise`).
+
+І Ви хочете обробляти це виключення глобально за допомогою FastAPI.
+
+Ви можете додати власний обробник виключень за допомогою `@app.exception_handler()`:
+
+{* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *}
+
+Тут, якщо Ви звернетеся до `/unicorns/yolo`, то згенерується помилка `UnicornException`.
+
+Але вона буде оброблена функцією-обробником `unicorn_exception_handler`.
+
+Отже, Ви отримаєте зрозумілу помилку зі HTTP-статусом `418` і JSON-відповіддю:
+
+```JSON
+{"message": "Oops! yolo did something. There goes a rainbow..."}
+```
+
+/// note | Технічні деталі
+
+Ви також можете використовувати `from starlette.requests import Request` і `from starlette.responses import JSONResponse`.
+
+**FastAPI** надає ті самі `starlette.responses`, що й `fastapi.responses`, просто для зручності розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette. Те ж саме стосується і `Request`.
+
+///
+
+## Перевизначення обробників помилок за замовчуванням
+
+**FastAPI** має кілька обробників помилок за замовчуванням.
+
+Ці обробники відповідають за повернення стандартних JSON-відповідей, коли Ви `генеруєте` (`raise`) `HTTPException`, а також коли запит містить некоректні дані.
+
+Ви можете перевизначити ці обробники, створивши власні.
+
+### Перевизначення помилок валідації запиту
+
+Коли запит містить некоректні дані, **FastAPI** генерує `RequestValidationError`.
+
+І також включає обробник помилок за замовчуванням для нього.
+
+Щоб перевизначити його, імпортуйте `RequestValidationError` і використовуйте його з `@app.exception_handler(RequestValidationError)` для декорування обробника помилок.
+
+Обробник помилок отримує `Request` і саму помилку.
+
+{* ../../docs_src/handling_errors/tutorial004.py hl[2,14:16] *}
+
+Тепер, якщо Ви перейдете за посиланням `/items/foo`, замість того, щоб отримати стандартну JSON-помилку:
+
+```JSON
+{
+ "detail": [
+ {
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer"
+ }
+ ]
+}
+```
+
+Ви отримаєте текстову версію:
+
+```
+1 validation error
+path -> item_id
+ value is not a valid integer (type=type_error.integer)
+```
+
+#### `RequestValidationError` проти `ValidationError`
+
+/// warning | Увага
+
+Це технічні деталі, які Ви можете пропустити, якщо вони зараз не важливі для Вас.
+
+///
+
+`RequestValidationError` є підкласом Pydantic `ValidationError`.
+
+**FastAPI** використовує його для того, якщо Ви використовуєте модель Pydantic у `response_model` і у ваших даних є помилка, Ви побачили помилку у своєму журналі.
+
+Але клієнт/користувач не побачить її. Натомість клієнт отримає "Internal Server Error" зі статусом HTTP `500`.
+
+Так має бути, якщо у Вас виникла `ValidationError` Pydantic у *відповіді* або деінде у вашому коді (не у *запиті* клієнта), це насправді є помилкою у Вашому коді.
+
+І поки Ви її виправляєте, клієнти/користувачі не повинні мати доступу до внутрішньої інформації про помилку, оскільки це може призвести до вразливості безпеки.
+
+### Перевизначення обробника помилок `HTTPException`
+
+Аналогічно, Ви можете перевизначити обробник `HTTPException`.
+
+Наприклад, Ви можете захотіти повернути текстову відповідь замість JSON для цих помилок:
+
+{* ../../docs_src/handling_errors/tutorial004.py hl[3:4,9:11,22] *}
+
+/// note | Технічні деталі
+
+Ви також можете використовувати `from starlette.responses import PlainTextResponse`.
+
+**FastAPI** надає ті самі `starlette.responses`, що й `fastapi.responses`, просто для зручності розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.
+
+///
+
+### Використання тіла `RequestValidationError`
+
+`RequestValidationError` містить `body`, який він отримав із некоректними даними.
+
+Ви можете використовувати це під час розробки свого додатка, щоб логувати тіло запиту та налагоджувати його, повертати користувачеві тощо.
+
+{* ../../docs_src/handling_errors/tutorial005.py hl[14] *}
+
+Тепер спробуйте надіслати некоректний елемент, наприклад:
+
+```JSON
+{
+ "title": "towel",
+ "size": "XL"
+}
+```
+Ви отримаєте відповідь, яка повідомить Вам, які саме дані є некоректні у вашому тілі запиту:
+
+
+```JSON hl_lines="12-15"
+{
+ "detail": [
+ {
+ "loc": [
+ "body",
+ "size"
+ ],
+ "msg": "value is not a valid integer",
+ "type": "type_error.integer"
+ }
+ ],
+ "body": {
+ "title": "towel",
+ "size": "XL"
+ }
+}
+```
+
+#### `HTTPException` FastAPI проти `HTTPException` Starlette
+
+**FastAPI** має власний `HTTPException`.
+
+І клас помилки `HTTPException` в **FastAPI** успадковується від класу помилки `HTTPException` в Starlette.
+
+Єдина різниця полягає в тому, що `HTTPException` в **FastAPI** приймає будь-які дані, які можна перетворити на JSON, для поля `detail`, тоді як `HTTPException` у Starlette приймає тільки рядки.
+
+Отже, Ви можете продовжувати використовувати `HTTPException` в **FastAPI** як зазвичай у своєму коді.
+
+Але коли Ви реєструєте обробник виключень, слід реєструвати його для `HTTPException` зі Starlette.
+
+Таким чином, якщо будь-яка частина внутрішнього коду Starlette або розширення чи плагін Starlette згенерує (raise) `HTTPException`, Ваш обробник зможе перехопити та обробити її.
+
+У цьому прикладі, щоб мати можливість використовувати обидва `HTTPException` в одному коді, помилка Starlette перейменовується на `StarletteHTTPException`:
+
+```Python
+from starlette.exceptions import HTTPException as StarletteHTTPException
+```
+
+### Повторне використання обробників помилок **FastAPI**
+
+Якщо Ви хочете використовувати помилки разом із такими ж обробниками помилок за замовчуванням, як у **FastAPI**, Ви можете імпортувати та повторно використовувати їх із `fastapi.exception_handlers`:
+
+{* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *}
+
+У цьому прикладі Ви просто використовуєте `print` для виведення дуже інформативного повідомлення, але Ви зрозуміли основну ідею. Ви можете обробити помилку та повторно використовувати обробники помилок за замовчуванням.
diff --git a/docs/uk/docs/tutorial/header-param-models.md b/docs/uk/docs/tutorial/header-param-models.md
new file mode 100644
index 000000000..6f7b0bdae
--- /dev/null
+++ b/docs/uk/docs/tutorial/header-param-models.md
@@ -0,0 +1,58 @@
+# Моделі Параметрів Заголовків
+
+Якщо у Вас є група пов’язаних параметрів заголовків, Ви можете створити **Pydantic модель** для їх оголошення.
+
+Це дозволить Вам повторно **використовувати модель** в **різних місцях**, а також оголосити валідації та метадані для всіх параметрів одночасно. 😎
+
+/// note | Нотатки
+
+Ця можливість підтримується починаючи з версії FastAPI `0.115.0`. 🤓
+
+///
+
+## Параметри Заголовків з Використанням Pydantic Model
+
+Оголосіть потрібні **параметри заголовків** у **Pydantic моделі**, а потім оголосіть параметр як `Header`:
+
+{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}
+
+FastAPI буде витягувати дані для кожного поля з заголовків у запиті та передавати їх у створену Вами Pydantic модель.
+
+**FastAPI** буде **витягувати** дані для **кожного поля** з **заголовків** у запиті та передавати їх у створену Вами Pydantic модель.
+
+## Перевірка в Документації
+
+Ви можете побачити необхідні заголовки в інтерфейсі документації за адресою `/docs`:
+
+
+
+
+
+## Заборона Додаткових Заголовків
+
+У деяких особливих випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** заголовки, які хочете отримати.
+
+Ви можете використати конфігурацію моделі Pydantic, щоб `заборонити` будь-які `додаткові` поля:
+
+{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}
+
+Якщо клієнт спробує надіслати **додаткові заголовки**, він отримає **помилку** у відповіді.
+
+Наприклад, якщо клієнт спробує надіслати заголовок `tool` зі значенням `plumbus`, він отримає **помилку** з повідомленням про те, що параметр заголовка `tool` не дозволений:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["header", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus",
+ }
+ ]
+}
+```
+
+## Підсумок
+
+Ви можете використовувати **Pydantic моделі** для оголошення **заголовків** у **FastAPI**. 😎
diff --git a/docs/uk/docs/tutorial/header-params.md b/docs/uk/docs/tutorial/header-params.md
new file mode 100644
index 000000000..09c70a4f6
--- /dev/null
+++ b/docs/uk/docs/tutorial/header-params.md
@@ -0,0 +1,91 @@
+# Header-параметри
+
+Ви можете визначати параметри заголовків, так само як визначаєте `Query`, `Path` і `Cookie` параметри.
+
+## Імпорт `Header`
+
+Спочатку імпортуйте `Header`:
+
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}
+
+## Оголошення параметрів `Header`
+
+Потім оголосіть параметри заголовків, використовуючи ту ж структуру, що й для `Path`, `Query` та `Cookie`.
+
+Ви можете визначити значення за замовчуванням, а також усі додаткові параметри валідації або анотації:
+
+{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}
+
+/// note | Технічні деталі
+
+`Header`є "сестринським" класом для `Path`, `Query` і `Cookie`. Він також успадковується від загального класу `Param`.
+
+Але пам’ятайте, що при імпорті `Query`, `Path`, `Header` та інших із `fastapi`, то насправді вони є функціями, які повертають спеціальні класи.
+
+///
+
+/// info | Інформація
+
+Щоб оголосити заголовки, потрібно використовувати `Header`, інакше параметри будуть інтерпретуватися як параметри запиту.
+
+///
+
+## Автоматичне перетворення
+
+`Header` має додатковий функціонал порівняно з `Path`, `Query` та `Cookie`.
+
+Більшість стандартних заголовків розділяються символом «дефіс», також відомим як «мінус» (`-`).
+
+Але змінна, така як `user-agent`, є недійсною в Python.
+
+Тому, за замовчуванням, `Header` автоматично перетворює символи підкреслення (`_`) на дефіси (`-`) для отримання та документування заголовків.
+
+Оскільки заголовки HTTP не чутливі до регістру, Ви можете використовувати стандартний стиль Python ("snake_case").
+
+Тому Ви можете використовувати `user_agent`, як зазвичай у коді Python, замість того щоб писати з великої літери, як `User_Agent` або щось подібне.
+
+Якщо Вам потрібно вимкнути автоматичне перетворення підкреслень у дефіси, встановіть `convert_underscores` в `Header` значення `False`:
+
+{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}
+
+/// warning | Увага
+
+Перед тим як встановити значення `False` для `convert_underscores` пам’ятайте, що деякі HTTP-проксі та сервери не підтримують заголовки з підкресленнями.
+
+///
+
+## Дубльовані заголовки
+
+Можливо отримати дубльовані заголовки, тобто той самий заголовок із кількома значеннями.
+
+Це можна визначити, використовуючи список у типізації параметра.
+
+Ви отримаєте всі значення дубльованого заголовка у вигляді `list` у Python.
+
+Наприклад, щоб оголосити заголовок `X-Token`, який може з’являтися більше ніж один раз:
+
+{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}
+
+Якщо Ви взаємодієте з цією операцією шляху, надсилаючи два HTTP-заголовки, наприклад:
+
+```
+X-Token: foo
+X-Token: bar
+```
+
+Відповідь буде така:
+
+```JSON
+{
+ "X-Token values": [
+ "bar",
+ "foo"
+ ]
+}
+```
+
+## Підсумок
+
+Оголошуйте заголовки за допомогою `Header`, використовуючи той самий підхід, що й для `Query`, `Path` та `Cookie`.
+
+Не хвилюйтеся про підкреслення у змінних — **FastAPI** автоматично конвертує їх.
diff --git a/docs/uk/docs/tutorial/metadata.md b/docs/uk/docs/tutorial/metadata.md
new file mode 100644
index 000000000..64e667ec6
--- /dev/null
+++ b/docs/uk/docs/tutorial/metadata.md
@@ -0,0 +1,120 @@
+# Метадані та URL-адреси документації
+
+Ви можете налаштувати кілька конфігурацій метаданих у Вашому додатку **FastAPI**.
+
+## Метадані для API
+
+Ви можете встановити такі поля, які використовуються в специфікації OpenAPI та в автоматично згенерованих інтерфейсах документації API:
+
+| Параметр | Тип | Опис |
+|------------|------|-------------|
+| `title` | `str` | Назва API. |
+| `summary` | `str` | Короткий опис API. Доступно з OpenAPI 3.1.0, FastAPI 0.99.0. |
+| `description` | `str` | Більш детальний опис API. Може використовувати Markdown. |
+| `version` | `string` | Версія API. Це версія Вашого додатка, а не OpenAPI. Наприклад, `2.5.0`. |
+| `terms_of_service` | `str` | URL до умов використання API. Якщо вказано, має бути у форматі URL. |
+| `contact` | `dict` | Інформація для контакту з API. Може містити кілька полів. contact поля
Параметр
Тип
Опис
name
str
Ім'я контактної особи або організації.
url
str
URL з інформацією для контакту. Повинен бути у форматі URL.
email
str
Email контактної особи або організації. Повинен бути у форматі електронної пошти.
|
+| `license_info` | `dict` | Інформація про ліцензію для API. Може містити кілька полів. license_info поля
Параметр
Тип
Опис
name
str
ОБОВ'ЯЗКОВО (якщо встановлено license_info). Назва ліцензії для API.
identifier
str
Ліцензійний вираз за SPDX для API. Поле identifier взаємовиключне з полем url. Доступно з OpenAPI 3.1.0, FastAPI 0.99.0.
url
str
URL до ліцензії, яка використовується для API. Повинен бути у форматі URL.
|
+
+Ви можете налаштувати їх наступним чином:
+
+{* ../../docs_src/metadata/tutorial001.py hl[3:16, 19:32] *}
+
+/// tip | Підказка
+
+У полі `description` можна використовувати Markdown, і він буде відображатися у результаті.
+
+///
+
+З цією конфігурацією автоматична документація API виглядатиме так:
+
+
+
+## Ідентифікатор ліцензії
+
+З початку використання OpenAPI 3.1.0 та FastAPI 0.99.0 Ви також можете налаштувати `license_info` за допомогою `identifier` замість `url`.
+
+Наприклад:
+
+{* ../../docs_src/metadata/tutorial001_1.py hl[31] *}
+
+## Метадані для тегів
+
+Ви також можете додати додаткові метадані для різних тегів, які використовуються для групування операцій шляхів, за допомогою параметра `openapi_tags`.
+
+Він приймає список, який містить один словник для кожного тега.
+
+Кожен словник може містити:
+
+* `name` (**обов'язково**): `str` з тією ж назвою тегу, яку Ви використовуєте у параметрі `tags` у Ваших *операціях шляху* та `APIRouter`s.
+* `description`: `str` з коротким описом тегу. Може містити Markdown і буде відображено в інтерфейсі документації.
+* `externalDocs`: `dict` який описує зовнішню документацію з такими полями:
+ * `description`: `str` з коротким описом зовнішньої документації.
+ * `url` (**обов'язково**): `str`з URL-адресою зовнішньої документації.
+
+### Створення метаданих для тегів
+
+Спробуймо це на прикладі з тегами для `users` та `items`.
+
+Створіть метадані для своїх тегів і передайте їх у параметр `openapi_tags`:
+
+{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *}
+
+Зверніть увагу, що в описах можна використовувати Markdown, наприклад, "login" буде показано жирним шрифтом (**login**), а "fancy" буде показано курсивом (_fancy_).
+
+/// tip | Порада
+
+Не обов'язково додавати метадані для всіх тегів, які Ви використовуєте.
+
+///
+
+### Використання тегів
+
+Використовуйте параметр `tags` зі своїми *операціями шляху* (і `APIRouter`) для призначення їх до різних тегів:
+
+{* ../../docs_src/metadata/tutorial004.py hl[21,26] *}
+
+/// info | Інформація
+
+Детальніше про теги читайте в розділі [Конфігурація шляхів операцій](path-operation-configuration.md#tags){.internal-link target=_blank}.
+
+///
+
+### Перевірка документації
+
+Якщо Ви зараз перевірите документацію, вона покаже всі додаткові метадані:
+
+
+
+### Порядок тегів
+
+Порядок кожного словника метаданих тегу також визначає порядок відображення в інтерфейсі документації.
+
+Наприклад, хоча `users` мав би йти після `items` в алфавітному порядку, він відображається перед ними, оскільки ми додали його метадані як перший словник у списку.
+
+## URL для OpenAPI
+
+За замовчуванням схема OpenAPI надається за адресою `/openapi.json`.
+
+Але Ви можете налаштувати це за допомогою параметра `openapi_url`.
+
+Наприклад, щоб налаштувати його на `/api/v1/openapi.json`:
+
+{* ../../docs_src/metadata/tutorial002.py hl[3] *}
+
+Якщо Ви хочете повністю вимкнути схему OpenAPI, Ви можете встановити `openapi_url=None`, це також вимкне інтерфейси документації, які її використовують.
+
+## URL-адреси документації
+
+Ви можете налаштувати два інтерфейси користувача для документації, які включені:
+
+* **Swagger UI**: доступний за адресою `/docs`.
+ * Ви можете змінити його URL за допомогою параметра `docs_url`.
+ * Ви можете вимкнути його, встановивши `docs_url=None`.
+* **ReDoc**: доступний за адресою `/redoc`.
+ * Ви можете змінити його URL за допомогою параметра `redoc_url`.
+ * Ви можете вимкнути його, встановивши `redoc_url=None`.
+
+Наприклад, щоб налаштувати Swagger UI на `/documentation` і вимкнути ReDoc:
+
+{* ../../docs_src/metadata/tutorial003.py hl[3] *}
diff --git a/docs/uk/docs/tutorial/middleware.md b/docs/uk/docs/tutorial/middleware.md
new file mode 100644
index 000000000..807be484a
--- /dev/null
+++ b/docs/uk/docs/tutorial/middleware.md
@@ -0,0 +1,75 @@
+# Middleware (Проміжний шар)
+
+У **FastAPI** можна додавати middleware (проміжний шар).
+
+"Middleware" — це функція, яка працює з кожним **запитом** перед його обробкою будь-якою конкретною *операцією шляху* (*path operation*), а також з кожною **відповіддю** перед її поверненням.
+
+* Middleware отримує кожен **запит**, що надходить до Вашого застосунку.
+* Може виконати певні дії із цим **запитом** або запустити необхідний код.
+* Далі передає **запит** для обробки основним застосунком (*операцією шляху*).
+* Отримує **відповідь**, сформовану застосунком (*операцією шляху*).
+* Може змінити цю **відповідь** або виконати додатковий код.
+* Повертає **відповідь** клієнту.
+
+/// note | Технічні деталі
+
+Якщо у Вас є залежності з `yield`, код виходу виконається *після* middleware.
+
+Якщо були заплановані фонові задачі (background tasks - розглянуто далі), вони виконаються *після* всіх middleware.
+
+///
+
+## Створення middleware
+
+Щоб створити middleware, Ви використовуєте декоратор `@app.middleware("http")` на функції.
+
+Функція middleware отримує:
+
+* `Запит`.
+* Функцію `call_next`, яка приймає `запит` як параметр.
+ * Ця функція передає `запит` відповідній *операції шляху*.
+ * Потім вона повертає `відповідь`, згенеровану цією *операцією шляху*.
+
+* Ви можете ще змінити `відповідь` перед тим, як повернути її.
+
+
+{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *}
+
+/// tip | Порада
+
+Не забувайте, що власні заголовки можна додавати, використовуючи префікс 'X-'.
+
+Але якщо у Вас є власні заголовки, які Ви хочете, щоб браузерний клієнт міг побачити, потрібно додати їх до Вашої конфігурації CORS (див. [CORS (Обмін ресурсами між різними джерелами)](cors.md){.internal-link target=_blank} за допомогою параметра `expose_headers`, описаного в документації Starlette по CORS.
+
+///
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.requests import Request`.
+
+**FastAPI** надає це для Вашої зручності як розробника. Але він походить безпосередньо зі Starlette.
+
+///
+
+### До і після `response`(`відповіді`)
+
+Ви можете додати код, який буде виконуватися з `запитом` (`request`), до того, як його обробить будь-яка *операція шляху* (*path operation*).
+
+Також Ви можете додати код, який буде виконуватися після того, як `відповідь` (`response`) буде згенеровано, перед тим як його повернути.
+
+Наприклад, Ви можете додати власний заголовок `X-Process-Time`, який міститиме час у секундах, який витратився на обробку запиту та генерацію відповіді:
+
+{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *}
+
+
+/// tip | Підказка
+
+Тут ми використовуємо `time.perf_counter()` замість `time.time()` оскільки він може бути більш точним для таких випадків. 🤓
+
+///
+
+## Інші middlewares
+
+Ви можете пізніше прочитати більше про інші middlewares в [Advanced User Guide: Advanced Middleware](../advanced/middleware.md){.internal-link target=_blank}.
+
+Ви дізнаєтесь, як обробляти CORS за допомогою middleware в наступному розділі.
diff --git a/docs/uk/docs/tutorial/path-params-numeric-validations.md b/docs/uk/docs/tutorial/path-params-numeric-validations.md
new file mode 100644
index 000000000..281ee183c
--- /dev/null
+++ b/docs/uk/docs/tutorial/path-params-numeric-validations.md
@@ -0,0 +1,165 @@
+# Path Параметри та валідація числових даних
+
+Так само як Ви можете оголошувати додаткові перевірки та метадані для query параметрів за допомогою `Query`, Ви можете оголошувати той самий тип перевірок і метаданих для параметрів шляху за допомогою `Path`.
+
+## Імпорт Path
+
+Спочатку імпортуйте `Path` з `fastapi` і імпортуйте `Annotated`:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}
+
+/// info | Інформація
+
+FastAPI додав підтримку `Annotated` (і почав рекомендувати його використання) у версії 0.95.0.
+
+Якщо у Вас стара версія, при спробі використати `Annotated` можуть виникати помилки.
+
+Переконайтеся, що Ви [оновили версію FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} принаймні до версії 0.95.1 перед використанням `Annotated`.
+
+///
+
+## Оголошення метаданих
+
+Ви можете оголошувати всі ті ж параметри, що і для `Query`.
+
+Наприклад, щоб оголосити значення метаданих `title` для параметра шляху `item_id`, Ви можете написати:
+
+{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}
+
+/// note | Примітка
+
+Параметр шляху завжди є обов’язковим, оскільки він має бути частиною шляху. Навіть якщо Ви оголосите його зі значенням `None` або встановите значення за замовчуванням — він все одно залишатиметься обов’язковим.
+
+///
+
+## Упорядковуйте параметри, як Вам потрібно
+
+/// tip | Підказка
+
+Це, мабуть, не настільки важливо або необхідно, якщо Ви використовуєте `Annotated`.
+
+///
+
+Припустимо, Ви хочете оголосити параметр запиту `q` як обов’язковий `str`.
+
+І Вам не потрібно оголошувати нічого іншого для цього параметра, тому немає потреби використовувати `Query`.
+
+Але Вам все одно потрібно використовувати `Path` для параметра шляху `item_id`. І з певних причин Ви не хочете використовувати `Annotated`.
+
+Python видасть помилку, якщо розмістити значення з "default" перед значенням, яке не має "default".
+
+Але Ви можете змінити порядок і розмістити значення без значення за замовчуванням (параметр запиту `q`) першим.
+
+
+Для **FastAPI** порядок не має значення. Він визначає параметри за їх іменами, типами та значеннями за замовчуванням (`Query`, `Path` тощо) і не звертає уваги на порядок.
+
+Тому Ви можете оголосити Вашу функцію так:
+
+//// tab | Python 3.8 non-Annotated
+
+/// tip | Підказка
+
+За можливості віддавайте перевагу версії з використанням `Annotated`.
+
+///
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *}
+
+////
+
+Але майте на увазі, що якщо Ви використовуєте `Annotated`, ця проблема не виникне, оскільки Ви не використовуєте значення за замовчуванням для параметрів `Query()` або `Path()`.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
+
+## Упорядковуйте параметри за потребою, хитрощі
+
+/// tip | Підказка
+
+Це, мабуть, не настільки важливо або необхідно, якщо Ви використовуєте `Annotated`.
+
+///
+
+Ось **невелика хитрість**, яка може стати в пригоді, хоча вона рідко знадобиться.
+
+Якщо Ви хочете:
+
+* оголосити параметр запиту `q` без використання `Query` або значення за замовчуванням
+* оголосити параметр шляху `item_id`, використовуючи `Path`
+* розмістити їх у різному порядку
+* не використовувати `Annotated`
+
+...у Python є спеціальний синтаксис для цього.
+
+Передайте `*` як перший параметр функції.
+
+Python нічого не зробить із цією `*`, але розпізнає, що всі наступні параметри слід викликати як аргументи за ключовим словом (пари ключ-значення), також відомі як kwargs. Навіть якщо вони не мають значення за замовчуванням.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *}
+
+### Краще з `Annotated`
+
+Майте на увазі, якщо Ви використовуєте `Annotated`, оскільки Ви не використовуєте значення за замовчуванням для параметрів функції, цієї проблеми не виникне, і, швидше за все, Вам не потрібно буде використовувати `*`.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *}
+
+## Валідація числових даних: більше або дорівнює
+
+За допомогою `Query` і `Path` (та інших, які Ви побачите пізніше) можна оголошувати числові обмеження.
+
+Тут, завдяки `ge=1`, `item_id` має бути цілим числом, яке "`g`reater than or `e`qual" (більше або дорівнює) `1`.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
+
+## Валідація числових даних: більше ніж і менше або дорівнює
+
+Те саме застосовується до:
+
+* `gt`: `g`reater `t`han (більше ніж)
+* `le`: `l`ess than or `e`qual (менше або дорівнює)
+
+{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *}
+
+## Валідація числових даних: float, більше ніж і менше ніж
+
+Валідація чисел також працює для значень типу `float`.
+
+Ось де стає важливо мати можливість оголошувати gt, а не тільки ge. Це дозволяє, наприклад, вимагати, щоб значення було більше `0`, навіть якщо воно менше `1`.
+
+Таким чином, значення `0.5` буде допустимим. Але `0.0` або `0` — ні.
+
+Те саме стосується lt.
+
+{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *}
+
+## Підсумок
+
+За допомогою `Query`, `Path` (і інших параметрів, які Ви ще не бачили) можна оголошувати метадані та перевірки рядків, так само як у [Query параметри та валідація рядків](query-params-str-validations.md){.internal-link target=_blank}.
+
+Також можна оголошувати числові перевірки:
+
+* `gt`: `g`reater `t`han (більше ніж)
+* `ge`: `g`reater than or `e`qual (більше або дорівнює)
+* `lt`: `l`ess `t`han (менше ніж)
+* `le`: `l`ess than or `e`qual (менше або дорівнює)
+
+/// info | Інформація
+
+`Query`, `Path` та інші класи, які Ви побачите пізніше, є підкласами спільного класу `Param`.
+
+Всі вони мають однакові параметри для додаткових перевірок і метаданих, які Ви вже бачили.
+
+///
+
+/// note | Технічні деталі
+
+Коли Ви імпортуєте `Query`, `Path` та інші з `fastapi`, насправді це функції.
+
+При виклику вони повертають екземпляри класів з такими ж іменами.
+
+Тобто Ви імпортуєте `Query`, яка є функцією. А коли Ви її викликаєте, вона повертає екземпляр класу, який теж називається `Query`.
+
+Ці функції створені таким чином (замість використання класів напряму), щоб Ваш редактор не відзначав їхні типи як помилки.
+
+Таким чином, Ви можете користуватися своїм звичайним редактором і інструментами для програмування без додаткових налаштувань для ігнорування таких помилок.
+
+///
diff --git a/docs/uk/docs/tutorial/path-params.md b/docs/uk/docs/tutorial/path-params.md
new file mode 100644
index 000000000..e7df1f19a
--- /dev/null
+++ b/docs/uk/docs/tutorial/path-params.md
@@ -0,0 +1,261 @@
+# Path Параметри
+
+Ви можете визначити "параметри" або "змінні" шляху, використовуючи синтаксис форматованих рядків:
+
+{* ../../docs_src/path_params/tutorial001.py hl[6:7] *}
+
+Значення параметра шляху `item_id` передається у функцію як аргумент `item_id`.
+
+Якщо запустити цей приклад та перейти за посиланням http://127.0.0.1:8000/items/foo, то отримаємо таку відповідь:
+
+```JSON
+{"item_id":"foo"}
+```
+
+## Path параметри з типами
+
+Ви можете визначити тип параметра шляху у функції, використовуючи стандартні анотації типів Python:
+
+{* ../../docs_src/path_params/tutorial002.py hl[7] *}
+
+У такому випадку `item_id` визначається як `int`.
+
+/// check | Примітка
+
+Це дасть можливість підтримки редактора всередині функції з перевірками помилок, автодоповнення тощо.
+
+///
+
+## Перетворення даних
+
+Якщо запустити цей приклад і перейти за посиланням http://127.0.0.1:8000/items/3, то отримаєте таку відповідь:
+
+```JSON
+{"item_id":3}
+```
+
+/// check | Примітка
+
+Зверніть увагу, що значення, яке отримала (і повернула) ваша функція, — це `3`. Це Python `int`, а не рядок `"3"`.
+
+Отже, з таким оголошенням типу **FastAPI** автоматично виконує "парсинг" запитів.
+
+///
+
+## Перевірка даних
+
+Якщо ж відкрити у браузері посилання http://127.0.0.1:8000/items/foo, то побачимо цікаву HTTP-помилку:
+
+```JSON
+{
+ "detail": [
+ {
+ "type": "int_parsing",
+ "loc": [
+ "path",
+ "item_id"
+ ],
+ "msg": "Input should be a valid integer, unable to parse string as an integer",
+ "input": "foo",
+ "url": "https://errors.pydantic.dev/2.1/v/int_parsing"
+ }
+ ]
+}
+```
+тому що параметр шляху має значення `"foo"`, яке не є типом `int`.
+
+Таку саму помилку отримаємо, якщо передати `float` замість `int`, як бачимо, у цьому прикладі: http://127.0.0.1:8000/items/4.2
+
+/// check | Примітка
+
+Отже, **FastAPI** надає перевірку типів з таким самим оголошенням типу в Python.
+
+Зверніть увагу, що помилка також чітко вказує саме на те місце, де валідація не пройшла.
+
+Це неймовірно корисно під час розробки та дебагінгу коду, що взаємодіє з вашим API.
+
+///
+
+## Документація
+
+Тепер коли відкриєте свій браузер за посиланням http://127.0.0.1:8000/docs, то побачите автоматично згенеровану, інтерактивну API-документацію:
+
+
+
+/// check | Примітка
+
+Знову ж таки, лише з цим самим оголошенням типу в Python, FastAPI надає вам автоматичну, інтерактивну документацію (з інтеграцією Swagger UI).
+
+Зверніть увагу, що параметр шляху оголошений як ціле число.
+
+
+///
+
+## Переваги стандартизації, альтернативна документація
+
+І оскільки згенерована схема відповідає стандарту OpenAPI, існує багато сумісних інструментів.
+
+З цієї причини FastAPI також надає альтернативну документацію API (використовуючи ReDoc), до якої можна отримати доступ за посиланням http://127.0.0.1:8000/redoc:
+
+
+
+Таким чином, існує багато сумісних інструментів, включаючи інструменти для генерації коду для багатьох мов.
+
+
+## Pydantic
+
+Вся валідація даних виконується за лаштунками за допомогою Pydantic, тому Ви отримуєте всі переваги від його використання. І можете бути впевнені, що все в надійних руках.
+
+Ви можете використовувати ті самі оголошення типів з `str`, `float`, `bool` та багатьма іншими складними типами даних.
+
+Декілька з них будуть розглянуті в наступних розділах посібника.
+
+## Порядок має значення
+
+При створенні *операцій шляху* можуть виникати ситуації, коли шлях фіксований.
+
+Наприклад, `/users/me`. Припустимо, що це шлях для отримання даних про поточного користувача.
+
+А також у вас може бути шлях `/users/{user_id}`, щоб отримати дані про конкретного користувача за його ID.
+
+Оскільки *операції шляху* оцінюються по черзі, Ви повинні переконатися, що шлях для `/users/me` оголошений перед шляхом для `/users/{user_id}`:
+
+{* ../../docs_src/path_params/tutorial003.py hl[6,11] *}
+
+Інакше шлях для `/users/{user_id}` також буде відповідати для `/users/me`, "вважаючи", що він отримує параметр `user_id` зі значенням `"me"`.
+
+Аналогічно, Ви не можете оголосити операцію шляху:
+
+{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *}
+
+Перша операція буде завжди використовуватися, оскільки шлях збігається першим.
+## Попередньо визначені значення
+
+Якщо у вас є *операція шляху*, яка приймає *параметр шляху*, але Ви хочете, щоб можливі допустимі значення *параметра шляху* були попередньо визначені, Ви можете використати стандартний Python Enum.
+
+### Створення класу `Enum`
+
+Імпортуйте `Enum` і створіть підклас, що наслідується від `str` та `Enum`.
+
+Наслідуючи від `str`, документація API зможе визначити, що значення повинні бути типу `string`, і правильно їх відобразить.
+
+Після цього створіть атрибути класу з фіксованими значеннями, які будуть доступними допустимими значеннями:
+
+{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *}
+
+/// info | Додаткова інформація
+
+Перелічення (або enums) доступні в Python починаючи з версії 3.4.
+
+///
+
+/// tip | Порада
+
+Якщо вам цікаво, "AlexNet", "ResNet" та "LeNet" — це просто назви ML моделей Machine Learning.
+
+///
+
+
+### Оголосіть *параметр шляху*
+
+Потім створіть *параметр шляху* з анотацією типу, використовуючи створений вами клас enum (`ModelName`):
+
+{* ../../docs_src/path_params/tutorial005.py hl[16] *}
+
+### Перевірка документації
+
+Оскільки доступні значення для *параметра шляху* визначені заздалегідь, інтерактивна документація зможе красиво їх відобразити:
+
+
+
+### Робота з *перелічуваннями* у Python
+
+Значення *параметра шляху* буде елементом *перелічування*.
+
+#### Порівняння *елементів перелічування*
+
+Ви можете порівнювати його з *елементами перелічування* у створеному вами enum `ModelName`:
+
+{* ../../docs_src/path_params/tutorial005.py hl[17] *}
+
+#### Отримання *значення перелічування*
+
+Ви можете отримати фактичне значення (у цьому випадку це `str`), використовуючи `model_name.value`, або загалом `your_enum_member.value`:
+
+{* ../../docs_src/path_params/tutorial005.py hl[20] *}
+
+/// tip | Порада
+
+Ви також можете отримати доступ до значення `"lenet"`, використовуючи `ModelName.lenet.value`.
+
+///
+
+
+#### Повернення *елементів перелічування*
+
+Ви можете повертати *елементи перелічування* з вашої *операції шляху*, навіть вкладені у JSON-тіло (наприклад, `dict`).
+
+Вони будуть перетворені на відповідні значення (у цьому випадку рядки) перед поверненням клієнту:
+
+{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *}
+
+На стороні клієнта Ви отримаєте відповідь у форматі JSON, наприклад:
+
+```JSON
+{
+ "model_name": "alexnet",
+ "message": "Deep Learning FTW!"
+}
+```
+
+## Path-параметри, що містять шляхи
+
+Припустимо, у вас є *операція шляху* з маршрутом `/files/{file_path}`.
+
+Але вам потрібно, щоб `file_path` містив *шлях*, наприклад `home/johndoe/myfile.txt`.
+
+Отже, URL для цього файлу виглядатиме так: `/files/home/johndoe/myfile.txt`.
+
+
+
+### Підтримка OpenAPI
+
+OpenAPI не підтримує спосіб оголошення *параметра шляху*, що містить *шлях* всередині, оскільки це може призвести до сценаріїв, які складно тестувати та визначати.
+
+Однак (одначе), Ви все одно можете зробити це в **FastAPI**, використовуючи один із внутрішніх інструментів Starlette.
+
+Документація все ще працюватиме, хоча й не додаватиме опису про те, що параметр повинен містити шлях.
+
+### Конвертер шляху
+
+Використовуючи опцію безпосередньо зі Starlette, Ви можете оголосити *параметр шляху*, що містить *шлях*, використовуючи URL на кшталт:
+
+```
+/files/{file_path:path}
+```
+У цьому випадку ім'я параметра — `file_path`, а остання частина `:path` вказує на те, що параметр повинен відповідати будь-якому *шляху*.
+
+Отже, Ви можете використати його так:
+
+{* ../../docs_src/path_params/tutorial004.py hl[6] *}
+
+/// tip | Порада
+
+Вам може знадобитися, щоб параметр містив `/home/johndoe/myfile.txt` із початковою косою рискою (`/`).
+
+У такому випадку URL виглядатиме так: `/files//home/johndoe/myfile.txt`, із подвійною косою рискою (`//`) між `files` і `home`.
+
+///
+
+## Підсумок
+
+З **FastAPI**, використовуючи короткі, інтуїтивно зрозумілі та стандартні оголошення типів Python, Ви отримуєте:
+
+* Підтримку в редакторі: перевірка помилок, автодоповнення тощо.
+* "Парсинг" даних
+* Валідацію даних
+* Анотацію API та автоматичну документацію
+
+І вам потрібно оголосити їх лише один раз.
+
+Це, ймовірно, основна видима перевага **FastAPI** порівняно з альтернативними фреймворками (окрім високої продуктивності).
diff --git a/docs/uk/docs/tutorial/query-param-models.md b/docs/uk/docs/tutorial/query-param-models.md
new file mode 100644
index 000000000..97eb82fa1
--- /dev/null
+++ b/docs/uk/docs/tutorial/query-param-models.md
@@ -0,0 +1,68 @@
+# Моделі Query параметрів
+
+Якщо у Вас є група **query параметрів**, які пов’язані між собою, Ви можете створити **Pydantic-модель** для їх оголошення.
+
+Це дозволить Вам **повторно використовувати модель** у **різних місцях**, а також оголошувати перевірки та метадані для всіх параметрів одночасно. 😎
+
+/// note | Примітка
+
+Ця можливість підтримується, починаючи з версії FastAPI `0.115.0`. 🤓
+
+///
+
+## Query параметри з Pydantic-моделлю
+
+Оголосіть **query параметри**, які Вам потрібні, у **Pydantic-моделі**, а потім оголосіть цей параметр як `Query`:
+
+{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}
+
+**FastAPI** буде **витягувати** дані для **кожного поля** з **query параметрів** у запиті та передавати їх у визначену вами Pydantic-модель.
+
+## Перевірте документацію
+
+Ви можете побачити параметри запиту в UI документації за `/docs`:
+
+
+
+
+
+## Заборона зайвих Query параметрів
+
+У деяких особливих випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** query параметри, які дозволено отримувати.
+
+Ви можете використати конфігурацію моделі Pydantic, щоб заборонити (`forbid`) будь-які зайві (`extra`) поля:
+
+{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}
+
+Якщо клієнт спробує надіслати **зайві** дані у **query параметрах**, він отримає **помилку**.
+
+Наприклад, якщо клієнт спробує надіслати query параметр `tool` зі значенням `plumbus`, як у цьому запиті:
+
+```http
+https://example.com/items/?limit=10&tool=plumbus
+```
+
+Він отримає відповідь з **помилкою**, яка повідомить, що query параметр `tool ` не дозволено:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["query", "tool"],
+ "msg": "Extra inputs are not permitted",
+ "input": "plumbus"
+ }
+ ]
+}
+```
+
+## Підсумок
+
+Ви можете використовувати **Pydantic-моделі** для оголошення **query параметрів** у **FastAPI**. 😎
+
+/// tip | Підказка
+
+Спойлер: Ви також можете використовувати Pydantic-моделі для оголошення cookie та заголовків, але про це Ви дізнаєтеся пізніше в цьому посібнику. 🤫
+
+///
diff --git a/docs/uk/docs/tutorial/query-params-str-validations.md b/docs/uk/docs/tutorial/query-params-str-validations.md
new file mode 100644
index 000000000..cd3f4ad93
--- /dev/null
+++ b/docs/uk/docs/tutorial/query-params-str-validations.md
@@ -0,0 +1,491 @@
+# Query параметри та валідація рядків
+
+**FastAPI** дозволяє оголошувати додаткову інформацію та виконувати валідацію для Ваших параметрів.
+
+Розглянемо цей додаток як приклад:
+
+{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
+
+Query параметр `q` має тип `str | None`, що означає, що він може бути як `str`, так і `None`. За замовчуванням він має значення `None`, тому FastAPI розуміє, що цей параметр не є обов'язковим.
+
+/// note | Примітка
+
+FastAPI знає, що `q` не є обов’язковим, завдяки значенню за замовчуванням `= None`.
+
+Використання `str | None` дозволить Вашому редактору коду надавати кращу підтримку та виявляти помилки.
+
+///
+
+## Додаткова валідація
+
+Ми хочемо, щоб навіть якщо `q` є необов’язковим, **його довжина не перевищувала 50 символів**, якщо він все ж буде переданий.
+
+### Імпорт `Query` та `Annotated`
+
+Щоб це зробити, спочатку імпортуємо:
+
+* `Query` з `fastapi`
+* `Annotated` з `typing`
+
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
+
+/// info | Інформація
+
+FastAPI додав підтримку `Annotated` (і почав рекомендувати його) у версії 0.95.0.
+
+Якщо у Вас старіша версія, під час використання `Annotated` можуть виникати помилки.
+
+Переконайтеся, що Ви [оновили версію FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} до принаймні 0.95.1, перш ніж використовувати `Annotated`.
+
+///
+
+## Використання `Annotated` у типі параметра `q`
+
+Пам’ятаєте, як я раніше розповідав, що `Annotated` можна використовувати для додавання метаданих до параметрів у [Вступі до типів Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank}?
+
+Зараз саме час використати його разом із FastAPI. 🚀
+
+Раніше ми мали таку анотацію типу:
+
+//// tab | Python 3.10+
+
+```Python
+q: str | None = None
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+q: Union[str, None] = None
+```
+
+////
+
+Тепер ми загорнемо її у `Annotated`, і отримаємо:
+
+//// tab | Python 3.10+
+
+```Python
+q: Annotated[str | None] = None
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+q: Annotated[Union[str, None]] = None
+```
+
+////
+
+Обидві ці версії означають одне й те саме: `q` — це параметр, який може бути `str` або `None`, і за замовчуванням має значення `None`.
+
+А тепер переходимо до цікавого! 🎉
+
+## Додавання `Query` до `Annotated` у параметр `q`
+
+Тепер, коли у нас є `Annotated`, де ми можемо додавати додаткову інформацію (зокрема валідацію), додамо `Query` всередину `Annotated` і встановимо параметр `max_length` у `50`:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
+
+Зверніть увагу, що значення за замовчуванням усе ще `None`, тому параметр залишається необов'язковим.
+
+Але тепер, додавши `Query(max_length=50)` всередину `Annotated`, ми повідомляємо FastAPI, що хочемо **додаткову валідацію** для цього значення — воно має містити максимум 50 символів. 😎
+
+/// tip | Підказка
+
+Ми використовуємо `Query()`, оскільки це **query параметр**. Далі ми розглянемо інші варіанти, як-от `Path()`, `Body()`, `Header()` та `Cookie()`, які приймають ті самі аргументи, що й `Query()`.
+
+///
+
+Тепер FastAPI:
+
+* **Перевірить** дані, щоб переконатися, що їхня довжина не перевищує 50 символів
+* Покажe **чітку помилку** клієнту, якщо дані недійсні
+* **Задокументує** параметр в OpenAPI-схемі *операції шляху* (що відобразиться в **автоматично згенерованій документації**)
+
+## Альтернативний (застарілий) метод: Query як значення за замовчуванням
+
+У попередніх версіях FastAPI (до 0.95.0) `Query` використовувався як значення за замовчуванням для параметра, а не всередині `Annotated`. Ви, ймовірно, побачите код, який використовує цей підхід, тому варто розглянути його.
+
+/// tip | Підказка
+
+Для нового коду та коли це можливо, використовуйте `Annotated`, як показано вище. Це має багато переваг (пояснених нижче) і не має недоліків. 🍰
+
+///
+
+Раніше ми писали `Query()` як значення за замовчуванням для параметра функції, встановлюючи `max_length` у 50:
+
+{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
+
+Оскільки в цьому випадку (без `Annotated`) нам потрібно замінити `None` у функції на `Query()`, тепер ми повинні явно встановити значення за замовчуванням через параметр `Query(default=None)`. Це виконує ту саму роль визначення значення за замовчуванням (принаймні для FastAPI).
+
+Таким чином:
+
+```Python
+q: str | None = Query(default=None)
+```
+
+...робить параметр необов’язковим зі значенням за замовчуванням `None`, що еквівалентно:
+
+
+```Python
+q: str | None = None
+```
+Але у версії з `Query` ми явно вказуємо, що це query параметр.
+
+Далі ми можемо передавати `Query` додаткові параметри, зокрема `max_length`, який застосовується до рядків:
+
+```Python
+q: str | None = Query(default=None, max_length=50)
+```
+
+Це забезпечить валідацію даних, виведе зрозумілу помилку у разі недійсних даних і задокументує параметр у схемі OpenAPI *операції шляху*.
+
+### `Query` як значення за замовчуванням або всередині `Annotated`
+
+Важливо пам’ятати, якщо використовувати `Query` всередині `Annotated`, не можна задавати параметр `default` у `Query`.
+
+Замість цього використовуйте значення за замовчуванням у самій функції. Інакше це буде нелогічно.
+
+Наприклад, цей варіант є некоректним:
+
+```Python
+q: Annotated[str, Query(default="rick")] = "morty"
+```
+
+...тому, що не зрозуміло, яке значення має бути значенням за замовчуванням: `"rick"` чи `"morty"`.
+
+Коректні варіанти:
+
+```Python
+q: Annotated[str, Query()] = "rick"
+```
+
+...або у старих кодових базах Ви знайдете:
+
+```Python
+q: str = Query(default="rick")
+```
+
+### Переваги використання `Annotated`
+
+**Використання `Annotated` є рекомендованим** замість задання значення за замовчуванням у параметрах функції, оскільки воно **краще** з кількох причин. 🤓
+
+Значення **за замовчуванням** параметра **функції** є його **фактичним значенням за замовчуванням**, що є більш інтуїтивним у Python загалом. 😌
+
+Ви можете **викликати** ту саму функцію **в інших місцях** без FastAPI, і вона **працюватиме очікувано**. Якщо параметр є **обов’язковим** (без значення за замовчуванням), Ваш **редактор** повідомить про помилку, а **Python** також видасть помилку, якщо Ви виконаєте функцію без передавання цього параметра.
+
+Якщо Ви не використовуєте `Annotated`, а використовуєте **(старий) стиль значень за замовчуванням**, то при виклику цієї функції без FastAPI **в інших місцях**, потрібно **не забути** передати їй аргументи, інакше значення будуть відрізнятися від очікуваних (наприклад, Ви отримаєте `QueryInfo` або подібне замість `str`). Ваш редактор не повідомить про помилку, і Python також не видасть помилку при запуску функції, поки не виникне помилка під час виконання операцій усередині.
+
+Оскільки `Annotated` може містити кілька анотацій метаданих, Ви навіть можете використовувати ту саму функцію з іншими інструментами, такими як Typer. 🚀
+
+## Додавання додаткових валідацій
+
+Ви також можете додати параметр `min_length`:
+
+{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
+
+## Додавання регулярних виразів
+
+Ви можете визначити регулярний вираз pattern, якому має відповідати параметр:
+
+{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
+
+Цей конкретний шаблон регулярного виразу перевіряє, що отримане значення параметра:
+
+* `^`: починається з наступних символів, перед якими немає інших символів.
+* `fixedquery`: точно відповідає значенню `fixedquery`.
+* `$`: закінчується тут, після `fixedquery` немає жодних символів.
+
+Якщо Ви почуваєтеся розгублено щодо **"регулярних виразів"**, не хвилюйтеся. Вони є складною темою для багатьох людей. Ви все одно можете зробити багато речей без їх використання.
+
+Але тепер Ви знаєте, що коли вони знадобляться, їх можна застосовувати у **FastAPI**.
+
+### Pydantic v1 `regex` замість `pattern`
+
+До версії Pydantic 2 і FastAPI 0.100.0 параметр називався `regex` замість `pattern`, але тепер він застарів.
+
+Ви все ще можете зустріти код, який використовує його:
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
+
+////
+
+Але майте на увазі, що він є застарілим і його слід оновити до нового параметра `pattern`. 🤓
+
+## Значення за замовчуванням
+
+Ви можете використовувати значення за замовчуванням, відмінні від `None`.
+
+Наприклад, якщо Ви хочете оголосити параметр запиту `q` з `min_length` `3` і значенням за замовчуванням `"fixedquery"`:
+
+{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
+
+/// note | Технічні деталі
+
+Наявність значення за замовчуванням будь-якого типу, включаючи `None`, робить параметр необов’язковим (not required).
+
+///
+
+## Обов’язкові параметри
+
+Якщо нам не потрібно вказувати додаткові перевірки або метадані, ми можемо зробити параметр `q` обов’язковим, просто не оголошуючи значення за замовчуванням, наприклад:
+
+```Python
+q: str
+```
+
+замість:
+
+```Python
+q: str | None = None
+```
+
+Але тепер ми оголошуємо його з `Query`, наприклад:
+
+//// tab | Annotated
+
+```Python
+q: Annotated[str | None, Query(min_length=3)] = None
+```
+
+////
+
+Тому, якщо Вам потрібно зробити значення обов’язковим, використовуючи `Query`, просто не вказуйте значення за замовчуванням:
+
+{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
+
+### Обов’язкове значення, яке може бути `None`
+
+Ви можете вказати, що параметр може приймати `None`, але при цьому залишається обов’язковим. Це змусить клієнтів надіслати значення, навіть якщо воно дорівнює `None`.
+
+Щоб зробити це, оголосіть, що `None` є допустимим типом, але не вказуйте значення за замовчуванням:
+
+{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
+
+## Список параметрів запиту / кілька значень
+
+Якщо Ви визначаєте параметр запиту за допомогою `Query`, Ви також можете дозволити отримання списку значень, тобто дозволити отримання кількох значень.
+
+Наприклад, щоб дозволити параметру запиту `q` з'являтися кілька разів в URL, можна написати:
+
+{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
+
+Тоді, у випадку запиту за URL:
+
+```
+http://localhost:8000/items/?q=foo&q=bar
+```
+
+Ви отримаєте кілька значень *query параметра* `q` (`foo` і `bar`) у вигляді списку `list` в Python у Вашій *функції обробки шляху*, у *параметрі функції* `q`.
+
+Отже, відповідь на цей URL буде:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+/// tip | Підказка
+
+Щоб оголосити параметр запиту з типом `list`, як у наведеному вище прикладі, потрібно явно використовувати `Query`, інакше він буде інтерпретований як тіло запиту.
+
+///
+
+Інтерактивна API-документація оновиться відповідно, дозволяючи передавати кілька значень:
+
+
+
+### Список параметрів запиту / кілька значень за замовчуванням
+
+Ви також можете визначити значення за замовчуванням для `list`, якщо жодне значення не було передане:
+
+{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
+
+Якщо Ви перейдете за посиланням:
+
+```
+http://localhost:8000/items/
+```
+
+то значення `q` за замовчуванням буде: `["foo", "bar"]`, і Ваша відповідь виглядатиме так:
+
+```JSON
+{
+ "q": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+#### Використання тільки `list`
+
+Ви також можете використовувати `list` без уточнення типу, замість `list[str]`:
+
+{* ../../docs_src/query_params_str_validations/tutorial013_an_py39.py hl[9] *}
+
+/// note | Технічні деталі
+
+Майте на увазі, що в цьому випадку FastAPI не перевірятиме вміст списку.
+
+Наприклад, `list[int]` перевірятиме (і документуватиме), що всі елементи списку є цілими числами. Але `list` без уточнення цього не робитиме.
+
+///
+
+## Додавання додаткових метаданих
+
+Ви можете додати більше інформації про параметр.
+
+Ця інформація буде включена у згенерований OpenAPI та використана в інтерфейсах документації та зовнішніх інструментах.
+
+/// note | Технічні деталі
+
+Майте на увазі, що різні інструменти можуть мати різний рівень підтримки OpenAPI.
+
+Деякі з них можуть ще не відображати всю додаткову інформацію, хоча в більшості випадків ця функція вже запланована для розробки.
+
+///
+
+Ви можете додати `title` :
+
+{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}
+
+А також `description`:
+
+{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
+
+## Аліаси параметрів
+
+Уявіть, що Ви хочете, щоб параметр називався `item-query`.
+
+Наприклад:
+
+```
+http://127.0.0.1:8000/items/?item-query=foobaritems
+```
+
+Але `item-query` — це некоректна назва змінної в Python.
+
+Найближчий допустимий варіант — `item_query`.
+
+Проте Вам потрібно, щоб параметр залишався саме `item-query`...
+
+У такому випадку можна оголосити `alias`, і саме він буде використовуватися для отримання значення параметра:
+
+{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}
+
+## Виведення параметрів як застарілих
+
+Припустимо, що Ви більше не хочете використовувати цей параметр.
+
+Вам потрібно залишити його на деякий час, оскільки ним користуються клієнти, але Ви хочете, щоб документація чітко показувала, що він є застарілим.
+
+Тоді Ви можете передати параметр `deprecated=True` до `Query`:
+
+{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
+
+Документація буде показувати це таким чином:
+
+
+
+## Виняток параметрів з OpenAPI
+
+Щоб виключити параметр запиту зі згенерованої схеми OpenAPI (і, таким чином, з автоматичних систем документації), встановіть параметр `include_in_schema` для `Query` в `False`:
+
+{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}
+
+## Кастомна валідація
+
+Можуть бути випадки, коли Вам потрібно провести **кастомну валідацію**, яку не можна реалізувати за допомогою параметрів, показаних вище.
+
+У таких випадках ви можете використати **кастомну функцію валідації**, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`).
+
+Це можна досягти за допомогою Pydantic's `AfterValidator` в середині `Annotated`.
+
+/// tip | Підказка
+
+Pydantic також має `BeforeValidator` та інші. 🤓
+
+///
+
+Наприклад, цей кастомний валідатор перевіряє, чи починається ID елемента з `isbn-` для номера книги ISBN або з `imdb-` для ID URL фільму на IMDB:
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
+
+/// info | Інформація
+
+Це доступно з версії Pydantic 2 або вище. 😎
+
+///
+
+/// tip | Підказка
+
+Якщо Вам потрібно виконати будь-яку валідацію, яка вимагає взаємодії з будь-яким **зовнішнім компонентом**, таким як база даних чи інший API, ви повинні замість цього використовувати **FastAPI Dependencies**. Ви дізнаєтесь про них пізніше.
+
+Ці кастомні валідатори використовуються для речей, які можна перевірити лише з **тими даними**, що надані в запиті.
+
+///
+
+### Зрозумійте цей код
+
+Головний момент – це використання **`AfterValidator` з функцією всередині `Annotated`**. Можете пропустити цю частину, якщо хочете. 🤸
+
+---
+
+Але якщо Вам цікаво розібратися в цьому конкретному прикладі коду і Вам ще не набридло, ось кілька додаткових деталей.
+
+#### Рядок із `value.startswith()`
+
+Звернули увагу? Рядок із `value.startswith()` може приймати кортеж, і тоді він перевірятиме кожне значення в кортежі:
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
+
+#### Випадковий елемент
+
+За допомогою `data.items()` ми отримуємо ітерабельний об'єкт із кортежами, що містять ключ і значення для кожного елемента словника.
+
+Ми перетворюємо цей ітерабельний об'єкт у звичайний `list` за допомогою `list(data.items())`.
+
+Потім, використовуючи `random.choice()`, ми можемо отримати випадкове значення зі списку, тобто отримуємо кортеж із `(id, name)`. Це може бути щось на зразок `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
+
+Далі ми **присвоюємо ці два значення** кортежу змінним `id` і `name`.
+
+Тож, якщо користувач не вказав ID елемента, він все одно отримає випадкову рекомендацію.
+
+...і все це реалізовано в **одному рядку коду**. 🤯 Хіба не прекрасний Python? 🐍
+
+{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
+
+## Підсумок
+
+Ви можете оголошувати додаткові валідації та метаінформацію для своїх параметрів.
+
+Загальні валідації та метаінформація:
+
+* `alias`
+* `title`
+* `description`
+* `deprecated`
+
+Валідації, специфічні для рядків:
+
+* `min_length`
+* `max_length`
+* `pattern`
+
+Кастомні валідації за допомогою `AfterValidator`.
+
+У цих прикладах Ви побачили, як оголошувати валідації для значень `str`.
+
+Дивіться наступні розділи, щоб дізнатися, як оголошувати валідації для інших типів, наприклад чисел.
diff --git a/docs/uk/docs/tutorial/query-params.md b/docs/uk/docs/tutorial/query-params.md
new file mode 100644
index 000000000..16bb42af3
--- /dev/null
+++ b/docs/uk/docs/tutorial/query-params.md
@@ -0,0 +1,192 @@
+# Query Параметри
+
+Коли Ви оголошуєте інші параметри функції, які не є частиною параметрів шляху, вони автоматично інтерпретуються як "query" параметри.
+
+{* ../../docs_src/query_params/tutorial001.py hl[9] *}
+
+Query параметри — це набір пар ключ-значення, що йдуть після символу `?` в URL, розділені символами `&`.
+
+Наприклад, в URL:
+
+```
+http://127.0.0.1:8000/items/?skip=0&limit=10
+```
+
+...query параметрами є:
+
+* `skip`: зі значенням `0`
+* `limit`: зі значенням `10`
+
+Оскільки вони є частиною URL, вони "за замовчуванням" є рядками.
+
+Але коли Ви оголошуєте їх із типами Python (у наведеному прикладі як `int`), вони перетворюються на цей тип і проходять перевірку відповідності.
+
+Увесь той самий процес, який застосовується до параметрів шляху, також застосовується до query параметрів:
+
+* Підтримка в редакторі (автодоповнення, перевірка помилок)
+* "Парсинг" даних
+* Валідація даних
+* Автоматична документація
+
+
+## Значення за замовчуванням
+
+Оскільки query параметри не є фіксованою частиною шляху, вони можуть бути необов’язковими та мати значення за замовчуванням.
+
+У наведеному вище прикладі вони мають значення за замовчуванням: `skip=0` і `limit=10`.
+
+Отже, результат переходу за URL:
+
+```
+http://127.0.0.1:8000/items/
+```
+буде таким самим, як і перехід за посиланням:
+
+```
+http://127.0.0.1:8000/items/?skip=0&limit=10
+```
+
+Але якщо Ви перейдете, наприклад, за посиланням:
+
+```
+http://127.0.0.1:8000/items/?skip=20
+```
+
+Значення параметрів у вашій функції будуть такими:
+
+* `skip=20`: оскільки Ви вказали його в URL
+* `limit=10`: оскільки це значення за замовчуванням
+
+## Необов'язкові параметри
+
+Аналогічно, Ви можете оголосити необов’язкові query параметри, встановивши для них значення за замовчуванням `None`:
+
+{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
+
+У цьому випадку параметр функції `q` буде необов’язковим і за замовчуванням матиме значення `None`.
+
+/// check | Примітка
+
+Також зверніть увагу, що **FastAPI** достатньо розумний, щоб визначити, що параметр шляху `item_id` є параметром шляху, а `q` — ні, отже, це query параметр.
+
+///
+
+## Перетворення типу Query параметра
+
+Ви також можете оголошувати параметри типу `bool`, і вони будуть автоматично конвертовані:
+
+{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
+
+У цьому випадку, якщо Ви звернетесь до:
+
+
+```
+http://127.0.0.1:8000/items/foo?short=1
+```
+
+або
+
+```
+http://127.0.0.1:8000/items/foo?short=True
+```
+
+або
+
+```
+http://127.0.0.1:8000/items/foo?short=true
+```
+
+або
+
+```
+http://127.0.0.1:8000/items/foo?short=on
+```
+
+або
+
+```
+http://127.0.0.1:8000/items/foo?short=yes
+```
+
+або будь-який інший варіант написання (великі літери, перша літера велика тощо), ваша функція побачить параметр `short` зі значенням `True` з типом даних `bool`. В іншому випадку – `False`.
+
+## Кілька path і query параметрів
+
+Ви можете одночасно оголошувати кілька path і query параметрів, і **FastAPI** автоматично визначить, який з них до чого належить.
+
+
+Не потрібно дотримуватись певного порядку їх оголошення.
+
+Вони визначаються за назвою:
+
+{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
+
+## Обов’язкові Query параметри
+
+Якщо Ви оголошуєте значення за замовчуванням для параметрів, які не є path-параметрами (у цьому розділі ми бачили поки що лише path параметри), тоді вони стають необов’язковими.
+
+Якщо Ви не хочете вказувати конкретні значення, але хочете зробити параметр опціональним, задайте `None` як значення за замовчуванням.
+
+Але якщо Ви хочете зробити query параметр обов’язковим, просто не вказуйте для нього значення за замовчуванням:
+
+{* ../../docs_src/query_params/tutorial005.py hl[6:7] *}
+
+Тут `needy` – обов’язковий query параметр типу `str`.
+
+Якщо Ви відкриєте у браузері URL-адресу:
+
+```
+http://127.0.0.1:8000/items/foo-item
+```
+
+...без додавання обов’язкового параметра `needy`, Ви побачите помилку:
+
+```JSON
+{
+ "detail": [
+ {
+ "type": "missing",
+ "loc": [
+ "query",
+ "needy"
+ ],
+ "msg": "Field required",
+ "input": null,
+ "url": "https://errors.pydantic.dev/2.1/v/missing"
+ }
+ ]
+}
+```
+
+Оскільки `needy` є обов’язковим параметром, вам потрібно вказати його в URL:
+
+```
+http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
+```
+
+...цей запит поверне:
+
+```JSON
+{
+ "item_id": "foo-item",
+ "needy": "sooooneedy"
+}
+```
+
+
+Звичайно, Ви можете визначити деякі параметри як обов’язкові, інші зі значенням за замовчуванням, а ще деякі — повністю опціональні:
+
+{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
+
+У цьому випадку є 3 query параметри:
+
+* `needy`, обов’язковий `str`.
+* `skip`, `int` зі значенням за замовчуванням `0`.
+* `limit`, опціональний `int`.
+
+
+/// tip | Підказка
+
+Ви також можете використовувати `Enum`-и, так само як і з [Path Parameters](path-params.md#predefined-values){.internal-link target=_blank}.
+
+///
diff --git a/docs/uk/docs/tutorial/request-files.md b/docs/uk/docs/tutorial/request-files.md
new file mode 100644
index 000000000..18b7cc01c
--- /dev/null
+++ b/docs/uk/docs/tutorial/request-files.md
@@ -0,0 +1,175 @@
+# Запит файлів
+
+Ви можете визначити файли, які будуть завантажуватися клієнтом, використовуючи `File`.
+
+/// info | Інформація
+
+Щоб отримувати завантажені файли, спочатку встановіть python-multipart.
+
+Переконайтеся, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його та встановили пакет, наприклад:
+
+```console
+$ pip install python-multipart
+```
+
+Це необхідно, оскільки завантажені файли передаються у вигляді "форматованих даних форми".
+
+///
+
+## Імпорт `File`
+
+Імпортуйте `File` та `UploadFile` з `fastapi`:
+
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[3] *}
+
+## Визначення параметрів `File`
+
+Створіть параметри файлів так само як Ви б створювали `Body` або `Form`:
+
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[9] *}
+
+/// info | Інформація
+
+`File` — це клас, який безпосередньо успадковує `Form`.
+
+Але пам’ятайте, що коли Ви імпортуєте `Query`, `Path`, `File` та інші з `fastapi`, це насправді функції, які повертають спеціальні класи.
+
+///
+
+/// tip | Підказка
+
+Щоб оголосити тіла файлів, Вам потрібно використовувати `File`, тому що інакше параметри будуть інтерпретовані як параметри запиту або параметри тіла (JSON).
+
+///
+
+Файли будуть завантажені у вигляді "форматованих даних форми".
+
+Якщо Ви оголосите тип параметра функції обробника маршруту як `bytes`, **FastAPI** прочитає файл за Вас, і Ви отримаєте його вміст у вигляді `bytes`.
+
+Однак майте на увазі, що весь вміст буде збережено в пам'яті. Це працюватиме добре для малих файлів.
+
+Але в деяких випадках Вам може знадобитися `UploadFile`.
+
+## Параметри файлу з `UploadFile`
+
+Визначте параметр файлу з типом `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial001_an_py39.py hl[14] *}
+
+Використання `UploadFile` має кілька переваг перед `bytes`:
+
+* Вам не потрібно використовувати `File()` у значенні за замовчуванням параметра.
+* Використовується "буферизований" файл:
+ * Файл зберігається в пам'яті до досягнення певного обмеження, після чого він записується на диск.
+* Це означає, що він добре працює для великих файлів, таких як зображення, відео, великі двійкові файли тощо, не споживаючи всю пам'ять.
+Ви можете отримати метадані про завантажений файл.
+* Він має file-like `асинхронний файловий інтерфейс` interface.
+* Він надає фактичний об'єкт Python `SpooledTemporaryFile`, який можна передавати безпосередньо іншим бібліотекам.
+
+### `UploadFile`
+
+`UploadFile` має такі атрибути:
+
+* `filename`: Рядок `str` з оригінальною назвою файлу, який був завантажений (наприклад, `myimage.jpg`).
+* `content_type`: Рядок `str` з MIME-типом (наприклад, `image/jpeg`).
+* `file`: Об'єкт SpooledTemporaryFile (файлоподібний об'єкт). Це фактичний файловий об'єкт Python, який можна безпосередньо передавати іншим функціям або бібліотекам, що очікують "файлоподібний" об'єкт.
+
+`UploadFile` має такі асинхронні `async` методи. Вони викликають відповідні методи файлу під капотом (використовуючи внутрішній `SpooledTemporaryFile`).
+
+* `write(data)`: Записує `data` (`str` або `bytes`) у файл.
+* `read(size)`: Читає `size` (`int`) байтів/символів з файлу.
+* `seek(offset)`: Переміщується до позиції `offset` (`int`) у файлі.
+ * Наприклад, `await myfile.seek(0)` поверне курсор на початок файлу.
+ * This is especially useful if you run `await myfile.read()` once and then need to read the contents again. Це особливо корисно, якщо Ви виконуєте await `await myfile.read()` один раз, а потім потрібно знову прочитати вміст.
+* `close()`: Закриває файл.
+
+Оскільки всі ці методи є асинхронними `async`, Вам потрібно використовувати "await":
+
+Наприклад, всередині `async` *функції обробки шляху* Ви можете отримати вміст за допомогою:
+
+```Python
+contents = await myfile.read()
+```
+Якщо Ви знаходитесь у звичайній `def` *функції обробки шляху*, Ви можете отримати доступ до `UploadFile.file` безпосередньо, наприклад:
+
+```Python
+contents = myfile.file.read()
+```
+
+/// note | Технічні деталі `async`
+
+Коли Ви використовуєте `async` методи, **FastAPI** виконує файлові операції у пулі потоків та очікує їх завершення.
+
+///
+
+/// note | Технічні деталі Starlette
+
+`UploadFile` у **FastAPI** успадковується безпосередньо від `UploadFile` у **Starlette**, але додає деякі необхідні частини, щоб зробити його сумісним із **Pydantic** та іншими компонентами FastAPI.
+
+///
+
+## Що таке "Form Data"
+
+Спосіб, у який HTML-форми (``) надсилають дані на сервер, зазвичай використовує "спеціальне" кодування, відмінне від JSON.
+
+**FastAPI** забезпечує правильне зчитування цих даних з відповідної частини запиту, а не з JSON.
+
+/// note | Технічні деталі
+
+Дані з форм зазвичай кодуються за допомогою "media type" `application/x-www-form-urlencoded`, якщо вони не містять файлів.
+
+Але якщо форма містить файли, вона кодується у форматі `multipart/form-data`. Якщо Ви використовуєте `File`, **FastAPI** визначить, що потрібно отримати файли з відповідної частини тіла запиту.
+
+Щоб дізнатися більше про ці типи кодування та формові поля, ознайомтеся з документацією MDN щодо POST.
+
+///
+
+/// warning | Увага
+
+Ви можете оголосити кілька параметрів `File` і `Form` в *операції шляху*, але Ви не можете одночасно оголошувати поля `Body`, які мають надходити у форматі JSON, оскільки тіло запиту буде закодоване у форматі `multipart/form-data`, а не `application/json`.
+
+Це не обмеження **FastAPI**, а особливість протоколу HTTP.
+
+///
+
+## Опціональне Завантаження Файлів
+
+Файл можна зробити необов’язковим, використовуючи стандартні анотації типів і встановлюючи значення за замовчуванням `None`:
+
+{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}
+
+## `UploadFile` із Додатковими Мета Даними
+
+Ви також можете використовувати `File()` разом із `UploadFile`, наприклад, для встановлення додаткових метаданих:
+
+{* ../../docs_src/request_files/tutorial001_03_an_py39.py hl[9,15] *}
+
+## Завантаження Кількох Файлів
+
+Можна завантажувати кілька файлів одночасно.
+
+Вони будуть пов’язані з одним і тим самим "form field", який передається у вигляді "form data".
+
+Щоб це реалізувати, потрібно оголосити список `bytes` або `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial002_an_py39.py hl[10,15] *}
+
+Ви отримаєте, як і було оголошено, `list` із `bytes` або `UploadFile`.
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette.responses import HTMLResponse`.
+
+**FastAPI** надає ті ж самі `starlette.responses`, що й `fastapi.responses`, для зручності розробників. Однак більшість доступних відповідей надходять безпосередньо від Starlette.
+
+///
+
+### Завантаження декількох файлів із додатковими метаданими
+
+Так само як і раніше, Ви можете використовувати `File()`, щоб встановити додаткові параметри навіть для `UploadFile`:
+
+{* ../../docs_src/request_files/tutorial003_an_py39.py hl[11,18:20] *}
+
+## Підсумок
+
+Використовуйте `File`, `bytes`та `UploadFile`, щоб оголошувати файли для завантаження у запитах, які надсилаються у вигляді form data.
diff --git a/docs/uk/docs/tutorial/request-form-models.md b/docs/uk/docs/tutorial/request-form-models.md
new file mode 100644
index 000000000..7f5759e79
--- /dev/null
+++ b/docs/uk/docs/tutorial/request-form-models.md
@@ -0,0 +1,78 @@
+# Моделі форм (Form Models)
+
+У FastAPI Ви можете використовувати **Pydantic-моделі** для оголошення **полів форми**.
+
+/// info | Інформація
+
+Щоб використовувати форми, спочатку встановіть python-multipart.
+
+Переконайтеся, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили бібліотеку, наприклад:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+/// note | Підказка
+
+Ця функція підтримується, починаючи з FastAPI версії `0.113.0`. 🤓
+
+///
+
+## Використання Pydantic-моделей для форм
+
+Вам просто потрібно оголосити **Pydantic-модель** з полями, які Ви хочете отримати як **поля форми**, а потім оголосити параметр як `Form`:
+
+{* ../../docs_src/request_form_models/tutorial001_an_py39.py hl[9:11,15] *}
+
+**FastAPI** **витягне** дані для **кожного поля** з **формових даних** у запиті та надасть вам Pydantic-модель, яку Ви визначили.
+
+## Перевірка документації
+
+Ви можете перевірити це в UI документації за `/docs`:
+
+
+
+
+
+## Заборона додаткових полів форми
+
+У деяких особливих випадках (ймовірно, рідко) Ви можете **обмежити** форму лише тими полями, які були оголошені в Pydantic-моделі, і **заборонити** будь-які **додаткові** поля.
+
+/// note | Підказка
+
+Ця функція підтримується, починаючи з FastAPI версії `0.114.0`. 🤓
+
+///
+
+Ви можете використати конфігурацію Pydantic-моделі, щоб заборонити `forbid` будь-які додаткові `extra` поля:
+
+{* ../../docs_src/request_form_models/tutorial002_an_py39.py hl[12] *}
+
+Якщо клієнт спробує надіслати додаткові дані, він отримає **відповідь з помилкою**.
+
+Наприклад, якщо клієнт спробує надіслати наступні поля форми:
+
+* `username`: `Rick`
+* `password`: `Portal Gun`
+* `extra`: `Mr. Poopybutthole`
+
+Він отримає відповідь із помилкою, яка повідомляє, що поле `extra` не дозволено:
+
+```json
+{
+ "detail": [
+ {
+ "type": "extra_forbidden",
+ "loc": ["body", "extra"],
+ "msg": "Extra inputs are not permitted",
+ "input": "Mr. Poopybutthole"
+ }
+ ]
+}
+```
+
+## Підсумок
+
+Ви можете використовувати Pydantic-моделі для оголошення полів форми у FastAPI. 😎
diff --git a/docs/uk/docs/tutorial/request-forms-and-files.md b/docs/uk/docs/tutorial/request-forms-and-files.md
new file mode 100644
index 000000000..a089ef945
--- /dev/null
+++ b/docs/uk/docs/tutorial/request-forms-and-files.md
@@ -0,0 +1,41 @@
+# Запити з формами та файлами
+
+У FastAPI Ви можете одночасно отримувати файли та поля форми, використовуючи `File` і `Form`.
+
+/// info | Інформація
+
+Щоб отримувати завантажені файли та/або дані форми, спочатку встановіть python-multipart.
+
+Переконайтеся, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили бібліотеку, наприклад:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+## Імпорт `File` та `Form`
+
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[3] *}
+
+## Оголошення параметрів `File` та `Form`
+
+Створіть параметри файлів та форми так само як і для `Body` або `Query`:
+
+{* ../../docs_src/request_forms_and_files/tutorial001_an_py39.py hl[10:12] *}
+
+Файли та поля форми будуть завантажені як формові дані, і Ви отримаєте як файли, так і введені користувачем поля.
+
+Ви також можете оголосити деякі файли як `bytes`, а деякі як `UploadFile`.
+
+/// warning | Увага
+
+Ви можете оголосити кілька параметрів `File` і `Form` в операції *шляху*, але не можете одночасно оголошувати `Body`-поля, які очікуєте отримати у форматі JSON, оскільки запит матиме тіло, закодоване за допомогою `multipart/form-data`, а не `application/json`.
+
+Це не обмеження **FastAPI**, а частина протоколу HTTP.
+
+///
+
+## Підсумок
+
+Використовуйте `File` та `Form` разом, коли вам потрібно отримувати дані форми та файли в одному запиті.
diff --git a/docs/uk/docs/tutorial/request-forms.md b/docs/uk/docs/tutorial/request-forms.md
new file mode 100644
index 000000000..10c58a73e
--- /dev/null
+++ b/docs/uk/docs/tutorial/request-forms.md
@@ -0,0 +1,73 @@
+# Дані форми
+
+Якщо Вам потрібно отримувати поля форми замість JSON, Ви можете використовувати `Form`.
+
+/// info | Інформація
+
+Щоб використовувати форми, спочатку встановіть `python-multipart`.
+
+Переконайтеся, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, і потім встановили бібліотеку, наприклад:
+
+```console
+$ pip install python-multipart
+```
+
+///
+
+## Імпорт `Form`
+
+Імпортуйте `Form` з `fastapi`:
+
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[3] *}
+
+## Оголошення параметрів `Form`
+
+Створюйте параметри форми так само як Ви б створювали `Body` або `Query`:
+
+{* ../../docs_src/request_forms/tutorial001_an_py39.py hl[9] *}
+
+Наприклад, один зі способів використання специфікації OAuth2 (так званий "password flow") вимагає надсилати `username` та `password` як поля форми.
+
+spec вимагає, щоб ці поля мали точні назви `username` і `password` та надсилалися у вигляді полів форми, а не JSON.
+
+З `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/uk/docs/tutorial/response-status-code.md b/docs/uk/docs/tutorial/response-status-code.md
new file mode 100644
index 000000000..1ed69d6f2
--- /dev/null
+++ b/docs/uk/docs/tutorial/response-status-code.md
@@ -0,0 +1,100 @@
+# Статус коди Відповідей
+
+Так само як Ви можете вказати модель відповіді, Ви також можете оголосити HTTP код статусу для відповіді за допомогою параметра `status_code` в будь-якій з *операцій шляху*:
+
+* `@app.get()`
+* `@app.post()`
+* `@app.put()`
+* `@app.delete()`
+* тощо.
+
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
+
+/// note | Нотатка
+
+Зверніть увагу, що `status_code` є параметром методу "декоратора" (`get`, `post` і т.д.), а не Вашої *функції операції шляху*, як усі інші параметри та тіло запиту.
+
+///
+
+Параметр `status_code` приймає число, яке відповідає HTTP коду статусу.
+
+/// info | Інформація
+`status_code` також може отримувати значення з `IntEnum`, наприклад, з Python `http.HTTPStatus`.
+
+///
+
+Він буде:
+
+* Повертати вказаний код статусу у відповіді.
+* Документувати його як такий у схемі OpenAPI (і, таким чином, в інтерфейсі користувача):
+
+
+
+/// note | Нотатка
+
+Деякі коди відповіді (див. наступний розділ) вказують, що відповідь не має тіла.
+
+FastAPI знає про це і створить OpenAPI документацію, яка вказує, що тіла відповіді немає.
+
+///
+
+## Про HTTP статус коди
+
+/// note | Нотатка
+
+Якщо Ви вже знаєте, що таке HTTP коди статусу, переходьте до наступного розділу.
+
+///
+
+В HTTP Ви надсилаєте числовий код статусу з 3 цифр як частину відповіді.
+
+Ці коди статусу мають пов’язану назву для їх розпізнавання, але найважливішою частиною є саме число.
+
+Коротко:
+
+* **`100 - 199`** "Інформаційні" відповіді. Ви рідко використовуєте їх напряму. Відповіді з такими кодами не можуть мати тіла.
+* **`200 - 299`** "Успішні" відповіді. Це ті, які Ви використовуватимете найчастіше.
+ * `200` - код за замовчуванням, який означає, що все пройшло "OK".
+ * Інший приклад – `201`, "Created" (створено). Його зазвичай використовують після створення нового запису в базі даних.
+ * Особливий випадок – `204`, "No Content" (немає вмісту). Ця відповідь використовується, коли немає даних для повернення клієнту, тому відповідь не повинна мати тіла.
+* **`300 - 399`** "Перенаправлення". Відповіді з цими кодами можуть мати або не мати тіла, за винятком `304`, "Not Modified" (не змінено), яка не повинна мати тіла.
+* **`400 - 499`** "Помилка клієнта". Це другий тип, який Ви, ймовірно, будете використовувати найчастіше.
+ * Приклад `404`, "Not Found" (не знайдено).
+ * Для загальних помилок клієнта можна використовувати `400`.
+* `500 - 599` "Помилки сервера". Ви майже ніколи не використовуєте їх напряму. Якщо в коді Вашого застосунку або на сервері щось пішло не так, автоматично буде повернено один із цих кодів статусу.
+
+/// tip | Порада
+
+Щоб дізнатися більше про кожен код статусу і призначення кожного з них, перегляньте документацію MDN про HTTP коди статусу.
+
+///
+
+## Легкий спосіб запам'ятати назви
+
+Розглянемо ще раз попередній приклад:
+
+{* ../../docs_src/response_status_code/tutorial001.py hl[6] *}
+
+`201` - це код статусу для "Created" (створено).
+
+Але Вам не потрібно запам'ятовувати, що означає кожен із цих кодів.
+
+Ви можете використовувати зручні змінні з `fastapi.status`
+
+{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *}
+
+Ці змінні просто для зручності. Вони містять ті ж самі числа, але Ви можете скористатися автозаповненням в редакторі:
+
+
+
+/// note | Технічні деталі
+
+Ви також можете використати `from starlette import status`.
+
+**FastAPI** надає ті ж самі змінні `starlette.status` як `fastapi.status`, просто для зручності розробника. Однак вони походять безпосередньо зі Starlette.
+
+///
+
+## Зміна значення за замовчуванням
+
+Далі, у Посібнику для досвідчених користувачів{.internal-link target=_blank}, Ви дізнаєтесь, як повернути інший код статусу, ніж той, який Ви оголосили тут.
diff --git a/docs/uk/docs/tutorial/schema-extra-example.md b/docs/uk/docs/tutorial/schema-extra-example.md
new file mode 100644
index 000000000..853fd5e65
--- /dev/null
+++ b/docs/uk/docs/tutorial/schema-extra-example.md
@@ -0,0 +1,222 @@
+# Декларування прикладів вхідних даних
+
+Ви можете задати приклади даних, які Ваш застосунок може отримувати.
+
+Ось кілька способів, як це зробити.
+
+## Додаткові дані JSON-схеми в моделях Pydantic
+
+Ви можете задати `examples` для моделі Pydantic, які буде додано до згенерованої JSON-схеми.
+
+//// tab | Pydantic v2
+
+{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
+
+////
+
+//// tab | Pydantic v1
+
+{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
+
+////
+
+Ця додаткова інформація буде додана як є до **JSON-схеми**, і вона буде використовуватися в документації до API.
+
+//// tab | Pydantic v2
+
+У версії Pydantic 2 використовується атрибут `model_config`, який приймає `dict`, як описано в документації Pydantic: Конфігурація.
+
+Ви можете встановити `"json_schema_extra"` як `dict`, що містить будь-які додаткові дані, які Ви хочете відобразити у згенерованій JSON-схемі, включаючи `examples`.
+
+////
+
+//// tab | Pydantic v1
+
+У версії Pydantic 1 використовується внутрішній клас `Config` і параметр `schema_extra`, як описано в документації Pydantic: Налаштування схеми.
+
+Ви можете задати `schema_extra` як `dict`, що містить будь-які додаткові дані, які Ви хочете бачити у згенерованій JSON-схемі, включаючи `examples`.
+
+////
+
+/// tip | Підказка
+
+Ви можете використати ту ж техніку, щоб розширити JSON-схему і додати власну додаткову інформацію.
+
+Наприклад, Ви можете використати її для додавання метаданих для інтерфейсу користувача на фронтенді тощо.
+
+///
+
+/// info | Інформація
+
+OpenAPI 3.1.0 (який використовується починаючи з FastAPI 0.99.0) додав підтримку `examples`, що є частиною стандарту **JSON-схеми**.
+
+До цього підтримувався лише ключ `example` з одним прикладом. Він все ще підтримується в OpenAPI 3.1.0, але є застарілим і не входить до стандарту JSON Schema. Тому рекомендується перейти з `example` на `examples`. 🤓
+
+Більше про це можна прочитати в кінці цієї сторінки.
+
+///
+
+## Додаткові аргументи `Field`
+
+Коли ви використовуєте `Field()` у моделях Pydantic, Ви також можете вказати додаткові `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}
+
+## `examples` у JSON-схемі — OpenAPI
+
+При використанні будь-кого з наступного:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+Ви також можете задати набір `examples` з додатковою інформацією, яка буде додана до їхніх **JSON-схем** у **OpenAPI**.
+
+### `Body` з `examples`
+
+Тут ми передаємо `examples`, які містять один приклад очікуваних даних у `Body()`:
+
+{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}
+
+### Приклад у UI документації
+
+За допомогою будь-якого з наведених вище методів це виглядатиме так у документації за `/docs`:
+
+
+
+### `Body` з кількома `examples`
+
+Звичайно, Ви також можете передати кілька `examples`:
+
+{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
+
+Коли Ви це робите, приклади будуть частиною внутрішньої **JSON-схеми** для цих даних.
+
+Втім, на момент написання цього (26 серпня 2023), Swagger UI — інструмент, який відповідає за відображення UI документації — не підтримує показ кількох прикладів у **JSON-схеми**. Але нижче можна прочитати про обхідний шлях.
+
+### Специфічні для OpenAPI `examples`
+
+Ще до того, як **JSON-схема** почала підтримувати `examples`, OpenAPI вже мала підтримку поля з такою ж назвою — `examples`.
+
+Це **специфічне для OpenAPI** поле `examples` розміщується в іншій частині специфікації OpenAPI — у **деталях кожної *операції шляху***, а не всередині самої JSON-схеми.
+
+Swagger UI вже давно підтримує це поле `examples`. Тому Ви можете використовувати його, щоб **відображати** кілька **прикладів у документації**.
+
+Це поле `examples` у специфікації OpenAPI — це `dict` (словник) з **кількома прикладами** (а не список `list`), кожен із яких може містити додаткову інформацію, що буде додана до **OpenAPI**.
+
+Воно не включається до JSON Schema кожного параметра, а розміщується зовні, безпосередньо в *операції шляху*.
+
+### Використання параметра `openapi_examples`
+
+Ви можете оголосити специфічні для OpenAPI `examples` у FastAPI за допомогою параметра `openapi_examples` для:
+
+* `Path()`
+* `Query()`
+* `Header()`
+* `Cookie()`
+* `Body()`
+* `Form()`
+* `File()`
+
+Ключі словника (`dict`) ідентифікують кожен приклад, а кожне значення `dict` — кожен специфічний словник `dict` в `examples` може містити:
+
+* `summary`: короткий опис прикладу.
+* `description`: розгорнутий опис (може містити Markdown).
+* `value`: сам приклад, наприклад, словник (`dict`).
+* `externalValue`: альтернатива `value`, URL-адреса, що вказує на приклад. Проте ця опція може не підтримуватися більшістю інструментів, на відміну від `value`.
+
+Використання виглядає так:
+
+{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}
+
+### Приклади OpenAPI у UI документації
+
+З параметром `openapi_examples`, доданим до `Body()`, документація `/docs` виглядатиме так:
+
+
+
+## Технічні деталі
+
+/// tip | Підказка
+
+Якщо Ви вже використовуєте **FastAPI** версії **0.99.0 або вище**, Ви можете **пропустити** цей розділ.
+
+Він більш актуальний для старих версій, до появи OpenAPI 3.1.0.
+
+Можна вважати це коротким **історичним екскурсом** у OpenAPI та JSON Schema. 🤓
+
+///
+
+/// warning | Попередження
+
+Це дуже технічна інформація про стандарти **JSON Schema** і **OpenAPI**.
+
+Якщо вищезгадані ідеї вже працюють у Вас — можете не заглиблюватися в ці деталі.
+
+///
+
+До OpenAPI 3.1.0 специфікація використовувала стару та модифіковану версію **JSON Schema**.
+
+Оскільки JSON Schema раніше не підтримувала `examples`, OpenAPI додала власне поле `examples`.
+
+OpenAPI також додала `example` і `examples` до інших частин специфікації:
+
+* `Parameter Object` (в специфікації) використовується FastAPI для:
+ * `Path()`
+ * `Query()`
+ * `Header()`
+ * `Cookie()`
+* `Request Body Object`, в полі `content`, в `Media Type Object` (в специфікації) використовується FastAPI для:
+ * `Body()`
+ * `File()`
+ * `Form()`
+
+/// info | Інформація
+
+Цей старий параметр `examples`, специфічний для OpenAPI, тепер називається `openapi_examples`, починаючи з FastAPI версії `0.103.0`.
+
+///
+
+### Поле `examples` у JSON Schema
+
+Пізніше JSON Schema додала поле `examples` у нову версію специфікації.
+
+І вже OpenAPI 3.1.0 базується на цій новій версії (JSON Schema 2020-12), яка включає поле `examples`.
+
+Тепер це поле `examples` є пріоритетним і замінює старе (і кастомне) поле `example`, яке стало застарілим.
+
+Нове поле `examples` у JSON Schema — це **просто список (`list`)** прикладів, без додаткових метаданих (на відміну від OpenAPI).
+
+/// info | Інформація
+
+Навіть після того, як з'явився OpenAPI 3.1.0, який підтримував examples у JSON Schema, інструмент Swagger UI ще деякий час не підтримував цю версію (підтримка з’явилась з версії 5.0.0 🎉).
+
+Через це версії FastAPI до 0.99.0 все ще використовували версії OpenAPI нижчі за 3.1.0.
+
+///
+
+### `Examples` в Pydantic і FastAPI
+
+Коли Ви додаєте `examples` у модель Pydantic через `schema_extra` або `Field(examples=["something"])`, ці приклади додаються до **JSON Schema** цієї моделі.
+
+І ця **JSON Schema** Pydantic-моделі включається до **OpenAPI** Вашого API, а потім використовується в UI документації (docs UI).
+
+У версіях FastAPI до 0.99.0 (починаючи з 0.99.0 використовується новіший OpenAPI 3.1.0), коли Ви використовували `example` або `examples` з іншими утилітами (`Query()`, `Body()` тощо), ці приклади не додавалися до JSON Schema, який описує ці дані (навіть не до власної версії JSON Schema у OpenAPI). Натомість вони додавалися безпосередньо до опису *обробника шляху* *(path operation)* в OpenAPI (тобто поза межами частин, які використовують JSON Schema).
+
+Але тепер, коли FastAPI 0.99.0 і вище використовують OpenAPI 3.1.0, а той — JSON Schema 2020-12, разом із Swagger UI 5.0.0 і вище — все стало більш узгодженим, і examples тепер включаються до JSON Schema.
+
+### Swagger UI та специфічні для OpenAPI `examples`
+
+Раніше (станом на 26 серпня 2023 року) Swagger UI не підтримував кілька прикладів у JSON Schema, тому користувачі не мали можливості показати декілька прикладів у документації.
+
+Щоб вирішити це, FastAPI починаючи з версії 0.103.0 **додав підтримку** старого **OpenAPI-специфічного** поля `examples` через новий параметр `openapi_examples`. 🤓
+
+### Підсумок
+
+Раніше я казав, що не люблю історію... а тепер ось я — розповідаю "технічні історичні" лекції. 😅
+
+Коротко: **оновіться до FastAPI 0.99.0 або вище** — і все стане значно **простішим, узгодженим та інтуїтивно зрозумілим**, і Вам не доведеться знати всі ці історичні деталі. 😎
diff --git a/docs/uk/docs/tutorial/static-files.md b/docs/uk/docs/tutorial/static-files.md
new file mode 100644
index 000000000..a84782d8f
--- /dev/null
+++ b/docs/uk/docs/tutorial/static-files.md
@@ -0,0 +1,40 @@
+# Статичні файли
+
+Ви можете автоматично надавати статичні файли з каталогу, використовуючи `StaticFiles`.
+
+## Використання `StaticFiles`
+
+* Імпортуйте `StaticFiles`.
+* "Під'єднати" екземпляр `StaticFiles()` з вказанням необхідного шляху.
+
+{* ../../docs_src/static_files/tutorial001.py hl[2,6] *}
+
+/// note | Технічні деталі
+
+Ви також можете використовувати `from starlette.staticfiles import StaticFiles`.
+
+**FastAPI** надає той самий `starlette.staticfiles`, що й `fastapi.staticfiles` для зручності розробників. Але фактично він безпосередньо походить із Starlette.
+
+///
+
+### Що таке "Під'єднання"
+
+"Під'єднання" означає додавання повноцінного "незалежного" застосунку за певним шляхом, який потім обробляє всі під шляхи.
+
+Це відрізняється від використання `APIRouter`, оскільки під'єднаний застосунок є повністю незалежним. OpenAPI та документація вашого основного застосунку не будуть знати нічого про ваш під'єднаний застосунок.
+
+Ви можете дізнатися більше про це в [Посібнику для просунутих користувачів](../advanced/index.md){.internal-link target=_blank}.
+
+## Деталі
+
+Перше `"/static"` вказує на під шлях, за яким буде "під'єднано" цей новий "застосунок". Тому будь-який шлях, який починається з `"/static"`, буде оброблятися ним.
+
+`directory="static"` визначає каталог, що містить ваші статичні файли.
+
+`name="static"` це ім'я, яке можна використовувати всередині **FastAPI**.
+
+Усі ці параметри можуть бути змінені відповідно до потреб і особливостей вашого застосунку.
+
+## Додаткова інформація
+
+Детальніше про налаштування та можливості можна дізнатися в документації Starlette про статичні файли.
diff --git a/docs/uk/docs/tutorial/testing.md b/docs/uk/docs/tutorial/testing.md
new file mode 100644
index 000000000..25fc370d6
--- /dev/null
+++ b/docs/uk/docs/tutorial/testing.md
@@ -0,0 +1,240 @@
+# Тестування
+
+Тестування **FastAPI** додатків є простим та ефективним завдяки бібліотеці Starlette, яка базується на HTTPX.
+Оскільки HTTPX розроблений на основі Requests, його API є інтуїтивно зрозумілим для тих, хто вже знайомий з Requests.
+
+З його допомогою Ви можете використовувати pytest безпосередньо з **FastAPI**.
+
+## Використання `TestClient`
+
+/// info | Інформація
+
+Щоб використовувати `TestClient`, спочатку встановіть `httpx`.
+
+Переконайтеся, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили саму бібліотеку, наприклад:
+
+```console
+$ pip install httpx
+```
+
+///
+
+Імпортуйте `TestClient`.
+
+Створіть `TestClient`, передавши йому Ваш застосунок **FastAPI**.
+
+Створюйте функції з іменами, що починаються з `test_` (це стандартна угода для `pytest`).
+
+Використовуйте об'єкт `TestClient` так само як і `httpx`.
+
+Записуйте прості `assert`-вирази зі стандартними виразами Python, які потрібно перевірити (це також стандарт для `pytest`).
+
+{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *}
+
+
+/// tip | Порада
+
+Зверніть увагу, що тестові функції — це звичайні `def`, а не `async def`.
+
+Виклики клієнта також звичайні, без використання `await`.
+
+Це дозволяє використовувати `pytest` без зайвих ускладнень.
+
+///
+
+/// note | Технічні деталі
+
+Ви також можете використовувати `from starlette.testclient import TestClient`.
+
+**FastAPI** надає той самий `starlette.testclient` під назвою `fastapi.testclient` для зручності розробників, але він безпосередньо походить із Starlette.
+
+///
+
+/// tip | Порада
+
+Якщо Вам потрібно викликати `async`-функції у ваших тестах, окрім відправлення запитів до FastAPI-застосунку (наприклад, асинхронні функції роботи з базою даних), перегляньте [Асинхронні тести](../advanced/async-tests.md){.internal-link target=_blank} у розширеному керівництві.
+
+///
+
+## Розділення тестів
+
+У реальному застосунку Ваші тести, ймовірно, будуть в окремому файлі.
+
+Також Ваш **FastAPI**-застосунок може складатися з кількох файлів або модулів тощо.
+
+### Файл застосунку **FastAPI**
+
+Припустимо, у Вас є структура файлів, описана в розділі [Більші застосунки](bigger-applications.md){.internal-link target=_blank}:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ └── main.py
+```
+У файлі `main.py` знаходиться Ваш застосунок **FastAPI** :
+
+{* ../../docs_src/app_testing/main.py *}
+
+### Файл тестування
+
+Ви можете створити файл `test_main.py` з Вашими тестами. Він може знаходитися в тому ж пакеті Python (у тій самій директорії з файлом `__init__.py`):
+
+
+``` hl_lines="5"
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Оскільки цей файл знаходиться в тому ж пакеті, Ви можете використовувати відносний імпорт, щоб імпортувати об'єкт `app` із модуля `main` (`main.py`):
+
+{* ../../docs_src/app_testing/test_main.py hl[3] *}
+
+
+...і написати код для тестів так само як і раніше.
+
+## Тестування: розширений приклад
+
+Тепер розширимо цей приклад і додамо більше деталей, щоб побачити, як тестувати різні частини.
+
+### Розширений файл застосунку **FastAPI**
+
+Залишимо ту саму структуру файлів:
+
+```
+.
+├── app
+│ ├── __init__.py
+│ ├── main.py
+│ └── test_main.py
+```
+
+Припустимо, що тепер файл `main.py` із Вашим **FastAPI**-застосунком містить додаткові операції шляху (**path operations**).
+
+Він має `GET`-операцію, яка може повертати помилку.
+
+Він має `POST`-операцію, яка може повертати кілька помилок.
+
+Обидві операції шляху вимагають заголовок `X-Token`.
+
+//// tab | Python 3.10+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.9+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an_py39/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+
+
+```Python
+{!> ../../docs_src/app_testing/app_b_an/main.py!}
+```
+
+////
+
+//// tab | Python 3.10+ non-Annotated
+
+/// tip | Порада
+
+Бажано використовувати версію з `Annotated`, якщо це можливо
+
+///
+
+```Python
+{!> ../../docs_src/app_testing/app_b_py310/main.py!}
+```
+
+////
+
+//// tab | Python 3.8+ non-Annotated
+
+/// tip | Порада
+
+Бажано використовувати версію з `Annotated`, якщо це можливо
+
+///
+
+```Python
+{!> ../../docs_src/app_testing/app_b/main.py!}
+```
+
+////
+
+### Розширений тестовий файл
+
+Потім Ви можете оновити `test_main.py`, додавши розширені тести:
+
+{* ../../docs_src/app_testing/app_b/test_main.py *}
+
+Коли Вам потрібно передати клієнту інформацію в запиті, але Ви не знаєте, як це зробити, Ви можете пошукати (наприклад, у Google) спосіб реалізації в `httpx`, або навіть у `requests`, оскільки HTTPX розроблений на основі дизайну Requests.
+
+Далі Ви просто повторюєте ці ж дії у ваших тестах.
+
+Наприклад:
+
+* Щоб передати *path* або *query* параметр, додайте його безпосередньо до URL.
+* Щоб передати тіло JSON, передайте Python-об'єкт (наприклад, `dict`) у параметр `json`.
+* Якщо потрібно надіслати *Form Data* замість JSON, використовуйте параметр `data`.
+* Щоб передати заголовки *headers*, використовуйте `dict` у параметрі `headers`.
+* Для *cookies* використовуйте `dict` у параметрі `cookies`.
+
+Докладніше про передачу даних у бекенд (за допомогою `httpx` або `TestClient`) можна знайти в документації HTTPX.
+
+/// info | Інформація
+
+Зверніть увагу, що `TestClient` отримує дані, які можна конвертувати в JSON, а не Pydantic-моделі.
+Якщо у Вас є Pydantic-модель у тесті, і Ви хочете передати її дані в додаток під час тестування, Ви можете використати `jsonable_encoder`, описаний у розділі [JSON Compatible Encoder](encoder.md){.internal-link target=_blank}.
+
+///
+
+## Запуск тестів
+
+Після цього вам потрібно встановити `pytest`.
+
+Переконайтеся, що Ви створили [віртуальне середовище]{.internal-link target=_blank}, активували його і встановили необхідні пакети, наприклад:
+
+
diff --git a/docs/vi/docs/deployment/cloud.md b/docs/vi/docs/deployment/cloud.md
new file mode 100644
index 000000000..9ab72769d
--- /dev/null
+++ b/docs/vi/docs/deployment/cloud.md
@@ -0,0 +1,17 @@
+# Triển khai FastAPI trên các Dịch vụ Cloud
+
+Bạn có thể sử dụng **bất kỳ nhà cung cấp dịch vụ cloud** nào để triển khai ứng dụng FastAPI của mình.
+
+Trong hầu hết các trường hợp, các nhà cung cấp dịch vụ cloud lớn đều có hướng dẫn triển khai FastAPI với họ.
+
+## Nhà cung cấp dịch vụ Cloud - Nhà tài trợ
+Một vài nhà cung cấp dịch vụ cloud ✨ [**tài trợ cho FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, điều này giúp đảm bảo sự phát triển liên tục và khỏe mạnh của FastAPI và hệ sinh thái của nó.
+
+Thêm nữa, điều này cũng thể hiện cam kết thực sự của họ đối với FastAPI và **cộng đồng người dùng** (bạn), vì họ không chỉ muốn cung cấp cho bạn một **dịch vụ tốt** mà còn muốn đảm bảo rằng bạn có một **framework tốt và bền vững**, đó chính là FastAPI. 🙇
+
+Bạn có thể thử các dịch vụ của họ và làm theo hướng dẫn của họ:
+
+* Platform.sh
+* Porter
+* Coherence
+* Render
diff --git a/docs/vi/docs/deployment/index.md b/docs/vi/docs/deployment/index.md
new file mode 100644
index 000000000..24ffdc71b
--- /dev/null
+++ b/docs/vi/docs/deployment/index.md
@@ -0,0 +1,21 @@
+# Triển khai
+
+Triển khai một ứng dụng **FastAPI** khá dễ dàng.
+
+## Triển khai là gì
+
+Triển khai một ứng dụng có nghĩa là thực hiện các bước cần thiết để làm cho nó **sẵn sàng phục vụ người dùng**.
+
+Đối với một **API web**, điều này có nghĩa là đặt nó trong một **máy chủ từ xa**, với một **chương trình máy chủ** cung cấp hiệu suất tốt, ổn định, v.v., để người dùng của bạn có thể truy cập ứng dụng của bạn một cách hiệu quả và không bị gián đoạn hoặc gặp vấn đề.
+
+Điều này trái ngược với các **giai đoạn phát triển**, trong đó bạn liên tục thay đổi mã, phá vỡ nó và sửa nó, ngừng và khởi động lại máy chủ phát triển, v.v.
+
+## Các Chiến lược Triển khai
+
+Có nhiều cách để triển khai ứng dụng của bạn tùy thuộc vào trường hợp sử dụng của bạn và các công cụ mà bạn sử dụng.
+
+Bạn có thể **triển khai một máy chủ** của riêng bạn bằng cách sử dụng một sự kết hợp các công cụ, hoặc bạn có thể sử dụng một **dịch vụ cloud** để làm một số công việc cho bạn, hoặc các tùy chọn khác.
+
+Tôi sẽ chỉ ra một số khái niệm chính cần thiết khi triển khai một ứng dụng **FastAPI** (mặc dù hầu hết nó áp dụng cho bất kỳ loại ứng dụng web nào).
+
+Bạn sẽ thấy nhiều chi tiết cần thiết và một số kỹ thuật để triển khai trong các phần tiếp theo. ✨
diff --git a/docs/vi/docs/deployment/versions.md b/docs/vi/docs/deployment/versions.md
new file mode 100644
index 000000000..04de393e7
--- /dev/null
+++ b/docs/vi/docs/deployment/versions.md
@@ -0,0 +1,93 @@
+# Về các phiên bản của FastAPI
+
+**FastAPI** đã được sử dụng ở quy mô thực tế (production) trong nhiều ứng dụng và hệ thống. Và phạm vi kiểm thử được giữ ở mức 100%. Nhưng việc phát triển của nó vẫn đang diễn ra nhanh chóng.
+
+Các tính năng mới được bổ sung thường xuyên, lỗi được sửa định kỳ, và mã nguồn vẫn đang được cải thiện liên tục
+
+Đó là lí do các phiên bản hiện tại vẫn còn là 0.x.x, điều này phản ánh rằng mỗi phiên bản có thể có các thay đổi gây mất tương thích. Điều này tuân theo các quy ước về Semantic Versioning.
+
+Bạn có thể tạo ra sản phẩm thực tế với **FastAPI** ngay bây giờ (và bạn có thể đã làm điều này trong một thời gian dài), bạn chỉ cần đảm bảo rằng bạn sử dụng một phiên bản hoạt động đúng với các đoạn mã còn lại của bạn.
+
+## Cố định phiên bản của `fastapi`
+
+Điều đầu tiên bạn nên làm là "cố định" phiên bản của **FastAPI** bạn đang sử dụng để phiên bản mới nhất mà bạn biết hoạt động đúng với ứng dụng của bạn.
+
+Ví dụ, giả sử bạn đang sử dụng phiên bản `0.112.0` trong ứng dụng của bạn.
+
+Nếu bạn sử dụng một tệp `requirements.txt` bạn có thể chỉ định phiên bản với:
+
+```txt
+fastapi[standard]==0.112.0
+```
+
+Như vậy, bạn sẽ sử dụng chính xác phiên bản `0.112.0`.
+
+Hoặc bạn cũng có thể cố định nó với:
+
+```txt
+fastapi[standard]>=0.112.0,<0.113.0
+```
+
+Như vậy, bạn sẽ sử dụng các phiên bản `0.112.0` trở lên, nhưng nhỏ hơn `0.113.0`, ví dụ, một phiên bản `0.112.2` vẫn được chấp nhận.
+
+Nếu bạn sử dụng bất kỳ công cụ nào để quản lý cài đặt của bạn, như `uv`, Poetry, Pipenv, hoặc bất kỳ công cụ nào khác, chúng đều có một cách để bạn có thể định nghĩa các phiên bản cụ thể cho các gói của bạn.
+
+## Các phiên bản có sẵn
+
+Bạn có thể xem các phiên bản có sẵn (ví dụ để kiểm tra phiên bản mới nhất) trong [Release Notes](../release-notes.md){.internal-link target=_blank}.
+
+## Về các phiên bản
+
+Theo quy ước về Semantic Versioning, bất kỳ phiên bản nào bên dưới `1.0.0` có thể thêm các thay đổi gây mất tương thích.
+
+**FastAPI** cũng theo quy ước rằng bất kỳ thay đổi phiên bản "PATCH" nào là cho các lỗi và các thay đổi không gây mất tương thích.
+
+/// tip
+
+"PATCH" là số cuối cùng, ví dụ, trong `0.2.3`, phiên bản PATCH là `3`.
+
+///
+
+Vì vậy, bạn có thể cố định đến một phiên bản như:
+
+```txt
+fastapi>=0.45.0,<0.46.0
+```
+
+Các thay đổi gây mất tương thích và các tính năng mới được thêm vào trong các phiên bản "MINOR".
+
+/// tip
+
+"MINOR" là số ở giữa, ví dụ, trong `0.2.3`, phiên bản MINOR là `2`.
+
+///
+
+## Nâng cấp các phiên bản của FastAPI
+
+Bạn nên thêm các bài kiểm tra (tests) cho ứng dụng của bạn.
+
+Với **FastAPI** điều này rất dễ dàng (nhờ vào Starlette), kiểm tra tài liệu: [Testing](../tutorial/testing.md){.internal-link target=_blank}
+
+Sau khi bạn có các bài kiểm tra, bạn có thể nâng cấp phiên bản **FastAPI** lên một phiên bản mới hơn, và đảm bảo rằng tất cả mã của bạn hoạt động đúng bằng cách chạy các bài kiểm tra của bạn.
+
+Nếu mọi thứ đang hoạt động, hoặc sau khi bạn thực hiện các thay đổi cần thiết, và tất cả các bài kiểm tra của bạn đều đi qua, thì bạn có thể cố định phiên bản của `fastapi` đến phiên bản mới hơn.
+
+## Về Starlette
+
+Bạn không nên cố định phiên bản của `starlette`.
+
+Các phiên bản khác nhau của **FastAPI** sẽ sử dụng một phiên bản Starlette mới hơn.
+
+Vì vậy, bạn có thể để **FastAPI** sử dụng phiên bản Starlette phù hợp.
+
+## Về Pydantic
+
+Pydantic bao gồm các bài kiểm tra của riêng nó cho **FastAPI**, vì vậy các phiên bản mới hơn của Pydantic (trên `1.0.0`) luôn tương thích với **FastAPI**.
+
+Bạn có thể cố định Pydantic đến bất kỳ phiên bản nào trên `1.0.0` mà bạn muốn.
+
+Ví dụ:
+
+```txt
+pydantic>=2.7.0,<3.0.0
+```
diff --git a/docs/vi/docs/environment-variables.md b/docs/vi/docs/environment-variables.md
new file mode 100644
index 000000000..dd06f8959
--- /dev/null
+++ b/docs/vi/docs/environment-variables.md
@@ -0,0 +1,300 @@
+# Biến môi trường (Environment Variables)
+
+/// tip
+
+Nếu bạn đã biết về "biến môi trường" và cách sử dụng chúng, bạn có thể bỏ qua phần này.
+
+///
+
+Một biến môi trường (còn được gọi là "**env var**") là một biến mà tồn tại **bên ngoài** đoạn mã Python, ở trong **hệ điều hành**, và có thể được đọc bởi đoạn mã Python của bạn (hoặc bởi các chương trình khác).
+
+Các biến môi trường có thể được sử dụng để xử lí **các thiết lập** của ứng dụng, như một phần của **các quá trình cài đặt** Python, v.v.
+
+## Tạo và Sử dụng các Biến Môi Trường
+
+Bạn có thể **tạo** và sử dụng các biến môi trường trong **shell (terminal)**, mà không cần sử dụng Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Bạn có thể tạo một biến môi trường MY_NAME với
+$ export MY_NAME="Wade Wilson"
+
+// Sau đó bạn có thể sử dụng nó với các chương trình khác, như
+$ echo "Hello $MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Tạo một biến môi trường MY_NAME
+$ $Env:MY_NAME = "Wade Wilson"
+
+// Sử dụng nó với các chương trình khác, như là
+$ echo "Hello $Env:MY_NAME"
+
+Hello Wade Wilson
+```
+
+
+
+////
+
+## Đọc các Biến Môi Trường trong Python
+
+Bạn cũng có thể tạo các biến môi trường **bên ngoài** đoạn mã Python, trong terminal (hoặc bằng bất kỳ phương pháp nào khác), và sau đó **đọc chúng trong Python**.
+
+Ví dụ, bạn có một file `main.py` với:
+
+```Python hl_lines="3"
+import os
+
+name = os.getenv("MY_NAME", "World")
+print(f"Hello {name} from Python")
+```
+
+/// tip
+
+Tham số thứ hai cho `os.getenv()` là giá trị mặc định để trả về.
+
+Nếu không được cung cấp, nó mặc định là `None`, ở đây chúng ta cung cấp `"World"` là giá trị mặc định để sử dụng.
+
+///
+
+Sau đó bạn có thể gọi chương trình Python:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+// Ở đây chúng ta chưa cài đặt biến môi trường
+$ python main.py
+
+// Vì chúng ta chưa cài đặt biến môi trường, chúng ta nhận được giá trị mặc định
+
+Hello World from Python
+
+// Nhưng nếu chúng ta tạo một biến môi trường trước đó
+$ export MY_NAME="Wade Wilson"
+
+// Và sau đó gọi chương trình lại
+$ python main.py
+
+// Bây giờ nó có thể đọc biến môi trường
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+```console
+// Ở đây chúng ta chưa cài đặt biến môi trường
+$ python main.py
+
+// Vì chúng ta chưa cài đặt biến môi trường, chúng ta nhận được giá trị mặc định
+
+Hello World from Python
+
+// Nhưng nếu chúng ta tạo một biến môi trường trước đó
+$ $Env:MY_NAME = "Wade Wilson"
+
+// Và sau đó gọi chương trình lại
+$ python main.py
+
+// Bây giờ nó có thể đọc biến môi trường
+
+Hello Wade Wilson from Python
+```
+
+
+
+////
+
+Vì các biến môi trường có thể được tạo bên ngoài đoạn mã Python, nhưng có thể được đọc bởi đoạn mã Python, và không cần được lưu trữ (commit vào `git`) cùng với các file khác, nên chúng thường được sử dụng để lưu các thiết lập hoặc **cấu hình**.
+
+Bạn cũng có thể tạo ra một biến môi trường dành riêng cho một **lần gọi chương trình**, chỉ có thể được sử dụng bởi chương trình đó, và chỉ trong thời gian chạy của chương trình.
+
+Để làm điều này, tạo nó ngay trước chương trình đó, trên cùng một dòng:
+
+
+
+```console
+// Tạo một biến môi trường MY_NAME cho lần gọi chương trình này
+$ MY_NAME="Wade Wilson" python main.py
+
+// Bây giờ nó có thể đọc biến môi trường
+
+Hello Wade Wilson from Python
+
+// Biến môi trường không còn tồn tại sau đó
+$ python main.py
+
+Hello World from Python
+```
+
+
+
+/// tip
+
+Bạn có thể đọc thêm về điều này tại The Twelve-Factor App: Config.
+
+///
+
+## Các Kiểu (Types) và Kiểm tra (Validation)
+
+Các biến môi trường có thể chỉ xử lí **chuỗi ký tự**, vì chúng nằm bên ngoài đoạn mã Python và phải tương thích với các chương trình khác và phần còn lại của hệ thống (và thậm chí với các hệ điều hành khác, như Linux, Windows, macOS).
+
+Điều này có nghĩa là **bất kỳ giá trị nào** được đọc trong Python từ một biến môi trường **sẽ là một `str`**, và bất kỳ hành động chuyển đổi sang kiểu dữ liệu khác hoặc hành động kiểm tra nào cũng phải được thực hiện trong đoạn mã.
+
+Bạn sẽ học thêm về việc sử dụng biến môi trường để xử lí **các thiết lập ứng dụng** trong [Hướng dẫn nâng cao - Các thiết lập và biến môi trường](./advanced/settings.md){.internal-link target=_blank}.
+
+## Biến môi trường `PATH`
+
+Có một biến môi trường **đặc biệt** được gọi là **`PATH`** được sử dụng bởi các hệ điều hành (Linux, macOS, Windows) nhằm tìm các chương trình để thực thi.
+
+Giá trị của biến môi trường `PATH` là một chuỗi dài được tạo bởi các thư mục được phân tách bởi dấu hai chấm `:` trên Linux và macOS, và bởi dấu chấm phẩy `;` trên Windows.
+
+Ví dụ, biến môi trường `PATH` có thể có dạng như sau:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Điều này có nghĩa là hệ thống sẽ tìm kiếm các chương trình trong các thư mục:
+
+* `/usr/local/bin`
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32
+```
+
+Điều này có nghĩa là hệ thống sẽ tìm kiếm các chương trình trong các thư mục:
+
+* `C:\Program Files\Python312\Scripts`
+* `C:\Program Files\Python312`
+* `C:\Windows\System32`
+
+////
+
+Khi bạn gõ một **lệnh** trong terminal, hệ điều hành **tìm kiếm** chương trình trong **mỗi thư mục** được liệt kê trong biến môi trường `PATH`.
+
+Ví dụ, khi bạn gõ `python` trong terminal, hệ điều hành tìm kiếm một chương trình được gọi `python` trong **thư mục đầu tiên** trong danh sách đó.
+
+Nếu tìm thấy, nó sẽ **sử dụng** nó. Nếu không tìm thấy, nó sẽ tiếp tục tìm kiếm trong **các thư mục khác**.
+
+### Cài đặt Python và cập nhật biến môi trường `PATH`
+
+Khi bạn cài đặt Python, bạn có thể được hỏi nếu bạn muốn cập nhật biến môi trường `PATH`.
+
+//// tab | Linux, macOS
+
+Giả sử bạn cài đặt Python vào thư mục `/opt/custompython/bin`.
+
+Nếu bạn chọn cập nhật biến môi trường `PATH`, thì cài đặt sẽ thêm `/opt/custompython/bin` vào biến môi trường `PATH`.
+
+Nó có thể có dạng như sau:
+
+```plaintext
+/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin
+```
+
+Như vậy, khi bạn gõ `python` trong terminal, hệ thống sẽ tìm thấy chương trình Python trong `/opt/custompython/bin` (thư mục cuối) và sử dụng nó.
+
+////
+
+//// tab | Windows
+
+Giả sử bạn cài đặt Python vào thư mục `C:\opt\custompython\bin`.
+
+Nếu bạn chọn cập nhật biến môi trường `PATH`, thì cài đặt sẽ thêm `C:\opt\custompython\bin` vào biến môi trường `PATH`.
+
+Nó có thể có dạng như sau:
+
+```plaintext
+C:\Program Files\Python312\Scripts;C:\Program Files\Python312;C:\Windows\System32;C:\opt\custompython\bin
+```
+
+Như vậy, khi bạn gõ `python` trong terminal, hệ thống sẽ tìm thấy chương trình Python trong `C:\opt\custompython\bin` (thư mục cuối) và sử dụng nó.
+
+////
+
+Vậy, nếu bạn gõ:
+
+
+
+```console
+$ python
+```
+
+
+
+//// tab | Linux, macOS
+
+Hệ thống sẽ **tìm kiếm** chương trình `python` trong `/opt/custompython/bin` và thực thi nó.
+
+Nó tương đương với việc bạn gõ:
+
+
+
+////
+
+//// tab | Windows
+
+Hệ thống sẽ **tìm kiếm** chương trình `python` trong `C:\opt\custompython\bin\python` và thực thi nó.
+
+Nó tương đương với việc bạn gõ:
+
+
+
+////
+
+Thông tin này sẽ hữu ích khi bạn học về [Môi trường ảo](virtual-environments.md){.internal-link target=_blank}.
+
+## Kết luận
+
+Với những thông tin này, bạn có thể hiểu được **các biến môi trường là gì** và **cách sử dụng chúng trong Python**.
+
+Bạn có thể đọc thêm về chúng tại Wikipedia cho Biến môi trường.
+
+Trong nhiều trường hợp, cách các biến môi trường trở nên hữu ích và có thể áp dụng không thực sự rõ ràng ngay từ đầu, nhưng chúng sẽ liên tục xuất hiện trong rất nhiều tình huống khi bạn phát triển ứng dụng, vì vậy việc hiểu biết về chúng là hữu ích.
+
+Chẳng hạn, bạn sẽ cần những thông tin này khi bạn học về [Môi trường ảo](virtual-environments.md).
diff --git a/docs/vi/docs/fastapi-cli.md b/docs/vi/docs/fastapi-cli.md
new file mode 100644
index 000000000..d9e315ae4
--- /dev/null
+++ b/docs/vi/docs/fastapi-cli.md
@@ -0,0 +1,75 @@
+# FastAPI CLI
+
+**FastAPI CLI** là một chương trình dòng lệnh có thể được sử dụng để phục vụ ứng dụng FastAPI của bạn, quản lý dự án FastAPI của bạn và nhiều hoạt động khác.
+
+Khi bạn cài đặt FastAPI (vd với `pip install "fastapi[standard]"`), nó sẽ bao gồm một gói được gọi là `fastapi-cli`, gói này cung cấp lệnh `fastapi` trong terminal.
+
+Để chạy ứng dụng FastAPI của bạn cho quá trình phát triển (development), bạn có thể sử dụng lệnh `fastapi dev`:
+
+
+
+```console
+$ fastapi dev main.py
+
+ FastAPI Starting development server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://127.0.0.1:8000
+ server Documentation at http://127.0.0.1:8000/docs
+
+ tip Running in development mode, for production use:
+ fastapi run
+
+ Logs:
+
+ INFO Will watch for changes in these directories:
+ ['/home/user/code/awesomeapp']
+ INFO Uvicorn running on http://127.0.0.1:8000(Press CTRL+C to
+ quit)
+ INFO Started reloader process [383138] using WatchFiles
+ INFO Started server process [383153]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+```
+
+
+
+Chương trình dòng lệnh `fastapi` là **FastAPI CLI**.
+
+FastAPI CLI nhận đường dẫn đến chương trình Python của bạn (vd `main.py`) và tự động phát hiện đối tượng `FastAPI` (thường được gọi là `app`), xác định quá trình nhập đúng, và sau đó chạy nó (serve).
+
+Đối với vận hành thực tế (production), bạn sẽ sử dụng `fastapi run` thay thế. 🚀
+
+Ở bên trong, **FastAPI CLI** sử dụng Uvicorn, một server ASGI có hiệu suất cao, sẵn sàng cho vận hành thực tế (production). 😎
+
+## `fastapi dev`
+
+Chạy `fastapi dev` sẽ khởi động quá trình phát triển.
+
+Mặc định, **auto-reload** được bật, tự động tải lại server khi bạn thay đổi code của bạn. Điều này tốn nhiều tài nguyên và có thể kém ổn định hơn khi nó bị tắt. Bạn nên sử dụng nó cho quá trình phát triển. Nó cũng lắng nghe địa chỉ IP `127.0.0.1`, đó là địa chỉ IP của máy tính để tự giao tiếp với chính nó (`localhost`).
+
+## `fastapi run`
+
+Chạy `fastapi run` mặc định sẽ khởi động FastAPI cho quá trình vận hành thực tế.
+
+Mặc định, **auto-reload** bị tắt. Nó cũng lắng nghe địa chỉ IP `0.0.0.0`, đó là tất cả các địa chỉ IP có sẵn, như vậy nó sẽ được truy cập công khai bởi bất kỳ ai có thể giao tiếp với máy tính. Đây là cách bạn thường chạy nó trong sản phẩm hoàn thiện, ví dụ trong một container.
+
+Trong hầu hết các trường hợp, bạn sẽ (và nên) có một "proxy điểm cuối (termination proxy)" xử lý HTTPS cho bạn, điều này sẽ phụ thuộc vào cách bạn triển khai ứng dụng của bạn, nhà cung cấp có thể làm điều này cho bạn, hoặc bạn có thể cần thiết lập nó.
+
+/// tip
+
+Bạn có thể tìm hiểu thêm về FastAPI CLI trong [tài liệu triển khai](deployment/index.md){.internal-link target=_blank}.
+
+///
diff --git a/docs/vi/docs/index.md b/docs/vi/docs/index.md
index 5e346ded8..5c6b7e8a4 100644
--- a/docs/vi/docs/index.md
+++ b/docs/vi/docs/index.md
@@ -12,7 +12,7 @@
+
+```console
+// Đi đến thư mục home
+$ cd
+// Tạo một thư mục cho tất cả các dự án của bạn
+$ mkdir code
+// Vào thư mục code
+$ cd code
+// Tạo một thư mục cho dự án này
+$ mkdir awesome-project
+// Vào thư mục dự án
+$ cd awesome-project
+```
+
+
+
+## Tạo một Môi trường ảo
+
+Khi bạn bắt đầu làm việc với một dự án Python **trong lần đầu**, hãy tạo một môi trường ảo **trong thư mục dự án của bạn**.
+
+/// tip
+
+Bạn cần làm điều này **một lần cho mỗi dự án**, không phải mỗi khi bạn làm việc.
+///
+
+//// tab | `venv`
+
+Để tạo một môi trường ảo, bạn có thể sử dụng module `venv` có sẵn của Python.
+
+
+
+```console
+$ python -m venv .venv
+```
+
+
+
+/// details | Cách các lệnh hoạt động
+
+* `python`: sử dụng chương trình `python`
+* `-m`: gọi một module như một script, chúng ta sẽ nói về module đó sau
+* `venv`: sử dụng module `venv` được cài đặt sẵn của Python
+* `.venv`: tạo môi trường ảo trong thư mục mới `.venv`
+
+///
+
+////
+
+//// tab | `uv`
+
+Nếu bạn có `uv` được cài đặt, bạn có thể sử dụng nó để tạo một môi trường ảo.
+
+
+
+```console
+$ uv venv
+```
+
+
+
+/// tip
+
+Mặc định, `uv` sẽ tạo một môi trường ảo trong một thư mục có tên `.venv`.
+
+Nhưng bạn có thể tùy chỉnh nó bằng cách thêm một đối số với tên thư mục.
+
+///
+
+////
+
+Lệnh này tạo một môi trường ảo mới trong một thư mục có tên `.venv`.
+
+/// details | `.venv` hoặc tên khác
+
+Bạn có thể tạo môi trường ảo trong một thư mục khác, nhưng thường người ta quy ước đặt nó là `.venv`.
+
+///
+
+## Kích hoạt Môi trường ảo
+
+Kích hoạt môi trường ảo mới để bất kỳ lệnh Python nào bạn chạy hoặc gói nào bạn cài đặt sẽ sử dụng nó.
+
+/// tip
+
+Làm điều này **mỗi khi** bạn bắt đầu một **phiên terminal mới** để làm việc trên dự án.
+
+///
+
+//// tab | Linux, macOS
+
+
+
+////
+
+/// tip
+
+Mỗi khi bạn cài đặt thêm một **package mới** trong môi trường đó, hãy **kích hoạt** môi trường đó lại.
+
+Điều này đảm bảo rằng khi bạn sử dụng một **chương trình dòng lệnh (CLI)** được cài đặt từ gói đó, bạn sẽ dùng bản cài đặt từ môi trường ảo của mình thay vì bản được cài đặt toàn cục khác có thể có phiên bản khác với phiên bản bạn cần.
+
+///
+
+## Kiểm tra xem Môi trường ảo đã được Kích hoạt chưa
+
+Kiểm tra xem môi trường ảo đã được kích hoạt chưa (lệnh trước đó đã hoạt động).
+
+/// tip
+
+Điều này là **không bắt buộc**, nhưng nó là một cách tốt để **kiểm tra** rằng mọi thứ đang hoạt động như mong đợi và bạn đang sử dụng đúng môi trường ảo mà bạn đã định.
+
+///
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+Nếu nó hiển thị `python` binary tại `.venv/bin/python`, trong dự án của bạn (trong trường hợp `awesome-project`), thì tức là nó hoạt động. 🎉
+
+////
+
+//// tab | Windows PowerShell
+
+
+
+Nếu nó hiển thị `python` binary tại `.venv\Scripts\python`, trong dự án của bạn (trong trường hợp `awesome-project`), thì tức là nó hoạt động. 🎉
+
+////
+
+## Nâng cấp `pip`
+
+/// tip
+
+Nếu bạn sử dụng `uv` bạn sử dụng nó để cài đặt thay vì `pip`, thì bạn không cần cập nhật `pip`. 😎
+
+///
+
+Nếu bạn sử dụng `pip` để cài đặt gói (nó được cài đặt mặc định với Python), bạn nên **nâng cấp** nó lên phiên bản mới nhất.
+
+Nhiều lỗi khác nhau trong khi cài đặt gói được giải quyết chỉ bằng cách nâng cấp `pip` trước.
+
+/// tip
+
+Bạn thường làm điều này **một lần**, ngay sau khi bạn tạo môi trường ảo.
+
+///
+
+Đảm bảo rằng môi trường ảo đã được kích hoạt (với lệnh trên) và sau đó chạy:
+
+
+
+## Thêm `.gitignore`
+
+Nếu bạn sử dụng **Git** (nên làm), hãy thêm một file `.gitignore` để Git bỏ qua mọi thứ trong `.venv`.
+
+/// tip
+
+Nếu bạn sử dụng `uv` để tạo môi trường ảo, nó đã tự động làm điều này cho bạn, bạn có thể bỏ qua bước này. 😎
+
+///
+
+/// tip
+
+Làm điều này **một lần**, ngay sau khi bạn tạo môi trường ảo.
+
+///
+
+
+
+/// details | Cách lệnh hoạt động
+
+* `echo "*"`: sẽ "in" văn bản `*` trong terminal (phần tiếp theo sẽ thay đổi điều đó một chút)
+* `>`: bất kỳ văn bản nào được in ra terminal bởi lệnh trước `>` không được in ra mà thay vào đó được viết vào file ở phía bên phải của `>`
+* `.gitignore`: tên của file mà văn bản sẽ được viết vào
+
+Và `*` với Git có nghĩa là "mọi thứ". Vì vậy, nó sẽ bỏ qua mọi thứ trong thư mục `.venv`.
+
+Lệnh này sẽ tạo một file `.gitignore` với nội dung:
+
+```gitignore
+*
+```
+
+///
+
+## Cài đặt gói (packages)
+
+Sau khi kích hoạt môi trường, bạn có thể cài đặt các gói trong đó.
+
+/// tip
+
+Thực hiện điều này **một lần** khi cài đặt hoặc cập nhật gói cần thiết cho dự án của bạn.
+
+Nếu bạn cần cập nhật phiên bản hoặc thêm một gói mới, bạn sẽ **thực hiện điều này lại**.
+
+///
+
+### Cài đặt gói trực tiếp
+
+Nếu bạn cần cập nhật phiên bản hoặc thêm một gói mới, bạn sẽ **thực hiện điều này lại**.
+
+/// tip
+Để quản lý dự án tốt hơn, hãy liệt kê tất cả các gói và phiên bản cần thiết trong một file (ví dụ `requirements.txt` hoặc `pyproject.toml`).
+
+///
+
+//// tab | `pip`
+
+
+
+////
+
+### Cài đặt từ `requirements.txt`
+
+Nếu bạn có một tệp `requirements.txt`, bạn có thể sử dụng nó để cài đặt các gói.
+
+//// tab | `pip`
+
+
+
+////
+
+/// details | `requirements.txt`
+
+Một tệp `requirements.txt` với một số gói sẽ trông như thế này:
+
+```requirements.txt
+fastapi[standard]==0.113.0
+pydantic==2.8.0
+```
+
+///
+
+## Chạy Chương trình của bạn
+
+Sau khi kích hoạt môi trường ảo, bạn có thể chạy chương trình của mình, nó sẽ sử dụng Python trong môi trường ảo của bạn với các gói bạn đã cài đặt.
+
+
+
+## Cấu hình Trình soạn thảo của bạn
+
+Nếu bạn sử dụng một trình soạn thảo, hãy đảm bảo bạn cấu hình nó để sử dụng cùng môi trường ảo mà bạn đã tạo (trình soạn thảo sẽ tự động phát hiện môi trường ảo) để bạn có thể nhận được tính năng tự động hoàn thành câu lệnh (autocomplete) và in lỗi trực tiếp trong trình soạn thảo (inline errors).
+
+Ví dụ:
+
+* VS Code
+* PyCharm
+
+/// tip
+
+Bạn thường chỉ cần làm điều này **một lần**, khi bạn tạo môi trường ảo.
+
+///
+
+## Huỷ kích hoạt Môi trường ảo
+
+Khi bạn hoàn tất việc làm trên dự án của bạn, bạn có thể **huỷ kích hoạt** môi trường ảo.
+
+
+
+```console
+$ deactivate
+```
+
+
+
+Như vậy, khi bạn chạy `python`, nó sẽ không chạy từ môi trường ảo đó với các gói đã cài đặt.
+
+## Sẵn sàng để Làm việc
+
+Bây giờ bạn đã sẵn sàng để làm việc trên dự án của mình rồi đấy.
+
+/// tip
+
+Bạn muốn hiểu tất cả những gì ở trên?
+
+Tiếp tục đọc. 👇🤓
+
+///
+
+## Tại sao cần Môi trường ảo
+
+Để làm việc với FastAPI, bạn cần cài đặt Python.
+
+Sau đó, bạn sẽ cần **cài đặt** FastAPI và bất kỳ **gói** nào mà bạn muốn sử dụng.
+
+Để cài đặt gói, bạn thường sử dụng lệnh `pip` có sẵn với Python (hoặc các phiên bản tương tự).
+
+Tuy nhiên, nếu bạn sử dụng `pip` trực tiếp, các gói sẽ được cài đặt trong **môi trường Python toàn cục** của bạn (phần cài đặt toàn cục của Python).
+
+### Vấn đề
+
+Vậy, vấn đề gì khi cài đặt gói trong môi trường Python toàn cục?
+
+Trong một vài thời điểm, bạn sẽ phải viết nhiều chương trình khác nhau phụ thuộc vào **các gói khác nhau**. Và một số dự án bạn thực hiện lại phụ thuộc vào **các phiên bản khác nhau** của cùng một gói. 😱
+
+Ví dụ, bạn có thể tạo một dự án được gọi là `philosophers-stone`, chương trình này phụ thuộc vào một gói khác được gọi là **`harry`, sử dụng phiên bản `1`**. Vì vậy, bạn cần cài đặt `harry`.
+
+```mermaid
+flowchart LR
+ stone(philosophers-stone) -->|phụ thuộc| harry-1[harry v1]
+```
+
+Sau đó, vào một vài thời điểm sau, bạn tạo một dự án khác được gọi là `prisoner-of-azkaban`, và dự án này cũng phụ thuộc vào `harry`, nhưng dự án này cần **`harry` phiên bản `3`**.
+
+```mermaid
+flowchart LR
+ azkaban(prisoner-of-azkaban) --> |phụ thuộc| harry-3[harry v3]
+```
+
+Bây giờ, vấn đề là, nếu bạn cài đặt các gói toàn cục (trong môi trường toàn cục) thay vì trong một **môi trường ảo cục bộ**, bạn sẽ phải chọn phiên bản `harry` nào để cài đặt.
+
+Nếu bạn muốn chạy `philosophers-stone` bạn sẽ cần phải cài đặt `harry` phiên bản `1`, ví dụ với:
+
+
+
+```console
+$ pip install "harry==1"
+```
+
+
+
+Và sau đó bạn sẽ có `harry` phiên bản `1` được cài đặt trong môi trường Python toàn cục của bạn.
+
+```mermaid
+flowchart LR
+ subgraph global[môi trường toàn cục]
+ harry-1[harry v1]
+ end
+ subgraph stone-project[dự án philosophers-stone ]
+ stone(philosophers-stone) -->|phụ thuộc| harry-1
+ end
+```
+
+Nhưng sau đó, nếu bạn muốn chạy `prisoner-of-azkaban`, bạn sẽ cần phải gỡ bỏ `harry` phiên bản `1` và cài đặt `harry` phiên bản `3` (hoặc chỉ cần cài đặt phiên bản `3` sẽ tự động gỡ bỏ phiên bản `1`).
+
+
+
+```console
+$ pip install "harry==3"
+```
+
+
+
+Và sau đó bạn sẽ có `harry` phiên bản `3` được cài đặt trong môi trường Python toàn cục của bạn.
+
+Và nếu bạn cố gắng chạy `philosophers-stone` lại, có khả năng nó sẽ **không hoạt động** vì nó cần `harry` phiên bản `1`.
+
+```mermaid
+flowchart LR
+ subgraph global[môi trường toàn cục]
+ harry-1[harry v1]
+ style harry-1 fill:#ccc,stroke-dasharray: 5 5
+ harry-3[harry v3]
+ end
+ subgraph stone-project[dự án philosophers-stone ]
+ stone(philosophers-stone) -.-x|⛔️| harry-1
+ end
+ subgraph azkaban-project[dự án prisoner-of-azkaban ]
+ azkaban(prisoner-of-azkaban) --> |phụ thuộc| harry-3
+ end
+```
+
+/// tip
+
+Mặc dù các gói Python thường cố gắng **tránh các thay đổi làm hỏng code** trong **phiên bản mới**, nhưng để đảm bảo an toàn, bạn nên chủ động cài đặt phiên bản mới và chạy kiểm thử để xác nhận mọi thứ vẫn hoạt động đúng.
+
+///
+
+Bây giờ, hãy hình dung về **nhiều** gói khác nhau mà tất cả các dự án của bạn phụ thuộc vào. Rõ ràng rất khó để quản lý. Điều này dẫn tới việc là bạn sẽ có nhiều dự án với **các phiên bản không tương thích** của các gói, và bạn có thể không biết tại sao một số thứ không hoạt động.
+
+Hơn nữa, tuỳ vào hệ điều hành của bạn (vd Linux, Windows, macOS), có thể đã có Python được cài đặt sẵn. Trong trường hợp ấy, một vài gói nhiều khả năng đã được cài đặt trước với các phiên bản **cần thiết cho hệ thống của bạn**. Nếu bạn cài đặt các gói trong môi trường Python toàn cục, bạn có thể sẽ **phá vỡ** một số chương trình đã được cài đặt sẵn cùng hệ thống.
+
+## Nơi các Gói được Cài đặt
+
+Khi bạn cài đặt Python, nó sẽ tạo ra một vài thư mục và tệp trong máy tính của bạn.
+
+Một vài thư mục này là những thư mục chịu trách nhiệm có tất cả các gói bạn cài đặt.
+
+Khi bạn chạy:
+
+
+
+```console
+// Đừng chạy lệnh này ngay, đây chỉ là một ví dụ 🤓
+$ pip install "fastapi[standard]"
+---> 100%
+```
+
+
+
+Lệnh này sẽ tải xuống một tệp nén với mã nguồn FastAPI, thường là từ PyPI.
+
+Nó cũng sẽ **tải xuống** các tệp cho các gói khác mà FastAPI phụ thuộc vào.
+
+Sau đó, nó sẽ **giải nén** tất cả các tệp đó và đưa chúng vào một thư mục trong máy tính của bạn.
+
+Mặc định, nó sẽ đưa các tệp đã tải xuống và giải nén vào thư mục được cài đặt cùng Python của bạn, đó là **môi trường toàn cục**.
+
+## Những Môi trường ảo là gì?
+
+Cách giải quyết cho vấn đề có tất cả các gói trong môi trường toàn cục là sử dụng một **môi trường ảo cho mỗi dự án** bạn làm việc.
+
+Một môi trường ảo là một **thư mục**, rất giống với môi trường toàn cục, trong đó bạn có thể cài đặt các gói cho một dự án.
+
+Vì vậy, mỗi dự án sẽ có một môi trường ảo riêng của nó (thư mục `.venv`) với các gói riêng của nó.
+
+```mermaid
+flowchart TB
+ subgraph stone-project[dự án philosophers-stone ]
+ stone(philosophers-stone) --->|phụ thuộc| harry-1
+ subgraph venv1[.venv]
+ harry-1[harry v1]
+ end
+ end
+ subgraph azkaban-project[dự án prisoner-of-azkaban ]
+ azkaban(prisoner-of-azkaban) --->|phụ thuộc| harry-3
+ subgraph venv2[.venv]
+ harry-3[harry v3]
+ end
+ end
+ stone-project ~~~ azkaban-project
+```
+
+## Kích hoạt Môi trường ảo nghĩa là gì
+
+Khi bạn kích hoạt một môi trường ảo, ví dụ với:
+
+//// tab | Linux, macOS
+
+
+
+////
+
+Lệnh này sẽ tạo hoặc sửa đổi một số [biến môi trường](environment-variables.md){.internal-link target=_blank} mà sẽ được sử dụng cho các lệnh tiếp theo.
+
+Một trong số đó là biến `PATH`.
+
+/// tip
+
+Bạn có thể tìm hiểu thêm về biến `PATH` trong [Biến môi trường](environment-variables.md#path-environment-variable){.internal-link target=_blank} section.
+
+///
+
+Kích hoạt môi trường ảo thêm đường dẫn `.venv/bin` (trên Linux và macOS) hoặc `.venv\Scripts` (trên Windows) vào biến `PATH`.
+
+Giả sử rằng trước khi kích hoạt môi trường, biến `PATH` như sau:
+
+//// tab | Linux, macOS
+
+```plaintext
+/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Nghĩa là hệ thống sẽ tìm kiếm chương trình trong:
+
+* `/usr/bin`
+* `/bin`
+* `/usr/sbin`
+* `/sbin`
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Windows\System32
+```
+
+Nghĩa là hệ thống sẽ tìm kiếm chương trình trong:
+
+* `C:\Windows\System32`
+
+////
+
+Sau khi kích hoạt môi trường ảo, biến `PATH` sẽ như sau:
+
+//// tab | Linux, macOS
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin
+```
+
+Nghĩa là hệ thống sẽ bắt đầu tìm kiếm chương trình trong:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin
+```
+
+trước khi tìm kiếm trong các thư mục khác.
+
+Vì vậy, khi bạn gõ `python` trong terminal, hệ thống sẽ tìm thấy chương trình Python trong:
+
+```plaintext
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+và sử dụng chương trình đó.
+
+////
+
+//// tab | Windows
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32
+```
+
+Nghĩa là hệ thống sẽ bắt đầu tìm kiếm chương trình trong:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts
+```
+
+trước khi tìm kiếm trong các thư mục khác.
+
+Vì vậy, khi bạn gõ `python` trong terminal, hệ thống sẽ tìm thấy chương trình Python trong:
+
+```plaintext
+C:\Users\user\code\awesome-project\.venv\Scripts\python
+```
+
+và sử dụng chương trình đó.
+
+////
+
+Một chi tiết quan trọng là nó sẽ đưa địa chỉ của môi trường ảo vào **đầu** của biến `PATH`. Hệ thống sẽ tìm kiếm nó **trước** khi tìm kiếm bất kỳ Python nào khác có sẵn. Vì vậy, khi bạn chạy `python`, nó sẽ sử dụng Python **từ môi trường ảo** thay vì bất kỳ Python nào khác (ví dụ, Python từ môi trường toàn cục).
+
+Kích hoạt một môi trường ảo cũng thay đổi một vài thứ khác, nhưng đây là một trong những điều quan trọng nhất mà nó thực hiện.
+
+## Kiểm tra một Môi trường ảo
+
+Khi bạn kiểm tra một môi trường ảo đã được kích hoạt chưa, ví dụ với:
+
+//// tab | Linux, macOS, Windows Bash
+
+
+
+```console
+$ which python
+
+/home/user/code/awesome-project/.venv/bin/python
+```
+
+
+
+////
+
+
+Điều đó có nghĩa là chương trình `python` sẽ được sử dụng là chương trình **trong môi trường ảo**.
+
+Bạn sử dụng `which` trên Linux và macOS và `Get-Command` trên Windows PowerShell.
+
+Cách hoạt động của lệnh này là nó sẽ đi và kiểm tra biến `PATH`, đi qua **mỗi đường dẫn theo thứ tự**, tìm kiếm chương trình được gọi là `python`. Khi nó tìm thấy nó, nó sẽ **hiển thị cho bạn đường dẫn** đến chương trình đó.
+
+Điều quan trọng nhất là khi bạn gọi `python`, đó chính là chương trình `python` được thực thi.
+
+Vì vậy, bạn có thể xác nhận nếu bạn đang ở trong môi trường ảo đúng.
+
+/// tip
+
+Dễ dàng kích hoạt một môi trường ảo, cài đặt Python, và sau đó **chuyển đến một dự án khác**.
+
+Và dự án thứ hai **sẽ không hoạt động** vì bạn đang sử dụng **Python không đúng**, từ một môi trường ảo cho một dự án khác.
+
+Thật tiện lợi khi có thể kiểm tra `python` nào đang được sử dụng 🤓
+
+///
+
+## Tại sao lại Huỷ kích hoạt một Môi trường ảo
+
+Ví dụ, bạn có thể làm việc trên một dự án `philosophers-stone`, **kích hoạt môi trường ảo**, cài đặt các gói và làm việc với môi trường ảo đó.
+
+Sau đó, bạn muốn làm việc trên **dự án khác** `prisoner-of-azkaban`.
+
+Bạn đi đến dự án đó:
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+```
+
+
+
+Nếu bạn không tắt môi trường ảo cho `philosophers-stone`, khi bạn chạy `python` trong terminal, nó sẽ cố gắng sử dụng Python từ `philosophers-stone`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+$ python main.py
+
+// Lỗi khi import sirius, nó không được cài đặt 😱
+Traceback (most recent call last):
+ File "main.py", line 1, in
+ import sirius
+```
+
+
+
+Nếu bạn huỷ kích hoạt môi trường ảo hiện tại và kích hoạt môi trường ảo mới cho `prisoner-of-azkaban`, khi bạn chạy `python`, nó sẽ sử dụng Python từ môi trường ảo trong `prisoner-of-azkaban`.
+
+
+
+```console
+$ cd ~/code/prisoner-of-azkaban
+
+// Bạn không cần phải ở trong thư mục trước để huỷ kích hoạt, bạn có thể làm điều đó ở bất kỳ đâu, ngay cả sau khi đi đến dự án khác 😎
+$ deactivate
+
+// Kích hoạt môi trường ảo trong prisoner-of-azkaban/.venv 🚀
+$ source .venv/bin/activate
+
+// Bây giờ khi bạn chạy python, nó sẽ tìm thấy gói sirius được cài đặt trong môi trường ảo này ✨
+$ python main.py
+
+I solemnly swear 🐺
+
+(Tôi long trọng thề 🐺 - câu này được lấy từ Harry Potter, chú thích của người dịch)
+```
+
+
+
+## Các cách làm tương tự
+
+Đây là một hướng dẫn đơn giản để bạn có thể bắt đầu và hiểu cách mọi thứ hoạt động **bên trong**.
+
+Có nhiều **cách khác nhau** để quản lí các môi trường ảo, các gói phụ thuộc (requirements), và các dự án.
+
+Một khi bạn đã sẵn sàng và muốn sử dụng một công cụ để **quản lí cả dự án**, các gói phụ thuộc, các môi trường ảo, v.v. Tôi sẽ khuyên bạn nên thử uv.
+
+`uv` có thể làm nhiều thứ, chẳng hạn:
+
+* **Cài đặt Python** cho bạn, bao gồm nhiều phiên bản khác nhau
+* Quản lí **các môi trường ảo** cho các dự án của bạn
+* Cài đặt **các gói (packages)**
+* Quản lí **các thành phần phụ thuộc và phiên bản** của các gói cho dự án của bạn
+* Đảm bảo rằng bạn có một **tập hợp chính xác** các gói và phiên bản để cài đặt, bao gồm các thành phần phụ thuộc của chúng, để bạn có thể đảm bảo rằng bạn có thể chạy dự án của bạn trong sản xuất chính xác như trong máy tính của bạn trong khi phát triển, điều này được gọi là **locking**
+* Và còn nhiều thứ khác nữa
+
+## Kết luận
+
+Nếu bạn đã đọc và hiểu hết những điều này, khá chắc là bây giờ bạn đã **biết nhiều hơn** về môi trường ảo so với kha khá lập trình viên khác đấy. 🤓
+
+Những hiểu biết chi tiết này có thể sẽ hữu ích với bạn trong tương lai khi mà bạn cần gỡ lỗi một vài thứ phức tạp, và bạn đã có những hiểu biết về **ngọn ngành gốc rễ cách nó hoạt động**. 😎
diff --git a/docs/yo/docs/index.md b/docs/yo/docs/index.md
index 3ad1483de..d6aa78b3d 100644
--- a/docs/yo/docs/index.md
+++ b/docs/yo/docs/index.md
@@ -12,7 +12,7 @@
-
-```console
-$ typer --install-completion
-
-zsh completion installed in /home/user/.bashrc.
-Completion will take effect once you restart the terminal.
-```
-
-
-
-```console
-// Use the command "live" and pass the language code as a CLI argument
-$ python ./scripts/docs.py live es
-
-[INFO] Serving on http://127.0.0.1:8008
-[INFO] Start watching changes
-[INFO] Start detecting changes
-```
-
-
-
-```console
-// Use the command new-lang, pass the language code as a CLI argument
-$ python ./scripts/docs.py new-lang ht
-
-Successfully initialized: docs/ht
-```
-
-
-
-```console
-// Use the command "build-all", this will take a bit
-$ python ./scripts/docs.py build-all
-
-Building docs for: en
-Building docs for: es
-Successfully built docs for: es
-```
-
-
-
-```console
-// Use the command "serve" after running "build-all"
-$ python ./scripts/docs.py serve
-
-Warning: this is a very simple server. For development, use mkdocs serve instead.
-This is here only to preview a site with translations already built.
-Make sure you run the build-all command first.
-Serving at: http://127.0.0.1:8008
-```
-
-
-
-## 测试
-
-你可以在本地运行下面的脚本来测试所有代码并生成 HTML 格式的覆盖率报告:
-
-
-请记住,当您一般读到“服务器”这个名词时,它可能指的是这两者之一。
+```console
+$ fastapi run main.py
-当提到远程主机时,通常将其称为**服务器**,但也称为**机器**(machine)、**VM**(虚拟机)、**节点**。 这些都是指某种类型的远程计算机,通常运行 Linux,您可以在其中运行程序。
+ FastAPI Starting production server 🚀
+ Searching for package file structure from directories
+ with __init__.py files
+ Importing from /home/user/code/awesomeapp
-## 安装服务器程序
+ module 🐍 main.py
-您可以使用以下命令安装 ASGI 兼容服务器:
+ code Importing the FastAPI app object from the module with
+ the following code:
-//// tab | Uvicorn
+ from main import app
-* Uvicorn,一个快如闪电 ASGI 服务器,基于 uvloop 和 httptools 构建。
+ app Using import string: main:app
-
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
-```console
-$ pip install "uvicorn[standard]"
+ Logs:
----> 100%
+ INFO Started server process [2306215]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Uvicorn running on http://0.0.0.0:8000(Press CTRL+C
+ to quit)
```
+$ fastapi run --workers 4 main.py
-这将安装带有`standard`扩展包(以获得高性能)的 Uvicorn 和 Gunicorn。
+ FastAPI Starting production server 🚀
-## Run Gunicorn with Uvicorn Workers
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
-接下来你可以通过以下命令运行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.
-```
-
-
+ module 🐍 main.py
+ code Importing the FastAPI app object from the module with the
+ following code:
-让我们看看每个选项的含义:
+ from main import app
-* `main:app`:这与 Uvicorn 使用的语法相同,`main` 表示名为"`main`"的 Python 模块,因此是文件 `main.py`。 `app` 是 **FastAPI** 应用程序的变量名称。
- * 你可以想象 `main:app` 相当于一个 Python `import` 语句,例如:
+ app Using import string: main:app
- ```Python
- from main import app
- ```
+ server Server started at http://0.0.0.0:8000
+ server Documentation at http://0.0.0.0:8000/docs
- * 因此,`main:app` 中的冒号相当于 `from main import app` 中的 Python `import` 部分。
+ Logs:
-* `--workers`:要使用的worker进程数量,每个进程将运行一个 Uvicorn worker进程,在本例中为 4 个worker进程。
-
-* `--worker-class`:在worker进程中使用的与 Gunicorn 兼容的工作类。
- * 这里我们传递了 Gunicorn 可以导入和使用的类:
-
- ```Python
- import uvicorn.workers.UvicornWorker
- ```
-
-* `--bind`:这告诉 Gunicorn 要监听的 IP 和端口,使用冒号 (`:`) 分隔 IP 和端口。
- * 如果您直接运行 Uvicorn,则可以使用`--host 0.0.0.0`和`--port 80`,而不是`--bind 0.0.0.0:80`(Gunicorn 选项)。
-
-
-在输出中,您可以看到它显示了每个进程的 **PID**(进程 ID)(它只是一个数字)。
-
-你可以看到:
-
-* Gunicorn **进程管理器** 以 PID `19499` 开头(在您的情况下,它将是一个不同的数字)。
-* 然后它开始`Listening at: http://0.0.0.0:80`。
-* 然后它检测到它必须使用 `uvicorn.workers.UvicornWorker` 处的worker类。
-* 然后它启动**4个worker**,每个都有自己的PID:`19511`、`19513`、`19514`和`19515`。
-
-Gunicorn 还将负责管理**死进程**和**重新启动**新进程(如果需要保持worker数量)。 因此,这在一定程度上有助于上面列表中**重启**的概念。
-
-尽管如此,您可能还希望有一些外部的东西,以确保在必要时**重新启动 Gunicorn**,并且**在启动时运行它**等。
+ INFO Uvicorn running on http://0.0.0.0:8000(Press CTRL+C to
+ quit)
+ INFO Started parent process [27365]
+ INFO Started server process [27368]
+ INFO Started server process [27369]
+ INFO Started server process [27370]
+ INFO Started server process [27367]
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Waiting for application startup.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+ INFO Application startup complete.
+```
-## Uvicorn with Workers
+
```console
-$ fastapi dev main.py
-INFO Using path main.py
-INFO Resolved absolute path /home/user/code/awesomeapp/main.py
-INFO Searching for package file structure from directories with __init__.py files
-INFO Importing from /home/user/code/awesomeapp
-
- ╭─ Python module file ─╮
- │ │
- │ 🐍 main.py │
- │ │
- ╰──────────────────────╯
-
-INFO Importing module main
-INFO Found importable FastAPI app
-
- ╭─ Importable FastAPI app ─╮
- │ │
- │ from main import app │
- │ │
- ╰──────────────────────────╯
-
-INFO Using import string main:app
-
- ╭────────── FastAPI CLI - Development mode ───────────╮
- │ │
- │ Serving at: http://127.0.0.1:8000 │
- │ │
- │ API docs: http://127.0.0.1:8000/docs │
- │ │
- │ Running in development mode, for production use: │
- │ │
- │ fastapi run │
- │ │
- ╰─────────────────────────────────────────────────────╯
-
-INFO: Will watch for changes in these directories: ['/home/user/code/awesomeapp']
-INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
-INFO: Started reloader process [2265862] using WatchFiles
-INFO: Started server process [2265873]
-INFO: Waiting for application startup.
-INFO: Application startup complete.
+$ fastapi dev main.py
+
+ FastAPI Starting development server 🚀
+
+ Searching for package file structure from directories with
+ __init__.py files
+ Importing from /home/user/code/awesomeapp
+
+ module 🐍 main.py
+
+ code Importing the FastAPI app object from the module with the
+ following code:
+
+ from main import app
+
+ app Using import string: main:app
+
+ server Server started at http://127.0.0.1:8000
+ server Documentation at http://127.0.0.1:8000/docs
+
+ tip Running in development mode, for production use:
+ fastapi run
+
+ Logs:
+
+ INFO Will watch for changes in these directories:
+ ['/home/user/code/awesomeapp']
+ INFO Uvicorn running on http://127.0.0.1:8000(Press CTRL+C to
+ quit)
+ INFO Started reloader process [383138] using WatchFiles
+ INFO Started server process [383153]
+ INFO Waiting for application startup.
+ INFO Application startup complete.
```