Compare commits
80 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5826c4f31f | ||
|
|
91510db620 | ||
|
|
bcd5a424cd | ||
|
|
678bed2fc9 | ||
|
|
a4aa79e0b4 | ||
|
|
e7756ae7dc | ||
|
|
dc2fdd56af | ||
|
|
36c2667768 | ||
|
|
d8185efb6e | ||
|
|
fc51d7e3c7 | ||
|
|
b98c65cb36 | ||
|
|
ba99214417 | ||
|
|
6f5aa81c07 | ||
|
|
73dcc40f09 | ||
|
|
33493ce694 | ||
|
|
01e570c56d | ||
|
|
ca03379b65 | ||
|
|
8cf2fa0fe4 | ||
|
|
99a2ec981b | ||
|
|
6fb951bae2 | ||
|
|
13cef7a21a | ||
|
|
e9ce31e96b | ||
|
|
1560879a84 | ||
|
|
ac93277d3b | ||
|
|
71d51a9953 | ||
|
|
81bab77617 | ||
|
|
781984b226 | ||
|
|
480620372a | ||
|
|
b04d07c933 | ||
|
|
46335068d2 | ||
|
|
4f89886b00 | ||
|
|
1c25e2d8dc | ||
|
|
7e5afe2cb9 | ||
|
|
6c53ddd084 | ||
|
|
0f1ddf5f69 | ||
|
|
758a8f29e1 | ||
|
|
e4b21c6eab | ||
|
|
759378d67f | ||
|
|
e7204ac7bf | ||
|
|
7702c5af36 | ||
|
|
0066578bbe | ||
|
|
6b903ff1fb | ||
|
|
cbc8f18664 | ||
|
|
fbe6ba6df1 | ||
|
|
b84f9f6ecb | ||
|
|
0b83491843 | ||
|
|
38db1fe074 | ||
|
|
378e590757 | ||
|
|
290191421b | ||
|
|
e0c5beb5c8 | ||
|
|
072c701b0e | ||
|
|
e45cbb7e5e | ||
|
|
2754d4e0fe | ||
|
|
f7e338dcd8 | ||
|
|
223970e03c | ||
|
|
2e14c69c31 | ||
|
|
4ef7a40eae | ||
|
|
e0a5edaaa3 | ||
|
|
f9b53ae778 | ||
|
|
e8bd645fa9 | ||
|
|
808e3bb9d5 | ||
|
|
9bfbacfe98 | ||
|
|
ab65486e75 | ||
|
|
9b3e166b43 | ||
|
|
07a9b240e9 | ||
|
|
89e03bad16 | ||
|
|
f41eb5e005 | ||
|
|
eb017270fc | ||
|
|
ae84ff6e44 | ||
|
|
f785a6ce90 | ||
|
|
6dac39dbca | ||
|
|
4bd1430677 | ||
|
|
cda5e770ab | ||
|
|
57a030175e | ||
|
|
968afca058 | ||
|
|
6eb30959bc | ||
|
|
dcbe7f7ac0 | ||
|
|
dc7838eec3 | ||
|
|
7670a132b3 | ||
|
|
c13aa9ed5f |
8
.github/workflows/build-docs.yml
vendored
@@ -28,6 +28,8 @@ jobs:
|
||||
- docs/**
|
||||
- docs_src/**
|
||||
- requirements-docs.txt
|
||||
- .github/workflows/build-docs.yml
|
||||
- .github/workflows/deploy-docs.yml
|
||||
langs:
|
||||
needs:
|
||||
- changes
|
||||
@@ -50,11 +52,13 @@ jobs:
|
||||
run: pip install -r requirements-docs.txt
|
||||
# Install MkDocs Material Insiders here just to put it in the cache for the rest of the steps
|
||||
- name: Install Material for MkDocs Insiders
|
||||
if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
|
||||
if: ( github.event_name != 'pull_request' || github.secret_source == 'Actions' ) && steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/griffe-typing-deprecated.git
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/mkdocstrings-python.git
|
||||
- name: Verify README
|
||||
run: python ./scripts/docs.py verify-readme
|
||||
- name: Export Language Codes
|
||||
id: show-langs
|
||||
run: |
|
||||
@@ -88,7 +92,7 @@ jobs:
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements-docs.txt
|
||||
- name: Install Material for MkDocs Insiders
|
||||
if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true'
|
||||
if: ( github.event_name != 'pull_request' || github.secret_source != 'Actions' ) && steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git
|
||||
pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/griffe-typing-deprecated.git
|
||||
|
||||
7
.github/workflows/latest-changes.yml
vendored
@@ -34,9 +34,12 @@ jobs:
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}
|
||||
with:
|
||||
limit-access-to-actor: true
|
||||
- uses: docker://tiangolo/latest-changes:0.0.3
|
||||
- uses: docker://tiangolo/latest-changes:0.2.0
|
||||
# - uses: tiangolo/latest-changes@main
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
latest_changes_file: docs/en/docs/release-notes.md
|
||||
latest_changes_header: '## Latest Changes\n\n'
|
||||
latest_changes_header: '## Latest Changes'
|
||||
end_regex: '^## '
|
||||
debug_logs: true
|
||||
label_header_prefix: '### '
|
||||
|
||||
4
.github/workflows/test.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v06
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v07
|
||||
- name: Install Dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements-tests.txt
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v06
|
||||
key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v07
|
||||
- name: Install Dependencies
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: pip install -r requirements-tests.txt
|
||||
|
||||
@@ -13,23 +13,13 @@ repos:
|
||||
- --unsafe
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.7.0
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args:
|
||||
- --py3-plus
|
||||
- --keep-runtime-typing
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.275
|
||||
rev: v0.1.2
|
||||
hooks:
|
||||
- id: ruff
|
||||
args:
|
||||
- --fix
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
- id: ruff-format
|
||||
ci:
|
||||
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
|
||||
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
|
||||
|
||||
24
CITATION.cff
Normal file
@@ -0,0 +1,24 @@
|
||||
# This CITATION.cff file was generated with cffinit.
|
||||
# Visit https://bit.ly/cffinit to generate yours today!
|
||||
|
||||
cff-version: 1.2.0
|
||||
title: FastAPI
|
||||
message: >-
|
||||
If you use this software, please cite it using the
|
||||
metadata from this file.
|
||||
type: software
|
||||
authors:
|
||||
- given-names: Sebastián
|
||||
family-names: Ramírez
|
||||
email: tiangolo@gmail.com
|
||||
identifiers:
|
||||
repository-code: 'https://github.com/tiangolo/fastapi'
|
||||
url: 'https://fastapi.tiangolo.com'
|
||||
abstract: >-
|
||||
FastAPI framework, high performance, easy to learn, fast to code,
|
||||
ready for production
|
||||
keywords:
|
||||
- fastapi
|
||||
- pydantic
|
||||
- starlette
|
||||
license: MIT
|
||||
@@ -48,9 +48,11 @@ The key features are:
|
||||
|
||||
<a href="https://cryptapi.io/" target="_blank" title="CryptAPI: Your easy to use, secure and privacy oriented payment gateway."><img src="https://fastapi.tiangolo.com/img/sponsors/cryptapi.svg"></a>
|
||||
<a href="https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023" target="_blank" title="Build, run and scale your apps on a modern, reliable, and secure PaaS."><img src="https://fastapi.tiangolo.com/img/sponsors/platform-sh.png"></a>
|
||||
<a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Fern | SDKs and API docs"><img src="https://fastapi.tiangolo.com/img/sponsors/fern.svg"></a>
|
||||
<a href="https://www.porter.run" target="_blank" title="Deploy FastAPI on AWS with a few clicks"><img src="https://fastapi.tiangolo.com/img/sponsors/porter.png"></a>
|
||||
<a href="https://bump.sh/fastapi?utm_source=fastapi&utm_medium=referral&utm_campaign=sponsor" target="_blank" title="Automate FastAPI documentation generation with Bump.sh"><img src="https://fastapi.tiangolo.com/img/sponsors/bump-sh.svg"></a>
|
||||
<a href="https://reflex.dev" target="_blank" title="Reflex"><img src="https://fastapi.tiangolo.com/img/sponsors/reflex.png"></a>
|
||||
<a href="https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge" target="_blank" title="Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files"><img src="https://fastapi.tiangolo.com/img/sponsors/scalar.svg"></a>
|
||||
<a href="https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge" target="_blank" title="Auth, user management and more for your B2B product"><img src="https://fastapi.tiangolo.com/img/sponsors/propelauth.png"></a>
|
||||
<a href="https://www.deta.sh/?ref=fastapi" target="_blank" title="The launchpad for all your (team's) ideas"><img src="https://fastapi.tiangolo.com/img/sponsors/deta.svg"></a>
|
||||
<a href="https://training.talkpython.fm/fastapi-courses" target="_blank" title="FastAPI video courses on demand from people you trust"><img src="https://fastapi.tiangolo.com/img/sponsors/talkpython.png"></a>
|
||||
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>
|
||||
@@ -59,6 +61,7 @@ The key features are:
|
||||
<a href="https://databento.com/" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
|
||||
<a href="https://speakeasyapi.dev?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
|
||||
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>
|
||||
<a href="https://www.codacy.com/?utm_source=github&utm_medium=sponsors&utm_id=pioneers" target="_blank" title="Take code reviews from hours to minutes"><img src="https://fastapi.tiangolo.com/img/sponsors/codacy.png"></a>
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" uvicorn main:app
|
||||
```
|
||||
|
||||
!!! tip
|
||||
👥 🔜 🔬 `@lru_cache()` 🍖.
|
||||
👥 🔜 🔬 `@lru_cache` 🍖.
|
||||
|
||||
🔜 👆 💪 🤔 `get_settings()` 😐 🔢.
|
||||
|
||||
@@ -254,7 +254,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" uvicorn main:app
|
||||
|
||||
✋️ 🇨🇻 📁 🚫 🤙 ✔️ ✔️ 👈 ☑ 📁.
|
||||
|
||||
Pydantic ✔️ 🐕🦺 👂 ⚪️➡️ 👉 🆎 📁 ⚙️ 🔢 🗃. 👆 💪 ✍ 🌖 <a href="https://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic ⚒: 🇨🇻 (.🇨🇻) 🐕🦺</a>.
|
||||
Pydantic ✔️ 🐕🦺 👂 ⚪️➡️ 👉 🆎 📁 ⚙️ 🔢 🗃. 👆 💪 ✍ 🌖 <a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic ⚒: 🇨🇻 (.🇨🇻) 🐕🦺</a>.
|
||||
|
||||
!!! tip
|
||||
👉 👷, 👆 💪 `pip install python-dotenv`.
|
||||
@@ -302,7 +302,7 @@ def get_settings():
|
||||
|
||||
👥 🔜 ✍ 👈 🎚 🔠 📨, & 👥 🔜 👂 `.env` 📁 🔠 📨. 👶 👶
|
||||
|
||||
✋️ 👥 ⚙️ `@lru_cache()` 👨🎨 🔛 🔝, `Settings` 🎚 🔜 ✍ 🕴 🕐, 🥇 🕰 ⚫️ 🤙. 👶 👶
|
||||
✋️ 👥 ⚙️ `@lru_cache` 👨🎨 🔛 🔝, `Settings` 🎚 🔜 ✍ 🕴 🕐, 🥇 🕰 ⚫️ 🤙. 👶 👶
|
||||
|
||||
```Python hl_lines="1 10"
|
||||
{!../../../docs_src/settings/app03/main.py!}
|
||||
@@ -312,14 +312,14 @@ def get_settings():
|
||||
|
||||
#### `lru_cache` 📡 ℹ
|
||||
|
||||
`@lru_cache()` 🔀 🔢 ⚫️ 🎀 📨 🎏 💲 👈 📨 🥇 🕰, ↩️ 💻 ⚫️ 🔄, 🛠️ 📟 🔢 🔠 🕰.
|
||||
`@lru_cache` 🔀 🔢 ⚫️ 🎀 📨 🎏 💲 👈 📨 🥇 🕰, ↩️ 💻 ⚫️ 🔄, 🛠️ 📟 🔢 🔠 🕰.
|
||||
|
||||
, 🔢 🔛 ⚫️ 🔜 🛠️ 🕐 🔠 🌀 ❌. & ⤴️ 💲 📨 🔠 👈 🌀 ❌ 🔜 ⚙️ 🔄 & 🔄 🕐❔ 🔢 🤙 ⏮️ ⚫️❔ 🎏 🌀 ❌.
|
||||
|
||||
🖼, 🚥 👆 ✔️ 🔢:
|
||||
|
||||
```Python
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def say_hi(name: str, salutation: str = "Ms."):
|
||||
return f"Hello {salutation} {name}"
|
||||
```
|
||||
@@ -371,7 +371,7 @@ participant execute as Execute function
|
||||
|
||||
👈 🌌, ⚫️ 🎭 🌖 🚥 ⚫️ 🌐 🔢. ✋️ ⚫️ ⚙️ 🔗 🔢, ⤴️ 👥 💪 🔐 ⚫️ 💪 🔬.
|
||||
|
||||
`@lru_cache()` 🍕 `functools` ❔ 🍕 🐍 🐩 🗃, 👆 💪 ✍ 🌅 🔃 ⚫️ <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">🐍 🩺 `@lru_cache()`</a>.
|
||||
`@lru_cache` 🍕 `functools` ❔ 🍕 🐍 🐩 🗃, 👆 💪 ✍ 🌅 🔃 ⚫️ <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">🐍 🩺 `@lru_cache`</a>.
|
||||
|
||||
## 🌃
|
||||
|
||||
@@ -379,4 +379,4 @@ participant execute as Execute function
|
||||
|
||||
* ⚙️ 🔗 👆 💪 📉 🔬.
|
||||
* 👆 💪 ⚙️ `.env` 📁 ⏮️ ⚫️.
|
||||
* ⚙️ `@lru_cache()` ➡️ 👆 ❎ 👂 🇨🇻 📁 🔄 & 🔄 🔠 📨, ⏪ 🤝 👆 🔐 ⚫️ ⏮️ 🔬.
|
||||
* ⚙️ `@lru_cache` ➡️ 👆 ❎ 👂 🇨🇻 📁 🔄 & 🔄 🔠 📨, ⏪ 🤝 👆 🔐 ⚫️ ⏮️ 🔬.
|
||||
|
||||
@@ -409,11 +409,11 @@ async def read_burgers():
|
||||
|
||||
### 🔗
|
||||
|
||||
🎏 ✔ [🔗](/tutorial/dependencies/index.md){.internal-link target=_blank}. 🚥 🔗 🐩 `def` 🔢 ↩️ `async def`, ⚫️ 🏃 🔢 🧵.
|
||||
🎏 ✔ [🔗](./tutorial/dependencies/index.md){.internal-link target=_blank}. 🚥 🔗 🐩 `def` 🔢 ↩️ `async def`, ⚫️ 🏃 🔢 🧵.
|
||||
|
||||
### 🎧-🔗
|
||||
|
||||
👆 💪 ✔️ 💗 🔗 & [🎧-🔗](/tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} 🚫 🔠 🎏 (🔢 🔢 🔑), 👫 💪 ✍ ⏮️ `async def` & ⏮️ 😐 `def`. ⚫️ 🔜 👷, & 🕐 ✍ ⏮️ 😐 `def` 🔜 🤙 🔛 🔢 🧵 (⚪️➡️ 🧵) ↩️ ➖ "⌛".
|
||||
👆 💪 ✔️ 💗 🔗 & [🎧-🔗](./tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} 🚫 🔠 🎏 (🔢 🔢 🔑), 👫 💪 ✍ ⏮️ `async def` & ⏮️ 😐 `def`. ⚫️ 🔜 👷, & 🕐 ✍ ⏮️ 😐 `def` 🔜 🤙 🔛 🔢 🧵 (⚪️➡️ 🧵) ↩️ ➖ "⌛".
|
||||
|
||||
### 🎏 🚙 🔢
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
* ⏮️ 🔢 🦲 💖 Certbot 📄 🔕
|
||||
* ✳
|
||||
* ⏮️ 🔢 🦲 💖 Certbot 📄 🔕
|
||||
* Kubernete ⏮️ 🚧 🕹 💖 👌
|
||||
* Kubernetes ⏮️ 🚧 🕹 💖 👌
|
||||
* ⏮️ 🔢 🦲 💖 🛂-👨💼 📄 🔕
|
||||
* 🍵 🔘 ☁ 🐕🦺 🍕 👫 🐕🦺 (✍ 🔛 👶)
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
🖼 🧰 👈 💪 👉 👨🏭:
|
||||
|
||||
* ☁
|
||||
* Kubernete
|
||||
* Kubernetes
|
||||
* ☁ ✍
|
||||
* ☁ 🐝 📳
|
||||
* ✳
|
||||
@@ -165,7 +165,7 @@
|
||||
🖼, 👉 💪 🍵:
|
||||
|
||||
* ☁
|
||||
* Kubernete
|
||||
* Kubernetes
|
||||
* ☁ ✍
|
||||
* ☁ 🐝 📳
|
||||
* ✳
|
||||
@@ -233,15 +233,15 @@
|
||||
* 🐁 🔜 **🛠️ 👨💼** 👂 🔛 **📢** & **⛴**, 🧬 🔜 ✔️ **💗 Uvicorn 👨🏭 🛠️**
|
||||
* **Uvicorn** 🛠️ **Uvicorn 👨🏭**
|
||||
* 1️⃣ Uvicorn **🛠️ 👨💼** 🔜 👂 🔛 **📢** & **⛴**, & ⚫️ 🔜 ▶️ **💗 Uvicorn 👨🏭 🛠️**
|
||||
* **Kubernete** & 🎏 📎 **📦 ⚙️**
|
||||
* **Kubernetes** & 🎏 📎 **📦 ⚙️**
|
||||
* 🕳 **☁** 🧽 🔜 👂 🔛 **📢** & **⛴**. 🧬 🔜 ✔️ **💗 📦**, 🔠 ⏮️ **1️⃣ Uvicorn 🛠️** 🏃♂
|
||||
* **☁ 🐕🦺** 👈 🍵 👉 👆
|
||||
* ☁ 🐕🦺 🔜 🎲 **🍵 🧬 👆**. ⚫️ 🔜 🎲 ➡️ 👆 🔬 **🛠️ 🏃**, ⚖️ **📦 🖼** ⚙️, 🙆 💼, ⚫️ 🔜 🌅 🎲 **👁 Uvicorn 🛠️**, & ☁ 🐕🦺 🔜 🈚 🔁 ⚫️.
|
||||
|
||||
!!! tip
|
||||
🚫 😟 🚥 👫 🏬 🔃 **📦**, ☁, ⚖️ Kubernete 🚫 ⚒ 📚 🔑.
|
||||
🚫 😟 🚥 👫 🏬 🔃 **📦**, ☁, ⚖️ Kubernetes 🚫 ⚒ 📚 🔑.
|
||||
|
||||
👤 🔜 💬 👆 🌅 🔃 📦 🖼, ☁, Kubernete, ♒️. 🔮 📃: [FastAPI 📦 - ☁](./docker.md){.internal-link target=_blank}.
|
||||
👤 🔜 💬 👆 🌅 🔃 📦 🖼, ☁, Kubernetes, ♒️. 🔮 📃: [FastAPI 📦 - ☁](./docker.md){.internal-link target=_blank}.
|
||||
|
||||
## ⏮️ 🔁 ⏭ ▶️
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
|
||||
📥 💪 💭:
|
||||
|
||||
* "🕑 📦" Kubernete 👈 🏃 ⏭ 👆 📱 📦
|
||||
* "🕑 📦" Kubernetes 👈 🏃 ⏭ 👆 📱 📦
|
||||
* 🎉 ✍ 👈 🏃 ⏮️ 🔁 & ⤴️ ▶️ 👆 🈸
|
||||
* 👆 🔜 💪 🌌 ▶️/⏏ *👈* 🎉 ✍, 🔍 ❌, ♒️.
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
, 👆 🔜 🏃 **💗 📦** ⏮️ 🎏 👜, 💖 💽, 🐍 🈸, 🕸 💽 ⏮️ 😥 🕸 🈸, & 🔗 👫 👯♂️ 📨 👫 🔗 🕸.
|
||||
|
||||
🌐 📦 🧾 ⚙️ (💖 ☁ ⚖️ Kubernete) ✔️ 👫 🕸 ⚒ 🛠️ 🔘 👫.
|
||||
🌐 📦 🧾 ⚙️ (💖 ☁ ⚖️ Kubernetes) ✔️ 👫 🕸 ⚒ 🛠️ 🔘 👫.
|
||||
|
||||
## 📦 & 🛠️
|
||||
|
||||
@@ -96,7 +96,7 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
👉 ⚫️❔ 👆 🔜 💚 **🏆 💼**, 🖼:
|
||||
|
||||
* ⚙️ **Kubernete** ⚖️ 🎏 🧰
|
||||
* ⚙️ **Kubernetes** ⚖️ 🎏 🧰
|
||||
* 🕐❔ 🏃♂ 🔛 **🍓 👲**
|
||||
* ⚙️ ☁ 🐕🦺 👈 🔜 🏃 📦 🖼 👆, ♒️.
|
||||
|
||||
@@ -395,7 +395,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
⚫️ 💪 ➕1️⃣ 📦, 🖼 ⏮️ <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, 🚚 **🇺🇸🔍** & **🏧** 🛠️ **📄**.
|
||||
|
||||
!!! tip
|
||||
Traefik ✔️ 🛠️ ⏮️ ☁, Kubernete, & 🎏, ⚫️ 📶 ⏩ ⚒ 🆙 & 🔗 🇺🇸🔍 👆 📦 ⏮️ ⚫️.
|
||||
Traefik ✔️ 🛠️ ⏮️ ☁, Kubernetes, & 🎏, ⚫️ 📶 ⏩ ⚒ 🆙 & 🔗 🇺🇸🔍 👆 📦 ⏮️ ⚫️.
|
||||
|
||||
👐, 🇺🇸🔍 💪 🍵 ☁ 🐕🦺 1️⃣ 👫 🐕🦺 (⏪ 🏃 🈸 📦).
|
||||
|
||||
@@ -403,7 +403,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
📤 🛎 ➕1️⃣ 🧰 🈚 **▶️ & 🏃♂** 👆 📦.
|
||||
|
||||
⚫️ 💪 **☁** 🔗, **☁ ✍**, **Kubernete**, **☁ 🐕🦺**, ♒️.
|
||||
⚫️ 💪 **☁** 🔗, **☁ ✍**, **Kubernetes**, **☁ 🐕🦺**, ♒️.
|
||||
|
||||
🌅 (⚖️ 🌐) 💼, 📤 🙅 🎛 🛠️ 🏃 📦 🔛 🕴 & 🛠️ ⏏ 🔛 ❌. 🖼, ☁, ⚫️ 📋 ⏸ 🎛 `--restart`.
|
||||
|
||||
@@ -413,7 +413,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
🚥 👆 ✔️ <abbr title="A group of machines that are configured to be connected and work together in some way.">🌑</abbr> 🎰 ⏮️ **☁**, ☁ 🐝 📳, 🖖, ⚖️ ➕1️⃣ 🎏 🏗 ⚙️ 🛠️ 📎 📦 🔛 💗 🎰, ⤴️ 👆 🔜 🎲 💚 **🍵 🧬** **🌑 🎚** ↩️ ⚙️ **🛠️ 👨💼** (💖 🐁 ⏮️ 👨🏭) 🔠 📦.
|
||||
|
||||
1️⃣ 📚 📎 📦 🧾 ⚙️ 💖 Kubernete 🛎 ✔️ 🛠️ 🌌 🚚 **🧬 📦** ⏪ 🔗 **📐 ⚖** 📨 📨. 🌐 **🌑 🎚**.
|
||||
1️⃣ 📚 📎 📦 🧾 ⚙️ 💖 Kubernetes 🛎 ✔️ 🛠️ 🌌 🚚 **🧬 📦** ⏪ 🔗 **📐 ⚖** 📨 📨. 🌐 **🌑 🎚**.
|
||||
|
||||
📚 💼, 👆 🔜 🎲 💚 🏗 **☁ 🖼 ⚪️➡️ 🖌** [🔬 🔛](#dockerfile), ❎ 👆 🔗, & 🏃♂ **👁 Uvicorn 🛠️** ↩️ 🏃♂ 🕳 💖 🐁 ⏮️ Uvicorn 👨🏭.
|
||||
|
||||
@@ -430,7 +430,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
### 1️⃣ 📐 ⚙ - 💗 👨🏭 📦
|
||||
|
||||
🕐❔ 👷 ⏮️ **Kubernete** ⚖️ 🎏 📎 📦 🧾 ⚙️, ⚙️ 👫 🔗 🕸 🛠️ 🔜 ✔ 👁 **📐 ⚙** 👈 👂 🔛 👑 **⛴** 📶 📻 (📨) 🎲 **💗 📦** 🏃 👆 📱.
|
||||
🕐❔ 👷 ⏮️ **Kubernetes** ⚖️ 🎏 📎 📦 🧾 ⚙️, ⚙️ 👫 🔗 🕸 🛠️ 🔜 ✔ 👁 **📐 ⚙** 👈 👂 🔛 👑 **⛴** 📶 📻 (📨) 🎲 **💗 📦** 🏃 👆 📱.
|
||||
|
||||
🔠 👫 📦 🏃♂ 👆 📱 🔜 🛎 ✔️ **1️⃣ 🛠️** (✅ Uvicorn 🛠️ 🏃 👆 FastAPI 🈸). 👫 🔜 🌐 **🌓 📦**, 🏃♂ 🎏 👜, ✋️ 🔠 ⏮️ 🚮 👍 🛠️, 💾, ♒️. 👈 🌌 👆 🔜 ✊ 📈 **🛠️** **🎏 🐚** 💽, ⚖️ **🎏 🎰**.
|
||||
|
||||
@@ -489,7 +489,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
🚥 👆 🏃 **👁 🛠️ 📍 📦** 👆 🔜 ✔️ 🌅 ⚖️ 🌘 👍-🔬, ⚖, & 📉 💸 💾 🍴 🔠 👈 📦 (🌅 🌘 1️⃣ 🚥 👫 🔁).
|
||||
|
||||
& ⤴️ 👆 💪 ⚒ 👈 🎏 💾 📉 & 📄 👆 📳 👆 📦 🧾 ⚙️ (🖼 **Kubernete**). 👈 🌌 ⚫️ 🔜 💪 **🔁 📦** **💪 🎰** ✊ 🔘 🏧 💸 💾 💪 👫, & 💸 💪 🎰 🌑.
|
||||
& ⤴️ 👆 💪 ⚒ 👈 🎏 💾 📉 & 📄 👆 📳 👆 📦 🧾 ⚙️ (🖼 **Kubernetes**). 👈 🌌 ⚫️ 🔜 💪 **🔁 📦** **💪 🎰** ✊ 🔘 🏧 💸 💾 💪 👫, & 💸 💪 🎰 🌑.
|
||||
|
||||
🚥 👆 🈸 **🙅**, 👉 🔜 🎲 **🚫 ⚠**, & 👆 💪 🚫 💪 ✔ 🏋️ 💾 📉. ✋️ 🚥 👆 **⚙️ 📚 💾** (🖼 ⏮️ **🎰 🏫** 🏷), 👆 🔜 ✅ ❔ 🌅 💾 👆 😩 & 🔆 **🔢 📦** 👈 🏃 **🔠 🎰** (& 🎲 🚮 🌖 🎰 👆 🌑).
|
||||
|
||||
@@ -497,14 +497,14 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
|
||||
## ⏮️ 🔁 ⏭ ▶️ & 📦
|
||||
|
||||
🚥 👆 ⚙️ 📦 (✅ ☁, Kubernete), ⤴️ 📤 2️⃣ 👑 🎯 👆 💪 ⚙️.
|
||||
🚥 👆 ⚙️ 📦 (✅ ☁, Kubernetes), ⤴️ 📤 2️⃣ 👑 🎯 👆 💪 ⚙️.
|
||||
|
||||
### 💗 📦
|
||||
|
||||
🚥 👆 ✔️ **💗 📦**, 🎲 🔠 1️⃣ 🏃 **👁 🛠️** (🖼, **Kubernete** 🌑), ⤴️ 👆 🔜 🎲 💚 ✔️ **🎏 📦** 🔨 👷 **⏮️ 📶** 👁 📦, 🏃 👁 🛠️, **⏭** 🏃 🔁 👨🏭 📦.
|
||||
🚥 👆 ✔️ **💗 📦**, 🎲 🔠 1️⃣ 🏃 **👁 🛠️** (🖼, **Kubernetes** 🌑), ⤴️ 👆 🔜 🎲 💚 ✔️ **🎏 📦** 🔨 👷 **⏮️ 📶** 👁 📦, 🏃 👁 🛠️, **⏭** 🏃 🔁 👨🏭 📦.
|
||||
|
||||
!!! info
|
||||
🚥 👆 ⚙️ Kubernete, 👉 🔜 🎲 <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">🕑 📦</a>.
|
||||
🚥 👆 ⚙️ Kubernetes, 👉 🔜 🎲 <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">🕑 📦</a>.
|
||||
|
||||
🚥 👆 ⚙️ 💼 📤 🙅♂ ⚠ 🏃♂ 👈 ⏮️ 📶 **💗 🕰 🔗** (🖼 🚥 👆 🚫 🏃 💽 🛠️, ✋️ ✅ 🚥 💽 🔜), ⤴️ 👆 💪 🚮 👫 🔠 📦 ▶️️ ⏭ ▶️ 👑 🛠️.
|
||||
|
||||
@@ -574,7 +574,7 @@ COPY ./app /app/app
|
||||
|
||||
### 🕐❔ ⚙️
|
||||
|
||||
👆 🔜 🎲 **🚫** ⚙️ 👉 🛂 🧢 🖼 (⚖️ 🙆 🎏 🎏 1️⃣) 🚥 👆 ⚙️ **Kubernete** (⚖️ 🎏) & 👆 ⏪ ⚒ **🧬** 🌑 🎚, ⏮️ 💗 **📦**. 📚 💼, 👆 👍 📆 **🏗 🖼 ⚪️➡️ 🖌** 🔬 🔛: [🏗 ☁ 🖼 FastAPI](#build-a-docker-image-for-fastapi).
|
||||
👆 🔜 🎲 **🚫** ⚙️ 👉 🛂 🧢 🖼 (⚖️ 🙆 🎏 🎏 1️⃣) 🚥 👆 ⚙️ **Kubernetes** (⚖️ 🎏) & 👆 ⏪ ⚒ **🧬** 🌑 🎚, ⏮️ 💗 **📦**. 📚 💼, 👆 👍 📆 **🏗 🖼 ⚪️➡️ 🖌** 🔬 🔛: [🏗 ☁ 🖼 FastAPI](#build-a-docker-image-for-fastapi).
|
||||
|
||||
👉 🖼 🔜 ⚠ ✴️ 🎁 💼 🔬 🔛 [📦 ⏮️ 💗 🛠️ & 🎁 💼](#containers-with-multiple-processes-and-special-cases). 🖼, 🚥 👆 🈸 **🙅 🥃** 👈 ⚒ 🔢 🔢 🛠️ ⚓️ 🔛 💽 👷 👍, 👆 🚫 💚 😥 ⏮️ ❎ 🛠️ 🧬 🌑 🎚, & 👆 🚫 🏃 🌅 🌘 1️⃣ 📦 ⏮️ 👆 📱. ⚖️ 🚥 👆 🛠️ ⏮️ **☁ ✍**, 🏃 🔛 👁 💽, ♒️.
|
||||
|
||||
@@ -585,7 +585,7 @@ COPY ./app /app/app
|
||||
🖼:
|
||||
|
||||
* ⏮️ **☁ ✍** 👁 💽
|
||||
* ⏮️ **Kubernete** 🌑
|
||||
* ⏮️ **Kubernetes** 🌑
|
||||
* ⏮️ ☁ 🐝 📳 🌑
|
||||
* ⏮️ ➕1️⃣ 🧰 💖 🖖
|
||||
* ⏮️ ☁ 🐕🦺 👈 ✊ 👆 📦 🖼 & 🛠️ ⚫️
|
||||
@@ -682,7 +682,7 @@ CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port"
|
||||
|
||||
## 🌃
|
||||
|
||||
⚙️ 📦 ⚙️ (✅ ⏮️ **☁** & **Kubernete**) ⚫️ ▶️️ 📶 🎯 🍵 🌐 **🛠️ 🔧**:
|
||||
⚙️ 📦 ⚙️ (✅ ⏮️ **☁** & **Kubernetes**) ⚫️ ▶️️ 📶 🎯 🍵 🌐 **🛠️ 🔧**:
|
||||
|
||||
* 🇺🇸🔍
|
||||
* 🏃♂ 🔛 🕴
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
📥 👤 🔜 🎦 👆 ❔ ⚙️ <a href="https://gunicorn.org/" class="external-link" target="_blank">**🐁**</a> ⏮️ **Uvicorn 👨🏭 🛠️**.
|
||||
|
||||
!!! info
|
||||
🚥 👆 ⚙️ 📦, 🖼 ⏮️ ☁ ⚖️ Kubernete, 👤 🔜 💬 👆 🌅 🔃 👈 ⏭ 📃: [FastAPI 📦 - ☁](./docker.md){.internal-link target=_blank}.
|
||||
🚥 👆 ⚙️ 📦, 🖼 ⏮️ ☁ ⚖️ Kubernetes, 👤 🔜 💬 👆 🌅 🔃 👈 ⏭ 📃: [FastAPI 📦 - ☁](./docker.md){.internal-link target=_blank}.
|
||||
|
||||
🎯, 🕐❔ 🏃 🔛 **Kubernete** 👆 🔜 🎲 **🚫** 💚 ⚙️ 🐁 & ↩️ 🏃 **👁 Uvicorn 🛠️ 📍 📦**, ✋️ 👤 🔜 💬 👆 🔃 ⚫️ ⏪ 👈 📃.
|
||||
🎯, 🕐❔ 🏃 🔛 **Kubernetes** 👆 🔜 🎲 **🚫** 💚 ⚙️ 🐁 & ↩️ 🏃 **👁 Uvicorn 🛠️ 📍 📦**, ✋️ 👤 🔜 💬 👆 🔃 ⚫️ ⏪ 👈 📃.
|
||||
|
||||
## 🐁 ⏮️ Uvicorn 👨🏭
|
||||
|
||||
@@ -167,7 +167,7 @@ $ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
|
||||
|
||||
👤 🔜 🎦 👆 **🛂 ☁ 🖼** 👈 🔌 **🐁 ⏮️ Uvicorn 👨🏭** & 🔢 📳 👈 💪 ⚠ 🙅 💼.
|
||||
|
||||
📤 👤 🔜 🎦 👆 ❔ **🏗 👆 👍 🖼 ⚪️➡️ 🖌** 🏃 👁 Uvicorn 🛠️ (🍵 🐁). ⚫️ 🙅 🛠️ & 🎲 ⚫️❔ 👆 🔜 💚 🕐❔ ⚙️ 📎 📦 🧾 ⚙️ 💖 **Kubernete**.
|
||||
📤 👤 🔜 🎦 👆 ❔ **🏗 👆 👍 🖼 ⚪️➡️ 🖌** 🏃 👁 Uvicorn 🛠️ (🍵 🐁). ⚫️ 🙅 🛠️ & 🎲 ⚫️❔ 👆 🔜 💚 🕐❔ ⚙️ 📎 📦 🧾 ⚙️ 💖 **Kubernetes**.
|
||||
|
||||
## 🌃
|
||||
|
||||
@@ -175,4 +175,4 @@ $ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
|
||||
|
||||
👆 💪 ⚙️ 👉 🧰 & 💭 🚥 👆 ⚒ 🆙 **👆 👍 🛠️ ⚙️** ⏪ ✊ 💅 🎏 🛠️ 🔧 👆.
|
||||
|
||||
✅ 👅 ⏭ 📃 💡 🔃 **FastAPI** ⏮️ 📦 (✅ ☁ & Kubernete). 👆 🔜 👀 👈 👈 🧰 ✔️ 🙅 🌌 ❎ 🎏 **🛠️ 🔧** 👍. 👶
|
||||
✅ 👅 ⏭ 📃 💡 🔃 **FastAPI** ⏮️ 📦 (✅ ☁ & Kubernetes). 👆 🔜 👀 👈 👈 🧰 ✔️ 🙅 🌌 ❎ 🎏 **🛠️ 🔧** 👍. 👶
|
||||
|
||||
@@ -11,77 +11,21 @@
|
||||
|
||||
## 📄
|
||||
|
||||
### 🇪🇸
|
||||
{% for section_name, section_content in external_links.items() %}
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
## {{ section_name }}
|
||||
|
||||
{% for lang_name, lang_content in section_content.items() %}
|
||||
|
||||
### {{ lang_name }}
|
||||
|
||||
{% for item in lang_content %}
|
||||
|
||||
* <a href="{{ item.link }}" class="external-link" target="_blank">{{ item.title }}</a> by <a href="{{ item.author_link }}" class="external-link" target="_blank">{{ item.author }}</a>.
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### 🇯🇵
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### 🇻🇳
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### 🇷🇺
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### 🇩🇪
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### 🇹🇼
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.taiwanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## 📻
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## 💬
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## 🏗
|
||||
|
||||
|
||||
@@ -231,8 +231,6 @@
|
||||
|
||||
⚙️ 💬 🕴 🎏 🏢 💬.
|
||||
|
||||
📤 ⏮️ <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">🥊 💬</a>, ✋️ ⚫️ 🚫 ✔️ 📻 & 🏧 ⚒, 💬 🌖 ⚠, 😧 🔜 👍 ⚙️.
|
||||
|
||||
### 🚫 ⚙️ 💬 ❔
|
||||
|
||||
✔️ 🤯 👈 💬 ✔ 🌅 "🆓 💬", ⚫️ ⏩ 💭 ❔ 👈 💁♂️ 🏢 & 🌅 ⚠ ❔,, 👆 💪 🚫 📨 ❔.
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
---
|
||||
|
||||
FastAPI 🏛, ⏩ (↕-🎭), 🕸 🛠️ 🏗 🛠️ ⏮️ 🐍 3️⃣.7️⃣ ➕ ⚓️ 🔛 🐩 🐍 🆎 🔑.
|
||||
FastAPI 🏛, ⏩ (↕-🎭), 🕸 🛠️ 🏗 🛠️ ⏮️ 🐍 3️⃣.8️⃣ ➕ ⚓️ 🔛 🐩 🐍 🆎 🔑.
|
||||
|
||||
🔑 ⚒:
|
||||
|
||||
|
||||
@@ -79,6 +79,6 @@
|
||||
* **🌈** 🕜 🏷 🛠️.
|
||||
* **☁ 🧠 🔎** 📨 📁 🏗.
|
||||
* **🏭 🔜** 🐍 🕸 💽 ⚙️ Uvicorn & 🐁.
|
||||
* **☁ 👩💻** Kubernete (🦲) 🆑/💿 🛠️ 🏗.
|
||||
* **☁ 👩💻** Kubernetes (🦲) 🆑/💿 🛠️ 🏗.
|
||||
* **🤸♂** 💪 ⚒ 1️⃣ 🌈 🏗 🇪🇸 ⏮️ 🏗 🖥.
|
||||
* **💪 🏧** 🎏 🏷 🛠️ (Pytorch, 🇸🇲), 🚫 🌈.
|
||||
|
||||
@@ -371,7 +371,7 @@ http://localhost:8000/items/
|
||||
|
||||
=== "🐍 3️⃣.1️⃣0️⃣ & 🔛"
|
||||
|
||||
```Python hl_lines="12"
|
||||
```Python hl_lines="11"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
|
||||
```
|
||||
|
||||
@@ -421,7 +421,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
|
||||
=== "🐍 3️⃣.1️⃣0️⃣ & 🔛"
|
||||
|
||||
```Python hl_lines="17"
|
||||
```Python hl_lines="16"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
articles:
|
||||
english:
|
||||
Articles:
|
||||
English:
|
||||
- author: Adejumo Ridwan Suleiman
|
||||
author_link: https://www.linkedin.com/in/adejumoridwan/
|
||||
link: https://medium.com/python-in-plain-english/build-an-sms-spam-classifier-serverless-database-with-faunadb-and-fastapi-23dbb275bc5b
|
||||
@@ -236,7 +236,7 @@ articles:
|
||||
author_link: https://medium.com/@krishnardt365
|
||||
link: https://medium.com/@krishnardt365/fastapi-docker-and-postgres-91943e71be92
|
||||
title: Fastapi, Docker(Docker compose) and Postgres
|
||||
german:
|
||||
German:
|
||||
- author: Marcel Sander (actidoo)
|
||||
author_link: https://www.actidoo.com
|
||||
link: https://www.actidoo.com/de/blog/python-fastapi-domain-driven-design
|
||||
@@ -249,7 +249,7 @@ articles:
|
||||
author_link: https://hellocoding.de/autor/felix-schuermeyer/
|
||||
link: https://hellocoding.de/blog/coding-language/python/fastapi
|
||||
title: REST-API Programmieren mittels Python und dem FastAPI Modul
|
||||
japanese:
|
||||
Japanese:
|
||||
- author: '@bee2'
|
||||
author_link: https://qiita.com/bee2
|
||||
link: https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9
|
||||
@@ -298,7 +298,7 @@ articles:
|
||||
author_link: https://qiita.com/mtitg
|
||||
link: https://qiita.com/mtitg/items/47770e9a562dd150631d
|
||||
title: FastAPI|DB接続してCRUDするPython製APIサーバーを構築
|
||||
russian:
|
||||
Russian:
|
||||
- author: Troy Köhler
|
||||
author_link: https://www.linkedin.com/in/trkohler/
|
||||
link: https://trkohler.com/fast-api-introduction-to-framework
|
||||
@@ -311,18 +311,18 @@ articles:
|
||||
author_link: https://habr.com/ru/users/57uff3r/
|
||||
link: https://habr.com/ru/post/454440/
|
||||
title: 'Мелкая питонячая радость #2: Starlette - Солидная примочка – FastAPI'
|
||||
vietnamese:
|
||||
Vietnamese:
|
||||
- author: Nguyễn Nhân
|
||||
author_link: https://fullstackstation.com/author/figonking/
|
||||
link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/
|
||||
title: 'FASTAPI: TRIỂN KHAI BẰNG DOCKER'
|
||||
taiwanese:
|
||||
Taiwanese:
|
||||
- author: Leon
|
||||
author_link: http://editor.leonh.space/
|
||||
link: https://editor.leonh.space/2022/tortoise/
|
||||
title: 'Tortoise ORM / FastAPI 整合快速筆記'
|
||||
podcasts:
|
||||
english:
|
||||
Podcasts:
|
||||
English:
|
||||
- author: Podcast.`__init__`
|
||||
author_link: https://www.pythonpodcast.com/
|
||||
link: https://www.pythonpodcast.com/fastapi-web-application-framework-episode-259/
|
||||
@@ -331,8 +331,8 @@ podcasts:
|
||||
author_link: https://pythonbytes.fm/
|
||||
link: https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855
|
||||
title: FastAPI on PythonBytes
|
||||
talks:
|
||||
english:
|
||||
Talks:
|
||||
English:
|
||||
- author: Sebastián Ramírez (tiangolo)
|
||||
author_link: https://twitter.com/tiangolo
|
||||
link: https://www.youtube.com/watch?v=PnpTY1f4k2U
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
sponsors:
|
||||
- - login: bump-sh
|
||||
- - login: codacy
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1834093?v=4
|
||||
url: https://github.com/codacy
|
||||
- login: bump-sh
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33217836?v=4
|
||||
url: https://github.com/bump-sh
|
||||
- login: cryptapi
|
||||
@@ -11,9 +14,6 @@ sponsors:
|
||||
- login: fern-api
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/102944815?v=4
|
||||
url: https://github.com/fern-api
|
||||
- login: nanram22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/116367316?v=4
|
||||
url: https://github.com/nanram22
|
||||
- - login: nihpo
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1841030?u=0264956d7580f7e46687a762a7baa629f84cf97c&v=4
|
||||
url: https://github.com/nihpo
|
||||
@@ -32,12 +32,12 @@ sponsors:
|
||||
- login: deepset-ai
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51827949?v=4
|
||||
url: https://github.com/deepset-ai
|
||||
- login: databento
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/64141749?v=4
|
||||
url: https://github.com/databento
|
||||
- login: svix
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/80175132?v=4
|
||||
url: https://github.com/svix
|
||||
- login: databento-bot
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/98378480?u=494f679996e39427f7ddb1a7de8441b7c96fb670&v=4
|
||||
url: https://github.com/databento-bot
|
||||
- login: VincentParedes
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4
|
||||
url: https://github.com/VincentParedes
|
||||
@@ -65,10 +65,7 @@ sponsors:
|
||||
- login: Trivie
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4
|
||||
url: https://github.com/Trivie
|
||||
- - login: moellenbeck
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4
|
||||
url: https://github.com/moellenbeck
|
||||
- login: birkjernstrom
|
||||
- - login: birkjernstrom
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/281715?u=4be14b43f76b4bd497b1941309bb390250b405e6&v=4
|
||||
url: https://github.com/birkjernstrom
|
||||
- login: yasyf
|
||||
@@ -83,15 +80,15 @@ sponsors:
|
||||
- login: mainframeindustries
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
|
||||
url: https://github.com/mainframeindustries
|
||||
- login: deployplex
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/57115726?v=4
|
||||
url: https://github.com/deployplex
|
||||
- - login: povilasb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1213442?u=b11f58ed6ceea6e8297c9b310030478ebdac894d&v=4
|
||||
url: https://github.com/povilasb
|
||||
- login: primer-io
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
|
||||
url: https://github.com/primer-io
|
||||
- - login: NateXVI
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48195620?u=4bc8751ae50cb087c40c1fe811764aa070b9eea6&v=4
|
||||
url: https://github.com/NateXVI
|
||||
- - login: Kludex
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
@@ -125,12 +122,12 @@ sponsors:
|
||||
- login: tcsmith
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/989034?u=7d8d741552b3279e8f4d3878679823a705a46f8f&v=4
|
||||
url: https://github.com/tcsmith
|
||||
- login: mrkmcknz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1089376?u=2b9b8a8c25c33a4f6c220095638bd821cdfd13a3&v=4
|
||||
url: https://github.com/mrkmcknz
|
||||
- login: mickaelandrieu
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1247388?u=599f6e73e452a9453f2bd91e5c3100750e731ad4&v=4
|
||||
url: https://github.com/mickaelandrieu
|
||||
- login: knallgelb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2358812?u=c48cb6362b309d74cbf144bd6ad3aed3eb443e82&v=4
|
||||
url: https://github.com/knallgelb
|
||||
- login: Shark009
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4
|
||||
url: https://github.com/Shark009
|
||||
@@ -174,7 +171,7 @@ sponsors:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=c485eefca5c6329600cae63dd35e4f5682ce6924&v=4
|
||||
url: https://github.com/iwpnd
|
||||
- login: FernandoCelmer
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6262214?u=ab6108a843a2fb9df0934f482375d2907609f3ff&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6262214?u=d29fff3fd862fda4ca752079f13f32e84c762ea4&v=4
|
||||
url: https://github.com/FernandoCelmer
|
||||
- login: simw
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6322526?v=4
|
||||
@@ -188,6 +185,9 @@ sponsors:
|
||||
- login: wdwinslow
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
|
||||
url: https://github.com/wdwinslow
|
||||
- login: drcat101
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11951946?u=e714b957185b8cf3d301cced7fc3ad2842122c6a&v=4
|
||||
url: https://github.com/drcat101
|
||||
- login: jsoques
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12414216?u=620921d94196546cc8b9eae2cc4cbc3f95bab42f&v=4
|
||||
url: https://github.com/jsoques
|
||||
@@ -212,9 +212,6 @@ sponsors:
|
||||
- login: Filimoa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=0be845711495bbd7b756e13fcaeb8efc1ebd78ba&v=4
|
||||
url: https://github.com/Filimoa
|
||||
- login: rahulsalgare
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21974430?u=ade6f182b94554ab8491d7421de5e78f711dcaf8&v=4
|
||||
url: https://github.com/rahulsalgare
|
||||
- login: BrettskiPy
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/30988215?u=d8a94a67e140d5ee5427724b292cc52d8827087a&v=4
|
||||
url: https://github.com/BrettskiPy
|
||||
@@ -269,9 +266,12 @@ sponsors:
|
||||
- login: pyt3h
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4
|
||||
url: https://github.com/pyt3h
|
||||
- - login: SebTota
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4
|
||||
url: https://github.com/SebTota
|
||||
- login: apitally
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/138365043?v=4
|
||||
url: https://github.com/apitally
|
||||
- - login: getsentry
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4
|
||||
url: https://github.com/getsentry
|
||||
- - login: pawamoy
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
|
||||
url: https://github.com/pawamoy
|
||||
@@ -299,6 +299,9 @@ sponsors:
|
||||
- login: securancy
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/606673?v=4
|
||||
url: https://github.com/securancy
|
||||
- login: natehouk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/805439?u=d8e4be629dc5d7efae7146157e41ee0bd129d9bc&v=4
|
||||
url: https://github.com/natehouk
|
||||
- login: browniebroke
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4
|
||||
url: https://github.com/browniebroke
|
||||
@@ -323,9 +326,9 @@ sponsors:
|
||||
- login: anthonycorletti
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
|
||||
url: https://github.com/anthonycorletti
|
||||
- login: nikeee
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4068864?u=bbe73151f2b409c120160d032dc9aa6875ef0c4b&v=4
|
||||
url: https://github.com/nikeee
|
||||
- login: erhan
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3872888?u=cd9a20fcd33c5598d9d7797a78dedfc9148592f6&v=4
|
||||
url: https://github.com/erhan
|
||||
- login: Alisa-lisa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4
|
||||
url: https://github.com/Alisa-lisa
|
||||
@@ -366,7 +369,7 @@ sponsors:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8574425?u=aad2a9674273c9275fe414d99269b7418d144089&v=4
|
||||
url: https://github.com/albertkun
|
||||
- login: xncbf
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=866a1311e4bd3ec5ae84185c4fcc99f397c883d7&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=05cb2d7c797a02f666805ad4639d9582f31d432c&v=4
|
||||
url: https://github.com/xncbf
|
||||
- login: DMantis
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9536869?v=4
|
||||
@@ -398,9 +401,6 @@ sponsors:
|
||||
- login: jangia
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4
|
||||
url: https://github.com/jangia
|
||||
- login: timzaz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19709244?u=264d7db95c28156363760229c30ee1116efd4eeb&v=4
|
||||
url: https://github.com/timzaz
|
||||
- login: shuheng-liu
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4
|
||||
url: https://github.com/shuheng-liu
|
||||
@@ -419,15 +419,15 @@ sponsors:
|
||||
- login: joerambo
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26282974?v=4
|
||||
url: https://github.com/joerambo
|
||||
- login: msniezynski
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/27588547?u=0e3be5ac57dcfdf124f470bcdf74b5bf79af1b6c&v=4
|
||||
url: https://github.com/msniezynski
|
||||
- login: rlnchow
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28018479?u=a93ca9cf1422b9ece155784a72d5f2fdbce7adff&v=4
|
||||
url: https://github.com/rlnchow
|
||||
- login: mertguvencli
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29762151?u=16a906d90df96c8cff9ea131a575c4bc171b1523&v=4
|
||||
url: https://github.com/mertguvencli
|
||||
- login: White-Mask
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31826970?u=8625355dc25ddf9c85a8b2b0b9932826c4c8f44c&v=4
|
||||
url: https://github.com/White-Mask
|
||||
- login: HosamAlmoghraby
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32025281?u=aa1b09feabccbf9dc506b81c71155f32d126cefa&v=4
|
||||
url: https://github.com/HosamAlmoghraby
|
||||
@@ -435,14 +435,11 @@ sponsors:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4
|
||||
url: https://github.com/engineerjoe440
|
||||
- login: bnkc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=1a104991a2ea90bfe304bc0b9ef191c7e4891a0e&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=ea88e4bd668c984cff1bca3e71ab2deb37fafdc4&v=4
|
||||
url: https://github.com/bnkc
|
||||
- login: declon
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
|
||||
url: https://github.com/declon
|
||||
- login: miraedbswo
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/36796047?u=9e7a5b3e558edc61d35d0f9dfac37541bae7f56d&v=4
|
||||
url: https://github.com/miraedbswo
|
||||
- login: DSMilestone6538
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37230924?u=f299dce910366471523155e0cb213356d34aadc1&v=4
|
||||
url: https://github.com/DSMilestone6538
|
||||
@@ -458,9 +455,6 @@ sponsors:
|
||||
- login: ArtyomVancyan
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/44609997?v=4
|
||||
url: https://github.com/ArtyomVancyan
|
||||
- login: josehenriqueroveda
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/46685746?u=2e672057a7dbe1dba47e57c378fc0cac336022eb&v=4
|
||||
url: https://github.com/josehenriqueroveda
|
||||
- login: hgalytoby
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=f4888c2c54929bd86eed0d3971d09fcb306e5088&v=4
|
||||
url: https://github.com/hgalytoby
|
||||
@@ -473,12 +467,18 @@ sponsors:
|
||||
- login: 0417taehyun
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
|
||||
url: https://github.com/0417taehyun
|
||||
- login: fernandosmither
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66154723?u=a76a037b5d674938a75d2cff862fb6dfd63ec214&v=4
|
||||
url: https://github.com/fernandosmither
|
||||
- login: romabozhanovgithub
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/67696229?u=e4b921eef096415300425aca249348f8abb78ad7&v=4
|
||||
url: https://github.com/romabozhanovgithub
|
||||
- login: mbukeRepo
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/70356088?u=d2eb23e2b222a3b316c4183b05a3236b32819dc2&v=4
|
||||
url: https://github.com/mbukeRepo
|
||||
- login: PelicanQ
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/77930606?v=4
|
||||
url: https://github.com/PelicanQ
|
||||
- - login: ssbarnea
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/102495?u=b4bf6818deefe59952ac22fec6ed8c76de1b8f7c&v=4
|
||||
url: https://github.com/ssbarnea
|
||||
@@ -491,18 +491,15 @@ sponsors:
|
||||
- login: sadikkuzu
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=d179c06bb9f65c4167fcab118526819f8e0dac17&v=4
|
||||
url: https://github.com/sadikkuzu
|
||||
- login: samnimoh
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33413170?u=147bc516be6cb647b28d7e3b3fea3a018a331145&v=4
|
||||
url: https://github.com/samnimoh
|
||||
- login: msniezynski
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/27588547?u=0e3be5ac57dcfdf124f470bcdf74b5bf79af1b6c&v=4
|
||||
url: https://github.com/msniezynski
|
||||
- login: danburonline
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
|
||||
url: https://github.com/danburonline
|
||||
- login: rwxd
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
|
||||
url: https://github.com/rwxd
|
||||
- login: shywn-mrk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51455763?u=389e2608e4056fe5e1f23e9ad56a9415277504d3&v=4
|
||||
url: https://github.com/shywn-mrk
|
||||
- login: almeida-matheus
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66216198?u=54335eaa0ced626be5c1ff52fead1ebc032286ec&v=4
|
||||
url: https://github.com/almeida-matheus
|
||||
- login: IvanReyesO7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/74359151?u=4b2c368f71e1411b462a8c2290c920ad35dc1af8&v=4
|
||||
url: https://github.com/IvanReyesO7
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
maintainers:
|
||||
- login: tiangolo
|
||||
answers: 1868
|
||||
prs: 496
|
||||
answers: 1870
|
||||
prs: 508
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
|
||||
url: https://github.com/tiangolo
|
||||
experts:
|
||||
- login: Kludex
|
||||
count: 501
|
||||
count: 512
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: dmontagu
|
||||
@@ -26,21 +26,21 @@ experts:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
|
||||
url: https://github.com/JarroVGIT
|
||||
- login: jgould22
|
||||
count: 168
|
||||
count: 186
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: euri10
|
||||
count: 153
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
|
||||
url: https://github.com/euri10
|
||||
- login: iudeen
|
||||
count: 126
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: phy25
|
||||
count: 126
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
|
||||
url: https://github.com/phy25
|
||||
- login: iudeen
|
||||
count: 122
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: raphaelauv
|
||||
count: 83
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
@@ -61,14 +61,14 @@ experts:
|
||||
count: 49
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
|
||||
url: https://github.com/sm-Fifteen
|
||||
- login: yinziyan1206
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: acidjunk
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
|
||||
url: https://github.com/acidjunk
|
||||
- login: insomnes
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
|
||||
url: https://github.com/insomnes
|
||||
- login: Dustyposa
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
|
||||
@@ -77,18 +77,18 @@ experts:
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4
|
||||
url: https://github.com/adriangb
|
||||
- login: yinziyan1206
|
||||
count: 44
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: odiseo0
|
||||
count: 43
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: insomnes
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4
|
||||
url: https://github.com/insomnes
|
||||
- login: frankie567
|
||||
count: 43
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=c159fe047727aedecbbeeaa96a1b03ceb9d39add&v=4
|
||||
url: https://github.com/frankie567
|
||||
- login: odiseo0
|
||||
count: 43
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: includeamin
|
||||
count: 40
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
@@ -101,14 +101,14 @@ experts:
|
||||
count: 37
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
|
||||
url: https://github.com/STeveShary
|
||||
- login: n8sty
|
||||
count: 36
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
|
||||
url: https://github.com/n8sty
|
||||
- login: krishnardt
|
||||
count: 35
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
|
||||
url: https://github.com/krishnardt
|
||||
- login: n8sty
|
||||
count: 32
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
|
||||
url: https://github.com/n8sty
|
||||
- login: panla
|
||||
count: 32
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
|
||||
@@ -137,18 +137,22 @@ experts:
|
||||
count: 21
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=5fe59a56e1f2f9ccd8005d71752a8276f133ae1a&v=4
|
||||
url: https://github.com/rafsaf
|
||||
- login: JavierSanchezCastro
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4
|
||||
url: https://github.com/JavierSanchezCastro
|
||||
- login: nsidnev
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
|
||||
url: https://github.com/nsidnev
|
||||
- login: chris-allnutt
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4
|
||||
url: https://github.com/chris-allnutt
|
||||
- login: ebottos94
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4
|
||||
url: https://github.com/ebottos94
|
||||
- login: nsidnev
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4
|
||||
url: https://github.com/nsidnev
|
||||
- login: JavierSanchezCastro
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4
|
||||
url: https://github.com/JavierSanchezCastro
|
||||
- login: chrisK824
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4
|
||||
@@ -161,10 +165,10 @@ experts:
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
|
||||
url: https://github.com/retnikt
|
||||
- login: ebottos94
|
||||
- login: nymous
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4
|
||||
url: https://github.com/ebottos94
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4
|
||||
url: https://github.com/nymous
|
||||
- login: Hultner
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
|
||||
@@ -181,39 +185,47 @@ experts:
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16540232?u=05d2beb8e034d584d0a374b99d8826327bd7f614&v=4
|
||||
url: https://github.com/caeser1996
|
||||
- login: nymous
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4
|
||||
url: https://github.com/nymous
|
||||
- login: jonatasoli
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
|
||||
url: https://github.com/jonatasoli
|
||||
- login: dstlny
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4
|
||||
url: https://github.com/dstlny
|
||||
- login: jonatasoli
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
|
||||
url: https://github.com/jonatasoli
|
||||
- login: abhint
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4
|
||||
url: https://github.com/abhint
|
||||
last_month_active:
|
||||
- login: jgould22
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: Kludex
|
||||
count: 8
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: White-Mask
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31826970?u=8625355dc25ddf9c85a8b2b0b9932826c4c8f44c&v=4
|
||||
url: https://github.com/White-Mask
|
||||
- login: n8sty
|
||||
count: 7
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
|
||||
url: https://github.com/n8sty
|
||||
- login: chrisK824
|
||||
- login: hasansezertasan
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4
|
||||
url: https://github.com/chrisK824
|
||||
- login: danielfcollier
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13135006?u=e389634d494d503cca867f76c2d00cacc273a46e&v=4
|
||||
url: https://github.com/hasansezertasan
|
||||
- login: pythonweb2
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38995330?u=5799be795fc310f75f3a5fe9242307d59b194520&v=4
|
||||
url: https://github.com/danielfcollier
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32141163?v=4
|
||||
url: https://github.com/pythonweb2
|
||||
- login: ebottos94
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4
|
||||
url: https://github.com/ebottos94
|
||||
top_contributors:
|
||||
- login: waynerv
|
||||
count: 25
|
||||
@@ -349,17 +361,17 @@ top_contributors:
|
||||
url: https://github.com/rostik1410
|
||||
top_reviewers:
|
||||
- login: Kludex
|
||||
count: 139
|
||||
count: 145
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: BilalAlpaslan
|
||||
count: 82
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
|
||||
url: https://github.com/BilalAlpaslan
|
||||
- login: yezz123
|
||||
count: 80
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4
|
||||
url: https://github.com/yezz123
|
||||
- login: BilalAlpaslan
|
||||
count: 79
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
|
||||
url: https://github.com/BilalAlpaslan
|
||||
- login: iudeen
|
||||
count: 54
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
@@ -376,14 +388,14 @@ top_reviewers:
|
||||
count: 47
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4
|
||||
url: https://github.com/Laineyzhang55
|
||||
- login: Xewus
|
||||
count: 47
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
|
||||
url: https://github.com/Xewus
|
||||
- login: ycd
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Xewus
|
||||
count: 44
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4
|
||||
url: https://github.com/Xewus
|
||||
- login: cikay
|
||||
count: 41
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4
|
||||
@@ -412,14 +424,14 @@ top_reviewers:
|
||||
count: 26
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
|
||||
url: https://github.com/lsglucas
|
||||
- login: Ryandaydev
|
||||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=ba0eea19429e7cf77cf2ab8ad2f3d3af202bc1cf&v=4
|
||||
url: https://github.com/Ryandaydev
|
||||
- login: LorhanSohaky
|
||||
count: 24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
|
||||
url: https://github.com/LorhanSohaky
|
||||
- login: Ryandaydev
|
||||
count: 24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4
|
||||
url: https://github.com/Ryandaydev
|
||||
- login: dmontagu
|
||||
count: 23
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
|
||||
@@ -476,14 +488,14 @@ top_reviewers:
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
|
||||
url: https://github.com/delhi09
|
||||
- login: peidrao
|
||||
count: 14
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=a66902b40c13647d0ed0e573d598128240a4dd04&v=4
|
||||
url: https://github.com/peidrao
|
||||
- login: sh0nk
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4
|
||||
url: https://github.com/sh0nk
|
||||
- login: peidrao
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=a66902b40c13647d0ed0e573d598128240a4dd04&v=4
|
||||
url: https://github.com/peidrao
|
||||
- login: wdh99
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/108172295?u=8a8fb95d5afe3e0fa33257b2aecae88d436249eb&v=4
|
||||
|
||||
@@ -5,15 +5,21 @@ gold:
|
||||
- url: https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023
|
||||
title: "Build, run and scale your apps on a modern, reliable, and secure PaaS."
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/platform-sh.png
|
||||
- url: https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge
|
||||
title: Fern | SDKs and API docs
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/fern.svg
|
||||
- url: https://www.porter.run
|
||||
title: Deploy FastAPI on AWS with a few clicks
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/porter.png
|
||||
- url: https://bump.sh/fastapi?utm_source=fastapi&utm_medium=referral&utm_campaign=sponsor
|
||||
title: Automate FastAPI documentation generation with Bump.sh
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/bump-sh.svg
|
||||
- url: https://reflex.dev
|
||||
title: Reflex
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/reflex.png
|
||||
- url: https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge
|
||||
title: "Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files"
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/scalar.svg
|
||||
- url: https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge
|
||||
title: Auth, user management and more for your B2B product
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/propelauth.png
|
||||
silver:
|
||||
- url: https://www.deta.sh/?ref=fastapi
|
||||
title: The launchpad for all your (team's) ideas
|
||||
@@ -39,6 +45,9 @@ silver:
|
||||
- url: https://www.svix.com/
|
||||
title: Svix - Webhooks as a service
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/svix.svg
|
||||
- url: https://www.codacy.com/?utm_source=github&utm_medium=sponsors&utm_id=pioneers
|
||||
title: Take code reviews from hours to minutes
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/codacy.png
|
||||
bronze:
|
||||
- url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source
|
||||
title: Biosecurity risk assessments made easy.
|
||||
|
||||
@@ -14,9 +14,12 @@ logins:
|
||||
- nihpo
|
||||
- armand-sauzay
|
||||
- databento-bot
|
||||
- databento
|
||||
- nanram22
|
||||
- Flint-company
|
||||
- porter-dev
|
||||
- fern-api
|
||||
- ndimares
|
||||
- svixhq
|
||||
- Alek99
|
||||
- codacy
|
||||
|
||||
@@ -20,10 +20,9 @@ Some of them also ✨ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-autho
|
||||
|
||||
And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good service** but also want to make sure you have a **good and healthy framework**, FastAPI. 🙇
|
||||
|
||||
You might want to try their services and follow their guides:
|
||||
For example, you might want to try <a href="https://speakeasyapi.dev/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>.
|
||||
|
||||
* <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-generate-clients" class="external-link" target="_blank">Fern</a>
|
||||
* <a href="https://speakeasyapi.dev/?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
|
||||
There are also several other companies offering similar services that you can search and find online. 🤓
|
||||
|
||||
## Generate a TypeScript Frontend Client
|
||||
|
||||
@@ -88,7 +87,7 @@ It could look like this:
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios"
|
||||
"generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes"
|
||||
},
|
||||
"author": "",
|
||||
"license": "",
|
||||
@@ -107,7 +106,7 @@ After having that NPM `generate-client` script there, you can run it with:
|
||||
$ npm run generate-client
|
||||
|
||||
frontend-app@1.0.0 generate-client /home/user/code/frontend-app
|
||||
> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios
|
||||
> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes
|
||||
```
|
||||
|
||||
</div>
|
||||
@@ -247,7 +246,7 @@ Now as the end result is in a file `openapi.json`, you would modify the `package
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"generate-client": "openapi --input ./openapi.json --output ./src/client --client axios"
|
||||
"generate-client": "openapi --input ./openapi.json --output ./src/client --client axios --useOptions --useUnionTypes"
|
||||
},
|
||||
"author": "",
|
||||
"license": "",
|
||||
|
||||
@@ -276,7 +276,7 @@ Now we create a dependency that returns a new `config.Settings()`.
|
||||
```
|
||||
|
||||
!!! tip
|
||||
We'll discuss the `@lru_cache()` in a bit.
|
||||
We'll discuss the `@lru_cache` in a bit.
|
||||
|
||||
For now you can assume `get_settings()` is a normal function.
|
||||
|
||||
@@ -326,7 +326,7 @@ This practice is common enough that it has a name, these environment variables a
|
||||
|
||||
But a dotenv file doesn't really have to have that exact filename.
|
||||
|
||||
Pydantic has support for reading from these types of files using an external library. You can read more at <a href="https://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic Settings: Dotenv (.env) support</a>.
|
||||
Pydantic has support for reading from these types of files using an external library. You can read more at <a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic Settings: Dotenv (.env) support</a>.
|
||||
|
||||
!!! tip
|
||||
For this to work, you need to `pip install python-dotenv`.
|
||||
@@ -388,7 +388,7 @@ def get_settings():
|
||||
|
||||
we would create that object for each request, and we would be reading the `.env` file for each request. ⚠️
|
||||
|
||||
But as we are using the `@lru_cache()` decorator on top, the `Settings` object will be created only once, the first time it's called. ✔️
|
||||
But as we are using the `@lru_cache` decorator on top, the `Settings` object will be created only once, the first time it's called. ✔️
|
||||
|
||||
=== "Python 3.9+"
|
||||
|
||||
@@ -415,14 +415,14 @@ Then for any subsequent calls of `get_settings()` in the dependencies for the ne
|
||||
|
||||
#### `lru_cache` Technical Details
|
||||
|
||||
`@lru_cache()` modifies the function it decorates to return the same value that was returned the first time, instead of computing it again, executing the code of the function every time.
|
||||
`@lru_cache` modifies the function it decorates to return the same value that was returned the first time, instead of computing it again, executing the code of the function every time.
|
||||
|
||||
So, the function below it will be executed once for each combination of arguments. And then the values returned by each of those combinations of arguments will be used again and again whenever the function is called with exactly the same combination of arguments.
|
||||
|
||||
For example, if you have a function:
|
||||
|
||||
```Python
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def say_hi(name: str, salutation: str = "Ms."):
|
||||
return f"Hello {salutation} {name}"
|
||||
```
|
||||
@@ -474,7 +474,7 @@ In the case of our dependency `get_settings()`, the function doesn't even take a
|
||||
|
||||
That way, it behaves almost as if it was just a global variable. But as it uses a dependency function, then we can override it easily for testing.
|
||||
|
||||
`@lru_cache()` is part of `functools` which is part of Python's standard library, you can read more about it in the <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python docs for `@lru_cache()`</a>.
|
||||
`@lru_cache` is part of `functools` which is part of Python's standard library, you can read more about it in the <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python docs for `@lru_cache`</a>.
|
||||
|
||||
## Recap
|
||||
|
||||
@@ -482,4 +482,4 @@ You can use Pydantic Settings to handle the settings or configurations for your
|
||||
|
||||
* By using a dependency you can simplify testing.
|
||||
* You can use `.env` files with it.
|
||||
* Using `@lru_cache()` lets you avoid reading the dotenv file again and again for each request, while allowing you to override it during testing.
|
||||
* Using `@lru_cache` lets you avoid reading the dotenv file again and again for each request, while allowing you to override it during testing.
|
||||
|
||||
@@ -119,8 +119,6 @@ That's why when talking about version 2.0 it's common to say "Swagger", and for
|
||||
|
||||
These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**).
|
||||
|
||||
For example, you could try <a href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=docs-alternatives" class="external-link" target="_blank">Fern</a> which is also a FastAPI sponsor. 😎🎉
|
||||
|
||||
### Flask REST frameworks
|
||||
|
||||
There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit.
|
||||
|
||||
@@ -409,11 +409,11 @@ Still, in both situations, chances are that **FastAPI** will [still be faster](/
|
||||
|
||||
### Dependencies
|
||||
|
||||
The same applies for [dependencies](/tutorial/dependencies/index.md){.internal-link target=_blank}. If a dependency is a standard `def` function instead of `async def`, it is run in the external threadpool.
|
||||
The same applies for [dependencies](./tutorial/dependencies/index.md){.internal-link target=_blank}. If a dependency is a standard `def` function instead of `async def`, it is run in the external threadpool.
|
||||
|
||||
### Sub-dependencies
|
||||
|
||||
You can have multiple dependencies and [sub-dependencies](/tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requiring each other (as parameters of the function definitions), some of them might be created with `async def` and some with normal `def`. It would still work, and the ones created with normal `def` would be called on an external thread (from the threadpool) instead of being "awaited".
|
||||
You can have multiple dependencies and [sub-dependencies](./tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requiring each other (as parameters of the function definitions), some of them might be created with `async def` and some with normal `def`. It would still work, and the ones created with normal `def` would be called on an external thread (from the threadpool) instead of being "awaited".
|
||||
|
||||
### Other utility functions
|
||||
|
||||
|
||||
@@ -9,79 +9,21 @@ Here's an incomplete list of some of them.
|
||||
!!! tip
|
||||
If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">Pull Request adding it</a>.
|
||||
|
||||
## Articles
|
||||
{% for section_name, section_content in external_links.items() %}
|
||||
|
||||
### English
|
||||
## {{ section_name }}
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
{% for lang_name, lang_content in section_content.items() %}
|
||||
|
||||
### {{ lang_name }}
|
||||
|
||||
{% for item in lang_content %}
|
||||
|
||||
* <a href="{{ item.link }}" class="external-link" target="_blank">{{ item.title }}</a> by <a href="{{ item.author_link }}" class="external-link" target="_blank">{{ item.author }}</a>.
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Japanese
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Vietnamese
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Russian
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### German
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Taiwanese
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.taiwanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Podcasts
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Talks
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Projects
|
||||
|
||||
|
||||
@@ -231,8 +231,6 @@ Join the 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" targ
|
||||
|
||||
Use the chat only for other general conversations.
|
||||
|
||||
There is also the previous <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">Gitter chat</a>, but as it doesn't have channels and advanced features, conversations are more difficult, so Discord is now the recommended system.
|
||||
|
||||
### Don't use the chat for questions
|
||||
|
||||
Have in mind that as chats allow more "free conversation", it's easy to ask questions that are too general and more difficult to answer, so, you might not receive answers.
|
||||
|
||||
@@ -96,8 +96,8 @@ You can probably right-click each link and select an option similar to `Save lin
|
||||
|
||||
**Swagger UI** uses the files:
|
||||
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js" class="external-link" target="_blank">`swagger-ui-bundle.js`</a>
|
||||
* <a href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css" class="external-link" target="_blank">`swagger-ui.css`</a>
|
||||
|
||||
And **ReDoc** uses the file:
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ It will have the database connection open at the beginning and will just wait so
|
||||
|
||||
This will easily let you test that your app with Peewee and FastAPI is behaving correctly with all the stuff about threads.
|
||||
|
||||
If you want to check how Peewee would break your app if used without modification, go the the `sql_app/database.py` file and comment the line:
|
||||
If you want to check how Peewee would break your app if used without modification, go the `sql_app/database.py` file and comment the line:
|
||||
|
||||
```Python
|
||||
# db._state = PeeweeConnectionState()
|
||||
|
||||
BIN
docs/en/docs/img/sponsors/codacy.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/en/docs/img/sponsors/propelauth-banner.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/en/docs/img/sponsors/propelauth.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/en/docs/img/sponsors/reflex-banner.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
docs/en/docs/img/sponsors/reflex.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
1
docs/en/docs/img/sponsors/scalar-banner.svg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
1
docs/en/docs/img/sponsors/scalar.svg
Normal file
|
After Width: | Height: | Size: 36 KiB |
@@ -1,3 +0,0 @@
|
||||
((window.gitter = {}).chat = {}).options = {
|
||||
room: 'tiangolo/fastapi'
|
||||
};
|
||||
@@ -18,7 +18,7 @@ from fastapi import Depends
|
||||
## `Security()`
|
||||
|
||||
For many scenarios, you can handle security (authorization, authentication, etc.) with
|
||||
dependendencies, using `Depends()`.
|
||||
dependencies, using `Depends()`.
|
||||
|
||||
But when you want to also declare OAuth2 scopes, you can use `Security()` instead of
|
||||
`Depends()`.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Reference - Code API
|
||||
|
||||
Here's the reference or code API, the classes, functions, parameters, attributes, and
|
||||
all the FastAPI parts you can use in you applications.
|
||||
all the FastAPI parts you can use in your applications.
|
||||
|
||||
If you want to **learn FastAPI** you are much better off reading the
|
||||
[FastAPI Tutorial](https://fastapi.tiangolo.com/tutorial/).
|
||||
|
||||
@@ -7,6 +7,182 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.106.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
Using resources from dependencies with `yield` in background tasks is no longer supported.
|
||||
|
||||
This change is what supports the new features, read below. 🤓
|
||||
|
||||
### Dependencies with `yield`, `HTTPException` and Background Tasks
|
||||
|
||||
Dependencies with `yield` now can raise `HTTPException` and other exceptions after `yield`. 🎉
|
||||
|
||||
Read the new docs here: [Dependencies with `yield` and `HTTPException`](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-httpexception).
|
||||
|
||||
```Python
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
from typing_extensions import Annotated
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
data = {
|
||||
"plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
|
||||
"portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
|
||||
}
|
||||
|
||||
|
||||
class OwnerError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except OwnerError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Onwer error: {e}")
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
|
||||
if item_id not in data:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
item = data[item_id]
|
||||
if item["owner"] != username:
|
||||
raise OwnerError(username)
|
||||
return item
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Before FastAPI 0.106.0, raising exceptions after `yield` was not possible, the exit code in dependencies with `yield` was executed *after* the response was sent, so [Exception Handlers](https://fastapi.tiangolo.com/tutorial/handling-errors/#install-custom-exception-handlers) would have already run.
|
||||
|
||||
This was designed this way mainly to allow using the same objects "yielded" by dependencies inside of background tasks, because the exit code would be executed after the background tasks were finished.
|
||||
|
||||
Nevertheless, as this would mean waiting for the response to travel through the network while unnecessarily holding a resource in a dependency with yield (for example a database connection), this was changed in FastAPI 0.106.0.
|
||||
|
||||
Additionally, a background task is normally an independent set of logic that should be handled separately, with its own resources (e.g. its own database connection).
|
||||
|
||||
If you used to rely on this behavior, now you should create the resources for background tasks inside the background task itself, and use internally only data that doesn't depend on the resources of dependencies with `yield`.
|
||||
|
||||
For example, instead of using the same database session, you would create a new database session inside of the background task, and you would obtain the objects from the database using this new session. And then instead of passing the object from the database as a parameter to the background task function, you would pass the ID of that object and then obtain the object again inside the background task function.
|
||||
|
||||
The sequence of execution before FastAPI 0.106.0 was like this diagram:
|
||||
|
||||
Time flows from top to bottom. And each column is one of the parts interacting or executing code.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant client as Client
|
||||
participant handler as Exception handler
|
||||
participant dep as Dep with yield
|
||||
participant operation as Path Operation
|
||||
participant tasks as Background tasks
|
||||
|
||||
Note over client,tasks: Can raise exception for dependency, handled after response is sent
|
||||
Note over client,operation: Can raise HTTPException and can change the response
|
||||
client ->> dep: Start request
|
||||
Note over dep: Run code up to yield
|
||||
opt raise
|
||||
dep -->> handler: Raise HTTPException
|
||||
handler -->> client: HTTP error response
|
||||
dep -->> dep: Raise other exception
|
||||
end
|
||||
dep ->> operation: Run dependency, e.g. DB session
|
||||
opt raise
|
||||
operation -->> dep: Raise HTTPException
|
||||
dep -->> handler: Auto forward exception
|
||||
handler -->> client: HTTP error response
|
||||
operation -->> dep: Raise other exception
|
||||
dep -->> handler: Auto forward exception
|
||||
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 -->> dep: Raise other exception
|
||||
end
|
||||
Note over dep: After yield
|
||||
opt Handle other exception
|
||||
dep -->> dep: Handle exception, can't change response. E.g. close DB session.
|
||||
end
|
||||
```
|
||||
|
||||
The new execution flow can be found in the docs: [Execution of dependencies with `yield`](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#execution-of-dependencies-with-yield).
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add support for raising exceptions (including `HTTPException`) in dependencies with `yield` in the exit code, do not support them in background tasks. PR [#10831](https://github.com/tiangolo/fastapi/pull/10831) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 👥 Update FastAPI People. PR [#10567](https://github.com/tiangolo/fastapi/pull/10567) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.105.0
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add support for multiple Annotated annotations, e.g. `Annotated[str, Field(), Query()]`. PR [#10773](https://github.com/tiangolo/fastapi/pull/10773) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Refactors
|
||||
|
||||
* 🔥 Remove unused NoneType. PR [#10774](https://github.com/tiangolo/fastapi/pull/10774) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Tweak default suggested configs for generating clients. PR [#10736](https://github.com/tiangolo/fastapi/pull/10736) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔧 Update sponsors, add Scalar. PR [#10728](https://github.com/tiangolo/fastapi/pull/10728) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, add PropelAuth. PR [#10760](https://github.com/tiangolo/fastapi/pull/10760) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Update build docs, verify README on CI. PR [#10750](https://github.com/tiangolo/fastapi/pull/10750) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, remove Fern. PR [#10729](https://github.com/tiangolo/fastapi/pull/10729) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, add Codacy. PR [#10677](https://github.com/tiangolo/fastapi/pull/10677) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, add Reflex. PR [#10676](https://github.com/tiangolo/fastapi/pull/10676) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update release notes, move and check latest-changes. PR [#10588](https://github.com/tiangolo/fastapi/pull/10588) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Upgrade latest-changes GitHub Action. PR [#10587](https://github.com/tiangolo/fastapi/pull/10587) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.104.1
|
||||
|
||||
### Fixes
|
||||
|
||||
* 📌 Pin Swagger UI version to 5.9.0 temporarily to handle a bug crashing it in 5.9.1. PR [#10529](https://github.com/tiangolo/fastapi/pull/10529) by [@alejandraklachquin](https://github.com/alejandraklachquin).
|
||||
* This is not really a bug in FastAPI but in Swagger UI, nevertheless pinning the version will work while a solution is found on the [Swagger UI side](https://github.com/swagger-api/swagger-ui/issues/9337).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update data structure and render for external-links. PR [#10495](https://github.com/tiangolo/fastapi/pull/10495) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ✏️ Fix link to SPDX license identifier in `docs/en/docs/tutorial/metadata.md`. PR [#10433](https://github.com/tiangolo/fastapi/pull/10433) by [@worldworm](https://github.com/worldworm).
|
||||
* 📝 Update example validation error from Pydantic v1 to match Pydantic v2 in `docs/en/docs/tutorial/path-params.md`. PR [#10043](https://github.com/tiangolo/fastapi/pull/10043) by [@giuliowaitforitdavide](https://github.com/giuliowaitforitdavide).
|
||||
* ✏️ Fix typos in emoji docs and in some source examples. PR [#10438](https://github.com/tiangolo/fastapi/pull/10438) by [@afuetterer](https://github.com/afuetterer).
|
||||
* ✏️ Fix typo in `docs/en/docs/reference/dependencies.md`. PR [#10465](https://github.com/tiangolo/fastapi/pull/10465) by [@suravshresth](https://github.com/suravshresth).
|
||||
* ✏️ Fix typos and rewordings in `docs/en/docs/tutorial/body-nested-models.md`. PR [#10468](https://github.com/tiangolo/fastapi/pull/10468) by [@yogabonito](https://github.com/yogabonito).
|
||||
* 📝 Update docs, remove references to removed `pydantic.Required` in `docs/en/docs/tutorial/query-params-str-validations.md`. PR [#10469](https://github.com/tiangolo/fastapi/pull/10469) by [@yogabonito](https://github.com/yogabonito).
|
||||
* ✏️ Fix typo in `docs/en/docs/reference/index.md`. PR [#10467](https://github.com/tiangolo/fastapi/pull/10467) by [@tarsil](https://github.com/tarsil).
|
||||
* 🔥 Remove unnecessary duplicated docstrings. PR [#10484](https://github.com/tiangolo/fastapi/pull/10484) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* ✏️ Update Pydantic links to dotenv support. PR [#10511](https://github.com/tiangolo/fastapi/pull/10511) by [@White-Mask](https://github.com/White-Mask).
|
||||
* ✏️ Update links in `docs/en/docs/async.md` and `docs/zh/docs/async.md` to make them relative. PR [#10498](https://github.com/tiangolo/fastapi/pull/10498) by [@hasnatsajid](https://github.com/hasnatsajid).
|
||||
* ✏️ Fix links in `docs/em/docs/async.md`. PR [#10507](https://github.com/tiangolo/fastapi/pull/10507) by [@hasnatsajid](https://github.com/hasnatsajid).
|
||||
* ✏️ Fix typo in `docs/em/docs/index.md`, Python 3.8. PR [#10521](https://github.com/tiangolo/fastapi/pull/10521) by [@kerriop](https://github.com/kerriop).
|
||||
* ⬆ Bump pillow from 9.5.0 to 10.1.0. PR [#10446](https://github.com/tiangolo/fastapi/pull/10446) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Update mkdocs-material requirement from <9.0.0,>=8.1.4 to >=8.1.4,<10.0.0. PR [#5862](https://github.com/tiangolo/fastapi/pull/5862) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump mkdocs-material from 9.1.21 to 9.4.7. PR [#10545](https://github.com/tiangolo/fastapi/pull/10545) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* 👷 Install MkDocs Material Insiders only when secrets are available, for Dependabot. PR [#10544](https://github.com/tiangolo/fastapi/pull/10544) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors badges, Databento. PR [#10519](https://github.com/tiangolo/fastapi/pull/10519) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Adopt Ruff format. PR [#10517](https://github.com/tiangolo/fastapi/pull/10517) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Add `CITATION.cff` file for academic citations. PR [#10496](https://github.com/tiangolo/fastapi/pull/10496) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix overriding MKDocs theme lang in hook. PR [#10490](https://github.com/tiangolo/fastapi/pull/10490) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔥 Drop/close Gitter chat. Questions should go to GitHub Discussions, free conversations to Discord.. PR [#10485](https://github.com/tiangolo/fastapi/pull/10485) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.104.0
|
||||
|
||||
## Features
|
||||
|
||||
@@ -183,18 +183,18 @@ This would mean that **FastAPI** would expect a body similar to:
|
||||
|
||||
Again, doing just that declaration, with **FastAPI** you get:
|
||||
|
||||
* Editor support (completion, etc), even for nested models
|
||||
* Editor support (completion, etc.), even for nested models
|
||||
* Data conversion
|
||||
* Data validation
|
||||
* Automatic documentation
|
||||
|
||||
## Special types and validation
|
||||
|
||||
Apart from normal singular types like `str`, `int`, `float`, etc. You can use more complex singular types that inherit from `str`.
|
||||
Apart from normal singular types like `str`, `int`, `float`, etc. you can use more complex singular types that inherit from `str`.
|
||||
|
||||
To see all the options you have, checkout the docs for <a href="https://pydantic-docs.helpmanual.io/usage/types/" class="external-link" target="_blank">Pydantic's exotic types</a>. You will see some examples in the next chapter.
|
||||
|
||||
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `HttpUrl`:
|
||||
For example, as in the `Image` model we have a `url` field, we can declare it to be an instance of Pydantic's `HttpUrl` instead of a `str`:
|
||||
|
||||
=== "Python 3.10+"
|
||||
|
||||
@@ -218,7 +218,7 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op
|
||||
|
||||
## Attributes with lists of submodels
|
||||
|
||||
You can also use Pydantic models as subtypes of `list`, `set`, etc:
|
||||
You can also use Pydantic models as subtypes of `list`, `set`, etc.:
|
||||
|
||||
=== "Python 3.10+"
|
||||
|
||||
@@ -238,7 +238,7 @@ You can also use Pydantic models as subtypes of `list`, `set`, etc:
|
||||
{!> ../../../docs_src/body_nested_models/tutorial006.py!}
|
||||
```
|
||||
|
||||
This will expect (convert, validate, document, etc) a JSON body like:
|
||||
This will expect (convert, validate, document, etc.) a JSON body like:
|
||||
|
||||
```JSON hl_lines="11"
|
||||
{
|
||||
@@ -334,15 +334,15 @@ But you don't have to worry about them either, incoming dicts are converted auto
|
||||
|
||||
## Bodies of arbitrary `dict`s
|
||||
|
||||
You can also declare a body as a `dict` with keys of some type and values of other type.
|
||||
You can also declare a body as a `dict` with keys of some type and values of some other type.
|
||||
|
||||
Without having to know beforehand what are the valid field/attribute names (as would be the case with Pydantic models).
|
||||
This way, you don't have to know beforehand what the valid field/attribute names are (as would be the case with Pydantic models).
|
||||
|
||||
This would be useful if you want to receive keys that you don't already know.
|
||||
|
||||
---
|
||||
|
||||
Other useful case is when you want to have keys of other type, e.g. `int`.
|
||||
Another useful case is when you want to have keys of another type (e.g., `int`).
|
||||
|
||||
That's what we are going to see here.
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Dependencies with yield
|
||||
|
||||
FastAPI supports dependencies that do some <abbr title='sometimes also called "exit", "cleanup", "teardown", "close", "context managers", ...'>extra steps after finishing</abbr>.
|
||||
FastAPI supports dependencies that do some <abbr title='sometimes also called "exit code", "cleanup code", "teardown code", "closing code", "context manager exit code", etc.'>extra steps after finishing</abbr>.
|
||||
|
||||
To do this, use `yield` instead of `return`, and write the extra steps after.
|
||||
To do this, use `yield` instead of `return`, and write the extra steps (code) after.
|
||||
|
||||
!!! tip
|
||||
Make sure to use `yield` one single time.
|
||||
@@ -21,7 +21,7 @@ To do this, use `yield` instead of `return`, and write the extra steps after.
|
||||
|
||||
For example, you could use this to create a database session and close it after finishing.
|
||||
|
||||
Only the code prior to and including the `yield` statement is executed before sending a response:
|
||||
Only the code prior to and including the `yield` statement is executed before creating a response:
|
||||
|
||||
```Python hl_lines="2-4"
|
||||
{!../../../docs_src/dependencies/tutorial007.py!}
|
||||
@@ -40,7 +40,7 @@ The code following the `yield` statement is executed after the response has been
|
||||
```
|
||||
|
||||
!!! tip
|
||||
You can use `async` or normal functions.
|
||||
You can use `async` or regular functions.
|
||||
|
||||
**FastAPI** will do the right thing with each, the same as with normal dependencies.
|
||||
|
||||
@@ -114,7 +114,7 @@ And, in turn, `dependency_b` needs the value from `dependency_a` (here named `de
|
||||
{!> ../../../docs_src/dependencies/tutorial008.py!}
|
||||
```
|
||||
|
||||
The same way, you could have dependencies with `yield` and `return` mixed.
|
||||
The same way, you could have some dependencies with `yield` and some other dependencies with `return`, and have some of those depend on some of the others.
|
||||
|
||||
And you could have a single dependency that requires several other dependencies with `yield`, etc.
|
||||
|
||||
@@ -131,24 +131,38 @@ You can have any combinations of dependencies that you want.
|
||||
|
||||
You saw that you can use dependencies with `yield` and have `try` blocks that catch exceptions.
|
||||
|
||||
It might be tempting to raise an `HTTPException` or similar in the exit code, after the `yield`. But **it won't work**.
|
||||
|
||||
The exit code in dependencies with `yield` is executed *after* the response is sent, so [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} will have already run. There's nothing catching exceptions thrown by your dependencies in the exit code (after the `yield`).
|
||||
|
||||
So, if you raise an `HTTPException` after the `yield`, the default (or any custom) exception handler that catches `HTTPException`s and returns an HTTP 400 response won't be there to catch that exception anymore.
|
||||
|
||||
This is what allows anything set in the dependency (e.g. a DB session) to, for example, be used by background tasks.
|
||||
|
||||
Background tasks are run *after* the response has been sent. So there's no way to raise an `HTTPException` because there's not even a way to change the response that is *already sent*.
|
||||
|
||||
But if a background task creates a DB error, at least you can rollback or cleanly close the session in the dependency with `yield`, and maybe log the error or report it to a remote tracking system.
|
||||
|
||||
If you have some code that you know could raise an exception, do the most normal/"Pythonic" thing and add a `try` block in that section of the code.
|
||||
|
||||
If you have custom exceptions that you would like to handle *before* returning the response and possibly modifying the response, maybe even raising an `HTTPException`, create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
The same way, you could raise an `HTTPException` or similar in the exit code, after the `yield`.
|
||||
|
||||
!!! tip
|
||||
You can still raise exceptions including `HTTPException` *before* the `yield`. But not after.
|
||||
|
||||
This is a somewhat advanced technique, and in most of the cases you won't really need it, as you can raise exceptions (including `HTTPException`) from inside of the rest of your application code, for example, in the *path operation function*.
|
||||
|
||||
But it's there for you if you need it. 🤓
|
||||
|
||||
=== "Python 3.9+"
|
||||
|
||||
```Python hl_lines="18-22 31"
|
||||
{!> ../../../docs_src/dependencies/tutorial008b_an_py39.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="17-21 30"
|
||||
{!> ../../../docs_src/dependencies/tutorial008b_an.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+ non-Annotated"
|
||||
|
||||
!!! tip
|
||||
Prefer to use the `Annotated` version if possible.
|
||||
|
||||
```Python hl_lines="16-20 29"
|
||||
{!> ../../../docs_src/dependencies/tutorial008b.py!}
|
||||
```
|
||||
|
||||
An alternative you could use to catch exceptions (and possibly also raise another `HTTPException`) is ot create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
|
||||
## Execution of dependencies with `yield`
|
||||
|
||||
The sequence of execution is more or less like this diagram. Time flows from top to bottom. And each column is one of the parts interacting or executing code.
|
||||
|
||||
@@ -161,34 +175,30 @@ participant dep as Dep with yield
|
||||
participant operation as Path Operation
|
||||
participant tasks as Background tasks
|
||||
|
||||
Note over client,tasks: Can raise exception for dependency, handled after response is sent
|
||||
Note over client,operation: Can raise HTTPException and can change the response
|
||||
Note over client,operation: Can raise exceptions, including HTTPException
|
||||
client ->> dep: Start request
|
||||
Note over dep: Run code up to yield
|
||||
opt raise
|
||||
dep -->> handler: Raise HTTPException
|
||||
opt raise Exception
|
||||
dep -->> handler: Raise Exception
|
||||
handler -->> client: HTTP error response
|
||||
dep -->> dep: Raise other exception
|
||||
end
|
||||
dep ->> operation: Run dependency, e.g. DB session
|
||||
opt raise
|
||||
operation -->> dep: Raise HTTPException
|
||||
dep -->> handler: Auto forward exception
|
||||
operation -->> dep: Raise Exception (e.g. HTTPException)
|
||||
opt handle
|
||||
dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception
|
||||
dep -->> handler: Auto forward exception
|
||||
end
|
||||
handler -->> client: HTTP error response
|
||||
operation -->> dep: Raise other exception
|
||||
dep -->> handler: Auto forward exception
|
||||
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 -->> dep: Raise other exception
|
||||
end
|
||||
Note over dep: After yield
|
||||
opt Handle other exception
|
||||
dep -->> dep: Handle exception, can't change response. E.g. close DB session.
|
||||
tasks -->> tasks: Handle exceptions in the background task code
|
||||
end
|
||||
```
|
||||
|
||||
@@ -198,10 +208,33 @@ participant tasks as Background tasks
|
||||
After one of those responses is sent, no other response can be sent.
|
||||
|
||||
!!! tip
|
||||
This diagram shows `HTTPException`, but you could also raise any other exception for which you create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
This diagram shows `HTTPException`, but you could also raise any other exception that you catch in a dependency with `yield` or with a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}.
|
||||
|
||||
If you raise any exception, it will be passed to the dependencies with yield, including `HTTPException`, and then **again** to the exception handlers. If there's no exception handler for that exception, it will then be handled by the default internal `ServerErrorMiddleware`, returning a 500 HTTP status code, to let the client know that there was an error in the server.
|
||||
|
||||
## Dependencies with `yield`, `HTTPException` and Background Tasks
|
||||
|
||||
!!! warning
|
||||
You most probably don't need these technical details, you can skip this section and continue below.
|
||||
|
||||
These details are useful mainly if you were using a version of FastAPI prior to 0.106.0 and used resources from dependencies with `yield` in background tasks.
|
||||
|
||||
Before FastAPI 0.106.0, raising exceptions after `yield` was not possible, the exit code in dependencies with `yield` was executed *after* the response was sent, so [Exception Handlers](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} would have already run.
|
||||
|
||||
This was designed this way mainly to allow using the same objects "yielded" by dependencies inside of background tasks, because the exit code would be executed after the background tasks were finished.
|
||||
|
||||
Nevertheless, as this would mean waiting for the response to travel through the network while unnecessarily holding a resource in a dependency with yield (for example a database connection), this was changed in FastAPI 0.106.0.
|
||||
|
||||
!!! tip
|
||||
|
||||
Additionally, a background task is normally an independent set of logic that should be handled separately, with its own resources (e.g. its own database connection).
|
||||
|
||||
So, this way you will probably have cleaner code.
|
||||
|
||||
If you used to rely on this behavior, now you should create the resources for background tasks inside the background task itself, and use internally only data that doesn't depend on the resources of dependencies with `yield`.
|
||||
|
||||
For example, instead of using the same database session, you would create a new database session inside of the background task, and you would obtain the objects from the database using this new session. And then instead of passing the object from the database as a parameter to the background task function, you would pass the ID of that object and then obtain the object again inside the background task function.
|
||||
|
||||
## Context Managers
|
||||
|
||||
### What are "Context Managers"
|
||||
@@ -220,7 +253,7 @@ Underneath, the `open("./somefile.txt")` creates an object that is a called a "C
|
||||
|
||||
When the `with` block finishes, it makes sure to close the file, even if there were exceptions.
|
||||
|
||||
When you create a dependency with `yield`, **FastAPI** will internally convert it to a context manager, and combine it with some other related tools.
|
||||
When you create a dependency with `yield`, **FastAPI** will internally create a context manager for it, and combine it with some other related tools.
|
||||
|
||||
### Using context managers in dependencies with `yield`
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ You can set the following fields that are used in the OpenAPI specification and
|
||||
| `version` | `string` | The version of the API. This is the version of your own application, not of OpenAPI. For example `2.5.0`. |
|
||||
| `terms_of_service` | `str` | A URL to the Terms of Service for the API. If provided, this has to be a URL. |
|
||||
| `contact` | `dict` | The contact information for the exposed API. It can contain several fields. <details><summary><code>contact</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>The identifying name of the contact person/organization.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>The URL pointing to the contact information. MUST be in the format of a URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>The email address of the contact person/organization. MUST be in the format of an email address.</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | The license information for the exposed API. It can contain several fields. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUIRED</strong> (if a <code>license_info</code> is set). The license name used for the API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>An <a href="https://spdx.dev/spdx-specification-21-web-version/#h.jxpfx0ykyb60" class="external-link" target="_blank">SPDX</a> license expression for the API. The <code>identifier</code> field is mutually exclusive of the <code>url</code> field. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL to the license used for the API. MUST be in the format of a URL.</td></tr></tbody></table></details> |
|
||||
| `license_info` | `dict` | The license information for the exposed API. It can contain several fields. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUIRED</strong> (if a <code>license_info</code> is set). The license name used for the API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>An <a href="https://spdx.org/licenses/" class="external-link" target="_blank">SPDX</a> license expression for the API. The <code>identifier</code> field is mutually exclusive of the <code>url</code> field. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL to the license used for the API. MUST be in the format of a URL.</td></tr></tbody></table></details> |
|
||||
|
||||
You can set them as follows:
|
||||
|
||||
|
||||
@@ -46,16 +46,18 @@ But if you go to the browser at <a href="http://127.0.0.1:8000/items/foo" class=
|
||||
|
||||
```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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -502,33 +502,8 @@ To do that, you can declare that `None` is a valid type but still use `...` as t
|
||||
!!! tip
|
||||
Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about <a href="https://pydantic-docs.helpmanual.io/usage/models/#required-optional-fields" class="external-link" target="_blank">Required Optional fields</a>.
|
||||
|
||||
### Use Pydantic's `Required` instead of Ellipsis (`...`)
|
||||
|
||||
If you feel uncomfortable using `...`, you can also import and use `Required` from Pydantic:
|
||||
|
||||
=== "Python 3.9+"
|
||||
|
||||
```Python hl_lines="4 10"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+"
|
||||
|
||||
```Python hl_lines="2 9"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.8+ non-Annotated"
|
||||
|
||||
!!! tip
|
||||
Prefer to use the `Annotated` version if possible.
|
||||
|
||||
```Python hl_lines="2 8"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial006d.py!}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...` nor `Required`.
|
||||
Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...`.
|
||||
|
||||
## Query parameter list / multiple values
|
||||
|
||||
@@ -762,7 +737,7 @@ And a `description`:
|
||||
!!! tip
|
||||
Prefer to use the `Annotated` version if possible.
|
||||
|
||||
```Python hl_lines="12"
|
||||
```Python hl_lines="11"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
|
||||
```
|
||||
|
||||
@@ -860,7 +835,7 @@ Then pass the parameter `deprecated=True` to `Query`:
|
||||
!!! tip
|
||||
Prefer to use the `Annotated` version if possible.
|
||||
|
||||
```Python hl_lines="17"
|
||||
```Python hl_lines="16"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -173,16 +173,18 @@ http://127.0.0.1:8000/items/foo-item
|
||||
|
||||
```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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -34,12 +34,6 @@
|
||||
<img class="sponsor-image" src="/img/sponsors/platform-sh-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Fern | SDKs and API docs" style="display: block; position: relative;" href="https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=top-banner" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/fern-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Deploy FastAPI on AWS with a few clicks" style="display: block; position: relative;" href="https://www.porter.run" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
@@ -52,6 +46,24 @@
|
||||
<img class="sponsor-image" src="/img/sponsors/bump-sh-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Reflex" style="display: block; position: relative;" href="https://reflex.dev" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/reflex-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files" style="display: block; position: relative;" href="https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=top-banner" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/scalar-banner.svg" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a title="Auth, user management and more for your B2B product" style="display: block; position: relative;" href="https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=topbanner" target="_blank">
|
||||
<span class="sponsor-badge">sponsor</span>
|
||||
<img class="sponsor-image" src="/img/sponsors/propelauth-banner.png" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -9,70 +9,21 @@ Voici une liste incomplète de certains d'entre eux.
|
||||
!!! tip "Astuce"
|
||||
Si vous avez un article, projet, outil, ou quoi que ce soit lié à **FastAPI** qui n'est actuellement pas listé ici, créez une <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">Pull Request l'ajoutant</a>.
|
||||
|
||||
## Articles
|
||||
{% for section_name, section_content in external_links.items() %}
|
||||
|
||||
### Anglais
|
||||
## {{ section_name }}
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
{% for lang_name, lang_content in section_content.items() %}
|
||||
|
||||
### {{ lang_name }}
|
||||
|
||||
{% for item in lang_content %}
|
||||
|
||||
* <a href="{{ item.link }}" class="external-link" target="_blank">{{ item.title }}</a> by <a href="{{ item.author_link }}" class="external-link" target="_blank">{{ item.author }}</a>.
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> par <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Japonais
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> par <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Vietnamien
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> par <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Russe
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> par <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Allemand
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> par <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Podcasts
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> par <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Conférences
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> par <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Projets
|
||||
|
||||
|
||||
@@ -84,24 +84,6 @@ Vous pouvez <a href="https://github.com/tiangolo/fastapi" class="external-link"
|
||||
* Pour corriger une Issue/Bug existant.
|
||||
* Pour ajouter une nouvelle fonctionnalité.
|
||||
|
||||
## Rejoindre le chat
|
||||
|
||||
<a href="https://gitter.im/tiangolo/fastapi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge" target="_blank">
|
||||
<img src="https://badges.gitter.im/tiangolo/fastapi.svg" alt="Rejoindre le chat à https://gitter.im/tiangolo/fastapi">
|
||||
</a>
|
||||
|
||||
Rejoignez le chat sur Gitter: <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">https://gitter.im/tiangolo/fastapi</a>.
|
||||
|
||||
Vous pouvez y avoir des conversations rapides avec d'autres personnes, aider les autres, partager des idées, etc.
|
||||
|
||||
Mais gardez à l'esprit que, comme il permet une "conversation plus libre", il est facile de poser des questions trop générales et plus difficiles à répondre, de sorte que vous risquez de ne pas recevoir de réponses.
|
||||
|
||||
Dans les Issues de GitHub, le modèle vous guidera pour écrire la bonne question afin que vous puissiez plus facilement obtenir une bonne réponse, ou même résoudre le problème vous-même avant même de le poser. Et dans GitHub, je peux m'assurer que je réponds toujours à tout, même si cela prend du temps. Je ne peux pas faire cela personnellement avec le chat Gitter. 😅
|
||||
|
||||
Les conversations dans Gitter ne sont pas non plus aussi facilement consultables que dans GitHub, de sorte que les questions et les réponses peuvent se perdre dans la conversation.
|
||||
|
||||
De l'autre côté, il y a plus de 1000 personnes dans le chat, il y a donc de fortes chances que vous y trouviez quelqu'un à qui parler, presque tout le temps. 😄
|
||||
|
||||
## Parrainer l'auteur
|
||||
|
||||
Vous pouvez également soutenir financièrement l'auteur (moi) via <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>.
|
||||
|
||||
@@ -9,70 +9,21 @@
|
||||
!!! tip "豆知識"
|
||||
ここにまだ載っていない**FastAPI**に関連する記事、プロジェクト、ツールなどがある場合は、 <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">プルリクエストして下さい</a>。
|
||||
|
||||
## 記事
|
||||
{% for section_name, section_content in external_links.items() %}
|
||||
|
||||
### 英語
|
||||
## {{ section_name }}
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
{% for lang_name, lang_content in section_content.items() %}
|
||||
|
||||
### {{ lang_name }}
|
||||
|
||||
{% for item in lang_content %}
|
||||
|
||||
* <a href="{{ item.link }}" class="external-link" target="_blank">{{ item.title }}</a> by <a href="{{ item.author_link }}" class="external-link" target="_blank">{{ item.author }}</a>.
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### 日本語
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### ベトナム語
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### ロシア語
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### ドイツ語
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## ポッドキャスト
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## トーク
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## プロジェクト
|
||||
|
||||
|
||||
@@ -82,20 +82,6 @@ GitHubレポジトリで<a href="https://github.com/tiangolo/fastapi/issues/new/
|
||||
* 既存のissue/バグを修正。
|
||||
* 新機能を追加。
|
||||
|
||||
## チャットに参加
|
||||
|
||||
Gitterでチャットに参加: <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">https://gitter.im/tiangolo/fastapi</a>.
|
||||
|
||||
そこで、他の人と手早く会話したり、手助けやアイデアの共有などができます。
|
||||
|
||||
しかし、「自由な会話」が許容されているので一般的すぎて回答が難しい質問もしやすくなります。そのせいで回答を得られないかもしれません。
|
||||
|
||||
GitHub issuesでは良い回答を得やすい質問ができるように、もしくは、質問する前に自身で解決できるようにテンプレートがガイドしてくれます。そして、GitHubではたとえ時間がかかっても全てに答えているか確認できます。個人的にはGitterチャットでは同じことはできないです。😅
|
||||
|
||||
Gitterでの会話はGitHubほど簡単に検索できないので、質問と回答が会話の中に埋もれてしまいます。
|
||||
|
||||
一方、チャットには1000人以上いるので、いつでも話し相手が見つかる可能性が高いです。😄
|
||||
|
||||
## 開発者のスポンサーになる
|
||||
|
||||
<a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">GitHub sponsors</a>を通して開発者を経済的にサポートできます。
|
||||
|
||||
@@ -231,8 +231,6 @@ Dołącz do 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" t
|
||||
|
||||
Używaj czatu tylko do innych ogólnych rozmów.
|
||||
|
||||
Istnieje również poprzedni <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">czat na Gitter</a>, ale ponieważ nie ma tam kanałów i zaawansowanych funkcji, rozmowy są trudniejsze, dlatego teraz zalecany jest Discord.
|
||||
|
||||
### Nie zadawaj pytań na czacie
|
||||
|
||||
Miej na uwadze, że ponieważ czaty pozwalają na bardziej "swobodną rozmowę", łatwo jest zadawać pytania, które są zbyt ogólne i trudniejsze do odpowiedzi, więc możesz nie otrzymać odpowiedzi.
|
||||
|
||||
@@ -9,70 +9,21 @@ Aqui tem uma lista, incompleta, de algumas delas.
|
||||
!!! tip "Dica"
|
||||
Se você tem um artigo, projeto, ferramenta ou qualquer coisa relacionada ao **FastAPI** que ainda não está listada aqui, crie um <a href="https://github.com/tiangolo/fastapi/edit/master/docs/external-links.md" class="external-link" target="_blank">_Pull Request_ adicionando ele</a>.
|
||||
|
||||
## Artigos
|
||||
{% for section_name, section_content in external_links.items() %}
|
||||
|
||||
### Inglês
|
||||
## {{ section_name }}
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
{% for lang_name, lang_content in section_content.items() %}
|
||||
|
||||
### {{ lang_name }}
|
||||
|
||||
{% for item in lang_content %}
|
||||
|
||||
* <a href="{{ item.link }}" class="external-link" target="_blank">{{ item.title }}</a> by <a href="{{ item.author_link }}" class="external-link" target="_blank">{{ item.author }}</a>.
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Japonês
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Vietnamita
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Russo
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Alemão
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Podcasts
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Palestras
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Projetos
|
||||
|
||||
|
||||
@@ -114,8 +114,6 @@ do FastAPI.
|
||||
|
||||
Use o chat apenas para outro tipo de assunto.
|
||||
|
||||
Também existe o <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">chat do Gitter</a>, porém ele não possuí canais e recursos avançados, conversas são mais engessadas, por isso o Discord é mais recomendado.
|
||||
|
||||
### Não faça perguntas no chat
|
||||
|
||||
Tenha em mente que os chats permitem uma "conversa mais livre", dessa forma é muito fácil fazer perguntas que são muito genéricas e dificeís de responder, assim você pode acabar não sendo respondido.
|
||||
|
||||
@@ -9,70 +9,21 @@
|
||||
!!! tip
|
||||
Если у вас есть статья, проект, инструмент или что-либо, связанное с **FastAPI**, что еще не перечислено здесь, создайте <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">Pull Request</a>.
|
||||
|
||||
## Статьи
|
||||
{% for section_name, section_content in external_links.items() %}
|
||||
|
||||
### На английском
|
||||
## {{ section_name }}
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.english %}
|
||||
{% for lang_name, lang_content in section_content.items() %}
|
||||
|
||||
### {{ lang_name }}
|
||||
|
||||
{% for item in lang_content %}
|
||||
|
||||
* <a href="{{ item.link }}" class="external-link" target="_blank">{{ item.title }}</a> by <a href="{{ item.author_link }}" class="external-link" target="_blank">{{ item.author }}</a>.
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### На японском
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.japanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### На вьетнамском
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.vietnamese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### На русском
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.russian %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### На немецком
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.german %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Подкасты
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.podcasts.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Talks
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.talks.english %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Проекты
|
||||
|
||||
|
||||
@@ -223,8 +223,6 @@
|
||||
|
||||
Используйте этот чат только для бесед на отвлечённые темы.
|
||||
|
||||
Существует также <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">чат в Gitter</a>, но поскольку в нем нет каналов и расширенных функций, общение в нём сложнее, потому рекомендуемой системой является Discord.
|
||||
|
||||
### Не использовать чаты для вопросов
|
||||
|
||||
Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
|
||||
|
||||
@@ -741,7 +741,7 @@ http://localhost:8000/items/
|
||||
!!! tip "Подсказка"
|
||||
Рекомендуется использовать версию с `Annotated` если возможно.
|
||||
|
||||
```Python hl_lines="12"
|
||||
```Python hl_lines="11"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!}
|
||||
```
|
||||
|
||||
@@ -839,7 +839,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
!!! tip "Подсказка"
|
||||
Рекомендуется использовать версию с `Annotated` если возможно.
|
||||
|
||||
```Python hl_lines="17"
|
||||
```Python hl_lines="16"
|
||||
{!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app
|
||||
```
|
||||
|
||||
!!! tip
|
||||
我们稍后会讨论 `@lru_cache()`。
|
||||
我们稍后会讨论 `@lru_cache`。
|
||||
|
||||
目前,您可以将 `get_settings()` 视为普通函数。
|
||||
|
||||
@@ -289,7 +289,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app
|
||||
|
||||
但是,dotenv 文件实际上不一定要具有确切的文件名。
|
||||
|
||||
Pydantic 支持使用外部库从这些类型的文件中读取。您可以在<a href="https://pydantic-docs.helpmanual.io/usage/settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic 设置: Dotenv (.env) 支持</a>中阅读更多相关信息。
|
||||
Pydantic 支持使用外部库从这些类型的文件中读取。您可以在<a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support" class="external-link" target="_blank">Pydantic 设置: Dotenv (.env) 支持</a>中阅读更多相关信息。
|
||||
|
||||
!!! tip
|
||||
要使其工作,您需要执行 `pip install python-dotenv`。
|
||||
@@ -337,7 +337,7 @@ def get_settings():
|
||||
|
||||
我们将为每个请求创建该对象,并且将在每个请求中读取 `.env` 文件。 ⚠️
|
||||
|
||||
但是,由于我们在顶部使用了 `@lru_cache()` 装饰器,因此只有在第一次调用它时,才会创建 `Settings` 对象一次。 ✔️
|
||||
但是,由于我们在顶部使用了 `@lru_cache` 装饰器,因此只有在第一次调用它时,才会创建 `Settings` 对象一次。 ✔️
|
||||
|
||||
=== "Python 3.9+"
|
||||
|
||||
@@ -364,13 +364,13 @@ def get_settings():
|
||||
|
||||
#### `lru_cache` 技术细节
|
||||
|
||||
`@lru_cache()` 修改了它所装饰的函数,以返回第一次返回的相同值,而不是再次计算它,每次都执行函数的代码。
|
||||
`@lru_cache` 修改了它所装饰的函数,以返回第一次返回的相同值,而不是再次计算它,每次都执行函数的代码。
|
||||
|
||||
因此,下面的函数将对每个参数组合执行一次。然后,每个参数组合返回的值将在使用完全相同的参数组合调用函数时再次使用。
|
||||
|
||||
例如,如果您有一个函数:
|
||||
```Python
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def say_hi(name: str, salutation: str = "Ms."):
|
||||
return f"Hello {salutation} {name}"
|
||||
```
|
||||
@@ -422,7 +422,7 @@ participant execute as Execute function
|
||||
|
||||
这样,它的行为几乎就像是一个全局变量。但是由于它使用了依赖项函数,因此我们可以轻松地进行测试时的覆盖。
|
||||
|
||||
`@lru_cache()` 是 `functools` 的一部分,它是 Python 标准库的一部分,您可以在<a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python 文档中了解有关 `@lru_cache()` 的更多信息</a>。
|
||||
`@lru_cache` 是 `functools` 的一部分,它是 Python 标准库的一部分,您可以在<a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">Python 文档中了解有关 `@lru_cache` 的更多信息</a>。
|
||||
|
||||
## 小结
|
||||
|
||||
@@ -430,4 +430,4 @@ participant execute as Execute function
|
||||
|
||||
* 通过使用依赖项,您可以简化测试。
|
||||
* 您可以使用 `.env` 文件。
|
||||
* 使用 `@lru_cache()` 可以避免为每个请求重复读取 dotenv 文件,同时允许您在测试时进行覆盖。
|
||||
* 使用 `@lru_cache` 可以避免为每个请求重复读取 dotenv 文件,同时允许您在测试时进行覆盖。
|
||||
|
||||
@@ -409,11 +409,11 @@ Starlette (和 **FastAPI**) 是基于 <a href="https://anyio.readthedocs.io/
|
||||
|
||||
### 依赖
|
||||
|
||||
这同样适用于[依赖](/tutorial/dependencies/index.md){.internal-link target=_blank}。如果一个依赖是标准的 `def` 函数而不是 `async def`,它将被运行在外部线程池中。
|
||||
这同样适用于[依赖](./tutorial/dependencies/index.md){.internal-link target=_blank}。如果一个依赖是标准的 `def` 函数而不是 `async def`,它将被运行在外部线程池中。
|
||||
|
||||
### 子依赖
|
||||
|
||||
你可以拥有多个相互依赖的依赖以及[子依赖](/tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (作为函数的参数),它们中的一些可能是通过 `async def` 声明,也可能是通过 `def` 声明。它们仍然可以正常工作,这些通过 `def` 声明的函数将会在外部线程中调用(来自线程池),而不是"被等待"。
|
||||
你可以拥有多个相互依赖的依赖以及[子依赖](./tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} (作为函数的参数),它们中的一些可能是通过 `async def` 声明,也可能是通过 `def` 声明。它们仍然可以正常工作,这些通过 `def` 声明的函数将会在外部线程中调用(来自线程池),而不是"被等待"。
|
||||
|
||||
### 其他函数
|
||||
|
||||
|
||||
@@ -114,8 +114,6 @@
|
||||
|
||||
聊天室仅供闲聊。
|
||||
|
||||
我们之前还使用过 <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">Gitter chat</a>,但它不支持频道等高级功能,聊天也比较麻烦,所以现在推荐使用 Discord。
|
||||
|
||||
### 别在聊天室里提问
|
||||
|
||||
注意,聊天室更倾向于“闲聊”,经常有人会提出一些笼统得让人难以回答的问题,所以在这里提问一般没人回答。
|
||||
|
||||
@@ -14,8 +14,8 @@ async def custom_swagger_ui_html():
|
||||
openapi_url=app.openapi_url,
|
||||
title=app.title + " - Swagger UI",
|
||||
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
|
||||
swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",
|
||||
swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",
|
||||
swagger_js_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js",
|
||||
swagger_css_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css",
|
||||
)
|
||||
|
||||
|
||||
|
||||
30
docs_src/dependencies/tutorial008b.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
data = {
|
||||
"plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
|
||||
"portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
|
||||
}
|
||||
|
||||
|
||||
class OwnerError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except OwnerError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Onwer error: {e}")
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: str = Depends(get_username)):
|
||||
if item_id not in data:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
item = data[item_id]
|
||||
if item["owner"] != username:
|
||||
raise OwnerError(username)
|
||||
return item
|
||||
31
docs_src/dependencies/tutorial008b_an.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
from typing_extensions import Annotated
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
data = {
|
||||
"plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
|
||||
"portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
|
||||
}
|
||||
|
||||
|
||||
class OwnerError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except OwnerError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Onwer error: {e}")
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
|
||||
if item_id not in data:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
item = data[item_id]
|
||||
if item["owner"] != username:
|
||||
raise OwnerError(username)
|
||||
return item
|
||||
32
docs_src/dependencies/tutorial008b_an_py39.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
data = {
|
||||
"plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"},
|
||||
"portal-gun": {"description": "Gun to create portals", "owner": "Rick"},
|
||||
}
|
||||
|
||||
|
||||
class OwnerError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
except OwnerError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Onwer error: {e}")
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
|
||||
if item_id not in data:
|
||||
raise HTTPException(status_code=404, detail="Item not found")
|
||||
item = data[item_id]
|
||||
if item["owner"] != username:
|
||||
raise OwnerError(username)
|
||||
return item
|
||||
@@ -10,6 +10,6 @@ app = FastAPI()
|
||||
async def read_items(
|
||||
strange_header: Annotated[
|
||||
Union[str, None], Header(convert_underscores=False)
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
return {"strange_header": strange_header}
|
||||
|
||||
@@ -9,6 +9,6 @@ app = FastAPI()
|
||||
async def read_items(
|
||||
strange_header: Annotated[
|
||||
Union[str, None], Header(convert_underscores=False)
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
return {"strange_header": strange_header}
|
||||
|
||||
@@ -8,7 +8,7 @@ app = FastAPI()
|
||||
|
||||
class Subscription(BaseModel):
|
||||
username: str
|
||||
montly_fee: float
|
||||
monthly_fee: float
|
||||
start_date: datetime
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ app = FastAPI()
|
||||
async def read_items(
|
||||
q: Union[str, None] = Query(
|
||||
default=None, min_length=3, max_length=50, pattern="^fixedquery$"
|
||||
)
|
||||
),
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -10,7 +10,7 @@ app = FastAPI()
|
||||
async def read_items(
|
||||
q: Annotated[
|
||||
Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$")
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -9,7 +9,7 @@ app = FastAPI()
|
||||
async def read_items(
|
||||
q: Annotated[
|
||||
str | None, Query(min_length=3, max_length=50, pattern="^fixedquery$")
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -9,7 +9,7 @@ app = FastAPI()
|
||||
async def read_items(
|
||||
q: Annotated[
|
||||
str | None, Query(min_length=3, max_length=50, regex="^fixedquery$")
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -9,7 +9,7 @@ app = FastAPI()
|
||||
async def read_items(
|
||||
q: Annotated[
|
||||
Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$")
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -5,8 +5,9 @@ app = FastAPI()
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(
|
||||
q: str
|
||||
| None = Query(default=None, min_length=3, max_length=50, pattern="^fixedquery$")
|
||||
q: str | None = Query(
|
||||
default=None, min_length=3, max_length=50, pattern="^fixedquery$"
|
||||
),
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -12,7 +12,7 @@ async def read_items(
|
||||
title="Query string",
|
||||
description="Query string for the items to search in the database that have a good match",
|
||||
min_length=3,
|
||||
)
|
||||
),
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -15,7 +15,7 @@ async def read_items(
|
||||
description="Query string for the items to search in the database that have a good match",
|
||||
min_length=3,
|
||||
),
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -14,7 +14,7 @@ async def read_items(
|
||||
description="Query string for the items to search in the database that have a good match",
|
||||
min_length=3,
|
||||
),
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -14,7 +14,7 @@ async def read_items(
|
||||
description="Query string for the items to search in the database that have a good match",
|
||||
min_length=3,
|
||||
),
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -5,13 +5,12 @@ app = FastAPI()
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(
|
||||
q: str
|
||||
| None = Query(
|
||||
q: str | None = Query(
|
||||
default=None,
|
||||
title="Query string",
|
||||
description="Query string for the items to search in the database that have a good match",
|
||||
min_length=3,
|
||||
)
|
||||
),
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -16,7 +16,7 @@ async def read_items(
|
||||
max_length=50,
|
||||
pattern="^fixedquery$",
|
||||
deprecated=True,
|
||||
)
|
||||
),
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -19,7 +19,7 @@ async def read_items(
|
||||
pattern="^fixedquery$",
|
||||
deprecated=True,
|
||||
),
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -18,7 +18,7 @@ async def read_items(
|
||||
pattern="^fixedquery$",
|
||||
deprecated=True,
|
||||
),
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -18,7 +18,7 @@ async def read_items(
|
||||
pattern="^fixedquery$",
|
||||
deprecated=True,
|
||||
),
|
||||
] = None
|
||||
] = None,
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -5,8 +5,7 @@ app = FastAPI()
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(
|
||||
q: str
|
||||
| None = Query(
|
||||
q: str | None = Query(
|
||||
default=None,
|
||||
alias="item-query",
|
||||
title="Query string",
|
||||
@@ -15,7 +14,7 @@ async def read_items(
|
||||
max_length=50,
|
||||
pattern="^fixedquery$",
|
||||
deprecated=True,
|
||||
)
|
||||
),
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
@@ -7,7 +7,7 @@ from .config import Settings
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
return Settings()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from .config import Settings
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
return Settings()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from .config import Settings
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
return Settings()
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from . import config
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
return config.Settings()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from . import config
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
return config.Settings()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from . import config
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@lru_cache()
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
return config.Settings()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.104.0"
|
||||
__version__ = "0.106.0"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -197,9 +197,9 @@ if PYDANTIC_V2:
|
||||
if "$ref" not in json_schema:
|
||||
# TODO remove when deprecating Pydantic v1
|
||||
# Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207
|
||||
json_schema[
|
||||
"title"
|
||||
] = field.field_info.title or field.alias.title().replace("_", " ")
|
||||
json_schema["title"] = (
|
||||
field.field_info.title or field.alias.title().replace("_", " ")
|
||||
)
|
||||
return json_schema
|
||||
|
||||
def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
|
||||
@@ -249,7 +249,12 @@ if PYDANTIC_V2:
|
||||
return is_bytes_sequence_annotation(field.type_)
|
||||
|
||||
def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
|
||||
return type(field_info).from_annotation(annotation)
|
||||
cls = type(field_info)
|
||||
merged_field_info = cls.from_annotation(annotation)
|
||||
new_field_info = copy(field_info)
|
||||
new_field_info.metadata = merged_field_info.metadata
|
||||
new_field_info.annotation = merged_field_info.annotation
|
||||
return new_field_info
|
||||
|
||||
def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
|
||||
origin_type = (
|
||||
|
||||
@@ -22,7 +22,6 @@ from fastapi.exception_handlers import (
|
||||
)
|
||||
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
|
||||
from fastapi.logger import logger
|
||||
from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware
|
||||
from fastapi.openapi.docs import (
|
||||
get_redoc_html,
|
||||
get_swagger_ui_html,
|
||||
@@ -37,8 +36,6 @@ from starlette.datastructures import State
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.middleware import Middleware
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.middleware.errors import ServerErrorMiddleware
|
||||
from starlette.middleware.exceptions import ExceptionMiddleware
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import HTMLResponse, JSONResponse, Response
|
||||
from starlette.routing import BaseRoute
|
||||
@@ -86,13 +83,6 @@ class FastAPI(Starlette):
|
||||
**Note**: you probably shouldn't use this parameter, it is inherited
|
||||
from Starlette and supported for compatibility.
|
||||
|
||||
In FastAPI, you normally would use the *path operation* decorators,
|
||||
like:
|
||||
|
||||
* `app.get()`
|
||||
* `app.post()`
|
||||
* etc.
|
||||
|
||||
---
|
||||
|
||||
A list of routes to serve incoming HTTP and WebSocket requests.
|
||||
@@ -903,9 +893,7 @@ class FastAPI(Starlette):
|
||||
[FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/).
|
||||
"""
|
||||
),
|
||||
] = (
|
||||
webhooks or routing.APIRouter()
|
||||
)
|
||||
] = webhooks or routing.APIRouter()
|
||||
self.root_path = root_path or openapi_prefix
|
||||
self.state: Annotated[
|
||||
State,
|
||||
@@ -958,7 +946,7 @@ class FastAPI(Starlette):
|
||||
)
|
||||
self.exception_handlers: Dict[
|
||||
Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]]
|
||||
] = ({} if exception_handlers is None else dict(exception_handlers))
|
||||
] = {} if exception_handlers is None else dict(exception_handlers)
|
||||
self.exception_handlers.setdefault(HTTPException, http_exception_handler)
|
||||
self.exception_handlers.setdefault(
|
||||
RequestValidationError, request_validation_exception_handler
|
||||
@@ -975,55 +963,6 @@ class FastAPI(Starlette):
|
||||
self.middleware_stack: Union[ASGIApp, None] = None
|
||||
self.setup()
|
||||
|
||||
def build_middleware_stack(self) -> ASGIApp:
|
||||
# Duplicate/override from Starlette to add AsyncExitStackMiddleware
|
||||
# inside of ExceptionMiddleware, inside of custom user middlewares
|
||||
debug = self.debug
|
||||
error_handler = None
|
||||
exception_handlers = {}
|
||||
|
||||
for key, value in self.exception_handlers.items():
|
||||
if key in (500, Exception):
|
||||
error_handler = value
|
||||
else:
|
||||
exception_handlers[key] = value
|
||||
|
||||
middleware = (
|
||||
[Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)]
|
||||
+ self.user_middleware
|
||||
+ [
|
||||
Middleware(
|
||||
ExceptionMiddleware, handlers=exception_handlers, debug=debug
|
||||
),
|
||||
# Add FastAPI-specific AsyncExitStackMiddleware for dependencies with
|
||||
# contextvars.
|
||||
# This needs to happen after user middlewares because those create a
|
||||
# new contextvars context copy by using a new AnyIO task group.
|
||||
# The initial part of dependencies with 'yield' is executed in the
|
||||
# FastAPI code, inside all the middlewares. However, the teardown part
|
||||
# (after 'yield') is executed in the AsyncExitStack in this middleware.
|
||||
# If the AsyncExitStack lived outside of the custom middlewares and
|
||||
# contextvars were set in a dependency with 'yield' in that internal
|
||||
# contextvars context, the values would not be available in the
|
||||
# outer context of the AsyncExitStack.
|
||||
# By placing the middleware and the AsyncExitStack here, inside all
|
||||
# user middlewares, the code before and after 'yield' in dependencies
|
||||
# with 'yield' is executed in the same contextvars context. Thus, all values
|
||||
# set in contextvars before 'yield' are still available after 'yield,' as
|
||||
# expected.
|
||||
# Additionally, by having this AsyncExitStack here, after the
|
||||
# ExceptionMiddleware, dependencies can now catch handled exceptions,
|
||||
# e.g. HTTPException, to customize the teardown code (e.g. DB session
|
||||
# rollback).
|
||||
Middleware(AsyncExitStackMiddleware),
|
||||
]
|
||||
)
|
||||
|
||||
app = self.router
|
||||
for cls, options in reversed(middleware):
|
||||
app = cls(app=app, **options)
|
||||
return app
|
||||
|
||||
def openapi(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate the OpenAPI schema of the application. This is called by FastAPI
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from contextlib import AsyncExitStack as AsyncExitStack # noqa
|
||||
from contextlib import asynccontextmanager as asynccontextmanager
|
||||
from typing import AsyncGenerator, ContextManager, TypeVar
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import inspect
|
||||
from contextlib import contextmanager
|
||||
from contextlib import AsyncExitStack, contextmanager
|
||||
from copy import deepcopy
|
||||
from typing import (
|
||||
Any,
|
||||
@@ -46,7 +46,6 @@ from fastapi._compat import (
|
||||
)
|
||||
from fastapi.background import BackgroundTasks
|
||||
from fastapi.concurrency import (
|
||||
AsyncExitStack,
|
||||
asynccontextmanager,
|
||||
contextmanager_in_threadpool,
|
||||
)
|
||||
@@ -325,10 +324,11 @@ def analyze_param(
|
||||
field_info = None
|
||||
depends = None
|
||||
type_annotation: Any = Any
|
||||
if (
|
||||
annotation is not inspect.Signature.empty
|
||||
and get_origin(annotation) is Annotated
|
||||
):
|
||||
use_annotation: Any = Any
|
||||
if annotation is not inspect.Signature.empty:
|
||||
use_annotation = annotation
|
||||
type_annotation = annotation
|
||||
if get_origin(use_annotation) is Annotated:
|
||||
annotated_args = get_args(annotation)
|
||||
type_annotation = annotated_args[0]
|
||||
fastapi_annotations = [
|
||||
@@ -336,14 +336,21 @@ def analyze_param(
|
||||
for arg in annotated_args[1:]
|
||||
if isinstance(arg, (FieldInfo, params.Depends))
|
||||
]
|
||||
assert (
|
||||
len(fastapi_annotations) <= 1
|
||||
), f"Cannot specify multiple `Annotated` FastAPI arguments for {param_name!r}"
|
||||
fastapi_annotation = next(iter(fastapi_annotations), None)
|
||||
fastapi_specific_annotations = [
|
||||
arg
|
||||
for arg in fastapi_annotations
|
||||
if isinstance(arg, (params.Param, params.Body, params.Depends))
|
||||
]
|
||||
if fastapi_specific_annotations:
|
||||
fastapi_annotation: Union[
|
||||
FieldInfo, params.Depends, None
|
||||
] = fastapi_specific_annotations[-1]
|
||||
else:
|
||||
fastapi_annotation = None
|
||||
if isinstance(fastapi_annotation, FieldInfo):
|
||||
# Copy `field_info` because we mutate `field_info.default` below.
|
||||
field_info = copy_field_info(
|
||||
field_info=fastapi_annotation, annotation=annotation
|
||||
field_info=fastapi_annotation, annotation=use_annotation
|
||||
)
|
||||
assert field_info.default is Undefined or field_info.default is Required, (
|
||||
f"`{field_info.__class__.__name__}` default value cannot be set in"
|
||||
@@ -356,8 +363,6 @@ def analyze_param(
|
||||
field_info.default = Required
|
||||
elif isinstance(fastapi_annotation, params.Depends):
|
||||
depends = fastapi_annotation
|
||||
elif annotation is not inspect.Signature.empty:
|
||||
type_annotation = annotation
|
||||
|
||||
if isinstance(value, params.Depends):
|
||||
assert depends is None, (
|
||||
@@ -402,15 +407,15 @@ def analyze_param(
|
||||
# We might check here that `default_value is Required`, but the fact is that the same
|
||||
# parameter might sometimes be a path parameter and sometimes not. See
|
||||
# `tests/test_infer_param_optionality.py` for an example.
|
||||
field_info = params.Path(annotation=type_annotation)
|
||||
field_info = params.Path(annotation=use_annotation)
|
||||
elif is_uploadfile_or_nonable_uploadfile_annotation(
|
||||
type_annotation
|
||||
) or is_uploadfile_sequence_annotation(type_annotation):
|
||||
field_info = params.File(annotation=type_annotation, default=default_value)
|
||||
field_info = params.File(annotation=use_annotation, default=default_value)
|
||||
elif not field_annotation_is_scalar(annotation=type_annotation):
|
||||
field_info = params.Body(annotation=type_annotation, default=default_value)
|
||||
field_info = params.Body(annotation=use_annotation, default=default_value)
|
||||
else:
|
||||
field_info = params.Query(annotation=type_annotation, default=default_value)
|
||||
field_info = params.Query(annotation=use_annotation, default=default_value)
|
||||
|
||||
field = None
|
||||
if field_info is not None:
|
||||
@@ -424,8 +429,8 @@ def analyze_param(
|
||||
and getattr(field_info, "in_", None) is None
|
||||
):
|
||||
field_info.in_ = params.ParamTypes.query
|
||||
use_annotation = get_annotation_from_field_info(
|
||||
type_annotation,
|
||||
use_annotation_from_field_info = get_annotation_from_field_info(
|
||||
use_annotation,
|
||||
field_info,
|
||||
param_name,
|
||||
)
|
||||
@@ -436,7 +441,7 @@ def analyze_param(
|
||||
field_info.alias = alias
|
||||
field = create_response_field(
|
||||
name=param_name,
|
||||
type_=use_annotation,
|
||||
type_=use_annotation_from_field_info,
|
||||
default=field_info.default,
|
||||
alias=alias,
|
||||
required=field_info.default in (Required, Undefined),
|
||||
@@ -466,16 +471,17 @@ def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool:
|
||||
|
||||
|
||||
def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
|
||||
field_info = cast(params.Param, field.field_info)
|
||||
if field_info.in_ == params.ParamTypes.path:
|
||||
field_info = field.field_info
|
||||
field_info_in = getattr(field_info, "in_", None)
|
||||
if field_info_in == params.ParamTypes.path:
|
||||
dependant.path_params.append(field)
|
||||
elif field_info.in_ == params.ParamTypes.query:
|
||||
elif field_info_in == params.ParamTypes.query:
|
||||
dependant.query_params.append(field)
|
||||
elif field_info.in_ == params.ParamTypes.header:
|
||||
elif field_info_in == params.ParamTypes.header:
|
||||
dependant.header_params.append(field)
|
||||
else:
|
||||
assert (
|
||||
field_info.in_ == params.ParamTypes.cookie
|
||||
field_info_in == params.ParamTypes.cookie
|
||||
), f"non-body parameters must be in path, query, header or cookie: {field.name}"
|
||||
dependant.cookie_params.append(field)
|
||||
|
||||
@@ -522,6 +528,7 @@ async def solve_dependencies(
|
||||
response: Optional[Response] = None,
|
||||
dependency_overrides_provider: Optional[Any] = None,
|
||||
dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
|
||||
async_exit_stack: AsyncExitStack,
|
||||
) -> Tuple[
|
||||
Dict[str, Any],
|
||||
List[Any],
|
||||
@@ -568,6 +575,7 @@ async def solve_dependencies(
|
||||
response=response,
|
||||
dependency_overrides_provider=dependency_overrides_provider,
|
||||
dependency_cache=dependency_cache,
|
||||
async_exit_stack=async_exit_stack,
|
||||
)
|
||||
(
|
||||
sub_values,
|
||||
@@ -583,10 +591,8 @@ async def solve_dependencies(
|
||||
if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
|
||||
solved = dependency_cache[sub_dependant.cache_key]
|
||||
elif is_gen_callable(call) or is_async_gen_callable(call):
|
||||
stack = request.scope.get("fastapi_astack")
|
||||
assert isinstance(stack, AsyncExitStack)
|
||||
solved = await solve_generator(
|
||||
call=call, stack=stack, sub_values=sub_values
|
||||
call=call, stack=async_exit_stack, sub_values=sub_values
|
||||
)
|
||||
elif is_coroutine_callable(call):
|
||||
solved = await call(**sub_values)
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi.concurrency import AsyncExitStack
|
||||
from starlette.types import ASGIApp, Receive, Scope, Send
|
||||
|
||||
|
||||
class AsyncExitStackMiddleware:
|
||||
def __init__(self, app: ASGIApp, context_name: str = "fastapi_astack") -> None:
|
||||
self.app = app
|
||||
self.context_name = context_name
|
||||
|
||||
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
||||
dependency_exception: Optional[Exception] = None
|
||||
async with AsyncExitStack() as stack:
|
||||
scope[self.context_name] = stack
|
||||
try:
|
||||
await self.app(scope, receive, send)
|
||||
except Exception as e:
|
||||
dependency_exception = e
|
||||
raise e
|
||||
if dependency_exception:
|
||||
# This exception was possibly handled by the dependency but it should
|
||||
# still bubble up so that the ServerErrorMiddleware can return a 500
|
||||
# or the ExceptionMiddleware can catch and handle any other exceptions
|
||||
raise dependency_exception
|
||||
@@ -53,7 +53,7 @@ def get_swagger_ui_html(
|
||||
It is normally set to a CDN URL.
|
||||
"""
|
||||
),
|
||||
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
|
||||
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js",
|
||||
swagger_css_url: Annotated[
|
||||
str,
|
||||
Doc(
|
||||
@@ -63,7 +63,7 @@ def get_swagger_ui_html(
|
||||
It is normally set to a CDN URL.
|
||||
"""
|
||||
),
|
||||
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
|
||||
] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css",
|
||||
swagger_favicon_url: Annotated[
|
||||
str,
|
||||
Doc(
|
||||
|
||||
@@ -216,95 +216,124 @@ def get_request_handler(
|
||||
actual_response_class = response_class
|
||||
|
||||
async def app(request: Request) -> Response:
|
||||
try:
|
||||
body: Any = None
|
||||
if body_field:
|
||||
if is_body_form:
|
||||
body = await request.form()
|
||||
stack = request.scope.get("fastapi_astack")
|
||||
assert isinstance(stack, AsyncExitStack)
|
||||
stack.push_async_callback(body.close)
|
||||
exception_to_reraise: Optional[Exception] = None
|
||||
response: Union[Response, None] = None
|
||||
async with AsyncExitStack() as async_exit_stack:
|
||||
# TODO: remove this scope later, after a few releases
|
||||
# This scope fastapi_astack is no longer used by FastAPI, kept for
|
||||
# compatibility, just in case
|
||||
request.scope["fastapi_astack"] = async_exit_stack
|
||||
try:
|
||||
body: Any = None
|
||||
if body_field:
|
||||
if is_body_form:
|
||||
body = await request.form()
|
||||
async_exit_stack.push_async_callback(body.close)
|
||||
else:
|
||||
body_bytes = await request.body()
|
||||
if body_bytes:
|
||||
json_body: Any = Undefined
|
||||
content_type_value = request.headers.get("content-type")
|
||||
if not content_type_value:
|
||||
json_body = await request.json()
|
||||
else:
|
||||
message = email.message.Message()
|
||||
message["content-type"] = content_type_value
|
||||
if message.get_content_maintype() == "application":
|
||||
subtype = message.get_content_subtype()
|
||||
if subtype == "json" or subtype.endswith("+json"):
|
||||
json_body = await request.json()
|
||||
if json_body != Undefined:
|
||||
body = json_body
|
||||
else:
|
||||
body = body_bytes
|
||||
except json.JSONDecodeError as e:
|
||||
validation_error = RequestValidationError(
|
||||
[
|
||||
{
|
||||
"type": "json_invalid",
|
||||
"loc": ("body", e.pos),
|
||||
"msg": "JSON decode error",
|
||||
"input": {},
|
||||
"ctx": {"error": e.msg},
|
||||
}
|
||||
],
|
||||
body=e.doc,
|
||||
)
|
||||
exception_to_reraise = validation_error
|
||||
raise validation_error from e
|
||||
except HTTPException as e:
|
||||
exception_to_reraise = e
|
||||
raise
|
||||
except Exception as e:
|
||||
http_error = HTTPException(
|
||||
status_code=400, detail="There was an error parsing the body"
|
||||
)
|
||||
exception_to_reraise = http_error
|
||||
raise http_error from e
|
||||
try:
|
||||
solved_result = await solve_dependencies(
|
||||
request=request,
|
||||
dependant=dependant,
|
||||
body=body,
|
||||
dependency_overrides_provider=dependency_overrides_provider,
|
||||
async_exit_stack=async_exit_stack,
|
||||
)
|
||||
values, errors, background_tasks, sub_response, _ = solved_result
|
||||
except Exception as e:
|
||||
exception_to_reraise = e
|
||||
raise e
|
||||
if errors:
|
||||
validation_error = RequestValidationError(
|
||||
_normalize_errors(errors), body=body
|
||||
)
|
||||
exception_to_reraise = validation_error
|
||||
raise validation_error
|
||||
else:
|
||||
try:
|
||||
raw_response = await run_endpoint_function(
|
||||
dependant=dependant, values=values, is_coroutine=is_coroutine
|
||||
)
|
||||
except Exception as e:
|
||||
exception_to_reraise = e
|
||||
raise e
|
||||
if isinstance(raw_response, Response):
|
||||
if raw_response.background is None:
|
||||
raw_response.background = background_tasks
|
||||
response = raw_response
|
||||
else:
|
||||
body_bytes = await request.body()
|
||||
if body_bytes:
|
||||
json_body: Any = Undefined
|
||||
content_type_value = request.headers.get("content-type")
|
||||
if not content_type_value:
|
||||
json_body = await request.json()
|
||||
else:
|
||||
message = email.message.Message()
|
||||
message["content-type"] = content_type_value
|
||||
if message.get_content_maintype() == "application":
|
||||
subtype = message.get_content_subtype()
|
||||
if subtype == "json" or subtype.endswith("+json"):
|
||||
json_body = await request.json()
|
||||
if json_body != Undefined:
|
||||
body = json_body
|
||||
else:
|
||||
body = body_bytes
|
||||
except json.JSONDecodeError as e:
|
||||
raise RequestValidationError(
|
||||
[
|
||||
{
|
||||
"type": "json_invalid",
|
||||
"loc": ("body", e.pos),
|
||||
"msg": "JSON decode error",
|
||||
"input": {},
|
||||
"ctx": {"error": e.msg},
|
||||
}
|
||||
],
|
||||
body=e.doc,
|
||||
) from e
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="There was an error parsing the body"
|
||||
) from e
|
||||
solved_result = await solve_dependencies(
|
||||
request=request,
|
||||
dependant=dependant,
|
||||
body=body,
|
||||
dependency_overrides_provider=dependency_overrides_provider,
|
||||
)
|
||||
values, errors, background_tasks, sub_response, _ = solved_result
|
||||
if errors:
|
||||
raise RequestValidationError(_normalize_errors(errors), body=body)
|
||||
else:
|
||||
raw_response = await run_endpoint_function(
|
||||
dependant=dependant, values=values, is_coroutine=is_coroutine
|
||||
)
|
||||
|
||||
if isinstance(raw_response, Response):
|
||||
if raw_response.background is None:
|
||||
raw_response.background = background_tasks
|
||||
return raw_response
|
||||
response_args: Dict[str, Any] = {"background": background_tasks}
|
||||
# If status_code was set, use it, otherwise use the default from the
|
||||
# response class, in the case of redirect it's 307
|
||||
current_status_code = (
|
||||
status_code if status_code else sub_response.status_code
|
||||
)
|
||||
if current_status_code is not None:
|
||||
response_args["status_code"] = current_status_code
|
||||
if sub_response.status_code:
|
||||
response_args["status_code"] = sub_response.status_code
|
||||
content = await serialize_response(
|
||||
field=response_field,
|
||||
response_content=raw_response,
|
||||
include=response_model_include,
|
||||
exclude=response_model_exclude,
|
||||
by_alias=response_model_by_alias,
|
||||
exclude_unset=response_model_exclude_unset,
|
||||
exclude_defaults=response_model_exclude_defaults,
|
||||
exclude_none=response_model_exclude_none,
|
||||
is_coroutine=is_coroutine,
|
||||
)
|
||||
response = actual_response_class(content, **response_args)
|
||||
if not is_body_allowed_for_status_code(response.status_code):
|
||||
response.body = b""
|
||||
response.headers.raw.extend(sub_response.headers.raw)
|
||||
return response
|
||||
response_args: Dict[str, Any] = {"background": background_tasks}
|
||||
# If status_code was set, use it, otherwise use the default from the
|
||||
# response class, in the case of redirect it's 307
|
||||
current_status_code = (
|
||||
status_code if status_code else sub_response.status_code
|
||||
)
|
||||
if current_status_code is not None:
|
||||
response_args["status_code"] = current_status_code
|
||||
if sub_response.status_code:
|
||||
response_args["status_code"] = sub_response.status_code
|
||||
content = await serialize_response(
|
||||
field=response_field,
|
||||
response_content=raw_response,
|
||||
include=response_model_include,
|
||||
exclude=response_model_exclude,
|
||||
by_alias=response_model_by_alias,
|
||||
exclude_unset=response_model_exclude_unset,
|
||||
exclude_defaults=response_model_exclude_defaults,
|
||||
exclude_none=response_model_exclude_none,
|
||||
is_coroutine=is_coroutine,
|
||||
)
|
||||
response = actual_response_class(content, **response_args)
|
||||
if not is_body_allowed_for_status_code(response.status_code):
|
||||
response.body = b""
|
||||
response.headers.raw.extend(sub_response.headers.raw)
|
||||
# This exception was possibly handled by the dependency but it should
|
||||
# still bubble up so that the ServerErrorMiddleware can return a 500
|
||||
# or the ExceptionMiddleware can catch and handle any other exceptions
|
||||
if exception_to_reraise:
|
||||
raise exception_to_reraise
|
||||
assert response is not None, "An error occurred while generating the request"
|
||||
return response
|
||||
|
||||
return app
|
||||
|
||||
@@ -313,16 +342,22 @@ def get_websocket_app(
|
||||
dependant: Dependant, dependency_overrides_provider: Optional[Any] = None
|
||||
) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
|
||||
async def app(websocket: WebSocket) -> None:
|
||||
solved_result = await solve_dependencies(
|
||||
request=websocket,
|
||||
dependant=dependant,
|
||||
dependency_overrides_provider=dependency_overrides_provider,
|
||||
)
|
||||
values, errors, _, _2, _3 = solved_result
|
||||
if errors:
|
||||
raise WebSocketRequestValidationError(_normalize_errors(errors))
|
||||
assert dependant.call is not None, "dependant.call must be a function"
|
||||
await dependant.call(**values)
|
||||
async with AsyncExitStack() as async_exit_stack:
|
||||
# TODO: remove this scope later, after a few releases
|
||||
# This scope fastapi_astack is no longer used by FastAPI, kept for
|
||||
# compatibility, just in case
|
||||
websocket.scope["fastapi_astack"] = async_exit_stack
|
||||
solved_result = await solve_dependencies(
|
||||
request=websocket,
|
||||
dependant=dependant,
|
||||
dependency_overrides_provider=dependency_overrides_provider,
|
||||
async_exit_stack=async_exit_stack,
|
||||
)
|
||||
values, errors, _, _2, _3 = solved_result
|
||||
if errors:
|
||||
raise WebSocketRequestValidationError(_normalize_errors(errors))
|
||||
assert dependant.call is not None, "dependant.call must be a function"
|
||||
await dependant.call(**values)
|
||||
|
||||
return app
|
||||
|
||||
@@ -624,13 +659,6 @@ class APIRouter(routing.Router):
|
||||
**Note**: you probably shouldn't use this parameter, it is inherited
|
||||
from Starlette and supported for compatibility.
|
||||
|
||||
In FastAPI, you normally would use the *path operation* decorators,
|
||||
like:
|
||||
|
||||
* `router.get()`
|
||||
* `router.post()`
|
||||
* etc.
|
||||
|
||||
---
|
||||
|
||||
A list of routes to serve incoming HTTP and WebSocket requests.
|
||||
|
||||
@@ -210,7 +210,7 @@ class HTTPBasic(HTTPBase):
|
||||
try:
|
||||
data = b64decode(param).decode("ascii")
|
||||
except (ValueError, UnicodeDecodeError, binascii.Error):
|
||||
raise invalid_user_credentials_exc
|
||||
raise invalid_user_credentials_exc # noqa: B904
|
||||
username, separator, password = data.partition(":")
|
||||
if not separator:
|
||||
raise invalid_user_credentials_exc
|
||||
|
||||
@@ -626,9 +626,7 @@ class SecurityScopes:
|
||||
The list of all the scopes required by dependencies.
|
||||
"""
|
||||
),
|
||||
] = (
|
||||
scopes or []
|
||||
)
|
||||
] = scopes or []
|
||||
self.scope_str: Annotated[
|
||||
str,
|
||||
Doc(
|
||||
|
||||
@@ -6,6 +6,5 @@ from pydantic import BaseModel
|
||||
|
||||
DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
|
||||
UnionType = getattr(types, "UnionType", Union)
|
||||
NoneType = getattr(types, "UnionType", None)
|
||||
ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
|
||||
IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
|
||||
|
||||