Compare commits

...

103 Commits

Author SHA1 Message Date
github-actions[bot]
3b441efc61 🎨 Auto format 2026-01-16 12:33:56 +00:00
github-actions[bot]
1cb4c55240 🌐 Update translations for pt (update-outdated) 2026-01-16 12:33:29 +00:00
github-actions[bot]
0c7f2b66d7 📝 Update release notes
[skip ci]
2026-01-16 12:27:29 +00:00
Rafael de Oliveira Marques
9fec72687f 🌐 Update portuguese llm-prompt.md (#14702)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Sofie Van Landeghem <svlandeg@users.noreply.github.com>
2026-01-16 13:27:02 +01:00
github-actions[bot]
8fa635c718 📝 Update release notes
[skip ci]
2026-01-16 11:57:32 +00:00
Sebastián Ramírez
fb15bba819 🌐 Update LLM prompt instructions file for French (#14618) 2026-01-16 12:57:08 +01:00
github-actions[bot]
23bcfa094d 📝 Update release notes
[skip ci]
2026-01-16 11:54:26 +00:00
Sebastián Ramírez
f317ede223 🌐 Update translations for ko (add-missing) (#14699)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-16 12:54:01 +01:00
github-actions[bot]
c597d9cb53 📝 Update release notes
[skip ci]
2026-01-16 10:54:08 +00:00
fcharrier
a96dd013a4 🐛 Fix copy button in custom.js (#14722) 2026-01-16 10:53:45 +00:00
github-actions[bot]
a456e92a21 📝 Update release notes
[skip ci]
2026-01-11 22:23:21 +00:00
Sebastián Ramírez
1be80f4885 📝 Add contribution instructions about LLM generated code and comments and automated tools for PRs (#14706) 2026-01-11 23:22:58 +01:00
github-actions[bot]
e63f382b0f 📝 Update release notes
[skip ci]
2026-01-11 21:19:50 +00:00
Sebastián Ramírez
7b864acf37 📝 Update docs for management tasks (#14705) 2026-01-11 21:19:26 +00:00
github-actions[bot]
e9e0419ed0 📝 Update release notes
[skip ci]
2026-01-11 19:19:29 +00:00
Sebastián Ramírez
249a776b70 📝 Update docs about managing translations (#14704) 2026-01-11 19:19:05 +00:00
github-actions[bot]
97aa825422 📝 Update release notes
[skip ci]
2026-01-11 18:18:58 +00:00
Sebastián Ramírez
1054fbd256 📝 Update docs for contributing with translations (#14701) 2026-01-11 18:18:38 +00:00
github-actions[bot]
effe493ae0 📝 Update release notes
[skip ci]
2026-01-11 16:43:35 +00:00
github-actions[bot]
612a2d20bc 📝 Update release notes
[skip ci]
2026-01-11 16:43:25 +00:00
dependabot[bot]
14f3068762 ⬆ Bump actions/cache from 4 to 5 (#14511)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-11 17:42:51 +01:00
dependabot[bot]
d05b18ec40 ⬆ Bump actions/upload-artifact from 5 to 6 (#14525)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-11 17:42:37 +01:00
github-actions[bot]
9a76f2fec9 📝 Update release notes
[skip ci]
2026-01-11 16:42:08 +00:00
dependabot[bot]
0383fb3ab9 ⬆ Bump actions/download-artifact from 6 to 7 (#14526)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-11 17:41:45 +01:00
github-actions[bot]
50fa3f7c88 📝 Update release notes
[skip ci]
2026-01-11 00:21:31 +00:00
Sebastián Ramírez
5ec2615b1a 👷 Tweak CI input names (#14688) 2026-01-11 01:21:07 +01:00
github-actions[bot]
16e583413c 📝 Update release notes
[skip ci]
2026-01-11 00:16:33 +00:00
github-actions[bot]
1fedd1c73b 📝 Update release notes
[skip ci]
2026-01-11 00:15:31 +00:00
Sebastián Ramírez
cf8dc98aad 🌐 Update translations for ko (update-outdated) (#14589)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Yurii Motov <yurii.motov.monte@gmail.com>
2026-01-11 00:15:26 +00:00
Sebastián Ramírez
6f977366a4 🌐 Update translations for uk (update-outdated) (#14587)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Yurii Motov <yurii.motov.monte@gmail.com>
2026-01-11 01:15:06 +01:00
github-actions[bot]
154ce03ff0 📝 Update release notes
[skip ci]
2026-01-11 00:04:10 +00:00
Sebastián Ramírez
49653aa295 🔨 Refactor translation script to allow committing in place (#14687) 2026-01-11 00:03:50 +00:00
github-actions[bot]
f03a1502a0 📝 Update release notes
[skip ci]
2026-01-10 23:41:44 +00:00
Sebastián Ramírez
a2912ffa26 🌐 Update translations for es (update-outdated) (#14686)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-11 00:41:20 +01:00
github-actions[bot]
8183e748ee 📝 Update release notes
[skip ci]
2026-01-10 23:06:59 +00:00
Sebastián Ramírez
cefd50702a 🐛 Fix translation script path (#14685) 2026-01-10 23:06:37 +00:00
github-actions[bot]
3d1f9268fc 📝 Update release notes
[skip ci]
2026-01-10 22:44:05 +00:00
Sebastián Ramírez
7eac6e3169 Enable tests in CI for scripts (#14684) 2026-01-10 23:43:44 +01:00
github-actions[bot]
21d2c5cea0 📝 Update release notes
[skip ci]
2026-01-10 22:18:13 +00:00
Sebastián Ramírez
c75ae058e4 🔧 Add pre-commit local script to fix language translations (#14683) 2026-01-10 22:17:46 +00:00
github-actions[bot]
961b2e844a 📝 Update release notes
[skip ci]
2026-01-10 22:03:19 +00:00
Jonathan Ehwald
b4ba7f4652 ⬆️ Migrate to uv (#14676) 2026-01-10 23:02:57 +01:00
github-actions[bot]
c35e1fd4b4 📝 Update release notes
[skip ci]
2026-01-10 21:48:32 +00:00
Motov Yurii
d1c67c0055 🔨 Add LLM translations tool fixer (#14652)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2026-01-10 21:48:08 +00:00
github-actions[bot]
18762e38a9 📝 Update release notes
[skip ci]
2026-01-10 21:35:32 +00:00
Motov Yurii
b1db1395b6 📝 Specify language code for code block (#14656) 2026-01-10 22:35:09 +01:00
github-actions[bot]
f2687dc1bb 📝 Update release notes
[skip ci]
2026-01-02 06:47:25 +00:00
github-actions[bot]
862c3f4f94 📝 Update release notes
[skip ci]
2026-01-02 06:46:59 +00:00
Sebastián Ramírez
052d6e86c2 👥 Update FastAPI People - Sponsors (#14626)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-02 07:46:57 +01:00
Sebastián Ramírez
31c7ffcdfe 👥 Update FastAPI GitHub topic repositories (#14630)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-02 07:46:34 +01:00
github-actions[bot]
6854be9ebc 📝 Update release notes
[skip ci]
2026-01-02 06:40:39 +00:00
Sebastián Ramírez
258deb925d 👥 Update FastAPI People - Contributors and Translators (#14625)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-01-02 07:40:15 +01:00
github-actions[bot]
53d2453d1a 📝 Update release notes
[skip ci]
2025-12-29 18:54:43 +00:00
Sebastián Ramírez
d9b7b65b81 🌐 Update translation prompts (#14619) 2025-12-29 18:54:20 +00:00
github-actions[bot]
9ed5f246ed 📝 Update release notes
[skip ci]
2025-12-29 12:38:35 +00:00
Sebastián Ramírez
edf7995775 🔧 Add LLM prompt file for Turkish, generated from the existing translations (#14547) 2025-12-29 13:38:11 +01:00
github-actions[bot]
47391ea8fb 📝 Update release notes
[skip ci]
2025-12-27 19:06:15 +00:00
Sebastián Ramírez
3b1b4f034b 🔨 Update LLM translation script to guide reviewers to change the prompt (#14614) 2025-12-27 19:05:53 +00:00
github-actions[bot]
f362fdc234 📝 Update release notes
[skip ci]
2025-12-27 18:51:39 +00:00
github-actions[bot]
4ce34686d9 📝 Update release notes
[skip ci]
2025-12-27 18:51:18 +00:00
Sebastián Ramírez
dbe83f3919 🔧 Add LLM prompt file for Traditional Chinese, generated from the existing translations (#14550)
Co-authored-by: W. H. Wang <mattwang44@gmail.com>
2025-12-27 19:49:46 +01:00
github-actions[bot]
13743e115a 📝 Update release notes
[skip ci]
2025-12-27 18:49:09 +00:00
Sebastián Ramírez
52842fb8d3 🔧 Add LLM prompt file for Simplified Chinese, generated from the existing translations (#14549)
Co-authored-by: 史雲昔 (Vincy SHI) <vincy@vincy1230.net>
2025-12-27 19:49:08 +01:00
Sebastián Ramírez
4d4fb28f9f 👷 Do not run translations on cron while finishing updating existing languages (#14613) 2025-12-27 18:48:45 +00:00
github-actions[bot]
a1735d6d11 📝 Update release notes
[skip ci]
2025-12-27 18:31:59 +00:00
Sebastián Ramírez
1b42639296 🔥 Remove test variants for Pydantic v1 in test_request_params (#14612) 2025-12-27 19:31:34 +01:00
github-actions[bot]
ded035a421 📝 Update release notes
[skip ci]
2025-12-27 18:19:33 +00:00
Sebastián Ramírez
44c849c4fc 🔥 Remove Pydantic v1 specific test variants (#14611) 2025-12-27 19:19:10 +01:00
Sebastián Ramírez
8322a4445a 🔖 Release version 0.128.0 2025-12-27 16:19:50 +01:00
github-actions[bot]
4b2cfcfd34 📝 Update release notes
[skip ci]
2025-12-27 12:55:22 +00:00
Sebastián Ramírez
e300630551 Drop support for pydantic.v1 (#14609) 2025-12-27 13:54:56 +01:00
github-actions[bot]
1b3bea8b6b 📝 Update release notes
[skip ci]
2025-12-26 20:40:51 +00:00
Sebastián Ramírez
34e884156f Run performance tests only on Pydantic v2 (#14608) 2025-12-26 20:40:26 +00:00
Sebastián Ramírez
cd90c78391 🔖 Release version 0.127.1 2025-12-26 14:02:41 +01:00
github-actions[bot]
93f4dfd88b 📝 Update release notes
[skip ci]
2025-12-26 12:46:00 +00:00
Sebastián Ramírez
535b5daa31 🔊 Add a custom FastAPIDeprecationWarning (#14605) 2025-12-26 12:45:20 +00:00
github-actions[bot]
6b53786f62 📝 Update release notes
[skip ci]
2025-12-26 11:37:18 +00:00
Sebastián Ramírez
d98f4eb56e 🔧 Update pre-commit to use local Ruff instead of hook (#14604) 2025-12-26 11:36:58 +00:00
github-actions[bot]
8cefc4b7cc 📝 Update release notes
[skip ci]
2025-12-26 10:43:27 +00:00
Motov Yurii
3063ada72f Add missing tests for code examples (#14569)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nils-Hero Lindemann <nilsherolindemann@proton.me>
2025-12-26 11:43:02 +01:00
github-actions[bot]
5eb8d6ed8a 📝 Update release notes
[skip ci]
2025-12-26 09:40:18 +00:00
Nils-Hero Lindemann
7c751a2e1c 🌐 Update translations for de (update-outdated) (#14602)
* Sync with #14600

* A few changes

The LLM suggested a few changes when retranslating the document, these are the good ones.

I also added a term to the llm prompt, the LLM instead used just "Abdeckung", which is too broad in this context.
2025-12-26 10:39:53 +01:00
github-actions[bot]
55b556a7d1 📝 Update release notes
[skip ci]
2025-12-26 08:54:23 +00:00
Motov Yurii
a4d04c9b7e 👷 Remove lint job from test CI workflow (#14593)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-26 09:53:59 +01:00
github-actions[bot]
23caa2709b 📝 Update release notes
[skip ci]
2025-12-25 11:02:01 +00:00
Sebastián Ramírez
c264467efe 📝 Add documentary to website (#14600) 2025-12-25 11:01:37 +00:00
github-actions[bot]
2b212ddd76 📝 Update release notes
[skip ci]
2025-12-24 10:28:45 +00:00
Nils-Hero Lindemann
7203e860b3 🌐 Update translations for de (update-outdated) (#14581)
* Sync with #14575 (Drop support for Pydantic v1)

* Add a word and fix a typo

Found while syncing.
2025-12-24 11:28:19 +01:00
github-actions[bot]
e55f223b46 📝 Update release notes
[skip ci]
2025-12-23 11:17:37 +00:00
Sebastián Ramírez
a329baaa54 👷 Update secrets check (#14592) 2025-12-23 11:17:16 +00:00
github-actions[bot]
a7a0aee984 📝 Update release notes
[skip ci]
2025-12-21 17:52:08 +00:00
Sebastián Ramírez
6539b80d9f 👷 Run CodSpeed tests in parallel to other tests to speed up CI (#14586) 2025-12-21 18:51:45 +01:00
github-actions[bot]
e1bd9f3e33 📝 Update release notes
[skip ci]
2025-12-21 17:40:41 +00:00
Sebastián Ramírez
b9b2793bda 🔨 Update scripts and pre-commit to autofix files (#14585) 2025-12-21 17:40:17 +00:00
Sebastián Ramírez
c4a1ab5036 🔖 Release version 0.127.0 2025-12-21 17:45:43 +01:00
github-actions[bot]
22c7200ebb 📝 Update release notes
[skip ci]
2025-12-21 16:44:32 +00:00
Sebastián Ramírez
6e42bcd8ce 🔊 Add deprecation warnings when using pydantic.v1 (#14583) 2025-12-21 17:44:10 +01:00
github-actions[bot]
6513d4daa1 📝 Update release notes
[skip ci]
2025-12-21 08:06:42 +00:00
Sebastián Ramírez
1d93d531bc ⬆️ Upgrade OpenAI model for translations to gpt-5.2 (#14579) 2025-12-21 08:06:22 +00:00
github-actions[bot]
c2c1cc8aec 📝 Update release notes
[skip ci]
2025-12-20 17:32:31 +00:00
Sebastián Ramírez
5289259275 🔧 Add LLM prompt file for Korean, generated from the existing translations (#14546)
Co-authored-by: hy.lee <rurouni24@gmail.com>
2025-12-20 18:32:05 +01:00
github-actions[bot]
5783910d0c 📝 Update release notes
[skip ci]
2025-12-20 17:31:11 +00:00
Sebastián Ramírez
026b43e5d3 🔧 Add LLM prompt file for Japanese, generated from the existing translations (#14545)
Co-authored-by: Maruo.S <raspi-maru2004@outlook.jp>
2025-12-20 18:30:52 +01:00
617 changed files with 37530 additions and 25008 deletions

View File

@@ -8,7 +8,7 @@ updates:
commit-message:
prefix:
# Python
- package-ecosystem: "pip"
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "monthly"

View File

@@ -8,9 +8,6 @@ on:
- opened
- synchronize
env:
UV_SYSTEM_PYTHON: 1
jobs:
changes:
runs-on: ubuntu-latest
@@ -31,8 +28,8 @@ jobs:
- README.md
- docs/**
- docs_src/**
- requirements-docs.txt
- pyproject.toml
- uv.lock
- mkdocs.yml
- mkdocs.env.yml
- .github/workflows/build-docs.yml
@@ -49,23 +46,20 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install docs extras
run: uv pip install -r requirements-docs.txt
- name: Verify Docs
run: python ./scripts/docs.py verify-docs
run: uv sync --locked --no-dev --group docs
- name: Export Language Codes
id: show-langs
run: |
echo "langs=$(python ./scripts/docs.py langs-json)" >> $GITHUB_OUTPUT
echo "langs=$(uv run ./scripts/docs.py langs-json)" >> $GITHUB_OUTPUT
build-docs:
needs:
@@ -85,26 +79,25 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install docs extras
run: uv pip install -r requirements-docs.txt
run: uv sync --locked --no-dev --group docs
- name: Update Languages
run: python ./scripts/docs.py update-languages
- uses: actions/cache@v4
run: uv run ./scripts/docs.py update-languages
- uses: actions/cache@v5
with:
key: mkdocs-cards-${{ matrix.lang }}-${{ github.ref }}
path: docs/${{ matrix.lang }}/.cache
- name: Build Docs
run: python ./scripts/docs.py build-lang ${{ matrix.lang }}
- uses: actions/upload-artifact@v5
run: uv run ./scripts/docs.py build-lang ${{ matrix.lang }}
- uses: actions/upload-artifact@v6
with:
name: docs-site-${{ matrix.lang }}
path: ./site/**

View File

@@ -10,9 +10,6 @@ on:
required: false
default: "false"
env:
UV_SYSTEM_PYTHON: 1
jobs:
job:
if: github.repository_owner == 'fastapi'
@@ -28,17 +25,16 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt
run: uv sync --locked --no-dev --group github-actions
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
@@ -48,6 +44,6 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }}
- name: FastAPI People Contributors
run: python ./scripts/contributors.py
run: uv run ./scripts/contributors.py
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }}

View File

@@ -12,9 +12,6 @@ permissions:
pull-requests: write
statuses: write
env:
UV_SYSTEM_PYTHON: 1
jobs:
deploy-docs:
runs-on: ubuntu-latest
@@ -27,19 +24,18 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install GitHub Actions dependencies
run: uv pip install -r requirements-github-actions.txt
run: uv sync --locked --no-dev --group github-actions
- name: Deploy Docs Status Pending
run: python ./scripts/deploy_docs_status.py
run: uv run ./scripts/deploy_docs_status.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
@@ -49,7 +45,7 @@ jobs:
run: |
rm -rf ./site
mkdir ./site
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v7
with:
path: ./site/
pattern: docs-site-*
@@ -70,14 +66,14 @@ jobs:
command: pages deploy ./site --project-name=${{ env.PROJECT_NAME }} --branch=${{ env.BRANCH }}
- name: Deploy Docs Status Error
if: failure()
run: python ./scripts/deploy_docs_status.py
run: uv run ./scripts/deploy_docs_status.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}
RUN_ID: ${{ github.run_id }}
STATE: "error"
- name: Comment Deploy
run: python ./scripts/deploy_docs_status.py
run: uv run ./scripts/deploy_docs_status.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEPLOY_URL: ${{ steps.deploy.outputs.deployment-url }}

View File

@@ -41,11 +41,15 @@ jobs:
"message": "As this PR has been waiting for the original user for a while but seems to be inactive, it's now going to be closed. But if there's anyone interested, feel free to create a new PR.",
"reminder": {
"before": "P3D",
"message": "Heads-up: this will be closed in 3 days unless theres new activity."
"message": "Heads-up: this will be closed in 3 days unless there's new activity."
}
},
"invalid": {
"delay": 0,
"message": "This was marked as invalid and will be closed now. If this is an error, please provide additional details."
},
"maybe-ai": {
"delay": 0,
"message": "This was marked as potentially AI generated and will be closed now. If this is an error, please provide additional details, make sure to read the docs about contributing and AI."
}
}

View File

@@ -8,9 +8,6 @@ on:
permissions:
pull-requests: write
env:
UV_SYSTEM_PYTHON: 1
jobs:
label-approved:
if: github.repository_owner == 'fastapi'
@@ -24,19 +21,18 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install GitHub Actions dependencies
run: uv pip install -r requirements-github-actions.txt
run: uv sync --locked --no-dev --group github-actions
- name: Label Approved
run: python ./scripts/label_approved.py
run: uv run ./scripts/label_approved.py
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
CONFIG: >

View File

@@ -15,9 +15,6 @@ on:
required: false
default: 'false'
env:
UV_SYSTEM_PYTHON: 1
jobs:
job:
runs-on: ubuntu-latest
@@ -32,17 +29,16 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt
run: uv sync --locked --no-dev --group github-actions
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
@@ -52,7 +48,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Notify Translations
run: python ./scripts/notify_translations.py
run: uv run ./scripts/notify_translations.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NUMBER: ${{ github.event.inputs.number || null }}

View File

@@ -10,9 +10,6 @@ on:
required: false
default: "false"
env:
UV_SYSTEM_PYTHON: 1
jobs:
job:
if: github.repository_owner == 'fastapi'
@@ -28,17 +25,16 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt
run: uv sync --locked --no-dev --group github-actions
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
@@ -48,7 +44,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_PEOPLE }}
- name: FastAPI People Experts
run: python ./scripts/people.py
run: uv run ./scripts/people.py
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_PEOPLE }}
SLEEP_INTERVAL: ${{ vars.PEOPLE_SLEEP_INTERVAL }}

View File

@@ -7,7 +7,8 @@ on:
- synchronize
env:
IS_FORK: ${{ github.event.pull_request.head.repo.full_name != github.repository }}
# Forks and Dependabot don't have access to secrets
HAS_SECRETS: ${{ secrets.PRE_COMMIT != '' }}
jobs:
pre-commit:
@@ -19,7 +20,7 @@ jobs:
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v5
name: Checkout PR for own repo
if: env.IS_FORK == 'false'
if: env.HAS_SECRETS == 'true'
with:
# To be able to commit it needs to fetch the head of the branch, not the
# merge commit
@@ -31,7 +32,7 @@ jobs:
# pre-commit lite ci needs the default checkout configs to work
- uses: actions/checkout@v5
name: Checkout PR for fork
if: env.IS_FORK == 'true'
if: env.HAS_SECRETS == 'false'
with:
# To be able to commit it needs the head branch of the PR, the remote one
ref: ${{ github.event.pull_request.head.sha }}
@@ -39,24 +40,21 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: |
uv venv
uv pip install -r requirements.txt
run: uv sync --locked --extra all
- name: Run prek - pre-commit
id: precommit
run: uvx prek run --from-ref origin/${GITHUB_BASE_REF} --to-ref HEAD --show-diff-on-failure
continue-on-error: true
- name: Commit and push changes
if: env.IS_FORK == 'false'
if: env.HAS_SECRETS == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
@@ -68,7 +66,7 @@ jobs:
git push
fi
- uses: pre-commit-ci/lite-action@v1.1.0
if: env.IS_FORK == 'true'
if: env.HAS_SECRETS == 'false'
with:
msg: 🎨 Auto format
- name: Error out on pre-commit errors

View File

@@ -15,6 +15,7 @@ jobs:
- fastapi-slim
permissions:
id-token: write
contents: read
steps:
- name: Dump GitHub context
env:
@@ -24,19 +25,15 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
python-version-file: ".python-version"
# Issue ref: https://github.com/actions/setup-python/issues/436
# cache: "pip"
# cache-dependency-path: pyproject.toml
- name: Install build dependencies
run: pip install build
- name: Install uv
uses: astral-sh/setup-uv@v7
- name: Build distribution
run: uv build
env:
TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }}
run: python -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@v1.13.0
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
run: uv publish

View File

@@ -8,9 +8,6 @@ on:
permissions:
statuses: write
env:
UV_SYSTEM_PYTHON: 1
jobs:
smokeshow:
runs-on: ubuntu-latest
@@ -23,15 +20,15 @@ jobs:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.13'
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: |
requirements**.txt
pyproject.toml
- run: uv pip install -r requirements-github-actions.txt
- uses: actions/download-artifact@v6
uv.lock
- run: uv sync --locked --no-dev --group github-actions
- uses: actions/download-artifact@v7
with:
name: coverage-html
path: htmlcov
@@ -41,7 +38,7 @@ jobs:
- name: Upload coverage to Smokeshow
run: |
for i in 1 2 3 4 5; do
if smokeshow upload htmlcov; then
if uv run smokeshow upload htmlcov; then
echo "Smokeshow upload success!"
break
fi

View File

@@ -10,9 +10,6 @@ on:
required: false
default: "false"
env:
UV_SYSTEM_PYTHON: 1
jobs:
job:
if: github.repository_owner == 'fastapi'
@@ -28,17 +25,16 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt
run: uv sync --locked --no-dev --group github-actions
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
@@ -46,7 +42,7 @@ jobs:
with:
limit-access-to-actor: true
- name: FastAPI People Sponsors
run: python ./scripts/sponsors.py
run: uv run ./scripts/sponsors.py
env:
SPONSORS_TOKEN: ${{ secrets.SPONSORS_TOKEN }}
PR_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }}

View File

@@ -26,7 +26,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.10"
python-version-file: ".python-version"
- name: Install build dependencies
run: pip install build
- name: Build source distribution
@@ -40,7 +40,7 @@ jobs:
- name: Install test dependencies
run: |
cd dist/fastapi*/
pip install -r requirements-tests.txt
pip install --group tests --editable .[all]
env:
TIANGOLO_BUILD_PACKAGE: ${{ matrix.package }}
- name: Run source distribution tests

View File

@@ -13,32 +13,9 @@ on:
- cron: "0 0 * * 1"
env:
UV_SYSTEM_PYTHON: 1
UV_NO_SYNC: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: |
requirements**.txt
pyproject.toml
- name: Install Dependencies
run: uv pip install -r requirements-tests.txt
- name: Lint
run: bash scripts/lint.sh
test:
strategy:
matrix:
@@ -54,15 +31,21 @@ jobs:
- os: windows-latest
python-version: "3.12"
coverage: coverage
# Ubuntu with 3.13 needs coverage for CodSpeed benchmarks
- os: ubuntu-latest
python-version: "3.13"
coverage: coverage
# Ubuntu with 3.13 needs coverage for CodSpeed benchmarks
- os: ubuntu-latest
python-version: "3.13"
coverage: coverage
codspeed: codspeed
- os: ubuntu-latest
python-version: "3.14"
coverage: coverage
fail-fast: false
runs-on: ${{ matrix.os }}
env:
UV_PYTHON: ${{ matrix.python-version }}
steps:
- name: Dump GitHub context
env:
@@ -76,32 +59,32 @@ jobs:
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-tests.txt
run: uv sync --locked --no-dev --group tests --extra all
- run: mkdir coverage
- name: Test
run: bash scripts/test.sh
if: matrix.codspeed != 'codspeed'
run: uv run bash scripts/test.sh
env:
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
- name: CodSpeed benchmarks
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
if: matrix.codspeed == 'codspeed'
uses: CodSpeedHQ/action@v4
env:
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
with:
mode: simulation
run: coverage run -m pytest tests/ --codspeed
run: uv run coverage run -m pytest tests/ --codspeed
# Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow
- name: Store coverage files
if: matrix.coverage == 'coverage'
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: coverage-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/coverage/.coverage.*') }}
path: coverage
@@ -118,33 +101,32 @@ jobs:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.11'
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-tests.txt
run: uv sync --locked --no-dev --group tests --extra all
- name: Get coverage files
uses: actions/download-artifact@v6
uses: actions/download-artifact@v7
with:
pattern: coverage-*
path: coverage
merge-multiple: true
- run: ls -la coverage
- run: coverage combine coverage
- run: coverage html --title "Coverage for ${{ github.sha }}"
- run: uv run coverage combine coverage
- run: uv run coverage html --title "Coverage for ${{ github.sha }}"
- name: Store coverage HTML
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v6
with:
name: coverage-html
path: htmlcov
include-hidden-files: true
- run: coverage report --fail-under=100
- run: uv run coverage report --fail-under=100
# https://github.com/marketplace/actions/alls-green#why
check: # This job does nothing and is only used for the branch protection

View File

@@ -5,9 +5,6 @@ on:
- cron: "0 12 1 * *"
workflow_dispatch:
env:
UV_SYSTEM_PYTHON: 1
jobs:
topic-repos:
if: github.repository_owner == 'fastapi'
@@ -23,18 +20,17 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
version: "0.4.15"
enable-cache: true
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install GitHub Actions dependencies
run: uv pip install -r requirements-github-actions.txt
run: uv sync --locked --no-dev --group github-actions
- name: Update Topic Repos
run: python ./scripts/topic_repos.py
run: uv run ./scripts/topic_repos.py
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }}

View File

@@ -1,8 +1,8 @@
name: Translate
on:
schedule:
- cron: "0 5 15 * *" # Run at 05:00 on the 15 of every month
# schedule:
# - cron: "0 5 15 * *" # Run at 05:00 on the 15 of every month
workflow_dispatch:
inputs:
@@ -30,9 +30,11 @@ on:
type: string
required: false
default: ""
env:
UV_SYSTEM_PYTHON: 1
commit_in_place:
description: Commit changes directly instead of making a PR
type: boolean
required: false
default: false
jobs:
langs:
@@ -45,20 +47,20 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt -r requirements-translations.txt
run: uv sync --locked --no-dev --group github-actions --group translations
- name: Export Language Codes
id: show-langs
run: |
echo "langs=$(python ./scripts/translate.py llm-translatable-json)" >> $GITHUB_OUTPUT
echo "commands=$(python ./scripts/translate.py commands-json)" >> $GITHUB_OUTPUT
echo "langs=$(uv run ./scripts/translate.py llm-translatable-json)" >> $GITHUB_OUTPUT
echo "commands=$(uv run ./scripts/translate.py commands-json)" >> $GITHUB_OUTPUT
env:
LANGUAGE: ${{ github.event.inputs.language }}
COMMAND: ${{ github.event.inputs.command }}
@@ -84,15 +86,15 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.11"
python-version-file: ".python-version"
- name: Setup uv
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: |
requirements**.txt
pyproject.toml
uv.lock
- name: Install Dependencies
run: uv pip install -r requirements-github-actions.txt -r requirements-translations.txt
run: uv sync --locked --no-dev --group github-actions --group translations
# Allow debugging with tmate
- name: Setup tmate session
uses: mxschmitt/action-tmate@v3
@@ -104,11 +106,12 @@ jobs:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: FastAPI Translate
run: |
python ./scripts/translate.py ${{ matrix.command }}
python ./scripts/translate.py make-pr
uv run ./scripts/translate.py ${{ matrix.command }}
uv run ./scripts/translate.py make-pr
env:
GITHUB_TOKEN: ${{ secrets.FASTAPI_TRANSLATIONS }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LANGUAGE: ${{ matrix.lang }}
EN_PATH: ${{ github.event.inputs.en_path }}
COMMAND: ${{ matrix.command }}
COMMIT_IN_PLACE: ${{ github.event.inputs.commit_in_place }}

3
.gitignore vendored
View File

@@ -29,7 +29,4 @@ archive.zip
# macOS
.DS_Store
# Ignore while the setup still depends on requirements.txt files
uv.lock
.codspeed

View File

@@ -6,25 +6,61 @@ repos:
hooks:
- id: check-added-large-files
args: ['--maxkb=750']
exclude: ^uv.lock$
- id: check-toml
- id: check-yaml
args:
- --unsafe
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.3
hooks:
- id: ruff
args:
- --fix
- id: ruff-format
- repo: local
hooks:
- id: local-script
- id: local-ruff-check
name: ruff check
entry: uv run ruff check --force-exclude --fix --exit-non-zero-on-fix
require_serial: true
language: unsupported
name: local script
types: [python]
- id: local-ruff-format
name: ruff format
entry: uv run ruff format --force-exclude --exit-non-zero-on-format
require_serial: true
language: unsupported
types: [python]
- id: add-permalinks-pages
language: unsupported
name: add-permalinks-pages
entry: uv run ./scripts/docs.py add-permalinks-pages
args:
- --update-existing
files: ^docs/en/docs/.*\.md$
- id: generate-readme
language: unsupported
name: generate README.md from index.md
entry: uv run ./scripts/docs.py generate-readme
files: ^docs/en/docs/index\.md|docs/en/data/sponsors\.yml|scripts/docs\.py$
pass_filenames: false
- id: update-languages
language: unsupported
name: update languages
entry: uv run ./scripts/docs.py update-languages
files: ^docs/.*|scripts/docs\.py$
pass_filenames: false
- id: ensure-non-translated
language: unsupported
name: ensure non-translated files are not modified
entry: uv run ./scripts/docs.py ensure-non-translated
files: ^docs/(?!en/).*|^scripts/docs\.py$
pass_filenames: false
- id: fix-translations
language: unsupported
name: fix translations
entry: uv run ./scripts/translation_fixer.py fix-pages
files: ^docs/(?!en/).*/docs/.*\.md$

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.11

View File

@@ -120,6 +120,12 @@ The key features are:
---
## FastAPI mini documentary
There's a <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">FastAPI mini documentary</a> released at the end of 2025, you can watch it online:
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
## **Typer**, the FastAPI of CLIs
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>

View File

@@ -4,7 +4,7 @@ FastAPI basiert auf **Pydantic**, und ich habe Ihnen gezeigt, wie Sie Pydantic-M
Aber FastAPI unterstützt auf die gleiche Weise auch die Verwendung von <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a>:
{* ../../docs_src/dataclasses/tutorial001_py310.py hl[1,6:11,18:19] *}
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
Das ist dank **Pydantic** ebenfalls möglich, da es <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">`dataclasses` intern unterstützt</a>.
@@ -32,7 +32,7 @@ Wenn Sie jedoch eine Menge Datenklassen herumliegen haben, ist dies ein guter Tr
Sie können `dataclasses` auch im Parameter `response_model` verwenden:
{* ../../docs_src/dataclasses/tutorial002_py310.py hl[1,6:12,18] *}
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
Die Datenklasse wird automatisch in eine Pydantic-Datenklasse konvertiert.
@@ -48,7 +48,7 @@ In einigen Fällen müssen Sie möglicherweise immer noch Pydantics Version von
In diesem Fall können Sie einfach die Standard-`dataclasses` durch `pydantic.dataclasses` ersetzen, was einen direkten Ersatz darstellt:
{* ../../docs_src/dataclasses/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
1. Wir importieren `field` weiterhin von Standard-`dataclasses`.

View File

@@ -48,7 +48,7 @@ Sie können die verwendeten Zeilen aus dem Docstring einer *Pfadoperation-Funkti
Das Hinzufügen eines `\f` (ein maskiertes „Form Feed“-Zeichen) führt dazu, dass **FastAPI** die für OpenAPI verwendete Ausgabe an dieser Stelle abschneidet.
Sie wird nicht in der Dokumentation angezeigt, aber andere Tools (z. B. Sphinx) können den Rest verwenden.
Sie wird nicht in der Dokumentation angezeigt, aber andere Tools (wie z. B. Sphinx) können den Rest verwenden.
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
@@ -153,48 +153,16 @@ Und Sie könnten dies auch tun, wenn der Datentyp im Request nicht JSON ist.
In der folgenden Anwendung verwenden wir beispielsweise weder die integrierte Funktionalität von FastAPI zum Extrahieren des JSON-Schemas aus Pydantic-Modellen noch die automatische Validierung für JSON. Tatsächlich deklarieren wir den Request-Content-Type als YAML und nicht als JSON:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
////
//// tab | Pydantic v1
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
////
/// info | Info
In Pydantic Version 1 hieß die Methode zum Abrufen des JSON-Schemas für ein Modell `Item.schema()`, in Pydantic Version 2 heißt die Methode `Item.model_json_schema()`.
///
Obwohl wir nicht die standardmäßig integrierte Funktionalität verwenden, verwenden wir dennoch ein Pydantic-Modell, um das JSON-Schema für die Daten, die wir in YAML empfangen möchten, manuell zu generieren.
Dann verwenden wir den Request direkt und extrahieren den Body als `bytes`. Das bedeutet, dass FastAPI nicht einmal versucht, den Request-Payload als JSON zu parsen.
Dann verwenden wir den Request direkt und extrahieren den Body als `bytes`. Das bedeutet, dass FastAPI nicht einmal versucht, die Request-Payload als JSON zu parsen.
Und dann parsen wir in unserem Code diesen YAML-Inhalt direkt und verwenden dann wieder dasselbe Pydantic-Modell, um den YAML-Inhalt zu validieren:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
////
//// tab | Pydantic v1
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
////
/// info | Info
In Pydantic Version 1 war die Methode zum Parsen und Validieren eines Objekts `Item.parse_obj()`, in Pydantic Version 2 heißt die Methode `Item.model_validate()`.
///
/// tip | Tipp
Hier verwenden wir dasselbe Pydantic-Modell wieder.

View File

@@ -60,24 +60,8 @@ Auf die gleiche Weise wie bei Pydantic-Modellen deklarieren Sie Klassenattribute
Sie können dieselben Validierungs-Funktionen und -Tools verwenden, die Sie für Pydantic-Modelle verwenden, z. B. verschiedene Datentypen und zusätzliche Validierungen mit `Field()`.
//// tab | Pydantic v2
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
////
//// tab | Pydantic v1
/// info | Info
In Pydantic v1 würden Sie `BaseSettings` direkt von `pydantic` statt von `pydantic_settings` importieren.
///
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
////
/// tip | Tipp
Für ein schnelles Copy-and-paste verwenden Sie nicht dieses Beispiel, sondern das letzte unten.
@@ -215,8 +199,6 @@ APP_NAME="ChimichangApp"
Und dann aktualisieren Sie Ihre `config.py` mit:
//// tab | Pydantic v2
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
/// tip | Tipp
@@ -225,26 +207,6 @@ Das Attribut `model_config` wird nur für die Pydantic-Konfiguration verwendet.
///
////
//// tab | Pydantic v1
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
/// tip | Tipp
Die Klasse `Config` wird nur für die Pydantic-Konfiguration verwendet. Weitere Informationen finden Sie unter <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
///
////
/// info | Info
In Pydantic Version 1 erfolgte die Konfiguration in einer internen Klasse `Config`, in Pydantic Version 2 erfolgt sie in einem Attribut `model_config`. Dieses Attribut akzeptiert ein <abbr title="Dictionary Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr>. Um automatische Codevervollständigung und Inline-Fehlerberichte zu erhalten, können Sie `SettingsConfigDict` importieren und verwenden, um dieses `dict` zu definieren.
///
Hier definieren wir die Konfiguration `env_file` innerhalb Ihrer Pydantic-`Settings`-Klasse und setzen den Wert auf den Dateinamen mit der dotenv-Datei, die wir verwenden möchten.
### Die `Settings` nur einmal laden mittels `lru_cache` { #creating-the-settings-only-once-with-lru-cache }

View File

@@ -35,7 +35,7 @@ Abhängig von Ihrem Anwendungsfall könnten Sie eine andere Bibliothek vorziehen
Hier ist eine kleine Vorschau, wie Sie Strawberry mit FastAPI integrieren können:
{* ../../docs_src/graphql/tutorial001_py39.py hl[3,22,25] *}
{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *}
Weitere Informationen zu Strawberry finden Sie in der <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry-Dokumentation</a>.

View File

@@ -2,21 +2,23 @@
Wenn Sie eine ältere FastAPI-App haben, nutzen Sie möglicherweise Pydantic Version 1.
FastAPI unterstützt seit Version 0.100.0 sowohl Pydantic v1 als auch v2.
FastAPI Version 0.100.0 unterstützte sowohl Pydantic v1 als auch v2. Es verwendete, was auch immer Sie installiert hatten.
Wenn Sie Pydantic v2 installiert hatten, wurde dieses verwendet. Wenn stattdessen Pydantic v1 installiert war, wurde jenes verwendet.
FastAPI Version 0.119.0 führte eine teilweise Unterstützung für Pydantic v1 innerhalb von Pydantic v2 (als `pydantic.v1`) ein, um die Migration zu v2 zu erleichtern.
Pydantic v1 ist jetzt deprecatet und die Unterstützung dafür wird in den nächsten Versionen von FastAPI entfernt, Sie sollten also zu **Pydantic v2 migrieren**. Auf diese Weise erhalten Sie die neuesten Features, Verbesserungen und Fixes.
FastAPI 0.126.0 entfernte die Unterstützung für Pydantic v1, während `pydantic.v1` noch eine Weile unterstützt wurde.
/// warning | Achtung
Außerdem hat das Pydantic-Team die Unterstützung für Pydantic v1 in den neuesten Python-Versionen eingestellt, beginnend mit **Python 3.14**.
Das Pydantic-Team hat die Unterstützung für Pydantic v1 in den neuesten Python-Versionen eingestellt, beginnend mit **Python 3.14**.
Dies schließt `pydantic.v1` ein, das unter Python 3.14 und höher nicht mehr unterstützt wird.
Wenn Sie die neuesten Features von Python nutzen möchten, müssen Sie sicherstellen, dass Sie Pydantic v2 verwenden.
///
Wenn Sie eine ältere FastAPI-App mit Pydantic v1 haben, zeige ich Ihnen hier, wie Sie sie zu Pydantic v2 migrieren, und die **neuen Features in FastAPI 0.119.0**, die Ihnen bei einer schrittweisen Migration helfen.
Wenn Sie eine ältere FastAPI-App mit Pydantic v1 haben, zeige ich Ihnen hier, wie Sie sie zu Pydantic v2 migrieren, und die **Features in FastAPI 0.119.0**, die Ihnen bei einer schrittweisen Migration helfen.
## Offizieller Leitfaden { #official-guide }
@@ -44,7 +46,7 @@ Danach können Sie die Tests ausführen und prüfen, ob alles funktioniert. Fall
## Pydantic v1 in v2 { #pydantic-v1-in-v2 }
Pydantic v2 enthält alles aus Pydantic v1 als Untermodul `pydantic.v1`.
Pydantic v2 enthält alles aus Pydantic v1 als Untermodul `pydantic.v1`. Dies wird aber in Versionen oberhalb von Python 3.13 nicht mehr unterstützt.
Das bedeutet, Sie können die neueste Version von Pydantic v2 installieren und die alten Pydanticv1Komponenten aus diesem Untermodul importieren und verwenden, als hätten Sie das alte Pydantic v1 installiert.

View File

@@ -1,6 +1,6 @@
# Separate OpenAPI-Schemas für Eingabe und Ausgabe oder nicht { #separate-openapi-schemas-for-input-and-output-or-not }
Bei Verwendung von **Pydantic v2** ist die generierte OpenAPI etwas genauer und **korrekter** als zuvor. 😎
Seit der Veröffentlichung von **Pydantic v2** ist die generierte OpenAPI etwas genauer und **korrekter** als zuvor. 😎
Tatsächlich gibt es in einigen Fällen sogar **zwei JSON-Schemas** in OpenAPI für dasselbe Pydantic-Modell, für Eingabe und Ausgabe, je nachdem, ob sie **Defaultwerte** haben.
@@ -100,5 +100,3 @@ Und jetzt wird es ein einziges Schema für die Eingabe und Ausgabe des Modells g
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
</div>
Dies ist das gleiche Verhalten wie in Pydantic v1. 🤓

View File

@@ -117,6 +117,12 @@ Seine Schlüssel-Merkmale sind:
---
## FastAPI Mini-Dokumentarfilm { #fastapi-mini-documentary }
Es gibt einen <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">FastAPI-Mini-Dokumentarfilm</a>, veröffentlicht Ende 2025, Sie können ihn online ansehen:
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini-Dokumentarfilm"></a>
## **Typer**, das FastAPI der CLIs { #typer-the-fastapi-of-clis }
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
@@ -233,7 +239,7 @@ INFO: Application startup complete.
</div>
<details markdown="1">
<summary>Was der Befehl <code>fastapi dev main.py</code> macht ...</summary>
<summary>Über den Befehl <code>fastapi dev main.py</code> ...</summary>
Der Befehl `fastapi dev` liest Ihre `main.py`-Datei, erkennt die **FastAPI**-App darin und startet einen Server mit <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>.
@@ -276,7 +282,7 @@ Sie sehen die alternative automatische Dokumentation (bereitgestellt von <a href
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Beispiel Aktualisierung { #example-upgrade }
## Beispielaktualisierung { #example-upgrade }
Ändern Sie jetzt die Datei `main.py`, um den <abbr title="Body Körper, Inhalt: Der eigentliche Inhalt einer Nachricht, nicht die Metadaten">Body</abbr> eines `PUT`-Requests zu empfangen.
@@ -326,7 +332,7 @@ Gehen Sie jetzt auf <a href="http://127.0.0.1:8000/docs" class="external-link" t
![Swagger UI Interaktion](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)
* Klicken Sie dann auf den Button „Execute“, die Benutzeroberfläche wird mit Ihrer API kommunizieren, sendet die Parameter, holt die Ergebnisse und zeigt sie auf dem Bildschirm an:
* Klicken Sie dann auf den Button „Execute“, die Benutzeroberfläche wird mit Ihrer API kommunizieren, die Parameter senden, die Ergebnisse erhalten und sie auf dem Bildschirm anzeigen:
![Swagger UI Interaktion](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
@@ -439,7 +445,7 @@ Für ein vollständigeres Beispiel, mit weiteren Funktionen, siehe das <a href="
* Deklaration von **Parametern** von anderen verschiedenen Stellen wie: **Header**, **Cookies**, **Formularfelder** und **Dateien**.
* Wie man **Validierungs-Constraints** wie `maximum_length` oder `regex` setzt.
* Ein sehr leistungsfähiges und einfach zu bedienendes System für **<abbr title="Dependency Injection Einbringen von Abhängigkeiten: Auch bekannt als Komponenten, Ressourcen, Provider, Services, Injectables">Dependency Injection</abbr>**.
* Ein sehr leistungsfähiges und einfach zu bedienendes System für **<abbr title="auch bekannt als Komponenten, Ressourcen, Provider, Services, Injectables">Dependency Injection</abbr>**.
* Sicherheit und Authentifizierung, einschließlich Unterstützung für **OAuth2** mit **JWT-Tokens** und **HTTP Basic** Authentifizierung.
* Fortgeschrittenere (aber ebenso einfache) Techniken zur Deklaration **tief verschachtelter JSON-Modelle** (dank Pydantic).
* **GraphQL**-Integration mit <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> und anderen Bibliotheken.
@@ -452,7 +458,7 @@ Für ein vollständigeres Beispiel, mit weiteren Funktionen, siehe das <a href="
### Ihre App deployen (optional) { #deploy-your-app-optional }
Optional können Sie Ihre FastAPI-App in die <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> deployen, treten Sie der Warteliste bei, falls noch nicht geschehen. 🚀
Optional können Sie Ihre FastAPI-App in die <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a> deployen, gehen Sie und treten Sie der Warteliste bei, falls noch nicht geschehen. 🚀
Wenn Sie bereits ein **FastAPI Cloud**-Konto haben (wir haben Sie von der Warteliste eingeladen 😉), können Sie Ihre Anwendung mit einem einzigen Befehl deployen.
@@ -494,7 +500,7 @@ Es vereinfacht den Prozess des **Erstellens**, **Deployens** und **Zugreifens**
Es bringt die gleiche **Developer-Experience** beim Erstellen von Apps mit FastAPI auch zum **Deployment** in der Cloud. 🎉
FastAPI Cloud ist der Hauptsponsor und Finanzierer der FastAPI and friends Open-Source-Projekte. ✨
FastAPI Cloud ist der Hauptsponsor und Finanzierer der *FastAPI and friends* Open-Source-Projekte. ✨
#### Bei anderen Cloudanbietern deployen { #deploy-to-other-cloud-providers }

View File

@@ -50,14 +50,6 @@ Wenn Sie Teil-Aktualisierungen entgegennehmen, ist der `exclude_unset`-Parameter
Wie in `item.model_dump(exclude_unset=True)`.
/// info | Info
In Pydantic v1 hieß diese Methode `.dict()`, in Pydantic v2 wurde sie <abbr title="veraltet, obsolet: Es soll nicht mehr verwendet werden">deprecatet</abbr> (aber immer noch unterstützt) und in `.model_dump()` umbenannt.
Die Beispiele hier verwenden `.dict()` für die Kompatibilität mit Pydantic v1, Sie sollten jedoch stattdessen `.model_dump()` verwenden, wenn Sie Pydantic v2 verwenden können.
///
Das wird ein <abbr title="Dictionary Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> erstellen, mit nur den Daten, die gesetzt wurden, als das `item`-Modell erstellt wurde, Defaultwerte ausgeschlossen.
Sie können das verwenden, um ein `dict` zu erstellen, das nur die (im <abbr title="Request Anfrage: Daten, die der Client zum Server sendet">Request</abbr>) gesendeten Daten enthält, ohne Defaultwerte:
@@ -68,14 +60,6 @@ Sie können das verwenden, um ein `dict` zu erstellen, das nur die (im <abbr tit
Jetzt können Sie eine Kopie des existierenden Modells mittels `.model_copy()` erstellen, wobei Sie dem `update`-Parameter ein `dict` mit den zu ändernden Daten übergeben.
/// info | Info
In Pydantic v1 hieß diese Methode `.copy()`, in Pydantic v2 wurde sie <abbr title="veraltet, obsolet: Es soll nicht mehr verwendet werden">deprecatet</abbr> (aber immer noch unterstützt) und in `.model_copy()` umbenannt.
Die Beispiele hier verwenden `.copy()` für die Kompatibilität mit Pydantic v1, Sie sollten jedoch stattdessen `.model_copy()` verwenden, wenn Sie Pydantic v2 verwenden können.
///
Wie in `stored_item_model.model_copy(update=update_data)`:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}

View File

@@ -127,14 +127,6 @@ Innerhalb der Funktion können Sie alle Attribute des Modellobjekts direkt verwe
{* ../../docs_src/body/tutorial002_py310.py *}
/// info | Info
In Pydantic v1 hieß die Methode `.dict()`, sie wurde in Pydantic v2 deprecatet (aber weiterhin unterstützt) und in `.model_dump()` umbenannt.
Die Beispiele hier verwenden `.dict()` zur Kompatibilität mit Pydantic v1, aber Sie sollten stattdessen `.model_dump()` verwenden, wenn Sie Pydantic v2 nutzen können.
///
## Requestbody- + Pfad-Parameter { #request-body-path-parameters }
Sie können Pfad-Parameter und den Requestbody gleichzeitig deklarieren.

View File

@@ -22,21 +22,13 @@ Hier ist eine allgemeine Idee, wie die Modelle mit ihren Passwortfeldern aussehe
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
/// info | Info
### Über `**user_in.model_dump()` { #about-user-in-model-dump }
In Pydantic v1 hieß die Methode `.dict()`, in Pydantic v2 wurde sie <abbr title="veraltet, obsolet: Es soll nicht mehr verwendet werden">deprecatet</abbr> (aber weiterhin unterstützt) und in `.model_dump()` umbenannt.
Die Beispiele hier verwenden `.dict()` für die Kompatibilität mit Pydantic v1, aber Sie sollten `.model_dump()` verwenden, wenn Sie Pydantic v2 verwenden können.
///
### Über `**user_in.dict()` { #about-user-in-dict }
#### Die `.dict()`-Methode von Pydantic { #pydantics-dict }
#### Pydantics `.model_dump()` { #pydantics-model-dump }
`user_in` ist ein Pydantic-Modell der Klasse `UserIn`.
Pydantic-Modelle haben eine `.dict()`-Methode, die ein <abbr title="Dictionary Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> mit den Daten des Modells zurückgibt.
Pydantic-Modelle haben eine `.model_dump()`-Methode, die ein <abbr title="Dictionary Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> mit den Daten des Modells zurückgibt.
Wenn wir also ein Pydantic-Objekt `user_in` erstellen, etwa so:
@@ -47,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
und dann aufrufen:
```Python
user_dict = user_in.dict()
user_dict = user_in.model_dump()
```
haben wir jetzt ein `dict` mit den Daten in der Variablen `user_dict` (es ist ein `dict` statt eines Pydantic-Modellobjekts).
@@ -103,20 +95,20 @@ UserInDB(
#### Ein Pydantic-Modell aus dem Inhalt eines anderen { #a-pydantic-model-from-the-contents-of-another }
Da wir im obigen Beispiel `user_dict` von `user_in.dict()` bekommen haben, wäre dieser Code:
Da wir im obigen Beispiel `user_dict` von `user_in.model_dump()` bekommen haben, wäre dieser Code:
```Python
user_dict = user_in.dict()
user_dict = user_in.model_dump()
UserInDB(**user_dict)
```
gleichwertig zu:
```Python
UserInDB(**user_in.dict())
UserInDB(**user_in.model_dump())
```
... weil `user_in.dict()` ein `dict` ist, und dann lassen wir Python es „entpacken“, indem wir es an `UserInDB` mit vorangestelltem `**` übergeben.
... weil `user_in.model_dump()` ein `dict` ist, und dann lassen wir Python es „entpacken“, indem wir es an `UserInDB` mit vorangestelltem `**` übergeben.
Auf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pydantic-Modells.
@@ -125,7 +117,7 @@ Auf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pyd
Und dann fügen wir das zusätzliche Schlüsselwort-Argument `hashed_password=hashed_password` hinzu, wie in:
```Python
UserInDB(**user_in.dict(), hashed_password=hashed_password)
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
```
... was so ist wie:
@@ -180,7 +172,6 @@ Wenn Sie eine <a href="https://docs.pydantic.dev/latest/concepts/types/#unions"
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
### `Union` in Python 3.10 { #union-in-python-3-10 }
In diesem Beispiel übergeben wir `Union[PlaneItem, CarItem]` als Wert des Arguments `response_model`.
@@ -203,7 +194,6 @@ Dafür verwenden Sie Pythons Standard-`typing.List` (oder nur `list` in Python 3
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
## Response mit beliebigem `dict` { #response-with-arbitrary-dict }
Sie können auch eine Response deklarieren, die ein beliebiges `dict` zurückgibt, indem Sie nur die Typen der Schlüssel und Werte ohne ein Pydantic-Modell deklarieren.
@@ -214,7 +204,6 @@ In diesem Fall können Sie `typing.Dict` verwenden (oder nur `dict` in Python 3.
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
## Zusammenfassung { #recap }
Verwenden Sie gerne mehrere Pydantic-Modelle und vererben Sie je nach Bedarf.

View File

@@ -205,20 +205,6 @@ Wenn Sie sich mit all diesen **„regulärer Ausdruck“**-Ideen verloren fühle
Aber nun wissen Sie, dass Sie sie in **FastAPI** immer dann verwenden können, wenn Sie sie brauchen.
### Pydantic v1 `regex` statt `pattern` { #pydantic-v1-regex-instead-of-pattern }
Vor Pydantic Version 2 und FastAPI 0.100.0, hieß der Parameter `regex` statt `pattern`, aber das ist jetzt obsolet.
Sie könnten immer noch Code sehen, der den alten Namen verwendet:
//// tab | Pydantic v1
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
////
Beachten Sie aber, dass das obsolet ist und auf den neuen Parameter `pattern` aktualisiert werden sollte. 🤓
## Defaultwerte { #default-values }
Natürlich können Sie Defaultwerte verwenden, die nicht `None` sind.

View File

@@ -252,20 +252,6 @@ Wenn Sie also den Artikel mit der ID `foo` bei der *Pfadoperation* anfragen, wir
/// info | Info
In Pydantic v1 hieß diese Methode `.dict()`, in Pydantic v2 wurde sie <abbr title="veraltet, obsolet: Es soll nicht mehr verwendet werden">deprecatet</abbr> (aber immer noch unterstützt) und in `.model_dump()` umbenannt.
Die Beispiele hier verwenden `.dict()` für die Kompatibilität mit Pydantic v1, Sie sollten jedoch stattdessen `.model_dump()` verwenden, wenn Sie Pydantic v2 verwenden können.
///
/// info | Info
FastAPI verwendet `.dict()` von Pydantic Modellen, <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">mit dessen `exclude_unset`-Parameter</a>, um das zu erreichen.
///
/// info | Info
Sie können auch:
* `response_model_exclude_defaults=True`

View File

@@ -8,36 +8,14 @@ Hier sind mehrere Möglichkeiten, das zu tun.
Sie können `examples` („Beispiele“) für ein Pydantic-Modell deklarieren, welche dem generierten JSON-Schema hinzugefügt werden.
//// tab | Pydantic v2
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
////
//// tab | Pydantic v1
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
////
Diese zusätzlichen Informationen werden unverändert zum für dieses Modell ausgegebenen **JSON-Schema** hinzugefügt und in der API-Dokumentation verwendet.
//// tab | Pydantic v2
In Pydantic Version 2 würden Sie das Attribut `model_config` verwenden, das ein <abbr title="Dictionary Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> akzeptiert, wie beschrieben in <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Pydantic-Dokumentation: Configuration</a>.
Sie können das Attribut `model_config` verwenden, das ein <abbr title="Dictionary Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt">`dict`</abbr> akzeptiert, wie beschrieben in <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">Pydantic-Dokumentation: Configuration</a>.
Sie können `json_schema_extra` setzen, mit einem `dict`, das alle zusätzlichen Daten enthält, die im generierten JSON-Schema angezeigt werden sollen, einschließlich `examples`.
////
//// tab | Pydantic v1
In Pydantic Version 1 würden Sie eine interne Klasse `Config` und `schema_extra` verwenden, wie beschrieben in <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic-Dokumentation: Schema customization</a>.
Sie können `schema_extra` setzen, mit einem `dict`, das alle zusätzlichen Daten enthält, die im generierten JSON-Schema angezeigt werden sollen, einschließlich `examples`.
////
/// tip | Tipp
Mit derselben Technik können Sie das JSON-Schema erweitern und Ihre eigenen benutzerdefinierten Zusatzinformationen hinzufügen.

View File

@@ -4,213 +4,197 @@ Translate to German (Deutsch).
Language code: de.
### Definitions
"hyphen"
The character «-»
Unicode U+002D (HYPHEN-MINUS)
Alternative names: hyphen, dash, minus sign
"dash"
The character «–»
Unicode U+2013 (EN DASH)
German name: Halbgeviertstrich
### Grammar to use when talking to the reader
Use the formal grammar (use «Sie» instead of «Du»).
Use the formal grammar (use `Sie` instead of `Du`).
### Quotes
1) Convert neutral double quotes («"») and English double typographic quotes («“» and «”») to German double typographic quotes («„» and «“»). Convert neutral single quotes («'») and English single typographic quotes («‘» and «’») to German single typographic quotes («‚» and «‘»). Do NOT convert «`"» to «„», do NOT convert «"`» to «“».
1) Convert neutral double quotes (`"`) to German double typographic quotes (`„` and `“`). Convert neutral single quotes (`'`) to German single typographic quotes (`` and ``).
Do NOT convert quotes in code snippets and code blocks to their German typographic equivalents.
Examples:
Source (English):
Source (English):
«««
"Hello world"
“Hello Universe”
"He said: 'Hello'"
“my name is Nils
`"__main__"`
`"items"`
»»»
```
"Hello world"
“Hello Universe”
"He said: 'Hello'"
“my name is Nils
`"__main__"`
`"items"`
```
Result (German):
«««
„Hallo Welt“
„Hallo Universum“
„Er sagte: Hallo
„Mein Name ist Nils
`"__main__"`
`"items"`
»»»
Result (German):
```
„Hallo Welt“
„Hallo Universum“
„Er sagte: Hallo
„Mein Name ist Nils
`"__main__"`
`"items"`
```
### Ellipsis
1) Make sure there is a space between an ellipsis and a word following or preceding the ellipsis.
- Make sure there is a space between an ellipsis and a word following or preceding the ellipsis.
Examples:
Source (English):
Source (English):
«««
...as we intended.
...this would work:
...etc.
others...
More to come...
»»»
```
...as we intended.
...this would work:
...etc.
others...
More to come...
```
Result (German):
Result (German):
«««
... wie wir es beabsichtigt hatten.
... das würde funktionieren:
... usw.
Andere ...
Später mehr ...
»»»
2) This does not apply in URLs, code blocks, and code snippets. Do not remove or add spaces there.
```
... wie wir es beabsichtigt hatten.
... das würde funktionieren:
... usw.
Andere ...
Später mehr ...
```
- This does not apply in URLs, code blocks, and code snippets. Do not remove or add spaces there.
### Headings
1) Translate headings using the infinite form.
- Translate headings using the infinite form.
Examples:
Source (English):
Source (English):
«««
## Create a Project { #create-a-project }
»»»
```
## Create a Project { #create-a-project }
```
Translate with (German):
Result (German):
«««
## Ein Projekt erstellen { #create-a-project }
»»»
```
## Ein Projekt erstellen { #create-a-project }
```
Do NOT translate with (German):
Do NOT translate with (German):
«««
## Erstellen Sie ein Projekt { #create-a-project }
»»»
```
## Erstellen Sie ein Projekt { #create-a-project }
```
Source (English):
Source (English):
«««
# Install Packages { #install-packages }
»»»
```
# Install Packages { #install-packages }
```
Translate with (German):
Translate with (German):
«««
# Pakete installieren { #install-packages }
»»»
```
# Pakete installieren { #install-packages }
```
Do NOT translate with (German):
Do NOT translate with (German):
«««
# Installieren Sie Pakete { #install-packages }
»»»
```
# Installieren Sie Pakete { #install-packages }
```
Source (English):
Source (English):
«««
### Run Your Program { #run-your-program }
»»»
```
### Run Your Program { #run-your-program }
```
Translate with (German):
Translate with (German):
«««
### Ihr Programm ausführen { #run-your-program }
»»»
```
### Ihr Programm ausführen { #run-your-program }
```
Do NOT translate with (German):
Do NOT translate with (German):
«««
### Führen Sie Ihr Programm aus { #run-your-program }
»»»
```
### Führen Sie Ihr Programm aus { #run-your-program }
```
2) Make sure that the translated part of the heading does not end with a period.
- Make sure that the translated part of the heading does not end with a period.
Example:
Source (English):
Source (English):
«««
## Another module with `APIRouter` { #another-module-with-apirouter }
»»»
```
## Another module with `APIRouter` { #another-module-with-apirouter }
```
Translate with (German):
Translate with (German):
«««
## Ein weiteres Modul mit `APIRouter` { #another-module-with-apirouter }
»»»
```
## Ein weiteres Modul mit `APIRouter` { #another-module-with-apirouter }
```
Do NOT translate with (German) notice the added period:
Do NOT translate with (German) notice the added period:
«««
## Ein weiteres Modul mit `APIRouter`. { #another-module-with-apirouter }
»»»
```
## Ein weiteres Modul mit `APIRouter`. { #another-module-with-apirouter }
```
3) Replace occurrences of literal « - » (a space followed by a hyphen followed by a space) with « » (a space followed by a dash followed by a space) in the translated part of the heading.
- Replace occurrences of literal ` - ` (a space followed by a hyphen followed by a space) with ` ` (a space followed by a dash followed by a space) in the translated part of the heading.
Example:
Source (English):
Source (English):
«««
# FastAPI in Containers - Docker { #fastapi-in-containers-docker }
»»»
```
# FastAPI in Containers - Docker { #fastapi-in-containers-docker }
```
Translate with (German) notice the dash:
Translate with (German) notice the dash:
«««
# FastAPI in Containern Docker { #fastapi-in-containers-docker }
»»»
```
# FastAPI in Containern Docker { #fastapi-in-containers-docker }
```
Do NOT translate with (German) notice the hyphen:
Do NOT translate with (German) notice the hyphen:
«««
# FastAPI in Containern - Docker { #fastapi-in-containers-docker }
»»»
```
# FastAPI in Containern - Docker { #fastapi-in-containers-docker }
```
3.1) Do not apply rule 3 when there is no space before or no space after the hyphen.
- Do not apply rule 3 when there is no space before or no space after the hyphen.
Example:
Source (English):
Source (English):
«««
## Type hints and annotations { #type-hints-and-annotations }
»»»
```
## Type hints and annotations { #type-hints-and-annotations }
```
Translate with (German) notice the hyphen:
Translate with (German) - notice the hyphen:
«««
## Typhinweise und -annotationen { #type-hints-and-annotations }
»»»
```
## Typhinweise und -annotationen { #type-hints-and-annotations }
```
Do NOT translate with (German) notice the dash:
Do NOT translate with (German) - notice the dash:
«««
## Typhinweise und annotationen { #type-hints-and-annotations }
»»»
```
## Typhinweise und annotationen { #type-hints-and-annotations }
```
3.2) Do not apply rule 3 to the untranslated part of the heading inside curly brackets, which you shall not translate.
- Do not modify the hyphens in the content in headers inside of curly braces, which you shall not translate.
### German instructions, when to use and when not to use hyphens in words (written in first person, which is you)
### German instructions, when to use and when not to use hyphens in words (written in first person, which is you).
In der Regel versuche ich so weit wie möglich Worte zusammenzuschreiben, also ohne Bindestrich, es sei denn, es ist Konkretesding-Klassevondingen, etwa «Pydantic-Modell» (aber: «Datenbankmodell»), «Python-Modul» (aber: «Standardmodul»). Ich setze auch einen Bindestrich, wenn er die gleichen Buchstaben verbindet, etwa «Enum-Member», «Cloud-Dienst», «Template-Engine». Oder wenn das Wort sonst einfach zu lang wird, etwa, «Performance-Optimierung». Oder um etwas visuell besser zu dokumentieren, etwa «Pfadoperation-Dekorator», «Pfadoperation-Funktion».
@@ -219,122 +203,122 @@ In der Regel versuche ich so weit wie möglich Worte zusammenzuschreiben, also o
Ich versuche nicht, alles einzudeutschen. Das bezieht sich besonders auf Begriffe aus dem Bereich der Programmierung. Ich wandele zwar korrekt in Großschreibung um und setze Bindestriche, wo notwendig, aber ansonsten lasse ich solch ein Wort unverändert. Beispielsweise wird aus dem englischen Wort «string» in der deutschen Übersetzung «String», aber nicht «Zeichenkette». Oder aus dem englischen Wort «request body» wird in der deutschen Übersetzung «Requestbody», aber nicht «Anfragekörper». Oder aus dem englischen «response» wird im Deutschen «Response», aber nicht «Antwort».
### List of English terms and their preferred German translations
Below is a list of English terms and their preferred German translations, separated by a colon («:»). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them. In the below list, a term or a translation may be followed by an explanation in brackets, which explains when to translate the term this way. If a translation is preceded by «NOT», then that means: do NOT use this translation for this term. English nouns, starting with the word «the», have the German genus «der», «die», «das» prepended to their German translation, to help you to grammatically decline them in the translation. They are given in singular case, unless they have «(plural)» attached, which means they are given in plural case. Verbs are given in the full infinitive starting with the word «to».
Below is a list of English terms and their preferred German translations, separated by a colon (:). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them. In the below list, a term or a translation may be followed by an explanation in brackets, which explains when to translate the term this way. If a translation is preceded by `NOT`, then that means: do NOT use this translation for this term. English nouns, starting with the word `the`, have the German genus `der`, `die`, `das` prepended to their German translation, to help you to grammatically decline them in the translation. They are given in singular case, unless they have `(plural)` attached, which means they are given in plural case. Verbs are given in the full infinitive starting with the word `to`.
* «/// check»: «/// check | Testen»
* «/// danger»: «/// danger | Gefahr»
* «/// info»: «/// info | Info»
* «/// note | Technical Details»: «/// note | Technische Details»
* «/// note»: «/// note | Hinweis»
* «/// tip»: «/// tip | Tipp»
* «/// warning»: «/// warning | Achtung»
* «you»: «Sie»
* «your»: «Ihr»
* «e.g»: «z. B.»
* «etc.»: «usw.»
* «ref»: «Ref.»
* «the Tutorial - User guide»: «das Tutorial Benutzerhandbuch»
* «the Advanced User Guide»: «das Handbuch für fortgeschrittene Benutzer»
* «the SQLModel docs»: «die SQLModel-Dokumentation»
* «the docs»: «die Dokumentation» (use singular case)
* «the env var»: «die Umgebungsvariable»
* «the `PATH` environment variable»: «die `PATH`-Umgebungsvariable»
* «the `PATH`»: «der `PATH`»
* «the `requirements.txt`»: «die `requirements.txt`»
* «the API Router»: «der API-Router»
* «the Authorization-Header»: «der Autorisierungsheader»
* «the `Authorization`-Header»: «der `Authorization`-Header»
* «the background task»: «der Hintergrundtask»
* «the button»: «der Button»
* «the cloud provider»: «der Cloudanbieter»
* «the CLI»: «Das CLI»
* «the command line interface»: «Das Kommandozeileninterface»
* «the default value»: «der Defaultwert»
* «the default value»: NOT «der Standardwert»
* «the default declaration»: «die Default-Deklaration»
* «the deployment»: «das Deployment»
* «the dict»: «das Dict»
* «the dictionary»: «das Dictionary»
* «the enumeration»: «die Enumeration»
* «the enum»: «das Enum»
* «the engine»: «die Engine»
* «the error response»: «die Error-Response»
* «the event»: «das Event»
* «the exception»: «die Exception»
* «the exception handler»: «der Exceptionhandler»
* «the form model»: «das Formularmodell»
* «the form body»: «der Formularbod
* «the header»: «der Header»
* «the headers» (plural): «die Header»
* «in headers» (plural): «in Header
* «the forwarded header»: «der Forwarded-Header»
* «the lifespan event»: «das Lifespan-Event»
* «the lock»: «der Lock»
* «the locking»: «das Locking»
* «the mobile application»: «die Mobile-Anwendung»
* «the model object»: «das Modellobjekt»
* «the mounting»: «das Mounten»
* «mounted»: «gemounte
* «the origin»: «das Origin»
* «the override»: «Die Überschreibung»
* «the parameter»: «der Parameter»
* «the parameters» (plural): «die Parameter»
* «the function parameter»: «der Funktionsparameter»
* «the default parameter»: «der Defaultparameter»
* «the body parameter»: «der Body-Parameter»
* «the request body parameter»: «der Requestbody-Parameter»
* «the path parameter»: «der Pfad-Parameter»
* «the query parameter»: «der Query-Parameter»
* «the cookie parameter»: «der Cookie-Parameter»
* «the header parameter»: «der Header-Parameter»
* «the form parameter»: «der Formular-Parameter»
* «the payload»: «die Payload»
* «the performance»: NOT «die Performance»
* «the query»: «die Query»
* «the recap»: «die Zusammenfassung»
* «the request» (what the client sends to the server): «der Request»
* «the request body»: «der Requestbody»
* «the request bodies» (plural): «die Requestbody
* «the response» (what the server sends back to the client): «die Response»
* «the return type»: «der Rückgabetyp»
* «the return value»: «der Rückgabewert»
* «the startup» (the event of the app): «der Startup»
* «the shutdown» (the event of the app): «der Shutdown»
* «the startup event»: «das Startup-Event»
* «the shutdown event»: «das Shutdown-Event»
* «the startup» (of the server): «das Hochfahren»
* «the startup» (the company): «das Startup»
* «the SDK»: «das SDK»
* «the tag»: «der Tag»
* «the type annotation»: «die Typannotation»
* «the type hint»: «der Typhinweis»
* «the wildcard»: «die Wildcard»
* «the worker class»: «die Workerklasse»
* «the worker class»: NOT «die Arbeiterklasse»
* «the worker process»: «der Workerprozess»
* «the worker process»: NOT «der Arbeiterprozess»
* «to commit»: «committen»
* «to deploy» (in the cloud): «deployen»
* «to modify»: «ändern»
* «to serve» (an application): «bereitstellen»
* «to serve» (a response): «ausliefern»
* «to serve»: NOT «bedienen»
* «to upgrade»: «aktualisieren»
* «to wrap»: «wrappen»
* «to wrap»: NOT «hüllen»
* «`foo` as a `type`»: «`foo` vom Typ `type`»
* «`foo` as a `type`»: «`foo`, ein `type`»
* «FastAPI's X»: «FastAPIs X»
* «Starlette's Y»: «Starlettes Y»
* «X is case-sensitive»: «Groß-/Klein­schrei­bung ist relevant in X»
* «X is case-insensitive»: «Groß-/Klein­schrei­bung ist nicht relevant in X»
* «standard Python»: «Standard-Python»
* «deprecated»: «deprecatet»
* /// check: /// check | Testen
* /// danger: /// danger | Gefahr
* /// info: /// info | Info
* /// note | Technical Details: /// note | Technische Details
* /// note: /// note | Hinweis
* /// tip: /// tip | Tipp
* /// warning: /// warning | Achtung
* you: Sie
* your: Ihr
* e.g: z. B.
* etc.: usw.
* ref: Ref.
* the Tutorial - User guide: das Tutorial Benutzerhandbuch
* the Advanced User Guide: das Handbuch für fortgeschrittene Benutzer
* the SQLModel docs: die SQLModel-Dokumentation
* the docs: die Dokumentation (use singular case)
* the env var: die Umgebungsvariable
* the `PATH` environment variable: die `PATH`-Umgebungsvariable
* the `PATH`: der `PATH`
* the `requirements.txt`: die `requirements.txt`
* the API Router: der API-Router
* the Authorization-Header: der Autorisierungsheader
* the `Authorization`-Header: der `Authorization`-Header
* the background task: der Hintergrundtask
* the button: der Button
* the cloud provider: der Cloudanbieter
* the CLI: Das CLI
* the coverage: Die Testabdeckung
* the command line interface: Das Kommandozeileninterface
* the default value: der Defaultwert
* the default value: NOT der Standardwert
* the default declaration: die Default-Deklaration
* the deployment: das Deployment
* the dict: das Dict
* the dictionary: das Dictionary
* the enumeration: die Enumeration
* the enum: das Enum
* the engine: die Engine
* the error response: die Error-Response
* the event: das Event
* the exception: die Exception
* the exception handler: der Exceptionhandler
* the form model: das Formularmodell
* the form body: der Formularbody
* the header: der Header
* the headers (plural): die Header
* in headers (plural): in Headern
* the forwarded header: der Forwarded-Header
* the lifespan event: das Lifespan-Event
* the lock: der Lock
* the locking: das Locking
* the mobile application: die Mobile-Anwendung
* the model object: das Modellobjekt
* the mounting: das Mounten
* mounted: gemountet
* the origin: das Origin
* the override: Die Überschreibung
* the parameter: der Parameter
* the parameters (plural): die Parameter
* the function parameter: der Funktionsparameter
* the default parameter: der Defaultparameter
* the body parameter: der Body-Parameter
* the request body parameter: der Requestbody-Parameter
* the path parameter: der Pfad-Parameter
* the query parameter: der Query-Parameter
* the cookie parameter: der Cookie-Parameter
* the header parameter: der Header-Parameter
* the form parameter: der Formular-Parameter
* the payload: die Payload
* the performance: NOT die Performance
* the query: die Query
* the recap: die Zusammenfassung
* the request (what the client sends to the server): der Request
* the request body: der Requestbody
* the request bodies (plural): die Requestbodys
* the response (what the server sends back to the client): die Response
* the return type: der Rückgabetyp
* the return value: der Rückgabewert
* the startup (the event of the app): der Startup
* the shutdown (the event of the app): der Shutdown
* the startup event: das Startup-Event
* the shutdown event: das Shutdown-Event
* the startup (of the server): das Hochfahren
* the startup (the company): das Startup
* the SDK: das SDK
* the tag: der Tag
* the type annotation: die Typannotation
* the type hint: der Typhinweis
* the wildcard: die Wildcard
* the worker class: die Workerklasse
* the worker class: NOT die Arbeiterklasse
* the worker process: der Workerprozess
* the worker process: NOT der Arbeiterprozess
* to commit: committen
* to deploy (in the cloud): deployen
* to modify: ändern
* to serve (an application): bereitstellen
* to serve (a response): ausliefern
* to serve: NOT bedienen
* to upgrade: aktualisieren
* to wrap: wrappen
* to wrap: NOT hüllen
* `foo` as a `type`: `foo` vom Typ `type`
* `foo` as a `type`: `foo`, ein `type`
* FastAPI's X: FastAPIs X
* Starlette's Y: Starlettes Y
* X is case-sensitive: Groß-/Klein­schrei­bung ist relevant in X
* X is case-insensitive: Groß-/Klein­schrei­bung ist nicht relevant in X
* standard Python: Standard-Python
* deprecated: deprecatet
### Other rules
Preserve indentation. Keep emoticons. Encode in utf-8. Use Linux line breaks (LF).
Preserve indentation. Keep emojis. Encode in utf-8. Use Linux line breaks (LF).

View File

@@ -1,6 +1,6 @@
tiangolo:
login: tiangolo
count: 808
count: 857
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
dependabot:
@@ -10,7 +10,7 @@ dependabot:
url: https://github.com/apps/dependabot
alejsdev:
login: alejsdev
count: 52
count: 53
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
url: https://github.com/alejsdev
pre-commit-ci:
@@ -18,6 +18,11 @@ pre-commit-ci:
count: 50
avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4
url: https://github.com/apps/pre-commit-ci
YuriiMotov:
login: YuriiMotov
count: 36
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
github-actions:
login: github-actions
count: 26
@@ -28,26 +33,21 @@ Kludex:
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4
url: https://github.com/Kludex
YuriiMotov:
login: YuriiMotov
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
dmontagu:
login: dmontagu
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu
svlandeg:
login: svlandeg
count: 16
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
url: https://github.com/svlandeg
nilslindemann:
login: nilslindemann
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
svlandeg:
login: svlandeg
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
url: https://github.com/svlandeg
euri10:
login: euri10
count: 13
@@ -553,6 +553,11 @@ DanielKusyDev:
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/36250676?u=2ea6114ff751fc48b55f231987a0e2582c6b1bd2&v=4
url: https://github.com/DanielKusyDev
Viicos:
login: Viicos
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/65306057?u=fcd677dc1b9bef12aa103613e5ccb3f8ce305af9&v=4
url: https://github.com/Viicos
DanielYang59:
login: DanielYang59
count: 2

View File

@@ -2,57 +2,51 @@ sponsors:
- - login: renderinc
avatarUrl: https://avatars.githubusercontent.com/u/36424661?v=4
url: https://github.com/renderinc
- login: andrew-propelauth
avatarUrl: https://avatars.githubusercontent.com/u/89474256?u=c98993dec8553c09d424ede67bbe86e5c35f48c9&v=4
url: https://github.com/andrew-propelauth
- login: blockbee-io
avatarUrl: https://avatars.githubusercontent.com/u/115143449?u=1b8620c2d6567c4df2111a371b85a51f448f9b85&v=4
url: https://github.com/blockbee-io
- login: zuplo
avatarUrl: https://avatars.githubusercontent.com/u/85497839?v=4
url: https://github.com/zuplo
- login: coderabbitai
avatarUrl: https://avatars.githubusercontent.com/u/132028505?v=4
url: https://github.com/coderabbitai
- login: greptileai
avatarUrl: https://avatars.githubusercontent.com/u/140149887?v=4
url: https://github.com/greptileai
- login: subtotal
avatarUrl: https://avatars.githubusercontent.com/u/176449348?v=4
url: https://github.com/subtotal
- login: greptileai
avatarUrl: https://avatars.githubusercontent.com/u/140149887?v=4
url: https://github.com/greptileai
- login: coderabbitai
avatarUrl: https://avatars.githubusercontent.com/u/132028505?v=4
url: https://github.com/coderabbitai
- login: zuplo
avatarUrl: https://avatars.githubusercontent.com/u/85497839?v=4
url: https://github.com/zuplo
- login: blockbee-io
avatarUrl: https://avatars.githubusercontent.com/u/115143449?u=1b8620c2d6567c4df2111a371b85a51f448f9b85&v=4
url: https://github.com/blockbee-io
- login: andrew-propelauth
avatarUrl: https://avatars.githubusercontent.com/u/89474256?u=c98993dec8553c09d424ede67bbe86e5c35f48c9&v=4
url: https://github.com/andrew-propelauth
- login: railwayapp
avatarUrl: https://avatars.githubusercontent.com/u/66716858?v=4
url: https://github.com/railwayapp
- - login: dribia
avatarUrl: https://avatars.githubusercontent.com/u/41189616?v=4
url: https://github.com/dribia
- login: svix
avatarUrl: https://avatars.githubusercontent.com/u/80175132?v=4
url: https://github.com/svix
- - login: speakeasy-api
avatarUrl: https://avatars.githubusercontent.com/u/91446104?v=4
url: https://github.com/speakeasy-api
- login: stainless-api
avatarUrl: https://avatars.githubusercontent.com/u/88061651?v=4
url: https://github.com/stainless-api
- login: speakeasy-api
avatarUrl: https://avatars.githubusercontent.com/u/91446104?v=4
url: https://github.com/speakeasy-api
- 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: permitio
avatarUrl: https://avatars.githubusercontent.com/u/71775833?v=4
url: https://github.com/permitio
- - login: Ponte-Energy-Partners
avatarUrl: https://avatars.githubusercontent.com/u/114745848?v=4
url: https://github.com/Ponte-Energy-Partners
- login: LambdaTest-Inc
- login: databento
avatarUrl: https://avatars.githubusercontent.com/u/64141749?v=4
url: https://github.com/databento
- - login: LambdaTest-Inc
avatarUrl: https://avatars.githubusercontent.com/u/171592363?u=96606606a45fa170427206199014f2a5a2a4920b&v=4
url: https://github.com/LambdaTest-Inc
- login: Ponte-Energy-Partners
avatarUrl: https://avatars.githubusercontent.com/u/114745848?v=4
url: https://github.com/Ponte-Energy-Partners
- login: BoostryJP
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
url: https://github.com/BoostryJP
- login: requestly
avatarUrl: https://avatars.githubusercontent.com/u/12287519?v=4
url: https://github.com/requestly
- login: acsone
avatarUrl: https://avatars.githubusercontent.com/u/7601056?v=4
url: https://github.com/acsone
@@ -68,9 +62,6 @@ sponsors:
- login: Doist
avatarUrl: https://avatars.githubusercontent.com/u/2565372?v=4
url: https://github.com/Doist
- login: bholagabbar
avatarUrl: https://avatars.githubusercontent.com/u/11693595?v=4
url: https://github.com/bholagabbar
- - login: mainframeindustries
avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
url: https://github.com/mainframeindustries
@@ -86,6 +77,9 @@ sponsors:
- login: ChargeStorm
avatarUrl: https://avatars.githubusercontent.com/u/26000165?v=4
url: https://github.com/ChargeStorm
- login: ibrahimpelumi6142
avatarUrl: https://avatars.githubusercontent.com/u/113442282?v=4
url: https://github.com/ibrahimpelumi6142
- login: nilslindemann
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
@@ -116,124 +110,127 @@ sponsors:
- login: Leay15
avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4
url: https://github.com/Leay15
- login: Karine-Bauch
avatarUrl: https://avatars.githubusercontent.com/u/90465103?u=7feb1018abb1a5631cfd9a91fea723d1ceb5f49b&v=4
url: https://github.com/Karine-Bauch
- login: jugeeem
avatarUrl: https://avatars.githubusercontent.com/u/116043716?u=ae590d79c38ac79c91b9c5caa6887d061e865a3d&v=4
url: https://github.com/jugeeem
- login: patsatsia
avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=3271b85f7a37b479c8d0ae0a235182e83c166edf&v=4
url: https://github.com/patsatsia
- login: anthonycepeda
avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=60bdf46240cff8fca482ff0fc07d963fd5e1a27c&v=4
url: https://github.com/anthonycepeda
- login: patricioperezv
avatarUrl: https://avatars.githubusercontent.com/u/73832292?u=5f471f156e19ee7920e62ae0f4a47b95580e61cf&v=4
url: https://github.com/patricioperezv
- login: chickenandstats
avatarUrl: https://avatars.githubusercontent.com/u/79477966?u=ae2b894aa954070db1d7830dab99b49eba4e4567&v=4
url: https://github.com/chickenandstats
- login: Karine-Bauch
avatarUrl: https://avatars.githubusercontent.com/u/90465103?u=7feb1018abb1a5631cfd9a91fea723d1ceb5f49b&v=4
url: https://github.com/Karine-Bauch
- login: kaoru0310
avatarUrl: https://avatars.githubusercontent.com/u/80977929?u=1b61d10142b490e56af932ddf08a390fae8ee94f&v=4
url: https://github.com/kaoru0310
- login: jstanden
avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4
url: https://github.com/jstanden
- login: knallgelb
avatarUrl: https://avatars.githubusercontent.com/u/2358812?u=c48cb6362b309d74cbf144bd6ad3aed3eb443e82&v=4
url: https://github.com/knallgelb
- login: dblackrun
avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4
url: https://github.com/dblackrun
- login: zsinx6
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
url: https://github.com/zsinx6
- login: kennywakeland
avatarUrl: https://avatars.githubusercontent.com/u/3631417?u=7c8f743f1ae325dfadea7c62bbf1abd6a824fc55&v=4
url: https://github.com/kennywakeland
- login: aacayaco
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
url: https://github.com/aacayaco
- login: anomaly
avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4
url: https://github.com/anomaly
- login: mj0331
avatarUrl: https://avatars.githubusercontent.com/u/3890353?u=1c627ac1a024515b4871de5c3ebbfaa1a57f65d4&v=4
url: https://github.com/mj0331
- login: gorhack
avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4
url: https://github.com/gorhack
- login: Ryandaydev
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=679ff84cb7b988c5795a5fa583857f574a055763&v=4
url: https://github.com/Ryandaydev
- login: jaredtrog
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
url: https://github.com/jaredtrog
- login: chickenandstats
avatarUrl: https://avatars.githubusercontent.com/u/79477966?u=ae2b894aa954070db1d7830dab99b49eba4e4567&v=4
url: https://github.com/chickenandstats
- login: patricioperezv
avatarUrl: https://avatars.githubusercontent.com/u/73832292?u=5f471f156e19ee7920e62ae0f4a47b95580e61cf&v=4
url: https://github.com/patricioperezv
- login: anthonycepeda
avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=60bdf46240cff8fca482ff0fc07d963fd5e1a27c&v=4
url: https://github.com/anthonycepeda
- login: AalbatrossGuy
avatarUrl: https://avatars.githubusercontent.com/u/68378354?u=0bdeea9356d24f638244131f6d8d1e2d2f3601ca&v=4
url: https://github.com/AalbatrossGuy
- login: patsatsia
avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=3271b85f7a37b479c8d0ae0a235182e83c166edf&v=4
url: https://github.com/patsatsia
- login: oliverxchen
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
url: https://github.com/oliverxchen
- login: paulcwatts
avatarUrl: https://avatars.githubusercontent.com/u/150269?u=1819e145d573b44f0ad74b87206d21cd60331d4e&v=4
url: https://github.com/paulcwatts
- login: robintw
avatarUrl: https://avatars.githubusercontent.com/u/296686?v=4
url: https://github.com/robintw
- login: pamelafox
avatarUrl: https://avatars.githubusercontent.com/u/297042?v=4
url: https://github.com/pamelafox
- login: wshayes
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
- login: koxudaxi
avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4
url: https://github.com/koxudaxi
- login: falkben
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4
url: https://github.com/falkben
- login: mintuhouse
avatarUrl: https://avatars.githubusercontent.com/u/769950?u=ecfbd79a97d33177e0d093ddb088283cf7fe8444&v=4
url: https://github.com/mintuhouse
- login: jaredtrog
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
url: https://github.com/jaredtrog
- login: Ryandaydev
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=679ff84cb7b988c5795a5fa583857f574a055763&v=4
url: https://github.com/Ryandaydev
- login: gorhack
avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4
url: https://github.com/gorhack
- login: mj0331
avatarUrl: https://avatars.githubusercontent.com/u/3890353?u=1c627ac1a024515b4871de5c3ebbfaa1a57f65d4&v=4
url: https://github.com/mj0331
- login: anomaly
avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4
url: https://github.com/anomaly
- login: aacayaco
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
url: https://github.com/aacayaco
- login: kennywakeland
avatarUrl: https://avatars.githubusercontent.com/u/3631417?u=7c8f743f1ae325dfadea7c62bbf1abd6a824fc55&v=4
url: https://github.com/kennywakeland
- login: zsinx6
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
url: https://github.com/zsinx6
- login: dblackrun
avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4
url: https://github.com/dblackrun
- login: knallgelb
avatarUrl: https://avatars.githubusercontent.com/u/2358812?u=c48cb6362b309d74cbf144bd6ad3aed3eb443e82&v=4
url: https://github.com/knallgelb
- login: dodo5522
avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4
url: https://github.com/dodo5522
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=371272f2c69e680e0559a7b0a57385e83a5dc728&v=4
url: https://github.com/wdwinslow
- login: jsoques
avatarUrl: https://avatars.githubusercontent.com/u/12414216?u=620921d94196546cc8b9eae2cc4cbc3f95bab42f&v=4
url: https://github.com/jsoques
- login: dannywade
avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4
url: https://github.com/dannywade
- login: khadrawy
avatarUrl: https://avatars.githubusercontent.com/u/13686061?u=59f25ef42ecf04c22657aac4238ce0e2d3d30304&v=4
url: https://github.com/khadrawy
- login: mjohnsey
avatarUrl: https://avatars.githubusercontent.com/u/16784016?u=38fad2e6b411244560b3af99c5f5a4751bc81865&v=4
url: https://github.com/mjohnsey
- login: ashi-agrawal
avatarUrl: https://avatars.githubusercontent.com/u/17105294?u=99c7a854035e5398d8e7b674f2d42baae6c957f8&v=4
url: https://github.com/ashi-agrawal
- login: mintuhouse
avatarUrl: https://avatars.githubusercontent.com/u/769950?u=ecfbd79a97d33177e0d093ddb088283cf7fe8444&v=4
url: https://github.com/mintuhouse
- login: falkben
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4
url: https://github.com/falkben
- login: koxudaxi
avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4
url: https://github.com/koxudaxi
- login: wshayes
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
url: https://github.com/wshayes
- login: pamelafox
avatarUrl: https://avatars.githubusercontent.com/u/297042?v=4
url: https://github.com/pamelafox
- login: robintw
avatarUrl: https://avatars.githubusercontent.com/u/296686?v=4
url: https://github.com/robintw
- login: jstanden
avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4
url: https://github.com/jstanden
- login: RaamEEIL
avatarUrl: https://avatars.githubusercontent.com/u/20320552?v=4
url: https://github.com/RaamEEIL
- login: ternaus
avatarUrl: https://avatars.githubusercontent.com/u/5481618?u=513a26b02a39e7a28d587cd37c6cc877ea368e6e&v=4
url: https://github.com/ternaus
- login: eseglem
avatarUrl: https://avatars.githubusercontent.com/u/5920492?u=208d419cf667b8ac594c82a8db01932c7e50d057&v=4
url: https://github.com/eseglem
- login: FernandoCelmer
avatarUrl: https://avatars.githubusercontent.com/u/6262214?u=58ba6d5888fa7f355934e52db19f950e20b38162&v=4
url: https://github.com/FernandoCelmer
- login: Rehket
avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4
url: https://github.com/Rehket
- login: ashi-agrawal
avatarUrl: https://avatars.githubusercontent.com/u/17105294?u=99c7a854035e5398d8e7b674f2d42baae6c957f8&v=4
url: https://github.com/ashi-agrawal
- login: mjohnsey
avatarUrl: https://avatars.githubusercontent.com/u/16784016?u=38fad2e6b411244560b3af99c5f5a4751bc81865&v=4
url: https://github.com/mjohnsey
- login: khadrawy
avatarUrl: https://avatars.githubusercontent.com/u/13686061?u=59f25ef42ecf04c22657aac4238ce0e2d3d30304&v=4
url: https://github.com/khadrawy
- login: dannywade
avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4
url: https://github.com/dannywade
- login: jsoques
avatarUrl: https://avatars.githubusercontent.com/u/12414216?u=620921d94196546cc8b9eae2cc4cbc3f95bab42f&v=4
url: https://github.com/jsoques
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=371272f2c69e680e0559a7b0a57385e83a5dc728&v=4
url: https://github.com/wdwinslow
- login: hiancdtrsnm
avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4
url: https://github.com/hiancdtrsnm
- - login: manoelpqueiroz
- login: Rehket
avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4
url: https://github.com/Rehket
- login: FernandoCelmer
avatarUrl: https://avatars.githubusercontent.com/u/6262214?u=58ba6d5888fa7f355934e52db19f950e20b38162&v=4
url: https://github.com/FernandoCelmer
- login: eseglem
avatarUrl: https://avatars.githubusercontent.com/u/5920492?u=208d419cf667b8ac594c82a8db01932c7e50d057&v=4
url: https://github.com/eseglem
- login: ternaus
avatarUrl: https://avatars.githubusercontent.com/u/5481618?u=513a26b02a39e7a28d587cd37c6cc877ea368e6e&v=4
url: https://github.com/ternaus
- - login: Artur-Galstyan
avatarUrl: https://avatars.githubusercontent.com/u/63471891?u=e8691f386037e51a737cc0ba866cd8c89e5cf109&v=4
url: https://github.com/Artur-Galstyan
- login: manoelpqueiroz
avatarUrl: https://avatars.githubusercontent.com/u/23669137?u=b12e84b28a84369ab5b30bd5a79e5788df5a0756&v=4
url: https://github.com/manoelpqueiroz
- - login: pawamoy
@@ -254,9 +251,12 @@ sponsors:
- login: hgalytoby
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=6cc9028f3db63f8f60ad21c17b1ce4b88c4e2e60&v=4
url: https://github.com/hgalytoby
- login: nisutec
avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4
url: https://github.com/nisutec
- login: johnl28
avatarUrl: https://avatars.githubusercontent.com/u/54412955?u=47dd06082d1c39caa90c752eb55566e4f3813957&v=4
url: https://github.com/johnl28
- login: danielunderwood
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood
- login: hoenie-ams
avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4
url: https://github.com/hoenie-ams
@@ -267,93 +267,87 @@ 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=db5e6f4f87836cad26c2aa90ce390ce49041c5a9&v=4
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=4771ac4e64066f0847d40e5b29910adabd9b2372&v=4
url: https://github.com/bnkc
- login: petercool
avatarUrl: https://avatars.githubusercontent.com/u/37613029?u=75aa8c6729e6e8f85a300561c4dbeef9d65c8797&v=4
url: https://github.com/petercool
- login: johnl28
avatarUrl: https://avatars.githubusercontent.com/u/54412955?u=47dd06082d1c39caa90c752eb55566e4f3813957&v=4
url: https://github.com/johnl28
- login: PunRabbit
avatarUrl: https://avatars.githubusercontent.com/u/70463212?u=1a835cfbc99295a60c8282f6aa6199d1b42241a5&v=4
url: https://github.com/PunRabbit
- login: PelicanQ
avatarUrl: https://avatars.githubusercontent.com/u/77930606?v=4
url: https://github.com/PelicanQ
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=8a80356e3e7d5a417157aba7ea565dabc8678327&v=4
url: https://github.com/WillHogan
- login: PunRabbit
avatarUrl: https://avatars.githubusercontent.com/u/70463212?u=1a835cfbc99295a60c8282f6aa6199d1b42241a5&v=4
url: https://github.com/PunRabbit
- login: my3
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
url: https://github.com/my3
- login: danielunderwood
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood
- login: ddanier
avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4
url: https://github.com/ddanier
- login: bryanculbertson
avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4
url: https://github.com/bryanculbertson
- login: slafs
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
url: https://github.com/slafs
- login: ceb10n
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
url: https://github.com/ceb10n
- login: tochikuji
avatarUrl: https://avatars.githubusercontent.com/u/851759?v=4
url: https://github.com/tochikuji
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=8a80356e3e7d5a417157aba7ea565dabc8678327&v=4
url: https://github.com/WillHogan
- login: miguelgr
avatarUrl: https://avatars.githubusercontent.com/u/1484589?u=54556072b8136efa12ae3b6902032ea2a39ace4b&v=4
url: https://github.com/miguelgr
- login: xncbf
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=a80a7bb349555b277645632ed66639ff43400614&v=4
url: https://github.com/xncbf
- login: DMantis
avatarUrl: https://avatars.githubusercontent.com/u/9536869?u=652dd0d49717803c0cbcbf44f7740e53cf2d4892&v=4
url: https://github.com/DMantis
- login: hard-coders
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
url: https://github.com/hard-coders
- login: mntolia
avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4
url: https://github.com/mntolia
- login: Zuzah
avatarUrl: https://avatars.githubusercontent.com/u/10934846?u=1ef43e075ddc87bd1178372bf4d95ee6175cae27&v=4
url: https://github.com/Zuzah
- login: TheR1D
avatarUrl: https://avatars.githubusercontent.com/u/16740832?u=b0dfdbdb27b79729430c71c6128962f77b7b53f7&v=4
url: https://github.com/TheR1D
- login: tochikuji
avatarUrl: https://avatars.githubusercontent.com/u/851759?v=4
url: https://github.com/tochikuji
- login: ceb10n
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
url: https://github.com/ceb10n
- login: slafs
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
url: https://github.com/slafs
- login: bryanculbertson
avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4
url: https://github.com/bryanculbertson
- login: ddanier
avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4
url: https://github.com/ddanier
- login: nisutec
avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4
url: https://github.com/nisutec
- login: joshuatz
avatarUrl: https://avatars.githubusercontent.com/u/17817563?u=f1bf05b690d1fc164218f0b420cdd3acb7913e21&v=4
url: https://github.com/joshuatz
- login: rangulvers
avatarUrl: https://avatars.githubusercontent.com/u/5235430?u=e254d4af4ace5a05fa58372ae677c7d26f0d5a53&v=4
url: https://github.com/rangulvers
- login: sdevkota
avatarUrl: https://avatars.githubusercontent.com/u/5250987?u=4ed9a120c89805a8aefda1cbdc0cf6512e64d1b4&v=4
url: https://github.com/sdevkota
- login: Baghdady92
avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4
url: https://github.com/Baghdady92
- login: KentShikama
avatarUrl: https://avatars.githubusercontent.com/u/6329898?u=8b236810db9b96333230430837e1f021f9246da1&v=4
url: https://github.com/KentShikama
- login: katnoria
avatarUrl: https://avatars.githubusercontent.com/u/7674948?u=09767eb13e07e09496c5fee4e5ce21d9eac34a56&v=4
url: https://github.com/katnoria
- login: harsh183
avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4
url: https://github.com/harsh183
- login: TheR1D
avatarUrl: https://avatars.githubusercontent.com/u/16740832?u=b0dfdbdb27b79729430c71c6128962f77b7b53f7&v=4
url: https://github.com/TheR1D
- login: Zuzah
avatarUrl: https://avatars.githubusercontent.com/u/10934846?u=1ef43e075ddc87bd1178372bf4d95ee6175cae27&v=4
url: https://github.com/Zuzah
- login: mntolia
avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4
url: https://github.com/mntolia
- login: hard-coders
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
url: https://github.com/hard-coders
- login: DMantis
avatarUrl: https://avatars.githubusercontent.com/u/9536869?u=652dd0d49717803c0cbcbf44f7740e53cf2d4892&v=4
url: https://github.com/DMantis
- login: xncbf
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=a80a7bb349555b277645632ed66639ff43400614&v=4
url: https://github.com/xncbf
- login: moonape1226
avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4
url: https://github.com/moonape1226
- - login: andrecorumba
avatarUrl: https://avatars.githubusercontent.com/u/37807517?u=9b9be3b41da9bda60957da9ef37b50dbf65baa61&v=4
url: https://github.com/andrecorumba
- login: KOZ39
- login: harsh183
avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4
url: https://github.com/harsh183
- login: katnoria
avatarUrl: https://avatars.githubusercontent.com/u/7674948?u=09767eb13e07e09496c5fee4e5ce21d9eac34a56&v=4
url: https://github.com/katnoria
- login: KentShikama
avatarUrl: https://avatars.githubusercontent.com/u/6329898?u=8b236810db9b96333230430837e1f021f9246da1&v=4
url: https://github.com/KentShikama
- login: Baghdady92
avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4
url: https://github.com/Baghdady92
- login: sdevkota
avatarUrl: https://avatars.githubusercontent.com/u/5250987?u=4ed9a120c89805a8aefda1cbdc0cf6512e64d1b4&v=4
url: https://github.com/sdevkota
- login: rangulvers
avatarUrl: https://avatars.githubusercontent.com/u/5235430?u=e254d4af4ace5a05fa58372ae677c7d26f0d5a53&v=4
url: https://github.com/rangulvers
- - login: KOZ39
avatarUrl: https://avatars.githubusercontent.com/u/38822500?u=9dfc0a697df1c9628f08e20dc3fb17b1afc4e5a7&v=4
url: https://github.com/KOZ39
- login: rwxd
@@ -365,27 +359,24 @@ sponsors:
- login: Olegt0rr
avatarUrl: https://avatars.githubusercontent.com/u/25399456?u=3e87b5239a2f4600975ba13be73054f8567c6060&v=4
url: https://github.com/Olegt0rr
- login: dinoz0rg
avatarUrl: https://avatars.githubusercontent.com/u/32940067?u=739cda1eb123a2dd5e1db45c361396f239e23f8b&v=4
url: https://github.com/dinoz0rg
- login: larsyngvelundin
avatarUrl: https://avatars.githubusercontent.com/u/34173819?u=74958599695bf83ac9f1addd935a51548a10c6b0&v=4
url: https://github.com/larsyngvelundin
- login: hippoley
avatarUrl: https://avatars.githubusercontent.com/u/135493401?u=1164ef48a645a7c12664fabc1638fbb7e1c459b0&v=4
url: https://github.com/hippoley
- login: 4anklee
avatarUrl: https://avatars.githubusercontent.com/u/144109238?u=a79c0d581b2a3d8f3897e7ef4c012640a6c1eb3a&v=4
url: https://github.com/4anklee
- login: andrecorumba
avatarUrl: https://avatars.githubusercontent.com/u/37807517?u=9b9be3b41da9bda60957da9ef37b50dbf65baa61&v=4
url: https://github.com/andrecorumba
- login: CoderDeltaLAN
avatarUrl: https://avatars.githubusercontent.com/u/152043745?u=4ff541efffb7d134e60c5fcf2dd1e343f90bb782&v=4
url: https://github.com/CoderDeltaLAN
- login: onestn
avatarUrl: https://avatars.githubusercontent.com/u/62360849?u=746dd21c34e7e06eefb11b03e8bb01aaae3c2a4f&v=4
url: https://github.com/onestn
- login: hippoley
avatarUrl: https://avatars.githubusercontent.com/u/135493401?u=1164ef48a645a7c12664fabc1638fbb7e1c459b0&v=4
url: https://github.com/hippoley
- login: nayasinghania
avatarUrl: https://avatars.githubusercontent.com/u/74111380?u=752e99a5e139389fdc0a0677122adc08438eb076&v=4
url: https://github.com/nayasinghania
- login: onestn
avatarUrl: https://avatars.githubusercontent.com/u/62360849?u=746dd21c34e7e06eefb11b03e8bb01aaae3c2a4f&v=4
url: https://github.com/onestn
- login: Toothwitch
avatarUrl: https://avatars.githubusercontent.com/u/1710406?u=5eebb23b46cd26e48643b9e5179536cad491c17a&v=4
url: https://github.com/Toothwitch

View File

@@ -1,495 +1,495 @@
- name: full-stack-fastapi-template
html_url: https://github.com/fastapi/full-stack-fastapi-template
stars: 39475
stars: 40334
owner_login: fastapi
owner_html_url: https://github.com/fastapi
- name: Hello-Python
html_url: https://github.com/mouredev/Hello-Python
stars: 33090
stars: 33628
owner_login: mouredev
owner_html_url: https://github.com/mouredev
- name: serve
html_url: https://github.com/jina-ai/serve
stars: 21798
stars: 21817
owner_login: jina-ai
owner_html_url: https://github.com/jina-ai
- name: HivisionIDPhotos
html_url: https://github.com/Zeyi-Lin/HivisionIDPhotos
stars: 20258
stars: 20409
owner_login: Zeyi-Lin
owner_html_url: https://github.com/Zeyi-Lin
- name: sqlmodel
html_url: https://github.com/fastapi/sqlmodel
stars: 17212
stars: 17415
owner_login: fastapi
owner_html_url: https://github.com/fastapi
- name: Douyin_TikTok_Download_API
html_url: https://github.com/Evil0ctal/Douyin_TikTok_Download_API
stars: 15145
owner_login: Evil0ctal
owner_html_url: https://github.com/Evil0ctal
- name: fastapi-best-practices
html_url: https://github.com/zhanymkanov/fastapi-best-practices
stars: 14644
stars: 15776
owner_login: zhanymkanov
owner_html_url: https://github.com/zhanymkanov
- name: Douyin_TikTok_Download_API
html_url: https://github.com/Evil0ctal/Douyin_TikTok_Download_API
stars: 15588
owner_login: Evil0ctal
owner_html_url: https://github.com/Evil0ctal
- name: machine-learning-zoomcamp
html_url: https://github.com/DataTalksClub/machine-learning-zoomcamp
stars: 12320
stars: 12447
owner_login: DataTalksClub
owner_html_url: https://github.com/DataTalksClub
- name: fastapi_mcp
html_url: https://github.com/tadata-org/fastapi_mcp
stars: 11174
owner_login: tadata-org
owner_html_url: https://github.com/tadata-org
- name: SurfSense
html_url: https://github.com/MODSetter/SurfSense
stars: 10858
stars: 12128
owner_login: MODSetter
owner_html_url: https://github.com/MODSetter
- name: fastapi_mcp
html_url: https://github.com/tadata-org/fastapi_mcp
stars: 11326
owner_login: tadata-org
owner_html_url: https://github.com/tadata-org
- name: awesome-fastapi
html_url: https://github.com/mjhea0/awesome-fastapi
stars: 10758
stars: 10901
owner_login: mjhea0
owner_html_url: https://github.com/mjhea0
- name: XHS-Downloader
html_url: https://github.com/JoeanAmier/XHS-Downloader
stars: 9313
stars: 9584
owner_login: JoeanAmier
owner_html_url: https://github.com/JoeanAmier
- name: FastUI
html_url: https://github.com/pydantic/FastUI
stars: 8915
owner_login: pydantic
owner_html_url: https://github.com/pydantic
- name: polar
html_url: https://github.com/polarsource/polar
stars: 8339
stars: 8951
owner_login: polarsource
owner_html_url: https://github.com/polarsource
- name: FastUI
html_url: https://github.com/pydantic/FastUI
stars: 8934
owner_login: pydantic
owner_html_url: https://github.com/pydantic
- name: FileCodeBox
html_url: https://github.com/vastsa/FileCodeBox
stars: 7721
stars: 7934
owner_login: vastsa
owner_html_url: https://github.com/vastsa
- name: nonebot2
html_url: https://github.com/nonebot/nonebot2
stars: 7170
stars: 7248
owner_login: nonebot
owner_html_url: https://github.com/nonebot
- name: hatchet
html_url: https://github.com/hatchet-dev/hatchet
stars: 6253
stars: 6392
owner_login: hatchet-dev
owner_html_url: https://github.com/hatchet-dev
- name: fastapi-users
html_url: https://github.com/fastapi-users/fastapi-users
stars: 5849
stars: 5899
owner_login: fastapi-users
owner_html_url: https://github.com/fastapi-users
- name: serge
html_url: https://github.com/serge-chat/serge
stars: 5756
stars: 5754
owner_login: serge-chat
owner_html_url: https://github.com/serge-chat
- name: strawberry
html_url: https://github.com/strawberry-graphql/strawberry
stars: 4569
stars: 4577
owner_login: strawberry-graphql
owner_html_url: https://github.com/strawberry-graphql
- name: chatgpt-web-share
html_url: https://github.com/chatpire/chatgpt-web-share
stars: 4294
owner_login: chatpire
owner_html_url: https://github.com/chatpire
- name: poem
html_url: https://github.com/poem-web/poem
stars: 4276
stars: 4303
owner_login: poem-web
owner_html_url: https://github.com/poem-web
- name: chatgpt-web-share
html_url: https://github.com/chatpire/chatgpt-web-share
stars: 4287
owner_login: chatpire
owner_html_url: https://github.com/chatpire
- name: dynaconf
html_url: https://github.com/dynaconf/dynaconf
stars: 4202
stars: 4221
owner_login: dynaconf
owner_html_url: https://github.com/dynaconf
- name: atrilabs-engine
html_url: https://github.com/Atri-Labs/atrilabs-engine
stars: 4093
owner_login: Atri-Labs
owner_html_url: https://github.com/Atri-Labs
- name: Kokoro-FastAPI
html_url: https://github.com/remsky/Kokoro-FastAPI
stars: 4019
stars: 4181
owner_login: remsky
owner_html_url: https://github.com/remsky
- name: atrilabs-engine
html_url: https://github.com/Atri-Labs/atrilabs-engine
stars: 4090
owner_login: Atri-Labs
owner_html_url: https://github.com/Atri-Labs
- name: devpush
html_url: https://github.com/hunvreus/devpush
stars: 4037
owner_login: hunvreus
owner_html_url: https://github.com/hunvreus
- name: logfire
html_url: https://github.com/pydantic/logfire
stars: 3805
stars: 3896
owner_login: pydantic
owner_html_url: https://github.com/pydantic
- name: LitServe
html_url: https://github.com/Lightning-AI/LitServe
stars: 3719
stars: 3756
owner_login: Lightning-AI
owner_html_url: https://github.com/Lightning-AI
- name: fastapi-admin
html_url: https://github.com/fastapi-admin/fastapi-admin
stars: 3632
owner_login: fastapi-admin
owner_html_url: https://github.com/fastapi-admin
- name: datamodel-code-generator
html_url: https://github.com/koxudaxi/datamodel-code-generator
stars: 3609
owner_login: koxudaxi
owner_html_url: https://github.com/koxudaxi
- name: huma
html_url: https://github.com/danielgtaylor/huma
stars: 3603
stars: 3702
owner_login: danielgtaylor
owner_html_url: https://github.com/danielgtaylor
- name: Yuxi-Know
html_url: https://github.com/xerrors/Yuxi-Know
stars: 3680
owner_login: xerrors
owner_html_url: https://github.com/xerrors
- name: datamodel-code-generator
html_url: https://github.com/koxudaxi/datamodel-code-generator
stars: 3675
owner_login: koxudaxi
owner_html_url: https://github.com/koxudaxi
- name: fastapi-admin
html_url: https://github.com/fastapi-admin/fastapi-admin
stars: 3659
owner_login: fastapi-admin
owner_html_url: https://github.com/fastapi-admin
- name: farfalle
html_url: https://github.com/rashadphz/farfalle
stars: 3490
stars: 3497
owner_login: rashadphz
owner_html_url: https://github.com/rashadphz
- name: tracecat
html_url: https://github.com/TracecatHQ/tracecat
stars: 3379
stars: 3421
owner_login: TracecatHQ
owner_html_url: https://github.com/TracecatHQ
- name: opyrator
html_url: https://github.com/ml-tooling/opyrator
stars: 3135
stars: 3136
owner_login: ml-tooling
owner_html_url: https://github.com/ml-tooling
- name: docarray
html_url: https://github.com/docarray/docarray
stars: 3114
stars: 3111
owner_login: docarray
owner_html_url: https://github.com/docarray
- name: devpush
html_url: https://github.com/hunvreus/devpush
stars: 3097
owner_login: hunvreus
owner_html_url: https://github.com/hunvreus
- name: fastapi-realworld-example-app
html_url: https://github.com/nsidnev/fastapi-realworld-example-app
stars: 3050
stars: 3051
owner_login: nsidnev
owner_html_url: https://github.com/nsidnev
- name: uvicorn-gunicorn-fastapi-docker
html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker
stars: 2911
owner_login: tiangolo
owner_html_url: https://github.com/tiangolo
- name: mcp-context-forge
html_url: https://github.com/IBM/mcp-context-forge
stars: 2899
stars: 3034
owner_login: IBM
owner_html_url: https://github.com/IBM
- name: best-of-web-python
html_url: https://github.com/ml-tooling/best-of-web-python
stars: 2648
owner_login: ml-tooling
owner_html_url: https://github.com/ml-tooling
- name: uvicorn-gunicorn-fastapi-docker
html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker
stars: 2904
owner_login: tiangolo
owner_html_url: https://github.com/tiangolo
- name: FastAPI-template
html_url: https://github.com/s3rius/FastAPI-template
stars: 2637
stars: 2680
owner_login: s3rius
owner_html_url: https://github.com/s3rius
- name: best-of-web-python
html_url: https://github.com/ml-tooling/best-of-web-python
stars: 2662
owner_login: ml-tooling
owner_html_url: https://github.com/ml-tooling
- name: YC-Killer
html_url: https://github.com/sahibzada-allahyar/YC-Killer
stars: 2599
stars: 2614
owner_login: sahibzada-allahyar
owner_html_url: https://github.com/sahibzada-allahyar
- name: fastapi-react
html_url: https://github.com/Buuntu/fastapi-react
stars: 2569
owner_login: Buuntu
owner_html_url: https://github.com/Buuntu
- name: Yuxi-Know
html_url: https://github.com/xerrors/Yuxi-Know
stars: 2563
owner_login: xerrors
owner_html_url: https://github.com/xerrors
- name: sqladmin
html_url: https://github.com/aminalaee/sqladmin
stars: 2558
stars: 2587
owner_login: aminalaee
owner_html_url: https://github.com/aminalaee
- name: fastapi-react
html_url: https://github.com/Buuntu/fastapi-react
stars: 2566
owner_login: Buuntu
owner_html_url: https://github.com/Buuntu
- name: RasaGPT
html_url: https://github.com/paulpierre/RasaGPT
stars: 2451
stars: 2456
owner_login: paulpierre
owner_html_url: https://github.com/paulpierre
- name: supabase-py
html_url: https://github.com/supabase/supabase-py
stars: 2344
stars: 2394
owner_login: supabase
owner_html_url: https://github.com/supabase
- name: nextpy
html_url: https://github.com/dot-agent/nextpy
stars: 2335
stars: 2338
owner_login: dot-agent
owner_html_url: https://github.com/dot-agent
- name: fastapi-utils
html_url: https://github.com/fastapiutils/fastapi-utils
stars: 2291
stars: 2289
owner_login: fastapiutils
owner_html_url: https://github.com/fastapiutils
- name: 30-Days-of-Python
html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python
stars: 2220
owner_login: codingforentrepreneurs
owner_html_url: https://github.com/codingforentrepreneurs
- name: langserve
html_url: https://github.com/langchain-ai/langserve
stars: 2215
stars: 2234
owner_login: langchain-ai
owner_html_url: https://github.com/langchain-ai
- name: 30-Days-of-Python
html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python
stars: 2232
owner_login: codingforentrepreneurs
owner_html_url: https://github.com/codingforentrepreneurs
- name: solara
html_url: https://github.com/widgetti/solara
stars: 2122
stars: 2141
owner_login: widgetti
owner_html_url: https://github.com/widgetti
- name: mangum
html_url: https://github.com/Kludex/mangum
stars: 2029
stars: 2046
owner_login: Kludex
owner_html_url: https://github.com/Kludex
- name: fastapi_best_architecture
html_url: https://github.com/fastapi-practices/fastapi_best_architecture
stars: 1963
owner_login: fastapi-practices
owner_html_url: https://github.com/fastapi-practices
- name: NoteDiscovery
html_url: https://github.com/gamosoft/NoteDiscovery
stars: 1943
owner_login: gamosoft
owner_html_url: https://github.com/gamosoft
- name: agentkit
html_url: https://github.com/BCG-X-Official/agentkit
stars: 1912
stars: 1936
owner_login: BCG-X-Official
owner_html_url: https://github.com/BCG-X-Official
- name: vue-fastapi-admin
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
stars: 1909
owner_login: mizhexiaoxiao
owner_html_url: https://github.com/mizhexiaoxiao
- name: manage-fastapi
html_url: https://github.com/ycd/manage-fastapi
stars: 1885
stars: 1887
owner_login: ycd
owner_html_url: https://github.com/ycd
- name: openapi-python-client
html_url: https://github.com/openapi-generators/openapi-python-client
stars: 1862
stars: 1879
owner_login: openapi-generators
owner_html_url: https://github.com/openapi-generators
- name: piccolo
html_url: https://github.com/piccolo-orm/piccolo
stars: 1836
owner_login: piccolo-orm
owner_html_url: https://github.com/piccolo-orm
- name: vue-fastapi-admin
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
stars: 1831
owner_login: mizhexiaoxiao
owner_html_url: https://github.com/mizhexiaoxiao
- name: python-week-2022
html_url: https://github.com/rochacbruno/python-week-2022
stars: 1817
owner_login: rochacbruno
owner_html_url: https://github.com/rochacbruno
- name: slowapi
html_url: https://github.com/laurentS/slowapi
stars: 1798
stars: 1845
owner_login: laurentS
owner_html_url: https://github.com/laurentS
- name: piccolo
html_url: https://github.com/piccolo-orm/piccolo
stars: 1843
owner_login: piccolo-orm
owner_html_url: https://github.com/piccolo-orm
- name: python-week-2022
html_url: https://github.com/rochacbruno/python-week-2022
stars: 1813
owner_login: rochacbruno
owner_html_url: https://github.com/rochacbruno
- name: fastapi-cache
html_url: https://github.com/long2ice/fastapi-cache
stars: 1789
stars: 1805
owner_login: long2ice
owner_html_url: https://github.com/long2ice
- name: ormar
html_url: https://github.com/collerek/ormar
stars: 1783
stars: 1785
owner_login: collerek
owner_html_url: https://github.com/collerek
- name: termpair
html_url: https://github.com/cs01/termpair
stars: 1716
owner_login: cs01
owner_html_url: https://github.com/cs01
- name: FastAPI-boilerplate
html_url: https://github.com/benavlabs/FastAPI-boilerplate
stars: 1660
owner_login: benavlabs
owner_html_url: https://github.com/benavlabs
- name: fastapi-langgraph-agent-production-ready-template
html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template
stars: 1638
stars: 1780
owner_login: wassim249
owner_html_url: https://github.com/wassim249
- name: langchain-serve
html_url: https://github.com/jina-ai/langchain-serve
stars: 1635
owner_login: jina-ai
owner_html_url: https://github.com/jina-ai
- name: awesome-fastapi-projects
html_url: https://github.com/Kludex/awesome-fastapi-projects
stars: 1589
owner_login: Kludex
owner_html_url: https://github.com/Kludex
- name: fastapi-pagination
html_url: https://github.com/uriyyo/fastapi-pagination
stars: 1585
owner_login: uriyyo
owner_html_url: https://github.com/uriyyo
- name: coronavirus-tracker-api
html_url: https://github.com/ExpDev07/coronavirus-tracker-api
stars: 1574
owner_login: ExpDev07
owner_html_url: https://github.com/ExpDev07
- name: FastAPI-boilerplate
html_url: https://github.com/benavlabs/FastAPI-boilerplate
stars: 1734
owner_login: benavlabs
owner_html_url: https://github.com/benavlabs
- name: termpair
html_url: https://github.com/cs01/termpair
stars: 1724
owner_login: cs01
owner_html_url: https://github.com/cs01
- name: fastapi-crudrouter
html_url: https://github.com/awtkns/fastapi-crudrouter
stars: 1559
stars: 1671
owner_login: awtkns
owner_html_url: https://github.com/awtkns
- name: langchain-serve
html_url: https://github.com/jina-ai/langchain-serve
stars: 1633
owner_login: jina-ai
owner_html_url: https://github.com/jina-ai
- name: fastapi-pagination
html_url: https://github.com/uriyyo/fastapi-pagination
stars: 1588
owner_login: uriyyo
owner_html_url: https://github.com/uriyyo
- name: awesome-fastapi-projects
html_url: https://github.com/Kludex/awesome-fastapi-projects
stars: 1583
owner_login: Kludex
owner_html_url: https://github.com/Kludex
- name: coronavirus-tracker-api
html_url: https://github.com/ExpDev07/coronavirus-tracker-api
stars: 1571
owner_login: ExpDev07
owner_html_url: https://github.com/ExpDev07
- name: bracket
html_url: https://github.com/evroon/bracket
stars: 1489
stars: 1549
owner_login: evroon
owner_html_url: https://github.com/evroon
- name: fastapi-amis-admin
html_url: https://github.com/amisadmin/fastapi-amis-admin
stars: 1475
stars: 1491
owner_login: amisadmin
owner_html_url: https://github.com/amisadmin
- name: fastapi-boilerplate
html_url: https://github.com/teamhide/fastapi-boilerplate
stars: 1436
stars: 1452
owner_login: teamhide
owner_html_url: https://github.com/teamhide
- name: awesome-python-resources
html_url: https://github.com/DjangoEx/awesome-python-resources
stars: 1426
owner_login: DjangoEx
owner_html_url: https://github.com/DjangoEx
- name: fastcrud
html_url: https://github.com/benavlabs/fastcrud
stars: 1414
stars: 1452
owner_login: benavlabs
owner_html_url: https://github.com/benavlabs
- name: awesome-python-resources
html_url: https://github.com/DjangoEx/awesome-python-resources
stars: 1430
owner_login: DjangoEx
owner_html_url: https://github.com/DjangoEx
- name: prometheus-fastapi-instrumentator
html_url: https://github.com/trallnag/prometheus-fastapi-instrumentator
stars: 1388
stars: 1399
owner_login: trallnag
owner_html_url: https://github.com/trallnag
- name: fastapi_best_architecture
html_url: https://github.com/fastapi-practices/fastapi_best_architecture
stars: 1378
owner_login: fastapi-practices
owner_html_url: https://github.com/fastapi-practices
- name: fastapi-code-generator
html_url: https://github.com/koxudaxi/fastapi-code-generator
stars: 1375
stars: 1371
owner_login: koxudaxi
owner_html_url: https://github.com/koxudaxi
- name: fastapi-tutorial
html_url: https://github.com/liaogx/fastapi-tutorial
stars: 1346
owner_login: liaogx
owner_html_url: https://github.com/liaogx
- name: budgetml
html_url: https://github.com/ebhy/budgetml
stars: 1345
owner_login: ebhy
owner_html_url: https://github.com/ebhy
- name: fastapi-tutorial
html_url: https://github.com/liaogx/fastapi-tutorial
stars: 1327
owner_login: liaogx
owner_html_url: https://github.com/liaogx
- name: fastapi-alembic-sqlmodel-async
html_url: https://github.com/jonra1993/fastapi-alembic-sqlmodel-async
stars: 1259
owner_login: jonra1993
owner_html_url: https://github.com/jonra1993
- name: fastapi-scaff
html_url: https://github.com/atpuxiner/fastapi-scaff
stars: 1255
stars: 1331
owner_login: atpuxiner
owner_html_url: https://github.com/atpuxiner
- name: bedrock-chat
html_url: https://github.com/aws-samples/bedrock-chat
stars: 1254
owner_login: aws-samples
owner_html_url: https://github.com/aws-samples
- name: bolt-python
html_url: https://github.com/slackapi/bolt-python
stars: 1253
stars: 1266
owner_login: slackapi
owner_html_url: https://github.com/slackapi
- name: bedrock-chat
html_url: https://github.com/aws-samples/bedrock-chat
stars: 1266
owner_login: aws-samples
owner_html_url: https://github.com/aws-samples
- name: fastapi-alembic-sqlmodel-async
html_url: https://github.com/jonra1993/fastapi-alembic-sqlmodel-async
stars: 1260
owner_login: jonra1993
owner_html_url: https://github.com/jonra1993
- name: fastapi_production_template
html_url: https://github.com/zhanymkanov/fastapi_production_template
stars: 1217
stars: 1222
owner_login: zhanymkanov
owner_html_url: https://github.com/zhanymkanov
- name: langchain-extract
html_url: https://github.com/langchain-ai/langchain-extract
stars: 1176
stars: 1179
owner_login: langchain-ai
owner_html_url: https://github.com/langchain-ai
- name: restish
html_url: https://github.com/rest-sh/restish
stars: 1140
stars: 1152
owner_login: rest-sh
owner_html_url: https://github.com/rest-sh
- name: odmantic
html_url: https://github.com/art049/odmantic
stars: 1138
stars: 1143
owner_login: art049
owner_html_url: https://github.com/art049
- name: authx
html_url: https://github.com/yezz123/authx
stars: 1119
stars: 1128
owner_login: yezz123
owner_html_url: https://github.com/yezz123
- name: NoteDiscovery
html_url: https://github.com/gamosoft/NoteDiscovery
stars: 1107
owner_login: gamosoft
owner_html_url: https://github.com/gamosoft
- name: flock
html_url: https://github.com/Onelevenvy/flock
stars: 1055
owner_login: Onelevenvy
owner_html_url: https://github.com/Onelevenvy
- name: fastapi-observability
html_url: https://github.com/blueswen/fastapi-observability
stars: 1038
owner_login: blueswen
owner_html_url: https://github.com/blueswen
- name: SAG
html_url: https://github.com/Zleap-AI/SAG
stars: 1104
owner_login: Zleap-AI
owner_html_url: https://github.com/Zleap-AI
- name: aktools
html_url: https://github.com/akfamily/aktools
stars: 1027
stars: 1072
owner_login: akfamily
owner_html_url: https://github.com/akfamily
- name: RuoYi-Vue3-FastAPI
html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI
stars: 1016
stars: 1063
owner_login: insistence
owner_html_url: https://github.com/insistence
- name: autollm
html_url: https://github.com/viddexa/autollm
stars: 1002
owner_login: viddexa
owner_html_url: https://github.com/viddexa
- name: titiler
html_url: https://github.com/developmentseed/titiler
stars: 999
owner_login: developmentseed
owner_html_url: https://github.com/developmentseed
- name: lanarky
html_url: https://github.com/ajndkr/lanarky
stars: 994
owner_login: ajndkr
owner_html_url: https://github.com/ajndkr
- name: every-pdf
html_url: https://github.com/DDULDDUCK/every-pdf
stars: 985
owner_login: DDULDDUCK
owner_html_url: https://github.com/DDULDDUCK
- name: flock
html_url: https://github.com/Onelevenvy/flock
stars: 1059
owner_login: Onelevenvy
owner_html_url: https://github.com/Onelevenvy
- name: fastapi-observability
html_url: https://github.com/blueswen/fastapi-observability
stars: 1046
owner_login: blueswen
owner_html_url: https://github.com/blueswen
- name: enterprise-deep-research
html_url: https://github.com/SalesforceAIResearch/enterprise-deep-research
stars: 973
stars: 1019
owner_login: SalesforceAIResearch
owner_html_url: https://github.com/SalesforceAIResearch
- name: fastapi-mail
html_url: https://github.com/sabuhish/fastapi-mail
stars: 964
owner_login: sabuhish
owner_html_url: https://github.com/sabuhish
- name: titiler
html_url: https://github.com/developmentseed/titiler
stars: 1016
owner_login: developmentseed
owner_html_url: https://github.com/developmentseed
- name: every-pdf
html_url: https://github.com/DDULDDUCK/every-pdf
stars: 1004
owner_login: DDULDDUCK
owner_html_url: https://github.com/DDULDDUCK
- name: autollm
html_url: https://github.com/viddexa/autollm
stars: 1003
owner_login: viddexa
owner_html_url: https://github.com/viddexa
- name: lanarky
html_url: https://github.com/ajndkr/lanarky
stars: 996
owner_login: ajndkr
owner_html_url: https://github.com/ajndkr

View File

@@ -15,7 +15,7 @@ sodaMelon:
url: https://github.com/sodaMelon
ceb10n:
login: ceb10n
count: 116
count: 117
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
url: https://github.com/ceb10n
tokusumi:
@@ -23,16 +23,16 @@ tokusumi:
count: 104
avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4
url: https://github.com/tokusumi
hard-coders:
login: hard-coders
count: 96
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
url: https://github.com/hard-coders
hasansezertasan:
login: hasansezertasan
count: 95
avatarUrl: https://avatars.githubusercontent.com/u/13135006?u=99f0b0f0fc47e88e8abb337b4447357939ef93e7&v=4
url: https://github.com/hasansezertasan
hard-coders:
login: hard-coders
count: 93
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
url: https://github.com/hard-coders
alv2017:
login: alv2017
count: 88
@@ -40,7 +40,7 @@ alv2017:
url: https://github.com/alv2017
nazarepiedady:
login: nazarepiedady
count: 86
count: 87
avatarUrl: https://avatars.githubusercontent.com/u/31008635?u=f69ddc4ea8bda3bdfac7aa0e2ea38de282e6ee2d&v=4
url: https://github.com/nazarepiedady
AlertRED:
@@ -48,6 +48,11 @@ AlertRED:
count: 81
avatarUrl: https://avatars.githubusercontent.com/u/15695000?u=f5a4944c6df443030409c88da7d7fa0b7ead985c&v=4
url: https://github.com/AlertRED
tiangolo:
login: tiangolo
count: 73
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
Alexandrhub:
login: Alexandrhub
count: 68
@@ -63,21 +68,16 @@ cassiobotaro:
count: 62
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=a08022b191ddbd0a6159b2981d9d878b6d5bb71f&v=4
url: https://github.com/cassiobotaro
mattwang44:
login: mattwang44
count: 61
avatarUrl: https://avatars.githubusercontent.com/u/24987826?u=58e37fb3927b9124b458945ac4c97aa0f1062d85&v=4
url: https://github.com/mattwang44
nilslindemann:
login: nilslindemann
count: 59
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
mattwang44:
login: mattwang44
count: 59
avatarUrl: https://avatars.githubusercontent.com/u/24987826?u=58e37fb3927b9124b458945ac4c97aa0f1062d85&v=4
url: https://github.com/mattwang44
tiangolo:
login: tiangolo
count: 56
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
Laineyzhang55:
login: Laineyzhang55
count: 48
@@ -88,6 +88,11 @@ Kludex:
count: 47
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4
url: https://github.com/Kludex
YuriiMotov:
login: YuriiMotov
count: 46
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
komtaki:
login: komtaki
count: 45
@@ -118,11 +123,6 @@ Winand:
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/53390?u=bb0e71a2fc3910a8e0ee66da67c33de40ea695f8&v=4
url: https://github.com/Winand
YuriiMotov:
login: YuriiMotov
count: 40
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
solomein-sv:
login: solomein-sv
count: 38
@@ -138,6 +138,11 @@ alejsdev:
count: 37
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
url: https://github.com/alejsdev
mezgoodle:
login: mezgoodle
count: 37
avatarUrl: https://avatars.githubusercontent.com/u/41520940?u=4a9c765af688389d54296845d18b8f6cd6ddf09a&v=4
url: https://github.com/mezgoodle
stlucasgarcia:
login: stlucasgarcia
count: 36
@@ -153,11 +158,6 @@ timothy-jeong:
count: 36
avatarUrl: https://avatars.githubusercontent.com/u/53824764?u=db3d0cea2f5fab64d810113c5039a369699a2774&v=4
url: https://github.com/timothy-jeong
mezgoodle:
login: mezgoodle
count: 35
avatarUrl: https://avatars.githubusercontent.com/u/41520940?u=4a9c765af688389d54296845d18b8f6cd6ddf09a&v=4
url: https://github.com/mezgoodle
rjNemo:
login: rjNemo
count: 34
@@ -173,6 +173,11 @@ akarev0:
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/53393089?u=6e528bb4789d56af887ce6fe237bea4010885406&v=4
url: https://github.com/akarev0
Vincy1230:
login: Vincy1230
count: 33
avatarUrl: https://avatars.githubusercontent.com/u/81342412?u=ab5e256a4077a4a91f3f9cd2115ba80780454cbe&v=4
url: https://github.com/Vincy1230
romashevchenko:
login: romashevchenko
count: 32
@@ -183,11 +188,6 @@ LorhanSohaky:
count: 30
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
url: https://github.com/LorhanSohaky
Vincy1230:
login: Vincy1230
count: 30
avatarUrl: https://avatars.githubusercontent.com/u/81342412?u=ab5e256a4077a4a91f3f9cd2115ba80780454cbe&v=4
url: https://github.com/Vincy1230
black-redoc:
login: black-redoc
count: 29
@@ -250,7 +250,7 @@ mycaule:
url: https://github.com/mycaule
Aruelius:
login: Aruelius
count: 24
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/25380989?u=574f8cfcda3ea77a3f81884f6b26a97068e36a9d&v=4
url: https://github.com/Aruelius
wisderfin:
@@ -263,6 +263,11 @@ OzgunCaglarArslan:
count: 24
avatarUrl: https://avatars.githubusercontent.com/u/86166426?v=4
url: https://github.com/OzgunCaglarArslan
ycd:
login: ycd
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=f1e7bae394a315da950912c92dc861a8eaf95d4c&v=4
url: https://github.com/ycd
sh0nk:
login: sh0nk
count: 23
@@ -288,11 +293,6 @@ Attsun1031:
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4
url: https://github.com/Attsun1031
ycd:
login: ycd
count: 20
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=f1e7bae394a315da950912c92dc861a8eaf95d4c&v=4
url: https://github.com/ycd
delhi09:
login: delhi09
count: 20
@@ -418,6 +418,11 @@ mattkoehne:
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/80362153?v=4
url: https://github.com/mattkoehne
maru0123-2004:
login: maru0123-2004
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4
url: https://github.com/maru0123-2004
jovicon:
login: jovicon
count: 13
@@ -443,6 +448,11 @@ impocode:
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/109408819?u=9cdfc5ccb31a2094c520f41b6087012fa9048982&v=4
url: https://github.com/impocode
waketzheng:
login: waketzheng
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/35413830?u=df19e4fd5bb928e7d086e053ef26a46aad23bf84&v=4
url: https://github.com/waketzheng
wesinalves:
login: wesinalves
count: 13
@@ -538,21 +548,16 @@ Lufa1u:
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/112495876?u=087658920ed9e74311597bdd921d8d2de939d276&v=4
url: https://github.com/Lufa1u
waketzheng:
login: waketzheng
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/35413830?u=df19e4fd5bb928e7d086e053ef26a46aad23bf84&v=4
url: https://github.com/waketzheng
KNChiu:
login: KNChiu
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/36751646?v=4
url: https://github.com/KNChiu
maru0123-2004:
login: maru0123-2004
Zhongheng-Cheng:
login: Zhongheng-Cheng
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4
url: https://github.com/maru0123-2004
avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4
url: https://github.com/Zhongheng-Cheng
mariacamilagl:
login: mariacamilagl
count: 10
@@ -608,16 +613,16 @@ nick-cjyx9:
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/119087246?u=7227a2de948c68fb8396d5beff1ee5b0e057c42e&v=4
url: https://github.com/nick-cjyx9
marcelomarkus:
login: marcelomarkus
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/20115018?u=dda090ce9160ef0cd2ff69b1e5ea741283425cba&v=4
url: https://github.com/marcelomarkus
lucasbalieiro:
login: lucasbalieiro
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/37416577?u=dad91601ee4f40458d691774ec439aff308344d7&v=4
avatarUrl: https://avatars.githubusercontent.com/u/37416577?u=d144221c34c08adac8b20e1833d776ffa1c4b1d0&v=4
url: https://github.com/lucasbalieiro
Zhongheng-Cheng:
login: Zhongheng-Cheng
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4
url: https://github.com/Zhongheng-Cheng
RunningIkkyu:
login: RunningIkkyu
count: 9
@@ -668,11 +673,6 @@ yodai-yodai:
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/7031039?u=4f3593f5931892b931a745cfab846eff6e9332e7&v=4
url: https://github.com/yodai-yodai
marcelomarkus:
login: marcelomarkus
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/20115018?u=dda090ce9160ef0cd2ff69b1e5ea741283425cba&v=4
url: https://github.com/marcelomarkus
JoaoGustavoRogel:
login: JoaoGustavoRogel
count: 9
@@ -683,6 +683,11 @@ Yarous:
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/61277193?u=5b462347458a373b2d599c6f416d2b75eddbffad&v=4
url: https://github.com/Yarous
Pyth3rEx:
login: Pyth3rEx
count: 9
avatarUrl: https://avatars.githubusercontent.com/u/26427764?u=087724f74d813c95925d51e354554bd4b6d6bb60&v=4
url: https://github.com/Pyth3rEx
dimaqq:
login: dimaqq
count: 8
@@ -1023,6 +1028,11 @@ devluisrodrigues:
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/21125286?v=4
url: https://github.com/11kkw
EdmilsonRodrigues:
login: EdmilsonRodrigues
count: 5
avatarUrl: https://avatars.githubusercontent.com/u/62777025?u=217d6f3cd6cc750bb8818a3af7726c8d74eb7c2d&v=4
url: https://github.com/EdmilsonRodrigues
lpdswing:
login: lpdswing
count: 4
@@ -1163,6 +1173,11 @@ AbolfazlKameli:
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/120686133?u=af8f025278cce0d489007071254e4055df60b78c&v=4
url: https://github.com/AbolfazlKameli
SBillion:
login: SBillion
count: 4
avatarUrl: https://avatars.githubusercontent.com/u/1070649?u=3ab493dfc88b39da0eb1600e3b8e7df1c90a5dee&v=4
url: https://github.com/SBillion
tyronedamasceno:
login: tyronedamasceno
count: 3
@@ -1211,7 +1226,7 @@ phamquanganh31101998:
peebbv6364:
login: peebbv6364
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/26784747?u=75583df215ee01a5cd2dc646aecb81e7dbd33d06&v=4
avatarUrl: https://avatars.githubusercontent.com/u/26784747?u=3bf07017eb4f4fa3639ba8d4ed19980a34bf8f90&v=4
url: https://github.com/peebbv6364
mrparalon:
login: mrparalon
@@ -1413,11 +1428,6 @@ Mohammad222PR:
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/116789737?u=25810a5fe049d2f1618e2e7417cea011cc353ce4&v=4
url: https://github.com/Mohammad222PR
EdmilsonRodrigues:
login: EdmilsonRodrigues
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/62777025?u=217d6f3cd6cc750bb8818a3af7726c8d74eb7c2d&v=4
url: https://github.com/EdmilsonRodrigues
blaisep:
login: blaisep
count: 2
@@ -1838,11 +1848,11 @@ NavesSapnis:
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/79222417?u=b5b10291b8e9130ca84fd20f0a641e04ed94b6b1&v=4
url: https://github.com/NavesSapnis
eqsdxr:
login: eqsdxr
isgin01:
login: isgin01
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=7927dc0366995334f9a18c3204a41d3a34d6d96f&v=4
url: https://github.com/eqsdxr
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=ddffde10876b50f35dc90d1337f507a630530a6a&v=4
url: https://github.com/isgin01
syedasamina56:
login: syedasamina56
count: 2

View File

@@ -1,6 +1,6 @@
nilslindemann:
login: nilslindemann
count: 125
count: 130
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
jaystone776:
@@ -28,6 +28,11 @@ SwftAlpc:
count: 23
avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4
url: https://github.com/SwftAlpc
tiangolo:
login: tiangolo
count: 22
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
hasansezertasan:
login: hasansezertasan
count: 22
@@ -46,7 +51,7 @@ AlertRED:
hard-coders:
login: hard-coders
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
url: https://github.com/hard-coders
Joao-Pedro-P-Holanda:
login: Joao-Pedro-P-Holanda
@@ -103,11 +108,6 @@ pablocm83:
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/28315068?u=3310fbb05bb8bfc50d2c48b6cb64ac9ee4a14549&v=4
url: https://github.com/pablocm83
tiangolo:
login: tiangolo
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
ptt3199:
login: ptt3199
count: 7
@@ -126,13 +126,18 @@ batlopes:
lucasbalieiro:
login: lucasbalieiro
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/37416577?u=dad91601ee4f40458d691774ec439aff308344d7&v=4
avatarUrl: https://avatars.githubusercontent.com/u/37416577?u=d144221c34c08adac8b20e1833d776ffa1c4b1d0&v=4
url: https://github.com/lucasbalieiro
Alexandrhub:
login: Alexandrhub
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
url: https://github.com/Alexandrhub
YuriiMotov:
login: YuriiMotov
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
Serrones:
login: Serrones
count: 5
@@ -358,11 +363,6 @@ ruzia:
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/24503?v=4
url: https://github.com/ruzia
YuriiMotov:
login: YuriiMotov
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
izaguerreiro:
login: izaguerreiro
count: 2

View File

@@ -6,7 +6,7 @@ Tests added here will be seen by all designers of language specific prompts.
Use as follows:
* Have a language specific prompt `docs/{language code}/llm-prompt.md`.
* Have a language specific prompt - `docs/{language code}/llm-prompt.md`.
* Do a fresh translation of this document into your desired target language (see e.g. the `translate-page` command of the `translate.py`). This will create the translation under `docs/{language code}/docs/_llm-test.md`.
* Check if things are okay in the translation.
* If necessary, improve your language specific prompt, the general prompt, or the English document.

View File

@@ -4,7 +4,7 @@ FastAPI is built on top of **Pydantic**, and I have been showing you how to use
But FastAPI also supports using <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> the same way:
{* ../../docs_src/dataclasses/tutorial001_py310.py hl[1,6:11,18:19] *}
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
This is still supported thanks to **Pydantic**, as it has <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">internal support for `dataclasses`</a>.
@@ -32,7 +32,7 @@ But if you have a bunch of dataclasses laying around, this is a nice trick to us
You can also use `dataclasses` in the `response_model` parameter:
{* ../../docs_src/dataclasses/tutorial002_py310.py hl[1,6:12,18] *}
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
The dataclass will be automatically converted to a Pydantic dataclass.
@@ -48,7 +48,7 @@ In some cases, you might still have to use Pydantic's version of `dataclasses`.
In that case, you can simply swap the standard `dataclasses` with `pydantic.dataclasses`, which is a drop-in replacement:
{* ../../docs_src/dataclasses/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
1. We still import `field` from standard `dataclasses`.

View File

@@ -6,44 +6,20 @@ First, you might want to see the basic ways to [help FastAPI and get help](help-
If you already cloned the <a href="https://github.com/fastapi/fastapi" class="external-link" target="_blank">fastapi repository</a> and you want to deep dive in the code, here are some guidelines to set up your environment.
### Virtual environment
Follow the instructions to create and activate a [virtual environment](virtual-environments.md){.internal-link target=_blank} for the internal code of `fastapi`.
### Install requirements
After activating the environment, install the required packages:
//// tab | `pip`
Create a virtual environment and install the required packages with <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
<div class="termy">
```console
$ pip install -r requirements.txt
$ uv sync
---> 100%
```
</div>
////
//// tab | `uv`
If you have <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">`uv`</a>:
<div class="termy">
```console
$ uv pip install -r requirements.txt
---> 100%
```
</div>
////
It will install all the dependencies and your local FastAPI in your local environment.
### Using your local FastAPI
@@ -56,9 +32,9 @@ That way, you don't have to "install" your local version to be able to test ever
/// note | Technical Details
This only happens when you install using this included `requirements.txt` instead of running `pip install fastapi` directly.
This only happens when you install using `uv sync` instead of running `pip install fastapi` directly.
That is because inside the `requirements.txt` file, the local version of FastAPI is marked to be installed in "editable" mode, with the `-e` option.
That is because `uv sync` will install the local version of FastAPI in "editable" mode by default.
///
@@ -201,252 +177,81 @@ as Uvicorn by default will use the port `8000`, the documentation on port `8008`
### Translations
/// warning | Attention
**Update on Translations**
We're updating the way we handle documentation translations.
Until now, we invited community members to translate pages via pull requests, which were then reviewed by at least two native speakers. While this has helped bring FastAPI to many more users, weve also run into several challenges - some languages have only a few translated pages, others are outdated and hard to maintain over time.
To improve this, were working on automation tools 🤖 to manage translations more efficiently. Once ready, documentation will be machine-translated and still reviewed by at least two native speakers ✅ before publishing. This will allow us to keep translations up-to-date while reducing the review burden on maintainers.
Whats changing now:
* 🚫 Were no longer accepting new community-submitted translation PRs.
* ⏳ Existing open PRs will be reviewed and can still be merged if completed within the next 3 weeks (since July 11 2025).
* 🌐 In the future, we will only support languages where at least three active native speakers are available to review and maintain translations.
This transition will help us keep translations more consistent and timely while better supporting our contributors 🙌. Thank you to everyone who has contributed so far — your help has been invaluable! 💖
///
Help with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀
Here are the steps to help with translations.
#### Tips and guidelines
#### Review Translation PRs
Translation pull requests are made by LLMs guided with prompts designed by the FastAPI team together with the community of native speakers for each supported language.
These translations are normally still reviewed by native speakers, and here's where you can help!
* Check the currently <a href="https://github.com/fastapi/fastapi/pulls" class="external-link" target="_blank">existing pull requests</a> for your language. You can filter the pull requests by the ones with the label for your language. For example, for Spanish, the label is <a href="https://github.com/fastapi/fastapi/pulls?q=is%3Aopen+sort%3Aupdated-desc+label%3Alang-es+label%3Aawaiting-review" class="external-link" target="_blank">`lang-es`</a>.
* Review those pull requests, requesting changes or approving them. For the languages I don't speak, I'll wait for several others to review the translation before merging.
* When reviewing a pull request, it's better not to suggest changes in the same pull request, because it is LLM generated, and it won't be possible to make sure that small individual changes are replicated in other similar sections, or that they are preserved when translating the same content again.
* Instead of adding suggestions to the translation PR, make the suggestions to the LLM prompt file for that language, in a new PR. For example, for Spanish, the LLM prompt file is at: <a href="https://github.com/fastapi/fastapi/blob/master/docs/es/llm-prompt.md" class="external-link" target="_blank">`docs/es/llm-prompt.md`</a>.
/// tip
You can <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request" class="external-link" target="_blank">add comments with change suggestions</a> to existing pull requests.
Check the docs about <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews" class="external-link" target="_blank">adding a pull request review</a> to approve it or request changes.
///
#### Subscribe to Notifications for Your Language
* Check if there's a <a href="https://github.com/fastapi/fastapi/discussions/categories/translations" class="external-link" target="_blank">GitHub Discussion</a> to coordinate translations for your language. You can subscribe to it, and when there's a new pull request to review, an automatic comment will be added to the discussion.
* If you translate pages, add a single pull request per page translated. That will make it much easier for others to review it.
* To check the 2-letter code for the language you want to translate, you can use the table <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">List of ISO 639-1 codes</a>.
#### Existing language
Let's say you want to translate a page for a language that already has translations for some pages, like Spanish.
In the case of Spanish, the 2-letter code is `es`. So, the directory for Spanish translations is located at `docs/es/`.
/// tip
The main ("official") language is English, located at `docs/en/`.
///
Now run the live server for the docs in Spanish:
<div class="termy">
```console
// Use the command "live" and pass the language code as a CLI argument
$ python ./scripts/docs.py live es
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008
<span style="color: green;">[INFO]</span> Start watching changes
<span style="color: green;">[INFO]</span> Start detecting changes
```
</div>
/// tip
Alternatively, you can perform the same steps that scripts does manually.
Go into the language directory, for the Spanish translations it's at `docs/es/`:
```console
$ cd docs/es/
```
Then run `mkdocs` in that directory:
```console
$ mkdocs serve --dev-addr 127.0.0.1:8008
```
///
Now you can go to <a href="http://127.0.0.1:8008" class="external-link" target="_blank">http://127.0.0.1:8008</a> and see your changes live.
You will see that every language has all the pages. But some pages are not translated and have an info box at the top, about the missing translation.
Now let's say that you want to add a translation for the section [Features](features.md){.internal-link target=_blank}.
* Copy the file at:
```
docs/en/docs/features.md
```
* Paste it in exactly the same location but for the language you want to translate, e.g.:
```
docs/es/docs/features.md
```
/// tip
Notice that the only change in the path and file name is the language code, from `en` to `es`.
///
If you go to your browser you will see that now the docs show your new section (the info box at the top is gone). 🎉
Now you can translate it all and see how it looks as you save the file.
#### Don't Translate these Pages
🚨 Don't translate:
* Files under `reference/`
* `release-notes.md`
* `fastapi-people.md`
* `external-links.md`
* `newsletter.md`
* `management-tasks.md`
* `management.md`
* `contributing.md`
Some of these files are updated very frequently and a translation would always be behind, or they include the main content from English source files, etc.
#### Request a New Language
Let's say that you want to request translations for a language that is not yet translated, not even some pages. For example, Latin.
If there is no discussion for that language, you can start by requesting the new language. For that, you can follow these steps:
* The first step would be for you to find other 2 people that would be willing to be reviewing translation PRs for that language with you.
* Once there are at least 3 people that would be willing to commit to help maintain that language, you can continue the next steps.
* Create a new discussion following the template.
* Get a few native speakers to comment on the discussion and commit to help review translations for that language.
* Tag the other 2 people that will help with the language, and ask them to confirm there they will help.
Once there are several people in the discussion, the FastAPI team can evaluate it and can make it an official translation.
Then the docs will be automatically translated using AI, and the team of native speakers can review the translation, and help tweak the AI prompts.
Then the docs will be automatically translated using LLMs, and the team of native speakers can review the translation, and help tweak the LLM prompts.
Once there's a new translation, for example if docs are updated or there's a new section, there will be a comment in the same discussion with the link to the new translation to review.
#### New Language
## Automated Code and AI
/// note
You are encouraged to use all the tools you want to do your work and contribute as efficiently as possible, this includes AI (LLM) tools, etc. Nevertheless, contributions should have meaningful human intervention, judgement, context, etc.
These steps will be performed by the FastAPI team.
If the **human effort** put in a PR, e.g. writing LLM prompts, is **less** than the **effort we would need to put** to **review it**, please **don't** submit the PR.
///
Think of it this way: we can already write LLM prompts or run automated tools ourselves, and that would be faster than reviewing external PRs.
Checking the link from above (List of ISO 639-1 codes), you can see that the 2-letter code for Latin is `la`.
### Closing Automated and AI PRs
Now you can create a new directory for the new language, running the following script:
If we see PRs that seem AI generated or automated in similar ways, we'll flag them and close them.
<div class="termy">
The same applies to comments and descriptions, please don't copy paste the content generated by an LLM.
```console
// Use the command new-lang, pass the language code as a CLI argument
$ python ./scripts/docs.py new-lang la
### Human Effort Denial of Service
Successfully initialized: docs/la
```
Using automated tools and AI to submit PRs or comments that we have to carefully review and handle would be the equivalent of a <a href="https://en.wikipedia.org/wiki/Denial-of-service_attack" class="external-link" target="_blank">Denial-of-service attack</a> on our human effort.
</div>
It would be very little effort from the person submitting the PR (an LLM prompt) that generates a large amount of effort on our side (carefully reviewing code).
Now you can check in your code editor the newly created directory `docs/la/`.
Please don't do that.
That command created a file `docs/la/mkdocs.yml` with a simple config that inherits everything from the `en` version:
We'll need to block accounts that spam us with repeated automated PRs or comments.
```yaml
INHERIT: ../en/mkdocs.yml
```
### Use Tools Wisely
/// tip
As Uncle Ben said:
You could also simply create that file with those contents manually.
<blockquote>
With great <strike>power</strike> <strong>tools</strong> comes great responsibility.
</blockquote>
///
Avoid inadvertently doing harm.
That command also created a dummy file `docs/la/index.md` for the main page, you can start by translating that one.
You can continue with the previous instructions for an "Existing Language" for that process.
You can make the first pull request with those two files, `docs/la/mkdocs.yml` and `docs/la/index.md`. 🎉
#### Preview the result
As already mentioned above, you can use the `./scripts/docs.py` with the `live` command to preview the results (or `mkdocs serve`).
Once you are done, you can also test it all as it would look online, including all the other languages.
To do that, first build all the docs:
<div class="termy">
```console
// Use the command "build-all", this will take a bit
$ python ./scripts/docs.py build-all
Building docs for: en
Building docs for: es
Successfully built docs for: es
```
</div>
This builds all those independent MkDocs sites for each language, combines them, and generates the final output at `./site/`.
Then you can serve that with the command `serve`:
<div class="termy">
```console
// Use the command "serve" after running "build-all"
$ python ./scripts/docs.py serve
Warning: this is a very simple server. For development, use mkdocs serve instead.
This is here only to preview a site with translations already built.
Make sure you run the build-all command first.
Serving at: http://127.0.0.1:8008
```
</div>
#### Translation specific tips and guidelines
* Translate only the Markdown documents (`.md`). Do not translate the code examples at `./docs_src`.
* In code blocks within the Markdown document, translate comments (`# a comment`), but leave the rest unchanged.
* Do not change anything enclosed in "``" (inline code).
* In lines starting with `///` translate only the text part after `|`. Leave the rest unchanged.
* You can translate info boxes like `/// warning` with for example `/// warning | Achtung`. But do not change the word immediately after the `///`, it determines the color of the info box.
* Do not change the paths in links to images, code files, Markdown documents.
* However, when a Markdown document is translated, the `#hash-parts` in links to its headings may change. Update these links if possible.
* Search for such links in the translated document using the regex `#[^# ]`.
* Search in all documents already translated into your language for `your-translated-document.md`. For example VS Code has an option "Edit" -> "Find in Files".
* When translating a document, do not "pre-translate" `#hash-parts` that link to headings in untranslated documents.
You have amazing tools at hand, use them wisely to help effectively.

View File

@@ -196,31 +196,11 @@ They have contributed source code, documentation, etc. 📦
There are hundreds of other contributors, you can see them all in the <a href="https://github.com/fastapi/fastapi/graphs/contributors" class="external-link" target="_blank">FastAPI GitHub Contributors page</a>. 👷
## Top Translators
These are the **Top Translators**. 🌐
These users have created the most Pull Requests with [translations to other languages](contributing.md#translations){.internal-link target=_blank} that have been *merged*.
<div class="user-list user-list-center">
{% for user in (translators.values() | list)[:50] %}
{% if user.login not in skip_users %}
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Translations: {{ user.count }}</div></div>
{% endif %}
{% endfor %}
</div>
## Top Translation Reviewers
These users are the **Top Translation Reviewers**. 🕵️
I only speak a few languages (and not very well 😅). So, the reviewers are the ones that have the [**power to approve translations**](contributing.md#translations){.internal-link target=_blank} of the documentation. Without them, there wouldn't be documentation in several other languages.
Translation reviewers have the [**power to approve translations**](contributing.md#translations){.internal-link target=_blank} of the documentation. Without them, there wouldn't be documentation in several other languages.
<div class="user-list user-list-center">
{% for user in (translation_reviewers.values() | list)[:50] %}

View File

@@ -35,7 +35,7 @@ Depending on your use case, you might prefer to use a different library, but if
Here's a small preview of how you could integrate Strawberry with FastAPI:
{* ../../docs_src/graphql/tutorial001_py39.py hl[3,22,25] *}
{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *}
You can learn more about Strawberry in the <a href="https://strawberry.rocks/" class="external-link" target="_blank">Strawberry documentation</a>.

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View File

@@ -117,6 +117,12 @@ The key features are:
---
## FastAPI mini documentary { #fastapi-mini-documentary }
There's a <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">FastAPI mini documentary</a> released at the end of 2025, you can watch it online:
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
## **Typer**, the FastAPI of CLIs { #typer-the-fastapi-of-clis }
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>

View File

@@ -81,8 +81,14 @@ function setupTermynal() {
}
}
saveBuffer();
const inputCommands = useLines
.filter(line => line.type === "input")
.map(line => line.value)
.join("\n");
node.textContent = inputCommands;
const div = document.createElement("div");
node.replaceWith(div);
node.style.display = "none";
node.after(div);
const termynal = new Termynal(div, {
lineData: useLines,
noInit: true,

View File

@@ -74,7 +74,7 @@ Make sure you use a supported label from the <a href="https://github.com/tiangol
* `refactor`: Refactors
* This is normally for changes to the internal code that don't change the behavior. Normally it improves maintainability, or enables future features, etc.
* `upgrade`: Upgrades
* This is for upgrades to direct dependencies from the project, or extra optional dependencies, normally in `pyproject.toml`. So, things that would affect final users, they would end up receiving the upgrade in their code base once they update. But this is not for upgrades to internal dependencies used for development, testing, docs, etc. Those internal dependencies, normally in `requirements.txt` files or GitHub Action versions should be marked as `internal`, not `upgrade`.
* This is for upgrades to direct dependencies from the project, or extra optional dependencies, normally in `pyproject.toml`. So, things that would affect final users, they would end up receiving the upgrade in their code base once they update. But this is not for upgrades to internal dependencies used for development, testing, docs, etc. Those internal dependencies or GitHub Action versions should be marked as `internal`, not `upgrade`.
* `docs`: Docs
* Changes in docs. This includes updating the docs, fixing typos. But it doesn't include changes to translations.
* You can normally quickly detect it by going to the "Files changed" tab in the PR and checking if the updated file(s) starts with `docs/en/docs`. The original version of the docs is always in English, so in `docs/en/docs`.
@@ -106,135 +106,25 @@ This way, we can notice when there are new translations ready, because they have
## Merge Translation PRs
For Spanish, as I'm a native speaker and it's a language close to me, I will give it a final review myself and in most cases tweak the PR a bit before merging it.
Translations are generated automatically with LLMs and scripts.
For the other languages, confirm that:
There's one GitHub Action that can be manually run to add or update translations for a language: <a href="https://github.com/fastapi/fastapi/actions/workflows/translate.yml" class="external-link" target="_blank">`translate.yml`</a>.
* The title is correct following the instructions above.
For these language translation PRs, confirm that:
* The PR was automated (authored by @tiangolo), not made by another user.
* It has the labels `lang-all` and `lang-{lang code}`.
* The PR changes only one Markdown file adding a translation.
* Or in some cases, at most two files, if they are small, for the same language, and people reviewed them.
* If it's the first translation for that language, it will have additional `mkdocs.yml` files, for those cases follow the instructions below.
* The PR doesn't add any additional or extraneous files.
* The translation seems to have a similar structure as the original English file.
* The translation doesn't seem to change the original content, for example with obvious additional documentation sections.
* The translation doesn't use different Markdown structures, for example adding HTML tags when the original didn't have them.
* The "admonition" sections, like `tip`, `info`, etc. are not changed or translated. For example:
```
/// tip
This is a tip.
///
```
looks like this:
/// tip
This is a tip.
///
...it could be translated as:
```
/// tip
Esto es un consejo.
///
```
...but needs to keep the exact `tip` keyword. If it was translated to `consejo`, like:
```
/// consejo
Esto es un consejo.
///
```
it would change the style to the default one, it would look like:
/// consejo
Esto es un consejo.
///
Those don't have to be translated, but if they are, they need to be written as:
```
/// tip | consejo
Esto es un consejo.
///
```
Which looks like:
/// tip | consejo
Esto es un consejo.
///
## First Translation PR
When there's a first translation for a language, it will have a `docs/{lang code}/docs/index.md` translated file and a `docs/{lang code}/mkdocs.yml`.
For example, for Bosnian, it would be:
* `docs/bs/docs/index.md`
* `docs/bs/mkdocs.yml`
The `mkdocs.yml` file will have only the following content:
```YAML
INHERIT: ../en/mkdocs.yml
```
The language code would normally be in the <a href="https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes" class="external-link" target="_blank">ISO 639-1 list of language codes</a>.
In any case, the language code should be in the file <a href="https://github.com/fastapi/fastapi/blob/master/docs/language_names.yml" class="external-link" target="_blank">docs/language_names.yml</a>.
There won't be yet a label for the language code, for example, if it was Bosnian, there wouldn't be a `lang-bs`. Before creating the label and adding it to the PR, create the GitHub Discussion:
* Go to the <a href="https://github.com/fastapi/fastapi/discussions/categories/translations" class="external-link" target="_blank">Translations GitHub Discussions</a>
* Create a new discussion with the title `Bosnian Translations` (or the language name in English)
* A description of:
```Markdown
## Bosnian translations
This is the issue to track translations of the docs to Bosnian. 🚀
Here are the [PRs to review with the label `lang-bs`](https://github.com/fastapi/fastapi/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc+label%3Alang-bs+label%3A%22awaiting-review%22). 🤓
```
Update "Bosnian" with the new language.
And update the search link to point to the new language label that will be created, like `lang-bs`.
Create and add the label to that new Discussion just created, like `lang-bs`.
Then go back to the PR, and add the label, like `lang-bs`, and `lang-all` and `awaiting-review`.
Now the GitHub action will automatically detect the label `lang-bs` and will post in that Discussion that this PR is waiting to be reviewed.
* If the PR is approved by at least one native speaker, you can merge it.
## Review PRs
If a PR doesn't explain what it does or why, ask for more information.
* If a PR doesn't explain what it does or why, if it seems like it could be useful, ask for more information. Otherwise, feel free to close it.
A PR should have a specific use case that it is solving.
* If a PR seems to be spam, meaningless, only to change statistics (to appear as "contributor") or similar, you can simply mark it as `invalid`, and it will be automatically closed.
* If a PR seems to be AI generated, and seems like reviewing it would take more time from you than the time it took to write the prompt, mark it as `maybe-ai`, and it will be automatically closed.
* A PR should have a specific use case that it is solving.
* If the PR is for a feature, it should have docs.
* Unless it's a feature we want to discourage, like support for a corner case that we don't want users to use.
@@ -254,27 +144,12 @@ Every month, a GitHub Action updates the FastAPI People data. Those PRs look lik
If the tests are passing, you can merge it right away.
## External Links PRs
When people add external links they edit this file <a href="https://github.com/fastapi/fastapi/blob/master/docs/en/data/external_links.yml" class="external-link" target="_blank">external_links.yml</a>.
* Make sure the new link is in the correct category (e.g. "Podcasts") and language (e.g. "Japanese").
* A new link should be at the top of its list.
* The link URL should work (it should not return a 404).
* The content of the link should be about FastAPI.
* The new addition should have these fields:
* `author`: The name of the author.
* `link`: The URL with the content.
* `title`: The title of the link (the title of the article, podcast, etc).
After checking all these things and ensuring the PR has the right labels, you can merge it.
## Dependabot PRs
Dependabot will create PRs to update dependencies for several things, and those PRs all look similar, but some are way more delicate than others.
* If the PR is for a direct dependency, so, Dependabot is modifying `pyproject.toml`, **don't merge it**. 😱 Let me check it first. There's a good chance that some additional tweaks or updates are needed.
* If the PR updates one of the internal dependencies, for example it's modifying `requirements.txt` files, or GitHub Action versions, if the tests are passing, the release notes (shown in a summary in the PR) don't show any obvious potential breaking change, you can merge it. 😎
* If the PR is for a direct dependency, so, Dependabot is modifying `pyproject.toml` in the main dependencies, **don't merge it**. 😱 Let me check it first. There's a good chance that some additional tweaks or updates are needed.
* If the PR updates one of the internal dependencies, for example the group `dev` in `pyproject.toml`, or GitHub Action versions, if the tests are passing, the release notes (shown in a summary in the PR) don't show any obvious potential breaking change, you can merge it. 😎
## Mark GitHub Discussions Answers

View File

@@ -7,6 +7,97 @@ hide:
## Latest Changes
### Docs
* 🐛 Fix copy button in custom.js. PR [#14722](https://github.com/fastapi/fastapi/pull/14722) by [@fcharrier](https://github.com/fcharrier).
* 📝 Add contribution instructions about LLM generated code and comments and automated tools for PRs. PR [#14706](https://github.com/fastapi/fastapi/pull/14706) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update docs for management tasks. PR [#14705](https://github.com/fastapi/fastapi/pull/14705) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update docs about managing translations. PR [#14704](https://github.com/fastapi/fastapi/pull/14704) by [@tiangolo](https://github.com/tiangolo).
* 📝 Update docs for contributing with translations. PR [#14701](https://github.com/fastapi/fastapi/pull/14701) by [@tiangolo](https://github.com/tiangolo).
* 📝 Specify language code for code block. PR [#14656](https://github.com/fastapi/fastapi/pull/14656) by [@YuriiMotov](https://github.com/YuriiMotov).
### Translations
* 🌐 Update portuguese llm-prompt.md. PR [#14702](https://github.com/fastapi/fastapi/pull/14702) by [@ceb10n](https://github.com/ceb10n).
* 🌐 Update LLM prompt instructions file for French. PR [#14618](https://github.com/fastapi/fastapi/pull/14618) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translations for ko (add-missing). PR [#14699](https://github.com/fastapi/fastapi/pull/14699) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translations for ko (update-outdated). PR [#14589](https://github.com/fastapi/fastapi/pull/14589) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translations for uk (update-outdated). PR [#14587](https://github.com/fastapi/fastapi/pull/14587) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translations for es (update-outdated). PR [#14686](https://github.com/fastapi/fastapi/pull/14686) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add LLM prompt file for Turkish, generated from the existing translations. PR [#14547](https://github.com/fastapi/fastapi/pull/14547) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add LLM prompt file for Traditional Chinese, generated from the existing translations. PR [#14550](https://github.com/fastapi/fastapi/pull/14550) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add LLM prompt file for Simplified Chinese, generated from the existing translations. PR [#14549](https://github.com/fastapi/fastapi/pull/14549) by [@tiangolo](https://github.com/tiangolo).
### Internal
* ⬆ Bump actions/cache from 4 to 5. PR [#14511](https://github.com/fastapi/fastapi/pull/14511) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump actions/upload-artifact from 5 to 6. PR [#14525](https://github.com/fastapi/fastapi/pull/14525) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump actions/download-artifact from 6 to 7. PR [#14526](https://github.com/fastapi/fastapi/pull/14526) by [@dependabot[bot]](https://github.com/apps/dependabot).
* 👷 Tweak CI input names. PR [#14688](https://github.com/fastapi/fastapi/pull/14688) by [@tiangolo](https://github.com/tiangolo).
* 🔨 Refactor translation script to allow committing in place. PR [#14687](https://github.com/fastapi/fastapi/pull/14687) by [@tiangolo](https://github.com/tiangolo).
* 🐛 Fix translation script path. PR [#14685](https://github.com/fastapi/fastapi/pull/14685) by [@tiangolo](https://github.com/tiangolo).
* ✅ Enable tests in CI for scripts. PR [#14684](https://github.com/fastapi/fastapi/pull/14684) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add pre-commit local script to fix language translations. PR [#14683](https://github.com/fastapi/fastapi/pull/14683) by [@tiangolo](https://github.com/tiangolo).
* ⬆️ Migrate to uv. PR [#14676](https://github.com/fastapi/fastapi/pull/14676) by [@DoctorJohn](https://github.com/DoctorJohn).
* 🔨 Add LLM translations tool fixer. PR [#14652](https://github.com/fastapi/fastapi/pull/14652) by [@YuriiMotov](https://github.com/YuriiMotov).
* 👥 Update FastAPI People - Sponsors. PR [#14626](https://github.com/fastapi/fastapi/pull/14626) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI GitHub topic repositories. PR [#14630](https://github.com/fastapi/fastapi/pull/14630) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI People - Contributors and Translators. PR [#14625](https://github.com/fastapi/fastapi/pull/14625) by [@tiangolo](https://github.com/tiangolo).
* 🌐 Update translation prompts. PR [#14619](https://github.com/fastapi/fastapi/pull/14619) by [@tiangolo](https://github.com/tiangolo).
* 🔨 Update LLM translation script to guide reviewers to change the prompt. PR [#14614](https://github.com/fastapi/fastapi/pull/14614) by [@tiangolo](https://github.com/tiangolo).
* 👷 Do not run translations on cron while finishing updating existing languages. PR [#14613](https://github.com/fastapi/fastapi/pull/14613) by [@tiangolo](https://github.com/tiangolo).
* 🔥 Remove test variants for Pydantic v1 in test_request_params. PR [#14612](https://github.com/fastapi/fastapi/pull/14612) by [@tiangolo](https://github.com/tiangolo).
* 🔥 Remove Pydantic v1 specific test variants. PR [#14611](https://github.com/fastapi/fastapi/pull/14611) by [@tiangolo](https://github.com/tiangolo).
## 0.128.0
### Breaking Changes
* Drop support for `pydantic.v1`. PR [#14609](https://github.com/fastapi/fastapi/pull/14609) by [@tiangolo](https://github.com/tiangolo).
### Internal
* ✅ Run performance tests only on Pydantic v2. PR [#14608](https://github.com/fastapi/fastapi/pull/14608) by [@tiangolo](https://github.com/tiangolo).
## 0.127.1
### Refactors
* 🔊 Add a custom `FastAPIDeprecationWarning`. PR [#14605](https://github.com/fastapi/fastapi/pull/14605) by [@tiangolo](https://github.com/tiangolo).
### Docs
* 📝 Add documentary to website. PR [#14600](https://github.com/fastapi/fastapi/pull/14600) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🌐 Update translations for de (update-outdated). PR [#14602](https://github.com/fastapi/fastapi/pull/14602) by [@nilslindemann](https://github.com/nilslindemann).
* 🌐 Update translations for de (update-outdated). PR [#14581](https://github.com/fastapi/fastapi/pull/14581) by [@nilslindemann](https://github.com/nilslindemann).
### Internal
* 🔧 Update pre-commit to use local Ruff instead of hook. PR [#14604](https://github.com/fastapi/fastapi/pull/14604) by [@tiangolo](https://github.com/tiangolo).
* ✅ Add missing tests for code examples. PR [#14569](https://github.com/fastapi/fastapi/pull/14569) by [@YuriiMotov](https://github.com/YuriiMotov).
* 👷 Remove `lint` job from `test` CI workflow. PR [#14593](https://github.com/fastapi/fastapi/pull/14593) by [@YuriiMotov](https://github.com/YuriiMotov).
* 👷 Update secrets check. PR [#14592](https://github.com/fastapi/fastapi/pull/14592) by [@tiangolo](https://github.com/tiangolo).
* 👷 Run CodSpeed tests in parallel to other tests to speed up CI. PR [#14586](https://github.com/fastapi/fastapi/pull/14586) by [@tiangolo](https://github.com/tiangolo).
* 🔨 Update scripts and pre-commit to autofix files. PR [#14585](https://github.com/fastapi/fastapi/pull/14585) by [@tiangolo](https://github.com/tiangolo).
## 0.127.0
### Breaking Changes
* 🔊 Add deprecation warnings when using `pydantic.v1`. PR [#14583](https://github.com/fastapi/fastapi/pull/14583) by [@tiangolo](https://github.com/tiangolo).
### Translations
* 🔧 Add LLM prompt file for Korean, generated from the existing translations. PR [#14546](https://github.com/fastapi/fastapi/pull/14546) by [@tiangolo](https://github.com/tiangolo).
* 🔧 Add LLM prompt file for Japanese, generated from the existing translations. PR [#14545](https://github.com/fastapi/fastapi/pull/14545) by [@tiangolo](https://github.com/tiangolo).
### Internal
* ⬆️ Upgrade OpenAI model for translations to gpt-5.2. PR [#14579](https://github.com/fastapi/fastapi/pull/14579) by [@tiangolo](https://github.com/tiangolo).
## 0.126.0
### Upgrades

View File

@@ -56,7 +56,7 @@ from app.routers import items
The same file structure with comments:
```
```bash
.
├── app # "app" is a Python package
│   ├── __init__.py # this file makes "app" a "Python package"

View File

@@ -317,10 +317,14 @@ extra:
name: de - Deutsch
- link: /es/
name: es - español
- link: /ko/
name: ko - 한국어
- link: /pt/
name: pt - português
- link: /ru/
name: ru - русский язык
- link: /uk/
name: uk - українська мова
extra_css:
- css/termynal.css
- css/custom.css

View File

@@ -1,17 +1,17 @@
# Archivo de prueba de LLM { #llm-test-file }
Este documento prueba si el <abbr title="Large Language Model Modelo de lenguaje grande">LLM</abbr>, que traduce la documentación, entiende el `general_prompt` en `scripts/translate.py` y el prompt específico del idioma en `docs/{language code}/llm-prompt.md`. El prompt específico del idioma se agrega al final de `general_prompt`.
Este documento prueba si el <abbr title="Large Language Model - Modelo de lenguaje grande">LLM</abbr>, que traduce la documentación, entiende el `general_prompt` en `scripts/translate.py` y el prompt específico del idioma en `docs/{language code}/llm-prompt.md`. El prompt específico del idioma se agrega al final de `general_prompt`.
Las pruebas añadidas aquí serán vistas por todas las personas que diseñan prompts específicos del idioma.
Úsalo de la siguiente manera:
* Ten un prompt específico del idioma `docs/{language code}/llm-prompt.md`.
* Ten un prompt específico del idioma - `docs/{language code}/llm-prompt.md`.
* Haz una traducción fresca de este documento a tu idioma destino (mira, por ejemplo, el comando `translate-page` de `translate.py`). Esto creará la traducción en `docs/{language code}/docs/_llm-test.md`.
* Comprueba si todo está bien en la traducción.
* Revisa si las cosas están bien en la traducción.
* Si es necesario, mejora tu prompt específico del idioma, el prompt general, o el documento en inglés.
* Luego corrige manualmente los problemas restantes en la traducción para que sea una buena traducción.
* Vuelve a traducir, teniendo la buena traducción en su lugar. El resultado ideal sería que el LLM ya no hiciera cambios a la traducción. Eso significa que el prompt general y tu prompt específico del idioma están tan bien como pueden estar (a veces hará algunos cambios aparentemente aleatorios; la razón es que <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">los LLMs no son algoritmos deterministas</a>).
* Vuelve a traducir, teniendo la buena traducción en su lugar. El resultado ideal sería que el LLM ya no hiciera cambios a la traducción. Eso significa que el prompt general y tu prompt específico del idioma están tan bien como pueden estar (A veces hará algunos cambios aparentemente aleatorios; la razón es que <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">los LLMs no son algoritmos deterministas</a>).
Las pruebas:
@@ -23,7 +23,7 @@ Este es un fragmento de código: `foo`. Y este es otro fragmento de código: `ba
////
//// tab | Información
//// tab | Info
El contenido de los fragmentos de código debe dejarse tal cual.
@@ -45,7 +45,7 @@ El LLM probablemente traducirá esto mal. Lo interesante es si mantiene la tradu
////
//// tab | Información
//// tab | Info
La persona que diseña el prompt puede elegir si quiere convertir comillas neutras a comillas tipográficas. También está bien dejarlas como están.
@@ -67,7 +67,7 @@ Hardcore: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you
////
//// tab | Información
//// tab | Info
... Sin embargo, las comillas dentro de fragmentos de código deben quedarse tal cual.
@@ -112,7 +112,7 @@ works(foo="bar") # Esto funciona 🎉
////
//// tab | Información
//// tab | Info
El código en bloques de código no debe modificarse, con la excepción de los comentarios.
@@ -154,7 +154,7 @@ Algo de texto
////
//// tab | Información
//// tab | Info
Las pestañas y los bloques `Info`/`Note`/`Warning`/etc. deben tener la traducción de su título añadida después de una barra vertical (`|`).
@@ -181,7 +181,7 @@ El texto del enlace debe traducirse, la dirección del enlace debe apuntar a la
////
//// tab | Información
//// tab | Info
Los enlaces deben traducirse, pero su dirección debe permanecer sin cambios. Una excepción son los enlaces absolutos a páginas de la documentación de FastAPI. En ese caso deben enlazar a la traducción.
@@ -197,10 +197,10 @@ Aquí algunas cosas envueltas en elementos HTML "abbr" (algunas son inventadas):
### El abbr da una frase completa { #the-abbr-gives-a-full-phrase }
* <abbr title="Getting Things Done Hacer las cosas">GTD</abbr>
* <abbr title="less than menor que"><code>lt</code></abbr>
* <abbr title="XML Web Token Token web XML">XWT</abbr>
* <abbr title="Parallel Server Gateway Interface Interfaz de pasarela de servidor paralela">PSGI</abbr>
* <abbr title="Getting Things Done - Hacer las cosas">GTD</abbr>
* <abbr title="less than - menor que"><code>lt</code></abbr>
* <abbr title="XML Web Token - Token web XML">XWT</abbr>
* <abbr title="Parallel Server Gateway Interface - Interfaz de pasarela de servidor paralela">PSGI</abbr>
### El abbr da una explicación { #the-abbr-gives-an-explanation }
@@ -209,12 +209,12 @@ Aquí algunas cosas envueltas en elementos HTML "abbr" (algunas son inventadas):
### El abbr da una frase completa y una explicación { #the-abbr-gives-a-full-phrase-and-an-explanation }
* <abbr title="Mozilla Developer Network Red de Desarrolladores de Mozilla: documentación para desarrolladores, escrita por la gente de Firefox">MDN</abbr>
* <abbr title="Input/Output Entrada/Salida: lectura o escritura de disco, comunicaciones de red.">I/O</abbr>.
* <abbr title="Mozilla Developer Network - Red de Desarrolladores de Mozilla: documentación para desarrolladores, escrita por la gente de Firefox">MDN</abbr>
* <abbr title="Input/Output: lectura o escritura de disco, comunicaciones de red.">I/O</abbr>.
////
//// tab | Información
//// tab | Info
Los atributos "title" de los elementos "abbr" se traducen siguiendo instrucciones específicas.
@@ -242,7 +242,7 @@ Hola de nuevo.
////
//// tab | Información
//// tab | Info
La única regla estricta para los encabezados es que el LLM deje la parte del hash dentro de llaves sin cambios, lo que asegura que los enlaces no se rompan.
@@ -355,7 +355,7 @@ Para instrucciones específicas del idioma, mira p. ej. la sección `### Heading
* los headers
* el header de autorización
* el header `Authorization`
* el header Forwarded
* el header forwarded
* el sistema de inyección de dependencias
* la dependencia
@@ -368,7 +368,7 @@ Para instrucciones específicas del idioma, mira p. ej. la sección `### Heading
* paralelismo
* multiprocesamiento
* la variable de entorno
* la env var
* la variable de entorno
* el `PATH`
* la variable `PATH`
@@ -433,7 +433,7 @@ Para instrucciones específicas del idioma, mira p. ej. la sección `### Heading
* el motor de plantillas
* la anotación de tipos
* la anotación de tipos
* las anotaciones de tipos
* el worker del servidor
* el worker de Uvicorn
@@ -468,7 +468,7 @@ Para instrucciones específicas del idioma, mira p. ej. la sección `### Heading
* el ítem
* el paquete
* el lifespan
* el bloqueo
* el lock
* el middleware
* la aplicación móvil
* el módulo
@@ -494,7 +494,7 @@ Para instrucciones específicas del idioma, mira p. ej. la sección `### Heading
////
//// tab | Información
//// tab | Info
Esta es una lista no completa y no normativa de términos (mayormente) técnicos vistos en la documentación. Puede ayudar a la persona que diseña el prompt a identificar para qué términos el LLM necesita una mano. Por ejemplo cuando sigue revirtiendo una buena traducción a una traducción subóptima. O cuando tiene problemas conjugando/declinando un término en tu idioma.

View File

@@ -4,7 +4,7 @@ FastAPI está construido sobre **Pydantic**, y te he estado mostrando cómo usar
Pero FastAPI también soporta el uso de <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a> de la misma manera:
{* ../../docs_src/dataclasses/tutorial001_py310.py hl[1,6:11,18:19] *}
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
Esto sigue siendo soportado gracias a **Pydantic**, ya que tiene <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">soporte interno para `dataclasses`</a>.
@@ -32,7 +32,7 @@ Pero si tienes un montón de dataclasses por ahí, este es un buen truco para us
También puedes usar `dataclasses` en el parámetro `response_model`:
{* ../../docs_src/dataclasses/tutorial002_py310.py hl[1,6:12,18] *}
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
El dataclass será automáticamente convertido a un dataclass de Pydantic.
@@ -48,7 +48,7 @@ En algunos casos, todavía podrías tener que usar la versión de `dataclasses`
En ese caso, simplemente puedes intercambiar los `dataclasses` estándar con `pydantic.dataclasses`, que es un reemplazo directo:
{* ../../docs_src/dataclasses/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
1. Todavía importamos `field` de los `dataclasses` estándar.

View File

@@ -10,7 +10,7 @@ Si no eres un "experto" en OpenAPI, probablemente no necesites esto.
Puedes establecer el `operationId` de OpenAPI para ser usado en tu *path operation* con el parámetro `operation_id`.
Tienes que asegurarte de que sea único para cada operación.
Tendrías que asegurarte de que sea único para cada operación.
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
@@ -46,7 +46,7 @@ Para excluir una *path operation* del esquema OpenAPI generado (y por lo tanto,
Puedes limitar las líneas usadas del docstring de una *path operation function* para OpenAPI.
Añadir un `\f` (un carácter de separación de página escapado) hace que **FastAPI** trunque la salida usada para OpenAPI en este punto.
Añadir un `\f` (un carácter "form feed" escapado) hace que **FastAPI** trunque la salida usada para OpenAPI en este punto.
No aparecerá en la documentación, pero otras herramientas (como Sphinx) podrán usar el resto.
@@ -141,9 +141,9 @@ Podrías hacer eso con `openapi_extra`:
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el cuerpo del request ni siquiera se <abbr title="convertido de algún formato plano, como bytes, a objetos de Python">parse</abbr> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera.
En este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera se <abbr title="converted from some plain format, like bytes, into Python objects - convertido de algún formato plano, como bytes, a objetos de Python">parse</abbr> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera.
Sin embargo, podemos declarar el esquema esperado para el cuerpo del request.
Sin embargo, podemos declarar el esquema esperado para el request body.
### Tipo de contenido personalizado de OpenAPI { #custom-openapi-content-type }
@@ -153,48 +153,16 @@ Y podrías hacer esto incluso si el tipo de datos en el request no es JSON.
Por ejemplo, en esta aplicación no usamos la funcionalidad integrada de FastAPI para extraer el JSON Schema de los modelos Pydantic ni la validación automática para JSON. De hecho, estamos declarando el tipo de contenido del request como YAML, no JSON:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
////
//// tab | Pydantic v1
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[15:20, 22] *}
////
/// info | Información
En la versión 1 de Pydantic el método para obtener el JSON Schema para un modelo se llamaba `Item.schema()`, en la versión 2 de Pydantic, el método se llama `Item.model_json_schema()`.
///
Sin embargo, aunque no estamos usando la funcionalidad integrada por defecto, aún estamos usando un modelo Pydantic para generar manualmente el JSON Schema para los datos que queremos recibir en YAML.
Luego usamos el request directamente, y extraemos el cuerpo como `bytes`. Esto significa que FastAPI ni siquiera intentará parsear la carga útil del request como JSON.
Y luego en nuestro código, parseamos ese contenido YAML directamente, y nuevamente estamos usando el mismo modelo Pydantic para validar el contenido YAML:
//// tab | Pydantic v2
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
////
//// tab | Pydantic v1
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py hl[24:31] *}
////
/// info | Información
En la versión 1 de Pydantic el método para parsear y validar un objeto era `Item.parse_obj()`, en la versión 2 de Pydantic, el método se llama `Item.model_validate()`.
///
/// tip | Consejo
Aquí reutilizamos el mismo modelo Pydantic.

View File

@@ -46,12 +46,6 @@ $ pip install "fastapi[all]"
</div>
/// info | Información
En Pydantic v1 venía incluido con el paquete principal. Ahora se distribuye como este paquete independiente para que puedas elegir si instalarlo o no si no necesitas esa funcionalidad.
///
### Crear el objeto `Settings` { #create-the-settings-object }
Importa `BaseSettings` de Pydantic y crea una sub-clase, muy similar a un modelo de Pydantic.
@@ -60,31 +54,15 @@ De la misma forma que con los modelos de Pydantic, declaras atributos de clase c
Puedes usar todas las mismas funcionalidades de validación y herramientas que usas para los modelos de Pydantic, como diferentes tipos de datos y validaciones adicionales con `Field()`.
//// tab | Pydantic v2
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
////
//// tab | Pydantic v1
/// info | Información
En Pydantic v1 importarías `BaseSettings` directamente desde `pydantic` en lugar de desde `pydantic_settings`.
///
{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *}
////
/// tip | Consejo
Si quieres algo rápido para copiar y pegar, no uses este ejemplo, usa el último más abajo.
///
Luego, cuando creas una instance de esa clase `Settings` (en este caso, en el objeto `settings`), Pydantic leerá las variables de entorno de una manera indiferente a mayúsculas y minúsculas, por lo que una variable en mayúsculas `APP_NAME` aún será leída para el atributo `app_name`.
Luego, cuando creas un instance de esa clase `Settings` (en este caso, en el objeto `settings`), Pydantic leerá las variables de entorno de una manera indiferente a mayúsculas y minúsculas, por lo que una variable en mayúsculas `APP_NAME` aún será leída para el atributo `app_name`.
Luego convertirá y validará los datos. Así que, cuando uses ese objeto `settings`, tendrás datos de los tipos que declaraste (por ejemplo, `items_per_user` será un `int`).
@@ -110,7 +88,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p
/// tip | Consejo
Para establecer múltiples variables de entorno para un solo comando, simplemente sepáralas con un espacio y ponlas todas antes del comando.
Para establecer múltiples env vars para un solo comando, simplemente sepáralas con un espacio y ponlas todas antes del comando.
///
@@ -150,7 +128,7 @@ Proveniente del ejemplo anterior, tu archivo `config.py` podría verse como:
{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *}
Nota que ahora no creamos una instance por defecto `settings = Settings()`.
Nota que ahora no creamos un instance por defecto `settings = Settings()`.
### El archivo principal de la app { #the-main-app-file }
@@ -172,11 +150,11 @@ Y luego podemos requerirlo desde la *path operation function* como una dependenc
### Configuraciones y pruebas { #settings-and-testing }
Luego sería muy fácil proporcionar un objeto de configuraciones diferente durante las pruebas al sobrescribir una dependencia para `get_settings`:
Luego sería muy fácil proporcionar un objeto de configuraciones diferente durante las pruebas al crear una sobrescritura de dependencia para `get_settings`:
{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *}
En la dependencia sobreescrita establecemos un nuevo valor para el `admin_email` al crear el nuevo objeto `Settings`, y luego devolvemos ese nuevo objeto.
En la sobrescritura de dependencia establecemos un nuevo valor para el `admin_email` al crear el nuevo objeto `Settings`, y luego devolvemos ese nuevo objeto.
Luego podemos probar que se está usando.
@@ -215,8 +193,6 @@ APP_NAME="ChimichangApp"
Y luego actualizar tu `config.py` con:
//// tab | Pydantic v2
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
/// tip | Consejo
@@ -225,26 +201,6 @@ El atributo `model_config` se usa solo para configuración de Pydantic. Puedes l
///
////
//// tab | Pydantic v1
{* ../../docs_src/settings/app03_an_py39/config_pv1.py hl[9:10] *}
/// tip | Consejo
La clase `Config` se usa solo para configuración de Pydantic. Puedes leer más en <a href="https://docs.pydantic.dev/1.10/usage/model_config/" class="external-link" target="_blank">Pydantic Model Config</a>.
///
////
/// info | Información
En la versión 1 de Pydantic la configuración se hacía en una clase interna `Config`, en la versión 2 de Pydantic se hace en un atributo `model_config`. Este atributo toma un `dict`, y para obtener autocompletado y errores en línea, puedes importar y usar `SettingsConfigDict` para definir ese `dict`.
///
Aquí definimos la configuración `env_file` dentro de tu clase Pydantic `Settings`, y establecemos el valor en el nombre del archivo con el archivo dotenv que queremos usar.
### Creando el `Settings` solo una vez con `lru_cache` { #creating-the-settings-only-once-with-lru-cache }
@@ -331,7 +287,7 @@ participant execute as Ejecutar función
end
```
En el caso de nuestra dependencia `get_settings()`, la función ni siquiera toma argumentos, por lo que siempre devolve el mismo valor.
En el caso de nuestra dependencia `get_settings()`, la función ni siquiera toma argumentos, por lo que siempre devuelve el mismo valor.
De esa manera, se comporta casi como si fuera solo una variable global. Pero como usa una función de dependencia, entonces podemos sobrescribirla fácilmente para las pruebas.

View File

@@ -35,7 +35,7 @@ Dependiendo de tu caso de uso, podrías preferir usar un paquete diferente, pero
Aquí tienes una pequeña vista previa de cómo podrías integrar Strawberry con FastAPI:
{* ../../docs_src/graphql/tutorial001_py39.py hl[3,22,25] *}
{* ../../docs_src/graphql_/tutorial001_py39.py hl[3,22,25] *}
Puedes aprender más sobre Strawberry en la <a href="https://strawberry.rocks/" class="external-link" target="_blank">documentación de Strawberry</a>.

View File

@@ -2,21 +2,23 @@
Si tienes una app de FastAPI antigua, podrías estar usando Pydantic versión 1.
FastAPI ha tenido compatibilidad con Pydantic v1 o v2 desde la versión 0.100.0.
FastAPI versión 0.100.0 tenía compatibilidad con Pydantic v1 o v2. Usaba la que tuvieras instalada.
Si tenías instalado Pydantic v2, lo usaba. Si en cambio tenías Pydantic v1, usaba ese.
FastAPI versión 0.119.0 introdujo compatibilidad parcial con Pydantic v1 desde dentro de Pydantic v2 (como `pydantic.v1`), para facilitar la migración a v2.
Pydantic v1 está deprecado y su soporte se eliminará en las próximas versiones de FastAPI, deberías migrar a Pydantic v2. Así obtendrás las funcionalidades, mejoras y correcciones más recientes.
FastAPI 0.126.0 eliminó la compatibilidad con Pydantic v1, aunque siguió soportando `pydantic.v1` por un poquito más de tiempo.
/// warning | Advertencia
Además, el equipo de Pydantic dejó de dar soporte a Pydantic v1 para las versiones más recientes de Python, comenzando con Python 3.14.
El equipo de Pydantic dejó de dar soporte a Pydantic v1 para las versiones más recientes de Python, comenzando con **Python 3.14**.
Esto incluye `pydantic.v1`, que ya no está soportado en Python 3.14 y superiores.
Si quieres usar las funcionalidades más recientes de Python, tendrás que asegurarte de usar Pydantic v2.
///
Si tienes una app de FastAPI antigua con Pydantic v1, aquí te muestro cómo migrarla a Pydantic v2 y las nuevas funcionalidades en FastAPI 0.119.0 para ayudarte con una migración gradual.
Si tienes una app de FastAPI antigua con Pydantic v1, aquí te muestro cómo migrarla a Pydantic v2, y las **funcionalidades en FastAPI 0.119.0** para ayudarte con una migración gradual.
## Guía oficial { #official-guide }
@@ -44,9 +46,9 @@ Después de esto, puedes ejecutar los tests y revisa si todo funciona. Si es as
## Pydantic v1 en v2 { #pydantic-v1-in-v2 }
Pydantic v2 incluye todo lo de Pydantic v1 como un submódulo `pydantic.v1`.
Pydantic v2 incluye todo lo de Pydantic v1 como un submódulo `pydantic.v1`. Pero esto ya no está soportado en versiones por encima de Python 3.13.
Esto significa que puedes instalar la versión más reciente de Pydantic v2 e importar y usar los componentes viejos de Pydantic v1 desde ese submódulo, como si tuvieras instalado el Pydantic v1 antiguo.
Esto significa que puedes instalar la versión más reciente de Pydantic v2 e importar y usar los componentes viejos de Pydantic v1 desde este submódulo, como si tuvieras instalado el Pydantic v1 antiguo.
{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
@@ -66,7 +68,7 @@ Ten en cuenta que, como el equipo de Pydantic ya no da soporte a Pydantic v1 en
### Pydantic v1 y v2 en la misma app { #pydantic-v1-and-v2-on-the-same-app }
No está soportado por Pydantic tener un modelo de Pydantic v2 con sus propios campos definidos como modelos de Pydantic v1 o viceversa.
**No está soportado** por Pydantic tener un modelo de Pydantic v2 con sus propios campos definidos como modelos de Pydantic v1 o viceversa.
```mermaid
graph TB
@@ -106,7 +108,7 @@ graph TB
style V2Field fill:#f9fff3
```
En algunos casos, incluso es posible tener modelos de Pydantic v1 y v2 en la misma path operation de tu app de FastAPI:
En algunos casos, incluso es posible tener modelos de Pydantic v1 y v2 en la misma **path operation** de tu app de FastAPI:
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
@@ -122,12 +124,12 @@ Si necesitas usar algunas de las herramientas específicas de FastAPI para pará
/// tip | Consejo
Primero prueba con `bump-pydantic`; si tus tests pasan y eso funciona, entonces terminaste con un solo comando. ✨
Primero prueba con `bump-pydantic`, si tus tests pasan y eso funciona, entonces terminaste con un solo comando. ✨
///
Si `bump-pydantic` no funciona para tu caso, puedes usar la compatibilidad de modelos Pydantic v1 y v2 en la misma app para hacer la migración a Pydantic v2 de forma gradual.
Si `bump-pydantic` no funciona para tu caso de uso, puedes usar la compatibilidad de modelos Pydantic v1 y v2 en la misma app para hacer la migración a Pydantic v2 de forma gradual.
Podrías primero actualizar Pydantic para usar la última versión 2 y cambiar los imports para usar `pydantic.v1` para todos tus modelos.
Podrías primero actualizar Pydantic para usar la última versión 2, y cambiar los imports para usar `pydantic.v1` para todos tus modelos.
Luego puedes empezar a migrar tus modelos de Pydantic v1 a v2 por grupos, en pasos graduales. 🚶

View File

@@ -1,6 +1,6 @@
# Separación de Esquemas OpenAPI para Entrada y Salida o No { #separate-openapi-schemas-for-input-and-output-or-not }
Al usar **Pydantic v2**, el OpenAPI generado es un poco más exacto y **correcto** que antes. 😎
Desde que se lanzó **Pydantic v2**, el OpenAPI generado es un poco más exacto y **correcto** que antes. 😎
De hecho, en algunos casos, incluso tendrá **dos JSON Schemas** en OpenAPI para el mismo modelo Pydantic, para entrada y salida, dependiendo de si tienen **valores por defecto**.
@@ -85,7 +85,7 @@ Probablemente el caso principal para esto es si ya tienes algún código cliente
En ese caso, puedes desactivar esta funcionalidad en **FastAPI**, con el parámetro `separate_input_output_schemas=False`.
/// info | Información
/// info
El soporte para `separate_input_output_schemas` fue agregado en FastAPI `0.102.0`. 🤓
@@ -100,5 +100,3 @@ Y ahora habrá un único esquema para entrada y salida para el modelo, solo `Ite
<div class="screenshot">
<img src="/img/tutorial/separate-openapi-schemas/image05.png">
</div>
Este es el mismo comportamiento que en Pydantic v1. 🤓

View File

@@ -93,13 +93,13 @@ Las funcionalidades clave son:
"_Estoy súper emocionado con **FastAPI**. ¡Es tan divertido!_"
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">host del podcast Python Bytes</a></strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> host del podcast</strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
---
"_Honestamente, lo que has construido parece súper sólido y pulido. En muchos aspectos, es lo que quería que **Hug** fuera; es realmente inspirador ver a alguien construir eso._"
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">creador de Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="https://github.com/hugapi/hug" target="_blank">Hug</a> creador</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
---
@@ -117,6 +117,12 @@ Las funcionalidades clave son:
---
## Mini documental de FastAPI { #fastapi-mini-documentary }
Hay un <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documental de FastAPI</a> lanzado a finales de 2025, puedes verlo online:
<a href="https://www.youtube.com/watch?v=mpR8ngthqiE" target="_blank"><img src="https://fastapi.tiangolo.com/img/fastapi-documentary.jpg" alt="FastAPI Mini Documentary"></a>
## **Typer**, el FastAPI de las CLIs { #typer-the-fastapi-of-clis }
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
@@ -268,7 +274,7 @@ Verás la documentación interactiva automática de la API (proporcionada por <a
![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
### Documentación de API Alternativa { #alternative-api-docs }
### Documentación alternativa de la API { #alternative-api-docs }
Y ahora, ve a <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
@@ -276,7 +282,7 @@ Verás la documentación alternativa automática (proporcionada por <a href="htt
![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
## Actualización del Ejemplo { #example-upgrade }
## Actualización del ejemplo { #example-upgrade }
Ahora modifica el archivo `main.py` para recibir un body desde un request `PUT`.
@@ -314,7 +320,7 @@ def update_item(item_id: int, item: Item):
El servidor `fastapi dev` debería recargarse automáticamente.
### Actualización de la Documentación Interactiva de la API { #interactive-api-docs-upgrade }
### Actualización de la documentación interactiva de la API { #interactive-api-docs-upgrade }
Ahora ve a <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
@@ -330,7 +336,7 @@ Ahora ve a <a href="http://127.0.0.1:8000/docs" class="external-link" target="_b
![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
### Actualización de la Documentación Alternativa de la API { #alternative-api-docs-upgrade }
### Actualización de la documentación alternativa de la API { #alternative-api-docs-upgrade }
Y ahora, ve a <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
@@ -393,13 +399,13 @@ Volviendo al ejemplo de código anterior, **FastAPI**:
* Validará que haya un `item_id` en el path para requests `GET` y `PUT`.
* Validará que el `item_id` sea del tipo `int` para requests `GET` y `PUT`.
* Si no lo es, el cliente verá un error útil y claro.
* Comprobará si hay un parámetro de query opcional llamado `q` (como en `http://127.0.0.1:8000/items/foo?q=somequery`) para requests `GET`.
* Revisa si hay un parámetro de query opcional llamado `q` (como en `http://127.0.0.1:8000/items/foo?q=somequery`) para requests `GET`.
* Como el parámetro `q` está declarado con `= None`, es opcional.
* Sin el `None` sería requerido (como lo es el body en el caso con `PUT`).
* Para requests `PUT` a `/items/{item_id}`, leerá el body como JSON:
* Comprobará que tiene un atributo requerido `name` que debe ser un `str`.
* Comprobará que tiene un atributo requerido `price` que debe ser un `float`.
* Comprobará que tiene un atributo opcional `is_offer`, que debe ser un `bool`, si está presente.
* Revisa que tiene un atributo requerido `name` que debe ser un `str`.
* Revisa que tiene un atributo requerido `price` que debe ser un `float`.
* Revisa que tiene un atributo opcional `is_offer`, que debe ser un `bool`, si está presente.
* Todo esto también funcionaría para objetos JSON profundamente anidados.
* Convertirá de y a JSON automáticamente.
* Documentará todo con OpenAPI, que puede ser usado por:

View File

@@ -56,7 +56,7 @@ from app.routers import items
La misma estructura de archivos con comentarios:
```
```bash
.
├── app # "app" es un paquete de Python
│   ├── __init__.py # este archivo hace que "app" sea un "paquete de Python"
@@ -185,7 +185,7 @@ El resultado final es que los paths de item son ahora:
* Todos incluirán las `responses` predefinidas.
* Todas estas *path operations* tendrán la lista de `dependencies` evaluadas/ejecutadas antes de ellas.
* Si también declaras dependencias en una *path operation* específica, **también se ejecutarán**.
* Las dependencias del router se ejecutan primero, luego las [dependencias en el decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, y luego las dependencias de parámetros normales.
* Las dependencias del router se ejecutan primero, luego las [`dependencies` en el decorador](dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}, y luego las dependencias de parámetros normales.
* También puedes agregar [dependencias de `Security` con `scopes`](../advanced/security/oauth2-scopes.md){.internal-link target=_blank}.
/// tip | Consejo
@@ -214,7 +214,7 @@ Así que usamos un import relativo con `..` para las dependencias:
/// tip | Consejo
Si sabes perfectamente cómo funcionan los imports, continúa a la siguiente sección.
Si sabes perfectamente cómo funcionan los imports, continúa a la siguiente sección abajo.
///
@@ -271,7 +271,7 @@ eso significaría:
Eso se referiría a algún paquete arriba de `app/`, con su propio archivo `__init__.py`, etc. Pero no tenemos eso. Así que, eso lanzaría un error en nuestro ejemplo. 🚨
Pero ahora sabes cómo funciona, para que puedas usar imports relativos en tus propias aplicaciones sin importar cuán complejas sean. 🤓
Pero ahora sabes cómo funciona, para que puedas usar imports relativos en tus propias apps sin importar cuán complejas sean. 🤓
### Agregar algunos `tags`, `responses`, y `dependencies` personalizados { #add-some-custom-tags-responses-and-dependencies }
@@ -283,7 +283,7 @@ Pero aún podemos agregar _más_ `tags` que se aplicarán a una *path operation*
/// tip | Consejo
Esta última *path operation* tendrá la combinación de tags: `["items", "custom"]`.
Esta última path operation tendrá la combinación de tags: `["items", "custom"]`.
Y también tendrá ambas responses en la documentación, una para `404` y otra para `403`.
@@ -301,7 +301,7 @@ Y como la mayor parte de tu lógica ahora vivirá en su propio módulo específi
### Importar `FastAPI` { #import-fastapi }
Importas y creas una clase `FastAPI` como de costumbre.
Importas y creas una clase `FastAPI` como normalmente.
Y podemos incluso declarar [dependencias globales](dependencies/global-dependencies.md){.internal-link target=_blank} que se combinarán con las dependencias para cada `APIRouter`:
@@ -398,7 +398,7 @@ Incluirá todas las rutas de ese router como parte de ella.
En realidad creará internamente una *path operation* para cada *path operation* que fue declarada en el `APIRouter`.
Así, detrás de escena, funcionará como si todo fuera la misma única aplicación.
Así, detrás de escena, funcionará como si todo fuera la misma única app.
///
@@ -430,20 +430,20 @@ Podemos declarar todo eso sin tener que modificar el `APIRouter` original pasand
De esa manera, el `APIRouter` original permanecerá sin modificar, por lo que aún podemos compartir ese mismo archivo `app/internal/admin.py` con otros proyectos en la organización.
El resultado es que, en nuestra aplicación, cada una de las *path operations* del módulo `admin` tendrá:
El resultado es que, en nuestra app, cada una de las *path operations* del módulo `admin` tendrá:
* El prefix `/admin`.
* El tag `admin`.
* La dependencia `get_token_header`.
* La response `418`. 🍵
Pero eso solo afectará a ese `APIRouter` en nuestra aplicación, no en ningún otro código que lo utilice.
Pero eso solo afectará a ese `APIRouter` en nuestra app, no en ningún otro código que lo utilice.
Así, por ejemplo, otros proyectos podrían usar el mismo `APIRouter` con un método de autenticación diferente.
### Incluir una *path operation* { #include-a-path-operation }
También podemos agregar *path operations* directamente a la aplicación de `FastAPI`.
También podemos agregar *path operations* directamente a la app de `FastAPI`.
Aquí lo hacemos... solo para mostrar que podemos 🤷:
@@ -461,13 +461,13 @@ Los `APIRouter`s no están "montados", no están aislados del resto de la aplica
Esto se debe a que queremos incluir sus *path operations* en el esquema de OpenAPI y las interfaces de usuario.
Como no podemos simplemente aislarlos y "montarlos" independientemente del resto, se "clonan" las *path operations* (se vuelven a crear), no se incluyen directamente.
Como no podemos simplemente aislarlos y "montarlos" independientemente del resto, las *path operations* se "clonan" (se vuelven a crear), no se incluyen directamente.
///
## Revisa la documentación automática de la API { #check-the-automatic-api-docs }
Ahora, ejecuta tu aplicación:
Ahora, ejecuta tu app:
<div class="termy">
@@ -481,7 +481,7 @@ $ fastapi dev app/main.py
Y abre la documentación en <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
Verás la documentación automática de la API, incluyendo los paths de todos los submódulos, usando los paths correctos (y prefijos) y las tags correctas:
Verás la documentación automática de la API, incluyendo los paths de todos los submódulos, usando los paths correctos (y prefijos) y los tags correctos:
<img src="/img/tutorial/bigger-applications/image01.png">
@@ -501,4 +501,4 @@ De la misma manera que puedes incluir un `APIRouter` en una aplicación `FastAPI
router.include_router(other_router)
```
Asegúrate de hacerlo antes de incluir `router` en la aplicación de `FastAPI`, para que las *path operations* de `other_router` también se incluyan.
Asegúrate de hacerlo antes de incluir `router` en la app de `FastAPI`, para que las *path operations* de `other_router` también se incluyan.

View File

@@ -1,4 +1,4 @@
# Cuerpo - Actualizaciones { #body-updates }
# Body - Actualizaciones { #body-updates }
## Actualización reemplazando con `PUT` { #update-replacing-with-put }
@@ -50,14 +50,6 @@ Si quieres recibir actualizaciones parciales, es muy útil usar el parámetro `e
Como `item.model_dump(exclude_unset=True)`.
/// info | Información
En Pydantic v1 el método se llamaba `.dict()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_dump()`.
Los ejemplos aquí usan `.dict()` para compatibilidad con Pydantic v1, pero deberías usar `.model_dump()` si puedes usar Pydantic v2.
///
Eso generaría un `dict` solo con los datos que se establecieron al crear el modelo `item`, excluyendo los valores por defecto.
Luego puedes usar esto para generar un `dict` solo con los datos que se establecieron (enviados en el request), omitiendo los valores por defecto:
@@ -68,14 +60,6 @@ Luego puedes usar esto para generar un `dict` solo con los datos que se establec
Ahora, puedes crear una copia del modelo existente usando `.model_copy()`, y pasar el parámetro `update` con un `dict` que contenga los datos a actualizar.
/// info | Información
En Pydantic v1 el método se llamaba `.copy()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_copy()`.
Los ejemplos aquí usan `.copy()` para compatibilidad con Pydantic v1, pero deberías usar `.model_copy()` si puedes usar Pydantic v2.
///
Como `stored_item_model.model_copy(update=update_data)`:
{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}
@@ -90,9 +74,9 @@ En resumen, para aplicar actualizaciones parciales deberías:
* Generar un `dict` sin valores por defecto del modelo de entrada (usando `exclude_unset`).
* De esta manera puedes actualizar solo los valores realmente establecidos por el usuario, en lugar de sobrescribir valores ya almacenados con valores por defecto en tu modelo.
* Crear una copia del modelo almacenado, actualizando sus atributos con las actualizaciones parciales recibidas (usando el parámetro `update`).
* Convertir el modelo copiado en algo que pueda almacenarse en tu base de datos (por ejemplo, usando el `jsonable_encoder`).
* Convertir el modelo copiado en algo que pueda almacenarse en tu DB (por ejemplo, usando el `jsonable_encoder`).
* Esto es comparable a usar el método `.model_dump()` del modelo de nuevo, pero asegura (y convierte) los valores a tipos de datos que pueden convertirse a JSON, por ejemplo, `datetime` a `str`.
* Guardar los datos en tu base de datos.
* Guardar los datos en tu DB.
* Devolver el modelo actualizado.
{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}

View File

@@ -32,7 +32,8 @@ Usa tipos estándar de Python para todos los atributos:
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
Al igual que al declarar parámetros de query, cuando un atributo del modelo tiene un valor por defecto, no es obligatorio. De lo contrario, es obligatorio. Usa `None` para hacerlo opcional.
Al igual que al declarar parámetros de query, cuando un atributo del modelo tiene un valor por defecto, no es obligatorio. De lo contrario, es obligatorio. Usa `None` para hacerlo solo opcional.
Por ejemplo, el modelo anterior declara un “`object`” JSON (o `dict` en Python) como:
@@ -127,14 +128,6 @@ Dentro de la función, puedes acceder a todos los atributos del objeto modelo di
{* ../../docs_src/body/tutorial002_py310.py *}
/// info | Información
En Pydantic v1 el método se llamaba `.dict()`, se marcó como obsoleto (pero sigue soportado) en Pydantic v2, y se renombró a `.model_dump()`.
Los ejemplos aquí usan `.dict()` por compatibilidad con Pydantic v1, pero deberías usar `.model_dump()` si puedes usar Pydantic v2.
///
## Request body + parámetros de path { #request-body-path-parameters }
Puedes declarar parámetros de path y request body al mismo tiempo.
@@ -143,6 +136,7 @@ Puedes declarar parámetros de path y request body al mismo tiempo.
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
## Request body + path + parámetros de query { #request-body-path-query-parameters }
También puedes declarar parámetros de **body**, **path** y **query**, todos al mismo tiempo.
@@ -155,7 +149,7 @@ Los parámetros de la función se reconocerán de la siguiente manera:
* Si el parámetro también se declara en el **path**, se utilizará como un parámetro de path.
* Si el parámetro es de un **tipo singular** (como `int`, `float`, `str`, `bool`, etc.), se interpretará como un parámetro de **query**.
* Si el parámetro se declara como del tipo de un **modelo de Pydantic**, se interpretará como un **request body**.
* Si el parámetro se declara como del tipo de un **modelo de Pydantic**, se interpretará como un **body** de request.
/// note | Nota

View File

@@ -22,21 +22,13 @@ Aquí tienes una idea general de cómo podrían ser los modelos con sus campos d
{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}
/// info | Información
### Acerca de `**user_in.model_dump()` { #about-user-in-model-dump }
En Pydantic v1 el método se llamaba `.dict()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_dump()`.
Los ejemplos aquí usan `.dict()` para compatibilidad con Pydantic v1, pero deberías usar `.model_dump()` en su lugar si puedes usar Pydantic v2.
///
### Acerca de `**user_in.dict()` { #about-user-in-dict }
#### `.dict()` de Pydantic { #pydantics-dict }
#### `.model_dump()` de Pydantic { #pydantics-model-dump }
`user_in` es un modelo Pydantic de la clase `UserIn`.
Los modelos Pydantic tienen un método `.dict()` que devuelve un `dict` con los datos del modelo.
Los modelos Pydantic tienen un método `.model_dump()` que devuelve un `dict` con los datos del modelo.
Así que, si creamos un objeto Pydantic `user_in` como:
@@ -47,7 +39,7 @@ user_in = UserIn(username="john", password="secret", email="john.doe@example.com
y luego llamamos a:
```Python
user_dict = user_in.dict()
user_dict = user_in.model_dump()
```
ahora tenemos un `dict` con los datos en la variable `user_dict` (es un `dict` en lugar de un objeto modelo Pydantic).
@@ -58,7 +50,7 @@ Y si llamamos a:
print(user_dict)
```
obtendremos un `dict` de Python con:
obtendríamos un `dict` de Python con:
```Python
{
@@ -103,20 +95,20 @@ UserInDB(
#### Un modelo Pydantic a partir del contenido de otro { #a-pydantic-model-from-the-contents-of-another }
Como en el ejemplo anterior obtuvimos `user_dict` de `user_in.dict()`, este código:
Como en el ejemplo anterior obtuvimos `user_dict` de `user_in.model_dump()`, este código:
```Python
user_dict = user_in.dict()
user_dict = user_in.model_dump()
UserInDB(**user_dict)
```
sería equivalente a:
```Python
UserInDB(**user_in.dict())
UserInDB(**user_in.model_dump())
```
...porque `user_in.dict()` es un `dict`, y luego hacemos que Python lo "desempaquete" al pasarlo a `UserInDB` con el prefijo `**`.
...porque `user_in.model_dump()` es un `dict`, y luego hacemos que Python lo "desempaquete" al pasarlo a `UserInDB` con el prefijo `**`.
Así, obtenemos un modelo Pydantic a partir de los datos en otro modelo Pydantic.
@@ -125,7 +117,7 @@ Así, obtenemos un modelo Pydantic a partir de los datos en otro modelo Pydantic
Y luego agregando el argumento de palabra clave adicional `hashed_password=hashed_password`, como en:
```Python
UserInDB(**user_in.dict(), hashed_password=hashed_password)
UserInDB(**user_in.model_dump(), hashed_password=hashed_password)
```
...termina siendo como:
@@ -156,7 +148,7 @@ Y estos modelos están compartiendo muchos de los datos y duplicando nombres y t
Podríamos hacerlo mejor.
Podemos declarar un modelo `UserBase` que sirva como base para nuestros otros modelos. Y luego podemos hacer subclases de ese modelo que heredan sus atributos (anotaciones de tipos, validación, etc).
Podemos declarar un modelo `UserBase` que sirva como base para nuestros otros modelos. Y luego podemos hacer subclases de ese modelo que heredan sus atributos (declaraciones de tipos, validación, etc).
Toda la conversión de datos, validación, documentación, etc. seguirá funcionando normalmente.
@@ -180,20 +172,19 @@ Al definir una <a href="https://docs.pydantic.dev/latest/concepts/types/#unions"
{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}
### `Union` en Python 3.10 { #union-in-python-3-10 }
En este ejemplo pasamos `Union[PlaneItem, CarItem]` como el valor del argumento `response_model`.
Porque lo estamos pasando como un **valor a un argumento** en lugar de ponerlo en **anotaciones de tipos**, tenemos que usar `Union` incluso en Python 3.10.
Porque lo estamos pasando como un **valor a un argumento** en lugar de ponerlo en una **anotación de tipos**, tenemos que usar `Union` incluso en Python 3.10.
Si estuviera en anotaciones de tipos podríamos haber usado la barra vertical, como:
Si estuviera en una anotación de tipos podríamos haber usado la barra vertical, como:
```Python
some_variable: PlaneItem | CarItem
```
Pero si ponemos eso en la asignación `response_model=PlaneItem | CarItem` obtendríamos un error, porque Python intentaría realizar una **operación inválida** entre `PlaneItem` y `CarItem` en lugar de interpretar eso como anotaciones de tipos.
Pero si ponemos eso en la asignación `response_model=PlaneItem | CarItem` obtendríamos un error, porque Python intentaría realizar una **operación inválida** entre `PlaneItem` y `CarItem` en lugar de interpretar eso como una anotación de tipos.
## Lista de modelos { #list-of-models }
@@ -203,7 +194,6 @@ Para eso, usa el `typing.List` estándar de Python (o simplemente `list` en Pyth
{* ../../docs_src/extra_models/tutorial004_py39.py hl[18] *}
## Response con `dict` arbitrario { #response-with-arbitrary-dict }
También puedes declarar un response usando un `dict` arbitrario plano, declarando solo el tipo de las claves y valores, sin usar un modelo Pydantic.
@@ -214,7 +204,6 @@ En este caso, puedes usar `typing.Dict` (o solo `dict` en Python 3.9 y posterior
{* ../../docs_src/extra_models/tutorial005_py39.py hl[6] *}
## Recapitulación { #recap }
Usa múltiples modelos Pydantic y hereda libremente para cada caso.

View File

@@ -109,7 +109,7 @@ FastAPI ahora:
## Alternativa (antigua): `Query` como valor por defecto { #alternative-old-query-as-the-default-value }
Versiones anteriores de FastAPI (antes de <abbr title="antes de 2023-03">0.95.0</abbr>) requerían que usaras `Query` como el valor por defecto de tu parámetro, en lugar de ponerlo en `Annotated`, hay una alta probabilidad de que veas código usándolo alrededor, así que te lo explicaré.
Versiones anteriores de FastAPI (antes de <abbr title="before 2023-03 - antes de 2023-03">0.95.0</abbr>) requerían que usaras `Query` como el valor por defecto de tu parámetro, en lugar de ponerlo en `Annotated`, hay una alta probabilidad de que veas código usándolo alrededor, así que te lo explicaré.
/// tip | Consejo
@@ -192,7 +192,7 @@ También puedes agregar un parámetro `min_length`:
## Agregar expresiones regulares { #add-regular-expressions }
Puedes definir un <abbr title="Una expresión regular, regex o regexp es una secuencia de caracteres que define un patrón de búsqueda para strings.">expresión regular</abbr> `pattern` que el parámetro debe coincidir:
Puedes definir una <abbr title="Una expresión regular, regex o regexp es una secuencia de caracteres que define un patrón de búsqueda para strings.">expresión regular</abbr> `pattern` que el parámetro debe coincidir:
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
@@ -206,20 +206,6 @@ Si te sientes perdido con todas estas ideas de **"expresión regular"**, no te p
Ahora sabes que cuando las necesites puedes usarlas en **FastAPI**.
### Pydantic v1 `regex` en lugar de `pattern` { #pydantic-v1-regex-instead-of-pattern }
Antes de la versión 2 de Pydantic y antes de FastAPI 0.100.0, el parámetro se llamaba `regex` en lugar de `pattern`, pero ahora está en desuso.
Todavía podrías ver algo de código que lo usa:
//// tab | Pydantic v1
{* ../../docs_src/query_params_str_validations/tutorial004_regex_an_py310.py hl[11] *}
////
Pero que sepas que esto está deprecado y debería actualizarse para usar el nuevo parámetro `pattern`. 🤓
## Valores por defecto { #default-values }
Puedes, por supuesto, usar valores por defecto diferentes de `None`.
@@ -280,7 +266,7 @@ Entonces, con una URL como:
http://localhost:8000/items/?q=foo&q=bar
```
recibirías los múltiples valores del *query parameter* `q` (`foo` y `bar`) en una `list` de Python dentro de tu *path operation function*, en el *parámetro de función* `q`.
recibirías los múltiples valores de los *query parameters* `q` (`foo` y `bar`) en una `list` de Python dentro de tu *path operation function*, en el *parámetro de función* `q`.
Entonces, el response a esa URL sería:
@@ -386,7 +372,7 @@ Entonces puedes declarar un `alias`, y ese alias será usado para encontrar el v
Ahora digamos que ya no te gusta este parámetro.
Tienes que dejarlo allí por un tiempo porque hay clientes usándolo, pero quieres que la documentación lo muestre claramente como <abbr title="obsoleto, se recomienda no usarlo">deprecated</abbr>.
Tienes que dejarlo allí por un tiempo porque hay clientes usándolo, pero quieres que la documentación lo muestre claramente como <abbr title="obsolete, recommended not to use it - obsoleto, se recomienda no usarlo">deprecated</abbr>.
Luego pasa el parámetro `deprecated=True` a `Query`:
@@ -416,7 +402,7 @@ Pydantic también tiene <a href="https://docs.pydantic.dev/latest/concepts/valid
///
Por ejemplo, este validador personalizado comprueba que el ID del ítem empiece con `isbn-` para un número de libro <abbr title="International Standard Book Number Número Estándar Internacional de Libro">ISBN</abbr> o con `imdb-` para un ID de URL de película de <abbr title="IMDB (Internet Movie Database) es un sitio web con información sobre películas">IMDB</abbr>:
Por ejemplo, este validador personalizado comprueba que el ID del ítem empiece con `isbn-` para un número de libro <abbr title="ISBN means International Standard Book Number - ISBN significa International Standard Book Number">ISBN</abbr> o con `imdb-` para un ID de URL de película de <abbr title="IMDB (Internet Movie Database) is a website with information about movies - IMDB (Internet Movie Database) es un sitio web con información sobre películas">IMDB</abbr>:
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
@@ -450,7 +436,7 @@ Pero si te da curiosidad este ejemplo de código específico y sigues entretenid
#### Un ítem aleatorio { #a-random-item }
Con `data.items()` obtenemos un <abbr title="Algo que podemos iterar con un for, como una list, set, etc.">objeto iterable</abbr> con tuplas que contienen la clave y el valor para cada elemento del diccionario.
Con `data.items()` obtenemos un <abbr title="Algo que podemos iterar con un for loop, como una list, set, etc.">objeto iterable</abbr> con tuplas que contienen la clave y el valor para cada elemento del diccionario.
Convertimos este objeto iterable en una `list` propiamente dicha con `list(data.items())`.

View File

@@ -2,7 +2,7 @@
Puedes declarar el tipo utilizado para el response anotando el **tipo de retorno** de la *path operation function*.
Puedes utilizar **anotaciones de tipos** de la misma manera que lo harías para datos de entrada en **parámetros** de función, puedes utilizar modelos de Pydantic, list, diccionarios, valores escalares como enteros, booleanos, etc.
Puedes utilizar **anotaciones de tipos** de la misma manera que lo harías para datos de entrada en **parámetros** de función, puedes utilizar modelos de Pydantic, lists, diccionarios, valores escalares como enteros, booleanos, etc.
{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}
@@ -27,7 +27,7 @@ Por ejemplo, podrías querer **devolver un diccionario** u objeto de base de dat
Si añadiste la anotación del tipo de retorno, las herramientas y editores se quejarían con un error (correcto) diciéndote que tu función está devolviendo un tipo (por ejemplo, un dict) que es diferente de lo que declaraste (por ejemplo, un modelo de Pydantic).
En esos casos, puedes usar el parámetro del decorador de path operation `response_model` en lugar del tipo de retorno.
En esos casos, puedes usar el parámetro del *decorador de path operation* `response_model` en lugar del tipo de retorno.
Puedes usar el parámetro `response_model` en cualquiera de las *path operations*:
@@ -153,7 +153,7 @@ Primero vamos a ver cómo los editores, mypy y otras herramientas verían esto.
`BaseUser` tiene los campos base. Luego `UserIn` hereda de `BaseUser` y añade el campo `password`, por lo que incluirá todos los campos de ambos modelos.
Anotamos el tipo de retorno de la función como `BaseUser`, pero en realidad estamos devolviendo un instance de `UserIn`.
Anotamos el tipo de retorno de la función como `BaseUser`, pero en realidad estamos devolviendo un `UserIn` instance.
El editor, mypy y otras herramientas no se quejarán de esto porque, en términos de tipificación, `UserIn` es una subclase de `BaseUser`, lo que significa que es un tipo *válido* cuando se espera algo que es un `BaseUser`.
@@ -252,20 +252,6 @@ Entonces, si envías un request a esa *path operation* para el ítem con ID `foo
/// info | Información
En Pydantic v1 el método se llamaba `.dict()`, fue deprecado (pero aún soportado) en Pydantic v2, y renombrado a `.model_dump()`.
Los ejemplos aquí usan `.dict()` para compatibilidad con Pydantic v1, pero deberías usar `.model_dump()` en su lugar si puedes usar Pydantic v2.
///
/// info | Información
FastAPI usa el método `.dict()` del modelo de Pydantic con <a href="https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict" class="external-link" target="_blank">su parámetro `exclude_unset`</a> para lograr esto.
///
/// info | Información
También puedes usar:
* `response_model_exclude_defaults=True`

View File

@@ -8,35 +8,13 @@ Aquí tienes varias formas de hacerlo.
Puedes declarar `examples` para un modelo de Pydantic que se añadirá al JSON Schema generado.
//// tab | Pydantic v2
{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}
////
Esa información extra se añadirá tal cual al **JSON Schema** resultante para ese modelo, y se usará en la documentación de la API.
//// tab | Pydantic v1
Puedes usar el atributo `model_config` que toma un `dict` como se describe en <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">la documentación de Pydantic: Configuración</a>.
{* ../../docs_src/schema_extra_example/tutorial001_pv1_py310.py hl[13:23] *}
////
Esa información extra se añadirá tal cual al **JSON Schema** generado para ese modelo, y se usará en la documentación de la API.
//// tab | Pydantic v2
En Pydantic versión 2, usarías el atributo `model_config`, que toma un `dict` como se describe en <a href="https://docs.pydantic.dev/latest/api/config/" class="external-link" target="_blank">la documentación de Pydantic: Configuración</a>.
Puedes establecer `"json_schema_extra"` con un `dict` que contenga cualquier dato adicional que desees que aparezca en el JSON Schema generado, incluyendo `examples`.
////
//// tab | Pydantic v1
En Pydantic versión 1, usarías una clase interna `Config` y `schema_extra`, como se describe en <a href="https://docs.pydantic.dev/1.10/usage/schema/#schema-customization" class="external-link" target="_blank">la documentación de Pydantic: Personalización de Esquema</a>.
Puedes establecer `schema_extra` con un `dict` que contenga cualquier dato adicional que desees que aparezca en el JSON Schema generado, incluyendo `examples`.
////
Puedes establecer `"json_schema_extra"` con un `dict` que contenga cualquier dato adicional que te gustaría que aparezca en el JSON Schema generado, incluyendo `examples`.
/// tip | Consejo
@@ -50,7 +28,7 @@ Por ejemplo, podrías usarlo para añadir metadatos para una interfaz de usuario
OpenAPI 3.1.0 (usado desde FastAPI 0.99.0) añadió soporte para `examples`, que es parte del estándar de **JSON Schema**.
Antes de eso, solo soportaba la palabra clave `example` con un solo ejemplo. Eso aún es soportado por OpenAPI 3.1.0, pero está obsoleto y no es parte del estándar de JSON Schema. Así que se recomienda migrar de `example` a `examples`. 🤓
Antes de eso, solo soportaba la palabra clave `example` con un solo ejemplo. Eso aún es soportado por OpenAPI 3.1.0, pero está obsoleto y no es parte del estándar de JSON Schema. Así que se te anima a migrar `example` a `examples`. 🤓
Puedes leer más al final de esta página.
@@ -94,7 +72,7 @@ Por supuesto, también puedes pasar múltiples `examples`:
{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}
Cuando haces esto, los ejemplos serán parte del **JSON Schema** interno para esos datos de body.
Cuando haces esto, los ejemplos serán parte del **JSON Schema** interno para esos datos del body.
Sin embargo, al <abbr title="2023-08-26">momento de escribir esto</abbr>, Swagger UI, la herramienta encargada de mostrar la interfaz de documentación, no soporta mostrar múltiples ejemplos para los datos en **JSON Schema**. Pero lee más abajo para una solución alternativa.
@@ -203,17 +181,17 @@ Debido a eso, las versiones de FastAPI anteriores a 0.99.0 todavía usaban versi
### `examples` de Pydantic y FastAPI { #pydantic-and-fastapi-examples }
Cuando añades `examples` dentro de un modelo de Pydantic, usando `schema_extra` o `Field(examples=["algo"])`, ese ejemplo se añade al **JSON Schema** para ese modelo de Pydantic.
Cuando añades `examples` dentro de un modelo de Pydantic, usando `schema_extra` o `Field(examples=["something"])`, ese ejemplo se añade al **JSON Schema** para ese modelo de Pydantic.
Y ese **JSON Schema** del modelo de Pydantic se incluye en el **OpenAPI** de tu API, y luego se usa en la interfaz de documentación.
En las versiones de FastAPI antes de 0.99.0 (0.99.0 y superior usan el nuevo OpenAPI 3.1.0) cuando usabas `example` o `examples` con cualquiera de las otras utilidades (`Query()`, `Body()`, etc.) esos ejemplos no se añadían al JSON Schema que describe esos datos (ni siquiera a la propia versión de JSON Schema de OpenAPI), se añadían directamente a la declaración de la *path operation* en OpenAPI (fuera de las partes de OpenAPI que usan JSON Schema).
En las versiones de FastAPI antes de 0.99.0 (0.99.0 y superiores usan el nuevo OpenAPI 3.1.0) cuando usabas `example` o `examples` con cualquiera de las otras utilidades (`Query()`, `Body()`, etc.) esos ejemplos no se añadían al JSON Schema que describe esos datos (ni siquiera a la propia versión de JSON Schema de OpenAPI), se añadían directamente a la declaración de la *path operation* en OpenAPI (fuera de las partes de OpenAPI que usan JSON Schema).
Pero ahora que FastAPI 0.99.0 y superiores usa OpenAPI 3.1.0, que usa JSON Schema 2020-12, y Swagger UI 5.0.0 y superiores, todo es más consistente y los ejemplos se incluyen en JSON Schema.
### Swagger UI y `examples` específicos de OpenAPI { #swagger-ui-and-openapi-specific-examples }
Ahora, como Swagger UI no soportaba múltiples ejemplos de JSON Schema (a fecha de 2023-08-26), los usuarios no tenían una forma de mostrar múltiples ejemplos en los documentos.
Ahora, como Swagger UI no soportaba múltiples ejemplos de JSON Schema (a fecha de 2023-08-26), los usuarios no tenían una forma de mostrar múltiples ejemplos en la documentación.
Para resolver eso, FastAPI `0.103.0` **añadió soporte** para declarar el mismo viejo campo **específico de OpenAPI** `examples` con el nuevo parámetro `openapi_examples`. 🤓

View File

@@ -6,123 +6,127 @@ Language code: fr.
### Grammar to use when talking to the reader
Use the formal grammar (use «vous» instead of «tu»).
Use the formal grammar (use `vous` instead of `tu`).
Additionally, in instructional sentences, prefer the present tense for obligations:
- Prefer `vous devez …` over `vous devrez …`, unless the English source explicitly refers to a future requirement.
- When translating “make sure (that) … is …”, prefer the indicative after `vous assurer que` (e.g. `Vous devez vous assurer qu'il est …`) instead of the subjunctive (e.g. `qu'il soit …`).
### Quotes
1) Convert neutral double quotes («"») and English double typographic quotes («“» and «”») to French guillemets (««» and «»»).
- Convert neutral double quotes (`"`) to French guillemets (`«` and `»`).
2) In the French docs, guillemets are written without extra spaces: use «texte», not « texte ».
3) Do not convert quotes inside code blocks, inline code, paths, URLs, or anything wrapped in backticks.
- Do not convert quotes inside code blocks, inline code, paths, URLs, or anything wrapped in backticks.
Examples:
Source (English):
Source (English):
«««
"Hello world"
“Hello Universe”
"He said: 'Hello'"
"The module is `__main__`"
»»»
```
"Hello world"
“Hello Universe”
"He said: 'Hello'"
"The module is `__main__`"
```
Result (French):
Result (French):
«««
«Hello world»
«Hello Universe»
«He said: 'Hello'»
«The module is `__main__`»
»»»
```
"Hello world"
Hello Universe
"He said: 'Hello'"
"The module is `__main__`"
```
### Ellipsis
1) Make sure there is a space between an ellipsis and a word following or preceding the ellipsis.
- Make sure there is a space between an ellipsis and a word following or preceding the ellipsis.
Examples:
Source (English):
Source (English):
«««
...as we intended.
...this would work:
...etc.
others...
More to come...
»»»
```
...as we intended.
...this would work:
...etc.
others...
More to come...
```
Result (French):
Result (French):
«««
... comme prévu.
... cela fonctionnerait :
... etc.
D'autres ...
La suite ...
»»»
```
... comme prévu.
... cela fonctionnerait :
... etc.
D'autres ...
La suite ...
```
2) This does not apply in URLs, code blocks, and code snippets. Do not remove or add spaces there.
- This does not apply in URLs, code blocks, and code snippets. Do not remove or add spaces there.
### Headings
1) Prefer translating headings using the infinitive form (as is common in the existing French docs): «Créer…», «Utiliser…», «Ajouter…».
- Prefer translating headings using the infinitive form (as is common in the existing French docs): `Créer…`, `Utiliser…`, `Ajouter…`.
2) For headings that are instructions written in imperative in English (e.g. Go check …), keep them in imperative in French, using the formal grammar (e.g. «Allez voir …»).
3) Keep heading punctuation as in the source. In particular, keep occurrences of literal « - » (space-hyphen-space) as « - » (the existing French docs use a hyphen here).
- For headings that are instructions written in imperative in English (e.g. `Go check …`), keep them in imperative in French, using the formal grammar (e.g. `Allez voir …`).
### French instructions about technical terms
Do not try to translate everything. In particular, keep common programming terms when that is the established usage in the French docs (e.g. «framework», «endpoint», «plug-in», «payload»). Use French where the existing docs already consistently use French (e.g. «requête», «réponse»).
Do not try to translate everything. In particular, keep common programming terms (e.g. `framework`, `endpoint`, `plug-in`, `payload`).
Keep class names, function names, modules, file names, and CLI commands unchanged.
### List of English terms and their preferred French translations
Below is a list of English terms and their preferred French translations, separated by a colon («:»). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them.
Below is a list of English terms and their preferred French translations, separated by a colon (:). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them.
* «/// note | Technical Details»: «/// note | Détails techniques»
* «/// note»: «/// note | Remarque»
* «/// tip»: «/// tip | Astuce»
* «/// warning»: «/// warning | Attention»
* «/// check»: «/// check | vérifier»
* «/// info»: «/// info»
- /// note | Technical Details»: /// note | Détails techniques
- /// note: /// note | Remarque
- /// tip: /// tip | Astuce
- /// warning: /// warning | Alertes
- /// check: /// check | Vérifications
- /// info: /// info
* «the docs»: «les documents»
* «the documentation»: «la documentation»
- the docs: les documents
- the documentation: la documentation
* «framework»: «framework» (do not translate to «cadre»)
* «performance»: «performance»
- Exclude from OpenAPI: Exclusion d'OpenAPI
* «type hints»: «annotations de type»
* «type annotations»: «annotations de type»
- framework: framework (do not translate to cadre)
- performance: performance
* «autocomplete»: «autocomplétion»
* «autocompletion»: «autocomplétion»
- type hints: annotations de type
- type annotations: annotations de type
* «the request» (what the client sends to the server): «la requête»
* «the response» (what the server sends back to the client): «la réponse»
- autocomplete: autocomplétion
- autocompletion: autocomplétion
* «the request body»: «le corps de la requête»
* «the response body»: «le corps de la réponse»
- the request (what the client sends to the server): la requête
- the response (what the server sends back to the client): la réponse
* «path operation»: «opération de chemin»
* «path operations» (plural): «opérations de chemin»
* «path operation function»: «fonction de chemin»
* «path operation decorator»: «décorateur d'opération de chemin»
- the request body: le corps de la requête
- the response body: le corps de la réponse
* «path parameter»: «paramètre de chemin»
* «query parameter»: «paramètre de requête»
- path operation: chemin d'accès
- path operations (plural): chemins d'accès
- path operation function: fonction de chemin d'accès
- path operation decorator: décorateur de chemin d'accès
* «the `Request`»: «`Request`» (keep as code identifier)
* «the `Response`»: «`Response`» (keep as code identifier)
- path parameter: paramètre de chemin
- query parameter: paramètre de requête
* «deployment»: «déploiement»
* «to upgrade»: «mettre à niveau»
- the `Request`: `Request` (keep as code identifier)
- the `Response`: `Response` (keep as code identifier)
* «deprecated»: «déprécié»
* «to deprecate»: «déprécier»
- deployment: déploiement
- to upgrade: mettre à niveau
* «cheat sheet»: «aide-mémoire»
* «plug-in»: «plug-in»
- deprecated: déprécié
- to deprecate: déprécier
- cheat sheet: aide-mémoire
- plug-in: plug-in

47
docs/ja/llm-prompt.md Normal file
View File

@@ -0,0 +1,47 @@
### Target language
Translate to Japanese (日本語).
Language code: ja.
### Grammar and tone
- Use polite, instructional Japanese (です/ます調).
- Keep the tone concise and technical (match existing Japanese FastAPI docs).
### Headings
- Follow the existing Japanese style: short, descriptive headings (often noun phrases), e.g. 「チェック」.
- Do not add a trailing period at the end of headings.
### Quotes
- Prefer Japanese corner brackets 「」 in normal prose when quoting a term.
- Do not change quotes inside inline code, code blocks, URLs, or file paths.
### Ellipsis
- Keep ellipsis style consistent with existing Japanese docs (commonly `...`).
- Never change `...` in code, URLs, or CLI examples.
### Preferred translations / glossary
Use the following preferred translations when they apply in documentation prose:
- request (HTTP): リクエスト
- response (HTTP): レスポンス
- path operation: パスオペレーション
- path operation function: パスオペレーション関数
### `///` admonitions
1) Keep the admonition keyword in English (do not translate `note`, `tip`, etc.).
2) If a title is present, prefer these canonical titles:
- `/// note | 備考`
- `/// note | 技術詳細`
- `/// tip | 豆知識`
- `/// warning | 注意`
- `/// info | 情報`
- `/// check | 確認`
- `/// danger | 警告`

503
docs/ko/docs/_llm-test.md Normal file
View File

@@ -0,0 +1,503 @@
# LLM 테스트 파일 { #llm-test-file }
이 문서는 문서를 번역하는 <abbr title="Large Language Model - 대규모 언어 모델">LLM</abbr>이 `scripts/translate.py``general_prompt``docs/{language code}/llm-prompt.md`의 언어별 프롬프트를 이해하는지 테스트합니다. 언어별 프롬프트는 `general_prompt`에 추가됩니다.
여기에 추가된 테스트는 언어별 프롬프트를 설계하는 모든 사람이 보게 됩니다.
사용 방법은 다음과 같습니다:
* 언어별 프롬프트 `docs/{language code}/llm-prompt.md`를 준비합니다.
* 이 문서를 원하는 대상 언어로 새로 번역합니다(예: `translate.py``translate-page` 명령). 그러면 `docs/{language code}/docs/_llm-test.md` 아래에 번역이 생성됩니다.
* 번역에서 문제가 없는지 확인합니다.
* 필요하다면 언어별 프롬프트, 일반 프롬프트, 또는 영어 문서를 개선합니다.
* 그런 다음 번역에서 남아 있는 문제를 수동으로 수정해 좋은 번역이 되게 합니다.
* 좋은 번역을 둔 상태에서 다시 번역합니다. 이상적인 결과는 LLM이 더 이상 번역에 변경을 만들지 않는 것입니다. 이는 일반 프롬프트와 언어별 프롬프트가 가능한 한 최선이라는 뜻입니다(때때로 몇 가지 seemingly random 변경을 할 수 있는데, 그 이유는 <a href="https://doublespeak.chat/#/handbook#deterministic-output" class="external-link" target="_blank">LLM은 결정론적 알고리즘이 아니기 때문</a>입니다).
테스트:
## 코드 스니펫 { #code-snippets }
//// tab | 테스트
다음은 코드 스니펫입니다: `foo`. 그리고 이것은 또 다른 코드 스니펫입니다: `bar`. 그리고 또 하나: `baz quux`.
////
//// tab | 정보
코드 스니펫의 내용은 그대로 두어야 합니다.
`scripts/translate.py`의 일반 프롬프트에서 `### Content of code snippets` 섹션을 참고하세요.
////
## 따옴표 { #quotes }
//// tab | 테스트
어제 제 친구가 이렇게 썼습니다: "If you spell incorrectly correctly, you have spelled it incorrectly". 이에 저는 이렇게 답했습니다: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"".
/// note | 참고
LLM은 아마 이것을 잘못 번역할 것입니다. 흥미로운 점은 재번역할 때 고정된 번역을 유지하는지 여부뿐입니다.
///
////
//// tab | 정보
프롬프트 설계자는 중립 따옴표를 타이포그래피 따옴표로 변환할지 선택할 수 있습니다. 그대로 두어도 괜찮습니다.
예를 들어 `docs/de/llm-prompt.md``### Quotes` 섹션을 참고하세요.
////
## 코드 스니펫의 따옴표 { #quotes-in-code-snippets }
//// tab | 테스트
`pip install "foo[bar]"`
코드 스니펫에서 문자열 리터럴의 예: `"this"`, `'that'`.
코드 스니펫에서 문자열 리터럴의 어려운 예: `f"I like {'oranges' if orange else "apples"}"`
하드코어: `Yesterday, my friend wrote: "If you spell incorrectly correctly, you have spelled it incorrectly". To which I answered: "Correct, but 'incorrectly' is incorrectly not '"incorrectly"'"`
////
//// tab | 정보
... 하지만 코드 스니펫 안의 따옴표는 그대로 유지되어야 합니다.
////
## 코드 블록 { #code-blocks }
//// tab | 테스트
Bash 코드 예시...
```bash
# 우주에 인사말 출력
echo "Hello universe"
```
...그리고 콘솔 코드 예시...
```console
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>
<span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span> Starting server
Searching for package file structure
```
...그리고 또 다른 콘솔 코드 예시...
```console
// "Code" 디렉터리 생성
$ mkdir code
// 해당 디렉터리로 이동
$ cd code
```
...그리고 Python 코드 예시...
```Python
wont_work() # 이건 동작하지 않습니다 😱
works(foo="bar") # 이건 동작합니다 🎉
```
...이상입니다.
////
//// tab | 정보
코드 블록의 코드는(주석을 제외하고) 수정하면 안 됩니다.
`scripts/translate.py`의 일반 프롬프트에서 `### Content of code blocks` 섹션을 참고하세요.
////
## 탭과 색상 박스 { #tabs-and-colored-boxes }
//// tab | 테스트
/// info | 정보
일부 텍스트
///
/// note | 참고
일부 텍스트
///
/// note Technical details | 기술 세부사항
일부 텍스트
///
/// check | 확인
일부 텍스트
///
/// tip | 팁
일부 텍스트
///
/// warning | 경고
일부 텍스트
///
/// danger | 위험
일부 텍스트
///
////
//// tab | 정보
탭과 `Info`/`Note`/`Warning`/등의 블록은 제목 번역을 수직 막대(`|`) 뒤에 추가해야 합니다.
`scripts/translate.py`의 일반 프롬프트에서 `### Special blocks``### Tab blocks` 섹션을 참고하세요.
////
## 웹 및 내부 링크 { #web-and-internal-links }
//// tab | 테스트
링크 텍스트는 번역되어야 하고, 링크 주소는 변경되지 않아야 합니다:
* [위의 제목으로 가는 링크](#code-snippets)
* [내부 링크](index.md#installation){.internal-link target=_blank}
* <a href="https://sqlmodel.tiangolo.com/" class="external-link" target="_blank">외부 링크</a>
* <a href="https://fastapi.tiangolo.com/css/styles.css" class="external-link" target="_blank">스타일로 가는 링크</a>
* <a href="https://fastapi.tiangolo.com/js/logic.js" class="external-link" target="_blank">스크립트로 가는 링크</a>
* <a href="https://fastapi.tiangolo.com/img/foo.jpg" class="external-link" target="_blank">이미지로 가는 링크</a>
링크 텍스트는 번역되어야 하고, 링크 주소는 번역 페이지를 가리켜야 합니다:
* <a href="https://fastapi.tiangolo.com/ko/" class="external-link" target="_blank">FastAPI 링크</a>
////
//// tab | 정보
링크는 번역되어야 하지만, 주소는 변경되지 않아야 합니다. 예외는 FastAPI 문서 페이지로 향하는 절대 링크이며, 이 경우 번역 페이지로 연결되어야 합니다.
`scripts/translate.py`의 일반 프롬프트에서 `### Links` 섹션을 참고하세요.
////
## HTML "abbr" 요소 { #html-abbr-elements }
//// tab | 테스트
여기 HTML "abbr" 요소로 감싼 몇 가지가 있습니다(일부는 임의로 만든 것입니다):
### abbr가 전체 문구를 제공 { #the-abbr-gives-a-full-phrase }
* <abbr title="Getting Things Done - 일을 끝내는 방법론">GTD</abbr>
* <abbr title="less than - 보다 작음"><code>lt</code></abbr>
* <abbr title="XML Web Token - XML 웹 토큰">XWT</abbr>
* <abbr title="Parallel Server Gateway Interface - 병렬 서버 게이트웨이 인터페이스">PSGI</abbr>
### abbr가 설명을 제공 { #the-abbr-gives-an-explanation }
* <abbr title="어떤 방식으로든 서로 연결되고 함께 작동하도록 구성된 머신들의 집합입니다.">cluster</abbr>
* <abbr title="입력과 출력 계층 사이에 수많은 은닉 계층을 둔 인공 신경망을 사용하는 머신 러닝 방법으로, 이를 통해 포괄적인 내부 구조를 형성합니다">Deep Learning</abbr>
### abbr가 전체 문구와 설명을 제공 { #the-abbr-gives-a-full-phrase-and-an-explanation }
* <abbr title="Mozilla Developer Network - 모질라 개발자 네트워크: Firefox를 만드는 사람들이 작성한 개발자용 문서">MDN</abbr>
* <abbr title="Input/Output - 입력/출력: 디스크 읽기 또는 쓰기, 네트워크 통신.">I/O</abbr>.
////
//// tab | 정보
"abbr" 요소의 "title" 속성은 몇 가지 구체적인 지침에 따라 번역됩니다.
번역에서는(영어 단어를 설명하기 위해) 자체 "abbr" 요소를 추가할 수 있으며, LLM은 이를 제거하면 안 됩니다.
`scripts/translate.py`의 일반 프롬프트에서 `### HTML abbr elements` 섹션을 참고하세요.
////
## 제목 { #headings }
//// tab | 테스트
### 웹앱 개발하기 - 튜토리얼 { #develop-a-webapp-a-tutorial }
안녕하세요.
### 타입 힌트와 -애너테이션 { #type-hints-and-annotations }
다시 안녕하세요.
### super- 및 subclasses { #super-and-subclasses }
다시 안녕하세요.
////
//// tab | 정보
제목에 대한 유일한 강한 규칙은, LLM이 중괄호 안의 해시 부분을 변경하지 않아 링크가 깨지지 않게 하는 것입니다.
`scripts/translate.py`의 일반 프롬프트에서 `### Headings` 섹션을 참고하세요.
언어별 지침은 예를 들어 `docs/de/llm-prompt.md``### Headings` 섹션을 참고하세요.
////
## 문서에서 사용되는 용어 { #terms-used-in-the-docs }
//// tab | 테스트
* 당신
* 당신의
* 예: (e.g.)
* 등 (etc.)
* `int`로서의 `foo`
* `str`로서의 `bar`
* `list`로서의 `baz`
* 튜토리얼 - 사용자 가이드
* 고급 사용자 가이드
* SQLModel 문서
* API 문서
* 자동 문서
* Data Science
* Deep Learning
* Machine Learning
* Dependency Injection
* HTTP Basic authentication
* HTTP Digest
* ISO format
* JSON Schema 표준
* JSON schema
* schema definition
* Password Flow
* Mobile
* deprecated
* designed
* invalid
* on the fly
* standard
* default
* case-sensitive
* case-insensitive
* 애플리케이션을 서빙하다
* 페이지를 서빙하다
*
* 애플리케이션
* 요청
* 응답
* 오류 응답
* 경로 처리
* 경로 처리 데코레이터
* 경로 처리 함수
* body
* 요청 body
* 응답 body
* JSON body
* form body
* file body
* 함수 body
* parameter
* body parameter
* path parameter
* query parameter
* cookie parameter
* header parameter
* form parameter
* function parameter
* event
* startup event
* 서버 startup
* shutdown event
* lifespan event
* handler
* event handler
* exception handler
* 처리하다
* model
* Pydantic model
* data model
* database model
* form model
* model object
* class
* base class
* parent class
* subclass
* child class
* sibling class
* class method
* header
* headers
* authorization header
* `Authorization` header
* forwarded header
* dependency injection system
* dependency
* dependable
* dependant
* I/O bound
* CPU bound
* concurrency
* parallelism
* multiprocessing
* env var
* environment variable
* `PATH`
* `PATH` variable
* authentication
* authentication provider
* authorization
* authorization form
* authorization provider
* 사용자가 인증한다
* 시스템이 사용자를 인증한다
* CLI
* command line interface
* server
* client
* cloud provider
* cloud service
* development
* development stages
* dict
* dictionary
* enumeration
* enum
* enum member
* encoder
* decoder
* encode하다
* decode하다
* exception
* raise하다
* expression
* statement
* frontend
* backend
* GitHub discussion
* GitHub issue
* performance
* performance optimization
* return type
* return value
* security
* security scheme
* task
* background task
* task function
* template
* template engine
* type annotation
* type hint
* server worker
* Uvicorn worker
* Gunicorn Worker
* worker process
* worker class
* workload
* deployment
* deploy하다
* SDK
* software development kit
* `APIRouter`
* `requirements.txt`
* Bearer Token
* breaking change
* bug
* button
* callable
* code
* commit
* context manager
* coroutine
* database session
* disk
* domain
* engine
* fake X
* HTTP GET method
* item
* library
* lifespan
* lock
* middleware
* mobile application
* module
* mounting
* network
* origin
* override
* payload
* processor
* property
* proxy
* pull request
* query
* RAM
* remote machine
* status code
* string
* tag
* web framework
* wildcard
* return하다
* validate하다
////
//// tab | 정보
이것은 문서에서 보이는 (대부분) 기술 용어의 불완전하고 비규범적인 목록입니다. 프롬프트 설계자가 어떤 용어에 대해 LLM에 추가적인 도움이 필요한지 파악하는 데 유용할 수 있습니다. 예를 들어, 좋은 번역을 계속 덜 좋은 번역으로 되돌릴 때, 또는 언어에서 용어의 활용/변화를 처리하는 데 문제가 있을 때 도움이 됩니다.
예를 들어 `docs/de/llm-prompt.md``### List of English terms and their preferred German translations` 섹션을 참고하세요.
////

View File

@@ -1,3 +1,3 @@
# 소개
# 소개 { #about }
FastAPI에 대한 디자인, 영감 등에 대해 🤓
FastAPI, 그 디자인, 영감 등에 대해 🤓

View File

@@ -0,0 +1,247 @@
# OpenAPI에서 추가 응답 { #additional-responses-in-openapi }
/// warning | 경고
이는 꽤 고급 주제입니다.
**FastAPI**를 막 시작했다면, 이 내용이 필요 없을 수도 있습니다.
///
추가 상태 코드, 미디어 타입, 설명 등을 포함한 추가 응답을 선언할 수 있습니다.
이러한 추가 응답은 OpenAPI 스키마에 포함되므로 API 문서에도 표시됩니다.
하지만 이러한 추가 응답의 경우, 상태 코드와 콘텐츠를 포함하여 `JSONResponse` 같은 `Response`를 직접 반환하도록 반드시 처리해야 합니다.
## `model`을 사용한 추가 응답 { #additional-response-with-model }
*경로 처리 데코레이터*에 `responses` 파라미터를 전달할 수 있습니다.
이는 `dict`를 받습니다. 키는 각 응답의 상태 코드(예: `200`)이고, 값은 각 응답에 대한 정보를 담은 다른 `dict`입니다.
각 응답 `dict`에는 `response_model`처럼 Pydantic 모델을 담는 `model` 키가 있을 수 있습니다.
**FastAPI**는 그 모델을 사용해 JSON Schema를 생성하고, OpenAPI의 올바른 위치에 포함합니다.
예를 들어, 상태 코드 `404`와 Pydantic 모델 `Message`를 사용하는 다른 응답을 선언하려면 다음과 같이 작성할 수 있습니다:
{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *}
/// note | 참고
`JSONResponse`를 직접 반환해야 한다는 점을 기억하세요.
///
/// info | 정보
`model` 키는 OpenAPI의 일부가 아닙니다.
**FastAPI**는 여기에서 Pydantic 모델을 가져와 JSON Schema를 생성하고 올바른 위치에 넣습니다.
올바른 위치는 다음과 같습니다:
* 값으로 또 다른 JSON 객체(`dict`)를 가지는 `content` 키 안에:
* 미디어 타입(예: `application/json`)을 키로 가지며, 값으로 또 다른 JSON 객체를 포함하고:
* `schema` 키가 있고, 그 값이 모델에서 생성된 JSON Schema입니다. 이것이 올바른 위치입니다.
* **FastAPI**는 이를 직접 포함하는 대신, OpenAPI의 다른 위치에 있는 전역 JSON Schemas를 참조하도록 여기에서 reference를 추가합니다. 이렇게 하면 다른 애플리케이션과 클라이언트가 그 JSON Schema를 직접 사용할 수 있고, 더 나은 코드 생성 도구 등을 제공할 수 있습니다.
///
이 *경로 처리*에 대해 OpenAPI에 생성되는 응답은 다음과 같습니다:
```JSON hl_lines="3-12"
{
"responses": {
"404": {
"description": "Additional Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
}
},
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
```
스키마는 OpenAPI 스키마 내부의 다른 위치를 참조합니다:
```JSON hl_lines="4-16"
{
"components": {
"schemas": {
"Message": {
"title": "Message",
"required": [
"message"
],
"type": "object",
"properties": {
"message": {
"title": "Message",
"type": "string"
}
}
},
"Item": {
"title": "Item",
"required": [
"id",
"value"
],
"type": "object",
"properties": {
"id": {
"title": "Id",
"type": "string"
},
"value": {
"title": "Value",
"type": "string"
}
}
},
"ValidationError": {
"title": "ValidationError",
"required": [
"loc",
"msg",
"type"
],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"type": "string"
}
},
"msg": {
"title": "Message",
"type": "string"
},
"type": {
"title": "Error Type",
"type": "string"
}
}
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {
"$ref": "#/components/schemas/ValidationError"
}
}
}
}
}
}
}
```
## 주요 응답에 대한 추가 미디어 타입 { #additional-media-types-for-the-main-response }
같은 `responses` 파라미터를 사용해 동일한 주요 응답에 대해 다른 미디어 타입을 추가할 수도 있습니다.
예를 들어, *경로 처리*가 JSON 객체(미디어 타입 `application/json`) 또는 PNG 이미지(미디어 타입 `image/png`)를 반환할 수 있다고 선언하기 위해 `image/png`라는 추가 미디어 타입을 추가할 수 있습니다:
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
/// note | 참고
이미지는 `FileResponse`를 사용해 직접 반환해야 한다는 점에 유의하세요.
///
/// info | 정보
`responses` 파라미터에서 다른 미디어 타입을 명시적으로 지정하지 않는 한, FastAPI는 응답이 주요 응답 클래스와 동일한 미디어 타입(기본값 `application/json`)을 가진다고 가정합니다.
하지만 커스텀 응답 클래스를 지정하면서 미디어 타입을 `None`으로 설정했다면, FastAPI는 연결된 모델이 있는 모든 추가 응답에 대해 `application/json`을 사용합니다.
///
## 정보 결합하기 { #combining-information }
`response_model`, `status_code`, `responses` 파라미터를 포함해 여러 위치의 응답 정보를 결합할 수도 있습니다.
기본 상태 코드 `200`(또는 필요하다면 커스텀 코드)을 사용하여 `response_model`을 선언하고, 그와 동일한 응답에 대한 추가 정보를 `responses`에서 OpenAPI 스키마에 직접 선언할 수 있습니다.
**FastAPI**는 `responses`의 추가 정보를 유지하고, 모델의 JSON Schema와 결합합니다.
예를 들어, Pydantic 모델을 사용하고 커스텀 `description`을 가진 상태 코드 `404` 응답을 선언할 수 있습니다.
또한 `response_model`을 사용하는 상태 코드 `200` 응답을 선언하되, 커스텀 `example`을 포함할 수도 있습니다:
{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *}
이 모든 내용은 OpenAPI에 결합되어 포함되고, API 문서에 표시됩니다:
<img src="/img/tutorial/additional-responses/image01.png">
## 미리 정의된 응답과 커스텀 응답 결합하기 { #combine-predefined-responses-and-custom-ones }
여러 *경로 처리*에 적용되는 미리 정의된 응답이 필요할 수도 있지만, 각 *경로 처리*마다 필요한 커스텀 응답과 결합하고 싶을 수도 있습니다.
그런 경우 Python의 `dict` “unpacking” 기법인 `**dict_to_unpack`을 사용할 수 있습니다:
```Python
old_dict = {
"old key": "old value",
"second old key": "second old value",
}
new_dict = {**old_dict, "new key": "new value"}
```
여기서 `new_dict`는 `old_dict`의 모든 키-값 쌍에 더해 새 키-값 쌍까지 포함합니다:
```Python
{
"old key": "old value",
"second old key": "second old value",
"new key": "new value",
}
```
이 기법을 사용해 *경로 처리*에서 일부 미리 정의된 응답을 재사용하고, 추가 커스텀 응답과 결합할 수 있습니다.
예를 들어:
{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}
## OpenAPI 응답에 대한 추가 정보 { #more-information-about-openapi-responses }
응답에 정확히 무엇을 포함할 수 있는지 보려면, OpenAPI 사양의 다음 섹션을 확인하세요:
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object" class="external-link" target="_blank">OpenAPI Responses Object</a>: `Response Object`를 포함합니다.
* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object" class="external-link" target="_blank">OpenAPI Response Object</a>: `responses` 파라미터 안의 각 응답에 이것의 어떤 항목이든 직접 포함할 수 있습니다. `description`, `headers`, `content`(여기에서 서로 다른 미디어 타입과 JSON Schema를 선언합니다), `links` 등을 포함할 수 있습니다.

View File

@@ -1,16 +1,16 @@
# 추가 상태 코드
# 추가 상태 코드 { #additional-status-codes }
기본적으로 **FastAPI**는 응답을 `JSONResponse`를 사용하여 반환하며, *경로 작업(path operation)*에서 반환한 내용을 해당 `JSONResponse` 안에 넣어 반환합니다.
기본 상태 코드 또는 *경로 작업*에서 설정한 상태 코드를 사용합니다.
## 추가 상태 코드
## 추가 상태 코드 { #additional-status-codes_1 }
기본 상태 코드와 별도로 추가 상태 코드를 반환하려면 `JSONResponse`와 같이 `Response`를 직접 반환하고 추가 상태 코드를 직접 설정할 수 있습니다.
예를 들어 항목을 업데이트할 수 있는 *경로 작업*이 있고 성공 시 200 “OK”의 HTTP 상태 코드를 반환한다고 가정해 보겠습니다.
하지만 새로운 항목을 허용하기를 원할 것입니다. 항목이 이전에 존재하지 않았다면 이를 생성하고 HTTP 상태 코드 201 "Created"를 반환합니다.
하지만 새로운 항목을 허용하기를 원할 것입니다. 그리고 항목이 이전에 존재하지 않았다면 이를 생성하고 HTTP 상태 코드 201 "Created"를 반환합니다.
이를 위해서는 `JSONResponse`를 가져와서 원하는 `status_code`를 설정하여 콘텐츠를 직접 반환합니다:
@@ -26,7 +26,7 @@
///
/// note | 기술 세부 정보
/// note | 기술 세부사항
`from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
@@ -34,7 +34,7 @@
///
## OpenAPI 및 API 문서
## OpenAPI 및 API 문서 { #openapi-and-api-docs }
추가 상태 코드와 응답을 직접 반환하는 경우, FastAPI는 반환할 내용을 미리 알 수 있는 방법이 없기 때문에 OpenAPI 스키마(API 문서)에 포함되지 않습니다.

View File

@@ -1,6 +1,6 @@
# 고급 의존성
# 고급 의존성 { #advanced-dependencies }
## 매개변수화된 의존성
## 매개변수화된 의존성 { #parameterized-dependencies }
지금까지 본 모든 의존성은 고정된 함수 또는 클래스입니다.
@@ -10,7 +10,7 @@
이때 해당 고정된 내용을 매개변수화할 수 있길 바랍니다.
## "호출 가능한" 인스턴스
## "호출 가능한" 인스턴스 { #a-callable-instance }
Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법이 있습니다.
@@ -21,9 +21,9 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *}
이 경우, **FastAPI**는 추가 매개변수와 하위 의존성을 확인하기 위해 `__call__`을 사용하게 되며,
나중에 *경로 연산 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다.
나중에 *경로 처리 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다.
## 인스턴스 매개변수화하기
## 인스턴스 매개변수화하기 { #parameterize-the-instance }
이제 `__init__`을 사용하여 의존성을 "매개변수화"할 수 있는 인스턴스의 매개변수를 선언할 수 있습니다:
@@ -31,7 +31,7 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법
이 경우, **FastAPI**는 `__init__`에 전혀 관여하지 않으며, 우리는 이 메서드를 코드에서 직접 사용하게 됩니다.
## 인스턴스 생성하기
## 인스턴스 생성하기 { #create-an-instance }
다음과 같이 이 클래스의 인스턴스를 생성할 수 있습니다:
@@ -39,10 +39,9 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법
이렇게 하면 `checker.fixed_content` 속성에 `"bar"`라는 값을 담아 의존성을 "매개변수화"할 수 있습니다.
## 인스턴스를 의존성으로 사용하기
## 인스턴스를 의존성으로 사용하기 { #use-the-instance-as-a-dependency }
그런 다음, `Depends(FixedContentQueryChecker)` 대신 `Depends(checker)`에서 이 `checker` 인스턴스를 사용할 수 있으며,
클래스 자체가 아닌 인스턴스 `checker`가 의존성이 됩니다.
그런 다음, 클래스 자체가 아닌 인스턴스 `checker`가 의존성이 되므로, `Depends(FixedContentQueryChecker)` 대신 `Depends(checker)`에서 이 `checker` 인스턴스를 사용할 수 있습니다.
의존성을 해결할 때 **FastAPI**는 이 `checker`를 다음과 같이 호출합니다:
@@ -50,18 +49,116 @@ Python에는 클래스의 인스턴스를 "호출 가능"하게 만드는 방법
checker(q="somequery")
```
...그리고 이때 반환되는 값을 *경로 연산 함수*의 `fixed_content_included` 매개변수 전달합니다:
...그리고 이때 반환되는 값을 *경로 처리 함수*의 의존성 값으로, `fixed_content_included` 매개변수 전달합니다:
{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *}
/// tip | 참고
/// tip |
이 모든 과정이 복잡하게 느껴질 수 있습니다. 그리고 지금은 이 방법이 얼마나 유용한지 명확하지 않을 수도 있습니다.
이 예시는 의도적으로 간단하게 만들었지만, 전체 구조가 어떻게 작동하는지 보여줍니다.
보안 관련 장에서는 이와 같은 방식으로 구현된 편의 함수들이 있습니다.
보안 관련 장에서는 이와 같은 방식으로 구현된 유틸리티 함수들이 있습니다.
이 모든 과정을 이해했다면, 이러한 보안 도구들이 내부적으로 어떻게 작동하는지 이미 파악한 것입니다.
이 모든 과정을 이해했다면, 이러한 보안용 유틸리티 도구들이 내부적으로 어떻게 작동하는지 이미 파악한 것입니다.
///
## `yield`, `HTTPException`, `except`, 백그라운드 태스크가 있는 의존성 { #dependencies-with-yield-httpexception-except-and-background-tasks }
/// warning | 경고
대부분의 경우 이러한 기술 세부사항이 필요하지 않을 것입니다.
이 세부사항은 주로 0.121.0 이전의 FastAPI 애플리케이션이 있고 `yield`가 있는 의존성에서 문제가 발생하는 경우에 유용합니다.
///
`yield`가 있는 의존성은 여러 사용 사례를 수용하고 일부 문제를 해결하기 위해 시간이 지나며 발전해 왔습니다. 다음은 변경된 내용의 요약입니다.
### `yield`와 `scope`가 있는 의존성 { #dependencies-with-yield-and-scope }
0.121.0 버전에서 FastAPI는 `yield`가 있는 의존성에 대해 `Depends(scope="function")` 지원을 추가했습니다.
`Depends(scope="function")`를 사용하면, `yield` 이후의 종료 코드는 *경로 처리 함수*가 끝난 직후(클라이언트에 응답이 반환되기 전)에 실행됩니다.
그리고 `Depends(scope="request")`(기본값)를 사용하면, `yield` 이후의 종료 코드는 응답이 전송된 후에 실행됩니다.
자세한 내용은 [Dependencies with `yield` - Early exit and `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) 문서를 참고하세요.
### `yield`가 있는 의존성과 `StreamingResponse`, 기술 세부사항 { #dependencies-with-yield-and-streamingresponse-technical-details }
FastAPI 0.118.0 이전에는 `yield`가 있는 의존성을 사용하면, *경로 처리 함수*가 반환된 뒤 응답을 보내기 직전에 `yield` 이후의 종료 코드가 실행되었습니다.
의도는 응답이 네트워크를 통해 전달되기를 기다리면서 필요한 것보다 더 오래 리소스를 점유하지 않도록 하는 것이었습니다.
이 변경은 `StreamingResponse`를 반환하는 경우에도 `yield`가 있는 의존성의 종료 코드가 이미 실행된다는 의미이기도 했습니다.
예를 들어, `yield`가 있는 의존성에 데이터베이스 세션이 있다면, `StreamingResponse`는 데이터를 스트리밍하는 동안 해당 세션을 사용할 수 없게 됩니다. `yield` 이후의 종료 코드에서 세션이 이미 닫혔기 때문입니다.
이 동작은 0.118.0에서 되돌려져, `yield` 이후의 종료 코드가 응답이 전송된 뒤 실행되도록 변경되었습니다.
/// info | 정보
아래에서 보시겠지만, 이는 0.106.0 버전 이전의 동작과 매우 비슷하지만, 여러 개선 사항과 코너 케이스에 대한 버그 수정이 포함되어 있습니다.
///
#### 종료 코드를 조기에 실행하는 사용 사례 { #use-cases-with-early-exit-code }
특정 조건의 일부 사용 사례에서는 응답을 보내기 전에 `yield`가 있는 의존성의 종료 코드를 실행하던 예전 동작이 도움이 될 수 있습니다.
예를 들어, `yield`가 있는 의존성에서 데이터베이스 세션을 사용해 사용자를 검증만 하고, *경로 처리 함수*에서는 그 데이터베이스 세션을 다시는 사용하지 않으며(의존성에서만 사용), **그리고** 응답을 전송하는 데 오랜 시간이 걸리는 경우를 생각해 봅시다. 예를 들어 데이터를 천천히 보내는 `StreamingResponse`인데, 어떤 이유로든 데이터베이스를 사용하지는 않는 경우입니다.
이 경우 데이터베이스 세션은 응답 전송이 끝날 때까지 유지되지만, 사용하지 않는다면 굳이 유지할 필요가 없습니다.
다음과 같이 보일 수 있습니다:
{* ../../docs_src/dependencies/tutorial013_an_py310.py *}
다음에서 `Session`을 자동으로 닫는 종료 코드는:
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
...응답이 느린 데이터 전송을 마친 뒤에 실행됩니다:
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
하지만 `generate_stream()`는 데이터베이스 세션을 사용하지 않으므로, 응답을 전송하는 동안 세션을 열린 채로 유지할 필요는 없습니다.
SQLModel(또는 SQLAlchemy)을 사용하면서 이런 특정 사용 사례가 있다면, 더 이상 필요하지 않을 때 세션을 명시적으로 닫을 수 있습니다:
{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}
그러면 세션이 데이터베이스 연결을 해제하여, 다른 요청들이 이를 사용할 수 있게 됩니다.
`yield`가 있는 의존성에서 조기 종료가 필요한 다른 사용 사례가 있다면, 여러분의 구체적인 사용 사례와 `yield`가 있는 의존성에 대한 조기 종료가 어떤 점에서 이득이 되는지를 포함해 <a href="https://github.com/fastapi/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussion Question</a>을 생성해 주세요.
`yield`가 있는 의존성에서 조기 종료에 대한 설득력 있는 사용 사례가 있다면, 조기 종료를 선택적으로 활성화할 수 있는 새로운 방법을 추가하는 것을 고려하겠습니다.
### `yield`가 있는 의존성과 `except`, 기술 세부사항 { #dependencies-with-yield-and-except-technical-details }
FastAPI 0.110.0 이전에는 `yield`가 있는 의존성을 사용한 다음 그 의존성에서 `except`로 예외를 잡고, 예외를 다시 발생시키지 않으면, 예외가 자동으로 어떤 예외 핸들러 또는 내부 서버 오류 핸들러로 raise/forward 되었습니다.
이는 핸들러 없이 전달된 예외(내부 서버 오류)로 인해 처리되지 않은 메모리 사용이 발생하는 문제를 수정하고, 일반적인 Python 코드의 동작과 일관되게 하기 위해 0.110.0 버전에서 변경되었습니다.
### 백그라운드 태스크와 `yield`가 있는 의존성, 기술 세부사항 { #background-tasks-and-dependencies-with-yield-technical-details }
FastAPI 0.106.0 이전에는 `yield` 이후에 예외를 발생시키는 것이 불가능했습니다. `yield`가 있는 의존성의 종료 코드는 응답이 전송된 *후에* 실행되었기 때문에, [Exception Handlers](../tutorial/handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}가 이미 실행된 뒤였습니다.
이는 주로 백그라운드 태스크 안에서 의존성이 "yield"한 동일한 객체들을 사용할 수 있게 하기 위한 설계였습니다. 백그라운드 태스크가 끝난 뒤에 종료 코드가 실행되었기 때문입니다.
이는 응답이 네트워크를 통해 전달되기를 기다리는 동안 리소스를 점유하지 않기 위한 의도로 FastAPI 0.106.0에서 변경되었습니다.
/// tip | 팁
추가로, 백그라운드 태스크는 보통 별도의 리소스(예: 자체 데이터베이스 연결)를 가지고 따로 처리되어야 하는 독립적인 로직 집합입니다.
따라서 이 방식이 코드를 더 깔끔하게 만들어줄 가능성이 큽니다.
///
이 동작에 의존하던 경우라면, 이제는 백그라운드 태스크를 위한 리소스를 백그라운드 태스크 내부에서 생성하고, 내부적으로는 `yield`가 있는 의존성의 리소스에 의존하지 않는 데이터만 사용해야 합니다.
예를 들어, 동일한 데이터베이스 세션을 사용하는 대신, 백그라운드 태스크 내부에서 새 데이터베이스 세션을 생성하고, 이 새 세션을 사용해 데이터베이스에서 객체를 가져오면 됩니다. 그리고 데이터베이스에서 가져온 객체를 백그라운드 태스크 함수의 매개변수로 전달하는 대신, 해당 객체의 ID를 전달한 다음 백그라운드 태스크 함수 내부에서 객체를 다시 가져오면 됩니다.

View File

@@ -1,31 +1,26 @@
# 비동기 테스트 코드 작성
# 비동기 테스트 { #async-tests }
이전 장에서 `TestClient` 이용해 **FastAPI** 플리케이션 테스트를 작성하는 법을 배우셨을텐데요.
지금까지는 `async` 키워드 사용없이 동기 함수의 테스트 코드를 작성하는 법만 익혔습니다.
제공된 `TestClient`사용하여 **FastAPI** 플리케이션을 테스트하는 방법을 이미 살펴보았습니다. 지금까지는 `async` 함수를 사용하지 않고, 동기 테스트를 작성하는 방법만 보았습니다.
하지만 비동기 함수를 사용하여 테스트 코드를 작성하는 것은 매우 유용할 수 있습니다.
예를 들면 데이터베이스에 비동기로 쿼리하는 경우를 생각해봅시다.
FastAPI 애플리케이션에 요청을 보내고, 비동기 데이터베이스 라이브러리를 사용하여 백엔드가 데이터베이스에 올바르게 데이터를 기록했는지 확인하고 싶을 때가 있을 겁니다.
테스트에서 비동기 함수를 사용할 수 있으면 유용할 수 있습니다. 예를 들어 데이터베이스를 비동기로 쿼리하는 경우를 생각해 보세요. FastAPI 애플리케이션에 요청을 보낸 다음, async 데이터베이스 라이브러리를 사용하면서 백엔드가 데이터베이스에 올바른 데이터를 성공적으로 기록했는지 검증하고 싶을 수 있습니다.
이런 경우의 테스트 코드를 어떻게 비동기로 작성하는지 알아봅시다.
어떻게 동작하게 만들 수 있는지 살펴보겠습니다.
## pytest.mark.anyio
## pytest.mark.anyio { #pytest-mark-anyio }
앞에서 작성한 테스트 함수에서 비동기 함수를 호출하고 싶다면, 테스트 코드도 비동기 함수여야합니다.
AnyIO는 특정 테스트 함수를 비동기 함수로 호출 할 수 있는 깔끔한 플러그인을 제공합니다.
테스트에서 비동기 함수를 호출하면, 테스트 함수도 비동기여야 합니다. AnyIO는 이를 위한 깔끔한 플러그인을 제공하며, 일부 테스트 함수를 비동기로 호출하도록 지정할 수 있습니다.
## HTTPX { #httpx }
## HTTPX
**FastAPI** 애플리케이션이 `async def` 대신 일반 `def` 함수를 사용하더라도, 내부적으로는 여전히 `async` 애플리케이션입니다.
**FastAPI** 애플리케이션`async def` 대신 `def` 키워드로 선언된 함수를 사용하더라도, 내부적으로는 여전히 `비동기` 애플리케이션입니다.
`TestClient`는 표준 pytest를 사용하여, 일반 `def` 테스트 함수 안에서 비동기 FastAPI 애플리케이션을 호출하도록 내부에서 마법 같은 처리를 합니다. 하지만 비동기 함수 안에서 이를 사용하면 그 마법은 더 이상 동작하지 않습니다. 테스트를 비동기로 실행하면, 테스트 함수 안에서 `TestClient`를 더 이상 사용할 수 없습니다.
`TestClient`pytest 표준을 사용하여 비동기 FastAPI 애플리케이션을 일반적인 `def` 테스트 함수 내에서 호출할 수 있도록 내부에서 마술을 부립니다. 하지만 이 마술은 비동기 함수 내부에서 사용할 때는 더 이상 작동하지 않습니다. 테스트를 비동기로 실행하면, 더 이상 테스트 함수 내부에서 `TestClient`를 사용할 수 습니다.
`TestClient`<a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>를 기반으로 하며, 다행히 HTTPX를 직접 사용해 API를 테스트할 수 습니다.
`TestClient`는 <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>를 기반으로 하고 있으며, 다행히 이를 직접 사용하여 API를 테스트할 수 있습니다.
## 예시 { #example }
## 예시
간단한 예시를 위해 [더 큰 어플리케이션 만들기](../ko/tutorial/bigger-applications.md){.internal-link target=_blank} 와 [테스트](../ko/tutorial/testing.md){.internal-link target=_blank}:에서 다룬 파일 구조와 비슷한 형태를 확인해봅시다:
간단한 예시로, [더 큰 애플리케이션](../tutorial/bigger-applications.md){.internal-link target=_blank}과 [테스트](../tutorial/testing.md){.internal-link target=_blank}에서 설명한 것과 비슷한 파일 구조를 살펴보겠습니다:
```
.
@@ -35,17 +30,17 @@ AnyIO는 특정 테스트 함수를 비동기 함수로 호출 할 수 있는
│   └── test_main.py
```
`main.py`는 아래와 같아야 합니다:
`main.py` 파일은 다음과 같습니다:
{* ../../docs_src/async_tests/main.py *}
{* ../../docs_src/async_tests/app_a_py39/main.py *}
`test_main.py` 파일 `main.py`에 대한 테스트가 있을 텐데, 다음과 같 수 있습니다:
`test_main.py` 파일에는 `main.py`에 대한 테스트가 있으며, 이제 다음과 같이 보일 수 있습니다:
{* ../../docs_src/async_tests/test_main.py *}
{* ../../docs_src/async_tests/app_a_py39/test_main.py *}
## 실행하기
## 실행하기 { #run-it }
아래의 명령어로 테스트 코드를 실행니다:
다음과 같이 평소처럼 테스트를 실행할 수 있습니다:
<div class="termy">
@@ -57,52 +52,48 @@ $ pytest
</div>
## 자세히 보기
## 자세히 보기 { #in-detail }
`@pytest.mark.anyio` 마커는 pytest에게 이 테스트 함수가 비동기로 호출되어야 함을 알려줍니다:
`@pytest.mark.anyio` 마커는 pytest에게 이 테스트 함수가 비동기로 호출되어야 한다고 알려줍니다:
{* ../../docs_src/async_tests/test_main.py hl[7] *}
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *}
/// tip | 팁
테스트 함수가 이제 `TestClient`를 사용할 때처럼 단순히 `def`가 아니라 `async def`로 작성된 점에 주목해주세요.
`TestClient`를 사용할 때처럼 단순히 `def`가 아니라, 이제 테스트 함수가 `async def`라는 점에 주목세요.
///
그 다음 `AsyncClient` 로 앱을 만들고 비동기 요청을 `await` 키워드로 보낼 수 있습니다:
그 다음 앱으로 `AsyncClient`를 만들고, `await`를 사용해 비동기 요청을 보낼 수 있습니다.
{* ../../docs_src/async_tests/test_main.py hl[9:12] *}
{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *}
위의 코드는:
이는 다음과 동등합니다:
```Python
response = client.get('/')
```
`TestClient` 요청을 보내던 것과 동일합니다.
`TestClient` 요청을 보내기 위해 사용하던 코드입니다.
/// tip | 팁
로운 `AsyncClient`를 사용할 때 async/await를 사용하고 있다는 점에 주목하세요. 요청은 비동기적으로 처리됩니다.
`AsyncClient`와 함께 async/await를 사용하고 있다는 점에 주목하세요. 요청은 비동기니다.
///
/// warning | 경고
만약의 어플리케이션이 Lifespan 이벤트에 의존성을 갖고 있다면 `AsyncClient` 이러한 이벤트를 실행시키지 않습니다.
`AsyncClient` 가 테스트를 실행시켰다는 것을 확인하기 위해
`LifespanManager` from <a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a>.확인해주세요.
플리케이션이 lifespan 이벤트에 의존다면, `AsyncClient` 이러한 이벤트를 트리거하지 않습니다. 이벤트가 트리거되도록 하려면 <a href="https://github.com/florimondmanca/asgi-lifespan#usage" class="external-link" target="_blank">florimondmanca/asgi-lifespan</a>의 `LifespanManager`를 사용하세요.
///
## 그 외의 비동기 함수 호출
## 기타 비동기 함수 호출 { #other-asynchronous-function-calls }
테스트 함수가 이제 비동기 함수이므로, FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 호출하고 `await` 키워드를 사용 할 수 있습니다.
테스트 함수가 이제 비동기이므로, 테스트에서 FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 코드의 다른 곳에서 호출하듯이 동일하게 호출하고 (`await`) 사용할 수 있습니다.
/// tip | 팁
테스트에 비동기 함수 호출을 통합할 때 (예: <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB의 MotorClient</a>를 사용할 때) `RuntimeError: Task attached to a different loop` 오류가 발생한다면, 이벤트 루프가 필요한 객체는 반드시 비동기 함수 에서만 인스턴스화해야 한다는 점을 주의하세요!
예를 들어 `@app.on_event("startup")` 콜백 내에서 인스턴스화하는 것이 좋습니다.
테스트에 비동기 함수 호출을 통합할 때(예: <a href="https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop" class="external-link" target="_blank">MongoDB의 MotorClient</a>를 사용할 때) `RuntimeError: Task attached to a different loop`를 마주친다면, 이벤트 루프가 필요한 객체는 async 함수 에서만 인스턴스화해야 한다는 점을 기억하세요. 예를 들어 `@app.on_event("startup")` 콜백에서 인스턴스화할 수 있습니다.
///

View File

@@ -0,0 +1,466 @@
# 프록시 뒤에서 실행하기 { #behind-a-proxy }
많은 경우 FastAPI 앱 앞단에 Traefik이나 Nginx 같은 **프록시(proxy)**를 두고 사용합니다.
이런 프록시는 HTTPS 인증서 처리 등 여러 작업을 담당할 수 있습니다.
## 프록시 전달 헤더 { #proxy-forwarded-headers }
애플리케이션 앞단의 **프록시**는 보통 **서버**로 요청을 보내기 전에, 해당 요청이 프록시에 의해 **전달(forwarded)**되었다는 것을 서버가 알 수 있도록 몇몇 헤더를 동적으로 설정합니다. 이를 통해 서버는 도메인을 포함한 원래의 (공개) URL, HTTPS 사용 여부 등 정보를 알 수 있습니다.
**서버** 프로그램(예: **FastAPI CLI**를 통해 실행되는 **Uvicorn**)은 이런 헤더를 해석할 수 있고, 그 정보를 애플리케이션으로 전달할 수 있습니다.
하지만 보안상, 서버는 자신이 신뢰할 수 있는 프록시 뒤에 있다는 것을 모르면 해당 헤더를 해석하지 않습니다.
/// note | 기술 세부사항
프록시 헤더는 다음과 같습니다:
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For" class="external-link" target="_blank">X-Forwarded-For</a>
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto" class="external-link" target="_blank">X-Forwarded-Proto</a>
* <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host" class="external-link" target="_blank">X-Forwarded-Host</a>
///
### 프록시 전달 헤더 활성화하기 { #enable-proxy-forwarded-headers }
FastAPI CLI를 *CLI 옵션* `--forwarded-allow-ips`로 실행하고, 전달 헤더를 읽을 수 있도록 신뢰할 IP 주소들을 넘길 수 있습니다.
`--forwarded-allow-ips="*"`로 설정하면 들어오는 모든 IP를 신뢰합니다.
**서버**가 신뢰할 수 있는 **프록시** 뒤에 있고 프록시만 서버에 접근한다면, 이는 해당 **프록시**의 IP가 무엇이든 간에 받아들이게 됩니다.
<div class="termy">
```console
$ fastapi run --forwarded-allow-ips="*"
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
### HTTPS에서 리디렉션 { #redirects-with-https }
예를 들어, *경로 처리* `/items/`를 정의했다고 해봅시다:
{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *}
클라이언트가 `/items`로 접근하면, 기본적으로 `/items/`로 리디렉션됩니다.
하지만 *CLI 옵션* `--forwarded-allow-ips`를 설정하기 전에는 `http://localhost:8000/items/`로 리디렉션될 수 있습니다.
그런데 애플리케이션이 `https://mysuperapp.com`에 호스팅되어 있고, 리디렉션도 `https://mysuperapp.com/items/`로 되어야 할 수 있습니다.
이때 `--proxy-headers`를 설정하면 FastAPI가 올바른 위치로 리디렉션할 수 있습니다. 😎
```
https://mysuperapp.com/items/
```
/// tip | 팁
HTTPS에 대해 더 알아보려면 가이드 [HTTPS에 대하여](../deployment/https.md){.internal-link target=_blank}를 확인하세요.
///
### 프록시 전달 헤더가 동작하는 방식 { #how-proxy-forwarded-headers-work }
다음은 **프록시**가 클라이언트와 **애플리케이션 서버** 사이에서 전달 헤더를 추가하는 과정을 시각적으로 나타낸 것입니다:
```mermaid
sequenceDiagram
participant Client
participant Proxy as Proxy/Load Balancer
participant Server as FastAPI Server
Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items
Note over Proxy: Proxy adds forwarded headers
Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items
Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)
Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs
Proxy->>Client: HTTPS Response
```
**프록시**는 원래의 클라이언트 요청을 가로채고, **애플리케이션 서버**로 요청을 전달하기 전에 특수한 *forwarded* 헤더(`X-Forwarded-*`)를 추가합니다.
이 헤더들은 그렇지 않으면 사라질 수 있는 원래 요청의 정보를 보존합니다:
* **X-Forwarded-For**: 원래 클라이언트의 IP 주소
* **X-Forwarded-Proto**: 원래 프로토콜(`https`)
* **X-Forwarded-Host**: 원래 호스트(`mysuperapp.com`)
**FastAPI CLI**를 `--forwarded-allow-ips`로 설정하면, 이 헤더를 신뢰하고 사용합니다. 예를 들어 리디렉션에서 올바른 URL을 생성하는 데 사용됩니다.
## 제거된 경로 접두사를 가진 프록시 { #proxy-with-a-stripped-path-prefix }
애플리케이션에 경로 접두사(prefix)를 추가하는 프록시를 둘 수도 있습니다.
이런 경우 `root_path`를 사용해 애플리케이션을 구성할 수 있습니다.
`root_path`는 (FastAPI가 Starlette를 통해 기반으로 하는) ASGI 사양에서 제공하는 메커니즘입니다.
`root_path`는 이러한 특정 사례를 처리하는 데 사용됩니다.
또한 서브 애플리케이션을 마운트할 때 내부적으로도 사용됩니다.
경로 접두사가 제거(stripped)되는 프록시가 있다는 것은, 코드에서는 `/app`에 경로를 선언하지만, 위에 한 겹(프록시)을 추가해 **FastAPI** 애플리케이션을 `/api/v1` 같은 경로 아래에 두는 것을 의미합니다.
이 경우 원래 경로 `/app`은 실제로 `/api/v1/app`에서 서비스됩니다.
코드는 모두 `/app`만 있다고 가정하고 작성되어 있는데도 말입니다.
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *}
그리고 프록시는 요청을 앱 서버(아마 FastAPI CLI를 통해 실행되는 Uvicorn)로 전달하기 전에, 동적으로 **경로 접두사**를 **"제거"**합니다. 그래서 애플리케이션은 여전히 `/app`에서 서비스된다고 믿게 되고, 코드 전체를 `/api/v1` 접두사를 포함하도록 수정할 필요가 없어집니다.
여기까지는 보통 정상적으로 동작합니다.
하지만 통합 문서 UI(프론트엔드)를 열면, OpenAPI 스키마를 `/api/v1/openapi.json`이 아니라 `/openapi.json`에서 가져오려고 합니다.
그래서 브라우저에서 실행되는 프론트엔드는 `/openapi.json`에 접근하려고 시도하지만 OpenAPI 스키마를 얻지 못합니다.
앱에 대해 `/api/v1` 경로 접두사를 가진 프록시가 있으므로, 프론트엔드는 `/api/v1/openapi.json`에서 OpenAPI 스키마를 가져와야 합니다.
```mermaid
graph LR
browser("Browser")
proxy["Proxy on http://0.0.0.0:9999/api/v1/app"]
server["Server on http://127.0.0.1:8000/app"]
browser --> proxy
proxy --> server
```
/// tip | 팁
IP `0.0.0.0`은 보통 해당 머신/서버에서 사용 가능한 모든 IP에서 프로그램이 리슨한다는 의미로 사용됩니다.
///
문서 UI는 또한 OpenAPI 스키마에서 이 API `server``/api/v1`(프록시 뒤) 위치에 있다고 선언해야 합니다. 예:
```JSON hl_lines="4-8"
{
"openapi": "3.1.0",
// More stuff here
"servers": [
{
"url": "/api/v1"
}
],
"paths": {
// More stuff here
}
}
```
이 예시에서 "Proxy"는 **Traefik** 같은 것이고, 서버는 **Uvicorn**으로 실행되는 FastAPI CLI처럼, FastAPI 애플리케이션을 실행하는 구성일 수 있습니다.
### `root_path` 제공하기 { #providing-the-root-path }
이를 달성하려면 다음처럼 커맨드 라인 옵션 `--root-path`를 사용할 수 있습니다:
<div class="termy">
```console
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
Hypercorn을 사용한다면, Hypercorn에도 `--root-path` 옵션이 있습니다.
/// note | 기술 세부사항
ASGI 사양은 이 사용 사례를 위해 `root_path`를 정의합니다.
그리고 커맨드 라인 옵션 `--root-path`가 그 `root_path`를 제공합니다.
///
### 현재 `root_path` 확인하기 { #checking-the-current-root-path }
요청마다 애플리케이션에서 사용 중인 현재 `root_path`를 얻을 수 있는데, 이는 `scope` 딕셔너리(ASGI 사양의 일부)에 포함되어 있습니다.
여기서는 데모 목적을 위해 메시지에 포함하고 있습니다.
{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *}
그 다음 Uvicorn을 다음과 같이 시작하면:
<div class="termy">
```console
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
응답은 다음과 비슷할 것입니다:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
### FastAPI 앱에서 `root_path` 설정하기 { #setting-the-root-path-in-the-fastapi-app }
또는 `--root-path` 같은 커맨드 라인 옵션(또는 동등한 방법)을 제공할 수 없는 경우, FastAPI 앱을 생성할 때 `root_path` 파라미터를 설정할 수 있습니다:
{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *}
`FastAPI`에 `root_path`를 전달하는 것은 Uvicorn이나 Hypercorn에 커맨드 라인 옵션 `--root-path`를 전달하는 것과 동일합니다.
### `root_path`에 대하여 { #about-root-path }
서버(Uvicorn)는 그 `root_path`를 앱에 전달하는 것 외에는 다른 용도로 사용하지 않는다는 점을 기억하세요.
하지만 브라우저로 <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a>에 접속하면 정상 응답을 볼 수 있습니다:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
따라서 `http://127.0.0.1:8000/api/v1/app`로 접근될 것이라고 기대하지는 않습니다.
Uvicorn은 프록시가 `http://127.0.0.1:8000/app`에서 Uvicorn에 접근할 것을 기대하고, 그 위에 `/api/v1` 접두사를 추가하는 것은 프록시의 책임입니다.
## 제거된 경로 접두사를 가진 프록시에 대하여 { #about-proxies-with-a-stripped-path-prefix }
경로 접두사가 제거되는 프록시는 구성 방법 중 하나일 뿐이라는 점을 기억하세요.
많은 경우 기본값은 프록시가 경로 접두사를 제거하지 않는 방식일 것입니다.
그런 경우(경로 접두사를 제거하지 않는 경우) 프록시는 `https://myawesomeapp.com` 같은 곳에서 리슨하고, 브라우저가 `https://myawesomeapp.com/api/v1/app`로 접근하면, 서버(예: Uvicorn)가 `http://127.0.0.1:8000`에서 리슨하고 있을 때 프록시(경로 접두사를 제거하지 않는)는 동일한 경로로 Uvicorn에 접근합니다: `http://127.0.0.1:8000/api/v1/app`.
## Traefik으로 로컬 테스트하기 { #testing-locally-with-traefik }
<a href="https://docs.traefik.io/" class="external-link" target="_blank">Traefik</a>을 사용하면, 경로 접두사가 제거되는 구성을 로컬에서 쉽게 실험할 수 있습니다.
<a href="https://github.com/containous/traefik/releases" class="external-link" target="_blank">Traefik 다운로드</a>는 단일 바이너리이며, 압축 파일을 풀고 터미널에서 바로 실행할 수 있습니다.
그 다음 다음 내용을 가진 `traefik.toml` 파일을 생성하세요:
```TOML hl_lines="3"
[entryPoints]
[entryPoints.http]
address = ":9999"
[providers]
[providers.file]
filename = "routes.toml"
```
이는 Traefik이 9999 포트에서 리슨하고, 다른 파일 `routes.toml`을 사용하도록 지시합니다.
/// tip | 팁
표준 HTTP 포트 80 대신 9999 포트를 사용해서, 관리자(`sudo`) 권한으로 실행하지 않아도 되게 했습니다.
///
이제 다른 파일 `routes.toml`을 생성하세요:
```TOML hl_lines="5 12 20"
[http]
[http.middlewares]
[http.middlewares.api-stripprefix.stripPrefix]
prefixes = ["/api/v1"]
[http.routers]
[http.routers.app-http]
entryPoints = ["http"]
service = "app"
rule = "PathPrefix(`/api/v1`)"
middlewares = ["api-stripprefix"]
[http.services]
[http.services.app]
[http.services.app.loadBalancer]
[[http.services.app.loadBalancer.servers]]
url = "http://127.0.0.1:8000"
```
이 파일은 Traefik이 경로 접두사 `/api/v1`을 사용하도록 설정합니다.
그리고 Traefik은 요청을 `http://127.0.0.1:8000`에서 실행 중인 Uvicorn으로 전달합니다.
이제 Traefik을 시작하세요:
<div class="termy">
```console
$ ./traefik --configFile=traefik.toml
INFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml
```
</div>
그리고 `--root-path` 옵션을 사용해 앱을 시작하세요:
<div class="termy">
```console
$ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
### 응답 확인하기 { #check-the-responses }
이제 Uvicorn의 포트로 된 URL인 <a href="http://127.0.0.1:8000/app" class="external-link" target="_blank">http://127.0.0.1:8000/app</a>로 접속하면 정상 응답을 볼 수 있습니다:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
/// tip | 팁
`http://127.0.0.1:8000/app`로 접근했는데도 `/api/v1`의 `root_path`가 표시되는 것에 주의하세요. 이는 옵션 `--root-path`에서 가져온 값입니다.
///
이제 Traefik의 포트가 포함되고 경로 접두사가 포함된 URL <a href="http://127.0.0.1:9999/api/v1/app" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/app</a>을 여세요.
동일한 응답을 얻습니다:
```JSON
{
"message": "Hello World",
"root_path": "/api/v1"
}
```
하지만 이번에는 프록시가 제공한 접두사 경로 `/api/v1`이 포함된 URL에서의 응답입니다.
물론 여기서의 아이디어는 모두가 프록시를 통해 앱에 접근한다는 것이므로, `/api/v1` 경로 접두사가 있는 버전이 "올바른" 접근입니다.
그리고 경로 접두사가 없는 버전(`http://127.0.0.1:8000/app`)은 Uvicorn이 직접 제공하는 것이며, 오직 _프록시_(Traefik)가 접근하기 위한 용도입니다.
이는 프록시(Traefik)가 경로 접두사를 어떻게 사용하는지, 그리고 서버(Uvicorn)가 옵션 `--root-path`로부터의 `root_path`를 어떻게 사용하는지를 보여줍니다.
### 문서 UI 확인하기 { #check-the-docs-ui }
하지만 재미있는 부분은 여기입니다. ✨
앱에 접근하는 "공식" 방법은 우리가 정의한 경로 접두사를 가진 프록시를 통해서입니다. 따라서 기대하는 대로, URL에 경로 접두사가 없는 상태에서 Uvicorn이 직접 제공하는 docs UI를 시도하면, 프록시를 통해 접근된다고 가정하고 있기 때문에 동작하지 않습니다.
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>에서 확인할 수 있습니다:
<img src="/img/tutorial/behind-a-proxy/image01.png">
하지만 프록시(포트 `9999`)를 사용해 "공식" URL인 `/api/v1/docs`에서 docs UI에 접근하면, 올바르게 동작합니다! 🎉
<a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>에서 확인할 수 있습니다:
<img src="/img/tutorial/behind-a-proxy/image02.png">
원하던 그대로입니다. ✔️
이는 FastAPI가 이 `root_path`를 사용해, OpenAPI에서 기본 `server`를 `root_path`가 제공한 URL로 생성하기 때문입니다.
## 추가 서버 { #additional-servers }
/// warning | 경고
이는 더 고급 사용 사례입니다. 건너뛰어도 괜찮습니다.
///
기본적으로 **FastAPI**는 OpenAPI 스키마에서 `root_path`의 URL로 `server`를 생성합니다.
하지만 예를 들어 동일한 docs UI가 스테이징과 프로덕션 환경 모두와 상호작용하도록 하려면, 다른 대안 `servers`를 제공할 수도 있습니다.
사용자 정의 `servers` 리스트를 전달했고 `root_path`(API가 프록시 뒤에 있기 때문)가 있다면, **FastAPI**는 리스트의 맨 앞에 이 `root_path`를 가진 "server"를 삽입합니다.
예:
{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *}
다음과 같은 OpenAPI 스키마를 생성합니다:
```JSON hl_lines="5-7"
{
"openapi": "3.1.0",
// More stuff here
"servers": [
{
"url": "/api/v1"
},
{
"url": "https://stag.example.com",
"description": "Staging environment"
},
{
"url": "https://prod.example.com",
"description": "Production environment"
}
],
"paths": {
// More stuff here
}
}
```
/// tip | 팁
`root_path`에서 가져온 값인 `/api/v1`의 `url` 값을 가진, 자동 생성된 server에 주목하세요.
///
<a href="http://127.0.0.1:9999/api/v1/docs" class="external-link" target="_blank">http://127.0.0.1:9999/api/v1/docs</a>의 docs UI에서는 다음처럼 보입니다:
<img src="/img/tutorial/behind-a-proxy/image03.png">
/// tip | 팁
docs UI는 선택한 server와 상호작용합니다.
///
/// note | 기술 세부사항
OpenAPI 사양에서 `servers` 속성은 선택 사항입니다.
`servers` 파라미터를 지정하지 않고 `root_path`가 `/`와 같다면, 생성된 OpenAPI 스키마의 `servers` 속성은 기본적으로 완전히 생략되며, 이는 `url` 값이 `/`인 단일 server와 동등합니다.
///
### `root_path`에서 자동 server 비활성화하기 { #disable-automatic-server-from-root-path }
**FastAPI**가 `root_path`를 사용한 자동 server를 포함하지 않게 하려면, `root_path_in_servers=False` 파라미터를 사용할 수 있습니다:
{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *}
그러면 OpenAPI 스키마에 포함되지 않습니다.
## 서브 애플리케이션 마운트하기 { #mounting-a-sub-application }
프록시에서 `root_path`를 사용하면서도, [서브 애플리케이션 - 마운트](sub-applications.md){.internal-link target=_blank}에 설명된 것처럼 서브 애플리케이션을 마운트해야 한다면, 기대하는 대로 일반적으로 수행할 수 있습니다.
FastAPI가 내부적으로 `root_path`를 똑똑하게 사용하므로, 그냥 동작합니다. ✨

View File

@@ -1,4 +1,4 @@
# 사용자 정의 응답 - HTML, Stream, 파일, 기타
# 사용자 정의 응답 - HTML, Stream, 파일, 기타 { #custom-response-html-stream-file-others }
기본적으로, **FastAPI** 응답을 `JSONResponse`를 사용하여 반환합니다.
@@ -6,11 +6,11 @@
그러나 `Response` (또는 `JSONResponse`와 같은 하위 클래스)를 직접 반환하면, 데이터가 자동으로 변환되지 않으며 (심지어 `response_model`을 선언했더라도), 문서화가 자동으로 생성되지 않습니다(예를 들어, 생성된 OpenAPI의 일부로 HTTP 헤더 `Content-Type`에 특정 "미디어 타입"을 포함하는 경우).
하지만 *경로 작업 데코레이터*에서 `response_class` 매개변수를 사용하여 원하는 `Response`(예: 모든 `Response` 하위 클래스)를 선언할 수도 있습니다.
하지만 *경로 처리 데코레이터*에서 `response_class` 매개변수를 사용하여 원하는 `Response`(예: 모든 `Response` 하위 클래스)를 선언할 수도 있습니다.
*경로 작업 함수*에서 반환하는 내용은 해당 `Response`안에 포함됩니다.
*경로 처리 함수*에서 반환하는 내용은 해당 `Response`안에 포함됩니다.
그리고 만약 그 `Response``JSONResponse``UJSONResponse`의 경우 처럼 JSON 미디어 타입(`application/json`)을 가지고 있다면, *경로 작업 데코레이터*에서 선언한 Pydantic의 `response_model`을 사용해 자동으로 변환(및 필터링) 됩니다.
그리고 만약 그 `Response``JSONResponse``UJSONResponse`의 경우 처럼 JSON 미디어 타입(`application/json`)을 가지고 있다면, *경로 처리 데코레이터*에서 선언한 Pydantic의 `response_model`을 사용해 자동으로 변환(및 필터링) 됩니다.
/// note | 참고
@@ -18,11 +18,11 @@
///
## `ORJSONResponse` 사용하기
## `ORJSONResponse` 사용하기 { #use-orjsonresponse }
예를 들어, 성능을 극대화하려는 경우, <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">orjson</a>을 설치하여 사용하고 응답을 `ORJSONResponse`로 설정할 수 있습니다.
예를 들어, 성능을 극대화하려는 경우, <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>을 설치하여 사용하고 응답을 `ORJSONResponse`로 설정할 수 있습니다.
사용하고자 하는 `Response` 클래스(하위 클래스)를 임포트한 후, **경로 작업 데코레이터*에서 선언하세요.
사용하고자 하는 `Response` 클래스(하위 클래스)를 임포트한 후, *경로 처리 데코레이터*에서 선언하세요.
대규모 응답의 경우, 딕셔너리를 반환하는 것보다 `Response`를 반환하는 것이 훨씬 빠릅니다.
@@ -30,7 +30,7 @@
하지만 반환하는 내용이 **JSON으로 직렬화 가능**하다고 확신하는 경우, 해당 내용을 응답 클래스에 직접 전달할 수 있으며, FastAPI가 반환 내용을 `jsonable_encoder`를 통해 처리한 뒤 응답 클래스에 전달하는 오버헤드를 피할 수 있습니다.
{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
/// info | 정보
@@ -48,14 +48,14 @@
///
## HTML 응답
## HTML 응답 { #html-response }
**FastAPI**에서 HTML 응답을 직접 반환하려면 `HTMLResponse`를 사용하세요.
* `HTMLResponse`를 임포트 합니다.
* *경로 작업 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다.
* *경로 처리 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다.
{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
/// info | 정보
@@ -67,17 +67,17 @@
///
### `Response` 반환하기
### `Response` 반환하기 { #return-a-response }
[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 본 것 처럼, *경로 작업*에서 응답을 직접 반환하여 재정의할 수도 있습니다.
[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 본 것 처럼, *경로 처리*에서 응답을 직접 반환하여 재정의할 수도 있습니다.
위의 예제와 동일하게 `HTMLResponse`를 반환하는 코드는 다음과 같을 수 있습니다:
{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
/// warning | 경고
*경로 작업 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를들어, `Content-Type`이 문서화되지 않음) 자동 대화형 문서에서도 표시되지 않습니다.
*경로 처리 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를들어, `Content-Type`이 문서화되지 않음) 자동 대화형 문서에서도 표시되지 않습니다.
///
@@ -87,27 +87,27 @@
///
### OpenAPI에 문서화하고 `Response` 재정의 하기
### OpenAPI에 문서화하고 `Response` 재정의 하기 { #document-in-openapi-and-override-response }
함수 내부에서 응답을 재정의하면서 동시에 OpenAPI에서 "미디어 타입"을 문서화하고 싶다면, `response_class` 매게변수를 사용하면서 `Response` 객체를 반환할 수 있습니다.
이 경우 `response_class`는 OpenAPI *경로 작업*을 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `Response`가 그대로 사용됩니다.
이 경우 `response_class`는 OpenAPI *경로 처리*를 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `Response`가 그대로 사용됩니다.
### `HTMLResponse`직접 반환하기
#### `HTMLResponse`직접 반환하기 { #return-an-htmlresponse-directly }
예를 들어, 다음과 같이 작성할 수 있습니다:
{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *}
{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *}
이 예제에서, `generate_html_response()` 함수는 HTML을 `str`로 반환하는 대신 이미 `Response`를 생성하고 반환합니다.
`generate_html_response()`를 호출한 결과를 반환함으로써, 기본적인 **FastAPI** 기본 동작을 재정의 하는 `Response`를 이미 반환하고 있습니다.
하지만 `response_class``HTMLResponse`를 함께 전달했기 때문에, FastAPI는 이를 OpenAPI 및 대화형 문서에서 `text/html`로 HTML을 문서화 하는 방법을 알 수 있습니다.
하지만 `response_class``HTMLResponse`를 함께 전달했기 때문에, **FastAPI**는 이를 OpenAPI 및 대화형 문서에서 `text/html`로 HTML을 문서화 하는 방법을 알 수 있습니다.
<img src="/img/tutorial/custom-response/image01.png">
## 사용 가능한 응답들
## 사용 가능한 응답들 { #available-responses }
다음은 사용할 수 있는 몇가지 응답들 입니다.
@@ -121,7 +121,7 @@
///
### `Response`
### `Response` { #response }
기본 `Response` 클래스는 다른 모든 응답 클래스의 부모 클래스 입니다.
@@ -134,27 +134,27 @@
* `headers` - 문자열로 이루어진 `dict`.
* `media_type` - 미디어 타입을 나타내는 `str` 예: `"text/html"`.
FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포함시킵니다. 또한 `media_type`에 기반하여 `Content-Type` 헤더를 포함하며, 텍스트 타입의 경우 문자 집합을 추가 합니다.
FastAPI (실제로는 Starlette)가 자동으로 Content-Length 헤더를 포함시킵니다. 또한 `media_type`에 기반하여 Content-Type 헤더를 포함하며, 텍스트 타입의 경우 문자 집합을 추가 합니다.
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
### `HTMLResponse`
### `HTMLResponse` { #htmlresponse }
텍스트 또는 바이트를 받아 HTML 응답을 반환합니다. 위에서 설명한 내용과 같습니다.
### `PlainTextResponse`
### `PlainTextResponse` { #plaintextresponse }
텍스트 또는 바이트를 받아 일반 텍스트 응답을 반환합니다.
{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *}
### `JSONResponse`
### `JSONResponse` { #jsonresponse }
데이터를 받아 `application/json`으로 인코딩된 응답을 반환합니다.
이는 위에서 설명했듯이 **FastAPI**에서 기본적으로 사용되는 응답 형식입니다.
### `ORJSONResponse`
### `ORJSONResponse` { #orjsonresponse }
<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>을 사용하여 빠른 JSON 응답을 제공하는 대안입니다. 위에서 설명한 내용과 같습니다.
@@ -164,13 +164,13 @@ FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포
///
### `UJSONResponse`
### `UJSONResponse` { #ujsonresponse }
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>을 사용한 또 다른 JSON 응답 형식입니다.
/// info | 정보
이 응답을 사용하려면 `ujson`을 설치해야합니다. 예: 'pip install ujson`.
이 응답을 사용하려면 `ujson`을 설치해야합니다. 예: `pip install ujson`.
///
@@ -180,7 +180,7 @@ FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포
///
{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
/// tip | 팁
@@ -188,22 +188,22 @@ FastAPI (실제로는 Starlette)가 자동으로 `Content-Length` 헤더를 포
///
### `RedirectResponse`
### `RedirectResponse` { #redirectresponse }
HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 307(임시 리디렉션)으로 설정됩니다.
`RedirectResponse`를 직접 반환할 수 있습니다.
{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
---
또는 `response_class` 매개변수에서 사용할 수도 있습니다:
{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
이 경우, *경로 작업* 함수에서 URL을 직접 반환할 수 있습니다.
이 경우, *경로 처리* 함수에서 URL을 직접 반환할 수 있습니다.
이 경우, 사용되는 `status_code``RedirectResponse`의 기본값인 `307` 입니다.
@@ -211,23 +211,23 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30
`status_code` 매개변수를 `response_class` 매개변수와 함께 사용할 수도 있습니다:
{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *}
{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
### `StreamingResponse`
### `StreamingResponse` { #streamingresponse }
비동기 제너레이터 또는 일반 제너레이터/이터레이터를 받아 응답 본문을 스트리밍 합니다.
{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
#### 파일과 같은 객체를 사용한 `StreamingResponse`
#### 파일과 같은 객체를 사용한 `StreamingResponse` { #using-streamingresponse-with-file-like-objects }
파일과 같은 객체(예: `open()`으로 반환된 객체)가 있는 경우, 해당 파일과 같은 객체를 반복(iterate)하는 제너레이터 함수를 만들 수 있습니다.
<a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> 객체(예: `open()`으로 반환된 객체)가 있는 경우, 해당 file-like 객체를 반복(iterate)하는 제너레이터 함수를 만들 수 있습니다.
이 방식으로, 파일 전체를 메모리에 먼저 읽어들일 필요 없이, 제너레이터 함수를 `StreamingResponse`에 전달하여 반환할 수 있습니다.
이 방식은 클라우드 스토리지, 비디오 처리 등의 다양한 라이브러리와 함께 사용할 수 있습니다.
{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}
{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
1. 이것이 제너레이터 함수입니다. `yield` 문을 포함하고 있으므로 "제너레이터 함수"입니다.
2. `with` 블록을 사용함으로써, 제너레이터 함수가 완료된 후 파일과 같은 객체가 닫히도록 합니다. 즉, 응답 전송이 끝난 후 닫힙니다.
@@ -235,15 +235,15 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30
이렇게 하면 "생성(generating)" 작업을 내부적으로 다른 무언가에 위임하는 제너레이터 함수가 됩니다.
이 방식을 사용하면 `with` 블록 안에서 파일을 열 수 있어, 작업이 완료된 후 파일과 같은 객체가 닫히는 것을 보장할 수 있습니다.
이 방식을 사용하면 `with` 블록 안에서 파일을 열 수 있어, 작업이 완료된 후 파일과 같은 객체가 닫히는 것을 보장할 수 있습니다.
/// tip | 팁
여기서 표준 `open()`을 사용하고 있기 때문에 `async`와 `await`를 지원하지 않습니다. 따라서 경로 작업은 일반 `def`로 선언합니다.
여기서 표준 `open()`을 사용하고 있기 때문에 `async``await`를 지원하지 않습니다. 따라서 경로 처리는 일반 `def`로 선언합니다.
///
### `FileResponse`
### `FileResponse` { #fileresponse }
파일을 비동기로 스트리밍하여 응답합니다.
@@ -256,25 +256,25 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30
파일 응답에는 적절한 `Content-Length`, `Last-Modified`, 및 `ETag` 헤더가 포함됩니다.
{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *}
{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *}
또한 `response_class` 매개변수를 사용할 수도 있습니다:
{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *}
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
이 경우, 경로 작업 함수에서 파일 경로를 직접 반환할 수 있습니다.
이 경우, 경로 처리 함수에서 파일 경로를 직접 반환할 수 있습니다.
## 사용자 정의 응답 클래스
## 사용자 정의 응답 클래스 { #custom-response-class }
`Response`를 상속받아 사용자 정의 응답 클래스를 생성하고 사용할 수 있습니다.
예를 들어, 포함된 `ORJSONResponse` 클래스에서 사용되지 않는 설정으로 <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">orjson</a>을 사용하고 싶다고 가정해봅시다.
예를 들어, 포함된 `ORJSONResponse` 클래스에서 사용되지 않는 설정으로 <a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>을 사용하고 싶다고 가정해봅시다.
만약 들여쓰기 및 포맷된 JSON을 반환하고 싶다면, `orjson.OPT_INDENT_2` 옵션을 사용할 수 있습니다.
`CustomORJSONResponse`를 생성할 수 있습니다. 여기서 핵심은 `Response.render(content)` 메서드를 생성하여 내용을 `bytes`로 반환하는 것입니다:
{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *}
{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
이제 다음 대신:
@@ -282,7 +282,7 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30
{"message": "Hello World"}
```
이 응답은 이렇게 반환됩니다:
...이 응답은 이렇게 반환됩니다:
```json
{
@@ -292,22 +292,22 @@ HTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 30
물론 JSON 포맷팅보다 더 유용하게 활용할 방법을 찾을 수 있을 것입니다. 😉
## 기본 응답 클래스
## 기본 응답 클래스 { #default-response-class }
**FastAPI** 클래스 객체 또는 `APIRouter`를 생성할 때 기본적으로 사용할 응답 클래스를 지정할 수 있습니다.
이를 정의하는 매개변수는 `default_response_class`입니다.
아래 예제에서 **FastAPI**는 모든 경로 작업에서 기본적으로 `JSONResponse` 대신 `ORJSONResponse`를 사용합니다.
아래 예제에서 **FastAPI**는 모든 *경로 처리*에서 기본적으로 `JSONResponse` 대신 `ORJSONResponse`를 사용합니다.
{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
/// tip | 팁
여전히 이전처럼 *경로 작업*에서 `response_class`를 재정의할 수 있습니다.
여전히 이전처럼 *경로 처리*에서 `response_class`를 재정의할 수 있습니다.
///
## 추가 문서화
## 추가 문서화 { #additional-documentation }
OpenAPI에서 `responses`를 사용하여 미디어 타입 및 기타 세부 정보를 선언할 수도 있습니다: [OpenAPI에서 추가 응답](additional-responses.md){.internal-link target=_blank}.

View File

@@ -0,0 +1,95 @@
# Dataclasses 사용하기 { #using-dataclasses }
FastAPI는 **Pydantic** 위에 구축되어 있으며, 지금까지는 Pydantic 모델을 사용해 요청과 응답을 선언하는 방법을 보여드렸습니다.
하지만 FastAPI는 <a href="https://docs.python.org/3/library/dataclasses.html" class="external-link" target="_blank">`dataclasses`</a>도 같은 방식으로 사용하는 것을 지원합니다:
{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}
이는 **Pydantic** 덕분에 여전히 지원되는데, Pydantic이 <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel" class="external-link" target="_blank">`dataclasses`에 대한 내부 지원</a>을 제공하기 때문입니다.
따라서 위 코드처럼 Pydantic을 명시적으로 사용하지 않더라도, FastAPI는 Pydantic을 사용해 표준 dataclasses를 Pydantic의 dataclasses 변형으로 변환합니다.
그리고 물론 다음과 같은 기능도 동일하게 지원합니다:
* 데이터 검증
* 데이터 직렬화
* 데이터 문서화 등
이는 Pydantic 모델을 사용할 때와 같은 방식으로 동작합니다. 그리고 실제로도 내부적으로는 Pydantic을 사용해 같은 방식으로 구현됩니다.
/// info | 정보
dataclasses는 Pydantic 모델이 할 수 있는 모든 것을 할 수는 없다는 점을 기억하세요.
그래서 여전히 Pydantic 모델을 사용해야 할 수도 있습니다.
하지만 이미 여러 dataclasses를 가지고 있다면, 이것은 FastAPI로 웹 API를 구동하는 데 그것들을 활용할 수 있는 좋은 방법입니다. 🤓
///
## `response_model`에서 Dataclasses 사용하기 { #dataclasses-in-response-model }
`response_model` 매개변수에서도 `dataclasses`를 사용할 수 있습니다:
{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}
dataclass는 자동으로 Pydantic dataclass로 변환됩니다.
이렇게 하면 해당 스키마가 API docs 사용자 인터페이스에 표시됩니다:
<img src="/img/tutorial/dataclasses/image01.png">
## 중첩 데이터 구조에서 Dataclasses 사용하기 { #dataclasses-in-nested-data-structures }
`dataclasses`를 다른 타입 애너테이션과 조합해 중첩 데이터 구조를 만들 수도 있습니다.
일부 경우에는 Pydantic 버전의 `dataclasses`를 사용해야 할 수도 있습니다. 예를 들어 자동 생성된 API 문서에서 오류가 발생하는 경우입니다.
그런 경우 표준 `dataclasses`를 드롭인 대체재인 `pydantic.dataclasses`로 간단히 바꾸면 됩니다:
{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}
1. 표준 `dataclasses`에서 `field`를 계속 임포트합니다.
2. `pydantic.dataclasses``dataclasses`의 드롭인 대체재입니다.
3. `Author` dataclass에는 `Item` dataclasses의 리스트가 포함됩니다.
4. `Author` dataclass가 `response_model` 매개변수로 사용됩니다.
5. 요청 본문으로 dataclasses와 함께 다른 표준 타입 애너테이션을 사용할 수 있습니다.
이 경우에는 `Item` dataclasses의 리스트입니다.
6. 여기서는 dataclasses 리스트인 `items`를 포함하는 딕셔너리를 반환합니다.
FastAPI는 여전히 데이터를 JSON으로 <abbr title="converting the data to a format that can be transmitted - 데이터를 전송 가능한 형식으로 변환하는 것">serializing</abbr>할 수 있습니다.
7. 여기서 `response_model``Author` dataclasses 리스트에 대한 타입 애너테이션을 사용합니다.
다시 말해, `dataclasses`를 표준 타입 애너테이션과 조합할 수 있습니다.
8. 이 *경로 처리 함수*는 `async def` 대신 일반 `def`를 사용하고 있다는 점에 주목하세요.
언제나처럼 FastAPI에서는 필요에 따라 `def``async def`를 조합해 사용할 수 있습니다.
어떤 것을 언제 사용해야 하는지 다시 확인하고 싶다면, [`async`와 `await`](../async.md#in-a-hurry){.internal-link target=_blank} 문서의 _"급하신가요?"_ 섹션을 확인하세요.
9. 이 *경로 처리 함수*는 dataclasses를(물론 반환할 수도 있지만) 반환하지 않고, 내부 데이터를 담은 딕셔너리들의 리스트를 반환합니다.
FastAPI는 `response_model` 매개변수(dataclasses 포함)를 사용해 응답을 변환합니다.
`dataclasses`는 다른 타입 애너테이션과 매우 다양한 조합으로 결합해 복잡한 데이터 구조를 구성할 수 있습니다.
더 구체적인 내용은 위 코드 내 애너테이션 팁을 확인하세요.
## 더 알아보기 { #learn-more }
`dataclasses`를 다른 Pydantic 모델과 조합하거나, 이를 상속하거나, 여러분의 모델에 포함하는 등의 작업도 할 수 있습니다.
자세한 내용은 <a href="https://docs.pydantic.dev/latest/concepts/dataclasses/" class="external-link" target="_blank">dataclasses에 관한 Pydantic 문서</a>를 참고하세요.
## 버전 { #version }
이 기능은 FastAPI `0.67.0` 버전부터 사용할 수 있습니다. 🔖

View File

@@ -1,67 +1,66 @@
# Lifespan 이벤트
# Lifespan 이벤트 { #lifespan-events }
애플리케이션 **시작 전**에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, **애플리케이션이 요청을 받기 시작하기 전**에 실행된다는 의미입니다.
애플리케이션 **시작**하기 전에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, 애플리케이션이 **요청을 받기 시작하기 전**에 실행된다는 의미입니다.
마찬가지로, 애플리케이션이 **종료될 때** 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다.
마찬가지로, 애플리케이션이 **종료**될 때 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다.
이 코드 애플리케이션이 **요청을 받기 시작하기 전에** 실행되고, 요청 처리가 끝난 후 **종료 직전에** 실행되기 때문에 전체 애플리케이션의 **수명(Lifespan)**을 다룹니다. (잠시 후 "수명"이라는 단어가 중요해집니다 😉)
이 코드 애플리케이션이 요청을 받기 **시작**하기 전에 실행되고, 요청 처리를 **끝낸 직후** 실행되기 때문에 전체 애플리케이션의 **수명(lifespan)**을 다룹니다(잠시 후 "lifespan"이라는 단어가 중요해집니다 😉).
방법은 전체 애플리케이션에서 사용해야 하는 **자원**을 설정하거나 요청 간에 **공유되는** 자원을 설정하고, 또는 후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유되는 머신러닝 모델을 로드하는 경우입니다.
는 전체 앱에서 사용해야 하는 **자원**을 설정하고, 요청 간에 **공유되는** 자원을 설정하고, 그리고/또는 후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유 머신러닝 모델을 로드하는 경우입니다.
## 사용 사례 { #use-case }
## 사용 사례
먼저 **사용 사례** 예시로 시작한 다음, 이를 어떻게 해결할지 살펴보겠습니다.
먼저 **사용 사례**를 예로 들어보고, 이를 어떻게 해결할 수 있는지 살펴보겠습니다.
요청을 처리하는 데 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖
우리가 요청을 처리하기 위해 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖
동일한 모델이 요청 간에 공유되므로, 요청마다 모델이 하나씩 있거나 사용자마다 하나씩 있는 등의 방식이 아닙니다.
이 모델들은 요청 간에 공유되므로, 요청마다 모델이 하나씩 있는 것이 아니라, 여러 요청에서 동일한 모델을 사용합니다.
모델을 로드하는 데 **상당한 시간이 걸린다고 상상해 봅시다**, 왜냐하면 모델이 **디스크에서 많은 데이터를 읽어야** 하기 때문입니다. 그래서 모든 요청마다 이를 수행하고 싶지는 않습니다.
델을 로드하는 데 **상당한 시간이 걸린다고 상상해 봅시다**, 왜냐하면 모델이 **디스크에서 많은 데이터를 읽어야** 하기 때문입니다. 따라서 모든 요청에 대해 모델을 매번 로드하고 싶지 않습니다.
듈/파일의 최상위에서 로드할 수도 있지만, 그러면 단순한 자동화된 테스트를 실행하는 경우에도 **모델을 로드**하게 되고, 테스트가 코드의 독립적인 부분을 실행하기 전에 모델이 로드될 때까지 기다려야 하므로 **느려집니다**.
모듈/파일의 최상위에서 모델을 로드할 수도 있지만, 그러면 **모델을 로드하는데** 시간이 걸리기 때문에, 단순한 자동화된 테스트를 실행할 때도 모델이 로드될 때까지 기다려야 해서 **테스트 속도가 느려집니다**.
이것이 우리가 해결할 문제입니다. 요청을 처리하기 전에 모델을 로드하되, 코드가 로드되는 동안이 아니라 애플리케이션이 요청을 받기 시작하기 직전에만 로드하겠습니다.
이 문제를 해결하려고 하는 것입니다. 요청을 처리하기 전에 모델을 로드하되, 애플리케이션이 요청을 받기 시작하기 직전에만 로드하고, 코드가 로드되는 동안은 로드하지 않도록 하겠습니다.
## Lifespan { #lifespan }
## Lifespan
`FastAPI` 앱의 `lifespan` 매개변수와 "컨텍스트 매니저"를 사용하여 *시작*과 *종료* 로직을 정의할 수 있습니다(컨텍스트 매니저가 무엇인지 잠시 후에 보여드리겠습니다).
`FastAPI` 애플리케이션의 `lifespan` 매개변수와 "컨텍스트 매니저"를 사용하여 *시작*과 *종료* 로직을 정의할 수 있습니다. (컨텍스트 매니저가 무엇인지 잠시 후에 설명드리겠습니다.)
예제로 시작한 다음 자세히 살펴보겠습니다.
예제를 통해 시작하고, 그 후에 자세히 살펴보겠습니다.
`yield`를 사용해 비동기 함수 `lifespan()`을 다음과 같이 생성합니다:
우리는 `yield`를 사용하여 비동기 함수 `lifespan()`을 다음과 같이 생성합니다:
{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}
{* ../../docs_src/events/tutorial003.py hl[16,19] *}
여기서는 `yield` 이전에 (가짜) 모델 함수를 머신러닝 모델이 들어 있는 딕셔너리에 넣어 모델을 로드하는 비용이 큰 *시작* 작업을 시뮬레이션합니다. 이 코드는 애플리케이션이 **요청을 받기 시작하기 전**, *시작* 동안에 실행됩니다.
여기서 우리는 모델을 로드하는 비싼 *시작* 작업을 시뮬레이션하고 있습니다. `yield` 앞에서 (가짜) 모델 함수를 머신러닝 모델이 담긴 딕셔너리에 넣습니다. 이 코드는 **애플리케이션이 요청을 받기 시작하기 전**, *시작* 동안에 실행됩니다.
그리고 `yield` 직후에는 모델을 언로드합니다. 이 코드는 **애플리케이션이 요청 처리 완료 후**, *종료* 직전에 실행됩니다. 예를 들어, 메모리나 GPU와 같은 자원을 해제하는 작업을 할 수 있습니다.
그리고 `yield` 직후에는 모델을 언로드합니다. 이 코드는 애플리케이션이 **요청 처리를 마친 후**, *종료* 직전에 실행됩니다. 예를 들어 메모리나 GPU 같은 자원을 해제할 수 있습니다.
/// tip | 팁
`shutdown`은 애플리케이션을 **종료**할 때 발생합니다.
`shutdown`은 애플리케이션을 **중지**할 때 발생합니다.
로운 버전을 시작해야 하거나, 그냥 실행을 멈추고 싶을 수도 있습니다. 🤷
새 버전을 시작해야 할 수도 있고, 그냥 실행하는 게 지겨워졌을 수도 있습니다. 🤷
///
### Lifespan 함수
### Lifespan 함수 { #lifespan-function }
먼저 주목할 점은, `yield`를 사용하여 비동기 함수(async function)를 정의하고 있다는 것입니다. 이는 `yield`를 사용 의존성과 매우 유사합니다.
먼저 주목할 점은 `yield`를 사용하여 비동기 함수를 정의하고 있다는 것입니다. 이는 `yield`를 사용하는 의존성과 매우 유사합니다.
{* ../../docs_src/events/tutorial003.py hl[14:19] *}
{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}
함수의 첫 번째 부분, 즉 `yield` 이전의 코드는 애플리케이션이 시작되기 **전에** 실행됩니다.
그리고 `yield` 이후의 부분은 애플리케이션이 료된 **나중** 실행됩니다.
그리고 `yield` 이후의 부분은 애플리케이션이 료된 **** 실행됩니다.
### 비동기 컨텍스트 매니저
### 비동기 컨텍스트 매니저 { #async-context-manager }
함수를 확인해보면, `@asynccontextmanager`장식되어 있습니다.
확인해 보면, 함수는 `@asynccontextmanager`데코레이션되어 있습니다.
것은 함수를 "**비동기 컨텍스트 매니저**"라고 불리는 것으로 변환시킵니다.
함수를 "**비동기 컨텍스트 매니저**"라고 불리는 것으로 변환니다.
{* ../../docs_src/events/tutorial003.py hl[1,13] *}
{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}
파이썬에서 **컨텍스트 매니저**는 `with` 문에서 사용할 수 있는 것입니다. 예를 들어, `open()`은 컨텍스트 매니저로 사용할 수 있습니다:
@@ -69,97 +68,98 @@
with open("file.txt") as file:
file.read()
```
최근 버전의 파이썬에서는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다:
최근 버전의 파이썬에는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다:
```Python
async with lifespan(app):
await do_stuff()
```
컨텍스트 매니저나 위와 같은 비동기 컨텍스트 매니저를 만들면, `with` 블록에 들어가기 전에 `yield` 이전의 코드 실행고, `with` 블록을 벗어난 후에는 `yield` 이후의 코드 실행니다.
위와 같은 컨텍스트 매니저 또는 비동기 컨텍스트 매니저를 만들면, `with` 블록에 들어가기 전에 `yield` 이전의 코드 실행고, `with` 블록을 벗어난 후에는 `yield` 이후의 코드 실행니다.
위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 사용하도록 합니다.
위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 FastAPI가 이를 사용하도록 합니다.
`FastAPI` 애플리케이션`lifespan` 매개변수는 **비동기 컨텍스트 매니저**를 받기 때문에, 새로운 `lifespan` 비동기 컨텍스트 매니저를 FastAPI에 전달할 수 있습니다.
`FastAPI` `lifespan` 매개변수는 **비동기 컨텍스트 매니저**를 받으므로, 새 `lifespan` 비동기 컨텍스트 매니저를 전달할 수 있습니다.
{* ../../docs_src/events/tutorial003.py hl[22] *}
{* ../../docs_src/events/tutorial003_py39.py hl[22] *}
## 대체 이벤트 (사용 중단)
## 대체 이벤트(사용 중단) { #alternative-events-deprecated }
/// warning | 경고
*시작*과 *종료*를 처리하는 권장 방법은 위에서 설명한 대로 `FastAPI` 애플리케이션`lifespan` 매개변수를 사용하는 것입니다. `lifespan` 매개변수를 제공하면 `startup``shutdown` 이벤트 핸들러는 더 이상 호출되지 않습니다. `lifespan`을 사용할지, 모든 이벤트를 사용할지 선택해야 하며 둘 다 사용할 수는 없습니다.
*시작*과 *종료*를 처리하는 권장 방법은 위에서 설명한 대로 `FastAPI` `lifespan` 매개변수를 사용하는 것입니다. `lifespan` 매개변수를 제공하면 `startup``shutdown` 이벤트 핸들러는 더 이상 호출되지 않습니다. `lifespan`만 쓰거나 이벤트만 쓰거나 둘 중 하나이지, 둘 다는 아닙니다.
이 부분은 건너뛰셔도 좋습니다.
이 부분은 아마 건너뛰셔도 니다.
///
*시작*과 *종료* 동안 실행될 이 로직을 정의하는 대체 방법이 있습니다.
애플리케이션이 시작되기 전에 또는 종료될 때 실행야 하는 이벤트 핸들러(함수)를 정의할 수 있습니다.
애플리케이션이 시작되기 전에 또는 애플리케이션이 종료될 때 실행되어야 하는 이벤트 핸들러(함수)를 정의할 수 있습니다.
이 함수들은 `async def` 또는 일반 `def`로 선언할 수 있습니다.
### `startup` 이벤트
### `startup` 이벤트 { #startup-event }
애플리케이션이 시작되기 전에 실행되어야 하는 함수를 추가하려면, `"startup"` 이벤트로 선언합니다:
{* ../../docs_src/events/tutorial001.py hl[8] *}
{* ../../docs_src/events/tutorial001_py39.py hl[8] *}
이 경우, `startup` 이벤트 핸들러 함수는 "database"라는 항목(단지 `dict`)을 일부 값으로 초기화합니다.
이 경우, `startup` 이벤트 핸들러 함수는 "database"(그냥 `dict`) 항목을 일부 값으로 초기화합니다.
여러 개의 이벤트 핸들러 함수를 추가할 수 있습니다.
애플리케이션은 모든 `startup` 이벤트 핸들러가 완료될 때까지 요청을 받기 시작하지 않습니다.
그리고 모든 `startup` 이벤트 핸들러가 완료될 때까지 애플리케이션은 요청을 받기 시작하지 않습니다.
### `shutdown` 이벤트
### `shutdown` 이벤트 { #shutdown-event }
애플리케이션이 종료될 때 실행되어야 하는 함수를 추가하려면, `"shutdown"` 이벤트로 선언합니다:
{* ../../docs_src/events/tutorial002.py hl[6] *}
{* ../../docs_src/events/tutorial002_py39.py hl[6] *}
여기서, `shutdown` 이벤트 핸들러 함수는 `"Application shutdown"`이라는 텍스트를 `log.txt` 파일에 기록합니다.
여기서 `shutdown` 이벤트 핸들러 함수는 텍스트 한 줄 `"Application shutdown"` `log.txt` 파일에 기록합니다.
/// info | 정보
`open()` 함수에서 `mode="a"`는 "추가"를 의미하므로, 파일에 있는 기존 내용 덮어쓰지 않고 새로운 줄이 추가됩니다.
`open()` 함수에서 `mode="a"`는 "append"(추가)를 의미하므로, 기존 내용 덮어쓰지 않고 파일에 있던 내용 뒤에 줄이 추가됩니다.
///
/// tip | 팁
이 경우, 우리는 표준 파이썬 `open()` 함수를 사용하여 파일과 상호작용하고 있습니다.
이 경우에는 파일과 상호작용하는 표준 파이썬 `open()` 함수를 사용하고 있습니다.
따라서 I/O(입출력) 작업이 포함되어 있어 디스크에 기록되는 것을 "기다리는" 과정이 필요합니다.
따라서 I/O(input/output)가 포함되어 있어 디스크에 기록되는 것을 "기다리는" 과정이 필요합니다.
하지만 `open()``async``await`를 사용하지 않습니다.
그래서 우리는 이벤트 핸들러 함수 `async def` 대신 일반 `def`로 선언합니다.
그래서 이벤트 핸들러 함수 `async def` 대신 표준 `def`로 선언합니다.
///
### `startup`과 `shutdown`을 함께 사용
### `startup`과 `shutdown`을 함께 { #startup-and-shutdown-together }
*시작*과 *종료* 로직 연결 가능성이 높습니다. 예를 들어, 무언가를 시작한 후 끝내거나, 자원을 획득한 후 해제하는 등의 작업할 수 있습니다.
*시작*과 *종료* 로직 연결되어 있을 가능성이 높습니다. 무언가를 시작했다가 끝내거나, 자원을 획득했다가 해제하는 등의 작업이 필요할 수 있습니다.
이러한 작업을 별도의 함수로 처리하면 서로 로직이나 변수를 공유하지 않기 때문에 더 어려워집니다. 값들을 전역 변수에 저장하거나 비슷한 트릭을 사용해야 할 수 있습니다.
로직이나 변수를 함께 공유하지 않는 분리된 함수에서 이를 처리하면, 전역 변수에 값을 저장하거나 비슷한 트릭이 필요해져 더 어렵습니다.
렇기 때문에 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다.
그 때문에, 이제는 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다.
## 기술적 세부사항
## 기술적 세부사항 { #technical-details }
호기심 많은 분들을 위한 기술적인 세부사항입니다. 🤓
ASGI 기술 사양에 따르면, 이는 <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protocol</a>의 일부이며, `startup``shutdown`이라는 이벤트를 정의합니다.
내부적으로 ASGI 기술 사양에서는 이것이 <a href="https://asgi.readthedocs.io/en/latest/specs/lifespan.html" class="external-link" target="_blank">Lifespan Protocol</a>의 일부이며, `startup``shutdown`이라는 이벤트를 정의합니다.
/// info | 정보
Starlette `lifespan` 핸들러에 대해 더 읽고 싶다면 <a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette의 Lifespan 문서</a>에서 확인할 수 있습니다.
Starlette `lifespan` 핸들러에 대해서는 <a href="https://www.starlette.dev/lifespan/" class="external-link" target="_blank">Starlette의 Lifespan 문서</a>에서 더 읽어볼 수 있습니다.
이 문서에는 코드의 다른 영역에서 사용할 수 있는 lifespan 상태를 처리하는 방법도 포함되어 있습니다.
또한 코드의 다른 영역에서 사용할 수 있는 lifespan 상태를 처리하는 방법도 포함되어 있습니다.
///
## 서브 애플리케이션
## 서브 애플리케이션 { #sub-applications }
🚨 이 lifespan 이벤트(`startup``shutdown`)는 메인 애플리케이션에 대해서만 실행되며, [서브 애플리케이션 - Mounts](sub-applications.md){.internal-link target=_blank}에는 실행되지 않음을 유의하세요.
🚨 이 lifespan 이벤트(startupshutdown)는 메인 애플리케이션에 대해서만 실행되며, [서브 애플리케이션 - Mounts](sub-applications.md){.internal-link target=_blank}에는 실행되지 않음을 유의하세요.

View File

@@ -0,0 +1,208 @@
# SDK 생성하기 { #generating-sdks }
**FastAPI**는 **OpenAPI** 사양을 기반으로 하므로, FastAPI의 API는 많은 도구가 이해할 수 있는 표준 형식으로 설명할 수 있습니다.
덕분에 여러 언어용 클라이언트 라이브러리(<abbr title="Software Development Kits - 소프트웨어 개발 키트">**SDKs**</abbr>), 최신 **문서**, 그리고 코드와 동기화된 **테스트** 또는 **자동화 워크플로**를 쉽게 생성할 수 있습니다.
이 가이드에서는 FastAPI 백엔드용 **TypeScript SDK**를 생성하는 방법을 배웁니다.
## 오픈 소스 SDK 생성기 { #open-source-sdk-generators }
다양하게 활용할 수 있는 옵션으로 <a href="https://openapi-generator.tech/" class="external-link" target="_blank">OpenAPI Generator</a>가 있으며, **다양한 프로그래밍 언어**를 지원하고 OpenAPI 사양으로부터 SDK를 생성할 수 있습니다.
**TypeScript 클라이언트**의 경우 <a href="https://heyapi.dev/" class="external-link" target="_blank">Hey API</a>는 TypeScript 생태계에 최적화된 경험을 제공하는 목적에 맞게 설계된 솔루션입니다.
더 많은 SDK 생성기는 <a href="https://openapi.tools/#sdk" class="external-link" target="_blank">OpenAPI.Tools</a>에서 확인할 수 있습니다.
/// tip | 팁
FastAPI는 **OpenAPI 3.1** 사양을 자동으로 생성하므로, 사용하는 도구는 이 버전을 지원해야 합니다.
///
## FastAPI 스폰서의 SDK 생성기 { #sdk-generators-from-fastapi-sponsors }
이 섹션에서는 FastAPI를 후원하는 회사들이 제공하는 **벤처 투자 기반****기업 지원** 솔루션을 소개합니다. 이 제품들은 고품질로 생성된 SDK에 더해 **추가 기능**과 **통합**을 제공합니다.
✨ [**FastAPI 후원하기**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} ✨를 통해, 이 회사들은 프레임워크와 그 **생태계**가 건강하고 **지속 가능**하게 유지되도록 돕습니다.
또한 이들의 후원은 FastAPI **커뮤니티**(여러분)에 대한 강한 헌신을 보여주며, **좋은 서비스**를 제공하는 것뿐 아니라, 견고하고 활발한 프레임워크인 FastAPI를 지원하는 데에도 관심이 있음을 나타냅니다. 🙇
예를 들어 다음을 사용해 볼 수 있습니다:
* <a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" class="external-link" target="_blank">Speakeasy</a>
* <a href="https://www.stainless.com/?utm_source=fastapi&utm_medium=referral" class="external-link" target="_blank">Stainless</a>
* <a href="https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi" class="external-link" target="_blank">liblab</a>
이 중 일부는 오픈 소스이거나 무료 티어를 제공하므로, 비용 부담 없이 사용해 볼 수 있습니다. 다른 상용 SDK 생성기도 있으며 온라인에서 찾을 수 있습니다. 🤓
## TypeScript SDK 만들기 { #create-a-typescript-sdk }
간단한 FastAPI 애플리케이션으로 시작해 보겠습니다:
{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *}
*path operation*에서 요청 페이로드와 응답 페이로드에 사용하는 모델을 `Item`, `ResponseMessage` 모델로 정의하고 있다는 점에 주목하세요.
### API 문서 { #api-docs }
`/docs`로 이동하면, 요청으로 보낼 데이터와 응답으로 받을 데이터에 대한 **스키마(schemas)**가 있는 것을 볼 수 있습니다:
<img src="/img/tutorial/generate-clients/image01.png">
이 스키마는 앱에서 모델로 선언되었기 때문에 볼 수 있습니다.
그 정보는 앱의 **OpenAPI 스키마**에서 사용할 수 있고, 이후 API 문서에 표시됩니다.
OpenAPI에 포함된 모델의 동일한 정보가 **클라이언트 코드 생성**에 사용될 수 있습니다.
### Hey API { #hey-api }
모델이 포함된 FastAPI 앱이 준비되면, Hey API를 사용해 TypeScript 클라이언트를 생성할 수 있습니다. 가장 빠른 방법은 npx를 사용하는 것입니다.
```sh
npx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client
```
이 명령은 `./src/client`에 TypeScript SDK를 생성합니다.
<a href="https://heyapi.dev/openapi-ts/get-started" class="external-link" target="_blank">`@hey-api/openapi-ts` 설치 방법</a>과 <a href="https://heyapi.dev/openapi-ts/output" class="external-link" target="_blank">생성된 결과물</a>은 해당 웹사이트에서 확인할 수 있습니다.
### SDK 사용하기 { #using-the-sdk }
이제 클라이언트 코드를 import해서 사용할 수 있습니다. 아래처럼 사용할 수 있으며, 메서드에 대한 자동 완성이 제공되는 것을 확인할 수 있습니다:
<img src="/img/tutorial/generate-clients/image02.png">
보낼 페이로드에 대해서도 자동 완성이 제공됩니다:
<img src="/img/tutorial/generate-clients/image03.png">
/// tip | 팁
`name``price`에 대한 자동 완성은 FastAPI 애플리케이션에서 `Item` 모델에 정의된 내용입니다.
///
전송하는 데이터에 대해 인라인 오류도 표시됩니다:
<img src="/img/tutorial/generate-clients/image04.png">
응답 객체도 자동 완성을 제공합니다:
<img src="/img/tutorial/generate-clients/image05.png">
## 태그가 있는 FastAPI 앱 { #fastapi-app-with-tags }
대부분의 경우 FastAPI 앱은 더 커지고, 서로 다른 *path operations* 그룹을 분리하기 위해 태그를 사용하게 될 가능성이 큽니다.
예를 들어 **items** 섹션과 **users** 섹션이 있고, 이를 태그로 분리할 수 있습니다:
{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *}
### 태그로 TypeScript 클라이언트 생성하기 { #generate-a-typescript-client-with-tags }
태그를 사용하는 FastAPI 앱에 대해 클라이언트를 생성하면, 일반적으로 생성된 클라이언트 코드도 태그를 기준으로 분리됩니다.
이렇게 하면 클라이언트 코드에서 항목들이 올바르게 정렬되고 그룹화됩니다:
<img src="/img/tutorial/generate-clients/image06.png">
이 경우 다음이 있습니다:
* `ItemsService`
* `UsersService`
### 클라이언트 메서드 이름 { #client-method-names }
현재 `createItemItemsPost` 같은 생성된 메서드 이름은 그다지 깔끔하지 않습니다:
```TypeScript
ItemsService.createItemItemsPost({name: "Plumbus", price: 5})
```
...이는 클라이언트 생성기가 각 *path operation*에 대해 OpenAPI 내부의 **operation ID**를 사용하기 때문입니다.
OpenAPI는 모든 *path operations* 전체에서 operation ID가 각각 유일해야 한다고 요구합니다. 그래서 FastAPI는 operation ID가 유일하도록 **함수 이름**, **경로**, **HTTP method/operation**을 조합해 operation ID를 생성합니다.
하지만 다음에서 이를 개선하는 방법을 보여드리겠습니다. 🤓
## 커스텀 Operation ID와 더 나은 메서드 이름 { #custom-operation-ids-and-better-method-names }
클라이언트에서 **더 단순한 메서드 이름**을 갖도록, operation ID가 **생성되는 방식**을 **수정**할 수 있습니다.
이 경우 operation ID가 다른 방식으로도 **유일**하도록 보장해야 합니다.
예를 들어 각 *path operation*이 태그를 갖도록 한 다음, **태그**와 *path operation* **이름**(함수 이름)을 기반으로 operation ID를 생성할 수 있습니다.
### 유일 ID 생성 함수 커스터마이징 { #custom-generate-unique-id-function }
FastAPI는 각 *path operation*에 대해 **유일 ID**를 사용하며, 이는 **operation ID** 및 요청/응답에 필요한 커스텀 모델 이름에도 사용됩니다.
이 함수를 커스터마이징할 수 있습니다. 이 함수는 `APIRoute`를 받아 문자열을 반환합니다.
예를 들어 아래에서는 첫 번째 태그(대부분 태그는 하나만 있을 것입니다)와 *path operation* 이름(함수 이름)을 사용합니다.
그 다음 이 커스텀 함수를 `generate_unique_id_function` 매개변수로 **FastAPI**에 전달할 수 있습니다:
{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *}
### 커스텀 Operation ID로 TypeScript 클라이언트 생성하기 { #generate-a-typescript-client-with-custom-operation-ids }
이제 클라이언트를 다시 생성하면, 개선된 메서드 이름을 확인할 수 있습니다:
<img src="/img/tutorial/generate-clients/image07.png">
보시다시피, 이제 메서드 이름은 태그 다음에 함수 이름이 오며, URL 경로와 HTTP operation의 정보는 포함하지 않습니다.
### 클라이언트 생성기를 위한 OpenAPI 사양 전처리 { #preprocess-the-openapi-specification-for-the-client-generator }
생성된 코드에는 여전히 일부 **중복 정보**가 있습니다.
`ItemsService`(태그에서 가져옴)에 이미 **items**가 포함되어 있어 이 메서드가 items와 관련되어 있음을 알 수 있지만, 메서드 이름에도 태그 이름이 접두사로 붙어 있습니다. 😕
OpenAPI 전반에서는 operation ID가 **유일**하다는 것을 보장하기 위해 이 방식을 유지하고 싶을 수 있습니다.
하지만 생성된 클라이언트에서는, 클라이언트를 생성하기 직전에 OpenAPI operation ID를 **수정**해서 메서드 이름을 더 보기 좋고 **깔끔하게** 만들 수 있습니다.
OpenAPI JSON을 `openapi.json` 파일로 다운로드한 뒤, 아래와 같은 스크립트로 **접두사 태그를 제거**할 수 있습니다:
{* ../../docs_src/generate_clients/tutorial004_py39.py *}
//// tab | Node.js
```Javascript
{!> ../../docs_src/generate_clients/tutorial004.js!}
```
////
이렇게 하면 operation ID가 `items-get_items` 같은 형태에서 `get_items`로 변경되어, 클라이언트 생성기가 더 단순한 메서드 이름을 생성할 수 있습니다.
### 전처리된 OpenAPI로 TypeScript 클라이언트 생성하기 { #generate-a-typescript-client-with-the-preprocessed-openapi }
이제 최종 결과가 `openapi.json` 파일에 있으므로, 입력 위치를 업데이트해야 합니다:
```sh
npx @hey-api/openapi-ts -i ./openapi.json -o src/client
```
새 클라이언트를 생성한 후에는 **깔끔한 메서드 이름**을 가지면서도, **자동 완성**, **인라인 오류** 등은 그대로 제공됩니다:
<img src="/img/tutorial/generate-clients/image08.png">
## 장점 { #benefits }
자동으로 생성된 클라이언트를 사용하면 다음에 대해 **자동 완성**을 받을 수 있습니다:
* 메서드
* 본문(body)의 요청 페이로드, 쿼리 파라미터 등
* 응답 페이로드
또한 모든 것에 대해 **인라인 오류**도 확인할 수 있습니다.
그리고 백엔드 코드를 업데이트한 뒤 프론트엔드를 **재생성(regenerate)**하면, 새 *path operations*가 메서드로 추가되고 기존 것은 제거되며, 그 밖의 변경 사항도 생성된 코드에 반영됩니다. 🤓
이는 무언가 변경되면 그 변경이 클라이언트 코드에도 자동으로 **반영**된다는 뜻입니다. 또한 클라이언트를 **빌드(build)**하면 사용된 데이터가 **불일치(mismatch)**할 경우 오류가 발생합니다.
따라서 운영 환경에서 최종 사용자에게 오류가 노출된 뒤 문제를 추적하는 대신, 개발 사이클 초기에 **많은 오류를 매우 빨리 감지**할 수 있습니다. ✨

View File

@@ -1,6 +1,6 @@
# 심화 사용자 안내서 - 도입부
# 심화 사용자 안내서 - 도입부 { #advanced-user-guide }
## 추가 기능
## 추가 기능 { #additional-features }
메인 [자습서 - 사용자 안내서](../tutorial/index.md){.internal-link target=_blank}는 여러분이 **FastAPI**의 모든 주요 기능을 둘러보시기에 충분할 것입니다.
@@ -14,14 +14,8 @@
///
## 자습서를 먼저 읽으십시오
## 자습서를 먼저 읽으십시오 { #read-the-tutorial-first }
여러분은 메인 [자습서 - 사용자 안내서](../tutorial/index.md){.internal-link target=_blank}의 지식으로 **FastAPI**의 대부분의 기능을 사용하실 수 있습니다.
이어지는 장들은 여러분이 메인 자습서 - 사용자 안내서를 이미 읽으셨으며 주요 아이디어를 알고 계신다고 가정합니다.
## TestDriven.io 강좌
여러분이 문서의 이 부분을 보완하시기 위해 심화-기초 강좌 수강을 희망하신다면 다음을 참고 하시기를 바랍니다: **TestDriven.io**의 <a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">FastAPI와 Docker를 사용한 테스트 주도 개발</a>.
그들은 현재 전체 수익의 10퍼센트를 **FastAPI** 개발에 기부하고 있습니다. 🎉 😄

View File

@@ -0,0 +1,97 @@
# 고급 Middleware { #advanced-middleware }
메인 튜토리얼에서 애플리케이션에 [커스텀 Middleware](../tutorial/middleware.md){.internal-link target=_blank}를 추가하는 방법을 읽었습니다.
그리고 [`CORSMiddleware`로 CORS 처리하기](../tutorial/cors.md){.internal-link target=_blank}도 읽었습니다.
이 섹션에서는 다른 middleware들을 사용하는 방법을 살펴보겠습니다.
## ASGI middleware 추가하기 { #adding-asgi-middlewares }
**FastAPI**는 Starlette를 기반으로 하고 <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr> 사양을 구현하므로, 어떤 ASGI middleware든 사용할 수 있습니다.
ASGI 사양을 따르기만 하면, FastAPI나 Starlette를 위해 만들어진 middleware가 아니어도 동작합니다.
일반적으로 ASGI middleware는 첫 번째 인자로 ASGI 앱을 받도록 기대하는 클래스입니다.
그래서 서드파티 ASGI middleware 문서에서는 아마 다음과 같이 하라고 안내할 것입니다:
```Python
from unicorn import UnicornMiddleware
app = SomeASGIApp()
new_app = UnicornMiddleware(app, some_config="rainbow")
```
하지만 FastAPI(정확히는 Starlette)는 더 간단한 방법을 제공하며, 이를 통해 내부 middleware가 서버 오류를 처리하고 커스텀 예외 핸들러가 올바르게 동작하도록 보장합니다.
이를 위해(그리고 CORS 예제에서처럼) `app.add_middleware()`를 사용합니다.
```Python
from fastapi import FastAPI
from unicorn import UnicornMiddleware
app = FastAPI()
app.add_middleware(UnicornMiddleware, some_config="rainbow")
```
`app.add_middleware()`는 첫 번째 인자로 middleware 클래스를 받고, 그 뒤에는 middleware에 전달할 추가 인자들을 받습니다.
## 통합 middleware { #integrated-middlewares }
**FastAPI**에는 일반적인 사용 사례를 위한 여러 middleware가 포함되어 있습니다. 다음에서 이를 사용하는 방법을 살펴보겠습니다.
/// note | 기술 세부사항
다음 예제에서는 `from starlette.middleware.something import SomethingMiddleware`를 사용해도 됩니다.
**FastAPI**는 개발자 편의를 위해 `fastapi.middleware`에 여러 middleware를 제공하지만, 사용 가능한 대부분의 middleware는 Starlette에서 직접 제공됩니다.
///
## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }
들어오는 모든 요청이 `https` 또는 `wss`여야 하도록 강제합니다.
`http` 또는 `ws`로 들어오는 모든 요청은 대신 보안 스킴으로 리디렉션됩니다.
{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *}
## `TrustedHostMiddleware` { #trustedhostmiddleware }
HTTP Host Header 공격을 방어하기 위해, 들어오는 모든 요청에 올바르게 설정된 `Host` 헤더가 있어야 하도록 강제합니다.
{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *}
다음 인자들을 지원합니다:
* `allowed_hosts` - 호스트명으로 허용할 도메인 이름 목록입니다. `*.example.com` 같은 와일드카드 도메인으로 서브도메인을 매칭하는 것도 지원합니다. 어떤 호스트명이든 허용하려면 `allowed_hosts=["*"]`를 사용하거나 middleware를 생략하세요.
* `www_redirect` - True로 설정하면, 허용된 호스트의 non-www 버전으로 들어오는 요청을 www 버전으로 리디렉션합니다. 기본값은 `True`입니다.
들어오는 요청이 올바르게 검증되지 않으면 `400` 응답이 전송됩니다.
## `GZipMiddleware` { #gzipmiddleware }
`Accept-Encoding` 헤더에 `"gzip"`이 포함된 어떤 요청이든 GZip 응답을 처리합니다.
이 middleware는 일반 응답과 스트리밍 응답을 모두 처리합니다.
{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *}
다음 인자들을 지원합니다:
* `minimum_size` - 바이트 단위로 지정한 최소 크기보다 작은 응답은 GZip으로 압축하지 않습니다. 기본값은 `500`입니다.
* `compresslevel` - GZip 압축 중에 사용됩니다. 1부터 9까지의 정수입니다. 기본값은 `9`입니다. 값이 낮을수록 압축은 더 빠르지만 파일 크기는 더 커지고, 값이 높을수록 압축은 더 느리지만 파일 크기는 더 작아집니다.
## 다른 middleware { #other-middlewares }
다른 ASGI middleware도 많이 있습니다.
예를 들어:
* <a href="https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py" class="external-link" target="_blank">Uvicorn의 `ProxyHeadersMiddleware`</a>
* <a href="https://github.com/florimondmanca/msgpack-asgi" class="external-link" target="_blank">MessagePack</a>
사용 가능한 다른 middleware를 보려면 <a href="https://www.starlette.dev/middleware/" class="external-link" target="_blank">Starlette의 Middleware 문서</a>와 <a href="https://github.com/florimondmanca/awesome-asgi" class="external-link" target="_blank">ASGI Awesome List</a>를 확인하세요.

View File

@@ -0,0 +1,186 @@
# OpenAPI 콜백 { #openapi-callbacks }
다른 사람이 만든 *external API*(아마도 당신의 API를 *사용*할 동일한 개발자)가 요청을 트리거하도록 만드는 *경로 처리*를 가진 API를 만들 수 있습니다.
당신의 API 앱이 *external API*를 호출할 때 일어나는 과정을 "callback"이라고 합니다. 외부 개발자가 작성한 소프트웨어가 당신의 API로 요청을 보낸 다음, 당신의 API가 다시 *external API*로 요청을 보내 *되돌려 호출*하기 때문입니다(아마도 같은 개발자가 만든 API일 것입니다).
이 경우, 그 *external API*가 어떤 형태여야 하는지 문서화하고 싶을 수 있습니다. 어떤 *경로 처리*를 가져야 하는지, 어떤 body를 기대하는지, 어떤 응답을 반환해야 하는지 등입니다.
## 콜백이 있는 앱 { #an-app-with-callbacks }
예시로 확인해 보겠습니다.
청구서를 생성할 수 있는 앱을 개발한다고 가정해 보세요.
이 청구서는 `id`, `title`(선택 사항), `customer`, `total`을 갖습니다.
당신의 API 사용자(외부 개발자)는 POST 요청으로 당신의 API에서 청구서를 생성합니다.
그 다음 당신의 API는(가정해 보면):
* 청구서를 외부 개발자의 고객에게 전송합니다.
* 돈을 수금합니다.
* API 사용자(외부 개발자)의 API로 다시 알림을 보냅니다.
* 이는 (당신의 API에서) 그 외부 개발자가 제공하는 어떤 *external API*로 POST 요청을 보내는 방식으로 수행됩니다(이것이 "callback"입니다).
## 일반적인 **FastAPI** 앱 { #the-normal-fastapi-app }
먼저 콜백을 추가하기 전, 일반적인 API 앱이 어떻게 생겼는지 보겠습니다.
`Invoice` body를 받는 *경로 처리*와, 콜백을 위한 URL을 담는 쿼리 파라미터 `callback_url`이 있을 것입니다.
이 부분은 꽤 일반적이며, 대부분의 코드는 이미 익숙할 것입니다:
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}
/// tip | 팁
`callback_url` 쿼리 파라미터는 Pydantic의 <a href="https://docs.pydantic.dev/latest/api/networks/" class="external-link" target="_blank">Url</a> 타입을 사용합니다.
///
유일하게 새로운 것은 *경로 처리 데코레이터*의 인자로 `callbacks=invoices_callback_router.routes`가 들어간다는 점입니다. 이것이 무엇인지 다음에서 보겠습니다.
## 콜백 문서화하기 { #documenting-the-callback }
실제 콜백 코드는 당신의 API 앱에 크게 의존합니다.
그리고 앱마다 많이 달라질 수 있습니다.
다음처럼 한두 줄의 코드일 수도 있습니다:
```Python
callback_url = "https://example.com/api/v1/invoices/events/"
httpx.post(callback_url, json={"description": "Invoice paid", "paid": True})
```
하지만 콜백에서 가장 중요한 부분은, 당신의 API 사용자(외부 개발자)가 콜백 요청 body로 *당신의 API*가 보낼 데이터 등에 맞춰 *external API*를 올바르게 구현하도록 보장하는 것입니다.
그래서 다음으로 할 일은, *당신의 API*에서 보내는 콜백을 받기 위해 그 *external API*가 어떤 형태여야 하는지 문서화하는 코드를 추가하는 것입니다.
그 문서는 당신의 API에서 `/docs`의 Swagger UI에 표시되며, 외부 개발자들이 *external API*를 어떻게 만들어야 하는지 알 수 있게 해줍니다.
이 예시는 콜백 자체(한 줄 코드로도 될 수 있음)를 구현하지 않고, 문서화 부분만 구현합니다.
/// tip | 팁
실제 콜백은 단지 HTTP 요청입니다.
콜백을 직접 구현할 때는 <a href="https://www.python-httpx.org" class="external-link" target="_blank">HTTPX</a>나 <a href="https://requests.readthedocs.io/" class="external-link" target="_blank">Requests</a> 같은 것을 사용할 수 있습니다.
///
## 콜백 문서화 코드 작성하기 { #write-the-callback-documentation-code }
이 코드는 앱에서 실행되지 않습니다. 그 *external API*가 어떤 형태여야 하는지 *문서화*하는 데만 필요합니다.
하지만 **FastAPI**로 API의 자동 문서를 쉽게 생성하는 방법은 이미 알고 있습니다.
따라서 그와 같은 지식을 사용해 *external API*가 어떻게 생겨야 하는지 문서화할 것입니다... 즉 외부 API가 구현해야 하는 *경로 처리(들)*(당신의 API가 호출할 것들)을 만들어서 말입니다.
/// tip | 팁
콜백을 문서화하는 코드를 작성할 때는, 자신이 그 *외부 개발자*라고 상상하는 것이 유용할 수 있습니다. 그리고 지금은 *당신의 API*가 아니라 *external API*를 구현하고 있다고 생각해 보세요.
이 관점(외부 개발자의 관점)을 잠시 채택하면, 그 *external API*를 위해 파라미터, body용 Pydantic 모델, 응답 등을 어디에 두어야 하는지가 더 명확하게 느껴질 수 있습니다.
///
### 콜백 `APIRouter` 생성하기 { #create-a-callback-apirouter }
먼저 하나 이상의 콜백을 담을 새 `APIRouter`를 만듭니다.
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}
### 콜백 *경로 처리* 생성하기 { #create-the-callback-path-operation }
콜백 *경로 처리*를 만들려면 위에서 만든 동일한 `APIRouter`를 사용합니다.
일반적인 FastAPI *경로 처리*처럼 보일 것입니다:
* 아마도 받아야 할 body 선언이 있을 것입니다(예: `body: InvoiceEvent`).
* 그리고 반환해야 할 응답 선언도 있을 수 있습니다(예: `response_model=InvoiceEventReceived`).
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}
일반적인 *경로 처리*와의 주요 차이점은 2가지입니다:
* 실제 코드를 가질 필요가 없습니다. 당신의 앱은 이 코드를 절대 호출하지 않기 때문입니다. 이는 *external API*를 문서화하는 데만 사용됩니다. 따라서 함수는 그냥 `pass`만 있어도 됩니다.
* *path*에는 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a>(자세한 내용은 아래 참고)이 포함될 수 있으며, 이를 통해 *당신의 API*로 보내진 원래 요청의 파라미터와 일부 값을 변수로 사용할 수 있습니다.
### 콜백 경로 표현식 { #the-callback-path-expression }
콜백 *path*는 *당신의 API*로 보내진 원래 요청의 일부를 포함할 수 있는 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a>을 가질 수 있습니다.
이 경우, 다음 `str`입니다:
```Python
"{$callback_url}/invoices/{$request.body.id}"
```
따라서 당신의 API 사용자(외부 개발자)가 *당신의 API*로 다음 요청을 보내고:
```
https://yourapi.com/invoices/?callback_url=https://www.external.org/events
```
JSON body가 다음과 같다면:
```JSON
{
"id": "2expen51ve",
"customer": "Mr. Richie Rich",
"total": "9999"
}
```
그러면 *당신의 API*는 청구서를 처리하고, 나중에 어느 시점에서 `callback_url`(즉 *external API*)로 콜백 요청을 보냅니다:
```
https://www.external.org/events/invoices/2expen51ve
```
그리고 다음과 같은 JSON body를 포함할 것입니다:
```JSON
{
"description": "Payment celebration",
"paid": true
}
```
또한 그 *external API*로부터 다음과 같은 JSON body 응답을 기대합니다:
```JSON
{
"ok": true
}
```
/// tip | 팁
콜백 URL에는 `callback_url` 쿼리 파라미터로 받은 URL(`https://www.external.org/events`)뿐 아니라, JSON body 안의 청구서 `id`(`2expen51ve`)도 함께 사용된다는 점에 주목하세요.
///
### 콜백 라우터 추가하기 { #add-the-callback-router }
이 시점에서, 위에서 만든 콜백 라우터 안에 *콜백 경로 처리(들)*(즉 *external developer*가 *external API*에 구현해야 하는 것들)을 준비했습니다.
이제 *당신의 API 경로 처리 데코레이터*에서 `callbacks` 파라미터를 사용해, 그 콜백 라우터의 `.routes` 속성(실제로는 routes/*경로 처리*의 `list`)을 전달합니다:
{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}
/// tip | 팁
`callback=`에 라우터 자체(`invoices_callback_router`)를 넘기는 것이 아니라, `invoices_callback_router.routes`처럼 `.routes` 속성을 넘긴다는 점에 주목하세요.
///
### 문서 확인하기 { #check-the-docs }
이제 앱을 실행하고 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>로 이동하세요.
*경로 처리*에 대해 "Callbacks" 섹션을 포함한 문서가 표시되며, *external API*가 어떤 형태여야 하는지 확인할 수 있습니다:
<img src="/img/tutorial/openapi-callbacks/image01.png">

View File

@@ -0,0 +1,55 @@
# OpenAPI Webhooks { #openapi-webhooks }
앱이 어떤 데이터와 함께 (요청을 보내서) *사용자의* 앱을 호출할 수 있고, 보통 어떤 **이벤트**를 **알리기** 위해 그렇게 할 수 있다는 것을 API **사용자**에게 알려야 하는 경우가 있습니다.
이는 사용자가 여러분의 API로 요청을 보내는 일반적인 과정 대신, **여러분의 API**(또는 앱)가 **사용자의 시스템**(사용자의 API, 사용자의 앱)으로 **요청을 보낼 수 있다**는 의미입니다.
이를 보통 **webhook**이라고 합니다.
## Webhooks 단계 { #webhooks-steps }
일반적인 과정은, 여러분이 코드에서 보낼 메시지, 즉 **요청 본문(body)**이 무엇인지 **정의**하는 것입니다.
또한 여러분의 앱이 어떤 **시점**에 그 요청(또는 이벤트)을 보낼지도 어떤 방식으로든 정의합니다.
그리고 **사용자**는 (예: 어딘가의 웹 대시보드에서) 여러분의 앱이 그 요청을 보내야 할 **URL**을 어떤 방식으로든 정의합니다.
webhook의 URL을 등록하는 방법과 실제로 그 요청을 보내는 코드에 대한 모든 **로직**은 여러분에게 달려 있습니다. **여러분의 코드**에서 원하는 방식으로 작성하면 됩니다.
## **FastAPI**와 OpenAPI로 webhooks 문서화하기 { #documenting-webhooks-with-fastapi-and-openapi }
**FastAPI**에서는 OpenAPI를 사용해, 이러한 webhook의 이름, 여러분의 앱이 보낼 수 있는 HTTP 작업 타입(예: `POST`, `PUT` 등), 그리고 여러분의 앱이 보낼 요청 **본문(body)**을 정의할 수 있습니다.
이렇게 하면 사용자가 여러분의 **webhook** 요청을 받기 위해 **자신들의 API를 구현**하기가 훨씬 쉬워지고, 경우에 따라서는 자신의 API 코드 일부를 자동 생성할 수도 있습니다.
/// info | 정보
Webhooks는 OpenAPI 3.1.0 이상에서 사용할 수 있으며, FastAPI `0.99.0` 이상에서 지원됩니다.
///
## webhooks가 있는 앱 { #an-app-with-webhooks }
**FastAPI** 애플리케이션을 만들면, *경로 처리*를 정의하는 것과 같은 방식으로(예: `@app.webhooks.post()`), *webhooks*를 정의하는 데 사용할 수 있는 `webhooks` 속성이 있습니다.
{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *}
여러분이 정의한 webhook은 **OpenAPI** 스키마와 자동 **docs UI**에 포함됩니다.
/// info | 정보
`app.webhooks` 객체는 실제로 `APIRouter`일 뿐이며, 여러 파일로 앱을 구조화할 때 사용하는 것과 동일한 타입입니다.
///
webhook에서는 실제로(`/items/` 같은) *경로(path)*를 선언하지 않는다는 점에 유의하세요. 그곳에 전달하는 텍스트는 webhook의 **식별자**(이벤트 이름)일 뿐입니다. 예를 들어 `@app.webhooks.post("new-subscription")`에서 webhook 이름은 `new-subscription`입니다.
이는 **사용자**가 webhook 요청을 받고 싶은 실제 **URL 경로**를 다른 방식(예: 웹 대시보드)으로 정의할 것이라고 기대하기 때문입니다.
### 문서 확인하기 { #check-the-docs }
이제 앱을 실행하고 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>로 이동하세요.
문서에 일반적인 *경로 처리*가 보이고, 이제는 일부 **webhooks**도 함께 보일 것입니다:
<img src="/img/tutorial/openapi-webhooks/image01.png">

View File

@@ -0,0 +1,172 @@
# 경로 처리 고급 구성 { #path-operation-advanced-configuration }
## OpenAPI operationId { #openapi-operationid }
/// warning | 경고
OpenAPI “전문가”가 아니라면, 아마 이 내용은 필요하지 않을 것입니다.
///
매개변수 `operation_id`를 사용해 *경로 처리*에 사용할 OpenAPI `operationId`를 설정할 수 있습니다.
각 작업마다 고유하도록 보장해야 합니다.
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
### *경로 처리 함수* 이름을 operationId로 사용하기 { #using-the-path-operation-function-name-as-the-operationid }
API의 함수 이름을 `operationId`로 사용하고 싶다면, 모든 API를 순회하면서 `APIRoute.name`을 사용해 각 *경로 처리*의 `operation_id`를 덮어쓸 수 있습니다.
모든 *경로 처리*를 추가한 뒤에 수행해야 합니다.
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
/// tip | 팁
`app.openapi()`를 수동으로 호출한다면, 그 전에 `operationId`들을 업데이트해야 합니다.
///
/// warning | 경고
이렇게 할 경우, 각 *경로 처리 함수*의 이름이 고유하도록 보장해야 합니다.
서로 다른 모듈(파이썬 파일)에 있어도 마찬가지입니다.
///
## OpenAPI에서 제외하기 { #exclude-from-openapi }
생성된 OpenAPI 스키마(따라서 자동 문서화 시스템)에서 특정 *경로 처리*를 제외하려면, `include_in_schema` 매개변수를 `False`로 설정하세요:
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
## docstring에서 고급 설명 가져오기 { #advanced-description-from-docstring }
OpenAPI에 사용할 *경로 처리 함수*의 docstring 줄 수를 제한할 수 있습니다.
`\f`(이스케이프된 "form feed" 문자)를 추가하면 **FastAPI**는 이 지점에서 OpenAPI에 사용할 출력 내용을 잘라냅니다.
문서에는 표시되지 않지만, Sphinx 같은 다른 도구는 나머지 부분을 사용할 수 있습니다.
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
## 추가 응답 { #additional-responses }
*경로 처리*에 대해 `response_model``status_code`를 선언하는 방법을 이미 보셨을 것입니다.
이는 *경로 처리*의 기본 응답에 대한 메타데이터를 정의합니다.
모델, 상태 코드 등과 함께 추가 응답도 선언할 수 있습니다.
이에 대한 문서의 전체 장이 있으니, [OpenAPI의 추가 응답](additional-responses.md){.internal-link target=_blank}에서 읽어보세요.
## OpenAPI Extra { #openapi-extra }
애플리케이션에서 *경로 처리*를 선언하면, **FastAPI**는 OpenAPI 스키마에 포함될 해당 *경로 처리*의 관련 메타데이터를 자동으로 생성합니다.
/// note | 기술 세부사항
OpenAPI 명세에서는 이를 <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Operation Object</a>라고 부릅니다.
///
여기에는 *경로 처리*에 대한 모든 정보가 있으며, 자동 문서를 생성하는 데 사용됩니다.
`tags`, `parameters`, `requestBody`, `responses` 등이 포함됩니다.
*경로 처리* 전용 OpenAPI 스키마는 보통 **FastAPI**가 자동으로 생성하지만, 확장할 수도 있습니다.
/// tip | 팁
이는 저수준 확장 지점입니다.
추가 응답만 선언하면 된다면, 더 편리한 방법은 [OpenAPI의 추가 응답](additional-responses.md){.internal-link target=_blank}을 사용하는 것입니다.
///
`openapi_extra` 매개변수를 사용해 *경로 처리*의 OpenAPI 스키마를 확장할 수 있습니다.
### OpenAPI 확장 { #openapi-extensions }
예를 들어 `openapi_extra`는 [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions)를 선언하는 데 도움이 될 수 있습니다:
{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *}
자동 API 문서를 열면, 해당 특정 *경로 처리*의 하단에 확장이 표시됩니다.
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
또한 API의 `/openapi.json`에서 결과 OpenAPI를 보면, 특정 *경로 처리*의 일부로 확장이 포함된 것도 확인할 수 있습니다:
```JSON hl_lines="22"
{
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"x-aperture-labs-portal": "blue"
}
}
}
}
```
### 사용자 정의 OpenAPI *경로 처리* 스키마 { #custom-openapi-path-operation-schema }
`openapi_extra`의 딕셔너리는 *경로 처리*에 대해 자동으로 생성된 OpenAPI 스키마와 깊게 병합됩니다.
따라서 자동 생성된 스키마에 추가 데이터를 더할 수 있습니다.
예를 들어 Pydantic과 함께 FastAPI의 자동 기능을 사용하지 않고, 자체 코드로 요청을 읽고 검증하기로 결정할 수도 있지만, OpenAPI 스키마에는 여전히 그 요청을 정의하고 싶을 수 있습니다.
그럴 때 `openapi_extra`를 사용할 수 있습니다:
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
이 예시에서는 어떤 Pydantic 모델도 선언하지 않았습니다. 사실 요청 바디는 JSON으로 <abbr title="converted from some plain format, like bytes, into Python objects - bytes 같은 일반 형식에서 Python 객체로 변환">parsed</abbr>되지도 않고, `bytes`로 직접 읽습니다. 그리고 함수 `magic_data_reader()`가 어떤 방식으로든 이를 파싱하는 역할을 담당합니다.
그럼에도 불구하고, 요청 바디에 대해 기대하는 스키마를 선언할 수 있습니다.
### 사용자 정의 OpenAPI 콘텐츠 타입 { #custom-openapi-content-type }
같은 트릭을 사용하면, Pydantic 모델을 이용해 JSON Schema를 정의하고 이를 *경로 처리*의 사용자 정의 OpenAPI 스키마 섹션에 포함시킬 수 있습니다.
요청의 데이터 타입이 JSON이 아니더라도 이렇게 할 수 있습니다.
예를 들어 이 애플리케이션에서는 Pydantic 모델에서 JSON Schema를 추출하는 FastAPI의 통합 기능도, JSON에 대한 자동 검증도 사용하지 않습니다. 실제로 요청 콘텐츠 타입을 JSON이 아니라 YAML로 선언합니다:
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
그럼에도 기본 통합 기능을 사용하지 않더라도, YAML로 받고자 하는 데이터에 대한 JSON Schema를 수동으로 생성하기 위해 Pydantic 모델을 여전히 사용합니다.
그 다음 요청을 직접 사용하고, 바디를 `bytes`로 추출합니다. 이는 FastAPI가 요청 페이로드를 JSON으로 파싱하려고 시도조차 하지 않는다는 뜻입니다.
그리고 코드에서 YAML 콘텐츠를 직접 파싱한 뒤, 다시 같은 Pydantic 모델을 사용해 YAML 콘텐츠를 검증합니다:
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
/// tip | 팁
여기서는 같은 Pydantic 모델을 재사용합니다.
하지만 마찬가지로, 다른 방식으로 검증할 수도 있습니다.
///

View File

@@ -1,31 +1,31 @@
# 응답 - 상태 코드 변경
# 응답 - 상태 코드 변경 { #response-change-status-code }
기본 [응답 상태 코드 설정](../tutorial/response-status-code.md){.internal-link target=_blank}이 가능하다는 걸 이미 알고 계실 겁니다.
하지만 경우에 따라 기본 설정과 다른 상태 코드를 반환해야 할 때가 있습니다.
## 사용 예
## 사용 예 { #use-case }
예를 들어 기본적으로 HTTP 상태 코드 "OK" `200`을 반환하고 싶다고 가정해 봅시다.
하지만 데이터가 존재하지 않으면 이를 새로 생성하고, HTTP 상태 코드 "CREATED" `201`을 반환하고자 할 때가 있을 수 있습니다.
이때도 여전히 `response_model`을 사용하여 반환하는 데이터를 필터링하고 변환하고 싶을 수 있습니다.
하지만 여전히 `response_model`을 사용하여 반환하는 데이터를 필터링하고 변환할 수 있기를 원합니다.
이런 경우에는 `Response` 파라미터를 사용할 수 있습니다.
## `Response` 파라미터 사용하기
## `Response` 파라미터 사용하기 { #use-a-response-parameter }
*경로 작동 함수*에 `Response` 타입의 파라미터를 선언할 수 있습니다. (쿠키와 헤더에 대해 선언하는 것과 유사하게)
*경로 처리 함수*에 `Response` 타입의 파라미터를 선언할 수 있습니다. (쿠키와 헤더에 대해 선언하는 것과 유사하게)
그리고 이 *임시* 응답 객체에서 `status_code`를 설정할 수 있습니다.
{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *}
{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *}
그리고 평소처럼 원하는 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
그리고 평소처럼 필요한 어떤 객체든 반환할 수 있습니다(`dict`, 데이터베이스 모델 등).
`response_model`을 선언했다면 반환된 객체는 여전히 필터링되고 변환됩니다.
**FastAPI**는 이 *임시* 응답 객체에서 상태 코드(쿠키와 헤더 포함)를 추출하여, `response_model`로 필터링된 반환 값을 최종 응답에 넣습니다.
**FastAPI**는 이 *임시* 응답 객체에서 상태 코드(쿠키와 헤더 포함)를 추출하여, `response_model`로 필터링된 반환 값을 포함하는 최종 응답에 넣습니다.
또한, 의존성에서도 `Response` 파라미터를 선언하고 그 안에서 상태 코드를 설정할 수 있습니다. 단, 마지막으로 설정된 상태 코드가 우선 적용된다는 점을 유의하세요.

View File

@@ -1,49 +1,51 @@
# 응답 쿠키
# 응답 쿠키 { #response-cookies }
## `Response` 매개변수 사용하기
## `Response` 매개변수 사용하기 { #use-a-response-parameter }
*경로 작동 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다.
*경로 처리 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다.
그런 다음 해당 *임시* 응답 객체에서 쿠키를 설정할 수 있습니다.
{* ../../docs_src/response_cookies/tutorial002.py hl[1,8:9] *}
{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *}
그런 다음 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
그런 다음 일반적으로 하듯이 필요한 어떤 객체든 반환할 수 있습니다(`dict`, 데이터베이스 모델 등).
그리고 `response_model`을 선언했다면 반환한 객체를 거르고 변환하는 데 여전히 사용됩니다.
**FastAPI**는 그 *임시* 응답에서 쿠키(또한 헤더 및 상태 코드)를 추출하고, 반환 값이 포함된 최종 응답에 이를 넣습니다. 이 값은 `response_model`로 걸러지게 됩니다.
**FastAPI**는 그 *임시* 응답에서 쿠키(또한 헤더 및 상태 코드)를 추출하고, `response_model`로 필터링된 반환 값이 포함된 최종 응답에 이를 넣습니다.
또한 의존관계에서 `Response` 매개변수를 선언하고, 해당 의존성에서 쿠키(및 헤더)를 설정할 수도 있습니다.
## `Response`를 직접 반환하기
## `Response`를 직접 반환하기 { #return-a-response-directly }
코드에서 `Response`를 직접 반환할 때도 쿠키를 생성할 수 있습니다.
이를 위해 [Response를 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 설명한 대로 응답을 생성할 수 있습니다.
그런 다음 쿠키를 설정하고 반환하면 됩니다:
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
/// tip
{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *}
/// tip | 팁
`Response` 매개변수를 사용하지 않고 응답을 직접 반환하는 경우, FastAPI는 이를 직접 반환한다는 점에 유의하세요.
따라서 데이터가 올바른 유형인지 확인해야 합니다. 예: `JSONResponse`를 반환하는 경우, JSON과 호환되는지 확인하세요.
또한 `response_model`걸러져야 할 데이터달되지 않도록 확인하세요.
또한 `response_model`필터링되어야 했던 데이터송하지 않도록 하세요.
///
### 추가 정보
### 추가 정보 { #more-info }
/// note | 기술 세부사항
/// note | 기술 세부사항
`from starlette.responses import Response` 또는 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
**FastAPI**는 개발자의 편의를 위해 `fastapi.responses`로 동일한 `starlette.responses`를 제공합니다. 그러나 대부분의 응답은 Starlette에서 직접 제공됩니다.
**FastAPI**는 개발자의 편의를 위해 `fastapi.responses`로 동일한 `starlette.responses`를 제공합니다. 하지만 사용 가능한 대부분의 응답은 Starlette에서 직접 제공됩니다.
또한 `Response`는 헤더와 쿠키를 설정하는 데 자주 사용되므로, **FastAPI**는 이를 `fastapi.Response`로도 제공합니다.
///
사용 가능한 모든 매개변수와 옵션은 <a href="https://www.starlette.dev/responses/#set-cookie" class="external-link" target="_blank">Starlette 문서</a>에서 확인할 수 있습니다.
사용 가능한 모든 매개변수와 옵션은 <a href="https://www.starlette.dev/responses/#set-cookie" class="external-link" target="_blank">Starlette 문서</a>에서 확인할 수 있습니다.

View File

@@ -1,20 +1,20 @@
# 응답을 직접 반환하기
# 응답을 직접 반환하기 { #return-a-response-directly }
**FastAPI**에서 *경로 작업(path operation)* 생성할 때, 일반적으로 `dict`, `list`, Pydantic 모델, 데이터베이스 모델 등의 데이터를 반환할 수 있습니다.
**FastAPI**에서 *경로 처리(path operation)* 생성할 때, 일반적으로 `dict`, `list`, Pydantic 모델, 데이터베이스 모델 등의 데이터를 반환할 수 있습니다.
기본적으로 **FastAPI**는 [JSON 호환 가능 인코더](../tutorial/encoder.md){.internal-link target=_blank}에 설명된 `jsonable_encoder`를 사용해 해당 반환 값을 자동으로 `JSON`으로 변환합니다.
기본적으로 **FastAPI**는 [JSON 호환 가능 인코더](../tutorial/encoder.md){.internal-link target=_blank}에 설명된 `jsonable_encoder`를 사용해 해당 반환 값을 자동으로 JSON으로 변환합니다.
그런 다음, JSON 호환 데이터(예: `dict`)를 `JSONResponse`에 넣어 사용자의 응답을 전송하는 방식으로 처리됩니다.
그런 다음, 내부적으로는 JSON 호환 데이터(예: `dict`)를 `JSONResponse`에 넣어 클라이언트로 응답을 전송하는 데 사용합니다.
그러나 *경로 작업*에서 `JSONResponse`를 직접 반환할 수도 있습니다.
하지만 *경로 처리*에서 `JSONResponse`를 직접 반환할 수도 있습니다.
예를 들어, 사용자 정의 헤더나 쿠키를 반환해야 하는 경우에 유용할 수 있습니다.
## `Response` 반환하기
## `Response` 반환하기 { #return-a-response }
사실, `Response` 또는 그 하위 클래스를 반환할 수 있습니다.
/// tip
/// tip | 팁
`JSONResponse` 자체도 `Response`의 하위 클래스입니다.
@@ -26,38 +26,40 @@ Pydantic 모델로 데이터 변환을 수행하지 않으며, 내용을 다른
이로 인해 많은 유연성을 얻을 수 있습니다. 어떤 데이터 유형이든 반환할 수 있고, 데이터 선언이나 유효성 검사를 재정의할 수 있습니다.
## `Response`에서 `jsonable_encoder` 사용하기
## `Response`에서 `jsonable_encoder` 사용하기 { #using-the-jsonable-encoder-in-a-response }
**FastAPI**는 반환하는 `Response`에 아무런 변환을 하지 않으므로, 그 내용이 준비되어 있야 합니다.
**FastAPI**는 반환하는 `Response`에 아무런 변경도 하지 않으므로, 그 내용이 준비되어 있는지 확인해야 합니다.
예를 들어, Pydantic 모델을 `dict`로 변환 `JSONResponse`에 넣지 않으면 JSON 호환 유형으로 변환된 데이터 유형(예: `datetime`, `UUID` 등)이 사용되지 않습니다.
예를 들어, Pydantic 모델을 먼저 `dict`로 변환하고 `datetime`, `UUID` 등의 모든 데이터 타입을 JSON 호환 타입으로 변환하지 않으면 Pydantic 모델을 `JSONResponse`에 넣을 수 없습니다.
이러한 경우, 데이터를 응답에 전달하기 전에 `jsonable_encoder`를 사용하여 변환할 수 있습니다:
{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *}
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
/// note | 기술 세부 사항
/// note | 기술 세부사항
`from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
**FastAPI**는 개발자의 편의를 위해 `starlette.responses``fastapi.responses`로 제공합니다. 그러나 대부분의 가능한 응답은 Starlette에서 직접 제공합니다.
**FastAPI**는 개발자의 편의를 위해 `starlette.responses``fastapi.responses`로 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 제공합니다.
///
## 사용자 정의 `Response` 반환하기
위 예제는 필요한 모든 부분을 보여주지만, 아직 유용하지는 않습니다. 사실 데이터를 직접 반환하면 **FastAPI**가 이를 `JSONResponse`에 넣고 `dict`로 변환하는 등 모든 작업을 자동으로 처리합니다.
## 사용자 정의 `Response` 반환하기 { #returning-a-custom-response }
이제, 사용자 정의 응답을 반환하는 방법을 알아보겠습니다.
위 예제는 필요한 모든 부분을 보여주지만, 아직은 그다지 유용하지 않습니다. `item`을 그냥 직접 반환했어도 **FastAPI**가 기본으로 이를 `JSONResponse`에 넣고 `dict`로 변환하는 등의 작업을 모두 수행해 주었을 것이기 때문입니다.
예를 들어 <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a> 응답을 반환하고 싶다고 가정해보겠습니다.
이제, 이를 사용해 사용자 정의 응답을 반환하는 방법을 알아보겠습니다.
예를 들어 <a href="https://en.wikipedia.org/wiki/XML" class="external-link" target="_blank">XML</a> 응답을 반환하고 싶다고 가정해 보겠습니다.
XML 내용을 문자열에 넣고, 이를 `Response`에 넣어 반환할 수 있습니다:
{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *}
{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *}
## 참고 사항 { #notes }
## 참고 사항
`Response`를 직접 반환할 때, 그 데이터는 자동으로 유효성 검사되거나, 변환(직렬화)되거나, 문서화되지 않습니다.
그러나 [OpenAPI에서 추가 응답](additional-responses.md){.internal-link target=_blank}에서 설명된 대로 문서화할 수 있습니다.
이후 단락에서 자동 데이터 변환, 문서화 등을 사용하면서 사용자 정의 `Response`를 선언하는 방법을 확인할 수 있습니다.
이후 섹션에서 자동 데이터 변환, 문서화 등을 계속 사용하면서 이러한 사용자 정의 `Response`사용하는/선언하는 방법을 확인할 수 있습니다.

View File

@@ -1,12 +1,12 @@
# 응답 헤더
# 응답 헤더 { #response-headers }
## `Response` 매개변수 사용하기
## `Response` 매개변수 사용하기 { #use-a-response-parameter }
여러분은 *경로 작동 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다 (쿠키와 같이 사용할 수 있습니다).
여러분은 *경로 처리 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다 (쿠키와 같이 사용할 수 있습니다).
그런 다음, 여러분은 해당 *임시* 응답 객체에서 헤더를 설정할 수 있습니다.
{* ../../docs_src/response_headers/tutorial002.py hl[1,7:8] *}
{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *}
그 후, 일반적으로 사용하듯이 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.
@@ -16,26 +16,26 @@
또한, 종속성에서 `Response` 매개변수를 선언하고 그 안에서 헤더(및 쿠키)를 설정할 수 있습니다.
## `Response` 직접 반환하기
## `Response` 직접 반환하기 { #return-a-response-directly }
`Response`를 직접 반환할 때에도 헤더를 추가할 수 있습니다.
[응답을 직접 반환하기](response-directly.md){.internal-link target=_blank}에서 설명한 대로 응답을 생성하고, 헤더를 추가 매개변수로 전달하세요.
{* ../../docs_src/response_headers/tutorial001.py hl[10:12] *}
{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *}
/// note | 기술 세부사항
/// note | 기술 세부사항
`from starlette.responses import Response``from starlette.responses import JSONResponse`를 사용할 수도 있습니다.
**FastAPI**는 `starlette.responses``fastapi.responses`로 개발자의 편의를 위해 직접 제공하지만, 대부분의 응답은 Starlette에서 직접 제공됩니다.
**FastAPI**는 해당 *임시* 응답에서 헤더(쿠키와 상태 코드도 포함)를 추출하여, 여러분이 반환한 값을 포함하는 최종 응답에 `response_model`로 필터링된 값을 넣습니다.
그리고 `Response`는 헤더와 쿠키를 설정하는 데 자주 사용될 수 있으므로, **FastAPI**는 `fastapi.Response`로도 이를 제공합니다.
///
## 커스텀 헤더
## 커스텀 헤더 { #custom-headers }
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">X- 접두어를 사용하여</a> 커스텀 사설 헤더를 추가할 수 있습니다.
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers" class="external-link" target="_blank">`X-` 접두어를 사용하여</a> 커스텀 사설 헤더를 추가할 수 있다는 점을 기억하세요.
하지만, 여러분이 브라우저에서 클라이언트가 볼 수 있기를 원하는 커스텀 헤더가 있는 경우, CORS 설정에 이를 추가해야 합니다([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}에서 자세히 알아보세요). `expose_headers` 매개변수를 사용하여 <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette의 CORS 설명서</a>에 문서화된 대로 설정할 수 있습니다.
하지만, 여러분이 브라우저에서 클라이언트가 볼 수 있기를 원하는 커스텀 헤더가 있는 경우, CORS 설정에 이를 추가해야 합니다([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md){.internal-link target=_blank}에서 자세히 알아보세요). <a href="https://www.starlette.dev/middleware/#corsmiddleware" class="external-link" target="_blank">Starlette의 CORS 서</a>에 문서화된 `expose_headers` 매개변수를 사용하세요.

View File

@@ -0,0 +1,107 @@
# HTTP Basic Auth { #http-basic-auth }
가장 단순한 경우에는 HTTP Basic Auth를 사용할 수 있습니다.
HTTP Basic Auth에서는 애플리케이션이 사용자명과 비밀번호가 들어 있는 헤더를 기대합니다.
이를 받지 못하면 HTTP 401 "Unauthorized" 오류를 반환합니다.
그리고 값이 `Basic`이고 선택적으로 `realm` 파라미터를 포함하는 `WWW-Authenticate` 헤더를 반환합니다.
이는 브라우저가 사용자명과 비밀번호를 입력하는 통합 프롬프트를 표시하도록 알려줍니다.
그다음 사용자명과 비밀번호를 입력하면, 브라우저가 자동으로 해당 값을 헤더에 담아 전송합니다.
## 간단한 HTTP Basic Auth { #simple-http-basic-auth }
* `HTTPBasic``HTTPBasicCredentials`를 임포트합니다.
* `HTTPBasic`을 사용해 "`security` scheme"을 생성합니다.
* *경로 처리*에서 dependency로 해당 `security`를 사용합니다.
* `HTTPBasicCredentials` 타입의 객체를 반환합니다:
* 전송된 `username``password`를 포함합니다.
{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
처음으로 URL을 열어보면(또는 문서에서 "Execute" 버튼을 클릭하면) 브라우저가 사용자명과 비밀번호를 물어봅니다:
<img src="/img/tutorial/security/image12.png">
## 사용자명 확인하기 { #check-the-username }
더 완전한 예시입니다.
dependency를 사용해 사용자명과 비밀번호가 올바른지 확인하세요.
이를 위해 Python 표준 모듈 <a href="https://docs.python.org/3/library/secrets.html" class="external-link" target="_blank">`secrets`</a>를 사용해 사용자명과 비밀번호를 확인합니다.
`secrets.compare_digest()``bytes` 또는 ASCII 문자(영어에서 사용하는 문자)만 포함한 `str`을 받아야 합니다. 즉, `Sebastián``á` 같은 문자가 있으면 동작하지 않습니다.
이를 처리하기 위해 먼저 `username``password`를 UTF-8로 인코딩해서 `bytes`로 변환합니다.
그런 다음 `secrets.compare_digest()`를 사용해 `credentials.username``"stanleyjobson"`이고 `credentials.password``"swordfish"`인지 확실히 확인할 수 있습니다.
{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
이는 다음과 비슷합니다:
```Python
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
# Return some error
...
```
하지만 `secrets.compare_digest()`를 사용하면 "timing attacks"라고 불리는 한 유형의 공격에 대해 안전해집니다.
### Timing Attacks { #timing-attacks }
그렇다면 "timing attack"이란 무엇일까요?
공격자들이 사용자명과 비밀번호를 추측하려고 한다고 가정해봅시다.
그리고 사용자명 `johndoe`, 비밀번호 `love123`으로 요청을 보냅니다.
그러면 애플리케이션의 Python 코드는 대략 다음과 같을 것입니다:
```Python
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
...
```
하지만 Python이 `johndoe`의 첫 글자 `j``stanleyjobson`의 첫 글자 `s`와 비교하는 순간, 두 문자열이 같지 않다는 것을 이미 알게 되어 `False`를 반환합니다. 이는 “나머지 글자들을 비교하느라 계산을 더 낭비할 필요가 없다”고 판단하기 때문입니다. 그리고 애플리케이션은 "Incorrect username or password"라고 말합니다.
그런데 공격자들이 사용자명을 `stanleyjobsox`, 비밀번호를 `love123`으로 다시 시도합니다.
그러면 애플리케이션 코드는 다음과 비슷하게 동작합니다:
```Python
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
...
```
Python은 두 문자열이 같지 않다는 것을 알아차리기 전까지 `stanleyjobsox``stanleyjobson` 양쪽의 `stanleyjobso` 전체를 비교해야 합니다. 그래서 "Incorrect username or password"라고 응답하기까지 추가로 몇 마이크로초가 더 걸릴 것입니다.
#### 응답 시간은 공격자에게 도움이 됩니다 { #the-time-to-answer-helps-the-attackers }
이 시점에서 서버가 "Incorrect username or password" 응답을 보내는 데 몇 마이크로초 더 걸렸다는 것을 알아채면, 공격자들은 _무언가_ 맞았다는 것(초기 몇 글자가 맞았다는 것)을 알게 됩니다.
그리고 `johndoe`보다는 `stanleyjobsox`에 더 가까운 값을 시도해야 한다는 것을 알고 다시 시도할 수 있습니다.
#### "전문적인" 공격 { #a-professional-attack }
물론 공격자들은 이런 작업을 손으로 하지 않습니다. 보통 초당 수천~수백만 번 테스트할 수 있는 프로그램을 작성할 것이고, 한 번에 정답 글자 하나씩 추가로 얻어낼 수 있습니다.
그렇게 하면 몇 분 또는 몇 시간 만에, 응답에 걸린 시간만을 이용해(우리 애플리케이션의 “도움”을 받아) 올바른 사용자명과 비밀번호를 추측할 수 있게 됩니다.
#### `secrets.compare_digest()`로 해결하기 { #fix-it-with-secrets-compare-digest }
하지만 우리 코드는 실제로 `secrets.compare_digest()`를 사용하고 있습니다.
요약하면, `stanleyjobsox``stanleyjobson`을 비교하는 데 걸리는 시간은 `johndoe``stanleyjobson`을 비교하는 데 걸리는 시간과 같아집니다. 비밀번호도 마찬가지입니다.
이렇게 애플리케이션 코드에서 `secrets.compare_digest()`를 사용하면, 이러한 범위의 보안 공격 전반에 대해 안전해집니다.
### 오류 반환하기 { #return-the-error }
자격 증명이 올바르지 않다고 판단되면, 상태 코드 401(자격 증명이 제공되지 않았을 때와 동일)을 사용하는 `HTTPException`을 반환하고 브라우저가 로그인 프롬프트를 다시 표시하도록 `WWW-Authenticate` 헤더를 추가하세요:
{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}

View File

@@ -0,0 +1,19 @@
# 고급 보안 { #advanced-security }
## 추가 기능 { #additional-features }
[튜토리얼 - 사용자 가이드: 보안](../../tutorial/security/index.md){.internal-link target=_blank}에서 다룬 내용 외에도, 보안을 처리하기 위한 몇 가지 추가 기능이 있습니다.
/// tip | 팁
다음 섹션들은 **반드시 "고급"이라고 할 수는 없습니다**.
그리고 사용 사례에 따라, 그중 하나에 해결책이 있을 수도 있습니다.
///
## 먼저 튜토리얼 읽기 { #read-the-tutorial-first }
다음 섹션은 주요 [튜토리얼 - 사용자 가이드: 보안](../../tutorial/security/index.md){.internal-link target=_blank}을 이미 읽었다고 가정합니다.
모두 동일한 개념을 기반으로 하지만, 몇 가지 추가 기능을 사용할 수 있게 해줍니다.

View File

@@ -0,0 +1,274 @@
# OAuth2 스코프 { #oauth2-scopes }
**FastAPI**에서 OAuth2 스코프를 직접 사용할 수 있으며, 자연스럽게 동작하도록 통합되어 있습니다.
이를 통해 OAuth2 표준을 따르는 더 세밀한 권한 시스템을 OpenAPI 애플리케이션(및 API 문서)에 통합할 수 있습니다.
스코프를 사용하는 OAuth2는 Facebook, Google, GitHub, Microsoft, X(Twitter) 등 많은 대형 인증 제공자가 사용하는 메커니즘입니다. 이들은 이를 통해 사용자와 애플리케이션에 특정 권한을 제공합니다.
Facebook, Google, GitHub, Microsoft, X(Twitter)로 “로그인”할 때마다, 해당 애플리케이션은 스코프가 있는 OAuth2를 사용하고 있습니다.
이 섹션에서는 **FastAPI** 애플리케이션에서 동일한 “스코프가 있는 OAuth2”로 인증(Authentication)과 인가(Authorization)를 관리하는 방법을 확인합니다.
/// warning | 경고
이 섹션은 다소 고급 내용입니다. 이제 막 시작했다면 건너뛰어도 됩니다.
OAuth2 스코프가 반드시 필요한 것은 아니며, 인증과 인가는 원하는 방식으로 처리할 수 있습니다.
하지만 스코프가 있는 OAuth2는 (OpenAPI와 함께) API 및 API 문서에 깔끔하게 통합될 수 있습니다.
그럼에도 불구하고, 해당 스코프(또는 그 밖의 어떤 보안/인가 요구사항이든)는 코드에서 필요에 맞게 직접 강제해야 합니다.
많은 경우 스코프가 있는 OAuth2는 과한 선택일 수 있습니다.
하지만 필요하다고 알고 있거나 궁금하다면 계속 읽어보세요.
///
## OAuth2 스코프와 OpenAPI { #oauth2-scopes-and-openapi }
OAuth2 사양은 “스코프(scopes)”를 공백으로 구분된 문자열 목록으로 정의합니다.
각 문자열의 내용은 어떤 형식이든 될 수 있지만, 공백을 포함하면 안 됩니다.
이 스코프들은 “권한”을 나타냅니다.
OpenAPI(예: API 문서)에서는 “security schemes”를 정의할 수 있습니다.
이 security scheme 중 하나가 OAuth2를 사용한다면, 스코프도 선언하고 사용할 수 있습니다.
각 “스코프”는 (공백 없는) 문자열일 뿐입니다.
보통 다음과 같이 특정 보안 권한을 선언하는 데 사용합니다:
* `users:read` 또는 `users:write` 는 흔한 예시입니다.
* `instagram_basic` 는 Facebook/Instagram에서 사용합니다.
* `https://www.googleapis.com/auth/drive` 는 Google에서 사용합니다.
/// info | 정보
OAuth2에서 “스코프”는 필요한 특정 권한을 선언하는 문자열일 뿐입니다.
`:` 같은 다른 문자가 있거나 URL이어도 상관없습니다.
그런 세부사항은 구현에 따라 달라집니다.
OAuth2 입장에서는 그저 문자열입니다.
///
## 전체 개요 { #global-view }
먼저, 메인 **튜토리얼 - 사용자 가이드**의 [비밀번호(및 해싱)를 사용하는 OAuth2, JWT 토큰을 사용하는 Bearer](../../tutorial/security/oauth2-jwt.md){.internal-link target=_blank} 예제에서 어떤 부분이 바뀌는지 빠르게 살펴보겠습니다. 이제 OAuth2 스코프를 사용합니다:
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}
이제 변경 사항을 단계별로 살펴보겠습니다.
## OAuth2 보안 스킴 { #oauth2-security-scheme }
첫 번째 변경 사항은 이제 사용 가능한 스코프 2개(`me`, `items`)로 OAuth2 보안 스킴을 선언한다는 점입니다.
`scopes` 매개변수는 각 스코프를 키로 하고, 설명을 값으로 하는 `dict`를 받습니다:
{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}
이제 스코프를 선언했기 때문에, 로그인/인가할 때 API 문서에 스코프가 표시됩니다.
그리고 접근을 허용할 스코프를 선택할 수 있게 됩니다: `me``items`.
이는 Facebook, Google, GitHub 등으로 로그인하면서 권한을 부여할 때 사용되는 것과 동일한 메커니즘입니다:
<img src="/img/tutorial/security/image11.png">
## 스코프를 포함한 JWT 토큰 { #jwt-token-with-scopes }
이제 토큰 *경로 처리*를 수정해, 요청된 스코프를 반환하도록 합니다.
여전히 동일한 `OAuth2PasswordRequestForm`을 사용합니다. 여기에는 요청에서 받은 각 스코프를 담는 `scopes` 속성이 있으며, 타입은 `str``list`입니다.
그리고 JWT 토큰의 일부로 스코프를 반환합니다.
/// danger | 위험
단순화를 위해, 여기서는 요청으로 받은 스코프를 그대로 토큰에 추가하고 있습니다.
하지만 실제 애플리케이션에서는 보안을 위해, 사용자가 실제로 가질 수 있는 스코프만(또는 미리 정의한 것만) 추가하도록 반드시 확인해야 합니다.
///
{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}
## *경로 처리*와 의존성에서 스코프 선언하기 { #declare-scopes-in-path-operations-and-dependencies }
이제 `/users/me/items/`에 대한 *경로 처리*가 스코프 `items`를 요구한다고 선언합니다.
이를 위해 `fastapi`에서 `Security`를 import하여 사용합니다.
`Security`는 (`Depends`처럼) 의존성을 선언하는 데 사용할 수 있지만, `Security`는 스코프(문자열) 목록을 받는 `scopes` 매개변수도 받습니다.
이 경우, 의존성 함수 `get_current_active_user``Security`에 전달합니다(`Depends`로 할 때와 같은 방식).
하지만 스코프 `list`도 함께 전달합니다. 여기서는 스코프 하나만: `items`(더 많을 수도 있습니다).
또한 의존성 함수 `get_current_active_user``Depends`뿐 아니라 `Security`로도 하위 의존성을 선언할 수 있습니다. 자체 하위 의존성 함수(`get_current_user`)와 추가 스코프 요구사항을 선언합니다.
이 경우에는 스코프 `me`를 요구합니다(여러 스코프를 요구할 수도 있습니다).
/// note | 참고
반드시 서로 다른 곳에 서로 다른 스코프를 추가해야 하는 것은 아닙니다.
여기서는 **FastAPI**가 서로 다른 레벨에서 선언된 스코프를 어떻게 처리하는지 보여주기 위해 이렇게 합니다.
///
{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}
/// info | 기술 세부사항
`Security`는 실제로 `Depends`의 서브클래스이며, 나중에 보게 될 추가 매개변수 하나만 더 있습니다.
하지만 `Depends` 대신 `Security`를 사용하면, **FastAPI**는 보안 스코프를 선언할 수 있음을 알고 내부적으로 이를 사용하며, OpenAPI로 API를 문서화할 수 있습니다.
하지만 `fastapi`에서 `Query`, `Path`, `Depends`, `Security` 등을 import할 때, 이것들은 실제로 특수한 클래스를 반환하는 함수입니다.
///
## `SecurityScopes` 사용하기 { #use-securityscopes }
이제 의존성 `get_current_user`를 업데이트합니다.
이는 위의 의존성들이 사용하는 것입니다.
여기에서 앞서 만든 동일한 OAuth2 스킴을 의존성으로 선언하여 사용합니다: `oauth2_scheme`.
이 의존성 함수 자체에는 스코프 요구사항이 없기 때문에, `oauth2_scheme`와 함께 `Depends`를 사용할 수 있습니다. 보안 스코프를 지정할 필요가 없을 때는 `Security`를 쓸 필요가 없습니다.
또한 `fastapi.security`에서 import한 `SecurityScopes` 타입의 특별한 매개변수를 선언합니다.
`SecurityScopes` 클래스는 `Request`와 비슷합니다(`Request`는 요청 객체를 직접 얻기 위해 사용했습니다).
{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}
## `scopes` 사용하기 { #use-the-scopes }
매개변수 `security_scopes`의 타입은 `SecurityScopes`입니다.
여기에는 `scopes` 속성이 있으며, 자기 자신과 이 함수를 하위 의존성으로 사용하는 모든 의존성이 요구하는 스코프 전체를 담은 `list`를 가집니다. 즉, 모든 “dependants”... 다소 헷갈릴 수 있는데, 아래에서 다시 설명합니다.
`security_scopes` 객체(`SecurityScopes` 클래스)에는 또한 `scope_str` 속성이 있는데, 공백으로 구분된 단일 문자열로 스코프들을 담고 있습니다(이를 사용할 것입니다).
나중에 여러 지점에서 재사용(`raise`)할 수 있는 `HTTPException`을 생성합니다.
이 예외에는 필요한 스코프(있다면)를 공백으로 구분된 문자열(`scope_str`)로 포함합니다. 그리고 그 스코프 문자열을 `WWW-Authenticate` 헤더에 넣습니다(이는 사양의 일부입니다).
{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}
## `username`과 데이터 형태 검증하기 { #verify-the-username-and-data-shape }
`username`을 얻었는지 확인하고, 스코프를 추출합니다.
그런 다음 Pydantic 모델로 데이터를 검증합니다(`ValidationError` 예외를 잡습니다). JWT 토큰을 읽거나 Pydantic으로 데이터를 검증하는 과정에서 오류가 나면, 앞에서 만든 `HTTPException`을 raise합니다.
이를 위해 Pydantic 모델 `TokenData`에 새 속성 `scopes`를 추가합니다.
Pydantic으로 데이터를 검증하면, 예를 들어 스코프가 정확히 `str``list`이고 `username``str`인지 등을 보장할 수 있습니다.
예를 들어 `dict`나 다른 형태라면, 나중에 애플리케이션이 어느 시점에 깨지면서 보안 위험이 될 수 있습니다.
또한 해당 username을 가진 사용자가 있는지 확인하고, 없다면 앞에서 만든 동일한 예외를 raise합니다.
{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}
## `scopes` 검증하기 { #verify-the-scopes }
이제 이 의존성과 모든 dependant( *경로 처리* 포함)가 요구하는 모든 스코프가, 받은 토큰의 스코프에 포함되어 있는지 확인합니다. 그렇지 않으면 `HTTPException`을 raise합니다.
이를 위해, 모든 스코프를 `str`로 담고 있는 `security_scopes.scopes`를 사용합니다.
{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}
## 의존성 트리와 스코프 { #dependency-tree-and-scopes }
이 의존성 트리와 스코프를 다시 살펴보겠습니다.
`get_current_active_user` 의존성은 `get_current_user`를 하위 의존성으로 가지므로, `get_current_active_user`에서 선언된 스코프 `"me"``get_current_user`에 전달되는 `security_scopes.scopes`의 요구 스코프 목록에 포함됩니다.
*경로 처리* 자체도 스코프 `"items"`를 선언하므로, 이것 또한 `get_current_user`에 전달되는 `security_scopes.scopes` 목록에 포함됩니다.
의존성과 스코프의 계층 구조는 다음과 같습니다:
* *경로 처리* `read_own_items`는:
* 의존성과 함께 요구 스코프 `["items"]`를 가집니다:
* `get_current_active_user`:
* 의존성 함수 `get_current_active_user`는:
* 의존성과 함께 요구 스코프 `["me"]`를 가집니다:
* `get_current_user`:
* 의존성 함수 `get_current_user`는:
* 자체적으로는 요구 스코프가 없습니다.
* `oauth2_scheme`를 사용하는 의존성이 있습니다.
* `SecurityScopes` 타입의 `security_scopes` 매개변수가 있습니다:
*`security_scopes` 매개변수는 위에서 선언된 모든 스코프를 담은 `list``scopes` 속성을 가지므로:
* *경로 처리* `read_own_items`의 경우 `security_scopes.scopes`에는 `["me", "items"]`가 들어갑니다.
* *경로 처리* `read_users_me`의 경우 `security_scopes.scopes`에는 `["me"]`가 들어갑니다. 이는 의존성 `get_current_active_user`에서 선언되기 때문입니다.
* *경로 처리* `read_system_status`의 경우 `security_scopes.scopes`에는 `[]`(없음)가 들어갑니다. `scopes`가 있는 `Security`를 선언하지 않았고, 그 의존성인 `get_current_user``scopes`를 선언하지 않았기 때문입니다.
/// tip | 팁
여기서 중요한 “마법 같은” 점은 `get_current_user`가 각 *경로 처리*마다 검사해야 하는 `scopes` 목록이 달라진다는 것입니다.
이는 특정 *경로 처리*에 대한 의존성 트리에서, 각 *경로 처리*와 각 의존성에 선언된 `scopes`에 따라 달라집니다.
///
## `SecurityScopes`에 대한 추가 설명 { #more-details-about-securityscopes }
`SecurityScopes`는 어느 지점에서든, 그리고 여러 곳에서 사용할 수 있으며, “루트” 의존성에만 있어야 하는 것은 아닙니다.
`SecurityScopes`**해당 특정** *경로 처리*와 **해당 특정** 의존성 트리에 대해, 현재 `Security` 의존성과 모든 dependant에 선언된 보안 스코프를 항상 갖고 있습니다.
`SecurityScopes`에는 dependant가 선언한 모든 스코프가 포함되므로, 중앙의 의존성 함수에서 토큰이 필요한 스코프를 가지고 있는지 검증한 다음, 서로 다른 *경로 처리*에서 서로 다른 스코프 요구사항을 선언할 수 있습니다.
이들은 각 *경로 처리*마다 독립적으로 검사됩니다.
## 확인하기 { #check-it }
API 문서를 열면, 인증하고 인가할 스코프를 지정할 수 있습니다.
<img src="/img/tutorial/security/image11.png">
어떤 스코프도 선택하지 않으면 “인증”은 되지만, `/users/me/` 또는 `/users/me/items/`에 접근하려고 하면 권한이 충분하지 않다는 오류가 발생합니다. `/status/`에는 여전히 접근할 수 있습니다.
그리고 스코프 `me`는 선택했지만 스코프 `items`는 선택하지 않았다면, `/users/me/`에는 접근할 수 있지만 `/users/me/items/`에는 접근할 수 없습니다.
이는 사용자가 애플리케이션에 얼마나 많은 권한을 부여했는지에 따라, 제3자 애플리케이션이 사용자로부터 제공받은 토큰으로 이 *경로 처리*들 중 하나에 접근하려고 할 때 발생하는 상황과 같습니다.
## 제3자 통합에 대해 { #about-third-party-integrations }
이 예제에서는 OAuth2 “password” 플로우를 사용하고 있습니다.
이는 보통 자체 프론트엔드가 있는 우리 애플리케이션에 로그인할 때 적합합니다.
우리가 이를 통제하므로 `username``password`를 받는 것을 신뢰할 수 있기 때문입니다.
하지만 다른 사람들이 연결할 OAuth2 애플리케이션(즉, Facebook, Google, GitHub 등과 동등한 인증 제공자를 만들고 있다면)을 구축한다면, 다른 플로우 중 하나를 사용해야 합니다.
가장 흔한 것은 implicit 플로우입니다.
가장 안전한 것은 code 플로우이지만, 더 많은 단계가 필요해 구현이 더 복잡합니다. 복잡하기 때문에 많은 제공자는 implicit 플로우를 권장하게 됩니다.
/// note | 참고
인증 제공자마다 자신들의 브랜드의 일부로 만들기 위해, 각 플로우를 서로 다른 방식으로 이름 붙이는 경우가 흔합니다.
하지만 결국, 동일한 OAuth2 표준을 구현하고 있는 것입니다.
///
**FastAPI**는 `fastapi.security.oauth2`에 이러한 모든 OAuth2 인증 플로우를 위한 유틸리티를 포함합니다.
## 데코레이터 `dependencies`에서의 `Security` { #security-in-decorator-dependencies }
[경로 처리 데코레이터의 의존성](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md){.internal-link target=_blank}에서 설명한 것처럼 데코레이터의 `dependencies` 매개변수에 `Depends``list`를 정의할 수 있는 것과 같은 방식으로, 거기에서 `scopes`와 함께 `Security`를 사용할 수도 있습니다.

View File

@@ -0,0 +1,302 @@
# 설정과 환경 변수 { #settings-and-environment-variables }
많은 경우 애플리케이션에는 외부 설정이나 구성(예: secret key, 데이터베이스 자격 증명, 이메일 서비스 자격 증명 등)이 필요할 수 있습니다.
이러한 설정 대부분은 데이터베이스 URL처럼 변동 가능(변경될 수 있음)합니다. 그리고 많은 설정은 secret처럼 민감할 수 있습니다.
이 때문에 보통 애플리케이션이 읽어들이는 환경 변수로 이를 제공하는 것이 일반적입니다.
/// tip | 팁
환경 변수를 이해하려면 [환경 변수](../environment-variables.md){.internal-link target=_blank}를 읽어보세요.
///
## 타입과 검증 { #types-and-validation }
이 환경 변수들은 Python 외부에 있으며 다른 프로그램 및 시스템의 나머지 부분(그리고 Linux, Windows, macOS 같은 서로 다른 운영체제와도)과 호환되어야 하므로, 텍스트 문자열만 다룰 수 있습니다.
즉, Python에서 환경 변수로부터 읽어온 어떤 값이든 `str`이 되며, 다른 타입으로의 변환이나 검증은 코드에서 수행해야 합니다.
## Pydantic `Settings` { #pydantic-settings }
다행히 Pydantic은 <a href="https://docs.pydantic.dev/latest/concepts/pydantic_settings/" class="external-link" target="_blank">Pydantic: Settings management</a>를 통해 환경 변수에서 오는 이러한 설정을 처리할 수 있는 훌륭한 유틸리티를 제공합니다.
### `pydantic-settings` 설치하기 { #install-pydantic-settings }
먼저 [가상 환경](../virtual-environments.md){.internal-link target=_blank}을 만들고 활성화한 다음, `pydantic-settings` 패키지를 설치하세요:
<div class="termy">
```console
$ pip install pydantic-settings
---> 100%
```
</div>
또는 다음처럼 `all` extras를 설치하면 함께 포함됩니다:
<div class="termy">
```console
$ pip install "fastapi[all]"
---> 100%
```
</div>
### `Settings` 객체 만들기 { #create-the-settings-object }
Pydantic에서 `BaseSettings`를 import하고, Pydantic 모델과 매우 비슷하게 서브클래스를 만드세요.
Pydantic 모델과 같은 방식으로, 타입 어노테이션(그리고 필요하다면 기본값)과 함께 클래스 속성을 선언합니다.
다양한 데이터 타입, `Field()`로 추가 검증 등 Pydantic 모델에서 사용하는 동일한 검증 기능과 도구를 모두 사용할 수 있습니다.
{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *}
/// tip | 팁
빠르게 복사/붙여넣기할 예시가 필요하다면, 이 예시는 사용하지 말고 아래의 마지막 예시를 사용하세요.
///
그 다음, 해당 `Settings` 클래스의 인스턴스(여기서는 `settings` 객체)를 생성하면 Pydantic이 대소문자를 구분하지 않고 환경 변수를 읽습니다. 따라서 대문자 변수 `APP_NAME``app_name` 속성에 대해 읽힙니다.
이후 데이터를 변환하고 검증합니다. 그래서 그 `settings` 객체를 사용할 때는 선언한 타입의 데이터를 갖게 됩니다(예: `items_per_user``int`가 됩니다).
### `settings` 사용하기 { #use-the-settings }
이제 애플리케이션에서 새 `settings` 객체를 사용할 수 있습니다:
{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *}
### 서버 실행하기 { #run-the-server }
다음으로 환경 변수를 통해 구성을 전달하면서 서버를 실행합니다. 예를 들어 다음처럼 `ADMIN_EMAIL``APP_NAME`을 설정할 수 있습니다:
<div class="termy">
```console
$ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
/// tip | 팁
하나의 명령에 여러 env var를 설정하려면 공백으로 구분하고, 모두 명령 앞에 두세요.
///
그러면 `admin_email` 설정은 `"deadpool@example.com"`으로 설정됩니다.
`app_name``"ChimichangApp"`이 됩니다.
그리고 `items_per_user`는 기본값 `50`을 유지합니다.
## 다른 모듈의 설정 { #settings-in-another-module }
[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}에서 본 것처럼, 설정을 다른 모듈 파일에 넣을 수도 있습니다.
예를 들어 `config.py` 파일을 다음처럼 만들 수 있습니다:
{* ../../docs_src/settings/app01_py39/config.py *}
그리고 `main.py` 파일에서 이를 사용합니다:
{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *}
/// tip | 팁
[Bigger Applications - Multiple Files](../tutorial/bigger-applications.md){.internal-link target=_blank}에서 본 것처럼 `__init__.py` 파일도 필요합니다.
///
## 의존성에서 설정 사용하기 { #settings-in-a-dependency }
어떤 경우에는 어디서나 사용되는 전역 `settings` 객체를 두는 대신, 의존성에서 설정을 제공하는 것이 유용할 수 있습니다.
이는 특히 테스트 중에 유용할 수 있는데, 사용자 정의 설정으로 의존성을 override하기가 매우 쉽기 때문입니다.
### config 파일 { #the-config-file }
이전 예시에서 이어서, `config.py` 파일은 다음과 같을 수 있습니다:
{* ../../docs_src/settings/app02_an_py39/config.py hl[10] *}
이제는 기본 인스턴스 `settings = Settings()`를 생성하지 않는다는 점에 유의하세요.
### 메인 앱 파일 { #the-main-app-file }
이제 새로운 `config.Settings()`를 반환하는 의존성을 생성합니다.
{* ../../docs_src/settings/app02_an_py39/main.py hl[6,12:13] *}
/// tip | 팁
`@lru_cache`는 조금 뒤에 다룹니다.
지금은 `get_settings()`가 일반 함수라고 가정해도 됩니다.
///
그 다음 *경로 처리 함수*에서 이를 의존성으로 요구하고, 필요한 어디서든 사용할 수 있습니다.
{* ../../docs_src/settings/app02_an_py39/main.py hl[17,19:21] *}
### 설정과 테스트 { #settings-and-testing }
그 다음, `get_settings`에 대한 의존성 override를 만들어 테스트 중에 다른 설정 객체를 제공하기가 매우 쉬워집니다:
{* ../../docs_src/settings/app02_an_py39/test_main.py hl[9:10,13,21] *}
의존성 override에서는 새 `Settings` 객체를 생성할 때 `admin_email`의 새 값을 설정하고, 그 새 객체를 반환합니다.
그 다음 그것이 사용되는지 테스트할 수 있습니다.
## `.env` 파일 읽기 { #reading-a-env-file }
많이 바뀔 수 있는 설정이 많고, 서로 다른 환경에서 사용한다면, 이를 파일에 넣어 환경 변수인 것처럼 읽는 것이 유용할 수 있습니다.
이 관행은 충분히 흔해서 이름도 있는데, 이러한 환경 변수들은 보통 `.env` 파일에 두며, 그 파일을 "dotenv"라고 부릅니다.
/// tip | 팁
점(`.`)으로 시작하는 파일은 Linux, macOS 같은 Unix 계열 시스템에서 숨김 파일입니다.
하지만 dotenv 파일이 꼭 그 정확한 파일명을 가져야 하는 것은 아닙니다.
///
Pydantic은 외부 라이브러리를 사용해 이런 유형의 파일에서 읽는 기능을 지원합니다. 자세한 내용은 <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 | 팁
이를 사용하려면 `pip install python-dotenv`가 필요합니다.
///
### `.env` 파일 { #the-env-file }
다음과 같은 `.env` 파일을 둘 수 있습니다:
```bash
ADMIN_EMAIL="deadpool@example.com"
APP_NAME="ChimichangApp"
```
### `.env`에서 설정 읽기 { #read-settings-from-env }
그리고 `config.py`를 다음처럼 업데이트합니다:
{* ../../docs_src/settings/app03_an_py39/config.py hl[9] *}
/// tip | 팁
`model_config` 속성은 Pydantic 설정을 위한 것입니다. 자세한 내용은 <a href="https://docs.pydantic.dev/latest/concepts/config/" class="external-link" target="_blank">Pydantic: Concepts: Configuration</a>을 참고하세요.
///
여기서는 Pydantic `Settings` 클래스 안에 config `env_file`을 정의하고, 사용하려는 dotenv 파일의 파일명을 값으로 설정합니다.
### `lru_cache`로 `Settings`를 한 번만 생성하기 { #creating-the-settings-only-once-with-lru-cache }
디스크에서 파일을 읽는 것은 보통 비용이 큰(느린) 작업이므로, 각 요청마다 읽기보다는 한 번만 수행하고 동일한 settings 객체를 재사용하는 것이 좋습니다.
하지만 매번 다음을 수행하면:
```Python
Settings()
```
`Settings` 객체가 생성되고, 생성 시점에 `.env` 파일을 다시 읽게 됩니다.
의존성 함수가 단순히 다음과 같다면:
```Python
def get_settings():
return Settings()
```
요청마다 객체를 생성하게 되고, 요청마다 `.env` 파일을 읽게 됩니다. ⚠️
하지만 위에 `@lru_cache` 데코레이터를 사용하고 있으므로, `Settings` 객체는 최초 호출 시 딱 한 번만 생성됩니다. ✔️
{* ../../docs_src/settings/app03_an_py39/main.py hl[1,11] *}
그 다음 요청들에서 의존성으로 `get_settings()`가 다시 호출될 때마다, `get_settings()`의 내부 코드를 실행해서 새 `Settings` 객체를 만드는 대신, 첫 호출에서 반환된 동일한 객체를 계속 반환합니다.
#### `lru_cache` Technical Details { #lru-cache-technical-details }
`@lru_cache`는 데코레이션한 함수가 매번 다시 계산하는 대신, 첫 번째에 반환된 동일한 값을 반환하도록 함수를 수정합니다(즉, 매번 함수 코드를 실행하지 않습니다).
따라서 아래의 함수는 인자 조합마다 한 번씩 실행됩니다. 그리고 각각의 인자 조합에 대해 반환된 값은, 함수가 정확히 같은 인자 조합으로 호출될 때마다 반복해서 사용됩니다.
예를 들어 다음 함수가 있다면:
```Python
@lru_cache
def say_hi(name: str, salutation: str = "Ms."):
return f"Hello {salutation} {name}"
```
프로그램은 다음과 같이 실행될 수 있습니다:
```mermaid
sequenceDiagram
participant code as Code
participant function as say_hi()
participant execute as Execute function
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Camila")
function ->> execute: execute function code
execute ->> code: return the result
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Camila")
function ->> code: return stored result
end
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Rick")
function ->> execute: execute function code
execute ->> code: return the result
end
rect rgba(0, 255, 0, .1)
code ->> function: say_hi(name="Rick", salutation="Mr.")
function ->> execute: execute function code
execute ->> code: return the result
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Rick")
function ->> code: return stored result
end
rect rgba(0, 255, 255, .1)
code ->> function: say_hi(name="Camila")
function ->> code: return stored result
end
```
우리의 의존성 `get_settings()`의 경우, 함수가 어떤 인자도 받지 않으므로 항상 같은 값을 반환합니다.
이렇게 하면 거의 전역 변수처럼 동작합니다. 하지만 의존성 함수를 사용하므로 테스트를 위해 쉽게 override할 수 있습니다.
`@lru_cache`는 Python 표준 라이브러리의 `functools`에 포함되어 있으며, 자세한 내용은 <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" class="external-link" target="_blank">`@lru_cache`에 대한 Python 문서</a>에서 확인할 수 있습니다.
## 정리 { #recap }
Pydantic Settings를 사용하면 Pydantic 모델의 모든 강력한 기능을 활용해 애플리케이션의 설정 또는 구성을 처리할 수 있습니다.
* 의존성을 사용하면 테스트를 단순화할 수 있습니다.
* `.env` 파일을 사용할 수 있습니다.
* `@lru_cache`를 사용하면 각 요청마다 dotenv 파일을 반복해서 읽는 것을 피하면서도, 테스트 중에는 이를 override할 수 있습니다.

View File

@@ -1,67 +1,67 @@
# 하위 응용프로그램 - 마운트
# 하위 응용프로그램 - 마운트 { #sub-applications-mounts }
만약 각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 응용프로그램이 필요하다면, 메인 어플리케이션에 하나 (또는 그 이상의) 하위-응용프로그램(들)마운트"해서 사용할 수 있습니다.
각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 애플리케이션이 필요하다면, 메인 앱을 두고 하나(또는 그 이상)의 하위 응용프로그램을 "마운트"할 수 있습니다.
## **FastAPI** 응용프로그램 마운트
## **FastAPI** 애플리케이션 마운트 { #mounting-a-fastapi-application }
마운트"란 완전히 독립적인" 응용프로그램을 특정 경로에 추가하여 해당 하위 응용프로그램에 선언된 *경로 동작*을 통해 해당 경로 아래에 있는 모든 작업들을 처리할 수 있도록 하는 것을 의미합니다.
"마운트"란 완전히 "독립적인" 애플리케이션을 특정 경로에 추가하고, 그 하위 응용프로그램에 선언된 _경로 처리_로 해당 경로 아래 모든 을 처리도록 하는 것을 의미합니다.
### 최상단 응용프로그램
### 최상위 애플리케이션 { #top-level-application }
먼저, 메인, 최상단의 **FastAPI** 응용프로그램과 이것의 *경로 동작*을 생성합니다:
먼저, 메인 최상 **FastAPI** 애플리케이션과 그 *경로 처리*를 생성합니다:
{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *}
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *}
### 하위 응용프로그램
### 하위 응용프로그램 { #sub-application }
다음으로, 하위 응용프로그램과 이것의 *경로 동작*을 생성합니다:
다음, 하위 응용프로그램과 *경로 처리*를 생성합니다.
이 하위 응용프로그램은 또 다른 표준 FastAPI 응용프로그램입니다. 다만 이것은 “마운트입니다:
이 하위 응용프로그램은 또 다른 표준 FastAPI 애플리케이션이지만, "마운트"애플리케이션입니다:
{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *}
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *}
### 하위 응용프로그램 마운트
### 하위 응용프로그램 마운트 { #mount-the-sub-application }
최상단 응용프로그램, `app`에 하위 응용프로그램, `subapi`를 마운트합니다.
최상위 애플리케이션 `app` 하위 응용프로그램 `subapi`를 마운트합니다.
예시에서, 하위 응용프로그램션은 `/subapi` 경로에 마운트 될 것입니다:
경우 `/subapi` 경로에 마운트니다:
{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *}
{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *}
### 자동으로 생성된 API 문서 확인
### 자동 API 문서 확인 { #check-the-automatic-api-docs }
이제, `uvicorn`으로 메인 응용프로그램을 실행하십시오. 당신의 파일이 `main.py`라면, 이렇게 실행합니다:
이제 파일과 함께 `fastapi` 명령을 실행하세요:
<div class="termy">
```console
$ uvicorn main:app --reload
$ fastapi dev main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```
</div>
그리고 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>에서 문서를 여십시오.
그리고 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>에서 문서를 여세요.
메인 응용프로그램의 *경로 동작*만을 포함하는, 메인 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다:
메인 앱의 자동 API 문서를 보게 될 것이며, 메인 앱 자체의 _경로 처리_만 포함됩니다:
<img src="https://fastapi.tiangolo.com//img/tutorial/sub-applications/image01.png">
<img src="/img/tutorial/sub-applications/image01.png">
다음으로, <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>에서 하위 응용프로그램의 문서를 여십시오.
다음, <a href="http://127.0.0.1:8000/subapi/docs" class="external-link" target="_blank">http://127.0.0.1:8000/subapi/docs</a>에서 하위 응용프로그램의 문서를 여세요.
하위 경로 접두사 `/subapi` 아래에 선언된 *경로 동작* 을 포함하는, 하위 응용프로그램에 대한 자동 API 문서를 확인할 수 있습니다:
하위 응용프로그램의 자동 API 문서를 보게 될 것이며, 하위 경로 접두사 `/subapi` 아래에 올바르게 포함된 하위 응용프로그램 자체의 _경로 처리_만 포함됩니다:
<img src="https://fastapi.tiangolo.com//img/tutorial/sub-applications/image02.png">
<img src="/img/tutorial/sub-applications/image02.png">
두 사용자 인터페이스 중 어느 하나를 사용해야하는 경우, 브라우저 특정 응용프로그램 또는 하위 응용프로그램과 각각 통신할 수 있기 때문에 올바르게 동작할 것입니다.
두 사용자 인터페이스 중 어느 것과 상호작용을 시도하더라도 올바르게 동작할 것입니다. 브라우저가 각 특정 또는 하위 앱과 통신할 수 있기 때문입니다.
### 기술적 세부사항: `root_path`
### 기술적 세부사항: `root_path` { #technical-details-root-path }
위에 설명된 것과 같이 하위 응용프로그램을 마운트하는 경우, FastAPI는 `root_path`라고 하는 ASGI 명세의 매커니즘을 사용하여 하위 응용프로그램에 대한 마운트 경로 통신을 처리합니다.
위에 설명한 대로 하위 응용프로그램을 마운트하, FastAPI는 ASGI 명세의 메커니즘인 `root_path` 사용 하위 응용프로그램에 대한 마운트 경로를 전달하는 작업을 처리합니다.
를 통해, 하위 응용프로그램은 문서 UI를 위해 경로 접두사를 사용해야 한다는 사실을 인지합니다.
렇게 하면 하위 응용프로그램은 문서 UI를 위해 해당 경로 접두사를 사용해야 한다는 것을 알게 됩니다.
하위 응용프로그램역시 다른 하위 응용프로그램을 마운트하는 것이 가능하며 FastAPI가 모든 `root_path` 들을 자동으로 처리하기 때문에 모든 것 올바르게 동작할 것입니다.
또한 하위 응용프로그램도 자체적으로 하위 앱을 마운트할 수 있으며, FastAPI가 모든 `root_path` 자동으로 처리하기 때문에 모든 것 올바르게 동작니다.
`root_path`와 이것을 사용하는 방법에 대해서는 [프록시의 뒷단](./behind-a-proxy.md){.internal-link target=_blank} 섹션에서 배울 수 있습니다.
`root_path`와 이를 명시적으로 사용하는 방법에 대해서는 [프록시](behind-a-proxy.md){.internal-link target=_blank} 섹션에서 더 알아볼 수 있습니다.

View File

@@ -1,4 +1,4 @@
# 템플릿
# 템플릿 { #templates }
**FastAPI**와 함께 원하는 어떤 템플릿 엔진도 사용할 수 있습니다.
@@ -6,10 +6,9 @@
설정을 쉽게 할 수 있는 유틸리티가 있으며, 이를 **FastAPI** 애플리케이션에서 직접 사용할 수 있습니다(Starlette 제공).
## 의존성 설치
가상 환경을 생성하고(virtual environment{.internal-link target=_blank}), 활성화한 후 jinja2를 설치해야 합니다:
## 의존성 설치 { #install-dependencies }
[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고, 활성화한 후 `jinja2`를 설치해야 합니다:
<div class="termy">
@@ -21,39 +20,38 @@ $ pip install jinja2
</div>
## 사용하기 `Jinja2Templates`
## `Jinja2Templates` 사용하기 { #using-jinja2templates }
* `Jinja2Templates`를 가져옵니다.
* 나중에 재사용할 수 있는 `templates` 객체를 생성합니다.
* 템플릿을 반환할 경로 작업`Request` 매개변수를 선언합니다.
* 템플릿을 반환할 *경로 처리*`Request` 매개변수를 선언합니다.
* 생성한 `templates`를 사용하여 `TemplateResponse`를 렌더링하고 반환합니다. 템플릿의 이름, 요청 객체 및 Jinja2 템플릿 내에서 사용될 키-값 쌍이 포함된 "컨텍스트" 딕셔너리도 전달합니다.
```Python hl_lines="4 11 15-18"
{!../../docs_src/templates/tutorial001.py!}
```
{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *}
/// note | 참고
FastAPI 0.108.0 이전 Starlette 0.29.0에서는 `name`이 첫 번째 매개변수였습니다.
FastAPI 0.108.0 이전, Starlette 0.29.0에서는 `name`이 첫 번째 매개변수였습니다.
또한 이전 버전에서는 `request` 객체가 Jinja2의 컨텍스트에서 키-값 쌍의 일부로 전달되었습니다.
또한 이전 버전에서는 `request` 객체가 Jinja2의 컨텍스트에서 키-값 쌍의 일부로 전달되었습니다.
///
/// tip | 팁
`response_class=HTMLResponse`를 선언하면 문서 UI 응답이 HTML임을 알 수 있습니다.
`response_class=HTMLResponse`를 선언하면 문서 UI 응답이 HTML임을 알 수 있습니다.
///
/// note | 기술 세부 사항
/// note | 기술 세부사항
`from starlette.templating import Jinja2Templates`를 사용할 수도 있습니다.
**FastAPI**는 개발자를 위한 편리함으로 `fastapi.templating` 대신 `starlette.templating`을 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 옵니다. `Request` 및 `StaticFiles`도 마찬가지입니다.
**FastAPI**는 개발자를 위한 편리함으로 `fastapi.templating`과 동일하게 `starlette.templating`을 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 옵니다. `Request``StaticFiles`도 마찬가지입니다.
///
## 템플릿 작성하기
## 템플릿 작성하기 { #writing-templates }
그런 다음 `templates/item.html`에 템플릿을 작성할 수 있습니다. 예를 들면:
@@ -61,7 +59,7 @@ FastAPI 0.108.0 이전과 Starlette 0.29.0에서는 `name`이 첫 번째 매개
{!../../docs_src/templates/templates/item.html!}
```
### 템플릿 컨텍스트 값
### 템플릿 컨텍스트 값 { #template-context-values }
다음과 같은 HTML에서:
@@ -85,9 +83,9 @@ Item ID: {{ id }}
Item ID: 42
```
### 템플릿 `url_for` 인수
### 템플릿 `url_for` 인수 { #template-url-for-arguments }
템플릿 내에서 `url_for()`를 사용할 수도 있으며, 이는 *경로 작업 함수*에서 사용될 인수와 동일한 인수를 받습니다.
템플릿 내에서 `url_for()`를 사용할 수도 있으며, 이는 *경로 처리 함수*에서 사용될 인수와 동일한 인수를 받습니다.
따라서 다음과 같은 부분에서:
@@ -99,14 +97,15 @@ Item ID: 42
{% endraw %}
...이는 *경로 작업 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다.
...이는 *경로 처리 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다.
예를 들어, ID가 `42`일 경우, 이는 다음과 같이 렌더링됩니다:
```html
<a href="/items/42">
```
## 템플릿과 정적 파일
## 템플릿과 정적 파일 { #templates-and-static-files }
템플릿 내에서 `url_for()`를 사용할 수 있으며, 예를 들어 `name="static"`으로 마운트한 `StaticFiles`와 함께 사용할 수 있습니다.
@@ -114,7 +113,7 @@ Item ID: 42
{!../../docs_src/templates/templates/item.html!}
```
이 예제에서는 `static/styles.css`에 있는 CSS 파일에 연결될 것입니다:
이 예제에서는 다음을 통해 `static/styles.css`에 있는 CSS 파일에 링크합니다:
```CSS hl_lines="4"
{!../../docs_src/templates/static/styles.css!}
@@ -122,6 +121,6 @@ Item ID: 42
그리고 `StaticFiles`를 사용하고 있으므로, 해당 CSS 파일은 **FastAPI** 애플리케이션에서 `/static/styles.css` URL로 자동 제공됩니다.
## 더 많은 세부 사항
## 더 많은 세부 사항 { #more-details }
템플릿 테스트를 포함한 더 많은 세부 사항은 <a href="https://www.starlette.dev/templates/" class="external-link" target="_blank">Starlette의 템플릿 문서</a>를 확인하세요.

View File

@@ -1,14 +1,14 @@
# 테스트 의존성 오버라이드
# 오버라이드로 의존성 테스트하기 { #testing-dependencies-with-overrides }
## 테스트 중 의존성 오버라이드하기
## 테스트 중 의존성 오버라이드하기 { #overriding-dependencies-during-testing }
테스트를 진행하다 보면 의존성을 오버라이드해야 하는 경우가 있습니다.
테스트를 진행하다 보면 테스트 중에 의존성을 오버라이드해야 하는 경우가 있습니다.
원래 의존성을 실행하고 싶지 않을 수도 있습니다(또는 그 의존성이 가지고 있는 하위 의존성까지도 실행되지 않길 원할 수 있습니다).
대신, 테스트 동안(특정 테스트에서만) 사용될 다른 의존성을 제공하고, 원래 의존성이 사용되던 곳에서 사용할 수 있는 값을 제공하기를 원할 수 있습니다.
### 사용 사례: 외부 서비스
### 사용 사례: 외부 서비스 { #use-cases-external-service }
예를 들어, 외부 인증 제공자를 호출해야 하는 경우를 생각해봅시다.
@@ -18,11 +18,11 @@
외부 제공자를 한 번만 테스트하고 싶을 수도 있지만 테스트를 실행할 때마다 반드시 호출할 필요는 없습니다.
이 경우 해당 공급자를 호출하는 종속성을 오버라이드하고 테스트에 대해서만 모의 사용자를 반환하는 사용자 지정 종속성을 사용할 수 있습니다.
이 경우 해당 공급자를 호출하는 의존성을 오버라이드하고 테스트에 대해서만 모의 사용자를 반환하는 사용자 지정 의존성을 사용할 수 있습니다.
### `app.dependency_overrides` 속성 사용하기
### `app.dependency_overrides` 속성 사용하기 { #use-the-app-dependency-overrides-attribute }
이런 경우를 위해 **FastAPI** 응용 프로그램에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다.
이런 경우를 위해 **FastAPI** 애플리케이션에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다.
테스트를 위해 의존성을 오버라이드하려면, 원래 의존성(함수)을 키로 설정하고 오버라이드할 의존성(다른 함수)을 값으로 설정합니다.
@@ -34,7 +34,7 @@
**FastAPI** 애플리케이션 어디에서든 사용된 의존성에 대해 오버라이드를 설정할 수 있습니다.
원래 의존성은 *경로 동작 함수*, *경로 동작 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다.
원래 의존성은 *경로 처리 함수*, *경로 처리 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다.
FastAPI는 여전히 이를 오버라이드할 수 있습니다.
@@ -42,7 +42,7 @@ FastAPI는 여전히 이를 오버라이드할 수 있습니다.
그런 다음, `app.dependency_overrides`를 빈 `dict`로 설정하여 오버라이드를 재설정(제거)할 수 있습니다:
```python
```Python
app.dependency_overrides = {}
```

View File

@@ -1,5 +1,12 @@
# 이벤트 테스트: 시작 - 종료
# 이벤트 테스트: 라이프스팬 및 시작 - 종료 { #testing-events-lifespan-and-startup-shutdown }
테스트에서 이벤트 핸들러(`startup``shutdown`)를 실행해야 하는 경우, `with` 문과 함께 `TestClient`를 사용할 수 있습니다.
테스트에서 `lifespan` 실행해야 하는 경우, `with` 문과 함께 `TestClient`를 사용할 수 있습니다:
{* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *}
{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *}
["공식 Starlette 문서 사이트에서 테스트에서 라이프스팬 실행하기."](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)에 대한 자세한 내용을 더 읽을 수 있습니다.
더 이상 권장되지 않는 `startup``shutdown` 이벤트의 경우, 다음과 같이 `TestClient`를 사용할 수 있습니다:
{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *}

View File

@@ -1,13 +1,13 @@
# WebSocket 테스트하기
# WebSocket 테스트하기 { #testing-websockets }
`TestClient`를 사용하여 WebSocket을 테스트할 수 있습니다.
같은 `TestClient`를 사용하여 WebSocket을 테스트할 수 있습니다.
이를 위해 `with` 문에서 `TestClient`를 사용하여 WebSocket에 연결합니다:
{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *}
{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *}
/// note | 참고
자세한 내용은 Starlette의 <a href="https://www.starlette.dev/testclient/#testing-websocket-sessions" class="external-link" target="_blank"> WebSocket 테스트</a>에 관한 설명서를 참고하시길 바랍니다.
자세한 내용은 Starlette의 <a href="https://www.starlette.dev/testclient/#testing-websocket-sessions" class="external-link" target="_blank">testing WebSockets</a> 문서를 확인하세요.
///

View File

@@ -1,10 +1,10 @@
# `Request` 직접 사용하기
# `Request` 직접 사용하기 { #using-the-request-directly }
지금까지 요청에서 필요한 부분을 각 타입으로 선언하여 사용해 왔습니다.
다음과 같은 곳에서 데이터를 가져왔습니다:
* 경로의 파라미터로부터.
* 경로를 매개변수로.
* 헤더.
* 쿠키.
* 기타 등등.
@@ -13,29 +13,29 @@
하지만 `Request` 객체에 직접 접근해야 하는 상황이 있을 수 있습니다.
## `Request` 객체에 대한 세부 사항
## `Request` 객체에 대한 세부 사항 { #details-about-the-request-object }
**FastAPI**는 실제로 내부에 **Starlette**을 사용하며, 그 위에 여러 도구를 덧붙인 구조입니다. 따라서 여러분이 필요할 때 Starlette의 <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">`Request`</a> 객체를 직접 사용할 수 있습니다.
`Request` 객체에서 데이터를 직접 가져오는 경우(예: 본문을 읽기)에는 FastAPI가 해당 데이터를 검증하거나 변환하지 않으며, 문서화(OpenAPI를 통한 문서 자동화(로 생성된) API 사용자 인터페이스)도 되지 않니다.
또한 이는 `Request` 객체에서 데이터를 직접 가져오는 경우(예: 본문을 읽기) FastAPI가 해당 데이터를 검증하거나 변환하지 않으며, 문서화(OpenAPI를 통한 자동 API 사용자 인터페이스)도 되지 않는다는 의미이기도 합니다.
그러나 다른 매개변수(예: Pydantic 모델을 사용한 본문)는 여전히 검증, 변환, 주석 추가 등이 이루어집니다.
하지만 특정한 경우에는 `Request` 객체에 직접 접근하는 것이 유용할 수 있습니다.
하지만 특정한 경우에는 `Request` 객체를 가져오는 것이 유용할 수 있습니다.
## `Request` 객체를 직접 사용하기
## `Request` 객체를 직접 사용하기 { #use-the-request-object-directly }
여러분이 클라이언트의 IP 주소/호스트 정보를 *경로 작동 함수* 내부에서 가져와야 한다고 가정해 보겠습니다.
여러분이 클라이언트의 IP 주소/호스트 정보를 *경로 처리 함수* 내부에서 가져와야 한다고 가정해 보겠습니다.
이를 위해서는 요청에 직접 접근해야 합니다.
{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *}
{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *}
*경로 작동 함수* 매개변수를 `Request` 타입으로 선언하면 **FastAPI**가 해당 매개변수에 `Request` 객체를 전달하는 것을 알게 됩니다.
*경로 처리 함수* 매개변수를 `Request` 타입으로 선언하면 **FastAPI**가 해당 매개변수에 `Request`를 전달하는 것을 알게 됩니다.
/// tip | 팁
이 경우, 요청 매개변수와 함께 경로 매개변수를 선언한 것을 볼 수 있습니다.
이 경우, 요청 매개변수 옆에 경로 매개변수를 선언하고 있다는 점을 참고하세요.
따라서, 경로 매개변수는 추출되고 검증되며 지정된 타입으로 변환되고 OpenAPI로 주석이 추가됩니다.
@@ -43,14 +43,14 @@
///
## `Request` 설명서
## `Request` 설명서 { #request-documentation }
여러분은 `Request` 객체에 대한 더 자세한 내용을 <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">공식 Starlette 설명서 사이트</a>에서 읽어볼 수 있습니다.
여러분은 <a href="https://www.starlette.dev/requests/" class="external-link" target="_blank">공식 Starlette 설명서 사이트`Request` 객체</a>에 대한 더 자세한 내용을 읽어볼 수 있습니다.
/// note | 기술 세부사항
`from starlette.requests import Request`를 사용할 수도 있습니다.
**FastAPI**는 여러분(개발자)를 위한 편의를 위해 이를 직접 제공하지만, 실제로는 Starlette에서 가져온 것입니다.
**FastAPI**는 여러분(개발자)를 위한 편의를 위해 이를 직접 제공하지만, Starlette에서 직접 가져온 것입니다.
///

View File

@@ -1,10 +1,10 @@
# WebSockets
# WebSockets { #websockets }
여러분은 **FastAPI**에서 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API" class="external-link" target="_blank">WebSockets</a>를 사용할 수 있습니다.
## `WebSockets` 설치
## `websockets` 설치 { #install-websockets }
[가상 환경](../virtual-environments.md){.internal-link target=_blank)를 생성하고 활성화한 다음, `websockets`를 설치하세요:
[가상 환경](../virtual-environments.md){.internal-link target=_blank}을 생성하고 활성화한 다음, `websockets`("WebSocket" 프로토콜을 쉽게 사용할 수 있게 해주는 Python 라이브러리)를 설치하세요:
<div class="termy">
@@ -16,13 +16,13 @@ $ pip install websockets
</div>
## WebSockets 클라이언트
## WebSockets 클라이언트 { #websockets-client }
### 프로덕션 환경에서
### 프로덕션 환경에서 { #in-production }
여러분의 프로덕션 시스템에서는 React, Vue.js 또는 Angular와 같은 최신 프레임워크로 생성된 프런트엔드를 사용하고 있을 가능성이 높습니다.
백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다.
그리고 백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다.
또는 네이티브 코드로 WebSocket 백엔드와 직접 통신하는 네이티브 모바일 응용 프로그램을 가질 수도 있습니다.
@@ -30,23 +30,23 @@ $ pip install websockets
---
하지만 이번 예제에서는 일부 자바스크립트를 포함한 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다.
하지만 이번 예제에서는 일부 자바스크립트를 포함한 매우 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다.
물론, 이는 최적의 방법이 아니며 프로덕션 환경에서는 사용하지 않을 것입니다.
프로덕션 환경에서는 위에서 설명한 옵션 중 하나를 사용하는 것이 좋습니다.
프로덕션 환경에서는 위에서 설명한 옵션 중 하나를 사용할 것입니다.
그러나 이는 WebSockets의 서버 측에 집중하고 동작하는 예제를 제공하는 가장 간단한 방법입니다:
{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *}
{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *}
## `websocket` 생성하기
## `websocket` 생성하기 { #create-a-websocket }
**FastAPI** 응용 프로그램에서 `websocket`을 생성합니다:
{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *}
{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *}
/// note | 기술 세부사항
/// note | 기술 세부사항
`from starlette.websockets import WebSocket`을 사용할 수도 있습니다.
@@ -54,17 +54,17 @@ $ pip install websockets
///
## 메시지를 대기하고 전송하기
## 메시지를 대기하고 전송하기 { #await-for-messages-and-send-messages }
WebSocket 경로에서 메시지를 대기(`await`)하고 전송할 수 있습니다.
{* ../../docs_src/websockets/tutorial001.py hl[48:52] *}
{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *}
여러분은 이진 데이터, 텍스트, JSON 데이터를 받을 수 있고 전송할 수 있습니다.
## 시도해보기
## 시도해보기 { #try-it }
파일 이름이 `main.py`라고 가정하고 응용 프로그램을 실행합니다:
파일 이름이 `main.py`라고 가정하고 다음으로 응용 프로그램을 실행합니다:
<div class="termy">
@@ -76,7 +76,7 @@ $ fastapi dev main.py
</div>
브라우저에서 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>을 열어보세요.
브라우저에서 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>을 세요.
간단한 페이지가 나타날 것입니다:
@@ -86,7 +86,7 @@ $ fastapi dev main.py
<img src="/img/tutorial/websockets/image02.png">
**FastAPI** WebSocket 응용 프로그램이 응답을 돌려줄 것입니다:
그리고 WebSockets가 포함된 **FastAPI** 응용 프로그램이 응답을 돌려줄 것입니다:
<img src="/img/tutorial/websockets/image03.png">
@@ -94,9 +94,9 @@ $ fastapi dev main.py
<img src="/img/tutorial/websockets/image04.png">
모든 메시지는 동일한 WebSocket 연결을 사용합니다.
그리고 모든 메시지는 동일한 WebSocket 연결을 사용합니다.
## `Depends` 및 기타 사용하기
## `Depends` 및 기타 사용하기 { #using-depends-and-others }
WebSocket 엔드포인트에서 `fastapi`에서 다음을 가져와 사용할 수 있습니다:
@@ -107,21 +107,21 @@ WebSocket 엔드포인트에서 `fastapi`에서 다음을 가져와 사용할
* `Path`
* `Query`
이들은 다른 FastAPI 엔드포인트/*경로 작동*과 동일하게 동작합니다:
이들은 다른 FastAPI 엔드포인트/*경로 처리*와 동일하게 동작합니다:
{* ../../docs_src/websockets/tutorial002_an_py310.py hl[68:69,82] *}
/// info | 정보
WebSocket에서는 `HTTPException`을 발생시키는 것하지 않습니다. 대신 `WebSocketException`을 발생시킵니다.
WebSocket이기 때문`HTTPException`을 발생시키는 것하지 않습니다. 대신 `WebSocketException`을 발생시킵니다.
명세서에 정의된 <a href="https://tools.ietf.org/html/rfc6455#section-7.4.1" class="external-link" target="_blank">유효한 코드</a>를 사용하여 종료 코드를 설정할 수 있습니다.
///
### 종속성을 가진 WebSockets 테스트
### 종속성을 가진 WebSockets 시도해보기 { #try-the-websockets-with-dependencies }
파일 이름이 `main.py`라고 가정하고 응용 프로그램을 실행합니다:
파일 이름이 `main.py`라고 가정하고 다음으로 응용 프로그램을 실행합니다:
<div class="termy">
@@ -133,9 +133,9 @@ $ fastapi dev main.py
</div>
브라우저에서 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>을 열어보세요.
브라우저에서 <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>을 세요.
다음과 같은 값을 설정할 수 있습니다:
여기에서 다음을 설정할 수 있습니다:
* 경로에 사용된 "Item ID".
* 쿼리 매개변수로 사용된 "Token".
@@ -146,13 +146,13 @@ $ fastapi dev main.py
///
WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다:
렇게 하면 WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다:
<img src="/img/tutorial/websockets/image05.png">
## 연결 해제 및 다중 클라이언트 처리
## 연결 해제 및 다중 클라이언트 처리 { #handling-disconnections-and-multiple-clients }
WebSocket 연결이 닫히면, `await websocket.receive_text()``WebSocketDisconnect` 예외를 발생시킵니다. 이를 잡아 처리할 수 있습니다:
WebSocket 연결이 닫히면, `await websocket.receive_text()``WebSocketDisconnect` 예외를 발생시킵니다. 그러면 이 예제처럼 이를 잡아 처리할 수 있습니다.
{* ../../docs_src/websockets/tutorial003_py39.py hl[79:81] *}
@@ -160,7 +160,7 @@ WebSocket 연결이 닫히면, `await websocket.receive_text()`가 `WebSocketDis
* 여러 브라우저 탭에서 앱을 엽니다.
* 각 탭에서 메시지를 작성합니다.
* 한 탭을 닫아보세요.
* 그런 다음 탭 중 하나를 닫아보세요.
`WebSocketDisconnect` 예외가 발생하며, 다른 모든 클라이언트가 다음과 같은 메시지를 수신합니다:
@@ -170,17 +170,17 @@ Client #1596980209979 left the chat
/// tip | 팁
응용 프로그램은 여러 WebSocket 연결에 메시지를 브로드캐스트하는 방법을 보여주는 간단한 예제입니다.
은 여러 WebSocket 연결에 메시지를 처리하고 브로드캐스트하는 방법을 보여주는 최소한의 간단한 예제입니다.
그러나 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동합니다.
하지만 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동한다는 점을 기억하세요.
FastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구를 찾고 있다면, <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>를 확인하세요.
FastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구가 필요하다면, <a href="https://github.com/encode/broadcaster" class="external-link" target="_blank">encode/broadcaster</a>를 확인하세요.
///
## 추가 정보
## 추가 정보 { #more-info }
다음 옵션에 대한 자세한 내용을 보려면 Starlette의 문서를 확인하세요:
다음 옵션에 대해 더 알아보려면 Starlette의 문서를 확인하세요:
* <a href="https://www.starlette.dev/websockets/" class="external-link" target="_blank">`WebSocket` 클래스</a>.
* <a href="https://www.starlette.dev/endpoints/#websocketendpoint" class="external-link" target="_blank">클래스 기반 WebSocket 처리</a>.

View File

@@ -1,10 +1,10 @@
# WSGI 포함하기 - Flask, Django 그 외
# WSGI 포함하기 - Flask, Django 그 외 { #including-wsgi-flask-django-others }
[서브 응용 프로그램 - 마운트](sub-applications.md){.internal-link target=_blank}, [프록시 뒤편에서](behind-a-proxy.md){.internal-link target=_blank}에서 보았듯이 WSGI 응용 프로그램들을 다음과 같이 마운트 할 수 있습니다.
[서브 응용 프로그램 - 마운트](sub-applications.md){.internal-link target=_blank}, [프록시 뒤편에서](behind-a-proxy.md){.internal-link target=_blank}에서 보았듯이 WSGI 응용 프로그램들을 마운트 할 수 있습니다.
`WSGIMiddleware`를 사용하여 WSGI 응용 프로그램(예: Flask, Django 등)을 감쌀 수 있습니다.
이를 위해 `WSGIMiddleware`를 사용 WSGI 응용 프로그램(예: Flask, Django 등)을 감쌀 수 있습니다.
## `WSGIMiddleware` 사용하기
## `WSGIMiddleware` 사용하기 { #using-wsgimiddleware }
`WSGIMiddleware`를 불러와야 합니다.
@@ -12,9 +12,9 @@
그 후, 해당 경로에 마운트합니다.
{* ../../docs_src/wsgi/tutorial001.py hl[2:3,23] *}
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
## 확인하기
## 확인하기 { #check-it }
이제 `/v1/` 경로에 있는 모든 요청은 Flask 응용 프로그램에서 처리됩니다.
@@ -26,7 +26,7 @@
Hello, World from Flask!
```
그리고 다음으로 이동하면 <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> Flask의 응답을 볼 수 있습니다:
그리고 다음으로 이동하면 <a href="http://localhost:8000/v2" class="external-link" target="_blank">http://localhost:8000/v2</a> **FastAPI**의 응답을 볼 수 있습니다:
```JSON
{

Some files were not shown because too many files have changed in this diff Show More