committed by
GitHub
1620 changed files with 42379 additions and 54172 deletions
@ -24,6 +24,8 @@ jobs: |
|||||
env: |
env: |
||||
GITHUB_CONTEXT: ${{ toJson(github) }} |
GITHUB_CONTEXT: ${{ toJson(github) }} |
||||
run: echo "$GITHUB_CONTEXT" |
run: echo "$GITHUB_CONTEXT" |
||||
|
# pin to actions/checkout@v5 for compatibility with latest-changes |
||||
|
# Ref: https://github.com/actions/checkout/issues/2313 |
||||
- uses: actions/checkout@v5 |
- uses: actions/checkout@v5 |
||||
with: |
with: |
||||
# To allow latest-changes to commit to the main branch |
# To allow latest-changes to commit to the main branch |
||||
@ -34,7 +36,7 @@ jobs: |
|||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} |
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} |
||||
with: |
with: |
||||
limit-access-to-actor: true |
limit-access-to-actor: true |
||||
- uses: tiangolo/[email protected].0 |
- uses: tiangolo/[email protected].1 |
||||
with: |
with: |
||||
token: ${{ secrets.GITHUB_TOKEN }} |
token: ${{ secrets.GITHUB_TOKEN }} |
||||
latest_changes_file: docs/en/docs/release-notes.md |
latest_changes_file: docs/en/docs/release-notes.md |
||||
|
|||||
@ -0,0 +1,93 @@ |
|||||
|
name: pre-commit |
||||
|
|
||||
|
on: |
||||
|
pull_request: |
||||
|
types: |
||||
|
- opened |
||||
|
- synchronize |
||||
|
|
||||
|
env: |
||||
|
# Forks and Dependabot don't have access to secrets |
||||
|
HAS_SECRETS: ${{ secrets.PRE_COMMIT != '' }} |
||||
|
|
||||
|
jobs: |
||||
|
pre-commit: |
||||
|
runs-on: ubuntu-latest |
||||
|
steps: |
||||
|
- name: Dump GitHub context |
||||
|
env: |
||||
|
GITHUB_CONTEXT: ${{ toJson(github) }} |
||||
|
run: echo "$GITHUB_CONTEXT" |
||||
|
- uses: actions/checkout@v5 |
||||
|
name: Checkout PR for own repo |
||||
|
if: env.HAS_SECRETS == 'true' |
||||
|
with: |
||||
|
# To be able to commit it needs to fetch the head of the branch, not the |
||||
|
# merge commit |
||||
|
ref: ${{ github.head_ref }} |
||||
|
# And it needs the full history to be able to compute diffs |
||||
|
fetch-depth: 0 |
||||
|
# A token other than the default GITHUB_TOKEN is needed to be able to trigger CI |
||||
|
token: ${{ secrets.PRE_COMMIT }} |
||||
|
# pre-commit lite ci needs the default checkout configs to work |
||||
|
- uses: actions/checkout@v5 |
||||
|
name: Checkout PR for fork |
||||
|
if: env.HAS_SECRETS == 'false' |
||||
|
with: |
||||
|
# To be able to commit it needs the head branch of the PR, the remote one |
||||
|
ref: ${{ github.event.pull_request.head.sha }} |
||||
|
fetch-depth: 0 |
||||
|
- name: Set up Python |
||||
|
uses: actions/setup-python@v6 |
||||
|
with: |
||||
|
python-version: "3.14" |
||||
|
- name: Setup uv |
||||
|
uses: astral-sh/setup-uv@v7 |
||||
|
with: |
||||
|
cache-dependency-glob: | |
||||
|
requirements**.txt |
||||
|
pyproject.toml |
||||
|
uv.lock |
||||
|
- name: Install Dependencies |
||||
|
run: | |
||||
|
uv venv |
||||
|
uv pip install -r requirements.txt |
||||
|
- name: Run prek - pre-commit |
||||
|
id: precommit |
||||
|
run: uvx prek run --from-ref origin/${GITHUB_BASE_REF} --to-ref HEAD --show-diff-on-failure |
||||
|
continue-on-error: true |
||||
|
- name: Commit and push changes |
||||
|
if: env.HAS_SECRETS == 'true' |
||||
|
run: | |
||||
|
git config user.name "github-actions[bot]" |
||||
|
git config user.email "github-actions[bot]@users.noreply.github.com" |
||||
|
git add -A |
||||
|
if git diff --staged --quiet; then |
||||
|
echo "No changes to commit" |
||||
|
else |
||||
|
git commit -m "🎨 Auto format" |
||||
|
git push |
||||
|
fi |
||||
|
- uses: pre-commit-ci/[email protected] |
||||
|
if: env.HAS_SECRETS == 'false' |
||||
|
with: |
||||
|
msg: 🎨 Auto format |
||||
|
- name: Error out on pre-commit errors |
||||
|
if: steps.precommit.outcome == 'failure' |
||||
|
run: exit 1 |
||||
|
|
||||
|
# https://github.com/marketplace/actions/alls-green#why |
||||
|
pre-commit-alls-green: # This job does nothing and is only used for the branch protection |
||||
|
if: always() |
||||
|
needs: |
||||
|
- pre-commit |
||||
|
runs-on: ubuntu-latest |
||||
|
steps: |
||||
|
- name: Dump GitHub context |
||||
|
env: |
||||
|
GITHUB_CONTEXT: ${{ toJson(github) }} |
||||
|
run: echo "$GITHUB_CONTEXT" |
||||
|
- name: Decide whether the needed jobs succeeded or failed |
||||
|
uses: re-actors/alls-green@release/v1 |
||||
|
with: |
||||
|
jobs: ${{ toJSON(needs) }} |
||||
@ -1,25 +1,59 @@ |
|||||
# See https://pre-commit.com for more information |
# See https://pre-commit.com for more information |
||||
# See https://pre-commit.com/hooks.html for more hooks |
# See https://pre-commit.com/hooks.html for more hooks |
||||
default_language_version: |
|
||||
python: python3.10 |
|
||||
repos: |
repos: |
||||
- repo: https://github.com/pre-commit/pre-commit-hooks |
- repo: https://github.com/pre-commit/pre-commit-hooks |
||||
rev: v6.0.0 |
rev: v6.0.0 |
||||
hooks: |
hooks: |
||||
- id: check-added-large-files |
- id: check-added-large-files |
||||
- id: check-toml |
args: ['--maxkb=750'] |
||||
- id: check-yaml |
- id: check-toml |
||||
|
- id: check-yaml |
||||
args: |
args: |
||||
- --unsafe |
- --unsafe |
||||
- id: end-of-file-fixer |
- id: end-of-file-fixer |
||||
- id: trailing-whitespace |
- id: trailing-whitespace |
||||
- repo: https://github.com/astral-sh/ruff-pre-commit |
|
||||
rev: v0.14.2 |
- repo: local |
||||
hooks: |
hooks: |
||||
- id: ruff |
- id: local-ruff-check |
||||
|
name: ruff check |
||||
|
entry: uv run ruff check --force-exclude --fix --exit-non-zero-on-fix |
||||
|
require_serial: true |
||||
|
language: unsupported |
||||
|
types: [python] |
||||
|
|
||||
|
- id: local-ruff-format |
||||
|
name: ruff format |
||||
|
entry: uv run ruff format --force-exclude --exit-non-zero-on-format |
||||
|
require_serial: true |
||||
|
language: unsupported |
||||
|
types: [python] |
||||
|
|
||||
|
- id: add-permalinks-pages |
||||
|
language: unsupported |
||||
|
name: add-permalinks-pages |
||||
|
entry: uv run ./scripts/docs.py add-permalinks-pages |
||||
args: |
args: |
||||
- --fix |
- --update-existing |
||||
- id: ruff-format |
files: ^docs/en/docs/.*\.md$ |
||||
ci: |
|
||||
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks |
- id: generate-readme |
||||
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate |
language: unsupported |
||||
|
name: generate README.md from index.md |
||||
|
entry: uv run ./scripts/docs.py generate-readme |
||||
|
files: ^docs/en/docs/index\.md|docs/en/data/sponsors\.yml|scripts/docs\.py$ |
||||
|
pass_filenames: false |
||||
|
|
||||
|
- id: update-languages |
||||
|
language: unsupported |
||||
|
name: update languages |
||||
|
entry: uv run ./scripts/docs.py update-languages |
||||
|
files: ^docs/.*|scripts/docs\.py$ |
||||
|
pass_filenames: false |
||||
|
|
||||
|
- id: ensure-non-translated |
||||
|
language: unsupported |
||||
|
name: ensure non-translated files are not modified |
||||
|
entry: uv run ./scripts/docs.py ensure-non-translated |
||||
|
files: ^docs/(?!en/).*|^scripts/docs\.py$ |
||||
|
pass_filenames: false |
||||
|
|||||
@ -1,16 +1,24 @@ |
|||||
# FastAPI bei Cloudanbietern bereitstellen { #deploy-fastapi-on-cloud-providers } |
# FastAPI bei Cloudanbietern deployen { #deploy-fastapi-on-cloud-providers } |
||||
|
|
||||
Sie können praktisch **jeden Cloudanbieter** verwenden, um Ihre FastAPI-Anwendung bereitzustellen. |
Sie können praktisch **jeden Cloudanbieter** verwenden, um Ihre FastAPI-Anwendung bereitzustellen. |
||||
|
|
||||
In den meisten Fällen bieten die großen Cloudanbieter Anleitungen zum Bereitstellen von FastAPI an. |
In den meisten Fällen bieten die großen Cloudanbieter Anleitungen zum Deployment von FastAPI an. |
||||
|
|
||||
## Cloudanbieter – Sponsoren { #cloud-providers-sponsors } |
## FastAPI Cloud { #fastapi-cloud } |
||||
|
|
||||
|
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** wurde vom selben Autor und Team hinter **FastAPI** entwickelt. |
||||
|
|
||||
|
Es vereinfacht den Prozess des **Erstellens**, **Deployens** und **Zugreifens** auf eine API mit minimalem Aufwand. |
||||
|
|
||||
Einige Cloudanbieter ✨ [**sponsern FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨, dies stellt die kontinuierliche und gesunde **Entwicklung** von FastAPI und seinem **Ökosystem** sicher. |
Es bringt die gleiche **Developer-Experience** beim Erstellen von Apps mit FastAPI auch zum **Deployment** in der Cloud. 🎉 |
||||
|
|
||||
|
FastAPI Cloud ist der Hauptsponsor und Finanzierungsgeber für die *FastAPI and friends* Open-Source-Projekte. ✨ |
||||
|
|
||||
|
## Cloudanbieter – Sponsoren { #cloud-providers-sponsors } |
||||
|
|
||||
Und es zeigt ihr wahres Engagement für FastAPI und seine **Community** (Sie), da sie Ihnen nicht nur einen **guten Service** bieten möchten, sondern auch sicherstellen möchten, dass Sie ein **gutes und gesundes Framework**, FastAPI, haben. 🙇 |
Einige andere Cloudanbieter ✨ [**sponsern FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨ ebenfalls. 🙇 |
||||
|
|
||||
Vielleicht möchten Sie deren Dienste ausprobieren und deren Anleitungen folgen: |
Sie könnten diese ebenfalls in Betracht ziehen, deren Anleitungen folgen und ihre Dienste ausprobieren: |
||||
|
|
||||
* <a href="https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi" class="external-link" target="_blank">Render</a> |
* <a href="https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi" class="external-link" target="_blank">Render</a> |
||||
* <a href="https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi" class="external-link" target="_blank">Railway</a> |
* <a href="https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi" class="external-link" target="_blank">Railway</a> |
||||
|
|||||
@ -0,0 +1,65 @@ |
|||||
|
# FastAPI Cloud { #fastapi-cloud } |
||||
|
|
||||
|
Sie können Ihre FastAPI-App in der <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> mit **einem einzigen Befehl** deployen – tragen Sie sich in die Warteliste ein, falls noch nicht geschehen. 🚀 |
||||
|
|
||||
|
## Anmelden { #login } |
||||
|
|
||||
|
Stellen Sie sicher, dass Sie bereits ein **FastAPI-Cloud-Konto** haben (wir haben Sie von der Warteliste eingeladen 😉). |
||||
|
|
||||
|
Melden Sie sich dann an: |
||||
|
|
||||
|
<div class="termy"> |
||||
|
|
||||
|
```console |
||||
|
$ fastapi login |
||||
|
|
||||
|
You are logged in to FastAPI Cloud 🚀 |
||||
|
``` |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
## Deployen { #deploy } |
||||
|
|
||||
|
Stellen Sie Ihre App jetzt mit **einem einzigen Befehl** bereit: |
||||
|
|
||||
|
<div class="termy"> |
||||
|
|
||||
|
```console |
||||
|
$ fastapi deploy |
||||
|
|
||||
|
Deploying to FastAPI Cloud... |
||||
|
|
||||
|
✅ Deployment successful! |
||||
|
|
||||
|
🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev |
||||
|
``` |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
Das war’s! Jetzt können Sie Ihre App unter dieser URL aufrufen. ✨ |
||||
|
|
||||
|
## Über FastAPI Cloud { #about-fastapi-cloud } |
||||
|
|
||||
|
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** wird vom gleichen Autor und Team hinter **FastAPI** entwickelt. |
||||
|
|
||||
|
Es vereinfacht den Prozess des **Erstellens**, **Deployens** und **Nutzens** einer API mit minimalem Aufwand. |
||||
|
|
||||
|
Es bringt die gleiche **Developer-Experience** beim Erstellen von Apps mit FastAPI auch zum **Deployment** in der Cloud. 🎉 |
||||
|
|
||||
|
Es kümmert sich außerdem um das meiste, was beim Deployen einer App nötig ist, zum Beispiel: |
||||
|
|
||||
|
* HTTPS |
||||
|
* Replikation, mit Autoscaling basierend auf Requests |
||||
|
* usw. |
||||
|
|
||||
|
FastAPI Cloud ist Hauptsponsor und Finanzierer der Open-Source-Projekte *FastAPI and friends*. ✨ |
||||
|
|
||||
|
## Bei anderen Cloudanbietern deployen { #deploy-to-other-cloud-providers } |
||||
|
|
||||
|
FastAPI ist Open Source und basiert auf Standards. Sie können FastAPI-Apps bei jedem Cloudanbieter Ihrer Wahl deployen. |
||||
|
|
||||
|
Folgen Sie den Anleitungen Ihres Cloudanbieters, um dort FastAPI-Apps zu deployen. 🤓 |
||||
|
|
||||
|
## Auf den eigenen Server deployen { #deploy-your-own-server } |
||||
|
|
||||
|
Ich werde Ihnen später in diesem **Deployment-Leitfaden** auch alle Details zeigen, sodass Sie verstehen, was passiert, was geschehen muss und wie Sie FastAPI-Apps selbst deployen können, auch auf Ihre eigenen Server. 🤓 |
||||
@ -0,0 +1,17 @@ |
|||||
|
# Alte 403-Authentifizierungsfehler-Statuscodes verwenden { #use-old-403-authentication-error-status-codes } |
||||
|
|
||||
|
Vor FastAPI-Version `0.122.0` verwendeten die integrierten Sicherheits-Utilities den HTTP-Statuscode `403 Forbidden`, wenn sie dem Client nach einer fehlgeschlagenen Authentifizierung einen Fehler zurückgaben. |
||||
|
|
||||
|
Ab FastAPI-Version `0.122.0` verwenden sie den passenderen HTTP-Statuscode `401 Unauthorized` und geben in der Response einen sinnvollen `WWW-Authenticate`-Header zurück, gemäß den HTTP-Spezifikationen, <a href="https://datatracker.ietf.org/doc/html/rfc7235#section-3.1" class="external-link" target="_blank">RFC 7235</a>, <a href="https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized" class="external-link" target="_blank">RFC 9110</a>. |
||||
|
|
||||
|
Aber falls Ihre Clients aus irgendeinem Grund vom alten Verhalten abhängen, können Sie darauf zurückgreifen, indem Sie in Ihren Sicherheitsklassen die Methode `make_not_authenticated_error` überschreiben. |
||||
|
|
||||
|
Sie können beispielsweise eine Unterklasse von `HTTPBearer` erstellen, die einen Fehler `403 Forbidden` zurückgibt, statt des Default-`401 Unauthorized`-Fehlers: |
||||
|
|
||||
|
{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *} |
||||
|
|
||||
|
/// tip | Tipp |
||||
|
|
||||
|
Beachten Sie, dass die Funktion die Exception-Instanz zurückgibt; sie wirft sie nicht. Das Werfen erfolgt im restlichen internen Code. |
||||
|
|
||||
|
/// |
||||
@ -1,3 +1,3 @@ |
|||||
# Ressourcen { #resources } |
# Ressourcen { #resources } |
||||
|
|
||||
Zusätzliche Ressourcen, externe Links, Artikel und mehr. ✈️ |
Zusätzliche Ressourcen, externe Links und mehr. ✈️ |
||||
|
|||||
@ -22,21 +22,13 @@ Hier ist eine allgemeine Idee, wie die Modelle mit ihren Passwortfeldern aussehe |
|||||
|
|
||||
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} |
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} |
||||
|
|
||||
/// info | Info |
### Über `**user_in.model_dump()` { #about-user-in-model-dump } |
||||
|
|
||||
In Pydantic v1 hieß die Methode `.dict()`, in Pydantic v2 wurde sie <abbr title="veraltet, obsolet: Es soll nicht mehr verwendet werden">deprecatet</abbr> (aber weiterhin unterstützt) und in `.model_dump()` umbenannt. |
#### Pydantics `.model_dump()` { #pydantics-model-dump } |
||||
|
|
||||
Die Beispiele hier verwenden `.dict()` für die Kompatibilität mit Pydantic v1, aber Sie sollten `.model_dump()` verwenden, wenn Sie Pydantic v2 verwenden können. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
### Über `**user_in.dict()` { #about-user-in-dict } |
|
||||
|
|
||||
#### Die `.dict()`-Methode von Pydantic { #pydantics-dict } |
|
||||
|
|
||||
`user_in` ist ein Pydantic-Modell der Klasse `UserIn`. |
`user_in` ist ein Pydantic-Modell der Klasse `UserIn`. |
||||
|
|
||||
Pydantic-Modelle haben eine `.dict()`-Methode, die ein <abbr title="Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> mit den Daten des Modells zurückgibt. |
Pydantic-Modelle haben eine `.model_dump()`-Methode, die ein <abbr title="Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> mit den Daten des Modells zurückgibt. |
||||
|
|
||||
Wenn wir also ein Pydantic-Objekt `user_in` erstellen, etwa so: |
Wenn wir also ein Pydantic-Objekt `user_in` erstellen, etwa so: |
||||
|
|
||||
@ -47,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="[email protected] |
|||||
und dann aufrufen: |
und dann aufrufen: |
||||
|
|
||||
```Python |
```Python |
||||
user_dict = user_in.dict() |
user_dict = user_in.model_dump() |
||||
``` |
``` |
||||
|
|
||||
haben wir jetzt ein `dict` mit den Daten in der Variablen `user_dict` (es ist ein `dict` statt eines Pydantic-Modellobjekts). |
haben wir jetzt ein `dict` mit den Daten in der Variablen `user_dict` (es ist ein `dict` statt eines Pydantic-Modellobjekts). |
||||
@ -103,20 +95,20 @@ UserInDB( |
|||||
|
|
||||
#### Ein Pydantic-Modell aus dem Inhalt eines anderen { #a-pydantic-model-from-the-contents-of-another } |
#### Ein Pydantic-Modell aus dem Inhalt eines anderen { #a-pydantic-model-from-the-contents-of-another } |
||||
|
|
||||
Da wir im obigen Beispiel `user_dict` von `user_in.dict()` bekommen haben, wäre dieser Code: |
Da wir im obigen Beispiel `user_dict` von `user_in.model_dump()` bekommen haben, wäre dieser Code: |
||||
|
|
||||
```Python |
```Python |
||||
user_dict = user_in.dict() |
user_dict = user_in.model_dump() |
||||
UserInDB(**user_dict) |
UserInDB(**user_dict) |
||||
``` |
``` |
||||
|
|
||||
gleichwertig zu: |
gleichwertig zu: |
||||
|
|
||||
```Python |
```Python |
||||
UserInDB(**user_in.dict()) |
UserInDB(**user_in.model_dump()) |
||||
``` |
``` |
||||
|
|
||||
... weil `user_in.dict()` ein `dict` ist, und dann lassen wir Python es „entpacken“, indem wir es an `UserInDB` mit vorangestelltem `**` übergeben. |
... weil `user_in.model_dump()` ein `dict` ist, und dann lassen wir Python es „entpacken“, indem wir es an `UserInDB` mit vorangestelltem `**` übergeben. |
||||
|
|
||||
Auf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pydantic-Modells. |
Auf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pydantic-Modells. |
||||
|
|
||||
@ -125,7 +117,7 @@ Auf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pyd |
|||||
Und dann fügen wir das zusätzliche Schlüsselwort-Argument `hashed_password=hashed_password` hinzu, wie in: |
Und dann fügen wir das zusätzliche Schlüsselwort-Argument `hashed_password=hashed_password` hinzu, wie in: |
||||
|
|
||||
```Python |
```Python |
||||
UserInDB(**user_in.dict(), hashed_password=hashed_password) |
UserInDB(**user_in.model_dump(), hashed_password=hashed_password) |
||||
``` |
``` |
||||
|
|
||||
... was so ist wie: |
... was so ist wie: |
||||
@ -180,7 +172,6 @@ Wenn Sie eine <a href="https://docs.pydantic.dev/latest/concepts/types/#unions" |
|||||
|
|
||||
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *} |
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *} |
||||
|
|
||||
|
|
||||
### `Union` in Python 3.10 { #union-in-python-3-10 } |
### `Union` in Python 3.10 { #union-in-python-3-10 } |
||||
|
|
||||
In diesem Beispiel übergeben wir `Union[PlaneItem, CarItem]` als Wert des Arguments `response_model`. |
In diesem Beispiel übergeben wir `Union[PlaneItem, CarItem]` als Wert des Arguments `response_model`. |
||||
@ -203,7 +194,6 @@ Dafür verwenden Sie Pythons Standard-`typing.List` (oder nur `list` in Python 3 |
|||||
|
|
||||
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *} |
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *} |
||||
|
|
||||
|
|
||||
## Response mit beliebigem `dict` { #response-with-arbitrary-dict } |
## Response mit beliebigem `dict` { #response-with-arbitrary-dict } |
||||
|
|
||||
Sie können auch eine Response deklarieren, die ein beliebiges `dict` zurückgibt, indem Sie nur die Typen der Schlüssel und Werte ohne ein Pydantic-Modell deklarieren. |
Sie können auch eine Response deklarieren, die ein beliebiges `dict` zurückgibt, indem Sie nur die Typen der Schlüssel und Werte ohne ein Pydantic-Modell deklarieren. |
||||
@ -214,7 +204,6 @@ In diesem Fall können Sie `typing.Dict` verwenden (oder nur `dict` in Python 3. |
|||||
|
|
||||
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *} |
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *} |
||||
|
|
||||
|
|
||||
## Zusammenfassung { #recap } |
## Zusammenfassung { #recap } |
||||
|
|
||||
Verwenden Sie gerne mehrere Pydantic-Modelle und vererben Sie je nach Bedarf. |
Verwenden Sie gerne mehrere Pydantic-Modelle und vererben Sie je nach Bedarf. |
||||
|
|||||
@ -1,247 +0,0 @@ |
|||||
# 🌖 📨 🗄 |
|
||||
|
|
||||
/// warning |
|
||||
|
|
||||
👉 👍 🏧 ❔. |
|
||||
|
|
||||
🚥 👆 ▶️ ⏮️ **FastAPI**, 👆 💪 🚫 💪 👉. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
👆 💪 📣 🌖 📨, ⏮️ 🌖 👔 📟, 🔉 🆎, 📛, ♒️. |
|
||||
|
|
||||
👈 🌖 📨 🔜 🔌 🗄 🔗, 👫 🔜 😑 🛠️ 🩺. |
|
||||
|
|
||||
✋️ 👈 🌖 📨 👆 ✔️ ⚒ 💭 👆 📨 `Response` 💖 `JSONResponse` 🔗, ⏮️ 👆 👔 📟 & 🎚. |
|
||||
|
|
||||
## 🌖 📨 ⏮️ `model` |
|
||||
|
|
||||
👆 💪 🚶♀️ 👆 *➡ 🛠️ 👨🎨* 🔢 `responses`. |
|
||||
|
|
||||
⚫️ 📨 `dict`, 🔑 👔 📟 🔠 📨, 💖 `200`, & 💲 🎏 `dict`Ⓜ ⏮️ ℹ 🔠 👫. |
|
||||
|
|
||||
🔠 👈 📨 `dict`Ⓜ 💪 ✔️ 🔑 `model`, ⚗ Pydantic 🏷, 💖 `response_model`. |
|
||||
|
|
||||
**FastAPI** 🔜 ✊ 👈 🏷, 🏗 🚮 🎻 🔗 & 🔌 ⚫️ ☑ 🥉 🗄. |
|
||||
|
|
||||
🖼, 📣 ➕1️⃣ 📨 ⏮️ 👔 📟 `404` & Pydantic 🏷 `Message`, 👆 💪 ✍: |
|
||||
|
|
||||
{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *} |
|
||||
|
|
||||
/// note |
|
||||
|
|
||||
✔️ 🤯 👈 👆 ✔️ 📨 `JSONResponse` 🔗. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
/// info |
|
||||
|
|
||||
`model` 🔑 🚫 🍕 🗄. |
|
||||
|
|
||||
**FastAPI** 🔜 ✊ Pydantic 🏷 ⚪️➡️ 📤, 🏗 `JSON Schema`, & 🚮 ⚫️ ☑ 🥉. |
|
||||
|
|
||||
☑ 🥉: |
|
||||
|
|
||||
* 🔑 `content`, 👈 ✔️ 💲 ➕1️⃣ 🎻 🎚 (`dict`) 👈 🔌: |
|
||||
* 🔑 ⏮️ 📻 🆎, ✅ `application/json`, 👈 🔌 💲 ➕1️⃣ 🎻 🎚, 👈 🔌: |
|
||||
* 🔑 `schema`, 👈 ✔️ 💲 🎻 🔗 ⚪️➡️ 🏷, 📥 ☑ 🥉. |
|
||||
* **FastAPI** 🚮 🔗 📥 🌐 🎻 🔗 ➕1️⃣ 🥉 👆 🗄 ↩️ ✅ ⚫️ 🔗. 👉 🌌, 🎏 🈸 & 👩💻 💪 ⚙️ 👈 🎻 🔗 🔗, 🚚 👻 📟 ⚡ 🧰, ♒️. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
🏗 📨 🗄 👉 *➡ 🛠️* 🔜: |
|
||||
|
|
||||
```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" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
🔗 🔗 ➕1️⃣ 🥉 🔘 🗄 🔗: |
|
||||
|
|
||||
```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" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
## 🌖 🔉 🆎 👑 📨 |
|
||||
|
|
||||
👆 💪 ⚙️ 👉 🎏 `responses` 🔢 🚮 🎏 🔉 🆎 🎏 👑 📨. |
|
||||
|
|
||||
🖼, 👆 💪 🚮 🌖 📻 🆎 `image/png`, 📣 👈 👆 *➡ 🛠️* 💪 📨 🎻 🎚 (⏮️ 📻 🆎 `application/json`) ⚖️ 🇩🇴 🖼: |
|
||||
|
|
||||
{* ../../docs_src/additional_responses/tutorial002.py hl[19:24,28] *} |
|
||||
|
|
||||
/// note |
|
||||
|
|
||||
👀 👈 👆 ✔️ 📨 🖼 ⚙️ `FileResponse` 🔗. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
/// info |
|
||||
|
|
||||
🚥 👆 ✔ 🎏 📻 🆎 🎯 👆 `responses` 🔢, FastAPI 🔜 🤔 📨 ✔️ 🎏 📻 🆎 👑 📨 🎓 (🔢 `application/json`). |
|
||||
|
|
||||
✋️ 🚥 👆 ✔️ ✔ 🛃 📨 🎓 ⏮️ `None` 🚮 📻 🆎, FastAPI 🔜 ⚙️ `application/json` 🙆 🌖 📨 👈 ✔️ 👨💼 🏷. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
## 🌀 ℹ |
|
||||
|
|
||||
👆 💪 🌀 📨 ℹ ⚪️➡️ 💗 🥉, 🔌 `response_model`, `status_code`, & `responses` 🔢. |
|
||||
|
|
||||
👆 💪 📣 `response_model`, ⚙️ 🔢 👔 📟 `200` (⚖️ 🛃 1️⃣ 🚥 👆 💪), & ⤴️ 📣 🌖 ℹ 👈 🎏 📨 `responses`, 🔗 🗄 🔗. |
|
||||
|
|
||||
**FastAPI** 🔜 🚧 🌖 ℹ ⚪️➡️ `responses`, & 🌀 ⚫️ ⏮️ 🎻 🔗 ⚪️➡️ 👆 🏷. |
|
||||
|
|
||||
🖼, 👆 💪 📣 📨 ⏮️ 👔 📟 `404` 👈 ⚙️ Pydantic 🏷 & ✔️ 🛃 `description`. |
|
||||
|
|
||||
& 📨 ⏮️ 👔 📟 `200` 👈 ⚙️ 👆 `response_model`, ✋️ 🔌 🛃 `example`: |
|
||||
|
|
||||
{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *} |
|
||||
|
|
||||
⚫️ 🔜 🌐 🌀 & 🔌 👆 🗄, & 🎦 🛠️ 🩺: |
|
||||
|
|
||||
<img src="/img/tutorial/additional-responses/image01.png"> |
|
||||
|
|
||||
## 🌀 🔢 📨 & 🛃 🕐 |
|
||||
|
|
||||
👆 💪 💚 ✔️ 🔁 📨 👈 ✔ 📚 *➡ 🛠️*, ✋️ 👆 💚 🌀 👫 ⏮️ 🛃 📨 💚 🔠 *➡ 🛠️*. |
|
||||
|
|
||||
📚 💼, 👆 💪 ⚙️ 🐍 ⚒ "🏗" `dict` ⏮️ `**dict_to_unpack`: |
|
||||
|
|
||||
```Python |
|
||||
old_dict = { |
|
||||
"old key": "old value", |
|
||||
"second old key": "second old value", |
|
||||
} |
|
||||
new_dict = {**old_dict, "new key": "new value"} |
|
||||
``` |
|
||||
|
|
||||
📥, `new_dict` 🔜 🔌 🌐 🔑-💲 👫 ⚪️➡️ `old_dict` ➕ 🆕 🔑-💲 👫: |
|
||||
|
|
||||
```Python |
|
||||
{ |
|
||||
"old key": "old value", |
|
||||
"second old key": "second old value", |
|
||||
"new key": "new value", |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
👆 💪 ⚙️ 👈 ⚒ 🏤-⚙️ 🔢 📨 👆 *➡ 🛠️* & 🌀 👫 ⏮️ 🌖 🛃 🕐. |
|
||||
|
|
||||
🖼: |
|
||||
|
|
||||
{* ../../docs_src/additional_responses/tutorial004.py hl[13:17,26] *} |
|
||||
|
|
||||
## 🌖 ℹ 🔃 🗄 📨 |
|
||||
|
|
||||
👀 ⚫️❔ ⚫️❔ 👆 💪 🔌 📨, 👆 💪 ✅ 👉 📄 🗄 🔧: |
|
||||
|
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">🗄 📨 🎚</a>, ⚫️ 🔌 `Response Object`. |
|
||||
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">🗄 📨 🎚</a>, 👆 💪 🔌 🕳 ⚪️➡️ 👉 🔗 🔠 📨 🔘 👆 `responses` 🔢. ✅ `description`, `headers`, `content` (🔘 👉 👈 👆 📣 🎏 🔉 🆎 & 🎻 🔗), & `links`. |
|
||||
@ -1,41 +0,0 @@ |
|||||
# 🌖 👔 📟 |
|
||||
|
|
||||
🔢, **FastAPI** 🔜 📨 📨 ⚙️ `JSONResponse`, 🚮 🎚 👆 📨 ⚪️➡️ 👆 *➡ 🛠️* 🔘 👈 `JSONResponse`. |
|
||||
|
|
||||
⚫️ 🔜 ⚙️ 🔢 👔 📟 ⚖️ 1️⃣ 👆 ⚒ 👆 *➡ 🛠️*. |
|
||||
|
|
||||
## 🌖 👔 📟 |
|
||||
|
|
||||
🚥 👆 💚 📨 🌖 👔 📟 ↖️ ⚪️➡️ 👑 1️⃣, 👆 💪 👈 🛬 `Response` 🔗, 💖 `JSONResponse`, & ⚒ 🌖 👔 📟 🔗. |
|
||||
|
|
||||
🖼, ➡️ 💬 👈 👆 💚 ✔️ *➡ 🛠️* 👈 ✔ ℹ 🏬, & 📨 🇺🇸🔍 👔 📟 2️⃣0️⃣0️⃣ "👌" 🕐❔ 🏆. |
|
||||
|
|
||||
✋️ 👆 💚 ⚫️ 🚫 🆕 🏬. & 🕐❔ 🏬 🚫 🔀 ⏭, ⚫️ ✍ 👫, & 📨 🇺🇸🔍 👔 📟 2️⃣0️⃣1️⃣ "✍". |
|
||||
|
|
||||
🏆 👈, 🗄 `JSONResponse`, & 📨 👆 🎚 📤 🔗, ⚒ `status_code` 👈 👆 💚: |
|
||||
|
|
||||
{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *} |
|
||||
|
|
||||
/// warning |
|
||||
|
|
||||
🕐❔ 👆 📨 `Response` 🔗, 💖 🖼 🔛, ⚫️ 🔜 📨 🔗. |
|
||||
|
|
||||
⚫️ 🏆 🚫 🎻 ⏮️ 🏷, ♒️. |
|
||||
|
|
||||
⚒ 💭 ⚫️ ✔️ 📊 👆 💚 ⚫️ ✔️, & 👈 💲 ☑ 🎻 (🚥 👆 ⚙️ `JSONResponse`). |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
/// note | 📡 ℹ |
|
||||
|
|
||||
👆 💪 ⚙️ `from starlette.responses import JSONResponse`. |
|
||||
|
|
||||
**FastAPI** 🚚 🎏 `starlette.responses` `fastapi.responses` 🏪 👆, 👩💻. ✋️ 🌅 💪 📨 👟 🔗 ⚪️➡️ 💃. 🎏 ⏮️ `status`. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
## 🗄 & 🛠️ 🩺 |
|
||||
|
|
||||
🚥 👆 📨 🌖 👔 📟 & 📨 🔗, 👫 🏆 🚫 🔌 🗄 🔗 (🛠️ 🩺), ↩️ FastAPI 🚫 ✔️ 🌌 💭 ⏪ ⚫️❔ 👆 🚶 📨. |
|
||||
|
|
||||
✋️ 👆 💪 📄 👈 👆 📟, ⚙️: [🌖 📨](additional-responses.md){.internal-link target=_blank}. |
|
||||
@ -1,65 +0,0 @@ |
|||||
# 🏧 🔗 |
|
||||
|
|
||||
## 🔗 🔗 |
|
||||
|
|
||||
🌐 🔗 👥 ✔️ 👀 🔧 🔢 ⚖️ 🎓. |
|
||||
|
|
||||
✋️ 📤 💪 💼 🌐❔ 👆 💚 💪 ⚒ 🔢 🔛 🔗, 🍵 ✔️ 📣 📚 🎏 🔢 ⚖️ 🎓. |
|
||||
|
|
||||
➡️ 🌈 👈 👥 💚 ✔️ 🔗 👈 ✅ 🚥 🔢 🔢 `q` 🔌 🔧 🎚. |
|
||||
|
|
||||
✋️ 👥 💚 💪 🔗 👈 🔧 🎚. |
|
||||
|
|
||||
## "🇧🇲" 👐 |
|
||||
|
|
||||
🐍 📤 🌌 ⚒ 👐 🎓 "🇧🇲". |
|
||||
|
|
||||
🚫 🎓 ⚫️ (❔ ⏪ 🇧🇲), ✋️ 👐 👈 🎓. |
|
||||
|
|
||||
👈, 👥 📣 👩🔬 `__call__`: |
|
||||
|
|
||||
{* ../../docs_src/dependencies/tutorial011.py hl[10] *} |
|
||||
|
|
||||
👉 💼, 👉 `__call__` ⚫️❔ **FastAPI** 🔜 ⚙️ ✅ 🌖 🔢 & 🎧-🔗, & 👉 ⚫️❔ 🔜 🤙 🚶♀️ 💲 🔢 👆 *➡ 🛠️ 🔢* ⏪. |
|
||||
|
|
||||
## 🔗 👐 |
|
||||
|
|
||||
& 🔜, 👥 💪 ⚙️ `__init__` 📣 🔢 👐 👈 👥 💪 ⚙️ "🔗" 🔗: |
|
||||
|
|
||||
{* ../../docs_src/dependencies/tutorial011.py hl[7] *} |
|
||||
|
|
||||
👉 💼, **FastAPI** 🏆 🚫 ⏱ 👆 ⚖️ 💅 🔃 `__init__`, 👥 🔜 ⚙️ ⚫️ 🔗 👆 📟. |
|
||||
|
|
||||
## ✍ 👐 |
|
||||
|
|
||||
👥 💪 ✍ 👐 👉 🎓 ⏮️: |
|
||||
|
|
||||
{* ../../docs_src/dependencies/tutorial011.py hl[16] *} |
|
||||
|
|
||||
& 👈 🌌 👥 💪 "🔗" 👆 🔗, 👈 🔜 ✔️ `"bar"` 🔘 ⚫️, 🔢 `checker.fixed_content`. |
|
||||
|
|
||||
## ⚙️ 👐 🔗 |
|
||||
|
|
||||
⤴️, 👥 💪 ⚙️ 👉 `checker` `Depends(checker)`, ↩️ `Depends(FixedContentQueryChecker)`, ↩️ 🔗 👐, `checker`, 🚫 🎓 ⚫️. |
|
||||
|
|
||||
& 🕐❔ ❎ 🔗, **FastAPI** 🔜 🤙 👉 `checker` 💖: |
|
||||
|
|
||||
```Python |
|
||||
checker(q="somequery") |
|
||||
``` |
|
||||
|
|
||||
...& 🚶♀️ ⚫️❔ 👈 📨 💲 🔗 👆 *➡ 🛠️ 🔢* 🔢 `fixed_content_included`: |
|
||||
|
|
||||
{* ../../docs_src/dependencies/tutorial011.py hl[20] *} |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
🌐 👉 💪 😑 🎭. & ⚫️ 💪 🚫 📶 🆑 ❔ ⚫️ ⚠. |
|
||||
|
|
||||
👫 🖼 😫 🙅, ✋️ 🎦 ❔ ⚫️ 🌐 👷. |
|
||||
|
|
||||
📃 🔃 💂♂, 📤 🚙 🔢 👈 🛠️ 👉 🎏 🌌. |
|
||||
|
|
||||
🚥 👆 🤔 🌐 👉, 👆 ⏪ 💭 ❔ 👈 🚙 🧰 💂♂ 👷 🔘. |
|
||||
|
|
||||
/// |
|
||||
@ -1,93 +0,0 @@ |
|||||
# 🔁 💯 |
|
||||
|
|
||||
👆 ✔️ ⏪ 👀 ❔ 💯 👆 **FastAPI** 🈸 ⚙️ 🚚 `TestClient`. 🆙 🔜, 👆 ✔️ 🕴 👀 ❔ ✍ 🔁 💯, 🍵 ⚙️ `async` 🔢. |
|
||||
|
|
||||
➖ 💪 ⚙️ 🔁 🔢 👆 💯 💪 ⚠, 🖼, 🕐❔ 👆 🔬 👆 💽 🔁. 🌈 👆 💚 💯 📨 📨 👆 FastAPI 🈸 & ⤴️ ✔ 👈 👆 👩💻 ⏪ ✍ ☑ 💽 💽, ⏪ ⚙️ 🔁 💽 🗃. |
|
||||
|
|
||||
➡️ 👀 ❔ 👥 💪 ⚒ 👈 👷. |
|
||||
|
|
||||
## pytest.mark.anyio |
|
||||
|
|
||||
🚥 👥 💚 🤙 🔁 🔢 👆 💯, 👆 💯 🔢 ✔️ 🔁. AnyIO 🚚 👌 📁 👉, 👈 ✔ 👥 ✔ 👈 💯 🔢 🤙 🔁. |
|
||||
|
|
||||
## 🇸🇲 |
|
||||
|
|
||||
🚥 👆 **FastAPI** 🈸 ⚙️ 😐 `def` 🔢 ↩️ `async def`, ⚫️ `async` 🈸 🔘. |
|
||||
|
|
||||
`TestClient` 🔨 🎱 🔘 🤙 🔁 FastAPI 🈸 👆 😐 `def` 💯 🔢, ⚙️ 🐩 ✳. ✋️ 👈 🎱 🚫 👷 🚫🔜 🕐❔ 👥 ⚙️ ⚫️ 🔘 🔁 🔢. 🏃 👆 💯 🔁, 👥 💪 🙅♂ 📏 ⚙️ `TestClient` 🔘 👆 💯 🔢. |
|
||||
|
|
||||
`TestClient` ⚓️ 🔛 <a href="https://www.python-httpx.org" class="external-link" target="_blank">🇸🇲</a>, & ↩️, 👥 💪 ⚙️ ⚫️ 🔗 💯 🛠️. |
|
||||
|
|
||||
## 🖼 |
|
||||
|
|
||||
🙅 🖼, ➡️ 🤔 📁 📊 🎏 1️⃣ 🔬 [🦏 🈸](../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 *} |
|
||||
|
|
||||
## 🏃 ⚫️ |
|
||||
|
|
||||
👆 💪 🏃 👆 💯 🐌 📨: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ pytest |
|
||||
|
|
||||
---> 100% |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
## ℹ |
|
||||
|
|
||||
📑 `@pytest.mark.anyio` 💬 ✳ 👈 👉 💯 🔢 🔜 🤙 🔁: |
|
||||
|
|
||||
{* ../../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 |
|
||||
|
|
||||
🗒 👈 👥 ⚙️ 🔁/⌛ ⏮️ 🆕 `AsyncClient` - 📨 🔁. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
## 🎏 🔁 🔢 🤙 |
|
||||
|
|
||||
🔬 🔢 🔜 🔁, 👆 💪 🔜 🤙 (& `await`) 🎏 `async` 🔢 ↖️ ⚪️➡️ 📨 📨 👆 FastAPI 🈸 👆 💯, ⚫️❔ 👆 🔜 🤙 👫 🙆 🙆 👆 📟. |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
🚥 👆 ⚔ `RuntimeError: Task attached to a different loop` 🕐❔ 🛠️ 🔁 🔢 🤙 👆 💯 (✅ 🕐❔ ⚙️ <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">✳ MotorClient</a>) 💭 🔗 🎚 👈 💪 🎉 ➰ 🕴 🏞 🔁 🔢, ✅ `'@app.on_event("startup")` ⏲. |
|
||||
|
|
||||
/// |
|
||||
@ -1,359 +0,0 @@ |
|||||
# ⛅ 🗳 |
|
||||
|
|
||||
⚠, 👆 5️⃣📆 💪 ⚙️ **🗳** 💽 💖 Traefik ⚖️ 👌 ⏮️ 📳 👈 🚮 ➕ ➡ 🔡 👈 🚫 👀 👆 🈸. |
|
||||
|
|
||||
👫 💼 👆 💪 ⚙️ `root_path` 🔗 👆 🈸. |
|
||||
|
|
||||
`root_path` 🛠️ 🚚 🔫 🔧 (👈 FastAPI 🏗 🔛, 🔘 💃). |
|
||||
|
|
||||
`root_path` ⚙️ 🍵 👫 🎯 💼. |
|
||||
|
|
||||
& ⚫️ ⚙️ 🔘 🕐❔ 🗜 🎧-🈸. |
|
||||
|
|
||||
## 🗳 ⏮️ 🎞 ➡ 🔡 |
|
||||
|
|
||||
✔️ 🗳 ⏮️ 🎞 ➡ 🔡, 👉 💼, ⛓ 👈 👆 💪 📣 ➡ `/app` 👆 📟, ✋️ ⤴️, 👆 🚮 🧽 🔛 🔝 (🗳) 👈 🔜 🚮 👆 **FastAPI** 🈸 🔽 ➡ 💖 `/api/v1`. |
|
||||
|
|
||||
👉 💼, ⏮️ ➡ `/app` 🔜 🤙 🍦 `/api/v1/app`. |
|
||||
|
|
||||
✋️ 🌐 👆 📟 ✍ 🤔 📤 `/app`. |
|
||||
|
|
||||
& 🗳 🔜 **"❎"** **➡ 🔡** 🔛 ✈ ⏭ 📶 📨 Uvicorn, 🚧 👆 🈸 🤔 👈 ⚫️ 🍦 `/app`, 👈 👆 🚫 ✔️ ℹ 🌐 👆 📟 🔌 🔡 `/api/v1`. |
|
||||
|
|
||||
🆙 📥, 🌐 🔜 👷 🛎. |
|
||||
|
|
||||
✋️ ⤴️, 🕐❔ 👆 📂 🛠️ 🩺 🎚 (🕸), ⚫️ 🔜 ⌛ 🤚 🗄 🔗 `/openapi.json`, ↩️ `/api/v1/openapi.json`. |
|
||||
|
|
||||
, 🕸 (👈 🏃 🖥) 🔜 🔄 🏆 `/openapi.json` & 🚫🔜 💪 🤚 🗄 🔗. |
|
||||
|
|
||||
↩️ 👥 ✔️ 🗳 ⏮️ ➡ 🔡 `/api/v1` 👆 📱, 🕸 💪 ☕ 🗄 🔗 `/api/v1/openapi.json`. |
|
||||
|
|
||||
```mermaid |
|
||||
graph LR |
|
||||
|
|
||||
browser("Browser") |
|
||||
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"] |
|
||||
server["Server on http://127.0.0.1:8000/app"] |
|
||||
|
|
||||
browser --> proxy |
|
||||
proxy --> server |
|
||||
``` |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
📢 `0.0.0.0` 🛎 ⚙️ ⛓ 👈 📋 👂 🔛 🌐 📢 💪 👈 🎰/💽. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
🩺 🎚 🔜 💪 🗄 🔗 📣 👈 👉 🛠️ `server` 🔎 `/api/v1` (⛅ 🗳). 🖼: |
|
||||
|
|
||||
```JSON hl_lines="4-8" |
|
||||
{ |
|
||||
"openapi": "3.0.2", |
|
||||
// More stuff here |
|
||||
"servers": [ |
|
||||
{ |
|
||||
"url": "/api/v1" |
|
||||
} |
|
||||
], |
|
||||
"paths": { |
|
||||
// More stuff here |
|
||||
} |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
👉 🖼, "🗳" 💪 🕳 💖 **Traefik**. & 💽 🔜 🕳 💖 **Uvicorn**, 🏃♂ 👆 FastAPI 🈸. |
|
||||
|
|
||||
### 🚚 `root_path` |
|
||||
|
|
||||
🏆 👉, 👆 💪 ⚙️ 📋 ⏸ 🎛 `--root-path` 💖: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ uvicorn main:app --root-path /api/v1 |
|
||||
|
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
🚥 👆 ⚙️ Hypercorn, ⚫️ ✔️ 🎛 `--root-path`. |
|
||||
|
|
||||
/// note | 📡 ℹ |
|
||||
|
|
||||
🔫 🔧 🔬 `root_path` 👉 ⚙️ 💼. |
|
||||
|
|
||||
& `--root-path` 📋 ⏸ 🎛 🚚 👈 `root_path`. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
### ✅ ⏮️ `root_path` |
|
||||
|
|
||||
👆 💪 🤚 ⏮️ `root_path` ⚙️ 👆 🈸 🔠 📨, ⚫️ 🍕 `scope` 📖 (👈 🍕 🔫 🔌). |
|
||||
|
|
||||
📥 👥 ✅ ⚫️ 📧 🎦 🎯. |
|
||||
|
|
||||
{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *} |
|
||||
|
|
||||
⤴️, 🚥 👆 ▶️ Uvicorn ⏮️: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ uvicorn main:app --root-path /api/v1 |
|
||||
|
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
📨 🔜 🕳 💖: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"message": "Hello World", |
|
||||
"root_path": "/api/v1" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
### ⚒ `root_path` FastAPI 📱 |
|
||||
|
|
||||
👐, 🚥 👆 🚫 ✔️ 🌌 🚚 📋 ⏸ 🎛 💖 `--root-path` ⚖️ 🌓, 👆 💪 ⚒ `root_path` 🔢 🕐❔ 🏗 👆 FastAPI 📱: |
|
||||
|
|
||||
{* ../../docs_src/behind_a_proxy/tutorial002.py hl[3] *} |
|
||||
|
|
||||
🚶♀️ `root_path` `FastAPI` 🔜 🌓 🚶♀️ `--root-path` 📋 ⏸ 🎛 Uvicorn ⚖️ Hypercorn. |
|
||||
|
|
||||
### 🔃 `root_path` |
|
||||
|
|
||||
✔️ 🤯 👈 💽 (Uvicorn) 🏆 🚫 ⚙️ 👈 `root_path` 🕳 🙆 🌘 🚶♀️ ⚫️ 📱. |
|
||||
|
|
||||
✋️ 🚥 👆 🚶 ⏮️ 👆 🖥 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000/app</a> 👆 🔜 👀 😐 📨: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"message": "Hello World", |
|
||||
"root_path": "/api/v1" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
, ⚫️ 🏆 🚫 ⌛ 🔐 `http://127.0.0.1:8000/api/v1/app`. |
|
||||
|
|
||||
Uvicorn 🔜 ⌛ 🗳 🔐 Uvicorn `http://127.0.0.1:8000/app`, & ⤴️ ⚫️ 🔜 🗳 🎯 🚮 ➕ `/api/v1` 🔡 🔛 🔝. |
|
||||
|
|
||||
## 🔃 🗳 ⏮️ 🎞 ➡ 🔡 |
|
||||
|
|
||||
✔️ 🤯 👈 🗳 ⏮️ 🎞 ➡ 🔡 🕴 1️⃣ 🌌 🔗 ⚫️. |
|
||||
|
|
||||
🎲 📚 💼 🔢 🔜 👈 🗳 🚫 ✔️ 🏚 ➡ 🔡. |
|
||||
|
|
||||
💼 💖 👈 (🍵 🎞 ➡ 🔡), 🗳 🔜 👂 🔛 🕳 💖 `https://myawesomeapp.com`, & ⤴️ 🚥 🖥 🚶 `https://myawesomeapp.com/api/v1/app` & 👆 💽 (✅ Uvicorn) 👂 🔛 `http://127.0.0.1:8000` 🗳 (🍵 🎞 ➡ 🔡) 🔜 🔐 Uvicorn 🎏 ➡: `http://127.0.0.1:8000/api/v1/app`. |
|
||||
|
|
||||
## 🔬 🌐 ⏮️ Traefik |
|
||||
|
|
||||
👆 💪 💪 🏃 🥼 🌐 ⏮️ 🎞 ➡ 🔡 ⚙️ <a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a>. |
|
||||
|
|
||||
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">⏬ Traefik</a>, ⚫️ 👁 💱, 👆 💪 ⚗ 🗜 📁 & 🏃 ⚫️ 🔗 ⚪️➡️ 📶. |
|
||||
|
|
||||
⤴️ ✍ 📁 `traefik.toml` ⏮️: |
|
||||
|
|
||||
```TOML hl_lines="3" |
|
||||
[entryPoints] |
|
||||
[entryPoints.http] |
|
||||
address = ":9999" |
|
||||
|
|
||||
[providers] |
|
||||
[providers.file] |
|
||||
filename = "routes.toml" |
|
||||
``` |
|
||||
|
|
||||
👉 💬 Traefik 👂 🔛 ⛴ 9️⃣9️⃣9️⃣9️⃣ & ⚙️ ➕1️⃣ 📁 `routes.toml`. |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
👥 ⚙️ ⛴ 9️⃣9️⃣9️⃣9️⃣ ↩️ 🐩 🇺🇸🔍 ⛴ 8️⃣0️⃣ 👈 👆 🚫 ✔️ 🏃 ⚫️ ⏮️ 📡 (`sudo`) 😌. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
🔜 ✍ 👈 🎏 📁 `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" |
|
||||
``` |
|
||||
|
|
||||
👉 📁 🔗 Traefik ⚙️ ➡ 🔡 `/api/v1`. |
|
||||
|
|
||||
& ⤴️ ⚫️ 🔜 ❎ 🚮 📨 👆 Uvicorn 🏃♂ 🔛 `http://127.0.0.1:8000`. |
|
||||
|
|
||||
🔜 ▶️ Traefik: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ ./traefik --configFile=traefik.toml |
|
||||
|
|
||||
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
& 🔜 ▶️ 👆 📱 ⏮️ Uvicorn, ⚙️ `--root-path` 🎛: |
|
||||
|
|
||||
<div class="termy"> |
|
||||
|
|
||||
```console |
|
||||
$ uvicorn main:app --root-path /api/v1 |
|
||||
|
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) |
|
||||
``` |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
### ✅ 📨 |
|
||||
|
|
||||
🔜, 🚥 👆 🚶 📛 ⏮️ ⛴ Uvicorn: <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a>, 👆 🔜 👀 😐 📨: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"message": "Hello World", |
|
||||
"root_path": "/api/v1" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
👀 👈 ✋️ 👆 🔐 ⚫️ `http://127.0.0.1:8000/app` ⚫️ 🎦 `root_path` `/api/v1`, ✊ ⚪️➡️ 🎛 `--root-path`. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
& 🔜 📂 📛 ⏮️ ⛴ Traefik, ✅ ➡ 🔡: <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a>. |
|
||||
|
|
||||
👥 🤚 🎏 📨: |
|
||||
|
|
||||
```JSON |
|
||||
{ |
|
||||
"message": "Hello World", |
|
||||
"root_path": "/api/v1" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
✋️ 👉 🕰 📛 ⏮️ 🔡 ➡ 🚚 🗳: `/api/v1`. |
|
||||
|
|
||||
↗️, 💭 📥 👈 👱 🔜 🔐 📱 🔘 🗳, ⏬ ⏮️ ➡ 🔡 `/app/v1` "☑" 1️⃣. |
|
||||
|
|
||||
& ⏬ 🍵 ➡ 🔡 (`http://127.0.0.1:8000/app`), 🚚 Uvicorn 🔗, 🔜 🎯 _🗳_ (Traefik) 🔐 ⚫️. |
|
||||
|
|
||||
👈 🎦 ❔ 🗳 (Traefik) ⚙️ ➡ 🔡 & ❔ 💽 (Uvicorn) ⚙️ `root_path` ⚪️➡️ 🎛 `--root-path`. |
|
||||
|
|
||||
### ✅ 🩺 🎚 |
|
||||
|
|
||||
✋️ 📥 🎊 🍕. 👶 |
|
||||
|
|
||||
"🛂" 🌌 🔐 📱 🔜 🔘 🗳 ⏮️ ➡ 🔡 👈 👥 🔬. , 👥 🔜 ⌛, 🚥 👆 🔄 🩺 🎚 🍦 Uvicorn 🔗, 🍵 ➡ 🔡 📛, ⚫️ 🏆 🚫 👷, ↩️ ⚫️ ⌛ 🔐 🔘 🗳. |
|
||||
|
|
||||
👆 💪 ✅ ⚫️ <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>: |
|
||||
|
|
||||
<img src="/img/tutorial/behind-a-proxy/image01.png"> |
|
||||
|
|
||||
✋️ 🚥 👥 🔐 🩺 🎚 "🛂" 📛 ⚙️ 🗳 ⏮️ ⛴ `9999`, `/api/v1/docs`, ⚫️ 👷 ☑ ❗ 👶 |
|
||||
|
|
||||
👆 💪 ✅ ⚫️ <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>: |
|
||||
|
|
||||
<img src="/img/tutorial/behind-a-proxy/image02.png"> |
|
||||
|
|
||||
▶️️ 👥 💚 ⚫️. 👶 👶 |
|
||||
|
|
||||
👉 ↩️ FastAPI ⚙️ 👉 `root_path` ✍ 🔢 `server` 🗄 ⏮️ 📛 🚚 `root_path`. |
|
||||
|
|
||||
## 🌖 💽 |
|
||||
|
|
||||
/// warning |
|
||||
|
|
||||
👉 🌅 🏧 ⚙️ 💼. 💭 🆓 🚶 ⚫️. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
🔢, **FastAPI** 🔜 ✍ `server` 🗄 🔗 ⏮️ 📛 `root_path`. |
|
||||
|
|
||||
✋️ 👆 💪 🚚 🎏 🎛 `servers`, 🖼 🚥 👆 💚 *🎏* 🩺 🎚 🔗 ⏮️ 🏗 & 🏭 🌐. |
|
||||
|
|
||||
🚥 👆 🚶♀️ 🛃 📇 `servers` & 📤 `root_path` (↩️ 👆 🛠️ 👨❤👨 ⛅ 🗳), **FastAPI** 🔜 📩 "💽" ⏮️ 👉 `root_path` ▶️ 📇. |
|
||||
|
|
||||
🖼: |
|
||||
|
|
||||
{* ../../docs_src/behind_a_proxy/tutorial003.py hl[4:7] *} |
|
||||
|
|
||||
🔜 🏗 🗄 🔗 💖: |
|
||||
|
|
||||
```JSON hl_lines="5-7" |
|
||||
{ |
|
||||
"openapi": "3.0.2", |
|
||||
// More stuff here |
|
||||
"servers": [ |
|
||||
{ |
|
||||
"url": "/api/v1" |
|
||||
}, |
|
||||
{ |
|
||||
"url": "https://stag.example.com", |
|
||||
"description": "Staging environment" |
|
||||
}, |
|
||||
{ |
|
||||
"url": "https://prod.example.com", |
|
||||
"description": "Production environment" |
|
||||
} |
|
||||
], |
|
||||
"paths": { |
|
||||
// More stuff here |
|
||||
} |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
👀 🚘-🏗 💽 ⏮️ `url` 💲 `/api/v1`, ✊ ⚪️➡️ `root_path`. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
🩺 🎚 <a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a> ⚫️ 🔜 👀 💖: |
|
||||
|
|
||||
<img src="/img/tutorial/behind-a-proxy/image03.png"> |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
🩺 🎚 🔜 🔗 ⏮️ 💽 👈 👆 🖊. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
### ❎ 🏧 💽 ⚪️➡️ `root_path` |
|
||||
|
|
||||
🚥 👆 🚫 💚 **FastAPI** 🔌 🏧 💽 ⚙️ `root_path`, 👆 💪 ⚙️ 🔢 `root_path_in_servers=False`: |
|
||||
|
|
||||
{* ../../docs_src/behind_a_proxy/tutorial004.py hl[9] *} |
|
||||
|
|
||||
& ⤴️ ⚫️ 🏆 🚫 🔌 ⚫️ 🗄 🔗. |
|
||||
|
|
||||
## 🗜 🎧-🈸 |
|
||||
|
|
||||
🚥 👆 💪 🗻 🎧-🈸 (🔬 [🎧 🈸 - 🗻](sub-applications.md){.internal-link target=_blank}) ⏪ ⚙️ 🗳 ⏮️ `root_path`, 👆 💪 ⚫️ 🛎, 👆 🔜 ⌛. |
|
||||
|
|
||||
FastAPI 🔜 🔘 ⚙️ `root_path` 🎆, ⚫️ 🔜 👷. 👶 |
|
||||
@ -1,303 +0,0 @@ |
|||||
# 🛃 📨 - 🕸, 🎏, 📁, 🎏 |
|
||||
|
|
||||
🔢, **FastAPI** 🔜 📨 📨 ⚙️ `JSONResponse`. |
|
||||
|
|
||||
👆 💪 🔐 ⚫️ 🛬 `Response` 🔗 👀 [📨 📨 🔗](response-directly.md){.internal-link target=_blank}. |
|
||||
|
|
||||
✋️ 🚥 👆 📨 `Response` 🔗, 📊 🏆 🚫 🔁 🗜, & 🧾 🏆 🚫 🔁 🏗 (🖼, 🔌 🎯 "📻 🆎", 🇺🇸🔍 🎚 `Content-Type` 🍕 🏗 🗄). |
|
||||
|
|
||||
✋️ 👆 💪 📣 `Response` 👈 👆 💚 ⚙️, *➡ 🛠️ 👨🎨*. |
|
||||
|
|
||||
🎚 👈 👆 📨 ⚪️➡️ 👆 *➡ 🛠️ 🔢* 🔜 🚮 🔘 👈 `Response`. |
|
||||
|
|
||||
& 🚥 👈 `Response` ✔️ 🎻 📻 🆎 (`application/json`), 💖 💼 ⏮️ `JSONResponse` & `UJSONResponse`, 💽 👆 📨 🔜 🔁 🗜 (& ⛽) ⏮️ 🙆 Pydantic `response_model` 👈 👆 📣 *➡ 🛠️ 👨🎨*. |
|
||||
|
|
||||
/// note |
|
||||
|
|
||||
🚥 👆 ⚙️ 📨 🎓 ⏮️ 🙅♂ 📻 🆎, FastAPI 🔜 ⌛ 👆 📨 ✔️ 🙅♂ 🎚, ⚫️ 🔜 🚫 📄 📨 📁 🚮 🏗 🗄 🩺. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
## ⚙️ `ORJSONResponse` |
|
||||
|
|
||||
🖼, 🚥 👆 ✊ 🎭, 👆 💪 ❎ & ⚙️ <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a> & ⚒ 📨 `ORJSONResponse`. |
|
||||
|
|
||||
🗄 `Response` 🎓 (🎧-🎓) 👆 💚 ⚙️ & 📣 ⚫️ *➡ 🛠️ 👨🎨*. |
|
||||
|
|
||||
⭕ 📨, 📨 `Response` 🔗 🌅 ⏩ 🌘 🛬 📖. |
|
||||
|
|
||||
👉 ↩️ 🔢, FastAPI 🔜 ✔ 🔠 🏬 🔘 & ⚒ 💭 ⚫️ 🎻 ⏮️ 🎻, ⚙️ 🎏 [🎻 🔗 🔢](../tutorial/encoder.md){.internal-link target=_blank} 🔬 🔰. 👉 ⚫️❔ ✔ 👆 📨 **❌ 🎚**, 🖼 💽 🏷. |
|
||||
|
|
||||
✋️ 🚥 👆 🎯 👈 🎚 👈 👆 🛬 **🎻 ⏮️ 🎻**, 👆 💪 🚶♀️ ⚫️ 🔗 📨 🎓 & ❎ ➕ 🌥 👈 FastAPI 🔜 ✔️ 🚶♀️ 👆 📨 🎚 🔘 `jsonable_encoder` ⏭ 🚶♀️ ⚫️ 📨 🎓. |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *} |
|
||||
|
|
||||
/// info |
|
||||
|
|
||||
🔢 `response_class` 🔜 ⚙️ 🔬 "📻 🆎" 📨. |
|
||||
|
|
||||
👉 💼, 🇺🇸🔍 🎚 `Content-Type` 🔜 ⚒ `application/json`. |
|
||||
|
|
||||
& ⚫️ 🔜 📄 ✅ 🗄. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
`ORJSONResponse` ⏳ 🕴 💪 FastAPI, 🚫 💃. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
## 🕸 📨 |
|
||||
|
|
||||
📨 📨 ⏮️ 🕸 🔗 ⚪️➡️ **FastAPI**, ⚙️ `HTMLResponse`. |
|
||||
|
|
||||
* 🗄 `HTMLResponse`. |
|
||||
* 🚶♀️ `HTMLResponse` 🔢 `response_class` 👆 *➡ 🛠️ 👨🎨*. |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *} |
|
||||
|
|
||||
/// info |
|
||||
|
|
||||
🔢 `response_class` 🔜 ⚙️ 🔬 "📻 🆎" 📨. |
|
||||
|
|
||||
👉 💼, 🇺🇸🔍 🎚 `Content-Type` 🔜 ⚒ `text/html`. |
|
||||
|
|
||||
& ⚫️ 🔜 📄 ✅ 🗄. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
### 📨 `Response` |
|
||||
|
|
||||
👀 [📨 📨 🔗](response-directly.md){.internal-link target=_blank}, 👆 💪 🔐 📨 🔗 👆 *➡ 🛠️*, 🛬 ⚫️. |
|
||||
|
|
||||
🎏 🖼 ⚪️➡️ 🔛, 🛬 `HTMLResponse`, 💪 👀 💖: |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *} |
|
||||
|
|
||||
/// warning |
|
||||
|
|
||||
`Response` 📨 🔗 👆 *➡ 🛠️ 🔢* 🏆 🚫 📄 🗄 (🖼, `Content-Type` 🏆 🚫 📄) & 🏆 🚫 ⭐ 🏧 🎓 🩺. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
/// info |
|
||||
|
|
||||
↗️, ☑ `Content-Type` 🎚, 👔 📟, ♒️, 🔜 👟 ⚪️➡️ `Response` 🎚 👆 📨. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
### 📄 🗄 & 🔐 `Response` |
|
||||
|
|
||||
🚥 👆 💚 🔐 📨 ⚪️➡️ 🔘 🔢 ✋️ 🎏 🕰 📄 "📻 🆎" 🗄, 👆 💪 ⚙️ `response_class` 🔢 & 📨 `Response` 🎚. |
|
||||
|
|
||||
`response_class` 🔜 ⤴️ ⚙️ 🕴 📄 🗄 *➡ 🛠️*, ✋️ 👆 `Response` 🔜 ⚙️. |
|
||||
|
|
||||
#### 📨 `HTMLResponse` 🔗 |
|
||||
|
|
||||
🖼, ⚫️ 💪 🕳 💖: |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *} |
|
||||
|
|
||||
👉 🖼, 🔢 `generate_html_response()` ⏪ 🏗 & 📨 `Response` ↩️ 🛬 🕸 `str`. |
|
||||
|
|
||||
🛬 🏁 🤙 `generate_html_response()`, 👆 ⏪ 🛬 `Response` 👈 🔜 🔐 🔢 **FastAPI** 🎭. |
|
||||
|
|
||||
✋️ 👆 🚶♀️ `HTMLResponse` `response_class` 💁♂️, **FastAPI** 🔜 💭 ❔ 📄 ⚫️ 🗄 & 🎓 🩺 🕸 ⏮️ `text/html`: |
|
||||
|
|
||||
<img src="/img/tutorial/custom-response/image01.png"> |
|
||||
|
|
||||
## 💪 📨 |
|
||||
|
|
||||
📥 💪 📨. |
|
||||
|
|
||||
✔️ 🤯 👈 👆 💪 ⚙️ `Response` 📨 🕳 🙆, ⚖️ ✍ 🛃 🎧-🎓. |
|
||||
|
|
||||
/// note | 📡 ℹ |
|
||||
|
|
||||
👆 💪 ⚙️ `from starlette.responses import HTMLResponse`. |
|
||||
|
|
||||
**FastAPI** 🚚 🎏 `starlette.responses` `fastapi.responses` 🏪 👆, 👩💻. ✋️ 🌅 💪 📨 👟 🔗 ⚪️➡️ 💃. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
### `Response` |
|
||||
|
|
||||
👑 `Response` 🎓, 🌐 🎏 📨 😖 ⚪️➡️ ⚫️. |
|
||||
|
|
||||
👆 💪 📨 ⚫️ 🔗. |
|
||||
|
|
||||
⚫️ 🚫 📄 🔢: |
|
||||
|
|
||||
* `content` - `str` ⚖️ `bytes`. |
|
||||
* `status_code` - `int` 🇺🇸🔍 👔 📟. |
|
||||
* `headers` - `dict` 🎻. |
|
||||
* `media_type` - `str` 🤝 📻 🆎. 🤶 Ⓜ. `"text/html"`. |
|
||||
|
|
||||
FastAPI (🤙 💃) 🔜 🔁 🔌 🎚-📐 🎚. ⚫️ 🔜 🔌 🎚-🆎 🎚, ⚓️ 🔛 = & 🔁 = ✍ 🆎. |
|
||||
|
|
||||
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} |
|
||||
|
|
||||
### `HTMLResponse` |
|
||||
|
|
||||
✊ ✍ ⚖️ 🔢 & 📨 🕸 📨, 👆 ✍ 🔛. |
|
||||
|
|
||||
### `PlainTextResponse` |
|
||||
|
|
||||
✊ ✍ ⚖️ 🔢 & 📨 ✅ ✍ 📨. |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *} |
|
||||
|
|
||||
### `JSONResponse` |
|
||||
|
|
||||
✊ 💽 & 📨 `application/json` 🗜 📨. |
|
||||
|
|
||||
👉 🔢 📨 ⚙️ **FastAPI**, 👆 ✍ 🔛. |
|
||||
|
|
||||
### `ORJSONResponse` |
|
||||
|
|
||||
⏩ 🎛 🎻 📨 ⚙️ <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, 👆 ✍ 🔛. |
|
||||
|
|
||||
### `UJSONResponse` |
|
||||
|
|
||||
🎛 🎻 📨 ⚙️ <a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>. |
|
||||
|
|
||||
/// warning |
|
||||
|
|
||||
`ujson` 🌘 💛 🌘 🐍 🏗-🛠️ ❔ ⚫️ 🍵 📐-💼. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *} |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
⚫️ 💪 👈 `ORJSONResponse` 💪 ⏩ 🎛. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
### `RedirectResponse` |
|
||||
|
|
||||
📨 🇺🇸🔍 ❎. ⚙️ 3️⃣0️⃣7️⃣ 👔 📟 (🍕 ❎) 🔢. |
|
||||
|
|
||||
👆 💪 📨 `RedirectResponse` 🔗: |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *} |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
⚖️ 👆 💪 ⚙️ ⚫️ `response_class` 🔢: |
|
||||
|
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *} |
|
||||
|
|
||||
🚥 👆 👈, ⤴️ 👆 💪 📨 📛 🔗 ⚪️➡️ 👆 *➡ 🛠️* 🔢. |
|
||||
|
|
||||
👉 💼, `status_code` ⚙️ 🔜 🔢 1️⃣ `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()`), 👆 💪 ✍ 🚂 🔢 🔁 🤭 👈 📁-💖 🎚. |
|
||||
|
|
||||
👈 🌌, 👆 🚫 ✔️ ✍ ⚫️ 🌐 🥇 💾, & 👆 💪 🚶♀️ 👈 🚂 🔢 `StreamingResponse`, & 📨 ⚫️. |
|
||||
|
|
||||
👉 🔌 📚 🗃 🔗 ⏮️ ☁ 💾, 📹 🏭, & 🎏. |
|
||||
|
|
||||
```{ .python .annotate hl_lines="2 10-12 14" } |
|
||||
{!../../docs_src/custom_response/tutorial008.py!} |
|
||||
``` |
|
||||
|
|
||||
1️⃣. 👉 🚂 🔢. ⚫️ "🚂 🔢" ↩️ ⚫️ 🔌 `yield` 📄 🔘. |
|
||||
2️⃣. ⚙️ `with` 🍫, 👥 ⚒ 💭 👈 📁-💖 🎚 📪 ⏮️ 🚂 🔢 🔨. , ⏮️ ⚫️ 🏁 📨 📨. |
|
||||
3️⃣. 👉 `yield from` 💬 🔢 🔁 🤭 👈 👜 🌟 `file_like`. & ⤴️, 🔠 🍕 🔁, 🌾 👈 🍕 👟 ⚪️➡️ 👉 🚂 🔢. |
|
||||
|
|
||||
, ⚫️ 🚂 🔢 👈 📨 "🏭" 👷 🕳 🙆 🔘. |
|
||||
|
|
||||
🔨 ⚫️ 👉 🌌, 👥 💪 🚮 ⚫️ `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` & ⚙️ ⚫️. |
|
||||
|
|
||||
🖼, ➡️ 💬 👈 👆 💚 ⚙️ <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>, ✋️ ⏮️ 🛃 ⚒ 🚫 ⚙️ 🔌 `ORJSONResponse` 🎓. |
|
||||
|
|
||||
➡️ 💬 👆 💚 ⚫️ 📨 🔂 & 📁 🎻, 👆 💚 ⚙️ Orjson 🎛 `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" |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
↗️, 👆 🔜 🎲 🔎 🌅 👍 🌌 ✊ 📈 👉 🌘 ❕ 🎻. 👶 |
|
||||
|
|
||||
## 🔢 📨 🎓 |
|
||||
|
|
||||
🕐❔ 🏗 **FastAPI** 🎓 👐 ⚖️ `APIRouter` 👆 💪 ✔ ❔ 📨 🎓 ⚙️ 🔢. |
|
||||
|
|
||||
🔢 👈 🔬 👉 `default_response_class`. |
|
||||
|
|
||||
🖼 🔛, **FastAPI** 🔜 ⚙️ `ORJSONResponse` 🔢, 🌐 *➡ 🛠️*, ↩️ `JSONResponse`. |
|
||||
|
|
||||
{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *} |
|
||||
|
|
||||
/// tip |
|
||||
|
|
||||
👆 💪 🔐 `response_class` *➡ 🛠️* ⏭. |
|
||||
|
|
||||
/// |
|
||||
|
|
||||
## 🌖 🧾 |
|
||||
|
|
||||
👆 💪 📣 📻 🆎 & 📚 🎏 ℹ 🗄 ⚙️ `responses`: [🌖 📨 🗄](additional-responses.md){.internal-link target=_blank}. |
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue