mirror of
https://github.com/fastapi/fastapi.git
synced 2026-02-06 04:11:14 -05:00
Compare commits
180 Commits
translate-
...
update-out
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df9b78b5d1 | ||
|
|
79406a4b04 | ||
|
|
de56c96c64 | ||
|
|
570e592a03 | ||
|
|
110b45d9b2 | ||
|
|
72325f698f | ||
|
|
8bdbd3725f | ||
|
|
23ddf09dd1 | ||
|
|
6646e2b94f | ||
|
|
c5fd75a321 | ||
|
|
54f8aeeb9a | ||
|
|
97145588f5 | ||
|
|
0dd42b746e | ||
|
|
b49435becd | ||
|
|
2d46372a6f | ||
|
|
464c359bb0 | ||
|
|
457cd75c23 | ||
|
|
2838dcb4a8 | ||
|
|
b82993643e | ||
|
|
b892c3126c | ||
|
|
3578270af4 | ||
|
|
2224b4e63b | ||
|
|
136d5f0a56 | ||
|
|
afb44f0ff8 | ||
|
|
4fe06cc24a | ||
|
|
cae2659678 | ||
|
|
da9e101d50 | ||
|
|
8488d31aff | ||
|
|
dcfd432c36 | ||
|
|
c7682a198a | ||
|
|
b5d276bda8 | ||
|
|
2c5a844c44 | ||
|
|
6ff8ff5b57 | ||
|
|
f23ea3bd95 | ||
|
|
b4ed7e5b06 | ||
|
|
c00cebc5c6 | ||
|
|
31faba8e41 | ||
|
|
64d0ee9104 | ||
|
|
2e170b9585 | ||
|
|
5ca11c59e3 | ||
|
|
0e68d36cd5 | ||
|
|
1de0de56c8 | ||
|
|
734c95b05a | ||
|
|
84a5bcf82d | ||
|
|
0e064009fb | ||
|
|
ad29e44c81 | ||
|
|
71ceac20da | ||
|
|
b0e99d66e8 | ||
|
|
cec4be00ba | ||
|
|
aea61373ae | ||
|
|
fe5b617aec | ||
|
|
ee0c12521f | ||
|
|
4a3a71f1c1 | ||
|
|
75c47187f3 | ||
|
|
1e5e8b44cb | ||
|
|
440bfd70a9 | ||
|
|
5d50b74915 | ||
|
|
09f5941f0e | ||
|
|
c944add5a9 | ||
|
|
1d96b3e3f1 | ||
|
|
3675e284ab | ||
|
|
741f77d571 | ||
|
|
9656e925a9 | ||
|
|
0748214c43 | ||
|
|
a1bb70e5a5 | ||
|
|
9df1f8293d | ||
|
|
b134f406d1 | ||
|
|
3ee652dd0c | ||
|
|
a4297066c2 | ||
|
|
61f95c9606 | ||
|
|
9e0f4ca77a | ||
|
|
41352de24c | ||
|
|
ca4692a8c6 | ||
|
|
08dad5c69f | ||
|
|
6ab68c62b8 | ||
|
|
3a41403ccd | ||
|
|
c9e512d808 | ||
|
|
4414286f2c | ||
|
|
938c5f3500 | ||
|
|
21b7b0893b | ||
|
|
5083f27e03 | ||
|
|
741c7345ea | ||
|
|
f6ba0141f4 | ||
|
|
27b91d4ad6 | ||
|
|
e3a66494c9 | ||
|
|
dc3278654f | ||
|
|
573c593dd0 | ||
|
|
261736ab4c | ||
|
|
dd780f8caa | ||
|
|
7621a3aa4b | ||
|
|
eacbce24c9 | ||
|
|
f3f498100f | ||
|
|
2247750d74 | ||
|
|
ec07e62e1c | ||
|
|
82959de14c | ||
|
|
bc9ad6b134 | ||
|
|
608ff552ba | ||
|
|
87b5333e8a | ||
|
|
ecb1444738 | ||
|
|
5c3f0307ae | ||
|
|
f2487ce88c | ||
|
|
a0e34c7473 | ||
|
|
da4083c30f | ||
|
|
b833e53ade | ||
|
|
6173733200 | ||
|
|
20ff394d75 | ||
|
|
779f7ddc37 | ||
|
|
3626d764c1 | ||
|
|
07f08fc79a | ||
|
|
df6530e002 | ||
|
|
08924400c2 | ||
|
|
c9629e0eb2 | ||
|
|
9348a5e2cf | ||
|
|
a3dccaeb14 | ||
|
|
8c32e91c10 | ||
|
|
7a0589466c | ||
|
|
442d007e76 | ||
|
|
eaf07c5d84 | ||
|
|
597b435ae7 | ||
|
|
74cc27fd5a | ||
|
|
f1a39cab12 | ||
|
|
509afeb475 | ||
|
|
6e47171e9c | ||
|
|
b9b75ba5f1 | ||
|
|
e0abd210f6 | ||
|
|
2eb978b87a | ||
|
|
50a78bf840 | ||
|
|
2d459e4845 | ||
|
|
7faa7089d6 | ||
|
|
0ab68a762f | ||
|
|
7443bc7a46 | ||
|
|
6afb15c518 | ||
|
|
ad6b2901a6 | ||
|
|
463a3a24d7 | ||
|
|
db5441eba1 | ||
|
|
536a5bafe7 | ||
|
|
0c7f2b66d7 | ||
|
|
9fec72687f | ||
|
|
8fa635c718 | ||
|
|
fb15bba819 | ||
|
|
23bcfa094d | ||
|
|
f317ede223 | ||
|
|
c597d9cb53 | ||
|
|
a96dd013a4 | ||
|
|
a456e92a21 | ||
|
|
1be80f4885 | ||
|
|
e63f382b0f | ||
|
|
7b864acf37 | ||
|
|
e9e0419ed0 | ||
|
|
249a776b70 | ||
|
|
97aa825422 | ||
|
|
1054fbd256 | ||
|
|
effe493ae0 | ||
|
|
612a2d20bc | ||
|
|
14f3068762 | ||
|
|
d05b18ec40 | ||
|
|
9a76f2fec9 | ||
|
|
0383fb3ab9 | ||
|
|
50fa3f7c88 | ||
|
|
5ec2615b1a | ||
|
|
16e583413c | ||
|
|
1fedd1c73b | ||
|
|
cf8dc98aad | ||
|
|
6f977366a4 | ||
|
|
154ce03ff0 | ||
|
|
49653aa295 | ||
|
|
f03a1502a0 | ||
|
|
a2912ffa26 | ||
|
|
8183e748ee | ||
|
|
cefd50702a | ||
|
|
3d1f9268fc | ||
|
|
7eac6e3169 | ||
|
|
21d2c5cea0 | ||
|
|
c75ae058e4 | ||
|
|
961b2e844a | ||
|
|
b4ba7f4652 | ||
|
|
c35e1fd4b4 | ||
|
|
d1c67c0055 | ||
|
|
18762e38a9 | ||
|
|
b1db1395b6 |
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@@ -8,7 +8,7 @@ updates:
|
||||
commit-message:
|
||||
prefix: ⬆
|
||||
# Python
|
||||
- package-ecosystem: "pip"
|
||||
- package-ecosystem: "uv"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
|
||||
1
.github/labeler.yml
vendored
1
.github/labeler.yml
vendored
@@ -31,6 +31,7 @@ internal:
|
||||
- .pre-commit-config.yaml
|
||||
- pdm_build.py
|
||||
- requirements*.txt
|
||||
- uv.lock
|
||||
- docs/en/data/sponsors.yml
|
||||
- docs/en/overrides/main.html
|
||||
- all-globs-to-all-files:
|
||||
|
||||
29
.github/workflows/build-docs.yml
vendored
29
.github/workflows/build-docs.yml
vendored
@@ -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,21 +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
|
||||
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:
|
||||
@@ -83,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/**
|
||||
|
||||
12
.github/workflows/contributors.yml
vendored
12
.github/workflows/contributors.yml
vendored
@@ -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 }}
|
||||
|
||||
18
.github/workflows/deploy-docs.yml
vendored
18
.github/workflows/deploy-docs.yml
vendored
@@ -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 }}
|
||||
|
||||
6
.github/workflows/issue-manager.yml
vendored
6
.github/workflows/issue-manager.yml
vendored
@@ -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 there’s 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."
|
||||
}
|
||||
}
|
||||
|
||||
12
.github/workflows/label-approved.yml
vendored
12
.github/workflows/label-approved.yml
vendored
@@ -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: >
|
||||
|
||||
12
.github/workflows/notify-translations.yml
vendored
12
.github/workflows/notify-translations.yml
vendored
@@ -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 }}
|
||||
|
||||
12
.github/workflows/people.yml
vendored
12
.github/workflows/people.yml
vendored
@@ -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 }}
|
||||
|
||||
7
.github/workflows/pre-commit.yml
vendored
7
.github/workflows/pre-commit.yml
vendored
@@ -40,18 +40,15 @@ 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
|
||||
|
||||
15
.github/workflows/publish.yml
vendored
15
.github/workflows/publish.yml
vendored
@@ -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
|
||||
|
||||
13
.github/workflows/smokeshow.yml
vendored
13
.github/workflows/smokeshow.yml
vendored
@@ -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
|
||||
|
||||
12
.github/workflows/sponsors.yml
vendored
12
.github/workflows/sponsors.yml
vendored
@@ -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 }}
|
||||
|
||||
4
.github/workflows/test-redistribute.yml
vendored
4
.github/workflows/test-redistribute.yml
vendored
@@ -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
|
||||
|
||||
64
.github/workflows/test.yml
vendored
64
.github/workflows/test.yml
vendored
@@ -13,10 +13,38 @@ on:
|
||||
- cron: "0 0 * * 1"
|
||||
|
||||
env:
|
||||
UV_SYSTEM_PYTHON: 1
|
||||
UV_NO_SYNC: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
# Required permissions
|
||||
permissions:
|
||||
pull-requests: read
|
||||
# Set job outputs to values from filter step
|
||||
outputs:
|
||||
src: ${{ steps.filter.outputs.src }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
# For pull requests it's not necessary to checkout the code but for the main branch it is
|
||||
- uses: dorny/paths-filter@v3
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
src:
|
||||
- .github/workflows/test.yml
|
||||
- docs_src/**
|
||||
- fastapi/**
|
||||
- scripts/**
|
||||
- tests/**
|
||||
- .python-version
|
||||
- pyproject.toml
|
||||
- uv.lock
|
||||
|
||||
test:
|
||||
needs:
|
||||
- changes
|
||||
if: needs.changes.outputs.src == 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-latest, macos-latest ]
|
||||
@@ -44,6 +72,8 @@ jobs:
|
||||
coverage: coverage
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
@@ -57,17 +87,16 @@ 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
|
||||
if: matrix.codspeed != 'codspeed'
|
||||
run: bash scripts/test.sh
|
||||
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 }}
|
||||
@@ -79,18 +108,19 @@ jobs:
|
||||
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
|
||||
include-hidden-files: true
|
||||
|
||||
coverage-combine:
|
||||
needs: [test]
|
||||
needs:
|
||||
- test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
@@ -100,33 +130,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
|
||||
@@ -143,3 +172,4 @@ jobs:
|
||||
uses: re-actors/alls-green@release/v1
|
||||
with:
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
allowed-skips: coverage-combine,test
|
||||
|
||||
12
.github/workflows/topic-repos.yml
vendored
12
.github/workflows/topic-repos.yml
vendored
@@ -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 }}
|
||||
|
||||
35
.github/workflows/translate.yml
vendored
35
.github/workflows/translate.yml
vendored
@@ -30,9 +30,16 @@ 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
|
||||
max:
|
||||
description: Maximum number of items to translate (e.g. 10)
|
||||
type: number
|
||||
required: false
|
||||
default: 10
|
||||
|
||||
jobs:
|
||||
langs:
|
||||
@@ -45,20 +52,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 +91,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 +111,13 @@ 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 }}
|
||||
MAX: ${{ github.event.inputs.max }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -29,7 +29,4 @@ archive.zip
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Ignore while the setup still depends on requirements.txt files
|
||||
uv.lock
|
||||
|
||||
.codspeed
|
||||
|
||||
@@ -6,6 +6,7 @@ repos:
|
||||
hooks:
|
||||
- id: check-added-large-files
|
||||
args: ['--maxkb=750']
|
||||
exclude: ^uv.lock$
|
||||
- id: check-toml
|
||||
- id: check-yaml
|
||||
args:
|
||||
@@ -29,6 +30,13 @@ repos:
|
||||
language: unsupported
|
||||
types: [python]
|
||||
|
||||
- id: local-mypy
|
||||
name: mypy check
|
||||
entry: uv run mypy fastapi
|
||||
require_serial: true
|
||||
language: unsupported
|
||||
pass_filenames: false
|
||||
|
||||
- id: add-permalinks-pages
|
||||
language: unsupported
|
||||
name: add-permalinks-pages
|
||||
@@ -57,3 +65,9 @@ repos:
|
||||
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
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.11
|
||||
18
README.md
18
README.md
@@ -164,8 +164,6 @@ $ pip install "fastapi[standard]"
|
||||
Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -177,7 +175,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -186,9 +184,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -200,7 +196,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -291,9 +287,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -303,7 +297,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: Union[bool, None] = None
|
||||
is_offer: bool | None = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -312,7 +306,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ Siehe Abschnitt `### Links` im allgemeinen Prompt in `scripts/translate.py`.
|
||||
|
||||
////
|
||||
|
||||
## HTML „abbr“-Elemente { #html-abbr-elements }
|
||||
## HTML-„abbr“-Elemente { #html-abbr-elements }
|
||||
|
||||
//// tab | Test
|
||||
|
||||
|
||||
@@ -6,13 +6,29 @@ Dazu können Sie die `WSGIMiddleware` verwenden und damit Ihre WSGI-Anwendung wr
|
||||
|
||||
## `WSGIMiddleware` verwenden { #using-wsgimiddleware }
|
||||
|
||||
Sie müssen `WSGIMiddleware` importieren.
|
||||
/// info | Info
|
||||
|
||||
Dafür muss `a2wsgi` installiert sein, z. B. mit `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Sie müssen `WSGIMiddleware` aus `a2wsgi` importieren.
|
||||
|
||||
Wrappen Sie dann die WSGI-Anwendung (z. B. Flask) mit der Middleware.
|
||||
|
||||
Und dann mounten Sie das auf einem Pfad.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | Hinweis
|
||||
|
||||
Früher wurde empfohlen, `WSGIMiddleware` aus `fastapi.middleware.wsgi` zu verwenden, dies ist jetzt deprecatet.
|
||||
|
||||
Stattdessen wird empfohlen, das Paket `a2wsgi` zu verwenden. Die Nutzung bleibt gleich.
|
||||
|
||||
Stellen Sie lediglich sicher, dass das Paket `a2wsgi` installiert ist und importieren Sie `WSGIMiddleware` korrekt aus `a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
## Es testen { #check-it }
|
||||
|
||||
|
||||
@@ -145,8 +145,6 @@ Es gibt andere Formate und Tools zum Definieren und Installieren von Paketabhän
|
||||
* Erstellen Sie eine `main.py`-Datei mit:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -158,7 +156,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
|
||||
@@ -161,8 +161,6 @@ $ pip install "fastapi[standard]"
|
||||
Erstellen Sie eine Datei `main.py` mit:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -174,7 +172,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -183,9 +181,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
|
||||
|
||||
Wenn Ihr Code `async` / `await` verwendet, benutzen Sie `async def`:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -197,7 +193,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -288,9 +284,7 @@ Sie sehen die alternative automatische Dokumentation (bereitgestellt von <a href
|
||||
|
||||
Deklarieren Sie den Body mit Standard-Python-Typen, dank Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -300,7 +294,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: Union[bool, None] = None
|
||||
is_offer: bool | None = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -309,7 +303,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -56,19 +56,19 @@ from app.routers import items
|
||||
|
||||
Die gleiche Dateistruktur mit Kommentaren:
|
||||
|
||||
```
|
||||
```bash
|
||||
.
|
||||
├── app # „app“ ist ein Python-Package
|
||||
│ ├── __init__.py # diese Datei macht „app“ zu einem „Python-Package“
|
||||
│ ├── main.py # „main“-Modul, z. B. import app.main
|
||||
│ ├── dependencies.py # „dependencies“-Modul, z. B. import app.dependencies
|
||||
│ └── routers # „routers“ ist ein „Python-Subpackage“
|
||||
│ │ ├── __init__.py # macht „routers“ zu einem „Python-Subpackage“
|
||||
│ │ ├── items.py # „items“-Submodul, z. B. import app.routers.items
|
||||
│ │ └── users.py # „users“-Submodul, z. B. import app.routers.users
|
||||
│ └── internal # „internal“ ist ein „Python-Subpackage“
|
||||
│ ├── __init__.py # macht „internal“ zu einem „Python-Subpackage“
|
||||
│ └── admin.py # „admin“-Submodul, z. B. import app.internal.admin
|
||||
├── app # "app" ist ein Python-Package
|
||||
│ ├── __init__.py # diese Datei macht "app" zu einem "Python-Package"
|
||||
│ ├── main.py # "main"-Modul, z. B. import app.main
|
||||
│ ├── dependencies.py # "dependencies"-Modul, z. B. import app.dependencies
|
||||
│ └── routers # "routers" ist ein "Python-Subpackage"
|
||||
│ │ ├── __init__.py # macht "routers" zu einem "Python-Subpackage"
|
||||
│ │ ├── items.py # "items"-Submodul, z. B. import app.routers.items
|
||||
│ │ └── users.py # "users"-Submodul, z. B. import app.routers.users
|
||||
│ └── internal # "internal" ist ein "Python-Subpackage"
|
||||
│ ├── __init__.py # macht "internal" zu einem "Python-Subpackage"
|
||||
│ └── admin.py # "admin"-Submodul, z. B. import app.internal.admin
|
||||
```
|
||||
|
||||
## `APIRouter` { #apirouter }
|
||||
@@ -479,7 +479,7 @@ $ fastapi dev app/main.py
|
||||
|
||||
</div>
|
||||
|
||||
und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Und öffnen Sie die Dokumentation unter <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Sie sehen die automatische API-Dokumentation, einschließlich der Pfade aller Submodule, mit den richtigen Pfaden (und Präfixen) und den richtigen Tags:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Body – Mehrere Parameter { #body-multiple-parameters }
|
||||
|
||||
Nun, da wir gesehen haben, wie `Path` und `Query` verwendet werden, schauen wir uns fortgeschrittenere Verwendungsmöglichkeiten von <abbr title="Anfragekörper">Requestbody</abbr>-Deklarationen an.
|
||||
Nun, da wir gesehen haben, wie `Path` und `Query` verwendet werden, schauen wir uns fortgeschrittenere Verwendungsmöglichkeiten von <abbr title="Requestbody">Requestbody</abbr>-Deklarationen an.
|
||||
|
||||
## `Path`-, `Query`- und Body-Parameter vermischen { #mix-path-query-and-body-parameters }
|
||||
|
||||
@@ -101,13 +101,13 @@ Natürlich können Sie auch, wann immer Sie das brauchen, weitere Query-Paramete
|
||||
Da einfache Werte standardmäßig als Query-Parameter interpretiert werden, müssen Sie `Query` nicht explizit hinzufügen, Sie können einfach schreiben:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Oder in Python 3.10 und darüber:
|
||||
Oder in Python 3.9:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Zum Beispiel:
|
||||
|
||||
@@ -52,7 +52,7 @@ In diesem Fall macht es Sinn, die Tags in einem `Enum` zu speichern.
|
||||
|
||||
Sie können eine <abbr title="Zusammenfassung">`summary`</abbr> und eine <abbr title="Beschreibung">`description`</abbr> hinzufügen:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
|
||||
## Beschreibung mittels Docstring { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@ Es wird in der interaktiven Dokumentation verwendet:
|
||||
|
||||
Sie können die Response mit dem Parameter `response_description` beschreiben:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info | Info
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 857
|
||||
count: 871
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
dependabot:
|
||||
login: dependabot
|
||||
count: 130
|
||||
count: 133
|
||||
avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4
|
||||
url: https://github.com/apps/dependabot
|
||||
alejsdev:
|
||||
login: alejsdev
|
||||
count: 53
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4
|
||||
url: https://github.com/alejsdev
|
||||
pre-commit-ci:
|
||||
login: pre-commit-ci
|
||||
@@ -20,8 +20,8 @@ pre-commit-ci:
|
||||
url: https://github.com/apps/pre-commit-ci
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 36
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
|
||||
count: 38
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
github-actions:
|
||||
login: github-actions
|
||||
@@ -40,7 +40,7 @@ dmontagu:
|
||||
url: https://github.com/dmontagu
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 16
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
nilslindemann:
|
||||
@@ -126,7 +126,7 @@ hitrust:
|
||||
ShahriyarR:
|
||||
login: ShahriyarR
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3852029?u=631b2ae59360ab380c524b32bc3d245aff1165af&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3852029?u=2dc6402d9053ee53f7afc407089cbab21c68f21d&v=4
|
||||
url: https://github.com/ShahriyarR
|
||||
adriangb:
|
||||
login: adriangb
|
||||
@@ -266,7 +266,7 @@ Nimitha-jagadeesha:
|
||||
lucaromagnoli:
|
||||
login: lucaromagnoli
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=15df02e806a2293af40ac619fba11dbe3c0c4fd4&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=a09a2e916625fa035f9dfa25ebc58e07aac8ec36&v=4
|
||||
url: https://github.com/lucaromagnoli
|
||||
salmantec:
|
||||
login: salmantec
|
||||
@@ -521,7 +521,7 @@ s111d:
|
||||
estebanx64:
|
||||
login: estebanx64
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=1900887aeed268699e5ea6f3fb7db614f7b77cd3&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=812422ae5d6a4bc5ff331c901fc54f9ab3cecf5c&v=4
|
||||
url: https://github.com/estebanx64
|
||||
ndimares:
|
||||
login: ndimares
|
||||
|
||||
@@ -65,9 +65,6 @@ bronze:
|
||||
# - url: https://testdriven.io/courses/tdd-fastapi/
|
||||
# title: Learn to build high-quality web apps with best practices
|
||||
# img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg
|
||||
- url: https://lambdatest.com/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage
|
||||
title: LambdaTest, AI-Powered Cloud-based Test Orchestration Platform
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/lambdatest.png
|
||||
- url: https://requestly.com/fastapi
|
||||
title: All-in-one platform to Test, Mock and Intercept APIs. Built for speed, privacy and offline support.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/requestly.png
|
||||
- url: https://www.testmu.ai/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage
|
||||
title: TestMu AI. The Native AI-Agentic Cloud Platform to Supercharge Quality Engineering.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/testmu.png
|
||||
|
||||
@@ -1,176 +1,181 @@
|
||||
- name: full-stack-fastapi-template
|
||||
html_url: https://github.com/fastapi/full-stack-fastapi-template
|
||||
stars: 40334
|
||||
stars: 41312
|
||||
owner_login: fastapi
|
||||
owner_html_url: https://github.com/fastapi
|
||||
- name: Hello-Python
|
||||
html_url: https://github.com/mouredev/Hello-Python
|
||||
stars: 33628
|
||||
stars: 34206
|
||||
owner_login: mouredev
|
||||
owner_html_url: https://github.com/mouredev
|
||||
- name: serve
|
||||
html_url: https://github.com/jina-ai/serve
|
||||
stars: 21817
|
||||
stars: 21832
|
||||
owner_login: jina-ai
|
||||
owner_html_url: https://github.com/jina-ai
|
||||
- name: HivisionIDPhotos
|
||||
html_url: https://github.com/Zeyi-Lin/HivisionIDPhotos
|
||||
stars: 20409
|
||||
stars: 20661
|
||||
owner_login: Zeyi-Lin
|
||||
owner_html_url: https://github.com/Zeyi-Lin
|
||||
- name: sqlmodel
|
||||
html_url: https://github.com/fastapi/sqlmodel
|
||||
stars: 17415
|
||||
stars: 17567
|
||||
owner_login: fastapi
|
||||
owner_html_url: https://github.com/fastapi
|
||||
- name: fastapi-best-practices
|
||||
html_url: https://github.com/zhanymkanov/fastapi-best-practices
|
||||
stars: 15776
|
||||
stars: 16291
|
||||
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
|
||||
stars: 16132
|
||||
owner_login: Evil0ctal
|
||||
owner_html_url: https://github.com/Evil0ctal
|
||||
- name: machine-learning-zoomcamp
|
||||
html_url: https://github.com/DataTalksClub/machine-learning-zoomcamp
|
||||
stars: 12447
|
||||
owner_login: DataTalksClub
|
||||
owner_html_url: https://github.com/DataTalksClub
|
||||
- name: SurfSense
|
||||
html_url: https://github.com/MODSetter/SurfSense
|
||||
stars: 12128
|
||||
stars: 12723
|
||||
owner_login: MODSetter
|
||||
owner_html_url: https://github.com/MODSetter
|
||||
- name: machine-learning-zoomcamp
|
||||
html_url: https://github.com/DataTalksClub/machine-learning-zoomcamp
|
||||
stars: 12575
|
||||
owner_login: DataTalksClub
|
||||
owner_html_url: https://github.com/DataTalksClub
|
||||
- name: fastapi_mcp
|
||||
html_url: https://github.com/tadata-org/fastapi_mcp
|
||||
stars: 11326
|
||||
stars: 11478
|
||||
owner_login: tadata-org
|
||||
owner_html_url: https://github.com/tadata-org
|
||||
- name: awesome-fastapi
|
||||
html_url: https://github.com/mjhea0/awesome-fastapi
|
||||
stars: 10901
|
||||
stars: 11018
|
||||
owner_login: mjhea0
|
||||
owner_html_url: https://github.com/mjhea0
|
||||
- name: XHS-Downloader
|
||||
html_url: https://github.com/JoeanAmier/XHS-Downloader
|
||||
stars: 9584
|
||||
stars: 9938
|
||||
owner_login: JoeanAmier
|
||||
owner_html_url: https://github.com/JoeanAmier
|
||||
- name: polar
|
||||
html_url: https://github.com/polarsource/polar
|
||||
stars: 8951
|
||||
stars: 9348
|
||||
owner_login: polarsource
|
||||
owner_html_url: https://github.com/polarsource
|
||||
- name: FastUI
|
||||
html_url: https://github.com/pydantic/FastUI
|
||||
stars: 8934
|
||||
stars: 8949
|
||||
owner_login: pydantic
|
||||
owner_html_url: https://github.com/pydantic
|
||||
- name: FileCodeBox
|
||||
html_url: https://github.com/vastsa/FileCodeBox
|
||||
stars: 7934
|
||||
stars: 8060
|
||||
owner_login: vastsa
|
||||
owner_html_url: https://github.com/vastsa
|
||||
- name: nonebot2
|
||||
html_url: https://github.com/nonebot/nonebot2
|
||||
stars: 7248
|
||||
stars: 7311
|
||||
owner_login: nonebot
|
||||
owner_html_url: https://github.com/nonebot
|
||||
- name: hatchet
|
||||
html_url: https://github.com/hatchet-dev/hatchet
|
||||
stars: 6392
|
||||
stars: 6479
|
||||
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: 5899
|
||||
stars: 5970
|
||||
owner_login: fastapi-users
|
||||
owner_html_url: https://github.com/fastapi-users
|
||||
- name: serge
|
||||
html_url: https://github.com/serge-chat/serge
|
||||
stars: 5754
|
||||
stars: 5751
|
||||
owner_login: serge-chat
|
||||
owner_html_url: https://github.com/serge-chat
|
||||
- name: strawberry
|
||||
html_url: https://github.com/strawberry-graphql/strawberry
|
||||
stars: 4577
|
||||
stars: 4598
|
||||
owner_login: strawberry-graphql
|
||||
owner_html_url: https://github.com/strawberry-graphql
|
||||
- name: devpush
|
||||
html_url: https://github.com/hunvreus/devpush
|
||||
stars: 4407
|
||||
owner_login: hunvreus
|
||||
owner_html_url: https://github.com/hunvreus
|
||||
- name: Kokoro-FastAPI
|
||||
html_url: https://github.com/remsky/Kokoro-FastAPI
|
||||
stars: 4359
|
||||
owner_login: remsky
|
||||
owner_html_url: https://github.com/remsky
|
||||
- name: poem
|
||||
html_url: https://github.com/poem-web/poem
|
||||
stars: 4303
|
||||
stars: 4337
|
||||
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
|
||||
stars: 4279
|
||||
owner_login: chatpire
|
||||
owner_html_url: https://github.com/chatpire
|
||||
- name: dynaconf
|
||||
html_url: https://github.com/dynaconf/dynaconf
|
||||
stars: 4221
|
||||
stars: 4244
|
||||
owner_login: dynaconf
|
||||
owner_html_url: https://github.com/dynaconf
|
||||
- name: Kokoro-FastAPI
|
||||
html_url: https://github.com/remsky/Kokoro-FastAPI
|
||||
stars: 4181
|
||||
owner_login: remsky
|
||||
owner_html_url: https://github.com/remsky
|
||||
- name: Yuxi-Know
|
||||
html_url: https://github.com/xerrors/Yuxi-Know
|
||||
stars: 4154
|
||||
owner_login: xerrors
|
||||
owner_html_url: https://github.com/xerrors
|
||||
- name: atrilabs-engine
|
||||
html_url: https://github.com/Atri-Labs/atrilabs-engine
|
||||
stars: 4090
|
||||
stars: 4086
|
||||
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: 3896
|
||||
stars: 3975
|
||||
owner_login: pydantic
|
||||
owner_html_url: https://github.com/pydantic
|
||||
- name: LitServe
|
||||
html_url: https://github.com/Lightning-AI/LitServe
|
||||
stars: 3756
|
||||
stars: 3797
|
||||
owner_login: Lightning-AI
|
||||
owner_html_url: https://github.com/Lightning-AI
|
||||
- name: huma
|
||||
html_url: https://github.com/danielgtaylor/huma
|
||||
stars: 3702
|
||||
stars: 3785
|
||||
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
|
||||
stars: 3731
|
||||
owner_login: koxudaxi
|
||||
owner_html_url: https://github.com/koxudaxi
|
||||
- name: fastapi-admin
|
||||
html_url: https://github.com/fastapi-admin/fastapi-admin
|
||||
stars: 3659
|
||||
stars: 3697
|
||||
owner_login: fastapi-admin
|
||||
owner_html_url: https://github.com/fastapi-admin
|
||||
- name: farfalle
|
||||
html_url: https://github.com/rashadphz/farfalle
|
||||
stars: 3497
|
||||
stars: 3506
|
||||
owner_login: rashadphz
|
||||
owner_html_url: https://github.com/rashadphz
|
||||
- name: tracecat
|
||||
html_url: https://github.com/TracecatHQ/tracecat
|
||||
stars: 3421
|
||||
stars: 3458
|
||||
owner_login: TracecatHQ
|
||||
owner_html_url: https://github.com/TracecatHQ
|
||||
- name: mcp-context-forge
|
||||
html_url: https://github.com/IBM/mcp-context-forge
|
||||
stars: 3216
|
||||
owner_login: IBM
|
||||
owner_html_url: https://github.com/IBM
|
||||
- name: opyrator
|
||||
html_url: https://github.com/ml-tooling/opyrator
|
||||
stars: 3136
|
||||
stars: 3134
|
||||
owner_login: ml-tooling
|
||||
owner_html_url: https://github.com/ml-tooling
|
||||
- name: docarray
|
||||
@@ -180,316 +185,311 @@
|
||||
owner_html_url: https://github.com/docarray
|
||||
- name: fastapi-realworld-example-app
|
||||
html_url: https://github.com/nsidnev/fastapi-realworld-example-app
|
||||
stars: 3051
|
||||
stars: 3072
|
||||
owner_login: nsidnev
|
||||
owner_html_url: https://github.com/nsidnev
|
||||
- name: mcp-context-forge
|
||||
html_url: https://github.com/IBM/mcp-context-forge
|
||||
stars: 3034
|
||||
owner_login: IBM
|
||||
owner_html_url: https://github.com/IBM
|
||||
- name: uvicorn-gunicorn-fastapi-docker
|
||||
html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker
|
||||
stars: 2904
|
||||
stars: 2908
|
||||
owner_login: tiangolo
|
||||
owner_html_url: https://github.com/tiangolo
|
||||
- name: FastAPI-template
|
||||
html_url: https://github.com/s3rius/FastAPI-template
|
||||
stars: 2680
|
||||
stars: 2728
|
||||
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
|
||||
stars: 2686
|
||||
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: 2614
|
||||
stars: 2648
|
||||
owner_login: sahibzada-allahyar
|
||||
owner_html_url: https://github.com/sahibzada-allahyar
|
||||
- name: sqladmin
|
||||
html_url: https://github.com/aminalaee/sqladmin
|
||||
stars: 2587
|
||||
stars: 2637
|
||||
owner_login: aminalaee
|
||||
owner_html_url: https://github.com/aminalaee
|
||||
- name: fastapi-react
|
||||
html_url: https://github.com/Buuntu/fastapi-react
|
||||
stars: 2566
|
||||
stars: 2573
|
||||
owner_login: Buuntu
|
||||
owner_html_url: https://github.com/Buuntu
|
||||
- name: RasaGPT
|
||||
html_url: https://github.com/paulpierre/RasaGPT
|
||||
stars: 2456
|
||||
stars: 2460
|
||||
owner_login: paulpierre
|
||||
owner_html_url: https://github.com/paulpierre
|
||||
- name: supabase-py
|
||||
html_url: https://github.com/supabase/supabase-py
|
||||
stars: 2394
|
||||
stars: 2428
|
||||
owner_login: supabase
|
||||
owner_html_url: https://github.com/supabase
|
||||
- name: 30-Days-of-Python
|
||||
html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python
|
||||
stars: 2347
|
||||
owner_login: codingforentrepreneurs
|
||||
owner_html_url: https://github.com/codingforentrepreneurs
|
||||
- name: nextpy
|
||||
html_url: https://github.com/dot-agent/nextpy
|
||||
stars: 2338
|
||||
stars: 2337
|
||||
owner_login: dot-agent
|
||||
owner_html_url: https://github.com/dot-agent
|
||||
- name: fastapi-utils
|
||||
html_url: https://github.com/fastapiutils/fastapi-utils
|
||||
stars: 2289
|
||||
stars: 2299
|
||||
owner_login: fastapiutils
|
||||
owner_html_url: https://github.com/fastapiutils
|
||||
- name: langserve
|
||||
html_url: https://github.com/langchain-ai/langserve
|
||||
stars: 2234
|
||||
stars: 2255
|
||||
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: NoteDiscovery
|
||||
html_url: https://github.com/gamosoft/NoteDiscovery
|
||||
stars: 2182
|
||||
owner_login: gamosoft
|
||||
owner_html_url: https://github.com/gamosoft
|
||||
- name: solara
|
||||
html_url: https://github.com/widgetti/solara
|
||||
stars: 2141
|
||||
stars: 2154
|
||||
owner_login: widgetti
|
||||
owner_html_url: https://github.com/widgetti
|
||||
- name: mangum
|
||||
html_url: https://github.com/Kludex/mangum
|
||||
stars: 2046
|
||||
stars: 2071
|
||||
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
|
||||
stars: 2036
|
||||
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: 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
|
||||
stars: 1983
|
||||
owner_login: mizhexiaoxiao
|
||||
owner_html_url: https://github.com/mizhexiaoxiao
|
||||
- name: manage-fastapi
|
||||
html_url: https://github.com/ycd/manage-fastapi
|
||||
stars: 1887
|
||||
owner_login: ycd
|
||||
owner_html_url: https://github.com/ycd
|
||||
- name: agentkit
|
||||
html_url: https://github.com/BCG-X-Official/agentkit
|
||||
stars: 1941
|
||||
owner_login: BCG-X-Official
|
||||
owner_html_url: https://github.com/BCG-X-Official
|
||||
- name: fastapi-langgraph-agent-production-ready-template
|
||||
html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template
|
||||
stars: 1920
|
||||
owner_login: wassim249
|
||||
owner_html_url: https://github.com/wassim249
|
||||
- name: openapi-python-client
|
||||
html_url: https://github.com/openapi-generators/openapi-python-client
|
||||
stars: 1879
|
||||
stars: 1900
|
||||
owner_login: openapi-generators
|
||||
owner_html_url: https://github.com/openapi-generators
|
||||
- name: manage-fastapi
|
||||
html_url: https://github.com/ycd/manage-fastapi
|
||||
stars: 1894
|
||||
owner_login: ycd
|
||||
owner_html_url: https://github.com/ycd
|
||||
- name: slowapi
|
||||
html_url: https://github.com/laurentS/slowapi
|
||||
stars: 1845
|
||||
stars: 1891
|
||||
owner_login: laurentS
|
||||
owner_html_url: https://github.com/laurentS
|
||||
- name: piccolo
|
||||
html_url: https://github.com/piccolo-orm/piccolo
|
||||
stars: 1843
|
||||
stars: 1854
|
||||
owner_login: piccolo-orm
|
||||
owner_html_url: https://github.com/piccolo-orm
|
||||
- name: fastapi-cache
|
||||
html_url: https://github.com/long2ice/fastapi-cache
|
||||
stars: 1816
|
||||
owner_login: long2ice
|
||||
owner_html_url: https://github.com/long2ice
|
||||
- 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: 1805
|
||||
owner_login: long2ice
|
||||
owner_html_url: https://github.com/long2ice
|
||||
- name: ormar
|
||||
html_url: https://github.com/collerek/ormar
|
||||
stars: 1785
|
||||
stars: 1797
|
||||
owner_login: collerek
|
||||
owner_html_url: https://github.com/collerek
|
||||
- name: fastapi-langgraph-agent-production-ready-template
|
||||
html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template
|
||||
stars: 1780
|
||||
owner_login: wassim249
|
||||
owner_html_url: https://github.com/wassim249
|
||||
- name: FastAPI-boilerplate
|
||||
html_url: https://github.com/benavlabs/FastAPI-boilerplate
|
||||
stars: 1734
|
||||
stars: 1792
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: termpair
|
||||
html_url: https://github.com/cs01/termpair
|
||||
stars: 1724
|
||||
stars: 1727
|
||||
owner_login: cs01
|
||||
owner_html_url: https://github.com/cs01
|
||||
- name: fastapi-crudrouter
|
||||
html_url: https://github.com/awtkns/fastapi-crudrouter
|
||||
stars: 1671
|
||||
stars: 1677
|
||||
owner_login: awtkns
|
||||
owner_html_url: https://github.com/awtkns
|
||||
- name: langchain-serve
|
||||
html_url: https://github.com/jina-ai/langchain-serve
|
||||
stars: 1633
|
||||
stars: 1634
|
||||
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
|
||||
stars: 1607
|
||||
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
|
||||
stars: 1592
|
||||
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: 1549
|
||||
stars: 1580
|
||||
owner_login: evroon
|
||||
owner_html_url: https://github.com/evroon
|
||||
- name: coronavirus-tracker-api
|
||||
html_url: https://github.com/ExpDev07/coronavirus-tracker-api
|
||||
stars: 1570
|
||||
owner_login: ExpDev07
|
||||
owner_html_url: https://github.com/ExpDev07
|
||||
- name: fastapi-amis-admin
|
||||
html_url: https://github.com/amisadmin/fastapi-amis-admin
|
||||
stars: 1491
|
||||
stars: 1512
|
||||
owner_login: amisadmin
|
||||
owner_html_url: https://github.com/amisadmin
|
||||
- name: fastapi-boilerplate
|
||||
html_url: https://github.com/teamhide/fastapi-boilerplate
|
||||
stars: 1452
|
||||
owner_login: teamhide
|
||||
owner_html_url: https://github.com/teamhide
|
||||
- name: fastcrud
|
||||
html_url: https://github.com/benavlabs/fastcrud
|
||||
stars: 1452
|
||||
stars: 1471
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: fastapi-boilerplate
|
||||
html_url: https://github.com/teamhide/fastapi-boilerplate
|
||||
stars: 1461
|
||||
owner_login: teamhide
|
||||
owner_html_url: https://github.com/teamhide
|
||||
- name: awesome-python-resources
|
||||
html_url: https://github.com/DjangoEx/awesome-python-resources
|
||||
stars: 1430
|
||||
stars: 1435
|
||||
owner_login: DjangoEx
|
||||
owner_html_url: https://github.com/DjangoEx
|
||||
- name: prometheus-fastapi-instrumentator
|
||||
html_url: https://github.com/trallnag/prometheus-fastapi-instrumentator
|
||||
stars: 1399
|
||||
stars: 1417
|
||||
owner_login: trallnag
|
||||
owner_html_url: https://github.com/trallnag
|
||||
- name: fastapi-code-generator
|
||||
html_url: https://github.com/koxudaxi/fastapi-code-generator
|
||||
stars: 1371
|
||||
stars: 1382
|
||||
owner_login: koxudaxi
|
||||
owner_html_url: https://github.com/koxudaxi
|
||||
- name: fastapi-scaff
|
||||
html_url: https://github.com/atpuxiner/fastapi-scaff
|
||||
stars: 1367
|
||||
owner_login: atpuxiner
|
||||
owner_html_url: https://github.com/atpuxiner
|
||||
- name: fastapi-tutorial
|
||||
html_url: https://github.com/liaogx/fastapi-tutorial
|
||||
stars: 1346
|
||||
stars: 1360
|
||||
owner_login: liaogx
|
||||
owner_html_url: https://github.com/liaogx
|
||||
- name: budgetml
|
||||
html_url: https://github.com/ebhy/budgetml
|
||||
stars: 1345
|
||||
stars: 1343
|
||||
owner_login: ebhy
|
||||
owner_html_url: https://github.com/ebhy
|
||||
- name: fastapi-scaff
|
||||
html_url: https://github.com/atpuxiner/fastapi-scaff
|
||||
stars: 1331
|
||||
owner_login: atpuxiner
|
||||
owner_html_url: https://github.com/atpuxiner
|
||||
- name: bolt-python
|
||||
html_url: https://github.com/slackapi/bolt-python
|
||||
stars: 1266
|
||||
stars: 1276
|
||||
owner_login: slackapi
|
||||
owner_html_url: https://github.com/slackapi
|
||||
- name: bedrock-chat
|
||||
html_url: https://github.com/aws-samples/bedrock-chat
|
||||
stars: 1266
|
||||
stars: 1268
|
||||
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
|
||||
html_url: https://github.com/vargasjona/fastapi-alembic-sqlmodel-async
|
||||
stars: 1265
|
||||
owner_login: vargasjona
|
||||
owner_html_url: https://github.com/vargasjona
|
||||
- name: fastapi_production_template
|
||||
html_url: https://github.com/zhanymkanov/fastapi_production_template
|
||||
stars: 1222
|
||||
stars: 1227
|
||||
owner_login: zhanymkanov
|
||||
owner_html_url: https://github.com/zhanymkanov
|
||||
- name: langchain-extract
|
||||
html_url: https://github.com/langchain-ai/langchain-extract
|
||||
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: 1152
|
||||
stars: 1200
|
||||
owner_login: rest-sh
|
||||
owner_html_url: https://github.com/rest-sh
|
||||
- name: langchain-extract
|
||||
html_url: https://github.com/langchain-ai/langchain-extract
|
||||
stars: 1183
|
||||
owner_login: langchain-ai
|
||||
owner_html_url: https://github.com/langchain-ai
|
||||
- name: odmantic
|
||||
html_url: https://github.com/art049/odmantic
|
||||
stars: 1143
|
||||
stars: 1162
|
||||
owner_login: art049
|
||||
owner_html_url: https://github.com/art049
|
||||
- name: authx
|
||||
html_url: https://github.com/yezz123/authx
|
||||
stars: 1128
|
||||
owner_login: yezz123
|
||||
owner_html_url: https://github.com/yezz123
|
||||
- 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: 1072
|
||||
stars: 1155
|
||||
owner_login: akfamily
|
||||
owner_html_url: https://github.com/akfamily
|
||||
- name: RuoYi-Vue3-FastAPI
|
||||
html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI
|
||||
stars: 1063
|
||||
stars: 1155
|
||||
owner_login: insistence
|
||||
owner_html_url: https://github.com/insistence
|
||||
- name: authx
|
||||
html_url: https://github.com/yezz123/authx
|
||||
stars: 1142
|
||||
owner_login: yezz123
|
||||
owner_html_url: https://github.com/yezz123
|
||||
- name: SAG
|
||||
html_url: https://github.com/Zleap-AI/SAG
|
||||
stars: 1110
|
||||
owner_login: Zleap-AI
|
||||
owner_html_url: https://github.com/Zleap-AI
|
||||
- name: flock
|
||||
html_url: https://github.com/Onelevenvy/flock
|
||||
stars: 1059
|
||||
stars: 1069
|
||||
owner_login: Onelevenvy
|
||||
owner_html_url: https://github.com/Onelevenvy
|
||||
- name: fastapi-observability
|
||||
html_url: https://github.com/blueswen/fastapi-observability
|
||||
stars: 1046
|
||||
stars: 1063
|
||||
owner_login: blueswen
|
||||
owner_html_url: https://github.com/blueswen
|
||||
- name: enterprise-deep-research
|
||||
html_url: https://github.com/SalesforceAIResearch/enterprise-deep-research
|
||||
stars: 1019
|
||||
stars: 1061
|
||||
owner_login: SalesforceAIResearch
|
||||
owner_html_url: https://github.com/SalesforceAIResearch
|
||||
- name: titiler
|
||||
html_url: https://github.com/developmentseed/titiler
|
||||
stars: 1016
|
||||
stars: 1039
|
||||
owner_login: developmentseed
|
||||
owner_html_url: https://github.com/developmentseed
|
||||
- name: every-pdf
|
||||
html_url: https://github.com/DDULDDUCK/every-pdf
|
||||
stars: 1004
|
||||
stars: 1017
|
||||
owner_login: DDULDDUCK
|
||||
owner_html_url: https://github.com/DDULDDUCK
|
||||
- name: autollm
|
||||
html_url: https://github.com/viddexa/autollm
|
||||
stars: 1003
|
||||
stars: 1005
|
||||
owner_login: viddexa
|
||||
owner_html_url: https://github.com/viddexa
|
||||
- name: lanarky
|
||||
html_url: https://github.com/ajndkr/lanarky
|
||||
stars: 996
|
||||
stars: 995
|
||||
owner_login: ajndkr
|
||||
owner_html_url: https://github.com/ajndkr
|
||||
|
||||
@@ -10,12 +10,12 @@ Xewus:
|
||||
url: https://github.com/Xewus
|
||||
sodaMelon:
|
||||
login: sodaMelon
|
||||
count: 127
|
||||
count: 128
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66295123?u=be939db90f1119efee9e6110cc05066ff1f40f00&v=4
|
||||
url: https://github.com/sodaMelon
|
||||
ceb10n:
|
||||
login: ceb10n
|
||||
count: 117
|
||||
count: 119
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
|
||||
url: https://github.com/ceb10n
|
||||
tokusumi:
|
||||
@@ -25,7 +25,7 @@ tokusumi:
|
||||
url: https://github.com/tokusumi
|
||||
hard-coders:
|
||||
login: hard-coders
|
||||
count: 96
|
||||
count: 102
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
hasansezertasan:
|
||||
@@ -50,7 +50,7 @@ AlertRED:
|
||||
url: https://github.com/AlertRED
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 73
|
||||
count: 78
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
Alexandrhub:
|
||||
@@ -58,26 +58,31 @@ Alexandrhub:
|
||||
count: 68
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4
|
||||
url: https://github.com/Alexandrhub
|
||||
cassiobotaro:
|
||||
login: cassiobotaro
|
||||
count: 64
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=a08022b191ddbd0a6159b2981d9d878b6d5bb71f&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
waynerv:
|
||||
login: waynerv
|
||||
count: 63
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
cassiobotaro:
|
||||
login: cassiobotaro
|
||||
count: 62
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=a08022b191ddbd0a6159b2981d9d878b6d5bb71f&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
nilslindemann:
|
||||
login: nilslindemann
|
||||
count: 61
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
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
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 56
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
Laineyzhang55:
|
||||
login: Laineyzhang55
|
||||
count: 48
|
||||
@@ -88,26 +93,21 @@ 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
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
|
||||
url: https://github.com/komtaki
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 43
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
rostik1410:
|
||||
login: rostik1410
|
||||
count: 42
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11443899?u=e26a635c2ba220467b308a326a579b8ccf4a8701&v=4
|
||||
url: https://github.com/rostik1410
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 42
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
alperiox:
|
||||
login: alperiox
|
||||
count: 42
|
||||
@@ -136,7 +136,7 @@ JavierSanchezCastro:
|
||||
alejsdev:
|
||||
login: alejsdev
|
||||
count: 37
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4
|
||||
url: https://github.com/alejsdev
|
||||
mezgoodle:
|
||||
login: mezgoodle
|
||||
@@ -383,6 +383,11 @@ Joao-Pedro-P-Holanda:
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/110267046?u=331bd016326dac4cf3df4848f6db2dbbf8b5f978&v=4
|
||||
url: https://github.com/Joao-Pedro-P-Holanda
|
||||
maru0123-2004:
|
||||
login: maru0123-2004
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4
|
||||
url: https://github.com/maru0123-2004
|
||||
JaeHyuckSa:
|
||||
login: JaeHyuckSa
|
||||
count: 16
|
||||
@@ -418,11 +423,6 @@ 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
|
||||
@@ -458,6 +458,11 @@ wesinalves:
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13563128?u=9eb17ed50645dd684bfec47e75dba4e9772ec9c1&v=4
|
||||
url: https://github.com/wesinalves
|
||||
andersonrocha0:
|
||||
login: andersonrocha0
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22346169?u=93a1359c8c5461d894802c0cc65bcd09217e7a02&v=4
|
||||
url: https://github.com/andersonrocha0
|
||||
NastasiaSaby:
|
||||
login: NastasiaSaby
|
||||
count: 12
|
||||
@@ -471,7 +476,7 @@ oandersonmagalhaes:
|
||||
mkdir700:
|
||||
login: mkdir700
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/56359329?u=3d6ea8714f5000829b60dcf7b13a75b1e73aaf47&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/56359329?u=818e5f4b4dcc1a6ffb3e5aaa08fd827e5a726dfd&v=4
|
||||
url: https://github.com/mkdir700
|
||||
batlopes:
|
||||
login: batlopes
|
||||
@@ -493,11 +498,6 @@ KaniKim:
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/19832624?u=296dbdd490e0eb96e3d45a2608c065603b17dc31&v=4
|
||||
url: https://github.com/KaniKim
|
||||
andersonrocha0:
|
||||
login: andersonrocha0
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22346169?u=93a1359c8c5461d894802c0cc65bcd09217e7a02&v=4
|
||||
url: https://github.com/andersonrocha0
|
||||
gitgernit:
|
||||
login: gitgernit
|
||||
count: 12
|
||||
@@ -558,6 +558,11 @@ Zhongheng-Cheng:
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4
|
||||
url: https://github.com/Zhongheng-Cheng
|
||||
Pyth3rEx:
|
||||
login: Pyth3rEx
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26427764?u=087724f74d813c95925d51e354554bd4b6d6bb60&v=4
|
||||
url: https://github.com/Pyth3rEx
|
||||
mariacamilagl:
|
||||
login: mariacamilagl
|
||||
count: 10
|
||||
@@ -611,7 +616,7 @@ socket-socket:
|
||||
nick-cjyx9:
|
||||
login: nick-cjyx9
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/119087246?u=7227a2de948c68fb8396d5beff1ee5b0e057c42e&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/119087246?u=3d51dcbd79222ecb6538642f31dc7c8bb708d191&v=4
|
||||
url: https://github.com/nick-cjyx9
|
||||
marcelomarkus:
|
||||
login: marcelomarkus
|
||||
@@ -683,11 +688,6 @@ 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
|
||||
@@ -736,7 +736,7 @@ minaton-ru:
|
||||
sungchan1:
|
||||
login: sungchan1
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28076127?u=a816d86ef3e60450a7225f128caf9a394c9320f9&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28076127?u=fadbf24840186aca639d344bb3e0ecf7ff3441cf&v=4
|
||||
url: https://github.com/sungchan1
|
||||
Serrones:
|
||||
login: Serrones
|
||||
@@ -761,7 +761,7 @@ anthonycepeda:
|
||||
fabioueno:
|
||||
login: fabioueno
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/14273852?u=edd700982b16317ac6ebfd24c47bc0029b21d360&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/14273852?u=a3d546449cdc96621c32bcc26cf74be6e4390209&v=4
|
||||
url: https://github.com/fabioueno
|
||||
cfraboulet:
|
||||
login: cfraboulet
|
||||
@@ -793,6 +793,11 @@ Zerohertz:
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42334717?u=5ebf4d33e73b1ad373154f6cdee44f7cab4d05ba&v=4
|
||||
url: https://github.com/Zerohertz
|
||||
EdmilsonRodrigues:
|
||||
login: EdmilsonRodrigues
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62777025?u=217d6f3cd6cc750bb8818a3af7726c8d74eb7c2d&v=4
|
||||
url: https://github.com/EdmilsonRodrigues
|
||||
deniscapeto:
|
||||
login: deniscapeto
|
||||
count: 6
|
||||
@@ -1028,11 +1033,6 @@ 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
|
||||
@@ -1178,6 +1178,11 @@ SBillion:
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1070649?u=3ab493dfc88b39da0eb1600e3b8e7df1c90a5dee&v=4
|
||||
url: https://github.com/SBillion
|
||||
seuthootDev:
|
||||
login: seuthootDev
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/175179350?u=7c2cbc48ab43b52e0c86592111d92e013d72ea4d&v=4
|
||||
url: https://github.com/seuthootDev
|
||||
tyronedamasceno:
|
||||
login: tyronedamasceno
|
||||
count: 3
|
||||
@@ -1266,7 +1271,7 @@ rafsaf:
|
||||
frnsimoes:
|
||||
login: frnsimoes
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66239468?u=fd8d408946633acc4bea057c207e6c0833871527&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66239468?u=cba345870d8d6b25dd6d56ee18f7120581e3c573&v=4
|
||||
url: https://github.com/frnsimoes
|
||||
lieryan:
|
||||
login: lieryan
|
||||
@@ -1593,6 +1598,11 @@ ayr-ton:
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1090517?u=5cf70a0e0f0dbf084e074e494aa94d7c91a46ba6&v=4
|
||||
url: https://github.com/ayr-ton
|
||||
Kadermiyanyedi:
|
||||
login: Kadermiyanyedi
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48386782?u=e34f31bf50a8ed8d37fbfa4f301b0c190b1b4b86&v=4
|
||||
url: https://github.com/Kadermiyanyedi
|
||||
raphaelauv:
|
||||
login: raphaelauv
|
||||
count: 2
|
||||
@@ -1831,7 +1841,7 @@ EgorOnishchuk:
|
||||
iamantonreznik:
|
||||
login: iamantonreznik
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/112612414?u=bf6de9a1ab17326fe14de0709719fff3826526d0&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/112612414?u=b9ba8d9b4d3940198bc3a4353dfce70c044a39b1&v=4
|
||||
url: https://github.com/iamantonreznik
|
||||
Azazul123:
|
||||
login: Azazul123
|
||||
@@ -1851,7 +1861,7 @@ NavesSapnis:
|
||||
isgin01:
|
||||
login: isgin01
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=ddffde10876b50f35dc90d1337f507a630530a6a&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=16d6466476cf7dbc55a4cd575b6ea920ebdd81e1&v=4
|
||||
url: https://github.com/isgin01
|
||||
syedasamina56:
|
||||
login: syedasamina56
|
||||
|
||||
@@ -8,9 +8,14 @@ jaystone776:
|
||||
count: 46
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4
|
||||
url: https://github.com/jaystone776
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 31
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
ceb10n:
|
||||
login: ceb10n
|
||||
count: 29
|
||||
count: 30
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
|
||||
url: https://github.com/ceb10n
|
||||
valentinDruzhinin:
|
||||
@@ -28,11 +33,6 @@ 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
|
||||
@@ -43,16 +43,16 @@ waynerv:
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4
|
||||
url: https://github.com/waynerv
|
||||
hard-coders:
|
||||
login: hard-coders
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4
|
||||
url: https://github.com/hard-coders
|
||||
AlertRED:
|
||||
login: AlertRED
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/15695000?u=f5a4944c6df443030409c88da7d7fa0b7ead985c&v=4
|
||||
url: https://github.com/AlertRED
|
||||
hard-coders:
|
||||
login: hard-coders
|
||||
count: 15
|
||||
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
|
||||
count: 14
|
||||
@@ -108,6 +108,11 @@ pablocm83:
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28315068?u=3310fbb05bb8bfc50d2c48b6cb64ac9ee4a14549&v=4
|
||||
url: https://github.com/pablocm83
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
ptt3199:
|
||||
login: ptt3199
|
||||
count: 7
|
||||
@@ -133,11 +138,6 @@ 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
|
||||
@@ -291,7 +291,7 @@ hsuanchi:
|
||||
alejsdev:
|
||||
login: alejsdev
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=85ceac49fb87138aebe8d663912e359447329090&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4
|
||||
url: https://github.com/alejsdev
|
||||
riroan:
|
||||
login: riroan
|
||||
@@ -361,7 +361,7 @@ Rishat-F:
|
||||
ruzia:
|
||||
login: ruzia
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24503?v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24503?u=abce66d26c9611818720f11e6ae6773a6e0928f8&v=4
|
||||
url: https://github.com/ruzia
|
||||
izaguerreiro:
|
||||
login: izaguerreiro
|
||||
@@ -413,6 +413,11 @@ ayr-ton:
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1090517?u=5cf70a0e0f0dbf084e074e494aa94d7c91a46ba6&v=4
|
||||
url: https://github.com/ayr-ton
|
||||
Kadermiyanyedi:
|
||||
login: Kadermiyanyedi
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48386782?u=e34f31bf50a8ed8d37fbfa4f301b0c190b1b4b86&v=4
|
||||
url: https://github.com/Kadermiyanyedi
|
||||
KdHyeon0661:
|
||||
login: KdHyeon0661
|
||||
count: 2
|
||||
@@ -461,7 +466,7 @@ ArtemKhymenko:
|
||||
hasnatsajid:
|
||||
login: hasnatsajid
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/86589885?u=6668823c3b029bfecf10a8918ed3af1aafb8b15e&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/86589885?v=4
|
||||
url: https://github.com/hasnatsajid
|
||||
alperiox:
|
||||
login: alperiox
|
||||
|
||||
@@ -120,7 +120,7 @@ The exit code, the automatic closing of the `Session` in:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}
|
||||
|
||||
...would be run after the the response finishes sending the slow data:
|
||||
...would be run after the response finishes sending the slow data:
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}
|
||||
|
||||
|
||||
@@ -6,13 +6,29 @@ For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI applicat
|
||||
|
||||
## Using `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
You need to import `WSGIMiddleware`.
|
||||
/// info
|
||||
|
||||
This requires installing `a2wsgi` for example with `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
You need to import `WSGIMiddleware` from `a2wsgi`.
|
||||
|
||||
Then wrap the WSGI (e.g. Flask) app with the middleware.
|
||||
|
||||
And then mount that under a path.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note
|
||||
|
||||
Previously, it was recommended to use `WSGIMiddleware` from `fastapi.middleware.wsgi`, but it is now deprecated.
|
||||
|
||||
It’s advised to use the `a2wsgi` package instead. The usage remains the same.
|
||||
|
||||
Just ensure that you have the `a2wsgi` package installed and import `WSGIMiddleware` correctly from `a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
## Check it { #check-it }
|
||||
|
||||
|
||||
@@ -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 --extra all
|
||||
|
||||
---> 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 --extra all` 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 --extra all` will install the local version of FastAPI in "editable" mode by default.
|
||||
|
||||
///
|
||||
|
||||
@@ -201,252 +177,85 @@ 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, we’ve 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, we’re 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.
|
||||
|
||||
What’s changing now:
|
||||
|
||||
* 🚫 We’re 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.
|
||||
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.
|
||||
|
||||
#### Tips and guidelines
|
||||
#### LLM Prompt per Language
|
||||
|
||||
* 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>.
|
||||
Each language has a directory: <a href="https://github.com/fastapi/fastapi/tree/master/docs" class="external-link" target="_blank">https://github.com/fastapi/fastapi/tree/master/docs</a>, in it you can see a file `llm-prompt.md` with the prompt specific for that language.
|
||||
|
||||
* 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.
|
||||
For example, for Spanish, the prompt 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>.
|
||||
|
||||
If you see mistakes in your language, you can make suggestions to the prompt in that file for your language, and request the specific pages you would like to re-generate after the changes.
|
||||
|
||||
#### Reviewing Translation PRs
|
||||
|
||||
You can also 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>.
|
||||
|
||||
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.
|
||||
|
||||
///
|
||||
|
||||
* 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.
|
||||
#### Subscribe to Notifications for Your Language
|
||||
|
||||
* If you translate pages, add a single pull request per page translated. That will make it much easier for others to review it.
|
||||
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.
|
||||
|
||||
* 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.
|
||||
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>.
|
||||
|
||||
#### 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.
|
||||
|
||||
@@ -145,8 +145,6 @@ There are other formats and tools to define and install package dependencies.
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -158,7 +156,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
|
||||
@@ -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] %}
|
||||
|
||||
BIN
docs/en/docs/img/sponsors/testmu.png
Normal file
BIN
docs/en/docs/img/sponsors/testmu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
@@ -161,8 +161,6 @@ $ pip install "fastapi[standard]"
|
||||
Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -174,7 +172,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -183,9 +181,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -197,7 +193,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -288,9 +284,7 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -300,7 +294,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: Union[bool, None] = None
|
||||
is_offer: bool | None = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -309,7 +303,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -35,11 +35,3 @@ It can be imported from `fastapi`:
|
||||
```python
|
||||
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
||||
```
|
||||
|
||||
::: fastapi.middleware.wsgi.WSGIMiddleware
|
||||
|
||||
It can be imported from `fastapi`:
|
||||
|
||||
```python
|
||||
from fastapi.middleware.wsgi import WSGIMiddleware
|
||||
```
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
You can declare a parameter in a *path operation function* or dependency to be of type `Request` and then you can access the raw request object directly, without any validation, etc.
|
||||
|
||||
Read more about it in the [FastAPI docs about using Request directly](https://fastapi.tiangolo.com/advanced/using-request-directly/)
|
||||
|
||||
You can import it directly from `fastapi`:
|
||||
|
||||
```python
|
||||
|
||||
@@ -4,6 +4,8 @@ You can declare a parameter in a *path operation function* or dependency to be o
|
||||
|
||||
You can also use it directly to create an instance of it and return it from your *path operations*.
|
||||
|
||||
Read more about it in the [FastAPI docs about returning a custom Response](https://fastapi.tiangolo.com/advanced/response-directly/#returning-a-custom-response)
|
||||
|
||||
You can import it directly from `fastapi`:
|
||||
|
||||
```python
|
||||
|
||||
@@ -56,6 +56,8 @@ There are a couple of custom FastAPI response classes, you can use them to optim
|
||||
|
||||
## Starlette Responses
|
||||
|
||||
You can read more about all of them in the [FastAPI docs for Custom Response](https://fastapi.tiangolo.com/advanced/custom-response/) and in the [Starlette docs about Responses](https://starlette.dev/responses/).
|
||||
|
||||
::: fastapi.responses.FileResponse
|
||||
options:
|
||||
members:
|
||||
|
||||
@@ -28,6 +28,8 @@ from fastapi.security import (
|
||||
)
|
||||
```
|
||||
|
||||
Read more about them in the [FastAPI docs about Security](https://fastapi.tiangolo.com/tutorial/security/).
|
||||
|
||||
## API Key Security Schemes
|
||||
|
||||
::: fastapi.security.APIKeyCookie
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
When defining WebSockets, you normally declare a parameter of type `WebSocket` and with it you can read data from the client and send data to it.
|
||||
|
||||
Read more about it in the [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/)
|
||||
|
||||
It is provided directly by Starlette, but you can import it from `fastapi`:
|
||||
|
||||
```python
|
||||
@@ -44,16 +46,6 @@ When you want to define dependencies that should be compatible with both HTTP an
|
||||
- send_json
|
||||
- close
|
||||
|
||||
When a client disconnects, a `WebSocketDisconnect` exception is raised, you can catch it.
|
||||
|
||||
You can import it directly form `fastapi`:
|
||||
|
||||
```python
|
||||
from fastapi import WebSocketDisconnect
|
||||
```
|
||||
|
||||
::: fastapi.WebSocketDisconnect
|
||||
|
||||
## WebSockets - additional classes
|
||||
|
||||
Additional classes for handling WebSockets.
|
||||
@@ -66,4 +58,16 @@ from fastapi.websockets import WebSocketDisconnect, WebSocketState
|
||||
|
||||
::: fastapi.websockets.WebSocketDisconnect
|
||||
|
||||
When a client disconnects, a `WebSocketDisconnect` exception is raised, you can catch it.
|
||||
|
||||
You can import it directly form `fastapi`:
|
||||
|
||||
```python
|
||||
from fastapi import WebSocketDisconnect
|
||||
```
|
||||
|
||||
Read more about it in the [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/#handling-disconnections-and-multiple-clients)
|
||||
|
||||
::: fastapi.websockets.WebSocketState
|
||||
|
||||
`WebSocketState` is an enumeration of the possible states of a WebSocket connection.
|
||||
|
||||
@@ -7,14 +7,133 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.128.2
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add support for PEP695 `TypeAliasType`. PR [#13920](https://github.com/fastapi/fastapi/pull/13920) by [@cstruct](https://github.com/cstruct).
|
||||
* ✨ Allow `Response` type hint as dependency annotation. PR [#14794](https://github.com/fastapi/fastapi/pull/14794) by [@jonathan-fulton](https://github.com/jonathan-fulton).
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Fix using `Json[list[str]]` type (issue #10997). PR [#14616](https://github.com/fastapi/fastapi/pull/14616) by [@mkanetsuna](https://github.com/mkanetsuna).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs for translations. PR [#14830](https://github.com/fastapi/fastapi/pull/14830) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Fix duplicate word in `advanced-dependencies.md`. PR [#14815](https://github.com/fastapi/fastapi/pull/14815) by [@Rayyan-Oumlil](https://github.com/Rayyan-Oumlil).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Enable Traditional Chinese translations. PR [#14842](https://github.com/fastapi/fastapi/pull/14842) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Enable French docs translations. PR [#14841](https://github.com/fastapi/fastapi/pull/14841) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for fr (translate-page). PR [#14837](https://github.com/fastapi/fastapi/pull/14837) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for de (update-outdated). PR [#14836](https://github.com/fastapi/fastapi/pull/14836) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for pt (update-outdated). PR [#14833](https://github.com/fastapi/fastapi/pull/14833) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for ko (update-outdated). PR [#14835](https://github.com/fastapi/fastapi/pull/14835) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for es (update-outdated). PR [#14832](https://github.com/fastapi/fastapi/pull/14832) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for tr (update-outdated). PR [#14831](https://github.com/fastapi/fastapi/pull/14831) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for tr (add-missing). PR [#14790](https://github.com/fastapi/fastapi/pull/14790) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for fr (update-outdated). PR [#14826](https://github.com/fastapi/fastapi/pull/14826) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for zh-hant (update-outdated). PR [#14825](https://github.com/fastapi/fastapi/pull/14825) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for uk (update-outdated). PR [#14822](https://github.com/fastapi/fastapi/pull/14822) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔨 Update docs and translations scripts, enable Turkish. PR [#14824](https://github.com/fastapi/fastapi/pull/14824) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
* 🔨 Add max pages to translate to configs. PR [#14840](https://github.com/fastapi/fastapi/pull/14840) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.128.1
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add `viewport` meta tag to improve Swagger UI on mobile devices. PR [#14777](https://github.com/fastapi/fastapi/pull/14777) by [@Joab0](https://github.com/Joab0).
|
||||
* 🚸 Improve error message for invalid query parameter type annotations. PR [#14479](https://github.com/fastapi/fastapi/pull/14479) by [@retwish](https://github.com/retwish).
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Update `ValidationError` schema to include `input` and `ctx`. PR [#14791](https://github.com/fastapi/fastapi/pull/14791) by [@jonathan-fulton](https://github.com/jonathan-fulton).
|
||||
* 🐛 Fix TYPE_CHECKING annotations for Python 3.14 (PEP 649). PR [#14789](https://github.com/fastapi/fastapi/pull/14789) by [@mgu](https://github.com/mgu).
|
||||
* 🐛 Strip whitespaces from `Authorization` header credentials. PR [#14786](https://github.com/fastapi/fastapi/pull/14786) by [@WaveTheory1](https://github.com/WaveTheory1).
|
||||
* 🐛 Fix OpenAPI duplication of `anyOf` refs for app-level responses with specified `content` and `model` as `Union`. PR [#14463](https://github.com/fastapi/fastapi/pull/14463) by [@DJMcoder](https://github.com/DJMcoder).
|
||||
|
||||
### Refactors
|
||||
|
||||
* 🎨 Tweak types for mypy. PR [#14816](https://github.com/fastapi/fastapi/pull/14816) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🏷️ Re-export `IncEx` type from Pydantic instead of duplicating it. PR [#14641](https://github.com/fastapi/fastapi/pull/14641) by [@mvanderlee](https://github.com/mvanderlee).
|
||||
* 💡 Update comment for Pydantic internals. PR [#14814](https://github.com/fastapi/fastapi/pull/14814) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs for contributing translations, simplify title. PR [#14817](https://github.com/fastapi/fastapi/pull/14817) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Fix typing issue in `docs_src/app_testing/app_b` code example. PR [#14573](https://github.com/fastapi/fastapi/pull/14573) by [@timakaa](https://github.com/timakaa).
|
||||
* 📝 Fix example of license identifier in documentation. PR [#14492](https://github.com/fastapi/fastapi/pull/14492) by [@johnson-earls](https://github.com/johnson-earls).
|
||||
* 📝 Add banner to translated pages. PR [#14809](https://github.com/fastapi/fastapi/pull/14809) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Add links to related sections of docs to docstrings. PR [#14776](https://github.com/fastapi/fastapi/pull/14776) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Update embedded code examples to Python 3.10 syntax. PR [#14758](https://github.com/fastapi/fastapi/pull/14758) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Fix dependency installation command in `docs/en/docs/contributing.md`. PR [#14757](https://github.com/fastapi/fastapi/pull/14757) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Use return type annotation instead of `response_model` when possible. PR [#14753](https://github.com/fastapi/fastapi/pull/14753) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Use `WSGIMiddleware` from `a2wsgi` instead of deprecated `fastapi.middleware.wsgi.WSGIMiddleware`. PR [#14756](https://github.com/fastapi/fastapi/pull/14756) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 📝 Fix minor typos in release notes. PR [#14780](https://github.com/fastapi/fastapi/pull/14780) by [@whyvineet](https://github.com/whyvineet).
|
||||
* 🐛 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
|
||||
|
||||
* 🌐 Improve LLM prompt of `uk` documentation. PR [#14795](https://github.com/fastapi/fastapi/pull/14795) by [@roli2py](https://github.com/roli2py).
|
||||
* 🌐 Update translations for ja (update-outdated). PR [#14588](https://github.com/fastapi/fastapi/pull/14588) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for uk (update outdated, found by fixer tool). PR [#14739](https://github.com/fastapi/fastapi/pull/14739) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for tr (update-outdated). PR [#14745](https://github.com/fastapi/fastapi/pull/14745) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update `llm-prompt.md` for Korean language. PR [#14763](https://github.com/fastapi/fastapi/pull/14763) by [@seuthootDev](https://github.com/seuthootDev).
|
||||
* 🌐 Update translations for ko (update outdated, found by fixer tool). PR [#14738](https://github.com/fastapi/fastapi/pull/14738) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for de (update-outdated). PR [#14690](https://github.com/fastapi/fastapi/pull/14690) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update LLM prompt for Russian translations. PR [#14733](https://github.com/fastapi/fastapi/pull/14733) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 🌐 Update translations for ru (update-outdated). PR [#14693](https://github.com/fastapi/fastapi/pull/14693) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update translations for pt (update-outdated). PR [#14724](https://github.com/fastapi/fastapi/pull/14724) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Update Korean LLM prompt. PR [#14740](https://github.com/fastapi/fastapi/pull/14740) by [@hard-coders](https://github.com/hard-coders).
|
||||
* 🌐 Improve LLM prompt for Turkish translations. PR [#14728](https://github.com/fastapi/fastapi/pull/14728) by [@Kadermiyanyedi](https://github.com/Kadermiyanyedi).
|
||||
* 🌐 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
|
||||
|
||||
* ⬇️ Downgrade LLM translations model to GPT-5 to reduce mistakes. PR [#14823](https://github.com/fastapi/fastapi/pull/14823) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🐛 Fix translation script commit in place. PR [#14818](https://github.com/fastapi/fastapi/pull/14818) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔨 Update translation script to retry if LLM-response doesn't pass validation with Translation Fixer tool. PR [#14749](https://github.com/fastapi/fastapi/pull/14749) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* 👷 Run tests only on relevant code changes (not on docs). PR [#14813](https://github.com/fastapi/fastapi/pull/14813) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👷 Run mypy by pre-commit. PR [#14806](https://github.com/fastapi/fastapi/pull/14806) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
* ⬆ Bump ruff from 0.14.3 to 0.14.14. PR [#14798](https://github.com/fastapi/fastapi/pull/14798) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump pyasn1 from 0.6.1 to 0.6.2. PR [#14804](https://github.com/fastapi/fastapi/pull/14804) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump sqlmodel from 0.0.27 to 0.0.31. PR [#14802](https://github.com/fastapi/fastapi/pull/14802) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump mkdocs-macros-plugin from 1.4.1 to 1.5.0. PR [#14801](https://github.com/fastapi/fastapi/pull/14801) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump gitpython from 3.1.45 to 3.1.46. PR [#14800](https://github.com/fastapi/fastapi/pull/14800) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump typer from 0.16.0 to 0.21.1. PR [#14799](https://github.com/fastapi/fastapi/pull/14799) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* 👥 Update FastAPI GitHub topic repositories. PR [#14803](https://github.com/fastapi/fastapi/pull/14803) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Update FastAPI People - Contributors and Translators. PR [#14796](https://github.com/fastapi/fastapi/pull/14796) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Ensure that an edit to `uv.lock` gets the `internal` label. PR [#14759](https://github.com/fastapi/fastapi/pull/14759) by [@svlandeg](https://github.com/svlandeg).
|
||||
* 🔧 Update sponsors: remove Requestly. PR [#14735](https://github.com/fastapi/fastapi/pull/14735) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors, LambdaTest changes to TestMu AI. PR [#14734](https://github.com/fastapi/fastapi/pull/14734) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ 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).
|
||||
@@ -247,7 +366,7 @@ hide:
|
||||
|
||||
### Refactors
|
||||
|
||||
* 🔥 Remove dangling extra condiitonal no longer needed. PR [#14435](https://github.com/fastapi/fastapi/pull/14435) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔥 Remove dangling extra conditional no longer needed. PR [#14435](https://github.com/fastapi/fastapi/pull/14435) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ♻️ Refactor internals, update `is_coroutine` check to reuse internal supported variants (unwrap, check class). PR [#14434](https://github.com/fastapi/fastapi/pull/14434) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Translations
|
||||
@@ -382,7 +501,7 @@ hide:
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Upate docs for advanced dependencies with `yield`, noting the changes in 0.121.0, adding `scope`. PR [#14287](https://github.com/fastapi/fastapi/pull/14287) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Update docs for advanced dependencies with `yield`, noting the changes in 0.121.0, adding `scope`. PR [#14287](https://github.com/fastapi/fastapi/pull/14287) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Internal
|
||||
|
||||
@@ -2610,7 +2729,7 @@ Read more in the [advisory: Content-Type Header ReDoS](https://github.com/tiango
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/handling-errors.md`. PR [#1953](https://github.com/tiangolo/fastapi/pull/1953) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/response-status-code.md`. PR [#1942](https://github.com/tiangolo/fastapi/pull/1942) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/extra-models.md`. PR [#1941](https://github.com/tiangolo/fastapi/pull/1941) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese tranlsation for `docs/ja/docs/tutorial/schema-extra-example.md`. PR [#1931](https://github.com/tiangolo/fastapi/pull/1931) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/schema-extra-example.md`. PR [#1931](https://github.com/tiangolo/fastapi/pull/1931) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/body-nested-models.md`. PR [#1930](https://github.com/tiangolo/fastapi/pull/1930) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add Japanese translation for `docs/ja/docs/tutorial/body-fields.md`. PR [#1923](https://github.com/tiangolo/fastapi/pull/1923) by [@SwftAlpc](https://github.com/SwftAlpc).
|
||||
* 🌐 Add German translation for `docs/de/docs/tutorial/index.md`. PR [#9502](https://github.com/tiangolo/fastapi/pull/9502) by [@fhabers21](https://github.com/fhabers21).
|
||||
@@ -3986,7 +4105,7 @@ You hopefully updated to a supported version of Python a while ago. If you haven
|
||||
### Fixes
|
||||
|
||||
* 🐛 Fix `RuntimeError` raised when `HTTPException` has a status code with no content. PR [#5365](https://github.com/tiangolo/fastapi/pull/5365) by [@iudeen](https://github.com/iudeen).
|
||||
* 🐛 Fix empty reponse body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel).
|
||||
* 🐛 Fix empty response body when default `status_code` is empty but the a `Response` parameter with `response.status_code` is set. PR [#5360](https://github.com/tiangolo/fastapi/pull/5360) by [@tmeckel](https://github.com/tmeckel).
|
||||
|
||||
### Docs
|
||||
|
||||
|
||||
11
docs/en/docs/translation-banner.md
Normal file
11
docs/en/docs/translation-banner.md
Normal file
@@ -0,0 +1,11 @@
|
||||
/// details | 🌐 Translation by AI and humans
|
||||
|
||||
This translation was made by AI guided by humans. 🤝
|
||||
|
||||
It could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖
|
||||
|
||||
You can improve this translation by [helping us guide the AI LLM better](https://fastapi.tiangolo.com/contributing/#translations).
|
||||
|
||||
[English version](ENGLISH_VERSION_URL)
|
||||
|
||||
///
|
||||
@@ -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"
|
||||
|
||||
@@ -102,15 +102,16 @@ Of course, you can also declare additional query parameters whenever you need, a
|
||||
|
||||
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Or in Python 3.9:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Or in Python 3.10 and above:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ In these cases, it could make sense to store the tags in an `Enum`.
|
||||
|
||||
You can add a `summary` and `description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
|
||||
## Description from docstring { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@ It will be used in the interactive docs:
|
||||
|
||||
You can specify the response description with the parameter `response_description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info
|
||||
|
||||
|
||||
@@ -319,10 +319,20 @@ extra:
|
||||
name: es - español
|
||||
- link: /fr/
|
||||
name: fr - français
|
||||
- link: /ja/
|
||||
name: ja - 日本語
|
||||
- link: /ko/
|
||||
name: ko - 한국어
|
||||
- link: /pt/
|
||||
name: pt - português
|
||||
- link: /ru/
|
||||
name: ru - русский язык
|
||||
- link: /tr/
|
||||
name: tr - Türkçe
|
||||
- link: /uk/
|
||||
name: uk - українська мова
|
||||
- link: /zh-hant/
|
||||
name: zh-hant - 繁體中文
|
||||
extra_css:
|
||||
- css/termynal.css
|
||||
- css/custom.css
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 devolverá 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.
|
||||
|
||||
|
||||
@@ -2,17 +2,33 @@
|
||||
|
||||
Puedes montar aplicaciones WSGI como viste con [Sub Aplicaciones - Mounts](sub-applications.md){.internal-link target=_blank}, [Detrás de un Proxy](behind-a-proxy.md){.internal-link target=_blank}.
|
||||
|
||||
Para eso, puedes usar `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.
|
||||
Para eso, puedes usar el `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.
|
||||
|
||||
## Usando `WSGIMiddleware` { #using-wsgimiddleware }
|
||||
|
||||
Necesitas importar `WSGIMiddleware`.
|
||||
/// info | Información
|
||||
|
||||
Esto requiere instalar `a2wsgi`, por ejemplo con `pip install a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
Necesitas importar `WSGIMiddleware` de `a2wsgi`.
|
||||
|
||||
Luego envuelve la aplicación WSGI (p. ej., Flask) con el middleware.
|
||||
|
||||
Y luego móntala bajo un path.
|
||||
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *}
|
||||
{* ../../docs_src/wsgi/tutorial001_py39.py hl[1,3,23] *}
|
||||
|
||||
/// note | Nota
|
||||
|
||||
Anteriormente, se recomendaba usar `WSGIMiddleware` de `fastapi.middleware.wsgi`, pero ahora está deprecado.
|
||||
|
||||
Se aconseja usar el paquete `a2wsgi` en su lugar. El uso sigue siendo el mismo.
|
||||
|
||||
Solo asegúrate de tener instalado el paquete `a2wsgi` e importar `WSGIMiddleware` correctamente desde `a2wsgi`.
|
||||
|
||||
///
|
||||
|
||||
## Revisa { #check-it }
|
||||
|
||||
|
||||
@@ -145,8 +145,6 @@ Existen otros formatos y herramientas para definir e instalar dependencias de pa
|
||||
* Crea un archivo `main.py` con:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -158,7 +156,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -572,7 +570,7 @@ Si tienes una configuración simple, con un **contenedor único** que luego inic
|
||||
|
||||
### Imagen Base de Docker { #base-docker-image }
|
||||
|
||||
Solía haber una imagen official de Docker de FastAPI: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi-docker</a>. Pero ahora está obsoleta. ⛔️
|
||||
Solía haber una imagen official de Docker de FastAPI: <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Pero ahora está obsoleta. ⛔️
|
||||
|
||||
Probablemente **no** deberías usar esta imagen base de Docker (o cualquier otra similar).
|
||||
|
||||
|
||||
@@ -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. 🚶
|
||||
|
||||
@@ -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. 🤓
|
||||
|
||||
@@ -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>
|
||||
@@ -155,8 +161,6 @@ $ pip install "fastapi[standard]"
|
||||
Crea un archivo `main.py` con:
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -168,7 +172,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -177,9 +181,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
|
||||
|
||||
Si tu código usa `async` / `await`, usa `async def`:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -191,7 +193,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -268,7 +270,7 @@ Verás la documentación interactiva automática de la API (proporcionada por <a
|
||||
|
||||

|
||||
|
||||
### 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,15 +278,13 @@ Verás la documentación alternativa automática (proporcionada por <a href="htt
|
||||
|
||||

|
||||
|
||||
## 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`.
|
||||
|
||||
Declara el body usando tipos estándar de Python, gracias a Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -294,7 +294,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: Union[bool, None] = None
|
||||
is_offer: bool | None = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -303,7 +303,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@@ -314,7 +314,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 +330,7 @@ Ahora ve a <a href="http://127.0.0.1:8000/docs" class="external-link" target="_b
|
||||
|
||||

|
||||
|
||||
### 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 +393,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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -101,13 +101,13 @@ Por supuesto, también puedes declarar parámetros adicionales de query siempre
|
||||
Como, por defecto, los valores singulares se interpretan como parámetros de query, no tienes que añadir explícitamente un `Query`, solo puedes hacer:
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
O en Python 3.10 y superior:
|
||||
O en Python 3.9:
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Por ejemplo:
|
||||
|
||||
@@ -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] *}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -52,7 +52,7 @@ En estos casos, podría tener sentido almacenar las tags en un `Enum`.
|
||||
|
||||
Puedes añadir un `summary` y `description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[18:19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}
|
||||
|
||||
## Descripción desde docstring { #description-from-docstring }
|
||||
|
||||
@@ -70,7 +70,7 @@ Será usado en la documentación interactiva:
|
||||
|
||||
Puedes especificar la descripción del response con el parámetro `response_description`:
|
||||
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[19] *}
|
||||
{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}
|
||||
|
||||
/// info | Información
|
||||
|
||||
|
||||
@@ -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())`.
|
||||
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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`. 🤓
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Réponses supplémentaires dans OpenAPI { #additional-responses-in-openapi }
|
||||
|
||||
/// warning | Attention
|
||||
/// warning | Alertes
|
||||
|
||||
Ceci concerne un sujet plutôt avancé.
|
||||
|
||||
@@ -16,7 +16,7 @@ Mais pour ces réponses supplémentaires, vous devez vous assurer de renvoyer di
|
||||
|
||||
## Réponse supplémentaire avec `model` { #additional-response-with-model }
|
||||
|
||||
Vous pouvez passer à vos *décorateurs d'opération de chemin* un paramètre `responses`.
|
||||
Vous pouvez passer à vos décorateurs de *chemin d'accès* un paramètre `responses`.
|
||||
|
||||
Il prend comme valeur un `dict` dont les clés sont des codes HTTP pour chaque réponse, comme `200`, et la valeur de ces clés sont d'autres `dict` avec des informations pour chacun d'eux.
|
||||
|
||||
@@ -49,7 +49,7 @@ Le bon endroit est :
|
||||
|
||||
///
|
||||
|
||||
Les réponses générées au format OpenAPI pour cette *opération de chemin* seront :
|
||||
Les réponses générées au format OpenAPI pour ce *chemin d'accès* seront :
|
||||
|
||||
```JSON hl_lines="3-12"
|
||||
{
|
||||
@@ -173,7 +173,7 @@ Les schémas sont référencés à un autre endroit du modèle OpenAPI :
|
||||
|
||||
Vous pouvez utiliser ce même paramètre `responses` pour ajouter différents types de médias pour la même réponse principale.
|
||||
|
||||
Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *opération de chemin* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
|
||||
Par exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *chemin d'accès* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :
|
||||
|
||||
{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}
|
||||
|
||||
@@ -191,7 +191,7 @@ Mais si vous avez spécifié une classe de réponse personnalisée avec `None` c
|
||||
|
||||
///
|
||||
|
||||
## Combinaison d'informations { #combining-information }
|
||||
## Combiner les informations { #combining-information }
|
||||
|
||||
Vous pouvez également combiner des informations de réponse provenant de plusieurs endroits, y compris les paramètres `response_model`, `status_code` et `responses`.
|
||||
|
||||
@@ -211,9 +211,9 @@ Tout sera combiné et inclus dans votre OpenAPI, et affiché dans la documentati
|
||||
|
||||
## Combinez les réponses prédéfinies et les réponses personnalisées { #combine-predefined-responses-and-custom-ones }
|
||||
|
||||
Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreuses *opérations de chemin*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *opération de chemin*.
|
||||
Vous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *chemins d'accès*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *chemin d'accès*.
|
||||
|
||||
Dans ces cas, vous pouvez utiliser la technique Python «d'affection par décomposition» (appelé _unpacking_ en anglais) d'un `dict` avec `**dict_to_unpack` :
|
||||
Dans ces cas, vous pouvez utiliser la technique Python « unpacking » d'un `dict` avec `**dict_to_unpack` :
|
||||
|
||||
```Python
|
||||
old_dict = {
|
||||
@@ -233,7 +233,7 @@ Ici, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la n
|
||||
}
|
||||
```
|
||||
|
||||
Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *opérations de chemin* et les combiner avec des réponses personnalisées supplémentaires.
|
||||
Vous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *chemins d'accès* et les combiner avec des réponses personnalisées supplémentaires.
|
||||
|
||||
Par exemple:
|
||||
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
# Codes HTTP supplémentaires { #additional-status-codes }
|
||||
|
||||
Par défaut, **FastAPI** renverra les réponses à l'aide d'une structure de données `JSONResponse`, en plaçant la réponse de votre *opération de chemin* à l'intérieur de cette `JSONResponse`.
|
||||
Par défaut, **FastAPI** renverra les réponses à l'aide d'une structure de données `JSONResponse`, en plaçant la réponse de votre *chemin d'accès* à l'intérieur de cette `JSONResponse`.
|
||||
|
||||
Il utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *opération de chemin*.
|
||||
Il utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *chemin d'accès*.
|
||||
|
||||
## Codes HTTP supplémentaires { #additional-status-codes_1 }
|
||||
|
||||
Si vous souhaitez renvoyer des codes HTTP supplémentaires en plus du code principal, vous pouvez le faire en renvoyant directement une `Response`, comme une `JSONResponse`, et en définissant directement le code HTTP supplémentaire.
|
||||
|
||||
Par exemple, disons que vous voulez avoir une *opération de chemin* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 «OK» en cas de succès.
|
||||
Par exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 « OK » en cas de succès.
|
||||
|
||||
Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 «Créé».
|
||||
Mais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 « Créé ».
|
||||
|
||||
Pour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous souhaitez :
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
|
||||
/// warning | Attention
|
||||
/// warning | Alertes
|
||||
|
||||
Lorsque vous renvoyez une `Response` directement, comme dans l'exemple ci-dessus, elle sera renvoyée directement.
|
||||
|
||||
Elle ne sera pas sérialisée avec un modèle.
|
||||
|
||||
Assurez-vous qu'elle contient les données souhaitées et que les valeurs soient dans un format JSON valides (si vous utilisez une `JSONResponse`).
|
||||
Assurez-vous qu'il contient les données souhaitées et que les valeurs sont dans un format JSON valide (si vous utilisez une `JSONResponse`).
|
||||
|
||||
///
|
||||
|
||||
@@ -34,8 +34,8 @@ Pour plus de commodités, **FastAPI** fournit les objets `starlette.responses` s
|
||||
|
||||
///
|
||||
|
||||
## OpenAPI et documentation de l'API { #openapi-and-api-docs }
|
||||
## Documents OpenAPI et API { #openapi-and-api-docs }
|
||||
|
||||
Si vous renvoyez directement des codes HTTP et des réponses supplémentaires, ils ne seront pas inclus dans le schéma OpenAPI (la documentation de l'API), car FastAPI n'a aucun moyen de savoir à l'avance ce que vous allez renvoyer.
|
||||
|
||||
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires](additional-responses.md){.internal-link target=_blank}.
|
||||
Mais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
@@ -8,13 +8,13 @@ Dans les sections suivantes, vous verrez des options, configurations et fonction
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Les sections de ce chapitre ne sont **pas nécessairement «avancées»**.
|
||||
Les sections suivantes ne sont **pas nécessairement « avancées »**.
|
||||
|
||||
Et il est possible que pour votre cas d'utilisation, la solution se trouve dans l'un d'entre eux.
|
||||
Et il est possible que, pour votre cas d'utilisation, la solution se trouve dans l'une d'entre elles.
|
||||
|
||||
///
|
||||
|
||||
## Lisez d'abord le didacticiel { #read-the-tutorial-first }
|
||||
## Lire d'abord le tutoriel { #read-the-tutorial-first }
|
||||
|
||||
Vous pouvez utiliser la plupart des fonctionnalités de **FastAPI** grâce aux connaissances du [Tutoriel - Guide de l'utilisateur](../tutorial/index.md){.internal-link target=_blank}.
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
# Configuration avancée des opérations de chemin { #path-operation-advanced-configuration }
|
||||
# Configuration avancée des chemins d'accès { #path-operation-advanced-configuration }
|
||||
|
||||
## ID d'opération OpenAPI { #openapi-operationid }
|
||||
## ID d’opération OpenAPI { #openapi-operationid }
|
||||
|
||||
/// warning | Attention
|
||||
/// warning | Alertes
|
||||
|
||||
Si vous n'êtes pas un «expert» d'OpenAPI, vous n'en avez probablement pas besoin.
|
||||
Si vous n’êtes pas un « expert » d’OpenAPI, vous n’en avez probablement pas besoin.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez définir l'OpenAPI `operationId` à utiliser dans votre *opération de chemin* avec le paramètre `operation_id`.
|
||||
Vous pouvez définir l’OpenAPI `operationId` à utiliser dans votre chemin d’accès avec le paramètre `operation_id`.
|
||||
|
||||
Vous devrez vous assurer qu'il soit unique pour chaque opération.
|
||||
Vous devez vous assurer qu’il est unique pour chaque opération.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *}
|
||||
|
||||
### Utiliser le nom de la *fonction d'opération de chemin* comme operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
### Utiliser le nom de la fonction de chemin d’accès comme operationId { #using-the-path-operation-function-name-as-the-operationid }
|
||||
|
||||
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer chaque `operation_id` de l’*opération de chemin* en utilisant leur `APIRoute.name`.
|
||||
Si vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer l’`operation_id` de chaque chemin d’accès en utilisant leur `APIRoute.name`.
|
||||
|
||||
Vous devriez le faire après avoir ajouté toutes vos *opérations de chemin*.
|
||||
Vous devez le faire après avoir ajouté tous vos chemins d’accès.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *}
|
||||
|
||||
@@ -28,35 +28,35 @@ Si vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `ope
|
||||
|
||||
///
|
||||
|
||||
/// warning | Attention
|
||||
/// warning | Alertes
|
||||
|
||||
Si vous faites cela, vous devez vous assurer que chacune de vos *fonctions d'opération de chemin* a un nom unique.
|
||||
Si vous faites cela, vous devez vous assurer que chacune de vos fonctions de chemin d’accès a un nom unique.
|
||||
|
||||
Même si elles se trouvent dans des modules différents (fichiers Python).
|
||||
|
||||
///
|
||||
|
||||
## Exclure d'OpenAPI { #exclude-from-openapi }
|
||||
## Exclusion d’OpenAPI { #exclude-from-openapi }
|
||||
|
||||
Pour exclure une *opération de chemin* du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et assignez-lui la valeur `False` :
|
||||
Pour exclure un chemin d’accès du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et définissez-le à `False` :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *}
|
||||
|
||||
## Description avancée depuis la docstring { #advanced-description-from-docstring }
|
||||
|
||||
Vous pouvez limiter les lignes utilisées de la docstring d'une *fonction d'opération de chemin* pour OpenAPI.
|
||||
Vous pouvez limiter les lignes utilisées de la docstring d’une fonction de chemin d’accès pour OpenAPI.
|
||||
|
||||
L'ajout d'un `\f` (un caractère d'échappement «form feed») fait que **FastAPI** tronque la sortie utilisée pour OpenAPI à cet endroit.
|
||||
L’ajout d’un `\f` (un caractère « saut de page » échappé) amène **FastAPI** à tronquer la sortie utilisée pour OpenAPI à cet endroit.
|
||||
|
||||
Cela n'apparaîtra pas dans la documentation, mais d'autres outils (tels que Sphinx) pourront utiliser le reste.
|
||||
Cela n’apparaîtra pas dans la documentation, mais d’autres outils (comme Sphinx) pourront utiliser le reste.
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}
|
||||
|
||||
## Réponses supplémentaires { #additional-responses }
|
||||
|
||||
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour une *opération de chemin*.
|
||||
Vous avez probablement vu comment déclarer le `response_model` et le `status_code` pour un chemin d’accès.
|
||||
|
||||
Cela définit les métadonnées de la réponse principale d'une *opération de chemin*.
|
||||
Cela définit les métadonnées sur la réponse principale d’un chemin d’accès.
|
||||
|
||||
Vous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc.
|
||||
|
||||
@@ -64,41 +64,41 @@ Il y a un chapitre entier dans la documentation à ce sujet, vous pouvez le lire
|
||||
|
||||
## OpenAPI supplémentaire { #openapi-extra }
|
||||
|
||||
Lorsque vous déclarez une *opération de chemin* dans votre application, **FastAPI** génère automatiquement les métadonnées pertinentes concernant cette *opération de chemin* à inclure dans le schéma OpenAPI.
|
||||
Lorsque vous déclarez un chemin d’accès dans votre application, **FastAPI** génère automatiquement les métadonnées pertinentes à propos de ce chemin d’accès à inclure dans le schéma OpenAPI.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
Dans la spécification OpenAPI, cela s'appelle l’<a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">Objet d'opération</a>.
|
||||
Dans la spécification OpenAPI, cela s’appelle l’<a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object" class="external-link" target="_blank">objet Operation</a>.
|
||||
|
||||
///
|
||||
|
||||
Il contient toutes les informations sur l’*opération de chemin* et est utilisé pour générer automatiquement la documentation.
|
||||
Il contient toutes les informations sur le chemin d’accès et est utilisé pour générer la documentation automatique.
|
||||
|
||||
Il inclut les `tags`, `parameters`, `requestBody`, `responses`, etc.
|
||||
|
||||
Ce schéma OpenAPI spécifique à l’*opération de chemin* est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l'étendre.
|
||||
Ce schéma OpenAPI spécifique à un chemin d’accès est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l’étendre.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ceci est un point d'extension de bas niveau.
|
||||
Ceci est un point d’extension de bas niveau.
|
||||
|
||||
Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d'utiliser [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
Si vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d’utiliser [Réponses supplémentaires dans OpenAPI](additional-responses.md){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez étendre le schéma OpenAPI pour une *opération de chemin* en utilisant le paramètre `openapi_extra`.
|
||||
Vous pouvez étendre le schéma OpenAPI pour un chemin d’accès en utilisant le paramètre `openapi_extra`.
|
||||
|
||||
### Extensions OpenAPI { #openapi-extensions }
|
||||
|
||||
Cet `openapi_extra` peut être utile, par exemple, pour déclarer des [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :
|
||||
Cet `openapi_extra` peut être utile, par exemple, pour déclarer des [Extensions OpenAPI](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] *}
|
||||
|
||||
Si vous ouvrez la documentation automatique de l'API, votre extension apparaîtra en bas de l’*opération de chemin* spécifique.
|
||||
Si vous ouvrez la documentation automatique de l’API, votre extension apparaîtra en bas du chemin d’accès spécifique.
|
||||
|
||||
<img src="/img/tutorial/path-operation-advanced-configuration/image01.png">
|
||||
|
||||
Et si vous regardez l’OpenAPI résultant (à `/openapi.json` dans votre API), vous verrez également votre extension dans le cadre de l’*opération de chemin* spécifique :
|
||||
Et si vous consultez l’OpenAPI résultant (à `/openapi.json` dans votre API), vous verrez également votre extension comme partie du chemin d’accès spécifique :
|
||||
|
||||
```JSON hl_lines="22"
|
||||
{
|
||||
@@ -129,37 +129,37 @@ Et si vous regardez l’OpenAPI résultant (à `/openapi.json` dans votre API),
|
||||
}
|
||||
```
|
||||
|
||||
### Schéma OpenAPI personnalisé pour une *opération de chemin* { #custom-openapi-path-operation-schema }
|
||||
### Personnaliser le schéma OpenAPI d’un chemin d’accès { #custom-openapi-path-operation-schema }
|
||||
|
||||
Le dictionnaire dans `openapi_extra` sera fusionné en profondeur avec le schéma OpenAPI généré automatiquement pour l’*opération de chemin*.
|
||||
Le dictionnaire dans `openapi_extra` sera fusionné en profondeur avec le schéma OpenAPI généré automatiquement pour le chemin d’accès.
|
||||
|
||||
Ainsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement.
|
||||
|
||||
Par exemple, vous pourriez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de FastAPI avec Pydantic, mais vous pourriez quand même vouloir définir la requête dans le schéma OpenAPI.
|
||||
Par exemple, vous pourriez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de FastAPI avec Pydantic, mais vous pourriez tout de même vouloir définir la requête dans le schéma OpenAPI.
|
||||
|
||||
Vous pouvez le faire avec `openapi_extra` :
|
||||
Vous pourriez le faire avec `openapi_extra` :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *}
|
||||
|
||||
Dans cet exemple, nous n'avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n'est même pas <abbr title="converti d'un format simple, comme des octets, en objets Python">parsé</abbr> en tant que JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargée de l'analyser d'une manière ou d'une autre.
|
||||
Dans cet exemple, nous n’avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n’est même pas <abbr title="converti d'un format simple, comme des octets, en objets Python">parsé</abbr> en JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargée de l’analyser d’une manière ou d’une autre.
|
||||
|
||||
Néanmoins, nous pouvons déclarer le schéma attendu pour le corps de la requête.
|
||||
|
||||
### Type de contenu OpenAPI personnalisé { #custom-openapi-content-type }
|
||||
|
||||
En utilisant cette même astuce, vous pourriez utiliser un modèle Pydantic pour définir le JSON Schema qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour l’*opération de chemin*.
|
||||
En utilisant cette même astuce, vous pourriez utiliser un modèle Pydantic pour définir le JSON Schema qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le chemin d’accès.
|
||||
|
||||
Et vous pourriez le faire même si le type de données dans la requête n'est pas du JSON.
|
||||
Et vous pourriez le faire même si le type de données dans la requête n’est pas du JSON.
|
||||
|
||||
Par exemple, dans cette application nous n'utilisons pas la fonctionnalité intégrée de FastAPI pour extraire le JSON Schema des modèles Pydantic ni la validation automatique pour JSON. En fait, nous déclarons le type de contenu de la requête comme YAML, et non JSON :
|
||||
Par exemple, dans cette application nous n’utilisons pas la fonctionnalité intégrée de FastAPI pour extraire le JSON Schema des modèles Pydantic ni la validation automatique pour le JSON. En fait, nous déclarons le type de contenu de la requête comme YAML, pas JSON :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *}
|
||||
|
||||
Néanmoins, bien que nous n'utilisions pas la fonctionnalité intégrée par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le JSON Schema pour les données que nous souhaitons recevoir en YAML.
|
||||
Néanmoins, bien que nous n’utilisions pas la fonctionnalité intégrée par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le JSON Schema pour les données que nous souhaitons recevoir en YAML.
|
||||
|
||||
Ensuite, nous utilisons directement la requête et extrayons son corps en tant que `bytes`. Cela signifie que FastAPI n'essaiera même pas d'analyser le payload de la requête en tant que JSON.
|
||||
Ensuite, nous utilisons directement la requête et extrayons le corps en tant que `bytes`. Cela signifie que FastAPI n’essaiera même pas d’analyser le payload de la requête en JSON.
|
||||
|
||||
Et puis, dans notre code, nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
|
||||
Ensuite, dans notre code, nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :
|
||||
|
||||
{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *}
|
||||
|
||||
@@ -167,6 +167,6 @@ Et puis, dans notre code, nous analysons directement ce contenu YAML, puis nous
|
||||
|
||||
Ici, nous réutilisons le même modèle Pydantic.
|
||||
|
||||
Mais de la même manière, nous aurions tout aussi bien pu le valider autrement.
|
||||
Mais de la même manière, nous aurions pu le valider autrement.
|
||||
|
||||
///
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Renvoyer directement une réponse { #return-a-response-directly }
|
||||
|
||||
Lorsque vous créez une *opération de chemin* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.
|
||||
Lorsque vous créez un *chemin d'accès* **FastAPI**, vous pouvez normalement retourner n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.
|
||||
|
||||
Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}.
|
||||
Par défaut, **FastAPI** convertirait automatiquement cette valeur de retour en JSON en utilisant le `jsonable_encoder` expliqué dans [Encodeur compatible JSON](../tutorial/encoder.md){.internal-link target=_blank}.
|
||||
|
||||
Ensuite, en arrière-plan, il mettra ces données JSON-compatible (par exemple un `dict`) à l'intérieur d'un `JSONResponse` qui sera utilisé pour envoyer la réponse au client.
|
||||
|
||||
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *opérations de chemin*.
|
||||
Mais vous pouvez retourner une `JSONResponse` directement à partir de vos *chemins d'accès*.
|
||||
|
||||
Cela peut être utile, par exemple, pour retourner des en-têtes personnalisés ou des cookies.
|
||||
|
||||
@@ -24,15 +24,15 @@ Et quand vous retournez une `Response`, **FastAPI** la transmet directement.
|
||||
|
||||
Elle ne fera aucune conversion de données avec les modèles Pydantic, elle ne convertira pas le contenu en un type quelconque.
|
||||
|
||||
Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données.
|
||||
Cela vous donne beaucoup de flexibilité. Vous pouvez retourner n'importe quel type de données, surcharger n'importe quelle déclaration ou validation de données, etc.
|
||||
|
||||
## Utiliser le `jsonable_encoder` dans une `Response` { #using-the-jsonable-encoder-in-a-response }
|
||||
|
||||
Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt à être utilisé.
|
||||
Parce que **FastAPI** n'apporte aucune modification à une `Response` que vous retournez, vous devez vous assurer que son contenu est prêt pour cela.
|
||||
|
||||
Par exemple, vous ne pouvez pas mettre un modèle Pydantic dans une `JSONResponse` sans d'abord le convertir en un `dict` avec tous les types de données (comme `datetime`, `UUID`, etc.) convertis en types compatibles avec JSON.
|
||||
|
||||
Pour ces cas, vous pouvez spécifier un appel à `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
|
||||
Pour ces cas, vous pouvez utiliser le `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :
|
||||
|
||||
{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}
|
||||
|
||||
@@ -40,7 +40,7 @@ Pour ces cas, vous pouvez spécifier un appel à `jsonable_encoder` pour convert
|
||||
|
||||
Vous pouvez aussi utiliser `from starlette.responses import JSONResponse`.
|
||||
|
||||
**FastAPI** fournit le même objet `starlette.responses` que `fastapi.responses` juste par commodité pour le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
|
||||
**FastAPI** fournit le même `starlette.responses` que `fastapi.responses` juste par commodité pour vous, le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.
|
||||
|
||||
///
|
||||
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
# Tests de performance { #benchmarks }
|
||||
|
||||
Des tests de performance indépendants de TechEmpower montrent que les applications **FastAPI** exécutées sous Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">parmi les frameworks Python les plus rapides disponibles</a>, seulement derrière Starlette et Uvicorn eux‑mêmes (tous deux utilisés en interne par FastAPI).
|
||||
Les benchmarks indépendants de TechEmpower montrent que les applications **FastAPI** s’exécutant avec Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">parmi les frameworks Python les plus rapides disponibles</a>, seulement en dessous de Starlette et Uvicorn eux‑mêmes (tous deux utilisés en interne par FastAPI).
|
||||
|
||||
Mais lorsque vous examinez les tests de performance et les comparaisons, vous devez garder les points suivants à l'esprit.
|
||||
Mais en prêtant attention aux tests de performance et aux comparaisons, vous devez tenir compte de ce qui suit.
|
||||
|
||||
## Tests de performance et rapidité { #benchmarks-and-speed }
|
||||
|
||||
Lorsque vous vérifiez les tests de performance, il est courant de voir plusieurs outils de types différents comparés comme équivalents.
|
||||
Lorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents.
|
||||
|
||||
En particulier, on voit Uvicorn, Starlette et FastAPI comparés ensemble (parmi de nombreux autres outils).
|
||||
En particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils).
|
||||
|
||||
Plus le problème résolu par l’outil est simple, meilleures seront ses performances. Et la plupart des tests de performance ne testent pas les fonctionnalités additionnelles fournies par l’outil.
|
||||
Plus le problème résolu par un outil est simple, meilleures seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils.
|
||||
|
||||
La hiérarchie est la suivante :
|
||||
|
||||
* **Uvicorn** : un serveur ASGI
|
||||
* **Starlette** : (utilise Uvicorn) un microframework web
|
||||
* **FastAPI** : (utilise Starlette) un microframework d’API avec plusieurs fonctionnalités supplémentaires pour créer des API, notamment la validation des données, etc.
|
||||
* **FastAPI**: (utilise Starlette) un microframework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc.
|
||||
|
||||
* **Uvicorn** :
|
||||
* Aura la meilleure performance, car il n’a pas beaucoup de code supplémentaire en dehors du serveur lui‑même.
|
||||
* Vous n’écririez pas une application directement avec Uvicorn. Cela signifierait que votre code devrait inclure, plus ou moins, au minimum, tout le code fourni par Starlette (ou **FastAPI**). Et si vous faisiez cela, votre application finale aurait la même surcharge que si vous aviez utilisé un framework, tout en minimisant le code de votre application et les bugs.
|
||||
* Si vous comparez Uvicorn, comparez‑le à Daphne, Hypercorn, uWSGI, etc. Des serveurs d’applications.
|
||||
* A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis à part le serveur en lui‑même.
|
||||
* On n'écrit pas une application directement avec Uvicorn. Cela signifie que le code devrait inclure, au minimum, plus ou moins tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale aura la même surcharge que si on avait utilisé un framework, tout en minimisant la quantité de code et les bugs.
|
||||
* Si on compare Uvicorn, il faut le comparer à d'autres serveurs d'applications comme Daphne, Hypercorn, uWSGI, etc.
|
||||
* **Starlette** :
|
||||
* Aura la deuxième meilleure performance, après Uvicorn. En fait, Starlette utilise Uvicorn pour s’exécuter. Donc, il ne peut probablement être que «plus lent» qu’Uvicorn, puisqu’il doit exécuter plus de code.
|
||||
* Mais il fournit les outils pour construire des applications web simples, avec un routage basé sur les chemins, etc.
|
||||
* Si vous comparez Starlette, comparez‑le à Sanic, Flask, Django, etc. Des frameworks web (ou microframeworks).
|
||||
* A les secondes meilleures performances après Uvicorn. En réalité, Starlette utilise Uvicorn. De ce fait, il ne peut qu’être plus « lent » qu'Uvicorn car il requiert l'exécution de plus de code.
|
||||
* Cependant, il apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc.
|
||||
* Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou microframeworks) comme Sanic, Flask, Django, etc.
|
||||
* **FastAPI** :
|
||||
* De la même manière que Starlette utilise Uvicorn et ne peut pas être plus rapide que lui, **FastAPI** utilise Starlette, il ne peut donc pas être plus rapide que lui.
|
||||
* FastAPI apporte davantage de fonctionnalités au‑dessus de Starlette. Des fonctionnalités dont vous avez presque toujours besoin lors de la création d’API, comme la validation des données et la sérialisation. Et en l’utilisant, vous obtenez gratuitement une documentation automatique (la documentation automatique n’ajoute même pas de surcharge aux applications en cours d’exécution, elle est générée au démarrage).
|
||||
* Si vous n’utilisiez pas FastAPI et utilisiez directement Starlette (ou un autre outil, comme Sanic, Flask, Responder, etc.), vous devriez implémenter vous‑même toute la validation et la sérialisation des données. Ainsi, votre application finale aurait tout de même la même surcharge que si elle avait été construite avec FastAPI. Et, dans de nombreux cas, cette validation et cette sérialisation des données représentent la plus grande quantité de code écrite dans les applications.
|
||||
* Donc, en utilisant FastAPI, vous gagnez du temps de développement, réduisez les bugs, diminuez le nombre de lignes de code, et vous obtiendrez probablement les mêmes performances (ou de meilleures) que si vous ne l’utilisiez pas (car vous auriez à tout implémenter dans votre code).
|
||||
* Si vous comparez FastAPI, comparez‑le à un framework (ou un ensemble d’outils) d’applications web qui fournit la validation des données, la sérialisation et la documentation, comme Flask‑apispec, NestJS, Molten, etc. Des frameworks avec validation des données, sérialisation et documentation automatiques intégrées.
|
||||
* Comme Starlette utilise Uvicorn et ne peut donc pas être plus rapide que lui, **FastAPI** utilise Starlette et ne peut donc pas être plus rapide que lui.
|
||||
* FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités dont vous avez presque toujours besoin lors de la création d'une API, comme la validation des données et la sérialisation. En l'utilisant, vous obtenez une documentation automatique « gratuitement » (la documentation automatique n'ajoute même pas de surcharge à l’exécution, elle est générée au démarrage).
|
||||
* Si on n'utilisait pas FastAPI mais directement Starlette (ou un autre outil comme Sanic, Flask, Responder, etc.), il faudrait implémenter toute la validation des données et la sérialisation soi‑même. L'application finale aurait donc la même surcharge que si elle avait été construite avec FastAPI. Et dans de nombreux cas, cette validation des données et cette sérialisation représentent la plus grande quantité de code écrite dans les applications.
|
||||
* De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient probablement les mêmes performances (voire de meilleures performances) que l'on aurait pu avoir sans ce framework (car il aurait fallu tout implémenter dans votre code).
|
||||
* Si on compare FastAPI, il faut le comparer à d'autres frameworks d’application web (ou ensembles d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc. Des frameworks avec validation des données, sérialisation et documentation automatiques intégrées.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# FastAPI dans des conteneurs - Docker { #fastapi-in-containers-docker }
|
||||
|
||||
Lors du déploiement d'applications FastAPI, une approche courante consiste à construire une **image de conteneur Linux**. C'est généralement fait avec <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Vous pouvez ensuite déployer cette image de conteneur de plusieurs manières possibles.
|
||||
Lors du déploiement d'applications FastAPI, une approche courante consiste à construire une **image de conteneur Linux**. C'est généralement fait avec <a href="https://www.docker.com/" class="external-link" target="_blank">**Docker**</a>. Vous pouvez ensuite déployer cette image de conteneur de plusieurs façons possibles.
|
||||
|
||||
L'utilisation de conteneurs Linux présente plusieurs avantages, notamment la **sécurité**, la **réplicabilité**, la **simplicité**, et d'autres.
|
||||
L'utilisation de conteneurs Linux présente plusieurs avantages, notamment la **sécurité**, la **réplicabilité**, la **simplicité**, entre autres.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pressé et vous connaissez déjà tout ça ? Passez au [`Dockerfile` ci-dessous 👇](#build-a-docker-image-for-fastapi).
|
||||
Vous êtes pressé et vous connaissez déjà tout ça ? Allez directement au [`Dockerfile` ci-dessous 👇](#build-a-docker-image-for-fastapi).
|
||||
|
||||
///
|
||||
|
||||
@@ -34,93 +34,93 @@ CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
|
||||
## Qu'est-ce qu'un conteneur { #what-is-a-container }
|
||||
|
||||
Les conteneurs (principalement les conteneurs Linux) sont une manière très **légère** d'emballer des applications, y compris toutes leurs dépendances et fichiers nécessaires, tout en les gardant isolées des autres conteneurs (autres applications ou composants) dans le même système.
|
||||
Les conteneurs (principalement les conteneurs Linux) sont un moyen très **léger** d'empaqueter des applications, y compris toutes leurs dépendances et les fichiers nécessaires, tout en les isolant des autres conteneurs (autres applications ou composants) dans le même système.
|
||||
|
||||
Les conteneurs Linux s'exécutent en utilisant le même noyau Linux que l’hôte (machine, machine virtuelle, serveur cloud, etc.). Cela signifie simplement qu’ils sont très légers (comparés aux machines virtuelles complètes qui émuleraient un système d’exploitation entier).
|
||||
Les conteneurs Linux s'exécutent en utilisant le même noyau Linux que l'hôte (machine, machine virtuelle, serveur cloud, etc.). Cela signifie simplement qu'ils sont très légers (comparés à des machines virtuelles complètes émulant un système d'exploitation entier).
|
||||
|
||||
De cette façon, les conteneurs consomment **peu de ressources**, une quantité comparable à l’exécution des processus directement (une machine virtuelle consommerait bien plus).
|
||||
Ainsi, les conteneurs consomment **peu de ressources**, une quantité comparable à l'exécution directe des processus (alors qu'une machine virtuelle consommerait beaucoup plus).
|
||||
|
||||
Les conteneurs ont également leurs **processus isolés** (généralement un seul processus), leur système de fichiers et leur réseau, ce qui simplifie le déploiement, la sécurité, le développement, etc.
|
||||
Les conteneurs ont également leurs propres processus d'exécution **isolés** (généralement un seul processus), leur système de fichiers et leur réseau, ce qui simplifie le déploiement, la sécurité, le développement, etc.
|
||||
|
||||
## Qu'est-ce qu'une image de conteneur { #what-is-a-container-image }
|
||||
|
||||
Un **conteneur** est exécuté à partir d’une **image de conteneur**.
|
||||
Un **conteneur** s'exécute à partir d'une **image de conteneur**.
|
||||
|
||||
Une image de conteneur est une version **statique** de tous les fichiers, variables d’environnement et de la commande/programme par défaut qui doivent être présents dans un conteneur. **Statique** signifie ici que l’**image** du conteneur n’est pas en cours d’exécution, elle n’est pas exécutée, ce sont uniquement les fichiers et métadonnées empaquetés.
|
||||
Une image de conteneur est une version **statique** de tous les fichiers, des variables d'environnement et de la commande/le programme par défaut devant être présents dans un conteneur. Ici, **statique** signifie que l'**image** du conteneur ne s'exécute pas, elle n'est pas en cours d'exécution, ce ne sont que les fichiers et métadonnées empaquetés.
|
||||
|
||||
Par opposition à une «**image de conteneur**» qui est le contenu statique stocké, un «**conteneur**» fait normalement référence à l’instance en cours d’exécution, la chose qui est **exécutée**.
|
||||
Par opposition à une « **image de conteneur** » qui correspond aux contenus statiques stockés, un « **conteneur** » fait normalement référence à l'instance en cours d'exécution, la chose qui est **exécutée**.
|
||||
|
||||
Lorsque le **conteneur** est démarré et en cours d’exécution (démarré à partir d’une **image de conteneur**), il peut créer ou modifier des fichiers, des variables d’environnement, etc. Ces changements n’existeront que dans ce conteneur, mais ne persisteront pas dans l’image de conteneur sous-jacente (ils ne seront pas sauvegardés sur le disque).
|
||||
Lorsque le **conteneur** est démarré et en cours d'exécution (démarré à partir d'une **image de conteneur**), il peut créer ou modifier des fichiers, des variables d'environnement, etc. Ces changements n'existeront que dans ce conteneur, mais ne persisteront pas dans l'image de conteneur sous-jacente (ils ne seront pas enregistrés sur le disque).
|
||||
|
||||
Une image de conteneur est comparable au **programme** et à ses fichiers, par exemple `python` et un fichier `main.py`.
|
||||
Une image de conteneur est comparable au **programme** et à ses contenus, par exemple `python` et un fichier `main.py`.
|
||||
|
||||
Et le **conteneur** lui-même (par opposition à l’**image de conteneur**) est l’instance réellement en cours d’exécution de l’image, comparable à un **processus**. En fait, un conteneur n’est en cours d’exécution que lorsqu’il a un **processus en cours** (et normalement un seul processus). Le conteneur s’arrête lorsqu’il n’y a plus de processus en cours à l’intérieur.
|
||||
Et le **conteneur** lui-même (par opposition à l'**image de conteneur**) est l'instance en cours d'exécution réelle de l'image, comparable à un **processus**. En fait, un conteneur ne fonctionne que lorsqu'il a un **processus en cours d'exécution** (et normalement, il s'agit d'un seul processus). Le conteneur s'arrête lorsqu'aucun processus n'y est en cours d'exécution.
|
||||
|
||||
## Images de conteneur { #container-images }
|
||||
|
||||
Docker a été l’un des principaux outils pour créer et gérer des **images de conteneur** et des **conteneurs**.
|
||||
Docker a été l'un des principaux outils pour créer et gérer des **images de conteneur** et des **conteneurs**.
|
||||
|
||||
Il existe un <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> public avec des **images de conteneur officielles** préconstruites pour de nombreux outils, environnements, bases de données et applications.
|
||||
Et il existe un <a href="https://hub.docker.com/" class="external-link" target="_blank">Docker Hub</a> public avec des **images de conteneur officielles** pré-construites pour de nombreux outils, environnements, bases de données et applications.
|
||||
|
||||
Par exemple, il existe une <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">image Python</a> officielle.
|
||||
Par exemple, il existe une <a href="https://hub.docker.com/_/python" class="external-link" target="_blank">image Python officielle</a>.
|
||||
|
||||
Et il existe de nombreuses autres images pour différentes choses comme des bases de données, par exemple pour :
|
||||
Et il existe beaucoup d'autres images pour différentes choses comme des bases de données, par exemple :
|
||||
|
||||
* <a href="https://hub.docker.com/_/postgres" class="external-link" target="_blank">PostgreSQL</a>
|
||||
* <a href="https://hub.docker.com/_/mysql" class="external-link" target="_blank">MySQL</a>
|
||||
* <a href="https://hub.docker.com/_/mongo" class="external-link" target="_blank">MongoDB</a>
|
||||
* <a href="https://hub.docker.com/_/redis" class="external-link" target="_blank">Redis</a>, etc.
|
||||
|
||||
En utilisant une image de conteneur préconstruite, il est très facile de **combiner** et d’utiliser différents outils. Par exemple, pour essayer une nouvelle base de données. Dans la plupart des cas, vous pouvez utiliser les **images officielles**, et simplement les configurer avec des variables d’environnement.
|
||||
En utilisant une image de conteneur pré-construite, il est très facile de **combiner** et d'utiliser différents outils. Par exemple, pour essayer une nouvelle base de données. Dans la plupart des cas, vous pouvez utiliser les **images officielles** et simplement les configurer avec des variables d'environnement.
|
||||
|
||||
De cette manière, dans de nombreux cas, vous pouvez apprendre les conteneurs et Docker et réutiliser ces connaissances avec de nombreux outils et composants différents.
|
||||
Ainsi, dans de nombreux cas, vous pouvez apprendre les conteneurs et Docker et réutiliser ces connaissances avec de nombreux outils et composants différents.
|
||||
|
||||
Ainsi, vous exécuteriez **plusieurs conteneurs** avec différentes choses, comme une base de données, une application Python, un serveur web avec une application frontend React, et vous les connecteriez ensemble via leur réseau interne.
|
||||
Vous exécuteriez donc **plusieurs conteneurs** avec des éléments différents, comme une base de données, une application Python, un serveur web avec une application frontend React, et les connecter entre eux via leur réseau interne.
|
||||
|
||||
Tous les systèmes de gestion de conteneurs (comme Docker ou Kubernetes) intègrent ces fonctionnalités réseau.
|
||||
Tous les systèmes de gestion de conteneurs (comme Docker ou Kubernetes) disposent de ces fonctionnalités réseau intégrées.
|
||||
|
||||
## Conteneurs et processus { #containers-and-processes }
|
||||
|
||||
Une **image de conteneur** inclut normalement dans ses métadonnées le programme ou la commande par défaut à exécuter lorsque le **conteneur** est démarré et les paramètres à passer à ce programme. Très similaire à ce que vous feriez en ligne de commande.
|
||||
Une **image de conteneur** inclut normalement dans ses métadonnées le programme/la commande par défaut à exécuter lorsque le **conteneur** est démarré et les paramètres à transmettre à ce programme. Très similaire à ce que vous utiliseriez en ligne de commande.
|
||||
|
||||
Lorsqu’un **conteneur** est démarré, il exécute cette commande/ce programme (bien que vous puissiez la/le remplacer et faire exécuter une commande/un programme différent).
|
||||
Lorsqu'un **conteneur** est démarré, il exécutera cette commande/ce programme (bien que vous puissiez la/le remplacer et faire exécuter une autre commande/un autre programme).
|
||||
|
||||
Un conteneur est en cours d’exécution tant que le **processus principal** (commande ou programme) est en cours d’exécution.
|
||||
Un conteneur fonctionne tant que le **processus principal** (commande ou programme) est en cours d'exécution.
|
||||
|
||||
Un conteneur a normalement un **seul processus**, mais il est également possible de démarrer des sous-processus à partir du processus principal, et ainsi vous aurez **plusieurs processus** dans le même conteneur.
|
||||
Un conteneur a normalement un **seul processus**, mais il est aussi possible de démarrer des sous-processus à partir du processus principal, et ainsi vous aurez **plusieurs processus** dans le même conteneur.
|
||||
|
||||
Mais il n’est pas possible d’avoir un conteneur en cours d’exécution sans **au moins un processus en cours**. Si le processus principal s’arrête, le conteneur s’arrête.
|
||||
Mais il n'est pas possible d'avoir un conteneur en cours d'exécution sans **au moins un processus en cours**. Si le processus principal s'arrête, le conteneur s'arrête.
|
||||
|
||||
## Construire une image Docker pour FastAPI { #build-a-docker-image-for-fastapi }
|
||||
|
||||
D’accord, construisons quelque chose maintenant ! 🚀
|
||||
Très bien, construisons quelque chose maintenant ! 🚀
|
||||
|
||||
Je vais vous montrer comment construire une **image Docker** pour FastAPI **depuis zéro**, basée sur l’image **Python officielle**.
|
||||
Je vais vous montrer comment construire une **image Docker** pour FastAPI **à partir de zéro**, basée sur l'image **officielle Python**.
|
||||
|
||||
C’est ce que vous voudrez faire dans **la plupart des cas**, par exemple :
|
||||
C'est ce que vous voudrez faire dans **la plupart des cas**, par exemple :
|
||||
|
||||
* En utilisant **Kubernetes** ou des outils similaires
|
||||
* Lors de l’exécution sur un **Raspberry Pi**
|
||||
* En utilisant un service cloud qui exécuterait une image de conteneur pour vous, etc.
|
||||
* Utiliser **Kubernetes** ou des outils similaires
|
||||
* Exécuter sur un **Raspberry Pi**
|
||||
* Utiliser un service cloud qui exécuterait une image de conteneur pour vous, etc.
|
||||
|
||||
### Dépendances des packages { #package-requirements }
|
||||
### Dépendances des paquets { #package-requirements }
|
||||
|
||||
Vous avez normalement les **dépendances** de votre application dans un fichier.
|
||||
Vous aurez normalement les **dépendances des paquets** de votre application dans un fichier.
|
||||
|
||||
Cela dépend principalement de l’outil que vous utilisez pour **installer** ces dépendances.
|
||||
Cela dépendra principalement de l'outil que vous utilisez pour **installer** ces dépendances.
|
||||
|
||||
La manière la plus courante de le faire est d’avoir un fichier `requirements.txt` avec les noms des packages et leurs versions, un par ligne.
|
||||
La manière la plus courante consiste à avoir un fichier `requirements.txt` avec les noms des paquets et leurs versions, un par ligne.
|
||||
|
||||
Vous utiliseriez bien sûr les mêmes idées lues dans [À propos des versions de FastAPI](versions.md){.internal-link target=_blank} pour définir les plages de versions.
|
||||
Vous utiliserez bien sûr les mêmes idées que vous avez lues dans [À propos des versions de FastAPI](versions.md){.internal-link target=_blank} pour définir les plages de versions.
|
||||
|
||||
Par exemple, votre `requirements.txt` pourrait ressembler à :
|
||||
Par exemple, votre `requirements.txt` pourrait ressembler à :
|
||||
|
||||
```
|
||||
fastapi[standard]>=0.113.0,<0.114.0
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
```
|
||||
|
||||
Et vous installeriez normalement ces dépendances de packages avec `pip`, par exemple :
|
||||
Et vous installerez normalement ces dépendances de paquets avec `pip`, par exemple :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -134,7 +134,7 @@ Successfully installed fastapi pydantic
|
||||
|
||||
/// info
|
||||
|
||||
Il existe d’autres formats et outils pour définir et installer des dépendances de packages.
|
||||
Il existe d'autres formats et outils pour définir et installer des dépendances de paquets.
|
||||
|
||||
///
|
||||
|
||||
@@ -142,11 +142,9 @@ Il existe d’autres formats et outils pour définir et installer des dépendanc
|
||||
|
||||
* Créez un répertoire `app` et entrez dedans.
|
||||
* Créez un fichier vide `__init__.py`.
|
||||
* Créez un fichier `main.py` avec :
|
||||
* Créez un fichier `main.py` avec :
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -158,13 +156,13 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
### Dockerfile { #dockerfile }
|
||||
|
||||
Maintenant, dans le même répertoire de projet, créez un fichier `Dockerfile` avec :
|
||||
Maintenant, dans le même répertoire de projet, créez un fichier `Dockerfile` avec :
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
# (1)!
|
||||
@@ -186,45 +184,45 @@ COPY ./app /code/app
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
1. Démarrer à partir de l’image de base Python officielle.
|
||||
1. Démarrer à partir de l'image de base Python officielle.
|
||||
|
||||
2. Définir le répertoire de travail courant sur `/code`.
|
||||
|
||||
C’est là que nous placerons le fichier `requirements.txt` et le répertoire `app`.
|
||||
C'est là que nous placerons le fichier `requirements.txt` et le répertoire `app`.
|
||||
|
||||
3. Copier le fichier des dépendances dans le répertoire `/code`.
|
||||
3. Copier le fichier des dépendances vers le répertoire `/code`.
|
||||
|
||||
Copier **uniquement** le fichier des dépendances en premier, pas le reste du code.
|
||||
|
||||
Comme ce fichier **ne change pas souvent**, Docker le détectera et utilisera le **cache** pour cette étape, activant aussi le cache pour l’étape suivante.
|
||||
Comme ce fichier **ne change pas souvent**, Docker le détectera et utilisera le **cache** pour cette étape, ce qui activera le cache pour l'étape suivante aussi.
|
||||
|
||||
4. Installer les dépendances de packages du fichier des dépendances.
|
||||
4. Installer les dépendances listées dans le fichier des dépendances.
|
||||
|
||||
L’option `--no-cache-dir` indique à `pip` de ne pas enregistrer localement les packages téléchargés, ce qui n’est utile que si `pip` devait être relancé pour installer les mêmes packages, ce qui n’est pas le cas lorsqu’on travaille avec des conteneurs.
|
||||
L'option `--no-cache-dir` indique à `pip` de ne pas enregistrer localement les paquets téléchargés, car cela ne sert que si `pip` devait être relancé pour installer les mêmes paquets, mais ce n'est pas le cas lorsque l'on travaille avec des conteneurs.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Le `--no-cache-dir` concerne uniquement `pip`, cela n’a rien à voir avec Docker ou les conteneurs.
|
||||
Le `--no-cache-dir` concerne uniquement `pip`, cela n'a rien à voir avec Docker ou les conteneurs.
|
||||
|
||||
///
|
||||
|
||||
L’option `--upgrade` indique à `pip` de mettre à niveau les packages s’ils sont déjà installés.
|
||||
L'option `--upgrade` indique à `pip` de mettre à niveau les paquets s'ils sont déjà installés.
|
||||
|
||||
Comme l’étape précédente de copie du fichier peut être détectée par le **cache Docker**, cette étape **utilisera également le cache Docker** lorsqu’il est disponible.
|
||||
Comme l'étape précédente de copie du fichier peut être détectée par le **cache Docker**, cette étape **utilisera également le cache Docker** lorsqu'il est disponible.
|
||||
|
||||
Utiliser le cache à cette étape vous fera **gagner** beaucoup de **temps** lors de la reconstruction de l’image à maintes reprises pendant le développement, au lieu de **télécharger et installer** toutes les dépendances **à chaque fois**.
|
||||
L'utilisation du cache à cette étape vous **fera gagner** beaucoup de **temps** lors de la reconstruction de l'image encore et encore pendant le développement, au lieu de **télécharger et installer** toutes les dépendances **à chaque fois**.
|
||||
|
||||
5. Copier le répertoire `./app` dans le répertoire `/code`.
|
||||
|
||||
Comme cela contient tout le code, qui est ce qui **change le plus fréquemment**, le **cache** Docker ne sera pas facilement utilisé pour cette étape ni pour les **étapes suivantes**.
|
||||
Comme cela contient tout le code qui est ce qui **change le plus fréquemment**, le **cache** Docker ne sera pas facilement utilisé pour cette étape ou pour les **étapes suivantes**.
|
||||
|
||||
Il est donc important de mettre ceci **vers la fin** du `Dockerfile`, pour optimiser les temps de construction de l’image de conteneur.
|
||||
Il est donc important de placer cela **vers la fin** du `Dockerfile`, pour optimiser les temps de construction de l'image de conteneur.
|
||||
|
||||
6. Définir la **commande** pour utiliser `fastapi run`, qui utilise Uvicorn en dessous.
|
||||
6. Définir la **commande** pour utiliser `fastapi run`, qui utilise Uvicorn sous le capot.
|
||||
|
||||
`CMD` prend une liste de chaînes, chacune de ces chaînes est ce que vous taperiez en ligne de commande séparé par des espaces.
|
||||
`CMD` prend une liste de chaînes, chacune de ces chaînes correspond à ce que vous taperiez en ligne de commande séparé par des espaces.
|
||||
|
||||
Cette commande sera exécutée depuis le **répertoire de travail courant**, le même répertoire `/code` que vous avez défini ci-dessus avec `WORKDIR /code`.
|
||||
Cette commande sera exécutée à partir du **répertoire de travail courant**, le même répertoire `/code` que vous avez défini plus haut avec `WORKDIR /code`.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
@@ -232,39 +230,39 @@ Passez en revue ce que fait chaque ligne en cliquant sur chaque bulle numéroté
|
||||
|
||||
///
|
||||
|
||||
/// warning | Attention
|
||||
/// warning | Alertes
|
||||
|
||||
Assurez-vous d’utiliser **toujours** la **forme exec** de l’instruction `CMD`, comme expliqué ci-dessous.
|
||||
Vous devez vous assurer d'utiliser **toujours** la **forme exec** de l'instruction `CMD`, comme expliqué ci-dessous.
|
||||
|
||||
///
|
||||
|
||||
#### Utiliser `CMD` - forme Exec { #use-cmd-exec-form }
|
||||
#### Utiliser `CMD` - Forme Exec { #use-cmd-exec-form }
|
||||
|
||||
L’instruction Docker <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> peut être écrite sous deux formes :
|
||||
L'instruction Docker <a href="https://docs.docker.com/reference/dockerfile/#cmd" class="external-link" target="_blank">`CMD`</a> peut être écrite sous deux formes :
|
||||
|
||||
✅ Forme **exec** :
|
||||
✅ Forme **Exec** :
|
||||
|
||||
```Dockerfile
|
||||
# ✅ À faire
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
|
||||
```
|
||||
|
||||
⛔️ Forme **shell** :
|
||||
⛔️ Forme **Shell** :
|
||||
|
||||
```Dockerfile
|
||||
# ⛔️ À ne pas faire
|
||||
CMD fastapi run app/main.py --port 80
|
||||
```
|
||||
|
||||
Assurez-vous d’utiliser toujours la forme **exec** afin que FastAPI puisse s’arrêter proprement et que les [événements de durée de vie](../advanced/events.md){.internal-link target=_blank} soient déclenchés.
|
||||
Assurez-vous d'utiliser toujours la forme **exec** pour garantir que FastAPI peut s'arrêter proprement et que les [événements de cycle de vie](../advanced/events.md){.internal-link target=_blank} sont déclenchés.
|
||||
|
||||
Vous pouvez en lire davantage dans la <a href="https://docs.docker.com/reference/dockerfile/#shell-and-exec-form" class="external-link" target="_blank">documentation Docker sur les formes shell et exec</a>.
|
||||
|
||||
Cela peut être assez perceptible avec `docker compose`. Voir cette section de la FAQ Docker Compose pour plus de détails techniques : <a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Pourquoi mes services prennent-ils 10 secondes pour être recréés ou arrêtés ?</a>.
|
||||
Cela peut être très visible lors de l'utilisation de `docker compose`. Voir cette section de la FAQ Docker Compose pour plus de détails techniques : <a href="https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop" class="external-link" target="_blank">Pourquoi mes services mettent-ils 10 secondes à se recréer ou à s'arrêter ?</a>.
|
||||
|
||||
#### Structure des répertoires { #directory-structure }
|
||||
#### Structure du répertoire { #directory-structure }
|
||||
|
||||
Vous devriez maintenant avoir une structure de répertoires comme :
|
||||
Vous devriez maintenant avoir une structure de répertoire comme :
|
||||
|
||||
```
|
||||
.
|
||||
@@ -277,7 +275,7 @@ Vous devriez maintenant avoir une structure de répertoires comme :
|
||||
|
||||
#### Derrière un proxy de terminaison TLS { #behind-a-tls-termination-proxy }
|
||||
|
||||
Si vous exécutez votre conteneur derrière un proxy de terminaison TLS (équilibreur de charge) comme Nginx ou Traefik, ajoutez l’option `--proxy-headers`. Cela indiquera à Uvicorn (via la CLI FastAPI) de faire confiance aux en-têtes envoyés par ce proxy lui indiquant que l’application s’exécute derrière HTTPS, etc.
|
||||
Si vous exécutez votre conteneur derrière un proxy de terminaison TLS (load balancer) comme Nginx ou Traefik, ajoutez l'option `--proxy-headers`, cela indiquera à Uvicorn (via la CLI FastAPI) de faire confiance aux en-têtes envoyés par ce proxy lui indiquant que l'application s'exécute derrière HTTPS, etc.
|
||||
|
||||
```Dockerfile
|
||||
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
@@ -285,42 +283,42 @@ CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
|
||||
|
||||
#### Cache Docker { #docker-cache }
|
||||
|
||||
Il y a une astuce importante dans ce `Dockerfile` : nous copions d’abord **le fichier des dépendances seul**, pas le reste du code. Laissez-moi vous expliquer pourquoi.
|
||||
Il y a une astuce importante dans ce `Dockerfile`, nous copions d'abord **le fichier des dépendances seul**, pas le reste du code. Laissez-moi vous expliquer pourquoi.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./requirements.txt /code/requirements.txt
|
||||
```
|
||||
|
||||
Docker et d’autres outils **construisent** ces images de conteneur **de manière incrémentale**, en ajoutant **une couche au-dessus de l’autre**, en commençant par le haut du `Dockerfile` et en ajoutant les fichiers créés par chacune des instructions du `Dockerfile`.
|
||||
Docker et d'autres outils **construisent** ces images de conteneur **de manière incrémentale**, en ajoutant **une couche au-dessus de l'autre**, en commençant par le haut du `Dockerfile` et en ajoutant tous les fichiers créés par chacune des instructions du `Dockerfile`.
|
||||
|
||||
Docker et des outils similaires utilisent également un **cache interne** lors de la construction de l’image : si un fichier n’a pas changé depuis la dernière construction, il **réutilisera la même couche** créée précédemment, au lieu de recopier le fichier et de créer une nouvelle couche à partir de zéro.
|
||||
Docker et des outils similaires utilisent également un **cache interne** lors de la construction de l'image : si un fichier n'a pas changé depuis la dernière construction de l'image de conteneur, alors il va **réutiliser la même couche** créée la dernière fois, au lieu de recopier le fichier et créer une nouvelle couche à partir de zéro.
|
||||
|
||||
Éviter simplement la copie de fichiers n’améliore pas forcément énormément les choses, mais comme le cache a été utilisé pour cette étape, il peut **être utilisé pour l’étape suivante**. Par exemple, il pourra être utilisé pour l’instruction qui installe les dépendances :
|
||||
Éviter simplement la copie des fichiers n'améliore pas nécessairement les choses de manière significative, mais comme il a utilisé le cache pour cette étape, il peut **utiliser le cache pour l'étape suivante**. Par exemple, il peut utiliser le cache pour l'instruction qui installe les dépendances avec :
|
||||
|
||||
```Dockerfile
|
||||
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
|
||||
```
|
||||
|
||||
Le fichier avec les dépendances des packages **ne changera pas fréquemment**. Ainsi, en copiant uniquement ce fichier, Docker pourra **utiliser le cache** pour cette étape.
|
||||
Le fichier des dépendances **ne changera pas fréquemment**. Ainsi, en copiant uniquement ce fichier, Docker pourra **utiliser le cache** pour cette étape.
|
||||
|
||||
Et ensuite, Docker pourra **utiliser le cache pour l’étape suivante** qui télécharge et installe ces dépendances. Et c’est là que nous **économisons beaucoup de temps**. ✨ ... et évitons l’ennui en attendant. 😪😆
|
||||
Et ensuite, Docker pourra **utiliser le cache pour l'étape suivante** qui télécharge et installe ces dépendances. Et c'est là que nous **gagnons beaucoup de temps**. ✨ ... et évitons l'ennui en attendant. 😪😆
|
||||
|
||||
Télécharger et installer les dépendances de packages **peut prendre des minutes**, alors qu’utiliser le **cache** ne **prendra que quelques secondes** au maximum.
|
||||
Télécharger et installer les dépendances de paquets **peut prendre des minutes**, mais utiliser le **cache** ne **prendra que quelques secondes** au plus.
|
||||
|
||||
Et comme vous reconstruirez l’image de conteneur encore et encore pendant le développement pour vérifier que vos modifications de code fonctionnent, cela vous fera gagner beaucoup de temps cumulé.
|
||||
Et comme vous reconstruirez l'image de conteneur encore et encore pendant le développement pour vérifier que vos modifications de code fonctionnent, cela vous fera gagner beaucoup de temps cumulé.
|
||||
|
||||
Puis, vers la fin du `Dockerfile`, nous copions tout le code. Comme c’est ce qui **change le plus fréquemment**, nous le mettons vers la fin, car presque toujours, tout ce qui suit cette étape ne pourra pas utiliser le cache.
|
||||
Ensuite, vers la fin du `Dockerfile`, nous copions tout le code. Comme c'est ce qui **change le plus fréquemment**, nous le plaçons vers la fin, car presque toujours, tout ce qui suit cette étape ne pourra pas utiliser le cache.
|
||||
|
||||
```Dockerfile
|
||||
COPY ./app /code/app
|
||||
```
|
||||
|
||||
### Construire l’image Docker { #build-the-docker-image }
|
||||
### Construire l'image Docker { #build-the-docker-image }
|
||||
|
||||
Maintenant que tous les fichiers sont en place, construisons l’image de conteneur.
|
||||
Maintenant que tous les fichiers sont en place, construisons l'image de conteneur.
|
||||
|
||||
* Allez dans le répertoire du projet (là où se trouve votre `Dockerfile`, contenant votre répertoire `app`).
|
||||
* Construisez votre image FastAPI :
|
||||
* Construisez votre image FastAPI :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -334,15 +332,15 @@ $ docker build -t myimage .
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Remarquez le `.` à la fin, c’est équivalent à `./`, il indique à Docker le répertoire à utiliser pour construire l’image de conteneur.
|
||||
Remarquez le `.` à la fin, équivalent à `./`, il indique à Docker le répertoire à utiliser pour construire l'image de conteneur.
|
||||
|
||||
Dans ce cas, c’est le répertoire courant (`.`).
|
||||
Dans ce cas, c'est le même répertoire courant (`.`).
|
||||
|
||||
///
|
||||
|
||||
### Démarrer le conteneur Docker { #start-the-docker-container }
|
||||
|
||||
* Exécutez un conteneur basé sur votre image :
|
||||
* Exécutez un conteneur basé sur votre image :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -354,33 +352,33 @@ $ docker run -d --name mycontainer -p 80:80 myimage
|
||||
|
||||
## Vérifier { #check-it }
|
||||
|
||||
Vous devriez pouvoir le vérifier dans l’URL de votre conteneur Docker, par exemple : <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
Vous devriez pouvoir le vérifier via l'URL de votre conteneur Docker, par exemple : <a href="http://192.168.99.100/items/5?q=somequery" class="external-link" target="_blank">http://192.168.99.100/items/5?q=somequery</a> ou <a href="http://127.0.0.1/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1/items/5?q=somequery</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
|
||||
Vous verrez quelque chose comme :
|
||||
Vous verrez quelque chose comme :
|
||||
|
||||
```JSON
|
||||
{"item_id": 5, "q": "somequery"}
|
||||
```
|
||||
|
||||
## Documentation interactive de l’API { #interactive-api-docs }
|
||||
## Documentation interactive de l'API { #interactive-api-docs }
|
||||
|
||||
Vous pouvez maintenant aller sur <a href="http://192.168.99.100/docs" class="external-link" target="_blank">http://192.168.99.100/docs</a> ou <a href="http://127.0.0.1/docs" class="external-link" target="_blank">http://127.0.0.1/docs</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
|
||||
Vous verrez la documentation API interactive automatique (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
Vous verrez la documentation interactive automatique de l'API (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
|
||||

|
||||
|
||||
## Documentation API alternative { #alternative-api-docs }
|
||||
## Documentation alternative de l'API { #alternative-api-docs }
|
||||
|
||||
Et vous pouvez également aller sur <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> ou <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
Et vous pouvez aussi aller sur <a href="http://192.168.99.100/redoc" class="external-link" target="_blank">http://192.168.99.100/redoc</a> ou <a href="http://127.0.0.1/redoc" class="external-link" target="_blank">http://127.0.0.1/redoc</a> (ou équivalent, en utilisant votre hôte Docker).
|
||||
|
||||
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
|
||||

|
||||
|
||||
## Construire une image Docker avec un FastAPI monofichier { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
## Construire une image Docker avec un FastAPI mono-fichier { #build-a-docker-image-with-a-single-file-fastapi }
|
||||
|
||||
Si votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./app`, votre structure de fichiers pourrait ressembler à ceci :
|
||||
Si votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./app`, votre structure de fichiers pourrait ressembler à ceci :
|
||||
|
||||
```
|
||||
.
|
||||
@@ -389,7 +387,7 @@ Si votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
Vous n’auriez alors qu’à changer les chemins correspondants pour copier le fichier dans le `Dockerfile` :
|
||||
Vous n'auriez alors qu'à changer les chemins correspondants pour copier le fichier dans le `Dockerfile` :
|
||||
|
||||
```{ .dockerfile .annotate hl_lines="10 13" }
|
||||
FROM python:3.9
|
||||
@@ -411,38 +409,38 @@ CMD ["fastapi", "run", "main.py", "--port", "80"]
|
||||
|
||||
2. Utiliser `fastapi run` pour servir votre application dans le fichier unique `main.py`.
|
||||
|
||||
Quand vous passez le fichier à `fastapi run`, il détectera automatiquement qu’il s’agit d’un fichier unique et non d’un package et saura comment l’importer et servir votre application FastAPI. 😎
|
||||
Lorsque vous passez le fichier à `fastapi run`, il détectera automatiquement qu'il s'agit d'un fichier unique et non d'un package et saura comment l'importer et servir votre application FastAPI. 😎
|
||||
|
||||
## Concepts de déploiement { #deployment-concepts }
|
||||
|
||||
Parlons à nouveau de certains des mêmes [Concepts de déploiement](concepts.md){.internal-link target=_blank} en termes de conteneurs.
|
||||
|
||||
Les conteneurs sont principalement un outil pour simplifier le processus de **construction et de déploiement** d’une application, mais ils n’imposent pas une approche particulière pour gérer ces **concepts de déploiement**, et il existe plusieurs stratégies possibles.
|
||||
Les conteneurs sont principalement un outil pour simplifier le processus de **construction et de déploiement** d'une application, mais ils n'imposent pas une approche particulière pour gérer ces **concepts de déploiement**, et il existe plusieurs stratégies possibles.
|
||||
|
||||
La **bonne nouvelle** est qu’avec chaque stratégie différente, il existe un moyen de couvrir tous les concepts de déploiement. 🎉
|
||||
La **bonne nouvelle**, c'est qu'avec chaque stratégie différente, il existe un moyen de couvrir tous les concepts de déploiement. 🎉
|
||||
|
||||
Réexaminons ces **concepts de déploiement** en termes de conteneurs :
|
||||
Passons en revue ces **concepts de déploiement** en termes de conteneurs :
|
||||
|
||||
* HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours)
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables avant de démarrer
|
||||
* Étapes préalables au démarrage
|
||||
|
||||
## HTTPS { #https }
|
||||
|
||||
Si l’on se concentre uniquement sur **l’image de conteneur** pour une application FastAPI (et plus tard le **conteneur** en cours), HTTPS serait normalement géré **en externe** par un autre outil.
|
||||
Si l'on se concentre uniquement sur l'**image de conteneur** pour une application FastAPI (et plus tard sur le **conteneur** en cours d'exécution), HTTPS serait normalement géré **à l'extérieur** par un autre outil.
|
||||
|
||||
Cela pourrait être un autre conteneur, par exemple avec <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, gérant **HTTPS** et l’acquisition **automatique** des **certificats**.
|
||||
Cela pourrait être un autre conteneur, par exemple avec <a href="https://traefik.io/" class="external-link" target="_blank">Traefik</a>, gérant **HTTPS** et l'acquisition **automatique** des **certificats**.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Traefik a des intégrations avec Docker, Kubernetes, et d’autres, il est donc très facile de configurer HTTPS pour vos conteneurs avec lui.
|
||||
Traefik s'intègre avec Docker, Kubernetes, et d'autres, donc il est très facile de configurer HTTPS pour vos conteneurs avec lui.
|
||||
|
||||
///
|
||||
|
||||
Alternativement, HTTPS pourrait être géré par un fournisseur cloud comme l’un de leurs services (tout en exécutant l’application dans un conteneur).
|
||||
Alternativement, HTTPS pourrait être géré par un fournisseur cloud comme l'un de leurs services (tout en exécutant l'application dans un conteneur).
|
||||
|
||||
## Exécution au démarrage et redémarrages { #running-on-startup-and-restarts }
|
||||
|
||||
@@ -450,55 +448,55 @@ Il y a normalement un autre outil chargé de **démarrer et exécuter** votre co
|
||||
|
||||
Cela pourrait être **Docker** directement, **Docker Compose**, **Kubernetes**, un **service cloud**, etc.
|
||||
|
||||
Dans la plupart (ou toutes) les situations, il y a une option simple pour activer l’exécution du conteneur au démarrage et les redémarrages en cas d’échec. Par exemple, dans Docker, c’est l’option de ligne de commande `--restart`.
|
||||
Dans la plupart (ou toutes) des situations, il existe une option simple pour activer l'exécution du conteneur au démarrage et activer les redémarrages en cas d'échec. Par exemple, dans Docker, c'est l'option de ligne de commande `--restart`.
|
||||
|
||||
Sans utiliser les conteneurs, faire en sorte que les applications s’exécutent au démarrage et avec redémarrages peut être fastidieux et difficile. Mais en **travaillant avec des conteneurs**, dans la plupart des cas, cette fonctionnalité est incluse par défaut. ✨
|
||||
Sans utiliser de conteneurs, faire en sorte que les applications s'exécutent au démarrage et avec redémarrages peut être fastidieux et difficile. Mais en **travaillant avec des conteneurs**, dans la plupart des cas, cette fonctionnalité est incluse par défaut. ✨
|
||||
|
||||
## Réplication - Nombre de processus { #replication-number-of-processes }
|
||||
|
||||
Si vous avez un <abbr title="Un groupe de machines configurées pour être connectées et travailler ensemble d'une certaine manière.">cluster</abbr> de machines avec **Kubernetes**, Docker Swarm Mode, Nomad, ou un autre système complexe similaire pour gérer des conteneurs distribués sur plusieurs machines, alors vous voudrez probablement **gérer la réplication** au **niveau du cluster** plutôt que d’utiliser un **gestionnaire de processus** (comme Uvicorn avec des workers) dans chaque conteneur.
|
||||
Si vous avez un <abbr title="Un groupe de machines configurées pour être connectées et fonctionner ensemble d'une certaine manière.">cluster</abbr> de machines avec **Kubernetes**, Docker Swarm Mode, Nomad, ou un autre système complexe similaire pour gérer des conteneurs distribués sur plusieurs machines, alors vous voudrez probablement **gérer la réplication** au **niveau du cluster** plutôt que d'utiliser un **gestionnaire de processus** (comme Uvicorn avec workers) dans chaque conteneur.
|
||||
|
||||
L’un de ces systèmes de gestion de conteneurs distribués, comme Kubernetes, dispose normalement d’un moyen intégré de gérer la **réplication des conteneurs** tout en prenant en charge **l’équilibrage de charge** pour les requêtes entrantes. Tout cela au **niveau du cluster**.
|
||||
L'un de ces systèmes de gestion de conteneurs distribués comme Kubernetes dispose normalement d'une manière intégrée de gérer la **réplication des conteneurs** tout en supportant l'**équilibrage de charge** des requêtes entrantes. Le tout au **niveau du cluster**.
|
||||
|
||||
Dans ces cas, vous voudrez probablement construire une **image Docker depuis zéro** comme [expliqué ci-dessus](#dockerfile), en installant vos dépendances, et en exécutant **un seul processus Uvicorn** au lieu d’utiliser plusieurs workers Uvicorn.
|
||||
Dans ces cas, vous voudrez probablement construire une **image Docker à partir de zéro** comme [expliqué ci-dessus](#dockerfile), en installant vos dépendances et en exécutant **un seul processus Uvicorn** au lieu d'utiliser plusieurs workers Uvicorn.
|
||||
|
||||
### Équilibreur de charge { #load-balancer }
|
||||
|
||||
Avec les conteneurs, vous avez normalement un composant **à l’écoute sur le port principal**. Il pourrait s’agir d’un autre conteneur qui est également un **proxy de terminaison TLS** pour gérer **HTTPS**, ou d’un outil similaire.
|
||||
Lors de l'utilisation de conteneurs, vous aurez normalement un composant **à l'écoute sur le port principal**. Cela pourrait être un autre conteneur qui est également un **proxy de terminaison TLS** pour gérer **HTTPS** ou un outil similaire.
|
||||
|
||||
Comme ce composant prend la **charge** des requêtes et les distribue entre les workers de façon (espérons-le) **équilibrée**, on l’appelle aussi couramment un **équilibreur de charge**.
|
||||
Comme ce composant prend la **charge** des requêtes et la distribue entre les workers de façon (espérons-le) **équilibrée**, on l'appelle également communément un **équilibreur de charge**.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le même composant **proxy de terminaison TLS** utilisé pour HTTPS sera probablement aussi un **équilibreur de charge**.
|
||||
Le même composant de **proxy de terminaison TLS** utilisé pour HTTPS sera probablement aussi un **équilibreur de charge**.
|
||||
|
||||
///
|
||||
|
||||
Et en travaillant avec des conteneurs, le même système que vous utilisez pour les démarrer et les gérer disposera déjà d’outils internes pour transmettre la **communication réseau** (par ex. les requêtes HTTP) depuis cet **équilibreur de charge** (qui peut également être un **proxy de terminaison TLS**) vers le ou les conteneurs avec votre application.
|
||||
Et en travaillant avec des conteneurs, le même système que vous utilisez pour les démarrer et les gérer dispose déjà d'outils internes pour transmettre la **communication réseau** (par ex. les requêtes HTTP) depuis cet **équilibreur de charge** (qui peut aussi être un **proxy de terminaison TLS**) vers le ou les conteneurs avec votre application.
|
||||
|
||||
### Un équilibreur de charge - plusieurs conteneurs worker { #one-load-balancer-multiple-worker-containers }
|
||||
### Un équilibreur de charge - Plusieurs conteneurs worker { #one-load-balancer-multiple-worker-containers }
|
||||
|
||||
Avec **Kubernetes** ou des systèmes de gestion de conteneurs distribués similaires, l’utilisation de leurs mécanismes réseau internes permet au **seul** équilibreur de charge qui écoute sur le **port** principal de transmettre la communication (les requêtes) vers **plusieurs conteneurs** exécutant votre application.
|
||||
Lorsque vous travaillez avec **Kubernetes** ou des systèmes de gestion de conteneurs distribués similaires, l'utilisation de leurs mécanismes réseau internes permet au **seul équilibreur de charge** à l'écoute sur le **port** principal de transmettre la communication (les requêtes) vers potentiellement **plusieurs conteneurs** exécutant votre application.
|
||||
|
||||
Chacun de ces conteneurs exécutant votre application aura normalement **un seul processus** (par ex. un processus Uvicorn exécutant votre application FastAPI). Ils seront tous des **conteneurs identiques**, exécutant la même chose, mais chacun avec son propre processus, sa propre mémoire, etc. De cette manière, vous profitez de la **parallélisation** sur **différents cœurs** du CPU, voire sur **différentes machines**.
|
||||
Chacun de ces conteneurs exécutant votre application aura normalement **un seul processus** (par ex. un processus Uvicorn exécutant votre application FastAPI). Ils seront tous des **conteneurs identiques**, exécutant la même chose, mais chacun avec son propre processus, sa mémoire, etc. De cette façon, vous profiterez de la **parallélisation** sur **différents cœurs** du CPU, voire sur **différentes machines**.
|
||||
|
||||
Et le système de conteneurs distribué avec l’**équilibreur de charge** **distribuera les requêtes** à chacun des conteneurs exécutant votre application **à tour de rôle**. Ainsi, chaque requête pourra être traitée par l’un des **conteneurs répliqués** exécutant votre application.
|
||||
Et le système de conteneurs distribués avec l'**équilibreur de charge** **distribuera les requêtes** à chacun des conteneurs exécutant votre application **à tour de rôle**. Ainsi, chaque requête pourrait être traitée par l'un des multiples **conteneurs répliqués** exécutant votre application.
|
||||
|
||||
Et normalement, cet **équilibreur de charge** sera capable de gérer les requêtes qui vont vers *d’autres* applications de votre cluster (par ex. vers un autre domaine, ou sous un autre préfixe de chemin d’URL), et transmettra cette communication aux bons conteneurs pour *cette autre* application s’exécutant dans votre cluster.
|
||||
Et normalement cet **équilibreur de charge** pourra gérer des requêtes qui vont vers *d'autres* applications dans votre cluster (par ex. vers un autre domaine, ou sous un autre préfixe de chemin d'URL), et transmettra cette communication aux bons conteneurs pour *cette autre* application s'exécutant dans votre cluster.
|
||||
|
||||
### Un processus par conteneur { #one-process-per-container }
|
||||
|
||||
Dans ce type de scénario, vous voudrez probablement avoir **un seul processus (Uvicorn) par conteneur**, car vous gérez déjà la réplication au niveau du cluster.
|
||||
Dans ce type de scénario, vous voudrez probablement avoir **un seul processus (Uvicorn) par conteneur**, puisque vous gérez déjà la réplication au niveau du cluster.
|
||||
|
||||
Dans ce cas, vous ne voudrez **pas** avoir plusieurs workers dans le conteneur, par exemple avec l’option de ligne de commande `--workers`. Vous voudrez avoir simplement **un seul processus Uvicorn** par conteneur (mais probablement plusieurs conteneurs).
|
||||
Donc, dans ce cas, vous **ne voudrez pas** avoir plusieurs workers dans le conteneur, par exemple avec l'option de ligne de commande `--workers`. Vous voudrez avoir **un seul processus Uvicorn** par conteneur (mais probablement plusieurs conteneurs).
|
||||
|
||||
Avoir un autre gestionnaire de processus dans le conteneur (comme ce serait le cas avec plusieurs workers) ne ferait qu’ajouter une **complexité inutile** que votre système de cluster gère très probablement déjà.
|
||||
Avoir un autre gestionnaire de processus à l'intérieur du conteneur (comme ce serait le cas avec plusieurs workers) n'ajouterait que de la **complexité inutile** que vous gérez très probablement déjà avec votre système de cluster.
|
||||
|
||||
### Conteneurs avec plusieurs processus et cas particuliers { #containers-with-multiple-processes-and-special-cases }
|
||||
|
||||
Bien sûr, il existe des **cas particuliers** où vous pourriez vouloir avoir **un conteneur** avec plusieurs **processus worker Uvicorn** à l’intérieur.
|
||||
Bien sûr, il existe des **cas particuliers** où vous pourriez vouloir avoir **un conteneur** avec plusieurs **processus worker Uvicorn** à l'intérieur.
|
||||
|
||||
Dans ces cas, vous pouvez utiliser l’option de ligne de commande `--workers` pour définir le nombre de workers que vous souhaitez exécuter :
|
||||
Dans ces cas, vous pouvez utiliser l'option de ligne de commande `--workers` pour définir le nombre de workers que vous souhaitez exécuter :
|
||||
|
||||
```{ .dockerfile .annotate }
|
||||
FROM python:3.9
|
||||
@@ -515,106 +513,106 @@ COPY ./app /code/app
|
||||
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
|
||||
```
|
||||
|
||||
1. Ici, nous utilisons l’option de ligne de commande `--workers` pour définir le nombre de workers à 4.
|
||||
1. Ici, nous utilisons l'option de ligne de commande `--workers` pour définir le nombre de workers à 4.
|
||||
|
||||
Voici quelques exemples où cela peut avoir du sens :
|
||||
Voici quelques exemples où cela pourrait avoir du sens :
|
||||
|
||||
#### Une application simple { #a-simple-app }
|
||||
|
||||
Vous pourriez vouloir un gestionnaire de processus dans le conteneur si votre application est **suffisamment simple** pour s’exécuter sur un **seul serveur**, et non un cluster.
|
||||
Vous pourriez vouloir un gestionnaire de processus dans le conteneur si votre application est **suffisamment simple** pour s'exécuter sur un **seul serveur**, pas un cluster.
|
||||
|
||||
#### Docker Compose { #docker-compose }
|
||||
|
||||
Vous pourriez déployer sur un **seul serveur** (pas un cluster) avec **Docker Compose**, vous n’auriez donc pas un moyen simple de gérer la réplication de conteneurs (avec Docker Compose) tout en conservant le réseau partagé et **l’équilibrage de charge**.
|
||||
Vous pourriez déployer sur un **seul serveur** (pas un cluster) avec **Docker Compose**, donc vous n'auriez pas un moyen simple de gérer la réplication des conteneurs (avec Docker Compose) tout en préservant le réseau partagé et l'**équilibrage de charge**.
|
||||
|
||||
Vous pourriez alors vouloir avoir **un seul conteneur** avec un **gestionnaire de processus** démarrant **plusieurs processus worker** à l’intérieur.
|
||||
Vous pourriez alors vouloir avoir **un seul conteneur** avec un **gestionnaire de processus** qui démarre **plusieurs processus worker** à l'intérieur.
|
||||
|
||||
---
|
||||
|
||||
L’idée principale est qu’**aucune** de ces approches n’est **gravée dans la pierre** que vous devez suivre aveuglément. Vous pouvez utiliser ces idées pour **évaluer votre propre cas d’utilisation** et décider de la meilleure approche pour votre système, en vérifiant comment gérer les concepts :
|
||||
L'idée principale est que **rien** de tout cela ne sont des **règles gravées dans la pierre** que vous devez suivre aveuglément. Vous pouvez utiliser ces idées pour **évaluer votre propre cas d'usage** et décider de la meilleure approche pour votre système, en vérifiant comment gérer les concepts suivants :
|
||||
|
||||
* Sécurité - HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours)
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables avant de démarrer
|
||||
* Étapes préalables au démarrage
|
||||
|
||||
## Mémoire { #memory }
|
||||
|
||||
Si vous exécutez **un seul processus par conteneur**, vous aurez une quantité de mémoire consommée plus ou moins bien définie, stable et limitée par chacun de ces conteneurs (plus d’un s’ils sont répliqués).
|
||||
Si vous exécutez **un seul processus par conteneur**, vous aurez une quantité de mémoire consommée plus ou moins bien définie, stable et limitée par chacun de ces conteneurs (plus d'un s'ils sont répliqués).
|
||||
|
||||
Vous pourrez ensuite définir ces mêmes limites et exigences de mémoire dans vos configurations pour votre système de gestion de conteneurs (par exemple dans **Kubernetes**). Ainsi, il pourra **répliquer les conteneurs** sur les **machines disponibles** en tenant compte de la quantité de mémoire nécessaire pour eux et de la quantité disponible sur les machines du cluster.
|
||||
Vous pouvez alors définir ces mêmes limites et exigences de mémoire dans vos configurations pour votre système de gestion de conteneurs (par exemple dans **Kubernetes**). De cette façon, il pourra **répliquer les conteneurs** sur les **machines disponibles** en tenant compte de la quantité de mémoire dont ils ont besoin et de la quantité disponible sur les machines du cluster.
|
||||
|
||||
Si votre application est **simple**, cela ne sera probablement **pas un problème**, et vous n’aurez peut-être pas besoin de spécifier des limites strictes de mémoire. Mais si vous **utilisez beaucoup de mémoire** (par exemple avec des modèles de **machine learning**), vous devriez vérifier la quantité de mémoire que vous consommez et ajuster le **nombre de conteneurs** exécutés sur **chaque machine** (et peut-être ajouter davantage de machines à votre cluster).
|
||||
Si votre application est **simple**, cela ne sera probablement **pas un problème**, et vous n'aurez peut-être pas besoin de spécifier des limites de mémoire strictes. Mais si vous **utilisez beaucoup de mémoire** (par exemple avec des modèles de **machine learning**), vous devez vérifier combien de mémoire vous consommez et ajuster le **nombre de conteneurs** qui s'exécutent sur **chaque machine** (et peut-être ajouter plus de machines à votre cluster).
|
||||
|
||||
Si vous exécutez **plusieurs processus par conteneur**, vous devrez vous assurer que le nombre de processus lancés ne **consomme pas plus de mémoire** que celle disponible.
|
||||
Si vous exécutez **plusieurs processus par conteneur**, vous devez vous assurer que le nombre de processus démarrés ne **consomme pas plus de mémoire** que ce qui est disponible.
|
||||
|
||||
## Étapes préalables avant de démarrer et conteneurs { #previous-steps-before-starting-and-containers }
|
||||
## Étapes préalables au démarrage et conteneurs { #previous-steps-before-starting-and-containers }
|
||||
|
||||
Si vous utilisez des conteneurs (par ex. Docker, Kubernetes), alors il y a deux approches principales que vous pouvez utiliser.
|
||||
Si vous utilisez des conteneurs (par ex. Docker, Kubernetes), alors il existe deux approches principales que vous pouvez utiliser.
|
||||
|
||||
### Plusieurs conteneurs { #multiple-containers }
|
||||
|
||||
Si vous avez **plusieurs conteneurs**, probablement chacun exécutant un **seul processus** (par exemple, dans un cluster **Kubernetes**), alors vous voudrez probablement avoir un **conteneur séparé** effectuant le travail des **étapes préalables** dans un seul conteneur, exécutant un seul processus, **avant** d’exécuter les conteneurs worker répliqués.
|
||||
Si vous avez **plusieurs conteneurs**, probablement chacun exécutant un **seul processus** (par exemple, dans un cluster **Kubernetes**), alors vous voudrez probablement avoir un **conteneur séparé** effectuant le travail des **étapes préalables** dans un seul conteneur, exécutant un seul processus, **avant** d'exécuter les conteneurs worker répliqués.
|
||||
|
||||
/// info
|
||||
|
||||
Si vous utilisez Kubernetes, il s’agira probablement d’un <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>.
|
||||
Si vous utilisez Kubernetes, ce sera probablement un <a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/" class="external-link" target="_blank">Init Container</a>.
|
||||
|
||||
///
|
||||
|
||||
Si, dans votre cas d’utilisation, il n’y a pas de problème à exécuter ces étapes préalables **plusieurs fois en parallèle** (par exemple si vous n’exécutez pas de migrations de base de données, mais vérifiez simplement si la base est prête), vous pouvez aussi simplement les placer dans chaque conteneur juste avant de démarrer le processus principal.
|
||||
Si, dans votre cas d'usage, il n'y a pas de problème à exécuter ces étapes préalables **plusieurs fois en parallèle** (par exemple si vous n'exécutez pas de migrations de base de données, mais vérifiez simplement si la base de données est prête), alors vous pourriez aussi simplement les mettre dans chaque conteneur juste avant de démarrer le processus principal.
|
||||
|
||||
### Un seul conteneur { #single-container }
|
||||
|
||||
Si vous avez une configuration simple, avec un **seul conteneur** qui démarre ensuite plusieurs **processus worker** (ou aussi un seul processus), alors vous pouvez exécuter ces étapes préalables dans le même conteneur, juste avant de démarrer le processus avec l’application.
|
||||
Si vous avez une configuration simple, avec **un seul conteneur** qui démarre ensuite plusieurs **processus worker** (ou un seul processus aussi), vous pouvez alors exécuter ces étapes préalables dans le même conteneur, juste avant de démarrer le processus avec l'application.
|
||||
|
||||
### Image Docker de base { #base-docker-image }
|
||||
|
||||
Il existait une image Docker officielle FastAPI : <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Mais elle est maintenant dépréciée. ⛔️
|
||||
Il existait une image Docker officielle FastAPI : <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker" class="external-link" target="_blank">tiangolo/uvicorn-gunicorn-fastapi</a>. Mais elle est désormais dépréciée. ⛔️
|
||||
|
||||
Vous ne devriez probablement **pas** utiliser cette image Docker de base (ni aucune autre similaire).
|
||||
|
||||
Si vous utilisez **Kubernetes** (ou autres) et que vous définissez déjà la **réplication** au niveau du cluster, avec plusieurs **conteneurs**, dans ces cas, il vaut mieux **construire une image depuis zéro** comme décrit ci-dessus : [Construire une image Docker pour FastAPI](#build-a-docker-image-for-fastapi).
|
||||
Si vous utilisez **Kubernetes** (ou autres) et que vous définissez déjà la **réplication** au niveau du cluster, avec plusieurs **conteneurs**. Dans ces cas, il est préférable de **construire une image à partir de zéro** comme décrit ci-dessus : [Construire une image Docker pour FastAPI](#build-a-docker-image-for-fastapi).
|
||||
|
||||
Et si vous avez besoin d’avoir plusieurs workers, vous pouvez simplement utiliser l’option de ligne de commande `--workers`.
|
||||
Et si vous devez avoir plusieurs workers, vous pouvez simplement utiliser l'option de ligne de commande `--workers`.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
L’image Docker a été créée à une époque où Uvicorn ne prenait pas en charge la gestion et le redémarrage des workers morts, il fallait donc utiliser Gunicorn avec Uvicorn, ce qui ajoutait pas mal de complexité, uniquement pour que Gunicorn gère et redémarre les processus worker Uvicorn.
|
||||
L'image Docker a été créée à une époque où Uvicorn ne supportait pas la gestion et le redémarrage des workers morts, il fallait donc utiliser Gunicorn avec Uvicorn, ce qui ajoutait pas mal de complexité, uniquement pour que Gunicorn gère et redémarre les processus worker Uvicorn.
|
||||
|
||||
Mais maintenant qu’Uvicorn (et la commande `fastapi`) prennent en charge l’utilisation de `--workers`, il n’y a plus de raison d’utiliser une image Docker de base au lieu de construire la vôtre (cela représente à peu près la même quantité de code 😅).
|
||||
Mais maintenant qu'Uvicorn (et la commande `fastapi`) supporte l'usage de `--workers`, il n'y a plus de raison d'utiliser une image Docker de base au lieu de construire la vôtre (c'est à peu près la même quantité de code 😅).
|
||||
|
||||
///
|
||||
|
||||
## Déployer l’image de conteneur { #deploy-the-container-image }
|
||||
## Déployer l'image de conteneur { #deploy-the-container-image }
|
||||
|
||||
Après avoir une image de conteneur (Docker), il existe plusieurs façons de la déployer.
|
||||
|
||||
Par exemple :
|
||||
Par exemple :
|
||||
|
||||
* Avec **Docker Compose** sur un seul serveur
|
||||
* Avec un cluster **Kubernetes**
|
||||
* Avec un cluster en mode Docker Swarm
|
||||
* Avec un cluster Docker Swarm Mode
|
||||
* Avec un autre outil comme Nomad
|
||||
* Avec un service cloud qui prend votre image de conteneur et la déploie
|
||||
|
||||
## Image Docker avec `uv` { #docker-image-with-uv }
|
||||
|
||||
Si vous utilisez <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> pour installer et gérer votre projet, vous pouvez suivre leur <a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">guide Docker uv</a>.
|
||||
Si vous utilisez <a href="https://github.com/astral-sh/uv" class="external-link" target="_blank">uv</a> pour installer et gérer votre projet, vous pouvez suivre leur <a href="https://docs.astral.sh/uv/guides/integration/docker/" class="external-link" target="_blank">guide Docker pour uv</a>.
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Avec les systèmes de conteneurs (par ex. avec **Docker** et **Kubernetes**), il devient assez simple de gérer tous les **concepts de déploiement** :
|
||||
Avec les systèmes de conteneurs (par ex. avec **Docker** et **Kubernetes**), il devient assez simple de gérer tous les **concepts de déploiement** :
|
||||
|
||||
* HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours)
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes préalables avant de démarrer
|
||||
* Étapes préalables au démarrage
|
||||
|
||||
Dans la plupart des cas, vous ne voudrez probablement pas utiliser d’image de base, et plutôt **construire une image de conteneur depuis zéro** basée sur l’image Docker Python officielle.
|
||||
Dans la plupart des cas, vous ne voudrez probablement pas utiliser d'image de base, et au contraire **construire une image de conteneur à partir de zéro** basée sur l'image Docker Python officielle.
|
||||
|
||||
En prenant soin de **l’ordre** des instructions dans le `Dockerfile` et du **cache Docker**, vous pouvez **minimiser les temps de construction** pour maximiser votre productivité (et éviter l’ennui). 😎
|
||||
En prenant soin de l'**ordre** des instructions dans le `Dockerfile` et du **cache Docker**, vous pouvez **minimiser les temps de construction**, maximiser votre productivité (et éviter l'ennui). 😎
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
# À propos de HTTPS { #about-https }
|
||||
|
||||
Il est facile de penser que HTTPS est quelque chose qui est simplement «activé» ou non.
|
||||
Il est facile de supposer que HTTPS est quelque chose qui est simplement « activé » ou non.
|
||||
|
||||
Mais c'est bien plus complexe que cela.
|
||||
Mais c'est beaucoup plus complexe que cela.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous êtes pressé ou si cela ne vous intéresse pas, passez aux sections suivantes pour obtenir des instructions pas à pas afin de tout configurer avec différentes techniques.
|
||||
Si vous êtes pressé ou si cela ne vous intéresse pas, continuez avec les sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques.
|
||||
|
||||
///
|
||||
|
||||
Pour apprendre les bases de **HTTPS**, du point de vue d'un utilisateur, consultez <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
Pour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez <a href="https://howhttps.works/" class="external-link" target="_blank">https://howhttps.works/</a>.
|
||||
|
||||
Maintenant, du point de vue d'un **développeur**, voici plusieurs points à garder à l'esprit en pensant à HTTPS :
|
||||
Maintenant, du point de vue d'un développeur, voici plusieurs choses à avoir en tête en pensant au HTTPS :
|
||||
|
||||
* Pour HTTPS, **le serveur** doit **avoir des «certificats»** générés par une **tierce partie**.
|
||||
* Ces certificats sont en réalité **acquis** auprès de la tierce partie, pas «générés».
|
||||
* Pour le HTTPS, **le serveur** doit **disposer de « certificats »** générés par une **tierce partie**.
|
||||
* Ces certificats sont en réalité **acquis** auprès de la tierce partie, et non « générés ».
|
||||
* Les certificats ont une **durée de vie**.
|
||||
* Ils **expirent**.
|
||||
* Ils doivent ensuite être **renouvelés**, **acquis à nouveau** auprès de la tierce partie.
|
||||
* Le **cryptage** de la connexion se fait au **niveau TCP**.
|
||||
* Puis ils doivent être **renouvelés**, **acquis à nouveau** auprès de la tierce partie.
|
||||
* Le cryptage de la connexion se fait au **niveau TCP**.
|
||||
* C'est une couche **en dessous de HTTP**.
|
||||
* Donc, la **gestion du certificat et du cryptage** est effectuée **avant HTTP**.
|
||||
* **TCP ne connaît pas les «domaines»**. Seulement les adresses IP.
|
||||
* Donc, la gestion du **certificat et du cryptage** est effectuée **avant HTTP**.
|
||||
* **TCP ne connaît pas les « domaines »**. Il ne connaît que les adresses IP.
|
||||
* L'information sur le **domaine spécifique** demandé se trouve dans les **données HTTP**.
|
||||
* Les **certificats HTTPS** «certifient» un **certain domaine**, mais le protocole et le cryptage ont lieu au niveau TCP, **avant de savoir** quel domaine est traité.
|
||||
* **Par défaut**, cela signifie que vous ne pouvez avoir **qu'un seul certificat HTTPS par adresse IP**.
|
||||
* Peu importe la taille de votre serveur ou la petitesse de chacune des applications qu'il héberge.
|
||||
* Il existe toutefois une **solution** à cela.
|
||||
* Il existe une **extension** du protocole **TLS** (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication – Indication du nom du serveur">SNI</abbr></a>**.
|
||||
* Cette extension SNI permet à un seul serveur (avec **une seule adresse IP**) d'avoir **plusieurs certificats HTTPS** et de servir **plusieurs domaines/applications HTTPS**.
|
||||
* Pour que cela fonctionne, un **seul** composant (programme) s'exécutant sur le serveur, à l'écoute de l'**adresse IP publique**, doit avoir **tous les certificats HTTPS** du serveur.
|
||||
* **Après** l'obtention d'une connexion sécurisée, le protocole de communication est **toujours HTTP**.
|
||||
* Les **certificats HTTPS** « certifient » un **certain domaine**, mais le protocole et le cryptage se font au niveau TCP, **avant de savoir** quel domaine est traité.
|
||||
* **Par défaut**, cela signifie que vous ne pouvez avoir qu'**un seul certificat HTTPS par adresse IP**.
|
||||
* Quelle que soit la taille de votre serveur ou la petitesse de chacune des applications qu'il contient.
|
||||
* Il existe cependant une **solution** à ce problème.
|
||||
* Il existe une **extension** du protocole **TLS** (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée **<a href="https://en.wikipedia.org/wiki/Server_Name_Indication" class="external-link" target="_blank"><abbr title="Server Name Indication - Indication du nom du serveur">SNI</abbr></a>**.
|
||||
* Cette extension SNI permet à un seul serveur (avec une **seule adresse IP**) d'avoir **plusieurs certificats HTTPS** et de servir **plusieurs domaines/applications HTTPS**.
|
||||
* Pour que cela fonctionne, un **seul** composant (programme) fonctionnant sur le serveur, écoutant sur l'**adresse IP publique**, doit avoir **tous les certificats HTTPS** du serveur.
|
||||
* **Après** l'établissement d'une connexion sécurisée, le protocole de communication est **toujours HTTP**.
|
||||
* Le contenu est **crypté**, même s'il est envoyé avec le **protocole HTTP**.
|
||||
|
||||
Il est courant d'avoir **un programme/serveur HTTP** fonctionnant sur le serveur (la machine, l'hôte, etc.) et **gérant toutes les parties HTTPS** : recevoir les **requêtes HTTPS chiffrées**, envoyer les **requêtes HTTP décryptées** à l'application HTTP réelle fonctionnant sur le même serveur (dans ce cas, l'application **FastAPI**), prendre la **réponse HTTP** de l'application, **la crypter** en utilisant le **certificat HTTPS** approprié et la renvoyer au client en utilisant **HTTPS**. Ce serveur est souvent appelé un **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">proxy de terminaison TLS</a>**.
|
||||
Il est courant d'avoir **un seul programme/serveur HTTP** fonctionnant sur le serveur (la machine, l'hôte, etc.) et **gérant toutes les parties HTTPS** : recevoir les **requêtes HTTPS chiffrées**, envoyer les **requêtes HTTP déchiffrées** à l'application HTTP réelle fonctionnant sur le même serveur (l'application **FastAPI**, dans ce cas), prendre la **réponse HTTP** de l'application, la **chiffrer** en utilisant le **certificat HTTPS** approprié et la renvoyer au client en utilisant **HTTPS**. Ce serveur est souvent appelé un **<a href="https://en.wikipedia.org/wiki/TLS_termination_proxy" class="external-link" target="_blank">Proxy de terminaison TLS</a>**.
|
||||
|
||||
Parmi les options que vous pourriez utiliser comme proxy de terminaison TLS :
|
||||
Parmi les options que vous pourriez utiliser comme Proxy de terminaison TLS :
|
||||
|
||||
* Traefik (qui peut aussi gérer le renouvellement des certificats)
|
||||
* Caddy (qui peut aussi gérer le renouvellement des certificats)
|
||||
* Traefik (qui peut également gérer les renouvellements de certificats)
|
||||
* Caddy (qui peut également gérer les renouvellements de certificats)
|
||||
* Nginx
|
||||
* HAProxy
|
||||
|
||||
@@ -47,33 +47,33 @@ Parmi les options que vous pourriez utiliser comme proxy de terminaison TLS :
|
||||
|
||||
Avant Let's Encrypt, ces **certificats HTTPS** étaient vendus par des tiers de confiance.
|
||||
|
||||
Le processus d'acquisition d'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasse et les certificats étaient assez chers.
|
||||
Le processus d'acquisition de l'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasses et les certificats étaient assez chers.
|
||||
|
||||
Mais ensuite, **<a href="https://letsencrypt.org/" class="external-link" target="_blank">Let's Encrypt</a>** a été créé.
|
||||
|
||||
Il s'agit d'un projet de la Fondation Linux. Il fournit des **certificats HTTPS gratuitement**, de manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la **sécurité est en fait meilleure** en raison de leur durée de vie réduite.
|
||||
Il s'agit d'un projet de la Fondation Linux. Il fournit **des certificats HTTPS gratuitement**, de manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la **sécurité est en fait meilleure** en raison de leur durée de vie réduite.
|
||||
|
||||
Les domaines sont vérifiés de manière sécurisée et les certificats sont générés automatiquement. Cela permet également d'automatiser le renouvellement de ces certificats.
|
||||
|
||||
L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un **HTTPS sécurisé, gratuit et pour toujours**.
|
||||
L'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un **HTTPS sécurisé, gratuitement et pour toujours**.
|
||||
|
||||
## HTTPS pour les développeurs { #https-for-developers }
|
||||
|
||||
Voici un exemple de ce à quoi une API HTTPS pourrait ressembler, étape par étape, en se concentrant principalement sur les idées importantes pour les développeurs.
|
||||
Voici un exemple de ce à quoi pourrait ressembler une API HTTPS, étape par étape, en portant principalement attention aux idées importantes pour les développeurs.
|
||||
|
||||
### Nom de domaine { #domain-name }
|
||||
|
||||
Tout commencerait probablement par **acquérir** un **nom de domaine**. Ensuite, vous le configureriez dans un serveur DNS (éventuellement votre même fournisseur cloud).
|
||||
Tout commencerait probablement par le fait que vous **acquériez** un **nom de domaine**. Ensuite, vous le configureriez dans un serveur DNS (possiblement le même que votre fournisseur cloud).
|
||||
|
||||
Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une **adresse IP publique** <abbr title="qui ne change pas">fixe</abbr>.
|
||||
Vous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une adresse IP **publique** <abbr title="Qui ne change pas">fixe</abbr>.
|
||||
|
||||
Dans le ou les serveurs DNS, vous configureriez un enregistrement (un «`A record`») pour faire pointer **votre domaine** vers l'**adresse IP** publique de **votre serveur**.
|
||||
Dans le ou les serveurs DNS, vous configureriez un enregistrement (un « `A record` ») pour faire pointer **votre domaine** vers l'**adresse IP publique de votre serveur**.
|
||||
|
||||
Vous feriez probablement cela une seule fois, la première fois, lors de la mise en place de l'ensemble.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Cette partie sur le nom de domaine se situe bien avant HTTPS, mais comme tout dépend du domaine et de l'adresse IP, cela vaut la peine de la mentionner ici.
|
||||
Cette partie relative au nom de domaine intervient bien avant HTTPS, mais comme tout dépend du domaine et de l'adresse IP, il vaut la peine de la mentionner ici.
|
||||
|
||||
///
|
||||
|
||||
@@ -83,11 +83,11 @@ Concentrons-nous maintenant sur toutes les parties réellement liées à HTTPS.
|
||||
|
||||
D'abord, le navigateur vérifierait auprès des **serveurs DNS** quelle est l'**IP du domaine**, dans ce cas, `someapp.example.com`.
|
||||
|
||||
Les serveurs DNS indiqueraient au navigateur d'utiliser une **adresse IP** spécifique. Ce serait l'adresse IP publique utilisée par votre serveur, que vous avez configurée dans les serveurs DNS.
|
||||
Les serveurs DNS indiqueraient au navigateur d'utiliser une **adresse IP** spécifique. Ce serait l'adresse IP publique utilisée par votre serveur, celle que vous avez configurée dans les serveurs DNS.
|
||||
|
||||
<img src="/img/deployment/https/https01.drawio.svg">
|
||||
|
||||
### Début de la poignée de main TLS { #tls-handshake-start }
|
||||
### Début de la négociation TLS (Handshake) { #tls-handshake-start }
|
||||
|
||||
Le navigateur communiquerait ensuite avec cette adresse IP sur le **port 443** (le port HTTPS).
|
||||
|
||||
@@ -95,106 +95,106 @@ La première partie de la communication consiste simplement à établir la conne
|
||||
|
||||
<img src="/img/deployment/https/https02.drawio.svg">
|
||||
|
||||
Cette interaction entre le client et le serveur pour établir la connexion TLS est appelée la **poignée de main TLS**.
|
||||
Cette interaction entre le client et le serveur pour établir la connexion TLS s'appelle la **négociation TLS (TLS handshake)**.
|
||||
|
||||
### TLS avec extension SNI { #tls-with-sni-extension }
|
||||
### TLS avec l'extension SNI { #tls-with-sni-extension }
|
||||
|
||||
**Un seul processus** sur le serveur peut être à l'écoute d'un **port** spécifique sur une **adresse IP** spécifique. Il pourrait y avoir d'autres processus à l'écoute d'autres ports sur la même adresse IP, mais un seul pour chaque combinaison adresse IP/port.
|
||||
**Un seul processus** sur le serveur peut écouter sur un **port** spécifique d'une **adresse IP** spécifique. Il pourrait y avoir d'autres processus écoutant sur d'autres ports de la même adresse IP, mais un seul pour chaque combinaison d'adresse IP et de port.
|
||||
|
||||
TLS (HTTPS) utilise par défaut le port spécifique `443`. C'est donc le port dont nous aurions besoin.
|
||||
|
||||
Comme un seul processus peut écouter sur ce port, le processus qui le ferait serait le **proxy de terminaison TLS**.
|
||||
Comme un seul processus peut écouter sur ce port, le processus qui le ferait serait le **Proxy de terminaison TLS**.
|
||||
|
||||
Le proxy de terminaison TLS aurait accès à un ou plusieurs **certificats TLS** (certificats HTTPS).
|
||||
Le Proxy de terminaison TLS aurait accès à un ou plusieurs **certificats TLS** (certificats HTTPS).
|
||||
|
||||
En utilisant l'**extension SNI** évoquée ci-dessus, le proxy de terminaison TLS vérifierait lequel des certificats TLS (HTTPS) disponibles il doit utiliser pour cette connexion, en utilisant celui qui correspond au domaine attendu par le client.
|
||||
En utilisant l'**extension SNI** mentionnée plus haut, le Proxy de terminaison TLS vérifierait lequel des certificats TLS (HTTPS) disponibles il devrait utiliser pour cette connexion, en choisissant celui qui correspond au domaine attendu par le client.
|
||||
|
||||
Dans ce cas, il utiliserait le certificat pour `someapp.example.com`.
|
||||
|
||||
<img src="/img/deployment/https/https03.drawio.svg">
|
||||
|
||||
Le client **fait déjà confiance** à l'entité qui a généré ce certificat TLS (dans ce cas Let's Encrypt, mais nous verrons cela plus tard), il peut donc **vérifier** que le certificat est valide.
|
||||
Le client **fait déjà confiance** à l'entité qui a généré ce certificat TLS (dans ce cas Let's Encrypt, mais nous y reviendrons plus tard), il peut donc **vérifier** que le certificat est valide.
|
||||
|
||||
Ensuite, en utilisant le certificat, le client et le proxy de terminaison TLS **décident comment chiffrer** le reste de la **communication TCP**. Cela complète la partie **poignée de main TLS**.
|
||||
Ensuite, en utilisant le certificat, le client et le Proxy de terminaison TLS **décident comment chiffrer** le reste de la **communication TCP**. Cela termine la partie **négociation TLS**.
|
||||
|
||||
Après cela, le client et le serveur ont une **connexion TCP chiffrée**, c'est ce que fournit TLS. Ils peuvent ensuite utiliser cette connexion pour démarrer la **communication HTTP** réelle.
|
||||
Après cela, le client et le serveur disposent d'une **connexion TCP chiffrée**, c'est ce que fournit TLS. Ils peuvent alors utiliser cette connexion pour démarrer la **communication HTTP** proprement dite.
|
||||
|
||||
Et c'est ce qu'est **HTTPS** : c'est simplement du **HTTP** ordinaire à l'intérieur d'une **connexion TLS sécurisée** au lieu d'une connexion TCP pure (non chiffrée).
|
||||
Et c'est ce qu'est **HTTPS** : c'est simplement du **HTTP** à l'intérieur d'une **connexion TLS sécurisée** au lieu d'une connexion TCP pure (non chiffrée).
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Remarquez que le chiffrement de la communication se fait au **niveau TCP**, pas au niveau HTTP.
|
||||
Remarquez que le cryptage de la communication se produit au **niveau TCP**, pas au niveau HTTP.
|
||||
|
||||
///
|
||||
|
||||
### Requête HTTPS { #https-request }
|
||||
|
||||
Maintenant que le client et le serveur (spécifiquement le navigateur et le proxy de terminaison TLS) ont une **connexion TCP chiffrée**, ils peuvent démarrer la **communication HTTP**.
|
||||
Maintenant que le client et le serveur (spécifiquement le navigateur et le Proxy de terminaison TLS) ont une **connexion TCP chiffrée**, ils peuvent démarrer la **communication HTTP**.
|
||||
|
||||
Ainsi, le client envoie une **requête HTTPS**. Il s'agit simplement d'une requête HTTP à travers une connexion TLS chiffrée.
|
||||
Ainsi, le client envoie une **requête HTTPS**. Ce n'est qu'une requête HTTP à travers une connexion TLS chiffrée.
|
||||
|
||||
<img src="/img/deployment/https/https04.drawio.svg">
|
||||
|
||||
### Déchiffrer la requête { #decrypt-the-request }
|
||||
|
||||
Le proxy de terminaison TLS utiliserait le chiffrement convenu pour **décrypter la requête**, et transmettrait la **requête HTTP en clair (décryptée)** au processus exécutant l'application (par exemple un processus avec Uvicorn exécutant l'application FastAPI).
|
||||
Le Proxy de terminaison TLS utiliserait le chiffrement convenu pour **déchiffrer la requête**, et transmettrait la **requête HTTP en clair (déchiffrée)** au processus exécutant l'application (par exemple un processus avec Uvicorn exécutant l'application FastAPI).
|
||||
|
||||
<img src="/img/deployment/https/https05.drawio.svg">
|
||||
|
||||
### Réponse HTTP { #http-response }
|
||||
|
||||
L'application traiterait la requête et enverrait une **réponse HTTP en clair (non chiffrée)** au proxy de terminaison TLS.
|
||||
L'application traiterait la requête et enverrait une **réponse HTTP en clair (non chiffrée)** au Proxy de terminaison TLS.
|
||||
|
||||
<img src="/img/deployment/https/https06.drawio.svg">
|
||||
|
||||
### Réponse HTTPS { #https-response }
|
||||
|
||||
Le proxy de terminaison TLS **chiffrerait ensuite la réponse** en utilisant la cryptographie convenue précédemment (qui a commencé avec le certificat pour `someapp.example.com`), et la renverrait au navigateur.
|
||||
Le Proxy de terminaison TLS **chiffrerait ensuite la réponse** en utilisant la cryptographie convenue auparavant (qui a commencé avec le certificat pour `someapp.example.com`), et la renverrait au navigateur.
|
||||
|
||||
Ensuite, le navigateur vérifierait que la réponse est valide et chiffrée avec la bonne clé cryptographique, etc. Il **décrypterait la réponse** et la traiterait.
|
||||
Ensuite, le navigateur vérifierait que la réponse est valide et chiffrée avec la bonne clé cryptographique, etc. Il **déchiffrerait la réponse** et la traiterait.
|
||||
|
||||
<img src="/img/deployment/https/https07.drawio.svg">
|
||||
|
||||
Le client (navigateur) saura que la réponse provient du bon serveur parce qu'elle utilise la cryptographie convenue précédemment à l'aide du **certificat HTTPS**.
|
||||
Le client (navigateur) saura que la réponse provient du bon serveur parce qu'elle utilise la cryptographie convenue auparavant à l'aide du **certificat HTTPS**.
|
||||
|
||||
### Applications multiples { #multiple-applications }
|
||||
|
||||
Sur le même serveur (ou des serveurs), il peut y avoir **plusieurs applications**, par exemple d'autres programmes d'API ou une base de données.
|
||||
Sur le même serveur (ou les mêmes serveurs), il pourrait y avoir **plusieurs applications**, par exemple d'autres programmes d'API ou une base de données.
|
||||
|
||||
Un seul processus peut gérer l'IP et le port spécifiques (le proxy de terminaison TLS dans notre exemple), mais les autres applications/processus peuvent également s'exécuter sur le ou les serveurs, tant qu'ils n'essaient pas d'utiliser la même **combinaison d'IP publique et de port**.
|
||||
Un seul processus peut gérer l'adresse IP et le port spécifiques (le Proxy de terminaison TLS dans notre exemple), mais les autres applications/processus peuvent également s'exécuter sur le ou les serveurs, tant qu'ils n'essaient pas d'utiliser la même **combinaison d'adresse IP publique et de port**.
|
||||
|
||||
<img src="/img/deployment/https/https08.drawio.svg">
|
||||
|
||||
De cette façon, le proxy de terminaison TLS pourrait gérer HTTPS et les certificats pour **plusieurs domaines**, pour plusieurs applications, puis transmettre les requêtes à la bonne application dans chaque cas.
|
||||
De cette façon, le Proxy de terminaison TLS pourrait gérer HTTPS et les certificats pour **plusieurs domaines**, pour plusieurs applications, puis transmettre les requêtes à la bonne application dans chaque cas.
|
||||
|
||||
### Renouvellement des certificats { #certificate-renewal }
|
||||
|
||||
À un moment donné dans le futur, chaque certificat **expirera** (environ 3 mois après son acquisition).
|
||||
À un moment donné dans le futur, chaque certificat **expirerait** (environ 3 mois après son acquisition).
|
||||
|
||||
Ensuite, un autre programme (dans certains cas c'est un autre programme, dans d'autres cas cela peut être le même proxy de terminaison TLS) communiquerait avec Let's Encrypt et renouvellerait le ou les certificats.
|
||||
Ensuite, il y aurait un autre programme (dans certains cas c'est un autre programme, dans d'autres cas cela pourrait être le même Proxy de terminaison TLS) qui communiquerait avec Let's Encrypt et renouvellerait le ou les certificats.
|
||||
|
||||
<img src="/img/deployment/https/https.drawio.svg">
|
||||
|
||||
Les **certificats TLS** sont **associés à un nom de domaine**, pas à une adresse IP.
|
||||
|
||||
Donc, pour renouveler les certificats, le programme de renouvellement doit **prouver** à l'autorité (Let's Encrypt) qu'il **«possède» et contrôle ce domaine**.
|
||||
Ainsi, pour renouveler les certificats, le programme de renouvellement doit **prouver** à l'autorité (Let's Encrypt) qu'il **« possède » et contrôle ce domaine**.
|
||||
|
||||
Pour ce faire, et pour s'adapter aux différents besoins des applications, il existe plusieurs manières de procéder. Parmi les méthodes populaires :
|
||||
Pour ce faire, et pour s'adapter aux différents besoins des applications, il existe plusieurs façons de procéder. Parmi les plus courantes :
|
||||
|
||||
* **Modifier certains enregistrements DNS**.
|
||||
* Pour cela, le programme de renouvellement doit prendre en charge les API du fournisseur DNS ; selon le fournisseur DNS que vous utilisez, cela peut être ou non une option.
|
||||
* Pour cela, le programme de renouvellement doit prendre en charge les API du fournisseur DNS ; ainsi, selon le fournisseur DNS que vous utilisez, cela peut être ou non une option.
|
||||
* **S'exécuter comme un serveur** (au moins pendant le processus d'acquisition du certificat) sur l'adresse IP publique associée au domaine.
|
||||
* Comme nous l'avons dit plus haut, un seul processus peut écouter sur une adresse IP et un port spécifiques.
|
||||
* C'est l'une des raisons pour lesquelles il est très utile que le même proxy de terminaison TLS s'occupe également du processus de renouvellement des certificats.
|
||||
* Sinon, vous pourriez devoir arrêter momentanément le proxy de terminaison TLS, démarrer le programme de renouvellement pour acquérir les certificats, puis les configurer avec le proxy de terminaison TLS, et redémarrer ensuite le proxy de terminaison TLS. Ce n'est pas idéal, car votre/vos application(s) ne seront pas disponibles pendant le temps où le proxy de terminaison TLS est arrêté.
|
||||
* C'est l'une des raisons pour lesquelles il est très utile que le même Proxy de terminaison TLS prenne également en charge le processus de renouvellement des certificats.
|
||||
* Sinon, vous pourriez avoir à arrêter le Proxy de terminaison TLS momentanément, démarrer le programme de renouvellement pour acquérir les certificats, puis les configurer avec le Proxy de terminaison TLS, et ensuite redémarrer le Proxy de terminaison TLS. Ce n'est pas idéal, car votre/vos application(s) ne seront pas disponibles pendant le temps où le Proxy de terminaison TLS est arrêté.
|
||||
|
||||
Tout ce processus de renouvellement, tout en continuant à servir l'application, est l'une des principales raisons pour lesquelles vous voudriez avoir un **système séparé pour gérer HTTPS** avec un proxy de terminaison TLS au lieu d'utiliser directement les certificats TLS avec le serveur d'application (par ex. Uvicorn).
|
||||
Tout ce processus de renouvellement, tout en continuant à servir l'application, est l'une des principales raisons pour lesquelles vous voudriez avoir un **système séparé pour gérer HTTPS** avec un Proxy de terminaison TLS, au lieu d'utiliser directement les certificats TLS avec le serveur d'application (par exemple Uvicorn).
|
||||
|
||||
## En-têtes transférés par le proxy { #proxy-forwarded-headers }
|
||||
## En-têtes Proxy Forwarded { #proxy-forwarded-headers }
|
||||
|
||||
Lorsque vous utilisez un proxy pour gérer HTTPS, votre **serveur d'application** (par exemple Uvicorn via FastAPI CLI) ne connaît rien du processus HTTPS, il communique en HTTP simple avec le **proxy de terminaison TLS**.
|
||||
Lorsque vous utilisez un proxy pour gérer HTTPS, votre **serveur d'application** (par exemple Uvicorn via FastAPI CLI) ne connaît rien du processus HTTPS, il communique en HTTP en clair avec le **Proxy de terminaison TLS**.
|
||||
|
||||
Ce **proxy** définirait normalement certains en-têtes HTTP à la volée avant de transmettre la requête au **serveur d'application**, pour informer le serveur d'application que la requête est **transférée** par le proxy.
|
||||
Ce **proxy** définirait normalement certains en-têtes HTTP à la volée avant de transmettre la requête au **serveur d'application**, pour informer le serveur d'application que la requête est **transmise** par le proxy.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
@@ -206,26 +206,26 @@ Les en-têtes du proxy sont :
|
||||
|
||||
///
|
||||
|
||||
Néanmoins, comme le **serveur d'application** ne sait pas qu'il est derrière un **proxy** de confiance, par défaut, il ne ferait pas confiance à ces en-têtes.
|
||||
Néanmoins, comme le **serveur d'application** ne sait pas qu'il se trouve derrière un **proxy** de confiance, par défaut, il ne ferait pas confiance à ces en-têtes.
|
||||
|
||||
Mais vous pouvez configurer le **serveur d'application** pour faire confiance aux en-têtes transférés envoyés par le **proxy**. Si vous utilisez FastAPI CLI, vous pouvez utiliser l’*option de CLI* `--forwarded-allow-ips` pour lui indiquer depuis quelles IP il doit faire confiance à ces en-têtes transférés.
|
||||
Mais vous pouvez configurer le **serveur d'application** pour qu'il fasse confiance aux en-têtes transmis (*forwarded*) envoyés par le **proxy**. Si vous utilisez FastAPI CLI, vous pouvez utiliser l'*option CLI* `--forwarded-allow-ips` pour lui indiquer à partir de quelles IP il doit faire confiance à ces en-têtes transmis.
|
||||
|
||||
Par exemple, si le **serveur d'application** ne reçoit des communications que du **proxy** de confiance, vous pouvez définir `--forwarded-allow-ips="*"` pour le faire faire confiance à toutes les IP entrantes, puisqu'il ne recevra des requêtes que depuis l'IP utilisée par le **proxy**.
|
||||
Par exemple, si le **serveur d'application** ne reçoit des communications que du **proxy** de confiance, vous pouvez définir `--forwarded-allow-ips="*"` pour lui faire faire confiance à toutes les IP entrantes, puisqu'il ne recevra des requêtes que depuis l'IP utilisée par le **proxy**.
|
||||
|
||||
Ainsi, l'application pourra savoir quelle est sa propre URL publique, si elle utilise HTTPS, le domaine, etc.
|
||||
De cette façon, l'application sera en mesure de savoir quelle est sa propre URL publique, si elle utilise HTTPS, le domaine, etc.
|
||||
|
||||
Cela serait utile par exemple pour gérer correctement les redirections.
|
||||
Cela serait utile, par exemple, pour gérer correctement les redirections.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pouvez en apprendre davantage dans la documentation [Derrière un proxy - Activer les en-têtes transférés par le proxy](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank}
|
||||
Vous pouvez en savoir plus dans la documentation [Derrière un proxy - Activer les en-têtes transmis par le proxy](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers){.internal-link target=_blank}
|
||||
|
||||
///
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Avoir **HTTPS** est très important, et assez **critique** dans la plupart des cas. La majeure partie de l'effort que vous, en tant que développeur, avez à fournir autour de HTTPS consiste simplement à **comprendre ces concepts** et leur fonctionnement.
|
||||
Disposer de **HTTPS** est très important, et assez **critique** dans la plupart des cas. La majeure partie de l'effort que vous, en tant que développeur, devez fournir autour de HTTPS consiste simplement à **comprendre ces concepts** et leur fonctionnement.
|
||||
|
||||
Mais une fois que vous connaissez les informations de base de **HTTPS pour les développeurs**, vous pouvez facilement combiner et configurer différents outils pour vous aider à tout gérer simplement.
|
||||
Mais une fois que vous connaissez les informations de base sur **HTTPS pour les développeurs**, vous pouvez facilement combiner et configurer différents outils pour vous aider à tout gérer simplement.
|
||||
|
||||
Dans certains des prochains chapitres, je vous montrerai plusieurs exemples concrets de configuration de **HTTPS** pour des applications **FastAPI**. 🔒
|
||||
|
||||
@@ -4,20 +4,27 @@ Le déploiement d'une application **FastAPI** est relativement simple.
|
||||
|
||||
## Que signifie le déploiement { #what-does-deployment-mean }
|
||||
|
||||
**Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les utilisateurs**.
|
||||
**Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les
|
||||
utilisateurs**.
|
||||
|
||||
Pour une **API Web**, cela implique normalement de la placer sur une **machine distante**, avec un **programme serveur** qui offre de bonnes performances, une bonne stabilité, _etc._, afin que vos **utilisateurs** puissent **accéder** à l'application efficacement et sans interruption ni problème.
|
||||
Pour une **API Web**, cela implique normalement de la placer sur une **machine distante**, avec un **programme serveur**
|
||||
qui offre de bonnes performances, une bonne stabilité, _etc._, afin que vos **utilisateurs** puissent **accéder** à
|
||||
l'application efficacement et sans interruption ni problème.
|
||||
|
||||
Ceci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser et de le réparer, d'arrêter et de redémarrer le serveur de développement, _etc._
|
||||
Ceci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser
|
||||
et de le réparer, d'arrêter et de redémarrer le serveur de développement, _etc._
|
||||
|
||||
## Stratégies de déploiement { #deployment-strategies }
|
||||
|
||||
Il existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous utilisez.
|
||||
Il existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous
|
||||
utilisez.
|
||||
|
||||
Vous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service cloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles.
|
||||
Vous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service
|
||||
cloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles.
|
||||
|
||||
Par exemple, nous, l'équipe derrière FastAPI, avons créé <a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a>, pour rendre le déploiement d'applications FastAPI dans le cloud aussi simple que possible, avec la même expérience développeur que lorsque vous travaillez avec FastAPI.
|
||||
Par exemple, nous, l'équipe derrière FastAPI, avons créé <a href="https://fastapicloud.com" class="external-link" target="_blank">**FastAPI Cloud**</a>, pour rendre le déploiement d'applications FastAPI dans le cloud aussi fluide que possible, avec la même expérience développeur que lorsque vous travaillez avec FastAPI.
|
||||
|
||||
Je vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement d'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web).
|
||||
Je vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement
|
||||
d'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web).
|
||||
|
||||
Vous verrez plus de détails à avoir en tête et certaines des techniques pour le faire dans les sections suivantes. ✨
|
||||
|
||||
@@ -1,33 +1,82 @@
|
||||
# Exécuter un serveur manuellement - Uvicorn
|
||||
# Exécuter un serveur manuellement { #run-a-server-manually }
|
||||
|
||||
La principale chose dont vous avez besoin pour exécuter une application **FastAPI** sur une machine serveur distante est un programme serveur ASGI tel que **Uvicorn**.
|
||||
## Utiliser la commande `fastapi run` { #use-the-fastapi-run-command }
|
||||
|
||||
Il existe 3 principales alternatives :
|
||||
En bref, utilisez `fastapi run` pour servir votre application FastAPI :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```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 production server 🚀
|
||||
|
||||
Searching for package file structure from directories
|
||||
with <font color="#3465A4">__init__.py</font> files
|
||||
Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> module </font></span> 🐍 main.py
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> code </font></span> Importing the FastAPI app object from the module with
|
||||
the following code:
|
||||
|
||||
<u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> app </font></span> Using import string: <font color="#3465A4">main:app</font>
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> server </font></span> Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>
|
||||
|
||||
Logs:
|
||||
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Started server process <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b>
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Waiting for application startup.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Application startup complete.
|
||||
<span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span> Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C
|
||||
to quit<b>)</b>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Cela fonctionnerait pour la plupart des cas. 😎
|
||||
|
||||
Vous pourriez utiliser cette commande par exemple pour démarrer votre application **FastAPI** dans un conteneur, sur un serveur, etc.
|
||||
|
||||
## Serveurs ASGI { #asgi-servers }
|
||||
|
||||
Allons un peu plus en détail.
|
||||
|
||||
FastAPI utilise un standard pour construire des frameworks web Python et des serveurs appelé <abbr title="Asynchronous Server Gateway Interface - Interface passerelle serveur asynchrone">ASGI</abbr>. FastAPI est un framework web ASGI.
|
||||
|
||||
La principale chose dont vous avez besoin pour exécuter une application **FastAPI** (ou toute autre application ASGI) sur une machine serveur distante est un programme serveur ASGI comme **Uvicorn**, c'est celui utilisé par défaut par la commande `fastapi`.
|
||||
|
||||
Il existe plusieurs alternatives, notamment :
|
||||
|
||||
* <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a> : un serveur ASGI haute performance.
|
||||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a> : un serveur
|
||||
ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.
|
||||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a> : le serveur ASGI
|
||||
conçu pour Django Channels.
|
||||
* <a href="https://hypercorn.readthedocs.io/" class="external-link" target="_blank">Hypercorn</a> : un serveur ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.
|
||||
* <a href="https://github.com/django/daphne" class="external-link" target="_blank">Daphne</a> : le serveur ASGI conçu pour Django Channels.
|
||||
* <a href="https://github.com/emmett-framework/granian" class="external-link" target="_blank">Granian</a> : un serveur HTTP Rust pour les applications Python.
|
||||
* <a href="https://unit.nginx.org/howto/fastapi/" class="external-link" target="_blank">NGINX Unit</a> : NGINX Unit est un environnement d'exécution d'applications web léger et polyvalent.
|
||||
|
||||
## Machine serveur et programme serveur
|
||||
## Machine serveur et programme serveur { #server-machine-and-server-program }
|
||||
|
||||
Il y a un petit détail sur les noms à garder à l'esprit. 💡
|
||||
|
||||
Le mot "**serveur**" est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
|
||||
Le mot « serveur » est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).
|
||||
|
||||
Gardez cela à l'esprit lorsque vous lisez "serveur" en général, cela pourrait faire référence à l'une de ces deux choses.
|
||||
Gardez cela à l'esprit lorsque vous lisez « serveur » en général, cela pourrait faire référence à l'une de ces deux choses.
|
||||
|
||||
Lorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant Linux, en règle générale, sur laquelle vous exécutez des programmes.
|
||||
Lorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant normalement Linux, sur laquelle vous exécutez des programmes.
|
||||
|
||||
## Installer le programme serveur { #install-the-server-program }
|
||||
|
||||
## Installer le programme serveur
|
||||
Lorsque vous installez FastAPI, il est fourni avec un serveur de production, Uvicorn, et vous pouvez le démarrer avec la commande `fastapi run`.
|
||||
|
||||
Vous pouvez installer un serveur compatible ASGI avec :
|
||||
Mais vous pouvez également installer un serveur ASGI manuellement.
|
||||
|
||||
//// tab | Uvicorn
|
||||
Vous devez créer un [environnement virtuel](../virtual-environments.md){.internal-link target=_blank}, l'activer, puis vous pouvez installer l'application serveur.
|
||||
|
||||
* <a href="https://www.uvicorn.dev/" class="external-link" target="_blank">Uvicorn</a>, un serveur ASGI rapide comme l'éclair, basé sur uvloop et httptools.
|
||||
Par exemple, pour installer Uvicorn :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -39,39 +88,21 @@ $ pip install "uvicorn[standard]"
|
||||
|
||||
</div>
|
||||
|
||||
Un processus similaire s'appliquerait à tout autre programme de serveur ASGI.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
En ajoutant `standard`, Uvicorn va installer et utiliser quelques dépendances supplémentaires recommandées.
|
||||
|
||||
Cela inclut `uvloop`, le remplaçant performant de `asyncio`, qui fournit le gros gain de performance en matière de concurrence.
|
||||
Cela inclut `uvloop`, le remplaçant hautes performances de `asyncio`, qui fournit le gros gain de performance en matière de concurrence.
|
||||
|
||||
Lorsque vous installez FastAPI avec quelque chose comme `pip install "fastapi[standard]"`, vous obtenez déjà `uvicorn[standard]` aussi.
|
||||
|
||||
///
|
||||
|
||||
////
|
||||
## Exécuter le programme serveur { #run-the-server-program }
|
||||
|
||||
//// tab | Hypercorn
|
||||
|
||||
* <a href="https://github.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>, un serveur ASGI également compatible avec HTTP/2.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install hypercorn
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
...ou tout autre serveur ASGI.
|
||||
|
||||
////
|
||||
|
||||
## Exécutez le programme serveur
|
||||
|
||||
Vous pouvez ensuite exécuter votre application de la même manière que vous l'avez fait dans les tutoriels, mais sans l'option `--reload`, par exemple :
|
||||
|
||||
//// tab | Uvicorn
|
||||
Si vous avez installé un serveur ASGI manuellement, vous devrez normalement passer une chaîne d'import dans un format spécial pour qu'il importe votre application FastAPI :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -83,85 +114,44 @@ $ uvicorn main:app --host 0.0.0.0 --port 80
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
/// note | Remarque
|
||||
|
||||
//// tab | Hypercorn
|
||||
La commande `uvicorn main:app` fait référence à :
|
||||
|
||||
<div class="termy">
|
||||
* `main` : le fichier `main.py` (le « module » Python).
|
||||
* `app` : l'objet créé dans `main.py` avec la ligne `app = FastAPI()`.
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --bind 0.0.0.0:80
|
||||
C'est équivalent à :
|
||||
|
||||
Running on 0.0.0.0:8080 over http (CTRL + C to quit)
|
||||
```Python
|
||||
from main import app
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
////
|
||||
|
||||
/// warning
|
||||
|
||||
N'oubliez pas de supprimer l'option `--reload` si vous l'utilisiez.
|
||||
|
||||
L'option `--reload` consomme beaucoup plus de ressources, est plus instable, etc.
|
||||
|
||||
Cela aide beaucoup pendant le **développement**, mais vous **ne devriez pas** l'utiliser en **production**.
|
||||
|
||||
///
|
||||
|
||||
## Hypercorn avec Trio
|
||||
Chaque programme de serveur ASGI alternatif aurait une commande similaire, vous pouvez en lire plus dans leur documentation respective.
|
||||
|
||||
Starlette et **FastAPI** sont basés sur
|
||||
<a href="https://anyio.readthedocs.io/en/stable/" class="external-link" target="_blank">AnyIO</a>, qui les rend
|
||||
compatibles avec <a href="https://docs.python.org/3/library/asyncio-task.html" class="external-link" target="_blank">asyncio</a>, de la bibliothèque standard Python et
|
||||
<a href="https://trio.readthedocs.io/en/stable/" class="external-link" target="_blank">Trio</a>.
|
||||
/// warning | Alertes
|
||||
|
||||
Néanmoins, Uvicorn n'est actuellement compatible qu'avec asyncio, et il utilise normalement <a href="https://github.
|
||||
com/MagicStack/uvloop" class="external-link" target="_blank">`uvloop`</a >, le remplaçant hautes performances de `asyncio`.
|
||||
Uvicorn et d'autres serveurs prennent en charge une option `--reload` utile pendant le développement.
|
||||
|
||||
Mais si vous souhaitez utiliser directement **Trio**, vous pouvez utiliser **Hypercorn** car il le prend en charge. ✨
|
||||
L'option `--reload` consomme beaucoup plus de ressources, est plus instable, etc.
|
||||
|
||||
### Installer Hypercorn avec Trio
|
||||
Cela aide beaucoup pendant le **développement**, mais vous **ne devriez pas** l'utiliser en **production**.
|
||||
|
||||
Vous devez d'abord installer Hypercorn avec le support Trio :
|
||||
///
|
||||
|
||||
<div class="termy">
|
||||
## Concepts de déploiement { #deployment-concepts }
|
||||
|
||||
```console
|
||||
$ pip install "hypercorn[trio]"
|
||||
---> 100%
|
||||
```
|
||||
Ces exemples exécutent le programme serveur (par exemple Uvicorn), en démarrant **un seul processus**, à l'écoute sur toutes les IP (`0.0.0.0`) sur un port prédéfini (par exemple `80`).
|
||||
|
||||
</div>
|
||||
C'est l'idée de base. Mais vous voudrez probablement vous occuper de certaines choses supplémentaires, comme :
|
||||
|
||||
### Exécuter avec Trio
|
||||
* Sécurité - HTTPS
|
||||
* Exécution au démarrage
|
||||
* Redémarrages
|
||||
* Réplication (le nombre de processus en cours d'exécution)
|
||||
* Mémoire
|
||||
* Étapes précédant le démarrage
|
||||
|
||||
Ensuite, vous pouvez passer l'option de ligne de commande `--worker-class` avec la valeur `trio` :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ hypercorn main:app --worker-class trio
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Et cela démarrera Hypercorn avec votre application en utilisant Trio comme backend.
|
||||
|
||||
Vous pouvez désormais utiliser Trio en interne dans votre application. Ou mieux encore, vous pouvez utiliser AnyIO pour que votre code reste compatible avec Trio et asyncio. 🎉
|
||||
|
||||
## Concepts de déploiement
|
||||
|
||||
Ces exemples lancent le programme serveur (e.g. Uvicorn), démarrant **un seul processus**, sur toutes les IPs (`0.0.
|
||||
0.0`) sur un port prédéfini (par example, `80`).
|
||||
|
||||
C'est l'idée de base. Mais vous vous préoccuperez probablement de certains concepts supplémentaires, tels que ... :
|
||||
|
||||
* la sécurité - HTTPS
|
||||
* l'exécution au démarrage
|
||||
* les redémarrages
|
||||
* la réplication (le nombre de processus en cours d'exécution)
|
||||
* la mémoire
|
||||
* les étapes précédant le démarrage
|
||||
|
||||
Je vous en dirai plus sur chacun de ces concepts, sur la façon de les aborder, et donnerai quelques exemples concrets avec des stratégies pour les traiter dans les prochains chapitres. 🚀
|
||||
Je vous en dirai plus sur chacun de ces concepts, sur la manière d'y réfléchir, et donnerai quelques exemples concrets avec des stratégies pour les gérer dans les prochains chapitres. 🚀
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
# À propos des versions de FastAPI { #about-fastapi-versions }
|
||||
|
||||
**FastAPI** est déjà utilisé en production dans de nombreuses applications et systèmes. Et la couverture de test est maintenue à 100 %. Mais son développement est toujours aussi rapide.
|
||||
**FastAPI** est déjà utilisé en production dans de nombreuses applications et de nombreux systèmes. Et la couverture de tests est maintenue à 100 %. Mais son développement avance toujours rapidement.
|
||||
|
||||
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code est
|
||||
amélioré continuellement.
|
||||
De nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code s'améliore continuellement.
|
||||
|
||||
C'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version peut potentiellement
|
||||
recevoir des changements non rétrocompatibles. Cela suit les conventions de <a href="https://semver.org/" class="external-link" target="_blank">versionnage sémantique</a>.
|
||||
C'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version pourrait potentiellement comporter des changements non rétrocompatibles. Cela suit les conventions de <a href="https://semver.org/" class="external-link" target="_blank">versionnage sémantique</a>.
|
||||
|
||||
Vous pouvez créer des applications de production avec **FastAPI** dès maintenant (et vous le faites probablement depuis un certain temps), vous devez juste vous assurer que vous utilisez une version qui fonctionne correctement avec le reste de votre code.
|
||||
|
||||
## Épinglez votre version de `fastapi` { #pin-your-fastapi-version }
|
||||
## Épingler votre version de `fastapi` { #pin-your-fastapi-version }
|
||||
|
||||
Tout d'abord il faut «épingler» la version de **FastAPI** que vous utilisez à la dernière version dont vous savez
|
||||
qu'elle fonctionne correctement pour votre application.
|
||||
La première chose que vous devez faire est « épingler » la version de **FastAPI** que vous utilisez à la dernière version spécifique dont vous savez qu’elle fonctionne correctement pour votre application.
|
||||
|
||||
Par exemple, disons que vous utilisez la version `0.112.0` dans votre application.
|
||||
|
||||
Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec :
|
||||
Si vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec :
|
||||
|
||||
```txt
|
||||
fastapi[standard]==0.112.0
|
||||
@@ -25,7 +22,7 @@ fastapi[standard]==0.112.0
|
||||
|
||||
ce qui signifierait que vous utiliseriez exactement la version `0.112.0`.
|
||||
|
||||
Ou vous pourriez aussi l'épingler avec :
|
||||
Ou vous pourriez aussi l'épingler avec :
|
||||
|
||||
```txt
|
||||
fastapi[standard]>=0.112.0,<0.113.0
|
||||
@@ -41,46 +38,43 @@ Vous pouvez consulter les versions disponibles (par exemple, pour vérifier quel
|
||||
|
||||
## À propos des versions { #about-versions }
|
||||
|
||||
Suivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter
|
||||
des changements non rétrocompatibles.
|
||||
Suivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter des changements non rétrocompatibles.
|
||||
|
||||
FastAPI suit également la convention que tout changement de version «PATCH» est pour des corrections de bogues et
|
||||
des changements rétrocompatibles.
|
||||
FastAPI suit également la convention selon laquelle tout changement de version « PATCH » concerne des corrections de bogues et des changements rétrocompatibles.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le «PATCH» est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.
|
||||
Le « PATCH » est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.
|
||||
|
||||
///
|
||||
|
||||
Donc, vous devriez être capable d'épingler une version comme suit :
|
||||
Donc, vous devriez être en mesure d'épingler une version comme suit :
|
||||
|
||||
```txt
|
||||
fastapi>=0.45.0,<0.46.0
|
||||
```
|
||||
|
||||
Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions «MINOR».
|
||||
Les changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions « MINOR ».
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le «MINOR» est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
|
||||
Le « MINOR » est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.
|
||||
|
||||
///
|
||||
|
||||
## Mettre à niveau les versions de FastAPI { #upgrading-the-fastapi-versions }
|
||||
|
||||
Vous devriez ajouter des tests pour votre application.
|
||||
Vous devez ajouter des tests pour votre application.
|
||||
|
||||
Avec **FastAPI** c'est très facile (merci à Starlette), consultez la documentation : [Tests](../tutorial/testing.md){.internal-link target=_blank}
|
||||
Avec **FastAPI** c'est très facile (merci à Starlette), consultez les documents : [Tests](../tutorial/testing.md){.internal-link target=_blank}
|
||||
|
||||
Après avoir effectué des tests, vous pouvez mettre à niveau la version de **FastAPI** vers une version plus récente, et vous assurer que tout votre code fonctionne correctement en exécutant vos tests.
|
||||
Après avoir des tests, vous pouvez mettre à niveau la version de **FastAPI** vers une version plus récente et vous assurer que tout votre code fonctionne correctement en exécutant vos tests.
|
||||
|
||||
Si tout fonctionne, ou après avoir fait les changements nécessaires, et que tous vos tests passent, vous pouvez
|
||||
épingler votre version de `fastapi` à cette nouvelle version récente.
|
||||
Si tout fonctionne, ou après avoir effectué les changements nécessaires, et que tous vos tests passent, vous pouvez alors épingler votre `fastapi` à cette nouvelle version récente.
|
||||
|
||||
## À propos de Starlette { #about-starlette }
|
||||
|
||||
Vous ne devriez pas épingler la version de `starlette`.
|
||||
Vous ne devez pas épingler la version de `starlette`.
|
||||
|
||||
Différentes versions de **FastAPI** utiliseront une version spécifique plus récente de Starlette.
|
||||
|
||||
@@ -88,12 +82,11 @@ Ainsi, vous pouvez simplement laisser **FastAPI** utiliser la bonne version de S
|
||||
|
||||
## À propos de Pydantic { #about-pydantic }
|
||||
|
||||
Pydantic inclut des tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus
|
||||
de `1.0.0`) sont toujours compatibles avec **FastAPI**.
|
||||
Pydantic inclut les tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus de `1.0.0`) sont toujours compatibles avec FastAPI.
|
||||
|
||||
Vous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous.
|
||||
|
||||
Par exemple :
|
||||
Par exemple :
|
||||
|
||||
```txt
|
||||
pydantic>=2.7.0,<3.0.0
|
||||
|
||||
@@ -29,24 +29,24 @@
|
||||
|
||||
**Documentation** : <a href="https://fastapi.tiangolo.com/fr" target="_blank">https://fastapi.tiangolo.com/fr</a>
|
||||
|
||||
**Code source** : <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
|
||||
**Code Source** : <a href="https://github.com/fastapi/fastapi" target="_blank">https://github.com/fastapi/fastapi</a>
|
||||
|
||||
---
|
||||
|
||||
FastAPI est un framework web moderne et rapide (haute performance) pour la création d’API avec Python, basé sur les annotations de type standard de Python.
|
||||
FastAPI est un framework web moderne et rapide (haute performance) pour la création d'API avec Python, basé sur les annotations de type standard de Python.
|
||||
|
||||
Les principales fonctionnalités sont :
|
||||
|
||||
* **Rapide** : Très hautes performances, au niveau de **NodeJS** et **Go** (grâce à Starlette et Pydantic). [L’un des frameworks Python les plus rapides](#performance).
|
||||
* **Rapide à coder** : Augmente la vitesse de développement des fonctionnalités d’environ 200 % à 300 %. *
|
||||
* **Moins de bugs** : Réduit d’environ 40 % les erreurs induites par le développeur. *
|
||||
* **Intuitif** : Excellente prise en charge par les éditeurs. <abbr title="également connu sous le nom d’auto-complétion, autocomplétion, IntelliSense">Complétion</abbr> partout. Moins de temps passé à déboguer.
|
||||
* **Facile** : Conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire la documentation.
|
||||
* **Concis** : Minimise la duplication de code. Plusieurs fonctionnalités à partir de chaque déclaration de paramètre. Moins de bugs.
|
||||
* **Robuste** : Obtenez du code prêt pour la production. Avec une documentation interactive automatique.
|
||||
* **Basé sur des standards** : Basé sur (et entièrement compatible avec) les standards ouverts pour les API : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (anciennement connu sous le nom de Swagger) et <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
* **Rapide** : très hautes performances, au niveau de **NodeJS** et **Go** (grâce à Starlette et Pydantic). [L'un des frameworks Python les plus rapides](#performance).
|
||||
* **Rapide à coder** : augmente la vitesse de développement des fonctionnalités d'environ 200 % à 300 %. *
|
||||
* **Moins de bugs** : réduit d'environ 40 % les erreurs induites par le développeur. *
|
||||
* **Intuitif** : excellente compatibilité avec les éditeurs. <abbr title="également appelé autocomplétion, IntelliSense">Autocomplétion</abbr> partout. Moins de temps passé à déboguer.
|
||||
* **Facile** : conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire les documents.
|
||||
* **Concis** : diminue la duplication de code. Plusieurs fonctionnalités à partir de chaque déclaration de paramètre. Moins de bugs.
|
||||
* **Robuste** : obtenez un code prêt pour la production. Avec une documentation interactive automatique.
|
||||
* **Basé sur des normes** : basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (précédemment connu sous le nom de Swagger) et <a href="https://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>.
|
||||
|
||||
<small>* estimation basée sur des tests d’une équipe de développement interne, construisant des applications de production.</small>
|
||||
<small>* estimation basée sur des tests d'une équipe de développement interne, construisant des applications de production.</small>
|
||||
|
||||
## Sponsors { #sponsors }
|
||||
|
||||
@@ -73,45 +73,45 @@ Les principales fonctionnalités sont :
|
||||
|
||||
## Opinions { #opinions }
|
||||
|
||||
«_[...] J’utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l’utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d’entre eux seront intégrés dans le cœur de **Windows** et dans certains produits **Office**._»
|
||||
« _[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux sont intégrés au cœur de **Windows** et à certains produits **Office**._ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>Microsoft</strong> <a href="https://github.com/fastapi/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
«_Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_»
|
||||
« _Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin et Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin, et Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
«_**Netflix** a le plaisir d’annoncer la sortie en open-source de notre framework d’orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_»
|
||||
« _**Netflix** est heureux d'annoncer la publication en open source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
«_Je suis très enthousiaste à propos de **FastAPI**. C’est un bonheur !_»
|
||||
« _Je suis plus qu'enthousiaste à propos de **FastAPI**. C'est tellement fun !_ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong>Animateur du podcast <a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a></strong> <a href="https://x.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
«_Honnêtement, ce que vous avez construit a l’air super solide et élégant. À bien des égards, c’est comme ça que je voulais que **Hug** soit — c’est vraiment inspirant de voir quelqu’un construire ça._»
|
||||
« _Honnêtement, ce que vous avez construit a l'air super solide et soigné. À bien des égards, c'est ce que je voulais que **Hug** soit — c'est vraiment inspirant de voir quelqu'un construire ça._ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong>Créateur de <a href="https://github.com/hugapi/hug" target="_blank">Hug</a></strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
«_Si vous cherchez à apprendre un **framework moderne** pour créer des API REST, regardez **FastAPI** [...] C’est rapide, facile à utiliser et à apprendre [...]_»
|
||||
« _Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et facile à apprendre [...]_ »
|
||||
|
||||
«_Nous sommes passés à **FastAPI** pour nos **API** [...] Je pense que vous l’aimerez [...]_»
|
||||
« _Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>Fondateurs de <a href="https://explosion.ai" target="_blank">Explosion AI</a> — Créateurs de <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong>Fondateurs de <a href="https://explosion.ai" target="_blank">Explosion AI</a> - Créateurs de <a href="https://spacy.io" target="_blank">spaCy</a></strong> <a href="https://x.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://x.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
«_Si quelqu’un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **bien conçu**, **simple à utiliser** et **très évolutif**, il est devenu un **composant clé** dans notre stratégie de développement API first et il est à l’origine de nombreux automatismes et services tels que notre ingénieur virtuel TAC._»
|
||||
« _Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **magnifiquement conçu**, **simple à utiliser** et **hautement scalable**. Il est devenu un **composant clé** de notre stratégie de développement API-first et alimente de nombreuses automatisations et services tels que notre ingénieur TAC virtuel._ »
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Deon Pillsbury - <strong>Cisco</strong> <a href="https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
@@ -119,17 +119,17 @@ Les principales fonctionnalités sont :
|
||||
|
||||
## Mini documentaire FastAPI { #fastapi-mini-documentary }
|
||||
|
||||
Un <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documentaire FastAPI</a> est sorti à la fin de 2025, vous pouvez le regarder en ligne :
|
||||
Un <a href="https://www.youtube.com/watch?v=mpR8ngthqiE" class="external-link" target="_blank">mini documentaire FastAPI</a> est sorti fin 2025, vous pouvez le regarder en ligne :
|
||||
|
||||
<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**, le FastAPI des <abbr title="Command Line Interface – Interface en ligne de commande">CLI</abbr> { #typer-the-fastapi-of-clis }
|
||||
## **Typer**, le FastAPI des 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>
|
||||
|
||||
Si vous souhaitez construire une application <abbr title="Command Line Interface – Interface en ligne de commande">CLI</abbr> utilisable dans un terminal au lieu d’une API web, regardez <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
Si vous construisez une application <abbr title="Command Line Interface - Interface en ligne de commande">CLI</abbr> à utiliser dans un terminal au lieu d'une API web, regardez <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>.
|
||||
|
||||
**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des CLI**. ⌨️ 🚀
|
||||
**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des CLIs**. ⌨️ 🚀
|
||||
|
||||
## Prérequis { #requirements }
|
||||
|
||||
@@ -152,7 +152,7 @@ $ pip install "fastapi[standard]"
|
||||
|
||||
</div>
|
||||
|
||||
**Remarque** : Assurez-vous de mettre `"fastapi[standard]"` entre guillemets pour garantir que cela fonctionne dans tous les terminaux.
|
||||
**Remarque** : Vous devez vous assurer de mettre « fastapi[standard] » entre guillemets pour garantir que cela fonctionne dans tous les terminaux.
|
||||
|
||||
## Exemple { #example }
|
||||
|
||||
@@ -161,8 +161,6 @@ $ pip install "fastapi[standard]"
|
||||
Créez un fichier `main.py` avec :
|
||||
|
||||
```Python
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -174,7 +172,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -183,9 +181,7 @@ def read_item(item_id: int, q: Union[str, None] = None):
|
||||
|
||||
Si votre code utilise `async` / `await`, utilisez `async def` :
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Union
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -197,13 +193,13 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: Union[str, None] = None):
|
||||
async def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
**Remarque** :
|
||||
|
||||
Si vous ne savez pas, consultez la section _«In a hurry?»_ à propos de <a href="https://fastapi.tiangolo.com/fr/async/#in-a-hurry" target="_blank">`async` et `await` dans la documentation</a>.
|
||||
Si vous ne savez pas, consultez la section « Vous êtes pressés ? » à propos de <a href="https://fastapi.tiangolo.com/fr/async/#in-a-hurry" target="_blank">`async` et `await` dans la documentation</a>.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -241,17 +237,17 @@ INFO: Application startup complete.
|
||||
<details markdown="1">
|
||||
<summary>À propos de la commande <code>fastapi dev main.py</code>...</summary>
|
||||
|
||||
La commande `fastapi dev` lit votre fichier `main.py`, détecte l’application **FastAPI** qu’il contient et démarre un serveur avec <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>.
|
||||
La commande `fastapi dev` lit votre fichier `main.py`, détecte l'application **FastAPI** qu'il contient et lance un serveur avec <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>.
|
||||
|
||||
Par défaut, `fastapi dev` démarre avec le rechargement automatique activé pour le développement local.
|
||||
|
||||
Vous pouvez en lire davantage dans la <a href="https://fastapi.tiangolo.com/fr/fastapi-cli/" target="_blank">documentation de la CLI FastAPI</a>.
|
||||
Vous pouvez en savoir plus dans la <a href="https://fastapi.tiangolo.com/fr/fastapi-cli/" target="_blank">documentation de la CLI FastAPI</a>.
|
||||
|
||||
</details>
|
||||
|
||||
### Vérifier { #check-it }
|
||||
|
||||
Ouvrez votre navigateur à l’adresse <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
Ouvrez votre navigateur à l'adresse <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
|
||||
|
||||
Vous verrez la réponse JSON :
|
||||
|
||||
@@ -261,36 +257,34 @@ Vous verrez la réponse JSON :
|
||||
|
||||
Vous avez déjà créé une API qui :
|
||||
|
||||
* Reçoit des requêtes HTTP pour les _chemins_ `/` et `/items/{item_id}`.
|
||||
* Les deux _chemins_ acceptent des <em>opérations</em> `GET` (également connues comme _méthodes_ HTTP).
|
||||
* Reçoit des requêtes HTTP sur les _chemins_ `/` et `/items/{item_id}`.
|
||||
* Les deux _chemins_ acceptent des <em>opérations</em> `GET` (également connues sous le nom de _méthodes_ HTTP).
|
||||
* Le _chemin_ `/items/{item_id}` a un _paramètre de chemin_ `item_id` qui doit être un `int`.
|
||||
* Le _chemin_ `/items/{item_id}` a un _paramètre de requête_ optionnel `q` de type `str`.
|
||||
|
||||
### Documentation API interactive { #interactive-api-docs }
|
||||
|
||||
Maintenant, allez sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Vous verrez la documentation API interactive automatique (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
Vous verrez la documentation interactive automatique de l'API (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
|
||||

|
||||
|
||||
### Documentation API alternative { #alternative-api-docs }
|
||||
|
||||
Et maintenant, allez sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
Et maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
Vous verrez la documentation alternative automatique (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
|
||||

|
||||
|
||||
## Exemple de mise à niveau { #example-upgrade }
|
||||
## Mettre à niveau l'exemple { #example-upgrade }
|
||||
|
||||
Modifiez maintenant le fichier `main.py` pour recevoir le corps d’une requête `PUT`.
|
||||
Modifiez maintenant le fichier `main.py` pour recevoir un corps depuis une requête `PUT`.
|
||||
|
||||
Déclarez le corps en utilisant les types Python standards, grâce à Pydantic.
|
||||
|
||||
```Python hl_lines="4 9-12 25-27"
|
||||
from typing import Union
|
||||
Déclarez le corps en utilisant les types Python standard, grâce à Pydantic.
|
||||
|
||||
```Python hl_lines="2 7-10 23-25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -300,7 +294,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: Union[bool, None] = None
|
||||
is_offer: bool | None = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -309,7 +303,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: Union[str, None] = None):
|
||||
def read_item(item_id: int, q: str | None = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@@ -320,37 +314,37 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||
Le serveur `fastapi dev` devrait se recharger automatiquement.
|
||||
|
||||
### Mise à niveau de la documentation API interactive { #interactive-api-docs-upgrade }
|
||||
### Mettre à niveau la documentation API interactive { #interactive-api-docs-upgrade }
|
||||
|
||||
Maintenant, allez sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
* La documentation API interactive sera automatiquement mise à jour, y compris le nouveau corps :
|
||||
* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps :
|
||||
|
||||

|
||||
|
||||
* Cliquez sur le bouton «Try it out», il vous permet de renseigner les paramètres et d’interagir directement avec l’API :
|
||||
* Cliquez sur le bouton « Try it out », il vous permet de renseigner les paramètres et d'interagir directement avec l'API :
|
||||
|
||||

|
||||
|
||||
* Cliquez ensuite sur le bouton «Execute», l’interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l’écran :
|
||||
* Cliquez ensuite sur le bouton « Execute », l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran :
|
||||
|
||||

|
||||
|
||||
### Mise à niveau de la documentation API alternative { #alternative-api-docs-upgrade }
|
||||
### Mettre à niveau la documentation API alternative { #alternative-api-docs-upgrade }
|
||||
|
||||
Et maintenant, allez sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
Et maintenant, rendez-vous sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
* La documentation alternative reflètera également le nouveau paramètre de requête et le nouveau corps :
|
||||
|
||||

|
||||
|
||||
### Récapitulatif { #recap }
|
||||
### En résumé { #recap }
|
||||
|
||||
En résumé, vous déclarez **une fois** les types de paramètres, le corps, etc. comme paramètres de fonction.
|
||||
En résumé, vous déclarez **une fois** les types de paramètres, le corps, etc. en tant que paramètres de fonction.
|
||||
|
||||
Vous faites cela avec les types Python modernes standards.
|
||||
Vous faites cela avec les types Python standard modernes.
|
||||
|
||||
Vous n’avez pas à apprendre une nouvelle syntaxe, les méthodes ou classes d’une bibliothèque spécifique, etc.
|
||||
Vous n'avez pas à apprendre une nouvelle syntaxe, les méthodes ou les classes d'une bibliothèque spécifique, etc.
|
||||
|
||||
Juste du **Python** standard.
|
||||
|
||||
@@ -366,15 +360,15 @@ ou pour un modèle `Item` plus complexe :
|
||||
item: Item
|
||||
```
|
||||
|
||||
... et avec cette seule déclaration vous obtenez :
|
||||
... et avec cette déclaration unique, vous obtenez :
|
||||
|
||||
* Assistance de l’éditeur, notamment :
|
||||
* Complétion.
|
||||
* Vérifications de type.
|
||||
* Validation des données :
|
||||
* Des erreurs automatiques et claires lorsque les données ne sont pas valides.
|
||||
* Une validation même pour des objets JSON profondément imbriqués.
|
||||
* <abbr title="également connu sous le nom de : sérialisation, analyse, marshalling">Conversion</abbr> des données d’entrée : depuis le réseau vers les données et types Python. Lecture depuis :
|
||||
* Une assistance dans l'éditeur, notamment :
|
||||
* l'autocomplétion.
|
||||
* la vérification des types.
|
||||
* La validation des données :
|
||||
* des erreurs automatiques et claires lorsque les données ne sont pas valides.
|
||||
* une validation même pour les objets JSON profondément imbriqués.
|
||||
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Conversion</abbr> des données d'entrée : venant du réseau vers les données et types Python. Lecture depuis :
|
||||
* JSON.
|
||||
* Paramètres de chemin.
|
||||
* Paramètres de requête.
|
||||
@@ -382,42 +376,42 @@ item: Item
|
||||
* En-têtes.
|
||||
* Formulaires.
|
||||
* Fichiers.
|
||||
* <abbr title="également connu sous le nom de : sérialisation, analyse, marshalling">Conversion</abbr> des données de sortie : conversion des données et types Python en données réseau (au format JSON) :
|
||||
* <abbr title="aussi connu sous le nom de : serialization, parsing, marshalling">Conversion</abbr> des données de sortie : conversion des données et types Python en données réseau (au format JSON) :
|
||||
* Conversion des types Python (`str`, `int`, `float`, `bool`, `list`, etc).
|
||||
* Objets `datetime`.
|
||||
* Objets `UUID`.
|
||||
* Modèles de base de données.
|
||||
* ... et bien plus.
|
||||
* Documentation API interactive automatique, avec 2 interfaces utilisateur alternatives :
|
||||
* Documentation API interactive automatique, avec 2 interfaces utilisateur au choix :
|
||||
* Swagger UI.
|
||||
* ReDoc.
|
||||
|
||||
---
|
||||
|
||||
Pour revenir à l’exemple de code précédent, **FastAPI** va :
|
||||
Pour revenir à l'exemple de code précédent, **FastAPI** va :
|
||||
|
||||
* Valider la présence d’un `item_id` dans le chemin pour les requêtes `GET` et `PUT`.
|
||||
* Valider la présence d'un `item_id` dans le chemin pour les requêtes `GET` et `PUT`.
|
||||
* Valider que `item_id` est de type `int` pour les requêtes `GET` et `PUT`.
|
||||
* Si ce n’est pas le cas, le client verra une erreur utile et claire.
|
||||
* Vérifier s’il existe un paramètre de requête optionnel nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.
|
||||
* Si ce n'est pas le cas, le client verra une erreur utile et claire.
|
||||
* Vérifier s'il existe un paramètre de requête optionnel nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.
|
||||
* Comme le paramètre `q` est déclaré avec `= None`, il est optionnel.
|
||||
* Sans le `None`, il serait requis (comme l’est le corps dans le cas du `PUT`).
|
||||
* Pour les requêtes `PUT` vers `/items/{item_id}`, lire le corps en JSON :
|
||||
* Vérifier qu’il possède un attribut obligatoire `name` qui doit être un `str`.
|
||||
* Vérifier qu’il possède un attribut obligatoire `price` qui doit être un `float`.
|
||||
* Vérifier qu’il possède un attribut optionnel `is_offer`, qui doit être un `bool`, s’il est présent.
|
||||
* Tout cela fonctionnerait également pour des objets JSON profondément imbriqués.
|
||||
* Convertir depuis et vers JSON automatiquement.
|
||||
* Sans le `None`, il serait requis (comme l'est le corps dans le cas de `PUT`).
|
||||
* Pour les requêtes `PUT` vers `/items/{item_id}`, lire le corps au format JSON :
|
||||
* Vérifier qu'il a un attribut obligatoire `name` qui doit être un `str`.
|
||||
* Vérifier qu'il a un attribut obligatoire `price` qui doit être un `float`.
|
||||
* Vérifier qu'il a un attribut optionnel `is_offer`, qui doit être un `bool`, s'il est présent.
|
||||
* Tout cela fonctionne également pour les objets JSON profondément imbriqués.
|
||||
* Convertir automatiquement depuis et vers JSON.
|
||||
* Tout documenter avec OpenAPI, qui peut être utilisé par :
|
||||
* Des systèmes de documentation interactive.
|
||||
* Des systèmes de génération automatique de code client, pour de nombreuses langues.
|
||||
* des systèmes de documentation interactive.
|
||||
* des systèmes de génération automatique de clients, pour de nombreux langages.
|
||||
* Fournir directement 2 interfaces web de documentation interactive.
|
||||
|
||||
---
|
||||
|
||||
Nous n’avons fait qu’effleurer la surface, mais vous comprenez déjà l’idée de fonctionnement général.
|
||||
Nous n'avons fait qu'effleurer la surface, mais vous avez déjà une idée de la façon dont tout fonctionne.
|
||||
|
||||
Essayez de changer la ligne :
|
||||
Essayez de changer la ligne contenant :
|
||||
|
||||
```Python
|
||||
return {"item_name": item.name, "item_id": item_id}
|
||||
@@ -429,40 +423,40 @@ Essayez de changer la ligne :
|
||||
... "item_name": item.name ...
|
||||
```
|
||||
|
||||
... vers :
|
||||
... à :
|
||||
|
||||
```Python
|
||||
... "item_price": item.price ...
|
||||
```
|
||||
|
||||
... et voyez comment votre éditeur complètera automatiquement les attributs et connaîtra leurs types :
|
||||
... et voyez comment votre éditeur complète automatiquement les attributs et connaît leurs types :
|
||||
|
||||

|
||||
|
||||
Pour un exemple plus complet incluant davantage de fonctionnalités, voir le <a href="https://fastapi.tiangolo.com/fr/tutorial/">Tutoriel - Guide utilisateur</a>.
|
||||
Pour un exemple plus complet comprenant plus de fonctionnalités, voir le <a href="https://fastapi.tiangolo.com/fr/tutorial/">Tutoriel - Guide utilisateur</a>.
|
||||
|
||||
**Alerte spoiler** : le tutoriel - guide utilisateur inclut :
|
||||
|
||||
* Déclaration de **paramètres** provenant d’autres endroits tels que : **en-têtes**, **cookies**, **champs de formulaire** et **fichiers**.
|
||||
* Déclaration de **paramètres** provenant d'autres emplacements comme : **en-têtes**, **cookies**, **champs de formulaire** et **fichiers**.
|
||||
* Comment définir des **contraintes de validation** comme `maximum_length` ou `regex`.
|
||||
* Un système de **<abbr title="également connu sous le nom de composants, ressources, fournisseurs, services, injectables">Injection de dépendances</abbr>** très puissant et facile à utiliser.
|
||||
* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec les **jetons <abbr title="JSON Web Tokens">JWT</abbr>** et l’authentification **HTTP Basic**.
|
||||
* Des techniques plus avancées (mais tout aussi simples) pour déclarer des **modèles JSON profondément imbriqués** (grâce à Pydantic).
|
||||
* Intégration **GraphQL** avec <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> et d’autres bibliothèques.
|
||||
* Un système **<abbr title="aussi connu sous le nom de composants, ressources, fournisseurs, services, injectables">d'injection de dépendances</abbr>** très puissant et facile à utiliser.
|
||||
* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec des **JWT tokens** et l'authentification **HTTP Basic**.
|
||||
* Des techniques plus avancées (mais tout aussi faciles) pour déclarer des **modèles JSON profondément imbriqués** (grâce à Pydantic).
|
||||
* Intégration **GraphQL** avec <a href="https://strawberry.rocks" class="external-link" target="_blank">Strawberry</a> et d'autres bibliothèques.
|
||||
* De nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :
|
||||
* **WebSockets**
|
||||
* des tests extrêmement faciles basés sur HTTPX et `pytest`
|
||||
* **CORS**
|
||||
* **Sessions Cookie**
|
||||
* **Cookie Sessions**
|
||||
* ... et plus encore.
|
||||
|
||||
### Déployer votre application (optionnel) { #deploy-your-app-optional }
|
||||
|
||||
Vous pouvez éventuellement déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, allez vous inscrire sur la liste d’attente si ce n’est pas déjà fait. 🚀
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, allez vous inscrire sur la liste d'attente si ce n'est pas déjà fait. 🚀
|
||||
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d'attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
|
||||
Avant de déployer, assurez-vous d’être connecté :
|
||||
Avant de déployer, assurez-vous d'être connecté :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -490,27 +484,27 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
C’est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
C'est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
|
||||
#### À propos de FastAPI Cloud { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est créé par le même auteur et la même équipe derrière **FastAPI**.
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est construit par le même auteur et la même équipe derrière **FastAPI**.
|
||||
|
||||
Il simplifie le processus de **construction**, de **déploiement** et d’**accès** à une API avec un minimum d’efforts.
|
||||
Il simplifie le processus de **construction**, de **déploiement** et **d'accès** à une API avec un effort minimal.
|
||||
|
||||
Il apporte la même **expérience développeur** de la création d’applications avec FastAPI au **déploiement** dans le cloud. 🎉
|
||||
Il apporte la même **expérience développeur** de la création d'applications avec FastAPI au **déploiement** dans le cloud. 🎉
|
||||
|
||||
FastAPI Cloud est le sponsor principal et le financeur des projets open source *FastAPI and friends*. ✨
|
||||
FastAPI Cloud est le principal sponsor et financeur des projets open source *FastAPI and friends*. ✨
|
||||
|
||||
#### Déployer sur d’autres fournisseurs cloud { #deploy-to-other-cloud-providers }
|
||||
#### Déployer sur d'autres fournisseurs cloud { #deploy-to-other-cloud-providers }
|
||||
|
||||
FastAPI est open source et basé sur des standards. Vous pouvez déployer des applications FastAPI sur n’importe quel fournisseur cloud de votre choix.
|
||||
FastAPI est open source et basé sur des standards. Vous pouvez déployer des applications FastAPI sur n'importe quel fournisseur cloud de votre choix.
|
||||
|
||||
Suivez les guides de votre fournisseur cloud pour y déployer des applications FastAPI. 🤓
|
||||
|
||||
## Performance { #performance }
|
||||
|
||||
Les benchmarks indépendants TechEmpower montrent que les applications **FastAPI** s’exécutant sous Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">parmi les frameworks Python les plus rapides</a>, juste derrière Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI). (*)
|
||||
Les benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">parmi les frameworks Python les plus rapides</a>, juste derrière Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI). (*)
|
||||
|
||||
Pour en savoir plus, consultez la section <a href="https://fastapi.tiangolo.com/fr/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
|
||||
|
||||
@@ -520,25 +514,25 @@ FastAPI dépend de Pydantic et Starlette.
|
||||
|
||||
### Dépendances `standard` { #standard-dependencies }
|
||||
|
||||
Lorsque vous installez FastAPI avec `pip install "fastapi[standard]"`, cela inclut le groupe `standard` de dépendances optionnelles :
|
||||
Lorsque vous installez FastAPI avec `pip install "fastapi[standard]"`, il inclut le groupe `standard` de dépendances optionnelles :
|
||||
|
||||
Utilisées par Pydantic :
|
||||
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> — pour la validation des adresses email.
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email-validator</code></a> - pour la validation des adresses e-mail.
|
||||
|
||||
Utilisées par Starlette :
|
||||
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> — requis si vous souhaitez utiliser `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> — requis si vous souhaitez utiliser la configuration de template par défaut.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> — requis si vous souhaitez prendre en charge l’<abbr title="conversion de la chaîne provenant d’une requête HTTP en données Python">«décodage»</abbr> de formulaires avec `request.form()`.
|
||||
* <a href="https://www.python-httpx.org" target="_blank"><code>httpx</code></a> - Obligatoire si vous souhaitez utiliser le `TestClient`.
|
||||
* <a href="https://jinja.palletsprojects.com" target="_blank"><code>jinja2</code></a> - Obligatoire si vous souhaitez utiliser la configuration de template par défaut.
|
||||
* <a href="https://github.com/Kludex/python-multipart" target="_blank"><code>python-multipart</code></a> - Obligatoire si vous souhaitez prendre en charge l’<abbr title="convertir la chaîne issue d'une requête HTTP en données Python">« parsing »</abbr> de formulaires avec `request.form()`.
|
||||
|
||||
Utilisées par FastAPI :
|
||||
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> — pour le serveur qui charge et sert votre application. Cela inclut `uvicorn[standard]`, qui comprend certaines dépendances (par ex. `uvloop`) nécessaires pour un service à haute performance.
|
||||
* `fastapi-cli[standard]` — pour fournir la commande `fastapi`.
|
||||
* <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - pour le serveur qui charge et sert votre application. Cela inclut `uvicorn[standard]`, qui comprend certaines dépendances (par ex. `uvloop`) nécessaires pour une haute performance.
|
||||
* `fastapi-cli[standard]` - pour fournir la commande `fastapi`.
|
||||
* Cela inclut `fastapi-cloud-cli`, qui vous permet de déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
|
||||
|
||||
### Sans dépendances `standard` { #without-standard-dependencies }
|
||||
### Sans les dépendances `standard` { #without-standard-dependencies }
|
||||
|
||||
Si vous ne souhaitez pas inclure les dépendances optionnelles `standard`, vous pouvez installer avec `pip install fastapi` au lieu de `pip install "fastapi[standard]"`.
|
||||
|
||||
@@ -546,19 +540,19 @@ Si vous ne souhaitez pas inclure les dépendances optionnelles `standard`, vous
|
||||
|
||||
Si vous souhaitez installer FastAPI avec les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
|
||||
|
||||
### Autres dépendances optionnelles { #additional-optional-dependencies }
|
||||
### Dépendances optionnelles supplémentaires { #additional-optional-dependencies }
|
||||
|
||||
Il existe des dépendances supplémentaires que vous pourriez vouloir installer.
|
||||
|
||||
Dépendances optionnelles supplémentaires pour Pydantic :
|
||||
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> — pour la gestion des paramètres.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> — pour des types supplémentaires à utiliser avec Pydantic.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - pour la gestion des paramètres.
|
||||
* <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - pour des types supplémentaires à utiliser avec Pydantic.
|
||||
|
||||
Dépendances optionnelles supplémentaires pour FastAPI :
|
||||
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> — requis si vous souhaitez utiliser `ORJSONResponse`.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> — requis si vous souhaitez utiliser `UJSONResponse`.
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Obligatoire si vous souhaitez utiliser `ORJSONResponse`.
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Obligatoire si vous souhaitez utiliser `UJSONResponse`.
|
||||
|
||||
## Licence { #license }
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
Voici les sections introductives et les tutoriels pour apprendre **FastAPI**.
|
||||
|
||||
Vous pouvez considérer ceci comme un **manuel**, un **cours**, la **méthode officielle** et recommandée pour appréhender FastAPI. 😎
|
||||
Vous pouvez considérer ceci comme un **livre**, un **cours**, la **méthode officielle** et recommandée pour apprendre FastAPI. 😎
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
# Modèle Full Stack FastAPI { #full-stack-fastapi-template }
|
||||
|
||||
Bien qu'ils soient généralement livrés avec une configuration spécifique, les modèles sont conçus pour être flexibles et personnalisables. Cela vous permet de les modifier et de les adapter aux besoins de votre projet, ce qui en fait un excellent point de départ. 🏁
|
||||
Les modèles, bien qu'ils soient généralement livrés avec une configuration spécifique, sont conçus pour être flexibles et personnalisables. Cela vous permet de les modifier et de les adapter aux exigences de votre projet, ce qui en fait un excellent point de départ. 🏁
|
||||
|
||||
Vous pouvez utiliser ce modèle pour démarrer, car il inclut une grande partie de la configuration initiale, la sécurité, la base de données et quelques endpoints d'API déjà prêts pour vous.
|
||||
|
||||
Dépôt GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Full Stack FastAPI Template</a>
|
||||
Dépôt GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-template" class="external-link" target="_blank">Modèle Full Stack FastAPI</a>
|
||||
|
||||
## Modèle Full Stack FastAPI - Stack technologique et fonctionnalités { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
## Modèle Full Stack FastAPI - Pile technologique et fonctionnalités { #full-stack-fastapi-template-technology-stack-and-features }
|
||||
|
||||
- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/fr) pour l'API backend Python.
|
||||
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) pour les interactions Python avec la base de données SQL (ORM).
|
||||
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) pour les interactions avec la base de données SQL en Python (ORM).
|
||||
- 🔍 [Pydantic](https://docs.pydantic.dev), utilisé par FastAPI, pour la validation des données et la gestion des paramètres.
|
||||
- 💾 [PostgreSQL](https://www.postgresql.org) comme base de données SQL.
|
||||
- 🚀 [React](https://react.dev) pour le frontend.
|
||||
- 💃 Utilisation de TypeScript, des hooks, de Vite et d'autres éléments d'une stack frontend moderne.
|
||||
- 💃 Utilisation de TypeScript, des hooks, de Vite et d'autres éléments d'un stack frontend moderne.
|
||||
- 🎨 [Tailwind CSS](https://tailwindcss.com) et [shadcn/ui](https://ui.shadcn.com) pour les composants frontend.
|
||||
- 🤖 Un client frontend généré automatiquement.
|
||||
- 🧪 [Playwright](https://playwright.dev) pour les tests de bout en bout.
|
||||
@@ -23,6 +23,6 @@ Dépôt GitHub : <a href="https://github.com/tiangolo/full-stack-fastapi-templat
|
||||
- 🔑 Authentification JWT (JSON Web Token).
|
||||
- 📫 Récupération de mot de passe par e-mail.
|
||||
- ✅ Tests avec [Pytest](https://pytest.org).
|
||||
- 📞 [Traefik](https://traefik.io) comme proxy inverse / équilibreur de charge.
|
||||
- 🚢 Instructions de déploiement avec Docker Compose, y compris la configuration d'un proxy Traefik en frontal pour gérer les certificats HTTPS automatiques.
|
||||
- 🏭 CI (intégration continue) et CD (déploiement continu) basées sur GitHub Actions.
|
||||
- 📞 [Traefik](https://traefik.io) comme proxy inverse / répartiteur de charge.
|
||||
- 🚢 Instructions de déploiement avec Docker Compose, y compris la configuration d'un proxy Traefik frontal pour gérer les certificats HTTPS automatiques.
|
||||
- 🏭 CI (intégration continue) et CD (déploiement continu) basés sur GitHub Actions.
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# Introduction aux types Python { #python-types-intro }
|
||||
|
||||
Python prend en charge des «type hints» (également appelées «annotations de type») optionnels.
|
||||
Python prend en charge des « type hints » (aussi appelées « annotations de type ») facultatives.
|
||||
|
||||
Ces **«type hints»** ou annotations sont une syntaxe spéciale qui permet de déclarer le <abbr title="par exemple : str, int, float, bool">type</abbr> d'une variable.
|
||||
Ces « type hints » ou annotations sont une syntaxe spéciale qui permet de déclarer le <abbr title="par exemple : str, int, float, bool">type</abbr> d'une variable.
|
||||
|
||||
En déclarant des types pour vos variables, les éditeurs et les outils peuvent vous offrir un meilleur support.
|
||||
En déclarant les types de vos variables, les éditeurs et outils peuvent vous offrir un meilleur support.
|
||||
|
||||
Il s'agit d'un **tutoriel rapide / rappel** sur les «type hints» Python. Il ne couvre que le minimum nécessaire pour les utiliser avec **FastAPI** ... ce qui est en réalité très peu.
|
||||
Ceci est un **tutoriel rapide / rappel** à propos des annotations de type Python. Il couvre uniquement le minimum nécessaire pour les utiliser avec **FastAPI** ... ce qui est en réalité très peu.
|
||||
|
||||
**FastAPI** est entièrement basé sur ces «type hints», qui lui apportent de nombreux avantages et bénéfices.
|
||||
**FastAPI** est totalement basé sur ces annotations de type, elles lui donnent de nombreux avantages et bénéfices.
|
||||
|
||||
Mais même si vous n'utilisez jamais **FastAPI**, vous auriez intérêt à en apprendre un peu à leur sujet.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Si vous êtes un expert Python et que vous savez déjà tout sur les «type hints», passez au chapitre suivant.
|
||||
Si vous êtes un expert Python, et que vous savez déjà tout sur les annotations de type, passez au chapitre suivant.
|
||||
|
||||
///
|
||||
|
||||
@@ -34,25 +34,25 @@ La fonction fait ce qui suit :
|
||||
|
||||
* Prend un `first_name` et un `last_name`.
|
||||
* Convertit la première lettre de chacun en majuscule avec `title()`.
|
||||
* <abbr title="Les met ensemble, en une seule. Avec le contenu de l'une après l'autre.">Concatène</abbr> les deux avec un espace au milieu.
|
||||
* <abbr title="Les met ensemble, en un seul. Avec le contenu de l'un après l'autre.">Concatène</abbr> ces deux valeurs avec un espace au milieu.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *}
|
||||
|
||||
### Modifiez-le { #edit-it }
|
||||
### Modifier le code { #edit-it }
|
||||
|
||||
C'est un programme très simple.
|
||||
|
||||
Mais maintenant, imaginez que vous l'écriviez à partir de zéro.
|
||||
Mais maintenant imaginez que vous l'écriviez de zéro.
|
||||
|
||||
À un certain moment, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts...
|
||||
À un certain moment, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts ...
|
||||
|
||||
Mais ensuite, vous devez appeler «cette méthode qui convertit la première lettre en majuscule».
|
||||
Mais ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ».
|
||||
|
||||
Était-ce `upper` ? Était-ce `uppercase` ? `first_uppercase` ? `capitalize` ?
|
||||
|
||||
Alors, vous essayez l'ami de toujours du programmeur : l'autocomplétion de l'éditeur.
|
||||
Vous essayez alors avec l'ami de toujours des programmeurs, l'autocomplétion de l'éditeur.
|
||||
|
||||
Vous saisissez le premier paramètre de la fonction, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'autocomplétion.
|
||||
Vous tapez le premier paramètre de la fonction, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'autocomplétion.
|
||||
|
||||
Mais, malheureusement, vous n'obtenez rien d'utile :
|
||||
|
||||
@@ -60,7 +60,7 @@ Mais, malheureusement, vous n'obtenez rien d'utile :
|
||||
|
||||
### Ajouter des types { #add-types }
|
||||
|
||||
Modifions une seule ligne par rapport à la version précédente.
|
||||
Modifions une seule ligne de la version précédente.
|
||||
|
||||
Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
|
||||
|
||||
@@ -76,11 +76,11 @@ Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
|
||||
|
||||
C'est tout.
|
||||
|
||||
Ce sont les «type hints» :
|
||||
Ce sont les « annotations de type » :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *}
|
||||
|
||||
Ce n'est pas la même chose que de déclarer des valeurs par défaut comme on le ferait avec :
|
||||
Ce n'est pas la même chose que de déclarer des valeurs par défaut, ce qui serait :
|
||||
|
||||
```Python
|
||||
first_name="john", last_name="doe"
|
||||
@@ -90,35 +90,35 @@ C'est différent.
|
||||
|
||||
Nous utilisons des deux-points (`:`), pas des signes égal (`=`).
|
||||
|
||||
Et ajouter des «type hints» ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans eux.
|
||||
Et ajouter des annotations de type ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans elles.
|
||||
|
||||
Mais maintenant, imaginez que vous êtes à nouveau en train de créer cette fonction, mais avec des «type hints».
|
||||
Mais maintenant, imaginez que vous êtes à nouveau en train de créer cette fonction, mais avec des annotations de type.
|
||||
|
||||
Au même moment, vous essayez de déclencher l'autocomplétion avec `Ctrl+Espace` et vous voyez :
|
||||
|
||||
<img src="/img/python-types/image02.png">
|
||||
|
||||
Avec cela, vous pouvez faire défiler, voir les options, jusqu'à trouver celle qui «vous dit quelque chose» :
|
||||
Avec cela, vous pouvez faire défiler en voyant les options, jusqu'à trouver celle qui « vous dit quelque chose » :
|
||||
|
||||
<img src="/img/python-types/image03.png">
|
||||
|
||||
## Plus de motivations { #more-motivation }
|
||||
## Plus de motivation { #more-motivation }
|
||||
|
||||
Regardez cette fonction, elle a déjà des «type hints» :
|
||||
Regardez cette fonction, elle a déjà des annotations de type :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *}
|
||||
|
||||
Comme l'éditeur connaît les types des variables, vous n'obtenez pas seulement l'autocomplétion, vous bénéficiez également de vérifications d'erreurs :
|
||||
Comme l'éditeur connaît les types des variables, vous n'obtenez pas seulement l'autocomplétion, vous obtenez aussi des vérifications d'erreurs :
|
||||
|
||||
<img src="/img/python-types/image04.png">
|
||||
|
||||
Maintenant vous savez qu'il faut corriger, convertir `age` en chaîne avec `str(age)` :
|
||||
Vous savez maintenant qu'il faut corriger, convertir `age` en chaîne avec `str(age)` :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *}
|
||||
|
||||
## Déclarer des types { #declaring-types }
|
||||
|
||||
Vous venez de voir l'endroit principal où déclarer des «type hints» : en tant que paramètres de fonctions.
|
||||
Vous venez de voir l'endroit principal pour déclarer des annotations de type : dans les paramètres des fonctions.
|
||||
|
||||
C'est aussi l'endroit principal où vous les utiliserez avec **FastAPI**.
|
||||
|
||||
@@ -137,31 +137,31 @@ Vous pouvez utiliser, par exemple :
|
||||
|
||||
### Types génériques avec paramètres de type { #generic-types-with-type-parameters }
|
||||
|
||||
Il existe des structures de données qui peuvent contenir d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent, elles aussi, avoir leur propre type.
|
||||
Il existe certaines structures de données qui peuvent contenir d'autres valeurs, comme `dict`, `list`, `set` et `tuple`. Et les valeurs internes peuvent aussi avoir leur propre type.
|
||||
|
||||
Ces types qui ont des types internes sont appelés types «génériques». Et il est possible de les déclarer, même avec leurs types internes.
|
||||
Ces types qui ont des types internes sont appelés types « génériques ». Et il est possible de les déclarer, même avec leurs types internes.
|
||||
|
||||
Pour déclarer ces types et leurs types internes, vous pouvez utiliser le module standard Python `typing`. Il existe précisément pour prendre en charge ces «type hints».
|
||||
Pour déclarer ces types et les types internes, vous pouvez utiliser le module standard Python `typing`. Il existe spécifiquement pour prendre en charge ces annotations de type.
|
||||
|
||||
#### Versions plus récentes de Python { #newer-versions-of-python }
|
||||
|
||||
La syntaxe utilisant `typing` est compatible avec toutes les versions, de Python 3.6 aux plus récentes, y compris Python 3.9, Python 3.10, etc.
|
||||
|
||||
Au fur et à mesure que Python évolue, les versions plus récentes offrent un meilleur support pour ces annotations de type et, dans de nombreux cas, vous n'aurez même pas besoin d'importer et d'utiliser le module `typing` pour déclarer les annotations de type.
|
||||
Au fur et à mesure que Python évolue, les versions plus récentes apportent un meilleur support pour ces annotations de type et dans de nombreux cas vous n'aurez même pas besoin d'importer et d'utiliser le module `typing` pour les déclarer.
|
||||
|
||||
Si vous pouvez choisir une version plus récente de Python pour votre projet, vous pourrez profiter de cette simplicité supplémentaire.
|
||||
|
||||
Dans toute la documentation, il y a des exemples compatibles avec chaque version de Python (lorsqu'il y a une différence).
|
||||
|
||||
Par exemple, «Python 3.6+» signifie que c'est compatible avec Python 3.6 ou supérieur (y compris 3.7, 3.8, 3.9, 3.10, etc.). Et «Python 3.9+» signifie que c'est compatible avec Python 3.9 ou supérieur (y compris 3.10, etc.).
|
||||
Par exemple « Python 3.6+ » signifie que c'est compatible avec Python 3.6 ou supérieur (y compris 3.7, 3.8, 3.9, 3.10, etc.). Et « Python 3.9+ » signifie que c'est compatible avec Python 3.9 ou supérieur (y compris 3.10, etc).
|
||||
|
||||
Si vous pouvez utiliser les dernières versions de Python, utilisez les exemples de la dernière version, ils auront la meilleure et la plus simple syntaxe, par exemple, «Python 3.10+».
|
||||
Si vous pouvez utiliser les dernières versions de Python, utilisez les exemples pour la dernière version, ils auront la meilleure et la plus simple syntaxe, par exemple, « Python 3.10+ ».
|
||||
|
||||
#### List { #list }
|
||||
#### Liste { #list }
|
||||
|
||||
Par exemple, définissons une variable comme étant une `list` de `str`.
|
||||
Par exemple, définissons une variable comme une `list` de `str`.
|
||||
|
||||
Déclarez la variable, en utilisant la même syntaxe avec les deux-points (`:`).
|
||||
Déclarez la variable, en utilisant la même syntaxe avec deux-points (`:`).
|
||||
|
||||
Comme type, mettez `list`.
|
||||
|
||||
@@ -171,23 +171,23 @@ Comme la liste est un type qui contient des types internes, mettez-les entre cro
|
||||
|
||||
/// info
|
||||
|
||||
Ces types internes entre crochets sont appelés «paramètres de type».
|
||||
Ces types internes entre crochets sont appelés « paramètres de type ».
|
||||
|
||||
Dans ce cas, `str` est le paramètre de type passé à `list`.
|
||||
|
||||
///
|
||||
|
||||
Cela signifie : «la variable `items` est une `list`, et chacun des éléments de cette liste est un `str`».
|
||||
Cela signifie : « la variable `items` est une `list`, et chacun des éléments de cette liste est un `str` ».
|
||||
|
||||
En faisant cela, votre éditeur peut vous offrir du support même pendant le traitement des éléments de la liste :
|
||||
En faisant cela, votre éditeur peut vous fournir de l'aide même pendant le traitement des éléments de la liste :
|
||||
|
||||
<img src="/img/python-types/image05.png">
|
||||
|
||||
Sans types, c'est presque impossible à atteindre.
|
||||
Sans types, c'est presque impossible à réaliser.
|
||||
|
||||
Notez que la variable `item` est l'un des éléments de la liste `items`.
|
||||
Remarquez que la variable `item` est l'un des éléments de la liste `items`.
|
||||
|
||||
Et pourtant, l'éditeur sait que c'est un `str` et fournit le support correspondant.
|
||||
Et pourtant, l'éditeur sait que c'est un `str` et fournit le support approprié.
|
||||
|
||||
#### Tuple et Set { #tuple-and-set }
|
||||
|
||||
@@ -206,7 +206,7 @@ Pour définir un `dict`, vous passez 2 paramètres de type, séparés par des vi
|
||||
|
||||
Le premier paramètre de type est pour les clés du `dict`.
|
||||
|
||||
Le deuxième paramètre de type est pour les valeurs du `dict` :
|
||||
Le second paramètre de type est pour les valeurs du `dict` :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *}
|
||||
|
||||
@@ -218,11 +218,11 @@ Cela signifie :
|
||||
|
||||
#### Union { #union }
|
||||
|
||||
Vous pouvez déclarer qu'une variable peut être n'importe lequel de plusieurs types, par exemple, un `int` ou un `str`.
|
||||
Vous pouvez déclarer qu'une variable peut être de plusieurs types, par exemple, un `int` ou un `str`.
|
||||
|
||||
En Python 3.6 et supérieur (y compris Python 3.10), vous pouvez utiliser le type `Union` de `typing` et mettre entre crochets les types possibles à accepter.
|
||||
Dans Python 3.6 et supérieur (y compris Python 3.10), vous pouvez utiliser le type `Union` de `typing` et mettre entre crochets les types possibles à accepter.
|
||||
|
||||
En Python 3.10, il existe également une **nouvelle syntaxe** dans laquelle vous pouvez indiquer les types possibles séparés par une <abbr title='également appelé «bitwise or operator», mais cette signification n’est pas pertinente ici'>barre verticale (`|`)</abbr>.
|
||||
Dans Python 3.10, il existe aussi une nouvelle syntaxe où vous pouvez mettre les types possibles séparés par une <abbr title='aussi appelé « opérateur OU bit à bit », mais ce sens n’est pas pertinent ici'>barre verticale (`|`)</abbr>.
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
@@ -242,21 +242,21 @@ En Python 3.10, il existe également une **nouvelle syntaxe** dans laquelle vous
|
||||
|
||||
Dans les deux cas, cela signifie que `item` peut être un `int` ou un `str`.
|
||||
|
||||
#### Éventuellement `None` { #possibly-none }
|
||||
#### Possiblement `None` { #possibly-none }
|
||||
|
||||
Vous pouvez déclarer qu'une valeur peut avoir un type, comme `str`, mais qu'elle peut aussi être `None`.
|
||||
|
||||
En Python 3.6 et supérieur (y compris Python 3.10), vous pouvez le déclarer en important et en utilisant `Optional` depuis le module `typing`.
|
||||
Dans Python 3.6 et supérieur (y compris Python 3.10), vous pouvez le déclarer en important et en utilisant `Optional` depuis le module `typing`.
|
||||
|
||||
```Python hl_lines="1 4"
|
||||
{!../../docs_src/python_types/tutorial009_py39.py!}
|
||||
```
|
||||
|
||||
Utiliser `Optional[str]` au lieu de simplement `str` permettra à l'éditeur de vous aider à détecter les erreurs où vous pourriez supposer qu'une valeur est toujours un `str`, alors qu'elle pourrait en fait être `None`.
|
||||
Utiliser `Optional[str]` au lieu de simplement `str` permettra à l'éditeur de vous aider à détecter des erreurs où vous supposeriez qu'une valeur est toujours un `str`, alors qu'elle pourrait en fait aussi être `None`.
|
||||
|
||||
`Optional[Something]` est en réalité un raccourci pour `Union[Something, None]`, c'est équivalent.
|
||||
`Optional[Something]` est en réalité un raccourci pour `Union[Something, None]`, ils sont équivalents.
|
||||
|
||||
Cela signifie aussi qu'en Python 3.10, vous pouvez utiliser `Something | None` :
|
||||
Cela signifie aussi que dans Python 3.10, vous pouvez utiliser `Something | None` :
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
@@ -287,39 +287,39 @@ Cela signifie aussi qu'en Python 3.10, vous pouvez utiliser `Something | None` :
|
||||
Si vous utilisez une version de Python inférieure à 3.10, voici un conseil de mon point de vue très **subjectif** :
|
||||
|
||||
* 🚨 Évitez d'utiliser `Optional[SomeType]`
|
||||
* À la place, ✨ **utilisez `Union[SomeType, None]`** ✨.
|
||||
* À la place ✨ **utilisez `Union[SomeType, None]`** ✨.
|
||||
|
||||
Les deux sont équivalents et, en interne, c'est la même chose, mais je recommanderais `Union` plutôt que `Optional` parce que le mot «optional» semble impliquer que la valeur est optionnelle, alors qu'il signifie en réalité «elle peut être `None`», même si elle n'est pas optionnelle et reste requise.
|
||||
Les deux sont équivalents et sous le capot ce sont les mêmes, mais je recommanderais `Union` plutôt que `Optional` parce que le mot « facultatif » semble impliquer que la valeur est optionnelle, alors que cela signifie en fait « elle peut être `None` », même si elle n'est pas facultative et est toujours requise.
|
||||
|
||||
Je pense que `Union[SomeType, None]` est plus explicite quant à ce que cela signifie.
|
||||
Je pense que `Union[SomeType, None]` est plus explicite sur ce que cela signifie.
|
||||
|
||||
Il ne s'agit que de mots et de noms. Mais ces mots peuvent influencer la manière dont vous et vos coéquipiers pensez au code.
|
||||
Il ne s'agit que des mots et des noms. Mais ces mots peuvent influencer la manière dont vous et vos coéquipiers pensez au code.
|
||||
|
||||
Par exemple, prenons cette fonction :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
|
||||
|
||||
Le paramètre `name` est défini comme `Optional[str]`, mais il n'est pas optionnel, vous ne pouvez pas appeler la fonction sans le paramètre :
|
||||
Le paramètre `name` est défini comme `Optional[str]`, mais il n'est pas facultatif, vous ne pouvez pas appeler la fonction sans le paramètre :
|
||||
|
||||
```Python
|
||||
say_hi() # Oh, non, cela lève une erreur ! 😱
|
||||
say_hi() # Oh non, cela lève une erreur ! 😱
|
||||
```
|
||||
|
||||
Le paramètre `name` est toujours requis (pas optionnel) parce qu'il n'a pas de valeur par défaut. Néanmoins, `name` accepte `None` comme valeur :
|
||||
Le paramètre `name` est toujours requis (pas « optionnel ») parce qu'il n'a pas de valeur par défaut. Néanmoins, `name` accepte `None` comme valeur :
|
||||
|
||||
```Python
|
||||
say_hi(name=None) # Cela fonctionne, None est valide 🎉
|
||||
```
|
||||
|
||||
La bonne nouvelle, c'est qu'une fois sur Python 3.10, vous n'aurez plus à vous en soucier, car vous pourrez simplement utiliser `|` pour définir des unions de types :
|
||||
La bonne nouvelle est que, dès que vous êtes sur Python 3.10, vous n'avez plus à vous en soucier, car vous pourrez simplement utiliser `|` pour définir des unions de types :
|
||||
|
||||
{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
|
||||
|
||||
Et vous n'aurez plus à vous préoccuper de noms comme «Optional» et «Union». 😎
|
||||
Et alors vous n'aurez plus à vous soucier de noms comme `Optional` et `Union`. 😎
|
||||
|
||||
#### Types génériques { #generic-types }
|
||||
|
||||
Ces types qui prennent des paramètres de type entre crochets sont appelés **types génériques** ou **Generics**, par exemple :
|
||||
Ces types qui prennent des paramètres de type entre crochets sont appelés des **types génériques** ou **Generics**, par exemple :
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
@@ -330,13 +330,13 @@ Vous pouvez utiliser les mêmes types intégrés comme génériques (avec des cr
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
Et, comme avec les versions précédentes de Python, ceux du module `typing` :
|
||||
Et, comme avec les versions précédentes de Python, depuis le module `typing` :
|
||||
|
||||
* `Union`
|
||||
* `Optional`
|
||||
* ... et d'autres.
|
||||
|
||||
En Python 3.10, comme alternative à l'utilisation des génériques `Union` et `Optional`, vous pouvez utiliser la <abbr title='également appelé «bitwise or operator», mais cette signification n’est pas pertinente ici'>barre verticale (`|`)</abbr> pour déclarer des unions de types, c'est bien mieux et plus simple.
|
||||
Dans Python 3.10, comme alternative à l'utilisation des génériques `Union` et `Optional`, vous pouvez utiliser la <abbr title='aussi appelé « opérateur OU bit à bit », mais ce sens n’est pas pertinent ici'>barre verticale (`|`)</abbr> pour déclarer des unions de types, c'est bien mieux et plus simple.
|
||||
|
||||
////
|
||||
|
||||
@@ -349,7 +349,7 @@ Vous pouvez utiliser les mêmes types intégrés comme génériques (avec des cr
|
||||
* `set`
|
||||
* `dict`
|
||||
|
||||
Et les génériques du module `typing` :
|
||||
Et des génériques depuis le module `typing` :
|
||||
|
||||
* `Union`
|
||||
* `Optional`
|
||||
@@ -357,9 +357,9 @@ Et les génériques du module `typing` :
|
||||
|
||||
////
|
||||
|
||||
### Classes comme types { #classes-as-types }
|
||||
### Classes en tant que types { #classes-as-types }
|
||||
|
||||
Vous pouvez également déclarer une classe comme type d'une variable.
|
||||
Vous pouvez aussi déclarer une classe comme type d'une variable.
|
||||
|
||||
Disons que vous avez une classe `Person`, avec un nom :
|
||||
|
||||
@@ -373,21 +373,21 @@ Et là encore, vous obtenez tout le support de l'éditeur :
|
||||
|
||||
<img src="/img/python-types/image06.png">
|
||||
|
||||
Notez que cela signifie que «`one_person` est une **instance** de la classe `Person`».
|
||||
Remarquez que cela signifie « `one_person` est une instance de la classe `Person` ».
|
||||
|
||||
Cela ne signifie pas «`one_person` est la **classe** appelée `Person`».
|
||||
Cela ne signifie pas « `one_person` est la classe appelée `Person` ».
|
||||
|
||||
## Modèles Pydantic { #pydantic-models }
|
||||
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> est une bibliothèque Python pour effectuer la validation de données.
|
||||
<a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> est une bibliothèque Python pour effectuer de la validation de données.
|
||||
|
||||
Vous déclarez la «forme» des données sous forme de classes avec des attributs.
|
||||
Vous déclarez la « forme » de la donnée sous forme de classes avec des attributs.
|
||||
|
||||
Et chaque attribut a un type.
|
||||
|
||||
Ensuite, vous créez une instance de cette classe avec certaines valeurs et elle validera les valeurs, les convertira dans le type approprié (le cas échéant) et vous donnera un objet avec toutes les données.
|
||||
|
||||
Et vous bénéficiez de tout le support de l'éditeur avec cet objet résultant.
|
||||
Et vous obtenez tout le support de l'éditeur avec cet objet résultant.
|
||||
|
||||
Un exemple tiré de la documentation officielle de Pydantic :
|
||||
|
||||
@@ -405,60 +405,60 @@ Vous verrez beaucoup plus de tout cela en pratique dans le [Tutoriel - Guide uti
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pydantic a un comportement particulier lorsque vous utilisez `Optional` ou `Union[Something, None]` sans valeur par défaut. Vous pouvez en lire davantage dans la documentation Pydantic à propos des <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">champs Optional requis</a>.
|
||||
Pydantic a un comportement spécial lorsque vous utilisez `Optional` ou `Union[Something, None]` sans valeur par défaut, vous pouvez en lire davantage dans la documentation de Pydantic à propos des <a href="https://docs.pydantic.dev/2.3/usage/models/#required-fields" class="external-link" target="_blank">champs Optionals requis</a>.
|
||||
|
||||
///
|
||||
|
||||
## Annotations de type avec métadonnées { #type-hints-with-metadata-annotations }
|
||||
|
||||
Python propose aussi une fonctionnalité qui permet d'ajouter des **<abbr title="Des données à propos des données, dans ce cas, des informations sur le type, p. ex. une description.">métadonnées</abbr> supplémentaires** dans ces «type hints» en utilisant `Annotated`.
|
||||
Python dispose également d'une fonctionnalité qui permet de mettre des **<abbr title="Données sur les données, dans ce cas, des informations sur le type, p. ex. une description.">métadonnées</abbr> supplémentaires** dans ces annotations de type en utilisant `Annotated`.
|
||||
|
||||
Depuis Python 3.9, `Annotated` fait partie de la bibliothèque standard, vous pouvez donc l'importer depuis `typing`.
|
||||
|
||||
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
|
||||
|
||||
Python lui-même ne fait rien avec cet `Annotated`. Et pour les éditeurs et autres outils, le type est toujours `str`.
|
||||
Python lui-même ne fait rien avec ce `Annotated`. Et pour les éditeurs et autres outils, le type est toujours `str`.
|
||||
|
||||
Mais vous pouvez utiliser cet espace dans `Annotated` pour fournir à **FastAPI** des métadonnées supplémentaires sur la façon dont vous souhaitez que votre application se comporte.
|
||||
Mais vous pouvez utiliser cet espace dans `Annotated` pour fournir à **FastAPI** des métadonnées supplémentaires sur la façon dont vous voulez que votre application se comporte.
|
||||
|
||||
L'important à retenir est que **le premier paramètre de type** que vous passez à `Annotated` est le **type réel**. Le reste n'est que des métadonnées pour d'autres outils.
|
||||
L'important à retenir est que le premier paramètre de type que vous passez à `Annotated` est le type réel. Le reste n'est que des métadonnées pour d'autres outils.
|
||||
|
||||
Pour l'instant, vous avez seulement besoin de savoir que `Annotated` existe et que c'est du Python standard. 😎
|
||||
Pour l'instant, vous avez juste besoin de savoir que `Annotated` existe, et que c'est du Python standard. 😎
|
||||
|
||||
Plus tard, vous verrez à quel point cela peut être **puissant**.
|
||||
Plus tard, vous verrez à quel point cela peut être puissant.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Le fait que ce soit du **Python standard** signifie que vous aurez toujours la **meilleure expérience développeur possible** dans votre éditeur, avec les outils que vous utilisez pour analyser et refactoriser votre code, etc. ✨
|
||||
Le fait que ce soit du Python standard signifie que vous bénéficierez toujours de la meilleure expérience développeur possible dans votre éditeur, avec les outils que vous utilisez pour analyser et refactoriser votre code, etc. ✨
|
||||
|
||||
Et aussi que votre code sera très compatible avec de nombreux autres outils et bibliothèques Python. 🚀
|
||||
|
||||
///
|
||||
|
||||
## Les annotations de type dans **FastAPI** { #type-hints-in-fastapi }
|
||||
## Annotations de type dans **FastAPI** { #type-hints-in-fastapi }
|
||||
|
||||
**FastAPI** tire parti de ces «type hints» pour faire plusieurs choses.
|
||||
**FastAPI** tire parti de ces annotations de type pour faire plusieurs choses.
|
||||
|
||||
Avec **FastAPI**, vous déclarez des paramètres avec des «type hints» et vous obtenez :
|
||||
Avec **FastAPI**, vous déclarez des paramètres avec des annotations de type et vous obtenez :
|
||||
|
||||
* **du support de l'éditeur**.
|
||||
* **des vérifications de type**.
|
||||
* **Du support de l'éditeur**.
|
||||
* **Des vérifications de types**.
|
||||
|
||||
... et **FastAPI** utilise les mêmes déclarations pour :
|
||||
|
||||
* **Définir les prérequis** : depuis les paramètres de chemin des requêtes, les paramètres de requête, les en-têtes, les corps, les dépendances, etc.
|
||||
* **Convertir les données** : depuis la requête vers le type requis.
|
||||
* **Valider les données** : provenant de chaque requête :
|
||||
* Générer des **erreurs automatiques** renvoyées au client lorsque les données sont invalides.
|
||||
* **Définir des prérequis** : à partir des paramètres de chemin de la requête, des paramètres de requête, des en-têtes, des corps, des dépendances, etc.
|
||||
* **Convertir des données** : de la requête vers le type requis.
|
||||
* **Valider des données** : provenant de chaque requête :
|
||||
* En générant des **erreurs automatiques** renvoyées au client lorsque la donnée est invalide.
|
||||
* **Documenter** l'API avec OpenAPI :
|
||||
* ce qui est ensuite utilisé par les interfaces utilisateur de documentation interactive automatiques.
|
||||
|
||||
Tout cela peut sembler abstrait. Ne vous inquiétez pas. Vous verrez tout cela en action dans le [Tutoriel - Guide utilisateur](tutorial/index.md){.internal-link target=_blank}.
|
||||
|
||||
L'important, c'est qu'en utilisant les types standard de Python, en un seul endroit (au lieu d'ajouter davantage de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous.
|
||||
L'important est qu'en utilisant les types standards de Python, en un seul endroit (au lieu d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous.
|
||||
|
||||
/// info
|
||||
|
||||
Si vous avez déjà parcouru tout le tutoriel et êtes revenu pour en savoir plus sur les types, une bonne ressource est <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">l'aide-mémoire de `mypy`</a>.
|
||||
Si vous avez déjà parcouru tout le tutoriel et êtes revenu pour en voir plus sur les types, une bonne ressource est <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">l'« aide-mémoire » de `mypy`</a>.
|
||||
|
||||
///
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
Vous pouvez définir des tâches d'arrière-plan qui seront exécutées après avoir retourné une réponse.
|
||||
|
||||
Ceci est utile pour les opérations qui doivent avoir lieu après une requête, mais où le client n'a pas vraiment à attendre que l'opération soit terminée pour recevoir la réponse.
|
||||
Ceci est utile pour les opérations qui doivent avoir lieu après une requête, mais où le client n'a pas réellement besoin d'attendre que l'opération soit terminée pour recevoir une réponse.
|
||||
|
||||
Cela comprend, par exemple :
|
||||
|
||||
* Les notifications par email envoyées après l'exécution d'une action :
|
||||
* Étant donné que se connecter à un serveur email et envoyer un email a tendance à être «lent» (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification par email en arrière-plan.
|
||||
* Étant donné que se connecter à un serveur et envoyer un email a tendance à être « lent » (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan.
|
||||
* Traiter des données :
|
||||
* Par exemple, disons que vous recevez un fichier qui doit passer par un processus lent, vous pouvez retourner une réponse «Accepted» (HTTP 202) et traiter le fichier en arrière-plan.
|
||||
* Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse « Accepted » (HTTP 202) puis faire le traitement en arrière-plan.
|
||||
|
||||
## Utiliser `BackgroundTasks` { #using-backgroundtasks }
|
||||
|
||||
Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin* avec `BackgroundTasks` comme type déclaré :
|
||||
Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin d'accès* avec `BackgroundTasks` comme type déclaré.
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *}
|
||||
|
||||
@@ -21,66 +21,62 @@ Pour commencer, importez `BackgroundTasks` et définissez un paramètre dans vot
|
||||
|
||||
## Créer une fonction de tâche { #create-a-task-function }
|
||||
|
||||
Créez une fonction à exécuter comme tâche d'arrière-plan.
|
||||
|
||||
C'est simplement une fonction standard qui peut recevoir des paramètres.
|
||||
Une fonction à exécuter comme tâche d'arrière-plan est juste une fonction standard qui peut recevoir des paramètres.
|
||||
|
||||
Elle peut être une fonction asynchrone (`async def`) ou une fonction normale (`def`), **FastAPI** saura la gérer correctement.
|
||||
|
||||
Dans cet exemple, la fonction de tâche écrira dans un fichier (afin de simuler un envoi d'email).
|
||||
|
||||
Et comme l'opération d'écriture n'utilise ni `async` ni `await`, nous définissons la fonction avec un `def` normal :
|
||||
L'opération d'écriture n'utilisant ni `async` ni `await`, on définit la fonction avec un `def` normal.
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *}
|
||||
|
||||
## Ajouter la tâche d'arrière-plan { #add-the-background-task }
|
||||
## Ajouter une tâche d'arrière-plan { #add-the-background-task }
|
||||
|
||||
Dans votre *fonction de chemin*, passez votre fonction de tâche à l'objet de tâches d'arrière-plan grâce à la méthode `.add_task()` :
|
||||
Dans votre *fonction de chemin d'accès*, passez votre fonction de tâche à l'objet de type `BackgroundTasks` (`background_tasks` ici) grâce à la méthode `.add_task()` :
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *}
|
||||
|
||||
`.add_task()` reçoit comme arguments :
|
||||
|
||||
* Une fonction de tâche à exécuter en arrière-plan (`write_notification`).
|
||||
* Toute séquence d'arguments à passer à la fonction de tâche dans l'ordre (`email`).
|
||||
* Tous les arguments nommés à passer à la fonction de tâche (`message="some notification"`).
|
||||
* Les arguments positionnels à passer à la fonction de tâche dans l'ordre (`email`).
|
||||
* Les arguments nommés à passer à la fonction de tâche (`message="some notification"`).
|
||||
|
||||
## Injection de dépendances { #dependency-injection }
|
||||
|
||||
Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances, vous pouvez déclarer un paramètre de type `BackgroundTasks` à plusieurs niveaux : dans une *fonction de chemin*, dans une dépendance (dependable), dans une sous-dépendance, etc.
|
||||
|
||||
**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que toutes les tâches d'arrière-plan soient fusionnées et exécutées ensuite en arrière-plan :
|
||||
Utiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances. Vous pouvez déclarer un paramètre de type `BackgroundTasks` à différents niveaux : dans une *fonction de chemin d'accès*, dans une dépendance (dependable), dans une sous-dépendance, etc.
|
||||
|
||||
**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que toutes les tâches d'arrière-plan soient fusionnées et que les tâches soient ensuite exécutées en arrière-plan :
|
||||
|
||||
{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}
|
||||
|
||||
|
||||
Dans cet exemple, les messages seront écrits dans le fichier `log.txt` après que la réponse soit envoyée.
|
||||
|
||||
S'il y avait un paramètre de requête dans la requête, il sera écrit dans le log via une tâche d'arrière-plan.
|
||||
S'il y avait un paramètre de requête dans la requête, alors il sera écrit dans le journal via une tâche d'arrière-plan.
|
||||
|
||||
Ensuite, une autre tâche d'arrière-plan générée dans la *fonction de chemin* écrira un message utilisant le paramètre de chemin `email`.
|
||||
Et ensuite une autre tâche d'arrière-plan (générée dans la *fonction de chemin d'accès*) écrira un message comprenant le paramètre de chemin `email`.
|
||||
|
||||
## Détails techniques { #technical-details }
|
||||
|
||||
La classe `BackgroundTasks` provient directement de <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">`starlette.background`</a>.
|
||||
|
||||
Elle est importée/incluse directement dans FastAPI afin que vous puissiez l'importer depuis `fastapi` et éviter d'importer par accident l'alternative `BackgroundTask` (sans le `s` final) depuis `starlette.background`.
|
||||
Elle est importée/incluse directement dans **FastAPI** pour que vous puissiez l'importer depuis `fastapi` et éviter d'importer accidentellement `BackgroundTask` (sans `s` à la fin) depuis `starlette.background`.
|
||||
|
||||
En utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin* et de laisser **FastAPI** gérer le reste pour vous, comme lorsque vous utilisez l'objet `Request` directement.
|
||||
En utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin d'accès* et de laisser **FastAPI** gérer le reste pour vous, comme en utilisant l'objet `Request` directement.
|
||||
|
||||
Il est toujours possible d'utiliser `BackgroundTask` seul dans FastAPI, mais vous devez créer l'objet dans votre code et renvoyer une `Response` Starlette qui l'inclut.
|
||||
Il est tout de même possible d'utiliser `BackgroundTask` seul dans **FastAPI**, mais dans ce cas il faut créer l'objet dans le code et renvoyer une `Response` Starlette l'incluant.
|
||||
|
||||
Vous pouvez voir plus de détails dans <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">la documentation officielle de Starlette sur les tâches d'arrière-plan</a>.
|
||||
Plus de détails sont disponibles dans <a href="https://www.starlette.dev/background/" class="external-link" target="_blank">la documentation officielle de Starlette sur les tâches d'arrière-plan</a>.
|
||||
|
||||
## Avertissement { #caveat }
|
||||
|
||||
Si vous avez besoin d'effectuer des calculs lourds en arrière-plan et que vous n'avez pas nécessairement besoin qu'ils soient exécutés par le même processus (par exemple, vous n'avez pas besoin de partager la mémoire, les variables, etc.), vous pourriez bénéficier d'utiliser des outils plus importants comme <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
|
||||
Si vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que <a href="https://docs.celeryq.dev" class="external-link" target="_blank">Celery</a>.
|
||||
|
||||
Ils nécessitent généralement des configurations plus complexes, un gestionnaire de file de messages/jobs, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans plusieurs processus, et surtout, sur plusieurs serveurs.
|
||||
Ces outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et surtout, sur plusieurs serveurs.
|
||||
|
||||
Mais si vous avez besoin d'accéder aux variables et objets de la même application **FastAPI**, ou si vous avez besoin d'effectuer de petites tâches d'arrière-plan (comme envoyer une notification par email), vous pouvez simplement utiliser `BackgroundTasks`.
|
||||
Mais si vous avez besoin d'accéder aux variables et objets de la même application **FastAPI**, ou si vous avez besoin d'effectuer de petites tâches d'arrière-plan (comme envoyer des notifications par email), vous pouvez simplement vous contenter d'utiliser `BackgroundTasks`.
|
||||
|
||||
## Résumé { #recap }
|
||||
|
||||
Importez et utilisez `BackgroundTasks` avec des paramètres dans les *fonctions de chemin* et les dépendances pour ajouter des tâches d'arrière-plan.
|
||||
Importez et utilisez `BackgroundTasks` grâce aux paramètres de *fonction de chemin d'accès* et les dépendances pour ajouter des tâches d'arrière-plan.
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
# Body - Paramètres multiples { #body-multiple-parameters }
|
||||
|
||||
Maintenant que nous avons vu comment utiliser `Path` et `Query`, voyons des utilisations plus avancées des déclarations du corps de la requête.
|
||||
Maintenant que nous avons vu comment utiliser `Path` et `Query`, voyons des usages plus avancés des déclarations de paramètres du corps de la requête.
|
||||
|
||||
## Mélanger les paramètres `Path`, `Query` et body { #mix-path-query-and-body-parameters }
|
||||
## Mélanger les paramètres `Path`, `Query` et du corps de la requête { #mix-path-query-and-body-parameters }
|
||||
|
||||
Tout d'abord, sachez que vous pouvez mélanger les déclarations des paramètres `Path`, `Query` et body, **FastAPI** saura quoi faire.
|
||||
Tout d'abord, sachez que vous pouvez mélanger librement les déclarations des paramètres `Path`, `Query` et du corps de la requête, **FastAPI** saura quoi faire.
|
||||
|
||||
Vous pouvez également déclarer des paramètres body comme étant optionnels, en leur assignant une valeur par défaut à `None` :
|
||||
Et vous pouvez également déclarer des paramètres du corps de la requête comme étant optionnels, en leur assignant une valeur par défaut à `None` :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Notez que, dans ce cas, le paramètre `item` provenant du body est optionnel. Sa valeur par défaut est `None`.
|
||||
Notez que, dans ce cas, l'élément `item` récupéré depuis le corps de la requête est optionnel. Comme sa valeur par défaut est `None`.
|
||||
|
||||
///
|
||||
|
||||
## Paramètres multiples du body { #multiple-body-parameters }
|
||||
## Paramètres multiples du corps de la requête { #multiple-body-parameters }
|
||||
|
||||
Dans l'exemple précédent, les *opérations de chemin* attendaient un body JSON avec les attributs d'un `Item`, par exemple :
|
||||
Dans l'exemple précédent, les chemins d'accès attendraient un corps de la requête JSON avec les attributs d'un `Item`, par exemple :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -29,13 +29,13 @@ Dans l'exemple précédent, les *opérations de chemin* attendaient un body JSON
|
||||
}
|
||||
```
|
||||
|
||||
Mais vous pouvez également déclarer plusieurs paramètres provenant de body, par exemple `item` et `user` :
|
||||
Mais vous pouvez également déclarer plusieurs paramètres provenant du corps de la requête, par exemple `item` et `user` :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}
|
||||
|
||||
Dans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre body dans la fonction (il y a deux paramètres qui sont des modèles Pydantic).
|
||||
Dans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre du corps de la requête dans la fonction (il y a deux paramètres qui sont des modèles Pydantic).
|
||||
|
||||
Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le body, et s'attendra à recevoir un body semblable à :
|
||||
Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le corps de la requête, et s'attendra à recevoir un corps de la requête semblable à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -54,27 +54,27 @@ Il utilisera alors les noms des paramètres comme clés (noms de champs) dans le
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Notez que, bien que `item` ait été déclaré de la même manière qu'auparavant, il est maintenant attendu dans le body sous la clé `item`.
|
||||
Notez que, bien que `item` ait été déclaré de la même manière qu'auparavant, il est désormais attendu à l'intérieur du corps de la requête sous la clé `item`.
|
||||
|
||||
///
|
||||
|
||||
**FastAPI** effectue la conversion automatique à partir de la requête, de sorte que le paramètre `item` reçoive son contenu spécifique, et de même pour `user`.
|
||||
**FastAPI** effectuera la conversion automatique depuis la requête, de sorte que le paramètre `item` reçoive son contenu spécifique, et de même pour `user`.
|
||||
|
||||
Il effectuera la validation des données composées et les documentera ainsi dans le schéma OpenAPI et la documentation automatique.
|
||||
Il effectuera la validation des données composées, et les documentera ainsi pour le schéma OpenAPI et la documentation automatique.
|
||||
|
||||
## Valeurs scalaires dans le body { #singular-values-in-body }
|
||||
## Valeurs singulières dans le corps de la requête { #singular-values-in-body }
|
||||
|
||||
De la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres query et path, **FastAPI** fournit un équivalent `Body`.
|
||||
De la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres de requête et de chemin, **FastAPI** fournit un équivalent `Body`.
|
||||
|
||||
Par exemple, en étendant le modèle précédent, vous pouvez vouloir ajouter un paramètre `importance` dans le même body, en plus des paramètres `item` et `user`.
|
||||
Par exemple, en étendant le modèle précédent, vous pourriez décider d'avoir une autre clé `importance` dans le même corps de la requête, en plus de `item` et `user`.
|
||||
|
||||
Si vous le déclarez tel quel, comme c'est une valeur scalaire, **FastAPI** supposera qu'il s'agit d'un paramètre de requête.
|
||||
Si vous le déclarez tel quel, comme c'est une valeur singulière, **FastAPI** supposera qu'il s'agit d'un paramètre de requête.
|
||||
|
||||
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une variable de body en utilisant `Body` :
|
||||
Mais vous pouvez indiquer à **FastAPI** de la traiter comme une autre clé du corps de la requête en utilisant `Body` :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}
|
||||
|
||||
Dans ce cas, **FastAPI** s'attendra à un body semblable à :
|
||||
Dans ce cas, **FastAPI** s'attendra à un corps de la requête semblable à :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -92,51 +92,51 @@ Dans ce cas, **FastAPI** s'attendra à un body semblable à :
|
||||
}
|
||||
```
|
||||
|
||||
Encore une fois, cela convertira les types de données, les validera, permettra de générer la documentation, etc.
|
||||
Encore une fois, il convertira les types de données, validera, documentera, etc.
|
||||
|
||||
## Paramètres multiples body et query { #multiple-body-params-and-query }
|
||||
## Paramètres multiples du corps de la requête et paramètres de requête { #multiple-body-params-and-query }
|
||||
|
||||
Bien entendu, vous pouvez également déclarer des paramètres de requête supplémentaires quand vous en avez besoin, en plus de tout paramètre body.
|
||||
Bien entendu, vous pouvez également déclarer des paramètres de requête supplémentaires quand vous en avez besoin, en plus de tout paramètre du corps de la requête.
|
||||
|
||||
Comme, par défaut, les valeurs scalaires sont interprétées comme des paramètres query, vous n'avez pas besoin d'ajouter explicitement `Query`. Vous pouvez simplement écrire :
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Ou bien, en Python 3.10 et supérieur :
|
||||
Comme, par défaut, les valeurs singulières sont interprétées comme des paramètres de requête, vous n'avez pas besoin d'ajouter explicitement `Query`, vous pouvez simplement écrire :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Ou en Python 3.9 :
|
||||
|
||||
```Python
|
||||
q: Union[str, None] = None
|
||||
```
|
||||
|
||||
Par exemple :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}
|
||||
|
||||
/// info
|
||||
|
||||
`Body` possède les mêmes paramètres de validation additionnels et de gestion des métadonnées que `Query` et `Path`, ainsi que d'autres que nous verrons plus tard.
|
||||
`Body` possède également les mêmes paramètres supplémentaires de validation et de métadonnées que `Query`, `Path` et d'autres que vous verrez plus tard.
|
||||
|
||||
///
|
||||
|
||||
## Inclure un seul paramètre body { #embed-a-single-body-parameter }
|
||||
## Intégrer un seul paramètre du corps de la requête { #embed-a-single-body-parameter }
|
||||
|
||||
Disons que vous avez seulement un paramètre `item` dans le body, correspondant à un modèle Pydantic `Item`.
|
||||
Supposons que vous n'ayez qu'un seul paramètre `item` dans le corps de la requête, provenant d'un modèle Pydantic `Item`.
|
||||
|
||||
Par défaut, **FastAPI** attendra sa déclaration directement dans le body.
|
||||
Par défaut, **FastAPI** attendra alors son contenu directement.
|
||||
|
||||
Cependant, si vous souhaitez qu'il interprète correctement un JSON avec une clé `item` associée au contenu du modèle, comme cela serait le cas si vous déclariez des paramètres body additionnels, vous pouvez utiliser le paramètre spécial `embed` de `Body` :
|
||||
Mais si vous voulez qu'il attende un JSON avec une clé `item` contenant le contenu du modèle, comme lorsqu'on déclare des paramètres supplémentaires du corps de la requête, vous pouvez utiliser le paramètre spécial `embed` de `Body` :
|
||||
|
||||
```Python
|
||||
item: Item = Body(embed=True)
|
||||
```
|
||||
|
||||
Voici un exemple complet :
|
||||
comme dans :
|
||||
|
||||
{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}
|
||||
|
||||
Dans ce cas **FastAPI** attendra un body semblable à :
|
||||
Dans ce cas **FastAPI** s'attendra à un corps de la requête semblable à :
|
||||
|
||||
```JSON hl_lines="2"
|
||||
{
|
||||
@@ -160,12 +160,12 @@ au lieu de :
|
||||
}
|
||||
```
|
||||
|
||||
## Pour résumer { #recap }
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Vous pouvez ajouter plusieurs paramètres body à votre *fonction de chemin*, même si une requête ne peut avoir qu'un seul body.
|
||||
Vous pouvez ajouter plusieurs paramètres du corps de la requête à votre fonction de chemin d'accès, même si une requête ne peut avoir qu'un seul corps de la requête.
|
||||
|
||||
Cependant, **FastAPI** s'en chargera, vous fournira les bonnes données dans votre fonction, et validera et documentera le schéma correct dans l'*opération de chemin*.
|
||||
Mais **FastAPI** s'en chargera, vous fournira les bonnes données dans votre fonction, et validera et documentera le schéma correct dans le chemin d'accès.
|
||||
|
||||
Vous pouvez également déclarer des valeurs scalaires à recevoir dans le body.
|
||||
Vous pouvez également déclarer des valeurs singulières à recevoir dans le corps de la requête.
|
||||
|
||||
Et vous pouvez indiquer à **FastAPI** d'inclure le body dans une clé, même lorsqu'un seul paramètre est déclaré.
|
||||
Et vous pouvez indiquer à **FastAPI** d'intégrer le corps de la requête sous une clé même lorsqu'un seul paramètre est déclaré.
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
# Corps de la requête { #request-body }
|
||||
|
||||
Quand vous avez besoin d'envoyer des données depuis un client (par exemple, un navigateur) vers votre API, vous les envoyez en tant que **corps de requête**.
|
||||
Quand vous avez besoin d'envoyer de la donnée depuis un client (comme un navigateur) vers votre API, vous l'envoyez en tant que **corps de requête**.
|
||||
|
||||
Le corps d'une **requête** est la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée que votre API envoie au client.
|
||||
Le corps d'une **requête** est de la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée envoyée par votre API au client.
|
||||
|
||||
Votre API doit presque toujours envoyer un corps de **réponse**. Mais les clients n'ont pas forcément besoin d'envoyer des **corps de requête** tout le temps, parfois ils ne demandent qu'un chemin, peut-être avec quelques paramètres de requête, mais n'envoient pas de corps.
|
||||
Votre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un **corps de requête** : parfois il demande seulement un chemin, peut-être avec quelques paramètres de requête, mais n'envoie pas de corps.
|
||||
|
||||
Pour déclarer un corps de **requête**, vous utilisez des modèles <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> avec toute leur puissance et leurs avantages.
|
||||
Pour déclarer un corps de **requête**, on utilise les modèles de <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> en profitant de tous leurs avantages et fonctionnalités.
|
||||
|
||||
/// info
|
||||
|
||||
Pour envoyer des données, vous devriez utiliser l'une de ces méthodes : `POST` (la plus courante), `PUT`, `DELETE` ou `PATCH`.
|
||||
Pour envoyer de la donnée, vous devriez utiliser : `POST` (le plus populaire), `PUT`, `DELETE` ou `PATCH`.
|
||||
|
||||
Envoyer un corps avec une requête `GET` a un comportement non défini dans les spécifications ; néanmoins, c'est supporté par FastAPI, seulement pour des cas d'utilisation très complexes/extrêmes.
|
||||
Envoyer un corps dans une requête `GET` a un comportement non défini dans les spécifications, cela est néanmoins supporté par **FastAPI**, seulement pour des cas d'utilisation très complexes/extrêmes.
|
||||
|
||||
Comme c'est découragé, la documentation interactive avec Swagger UI n'affichera pas la documentation pour le corps lors de l'utilisation de `GET`, et des proxys intermédiaires pourraient ne pas le supporter.
|
||||
Ceci étant découragé, la documentation interactive générée par Swagger UI ne montrera pas de documentation pour le corps d'une requête `GET`, et les proxys intermédiaires risquent de ne pas le supporter.
|
||||
|
||||
///
|
||||
|
||||
## Importer `BaseModel` de Pydantic { #import-pydantics-basemodel }
|
||||
## Importer le `BaseModel` de Pydantic { #import-pydantics-basemodel }
|
||||
|
||||
Commencez par importer la classe `BaseModel` depuis `pydantic` :
|
||||
Commencez par importer la classe `BaseModel` du module `pydantic` :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[2] *}
|
||||
|
||||
@@ -28,13 +28,13 @@ Commencez par importer la classe `BaseModel` depuis `pydantic` :
|
||||
|
||||
Déclarez ensuite votre modèle de données en tant que classe qui hérite de `BaseModel`.
|
||||
|
||||
Utilisez les types Python standards pour tous les attributs :
|
||||
Utilisez les types Python standard pour tous les attributs :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}
|
||||
|
||||
Comme pour la déclaration de paramètres de requête, lorsqu'un attribut de modèle a une valeur par défaut, il n'est pas requis. Sinon, il est requis. Utilisez `None` pour le rendre simplement optionnel.
|
||||
Tout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, cet attribut doit être renseigné dans le corps de la requête. Utilisez `None` pour le rendre simplement optionnel.
|
||||
|
||||
Par exemple, le modèle ci-dessus déclare un «`object`» JSON (ou `dict` Python) tel que :
|
||||
Par exemple, le modèle ci-dessus déclare un JSON « `object` » (ou `dict` Python) tel que :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -45,7 +45,7 @@ Par exemple, le modèle ci-dessus déclare un «`object`» JSON (ou `dict` Pytho
|
||||
}
|
||||
```
|
||||
|
||||
... comme `description` et `tax` sont optionnels (avec une valeur par défaut de `None`), cet «`object`» JSON serait aussi valide :
|
||||
... `description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), ce JSON « `object` » serait aussi valide :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -56,109 +56,109 @@ Par exemple, le modèle ci-dessus déclare un «`object`» JSON (ou `dict` Pytho
|
||||
|
||||
## Le déclarer comme paramètre { #declare-it-as-a-parameter }
|
||||
|
||||
Pour l'ajouter à votre *opération de chemin*, déclarez-le de la même manière que vous déclarez des paramètres de chemin et de requête :
|
||||
Pour l'ajouter à votre *opération de chemin*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête :
|
||||
|
||||
{* ../../docs_src/body/tutorial001_py310.py hl[16] *}
|
||||
|
||||
... et déclarez son type comme étant le modèle que vous avez créé, `Item`.
|
||||
... et déclarez que son type est le modèle que vous avez créé : `Item`.
|
||||
|
||||
## Résultats { #results }
|
||||
|
||||
Avec cette seule déclaration de type Python, **FastAPI** va :
|
||||
En utilisant uniquement les déclarations de type Python, **FastAPI** réussit à :
|
||||
|
||||
* Lire le corps de la requête en tant que JSON.
|
||||
* Lire le contenu de la requête en tant que JSON.
|
||||
* Convertir les types correspondants (si nécessaire).
|
||||
* Valider la donnée.
|
||||
* Si la donnée est invalide, renvoyer une erreur claire et explicite, indiquant exactement où et quelle donnée est incorrecte.
|
||||
* Vous fournir la donnée reçue dans le paramètre `item`.
|
||||
* Comme vous l'avez déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support de l'éditeur (autocomplétion, etc.) pour tous ses attributs et leurs types.
|
||||
* Générer des définitions <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> pour votre modèle ; vous pouvez aussi les utiliser ailleurs si cela a du sens pour votre projet.
|
||||
* Ces schémas feront partie du schéma OpenAPI généré et seront utilisés par la documentation automatique <abbr title="User Interfaces – Interfaces utilisateur">UIs</abbr>.
|
||||
* Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où et quelle était la donnée incorrecte.
|
||||
* Passer la donnée reçue dans le paramètre `item`.
|
||||
* Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (autocomplétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs.
|
||||
* Générer des définitions <a href="https://json-schema.org" class="external-link" target="_blank">JSON Schema</a> pour votre modèle ; vous pouvez également les utiliser partout ailleurs si cela a du sens pour votre projet.
|
||||
* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront utilisés par les documentations automatiques <abbr title="User Interfaces - Interfaces utilisateur">UIs</abbr>.
|
||||
|
||||
## Documentation automatique { #automatic-docs }
|
||||
|
||||
Les schémas JSON de vos modèles feront partie du schéma OpenAPI généré et seront affichés dans la documentation interactive de l'API :
|
||||
Les schémas JSON de vos modèles seront intégrés au schéma OpenAPI global de votre application, et seront donc affichés dans la documentation interactive de l'API :
|
||||
|
||||
<img src="/img/tutorial/body/image01.png">
|
||||
|
||||
Ils seront aussi utilisés dans chaque *opération de chemin* de la documentation qui en a besoin :
|
||||
Et seront aussi utilisés dans chaque *opération de chemin* de la documentation utilisant ces modèles :
|
||||
|
||||
<img src="/img/tutorial/body/image02.png">
|
||||
|
||||
## Support de l'éditeur { #editor-support }
|
||||
|
||||
Dans votre éditeur, à l'intérieur de votre fonction, vous obtiendrez des annotations de type et de l'autocomplétion partout (ce qui n'arriverait pas si vous receviez un `dict` au lieu d'un modèle Pydantic) :
|
||||
Dans votre éditeur, vous aurez des annotations de type et de l'autocomplétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez reçu un `dict` plutôt qu'un modèle Pydantic) :
|
||||
|
||||
<img src="/img/tutorial/body/image03.png">
|
||||
|
||||
Vous obtenez aussi des vérifications d'erreurs pour les opérations incorrectes sur les types :
|
||||
Et vous obtenez aussi des vérifications d'erreurs pour les opérations de types incorrectes :
|
||||
|
||||
<img src="/img/tutorial/body/image04.png">
|
||||
|
||||
Ce n'est pas un hasard, tout le framework a été construit autour de ce design.
|
||||
Ce n'est pas un hasard, ce framework entier a été bâti avec ce design comme objectif.
|
||||
|
||||
Et il a été rigoureusement testé lors de la phase de conception, avant toute implémentation, pour s'assurer qu'il fonctionne avec tous les éditeurs.
|
||||
Et cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour vous assurer que cela fonctionnerait avec tous les éditeurs.
|
||||
|
||||
Des changements ont même été apportés à Pydantic lui‑même pour le supporter.
|
||||
Des changements sur Pydantic ont même été faits pour supporter cela.
|
||||
|
||||
Les captures d'écran précédentes ont été prises avec <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
|
||||
Les captures d'écran précédentes ont été prises sur <a href="https://code.visualstudio.com" class="external-link" target="_blank">Visual Studio Code</a>.
|
||||
|
||||
Mais vous obtiendrez le même support de l'éditeur avec <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> et la plupart des autres éditeurs Python :
|
||||
Mais vous auriez le même support de l'éditeur avec <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> et la majorité des autres éditeurs de code Python :
|
||||
|
||||
<img src="/img/tutorial/body/image05.png">
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">plug-in Pydantic pour PyCharm</a>.
|
||||
Si vous utilisez <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a> comme éditeur, vous pouvez utiliser le plug-in <a href="https://github.com/koxudaxi/pydantic-pycharm-plugin/" class="external-link" target="_blank">Pydantic PyCharm Plugin</a>.
|
||||
|
||||
Il améliore le support des modèles Pydantic avec :
|
||||
Ce qui améliore le support pour les modèles Pydantic avec :
|
||||
|
||||
* autocomplétion
|
||||
* vérifications de type
|
||||
* refactoring
|
||||
* recherche
|
||||
* inspections
|
||||
* de l'autocomplétion
|
||||
* des vérifications de type
|
||||
* du « refactoring » (ou remaniement de code)
|
||||
* de la recherche
|
||||
* des inspections
|
||||
|
||||
///
|
||||
|
||||
## Utiliser le modèle { #use-the-model }
|
||||
|
||||
Dans la fonction, vous pouvez accéder directement à tous les attributs de l'objet du modèle :
|
||||
Dans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement :
|
||||
|
||||
{* ../../docs_src/body/tutorial002_py310.py *}
|
||||
|
||||
## Corps de la requête + paramètres de chemin { #request-body-path-parameters }
|
||||
|
||||
Vous pouvez déclarer des paramètres de chemin et un corps de requête en même temps.
|
||||
Vous pouvez déclarer des paramètres de chemin et un corps de requête pour la même *opération de chemin*.
|
||||
|
||||
**FastAPI** reconnaîtra que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de fonction déclarés comme modèles Pydantic doivent être **récupérés depuis le corps de la requête**.
|
||||
**FastAPI** est capable de reconnaître que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de fonctions déclarés comme modèles Pydantic devraient être **récupérés depuis le corps de la requête**.
|
||||
|
||||
{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}
|
||||
|
||||
## Corps de la requête + paramètres de chemin et de requête { #request-body-path-query-parameters }
|
||||
|
||||
Vous pouvez aussi déclarer des paramètres de **corps**, de **chemin** et de **requête**, tous en même temps.
|
||||
Vous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête** dans la même *opération de chemin*.
|
||||
|
||||
**FastAPI** reconnaîtra chacun d'entre eux et récupérera la donnée au bon endroit.
|
||||
**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit.
|
||||
|
||||
{* ../../docs_src/body/tutorial004_py310.py hl[16] *}
|
||||
|
||||
Les paramètres de la fonction seront reconnus comme suit :
|
||||
Les paramètres de la fonction seront reconnus comme tel :
|
||||
|
||||
* Si le paramètre est aussi déclaré dans le **chemin**, il sera utilisé comme paramètre de chemin.
|
||||
* Si le paramètre est d'un **type singulier** (comme `int`, `float`, `str`, `bool`, etc.), il sera interprété comme un paramètre de **requête**.
|
||||
* Si le paramètre est déclaré comme étant du type d'un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête.
|
||||
* Si le paramètre est déclaré comme ayant pour type un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
FastAPI saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
|
||||
**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
|
||||
|
||||
L'annotation de type `str | None` (Python 3.10+) ou `Union` dans `Union[str, None]` (Python 3.9+) n'est pas utilisée par FastAPI pour déterminer que la valeur n'est pas requise, il le saura parce qu'il y a une valeur par défaut `= None`.
|
||||
L'annotation de type `str | None` (Python 3.10+) ou `Union` dans `Union[str, None]` (Python 3.9+) n'est pas utilisée par **FastAPI** pour déterminer que la valeur n'est pas requise, il le saura parce qu'elle a une valeur par défaut `= None`.
|
||||
|
||||
Mais ajouter des annotations de type permettra à votre éditeur de vous offrir un meilleur support et de détecter des erreurs.
|
||||
Mais ajouter ces annotations de type permettra à votre éditeur de vous offrir un meilleur support et de détecter des erreurs.
|
||||
|
||||
///
|
||||
|
||||
## Sans Pydantic { #without-pydantic }
|
||||
|
||||
Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres **Body**. Voir les documents pour [Corps de la requête - Paramètres multiples : Valeurs singulières dans le corps](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
Si vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Body**. Pour cela, allez voir la documentation sur [Corps de la requête - Paramètres multiples : Valeurs singulières dans le corps](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Vous pouvez connecter le <abbr title="En anglais: debugger">débogueur</abbr> dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.
|
||||
|
||||
## Faites appel à `uvicorn` { #call-uvicorn }
|
||||
## Appeler `uvicorn` { #call-uvicorn }
|
||||
|
||||
Dans votre application FastAPI, importez et exécutez directement `uvicorn` :
|
||||
|
||||
@@ -78,7 +78,7 @@ Pour plus d'informations, consultez <a href="https://docs.python.org/3/library/_
|
||||
|
||||
///
|
||||
|
||||
## Exécutez votre code avec votre <abbr title="En anglais: debugger">débogueur</abbr> { #run-your-code-with-your-debugger }
|
||||
## Exécuter votre code avec votre <abbr title="En anglais: debugger">débogueur</abbr> { #run-your-code-with-your-debugger }
|
||||
|
||||
Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le <abbr title="En anglais: debugger">débogueur</abbr>.
|
||||
|
||||
@@ -86,10 +86,10 @@ Parce que vous exécutez le serveur Uvicorn directement depuis votre code, vous
|
||||
|
||||
Par exemple, dans Visual Studio Code, vous pouvez :
|
||||
|
||||
* Aller au panneau «Debug».
|
||||
* «Add configuration ...».
|
||||
* Sélectionnez «Python»
|
||||
* Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option «`Python: Current File (Integrated Terminal)`».
|
||||
- Allez dans le panneau « Debug ».
|
||||
- « Add configuration... ».
|
||||
- Sélectionnez « Python ».
|
||||
- Lancez le <abbr title="En anglais: debugger">débogueur</abbr> avec l'option « Python: Current File (Integrated Terminal) ».
|
||||
|
||||
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
|
||||
|
||||
@@ -101,10 +101,10 @@ Voici à quoi cela pourrait ressembler :
|
||||
|
||||
Si vous utilisez Pycharm, vous pouvez :
|
||||
|
||||
* Ouvrez le menu «Run».
|
||||
* Sélectionnez l'option «Debug ...».
|
||||
* Un menu contextuel s'affiche alors.
|
||||
* Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).
|
||||
- Ouvrez le menu « Run ».
|
||||
- Sélectionnez l'option « Debug... ».
|
||||
- Un menu contextuel s'affiche alors.
|
||||
- Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).
|
||||
|
||||
Il démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Premiers pas { #first-steps }
|
||||
# Démarrage { #first-steps }
|
||||
|
||||
Le fichier FastAPI le plus simple possible pourrait ressembler à ceci :
|
||||
Le fichier **FastAPI** le plus simple possible pourrait ressembler à ceci :
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py *}
|
||||
|
||||
Copiez cela dans un fichier `main.py`.
|
||||
|
||||
Lancez le serveur de développement :
|
||||
Démarrez le serveur en direct :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -48,19 +48,19 @@ $ <font color="#4E9A06">fastapi</font> dev <u style="text-decoration-style:solid
|
||||
|
||||
</div>
|
||||
|
||||
Dans la sortie, il y a une ligne semblable à :
|
||||
Dans la sortie, il y a une ligne semblable à :
|
||||
|
||||
```hl_lines="4"
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
Cette ligne indique l’URL à laquelle votre application est servie, sur votre machine locale.
|
||||
Cette ligne montre l’URL où votre application est servie, sur votre machine locale.
|
||||
|
||||
### Vérifiez { #check-it }
|
||||
|
||||
Ouvrez votre navigateur à l’adresse <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a>.
|
||||
|
||||
Vous verrez la réponse JSON suivante :
|
||||
Vous verrez la réponse JSON suivante :
|
||||
|
||||
```JSON
|
||||
{"message": "Hello World"}
|
||||
@@ -68,9 +68,9 @@ Vous verrez la réponse JSON suivante :
|
||||
|
||||
### Documentation interactive de l’API { #interactive-api-docs }
|
||||
|
||||
Rendez-vous maintenant sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
Allez maintenant sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
|
||||
|
||||
Vous verrez la documentation interactive automatique de l’API (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
Vous verrez la documentation interactive de l’API générée automatiquement (fournie par <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a>) :
|
||||
|
||||

|
||||
|
||||
@@ -78,41 +78,41 @@ Vous verrez la documentation interactive automatique de l’API (fournie par <a
|
||||
|
||||
Et maintenant, allez sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
|
||||
|
||||
Vous verrez la documentation alternative automatique (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
Vous verrez la documentation automatique alternative (fournie par <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>) :
|
||||
|
||||

|
||||
|
||||
### OpenAPI { #openapi }
|
||||
|
||||
**FastAPI** génère un «schéma» avec toute votre API en utilisant le standard **OpenAPI** pour définir des API.
|
||||
**FastAPI** génère un « schéma » contenant toute votre API en utilisant le standard **OpenAPI** pour définir des API.
|
||||
|
||||
#### «Schéma» { #schema }
|
||||
#### « Schéma » { #schema }
|
||||
|
||||
Un «schéma» est une définition ou description de quelque chose. Pas le code qui l’implémente, mais juste une description abstraite.
|
||||
Un « schéma » est une définition ou une description de quelque chose. Pas le code qui l’implémente, mais uniquement une description abstraite.
|
||||
|
||||
#### «Schéma» d’API { #api-schema }
|
||||
#### « Schéma » d’API { #api-schema }
|
||||
|
||||
Ici, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> est une spécification qui dicte comment définir le schéma de votre API.
|
||||
|
||||
Cette définition de schéma inclut les chemins de votre API, les paramètres possibles qu’ils prennent, etc.
|
||||
|
||||
#### «Schéma» de données { #data-schema }
|
||||
#### « Schéma » de données { #data-schema }
|
||||
|
||||
Le terme «schéma» peut aussi se référer à la forme de certaines données, comme un contenu JSON.
|
||||
Le terme « schéma » peut également faire référence à la forme d’une donnée, comme un contenu JSON.
|
||||
|
||||
Dans ce cas, cela désignerait les attributs JSON, et leurs types de données, etc.
|
||||
Dans ce cas, cela désignerait les attributs JSON, ainsi que leurs types, etc.
|
||||
|
||||
#### OpenAPI et JSON Schema { #openapi-and-json-schema }
|
||||
|
||||
OpenAPI définit un schéma d’API pour votre API. Et ce schéma inclut des définitions (ou «schémas») des données envoyées et reçues par votre API en utilisant **JSON Schema**, le standard pour les schémas de données JSON.
|
||||
OpenAPI définit un schéma d’API pour votre API. Et ce schéma inclut des définitions (ou « schémas ») des données envoyées et reçues par votre API en utilisant **JSON Schema**, le standard pour les schémas de données JSON.
|
||||
|
||||
#### Vérifier `openapi.json` { #check-the-openapi-json }
|
||||
#### Voir le `openapi.json` { #check-the-openapi-json }
|
||||
|
||||
Si vous êtes curieux de voir à quoi ressemble le schéma OpenAPI brut, FastAPI génère automatiquement un JSON (schéma) avec les descriptions de toute votre API.
|
||||
|
||||
Vous pouvez le voir directement ici : <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
Vous pouvez le voir directement à l’adresse : <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
|
||||
Il affichera un JSON commençant par quelque chose comme :
|
||||
Il affichera un JSON commençant par quelque chose comme :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -137,19 +137,19 @@ Il affichera un JSON commençant par quelque chose comme :
|
||||
|
||||
#### À quoi sert OpenAPI { #what-is-openapi-for }
|
||||
|
||||
Le schéma OpenAPI alimente les deux systèmes de documentation interactive inclus.
|
||||
Le schéma OpenAPI est ce qui alimente les deux systèmes de documentation interactive inclus.
|
||||
|
||||
Et il existe des dizaines d’alternatives, toutes basées sur OpenAPI. Vous pourriez facilement ajouter l’une de ces alternatives à votre application construite avec **FastAPI**.
|
||||
Et il existe des dizaines d’alternatives, toutes basées sur OpenAPI. Vous pourriez facilement ajouter n’importe laquelle de ces alternatives à votre application construite avec **FastAPI**.
|
||||
|
||||
Vous pourriez également l’utiliser pour générer automatiquement du code pour des clients qui communiquent avec votre API. Par exemple, des applications frontend, mobiles ou IoT.
|
||||
Vous pourriez également l’utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Par exemple, des applications frontend, mobiles ou IoT.
|
||||
|
||||
### Déployer votre application (optionnel) { #deploy-your-app-optional }
|
||||
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, rejoignez la liste d’attente si ce n’est pas déjà fait. 🚀
|
||||
Vous pouvez, si vous le souhaitez, déployer votre application FastAPI sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>, allez rejoindre la liste d’attente si ce n’est pas déjà fait. 🚀
|
||||
|
||||
Si vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉), vous pouvez déployer votre application avec une seule commande.
|
||||
|
||||
Avant de déployer, assurez-vous d’être connecté :
|
||||
Avant de déployer, vous devez vous assurer que vous êtes connecté :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -161,7 +161,7 @@ You are logged in to FastAPI Cloud 🚀
|
||||
|
||||
</div>
|
||||
|
||||
Puis déployez votre application :
|
||||
Puis déployez votre application :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -177,7 +177,7 @@ Deploying to FastAPI Cloud...
|
||||
|
||||
</div>
|
||||
|
||||
Et voilà ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
C’est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨
|
||||
|
||||
## Récapitulatif, étape par étape { #recap-step-by-step }
|
||||
|
||||
@@ -185,7 +185,7 @@ Et voilà ! Vous pouvez maintenant accéder à votre application à cette URL.
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *}
|
||||
|
||||
`FastAPI` est une classe Python qui fournit toutes les fonctionnalités pour votre API.
|
||||
`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires à votre API.
|
||||
|
||||
/// note | Détails techniques
|
||||
|
||||
@@ -195,27 +195,27 @@ Vous pouvez donc aussi utiliser toutes les fonctionnalités de <a href="https://
|
||||
|
||||
///
|
||||
|
||||
### Étape 2 : créer une «instance» `FastAPI` { #step-2-create-a-fastapi-instance }
|
||||
### Étape 2 : créer une « instance » `FastAPI` { #step-2-create-a-fastapi-instance }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *}
|
||||
|
||||
Ici, la variable `app` sera une «instance» de la classe `FastAPI`.
|
||||
Ici, la variable `app` sera une « instance » de la classe `FastAPI`.
|
||||
|
||||
Ce sera le point principal d’interaction pour créer toute votre API.
|
||||
|
||||
### Étape 3 : créer une *opération de chemin* { #step-3-create-a-path-operation }
|
||||
### Étape 3 : créer un « chemin d’accès » { #step-3-create-a-path-operation }
|
||||
|
||||
#### Chemin { #path }
|
||||
|
||||
«Chemin» (ou «path») fait ici référence à la dernière partie de l’URL à partir du premier `/`.
|
||||
« Chemin » fait ici référence à la dernière partie de l’URL à partir du premier `/`.
|
||||
|
||||
Ainsi, dans une URL comme :
|
||||
Donc, dans une URL telle que :
|
||||
|
||||
```
|
||||
https://example.com/items/foo
|
||||
```
|
||||
|
||||
... le chemin serait :
|
||||
... le chemin serait :
|
||||
|
||||
```
|
||||
/items/foo
|
||||
@@ -223,77 +223,77 @@ https://example.com/items/foo
|
||||
|
||||
/// info
|
||||
|
||||
Un «chemin» est aussi couramment appelé un «endpoint» ou une «route».
|
||||
Un « chemin » est aussi couramment appelé « endpoint » ou « route ».
|
||||
|
||||
///
|
||||
|
||||
Lors de la construction d’une API, le «chemin» est le principal moyen de séparer les «responsabilités» et les «ressources».
|
||||
Lors de la création d’une API, le « chemin » est la manière principale de séparer les « préoccupations » et les « ressources ».
|
||||
|
||||
#### Opération { #operation }
|
||||
|
||||
«Opération» fait ici référence à l’une des «méthodes» HTTP.
|
||||
« Opération » fait ici référence à l’une des « méthodes » HTTP.
|
||||
|
||||
L’une de :
|
||||
L’une de :
|
||||
|
||||
* `POST`
|
||||
* `GET`
|
||||
* `PUT`
|
||||
* `DELETE`
|
||||
|
||||
... et les plus exotiques :
|
||||
... et les plus exotiques :
|
||||
|
||||
* `OPTIONS`
|
||||
* `HEAD`
|
||||
* `PATCH`
|
||||
* `TRACE`
|
||||
|
||||
Dans le protocole HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plusieurs) de ces «méthodes».
|
||||
Dans le protocole HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plusieurs) de ces « méthodes ».
|
||||
|
||||
---
|
||||
|
||||
En construisant des API, vous utilisez normalement ces méthodes HTTP spécifiques pour effectuer une action spécifique.
|
||||
En construisant des APIs, vous utilisez normalement ces méthodes HTTP spécifiques pour effectuer une action précise.
|
||||
|
||||
Normalement, vous utilisez :
|
||||
En général, vous utilisez :
|
||||
|
||||
* `POST` : pour créer des données.
|
||||
* `GET` : pour lire des données.
|
||||
* `PUT` : pour mettre à jour des données.
|
||||
* `DELETE` : pour supprimer des données.
|
||||
|
||||
Ainsi, dans OpenAPI, chacune des méthodes HTTP est appelée une «opération».
|
||||
Donc, dans OpenAPI, chacune des méthodes HTTP est appelée une « opération ».
|
||||
|
||||
Nous allons donc aussi les appeler «opérations».
|
||||
Nous allons donc aussi les appeler « opérations ».
|
||||
|
||||
#### Définir un *décorateur d’opération de chemin* { #define-a-path-operation-decorator }
|
||||
#### Définir un « décorateur de chemin d’accès » { #define-a-path-operation-decorator }
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *}
|
||||
|
||||
Le `@app.get("/")` indique à **FastAPI** que la fonction juste en dessous est chargée de traiter les requêtes qui vont vers :
|
||||
Le `@app.get("/")` indique à **FastAPI** que la fonction juste en dessous est chargée de gérer les requêtes qui vont vers :
|
||||
|
||||
* le chemin `/`
|
||||
* en utilisant une <abbr title="une méthode HTTP GET">opération <code>get</code></abbr>
|
||||
* en utilisant une <abbr title="une méthode HTTP GET"><code>get</code> opération</abbr>
|
||||
|
||||
/// info | `@décorateur` Info
|
||||
|
||||
Cette syntaxe `@something` en Python est appelée un «décorateur».
|
||||
Cette syntaxe `@something` en Python est appelée un « décorateur ».
|
||||
|
||||
Vous la placez au-dessus d’une fonction. Comme un joli chapeau décoratif (je suppose que c’est de là que vient le terme 🤷🏻♂).
|
||||
Vous la mettez au-dessus d’une fonction. Comme un joli chapeau décoratif (j’imagine que c’est de là que vient le terme 🤷🏻♂).
|
||||
|
||||
Un «décorateur» prend la fonction en dessous et fait quelque chose avec.
|
||||
Un « décorateur » prend la fonction en dessous et fait quelque chose avec.
|
||||
|
||||
Dans notre cas, ce décorateur indique à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec l’**opération** `get`.
|
||||
Dans notre cas, ce décorateur indique à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec une **opération** `get`.
|
||||
|
||||
C’est le «décorateur d’opération de chemin».
|
||||
C’est le « décorateur de chemin d’accès ».
|
||||
|
||||
///
|
||||
|
||||
Vous pouvez aussi utiliser les autres opérations :
|
||||
Vous pouvez aussi utiliser les autres opérations :
|
||||
|
||||
* `@app.post()`
|
||||
* `@app.put()`
|
||||
* `@app.delete()`
|
||||
|
||||
Et les plus exotiques :
|
||||
Ainsi que les plus exotiques :
|
||||
|
||||
* `@app.options()`
|
||||
* `@app.head()`
|
||||
@@ -306,37 +306,37 @@ Vous êtes libre d’utiliser chaque opération (méthode HTTP) comme vous le so
|
||||
|
||||
**FastAPI** n’impose aucune signification spécifique.
|
||||
|
||||
Les informations ici sont présentées comme des lignes directrices, pas comme une exigence.
|
||||
Les informations ici sont présentées comme des lignes directrices, pas comme une obligation.
|
||||
|
||||
Par exemple, lorsque vous utilisez GraphQL, vous effectuez normalement toutes les actions en utilisant uniquement des opérations `POST`.
|
||||
|
||||
///
|
||||
|
||||
### Étape 4 : définir la **fonction d’opération de chemin** { #step-4-define-the-path-operation-function }
|
||||
### Étape 4 : définir la **fonction de chemin d’accès** { #step-4-define-the-path-operation-function }
|
||||
|
||||
Voici notre «fonction d’opération de chemin» :
|
||||
Voici notre « fonction de chemin d’accès » :
|
||||
|
||||
* **chemin** : `/`.
|
||||
* **opération** : `get`.
|
||||
* **fonction** : la fonction sous le «décorateur» (sous `@app.get("/")`).
|
||||
* **fonction** : la fonction sous le « décorateur » (sous `@app.get("/")`).
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *}
|
||||
|
||||
C’est une fonction Python.
|
||||
|
||||
Elle sera appelée par **FastAPI** chaque fois qu’il reçoit une requête vers l’URL «`/`» en utilisant une opération `GET`.
|
||||
Elle sera appelée par **FastAPI** chaque fois qu’il recevra une requête vers l’URL « / » en utilisant une opération `GET`.
|
||||
|
||||
Dans ce cas, c’est une fonction `async`.
|
||||
|
||||
---
|
||||
|
||||
Vous pourriez aussi la définir comme une fonction normale au lieu de `async def` :
|
||||
Vous pouvez aussi la définir comme une fonction normale au lieu de `async def` :
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *}
|
||||
|
||||
/// note | Remarque
|
||||
/// note
|
||||
|
||||
Si vous ne connaissez pas la différence, consultez [Asynchrone : *«Pressé ?»*](../async.md#in-a-hurry){.internal-link target=_blank}.
|
||||
Si vous ne connaissez pas la différence, consultez [Asynchrone : « Pressé ? »](../async.md#in-a-hurry){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
@@ -344,23 +344,23 @@ Si vous ne connaissez pas la différence, consultez [Asynchrone : *«Pressé ?»
|
||||
|
||||
{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *}
|
||||
|
||||
Vous pouvez retourner un `dict`, une `list`, des valeurs simples comme `str`, `int`, etc.
|
||||
Vous pouvez retourner un `dict`, une `list`, des valeurs uniques comme `str`, `int`, etc.
|
||||
|
||||
Vous pouvez également retourner des modèles Pydantic (vous en verrez plus à ce sujet plus tard).
|
||||
|
||||
Il existe de nombreux autres objets et modèles qui seront automatiquement convertis en JSON (y compris des ORM, etc.). Essayez d’utiliser vos préférés, il est très probable qu’ils soient déjà pris en charge.
|
||||
Il existe de nombreux autres objets et modèles qui seront automatiquement convertis en JSON (y compris des ORM, etc.). Essayez d’utiliser vos favoris, il est fort probable qu’ils soient déjà pris en charge.
|
||||
|
||||
### Étape 6 : la déployer { #step-6-deploy-it }
|
||||
### Étape 6 : le déployer { #step-6-deploy-it }
|
||||
|
||||
Déployez votre application sur **<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** avec une seule commande : `fastapi deploy`. 🎉
|
||||
Déployez votre application sur **<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** avec une seule commande : `fastapi deploy`. 🎉
|
||||
|
||||
#### À propos de FastAPI Cloud { #about-fastapi-cloud }
|
||||
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est développé par le même auteur et la même équipe derrière **FastAPI**.
|
||||
**<a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>** est construit par le même auteur et l’équipe derrière **FastAPI**.
|
||||
|
||||
Il rationalise le processus de **construction**, **déploiement** et **accès** à une API avec un effort minimal.
|
||||
Il simplifie le processus de **construction**, de **déploiement** et d’**accès** à une API avec un minimum d’effort.
|
||||
|
||||
Il apporte la même **expérience développeur** que pour la création d’applications avec FastAPI au **déploiement** dans le cloud. 🎉
|
||||
Il apporte la même **expérience développeur** de création d’applications avec FastAPI au **déploiement** dans le cloud. 🎉
|
||||
|
||||
FastAPI Cloud est le sponsor principal et le financeur des projets open source *FastAPI and friends*. ✨
|
||||
|
||||
@@ -374,7 +374,7 @@ Suivez les guides de votre fournisseur cloud pour y déployer des applications F
|
||||
|
||||
* Importez `FastAPI`.
|
||||
* Créez une instance `app`.
|
||||
* Écrivez un **décorateur d’opération de chemin** avec des décorateurs comme `@app.get("/")`.
|
||||
* Définissez une **fonction d’opération de chemin** ; par exemple, `def root(): ...`.
|
||||
* Lancez le serveur de développement avec la commande `fastapi dev`.
|
||||
* Écrivez un **décorateur de chemin d’accès** avec des décorateurs comme `@app.get("/")`.
|
||||
* Définissez une **fonction de chemin d’accès** ; par exemple, `def root(): ...`.
|
||||
* Exécutez le serveur de développement avec la commande `fastapi dev`.
|
||||
* Déployez éventuellement votre application avec `fastapi deploy`.
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Tutoriel - Guide d'utilisation { #tutorial-user-guide }
|
||||
# Tutoriel - Guide utilisateur { #tutorial-user-guide }
|
||||
|
||||
Ce tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape.
|
||||
|
||||
Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour résoudre vos besoins spécifiques en matière d'API.
|
||||
Chaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour répondre à vos besoins spécifiques d'API.
|
||||
|
||||
Il est également conçu pour servir de référence future afin que vous puissiez revenir et voir exactement ce dont vous avez besoin.
|
||||
Il est également conçu pour servir de référence ultérieure, afin que vous puissiez revenir voir exactement ce dont vous avez besoin.
|
||||
|
||||
## Exécuter le code { #run-the-code }
|
||||
|
||||
Tous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés).
|
||||
|
||||
Pour exécuter l'un des exemples, copiez le code dans un fichier `main.py`, et lancez `fastapi dev` avec :
|
||||
Pour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et démarrez `fastapi dev` avec :
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -76,11 +76,11 @@ $ pip install "fastapi[standard]"
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Lorsque vous installez avec `pip install "fastapi[standard]"`, cela inclut certaines dépendances standard optionnelles par défaut, y compris `fastapi-cloud-cli`, qui vous permet de déployer sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
|
||||
Lorsque vous installez avec `pip install "fastapi[standard]"` cela inclut des dépendances standard optionnelles par défaut, y compris `fastapi-cloud-cli`, qui vous permet de déployer sur <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
|
||||
|
||||
Si vous ne souhaitez pas avoir ces dépendances optionnelles, vous pouvez installer à la place `pip install fastapi`.
|
||||
Si vous ne souhaitez pas avoir ces dépendances optionnelles, vous pouvez à la place installer `pip install fastapi`.
|
||||
|
||||
Si vous voulez installer les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
|
||||
Si vous souhaitez installer les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
|
||||
|
||||
///
|
||||
|
||||
@@ -88,8 +88,8 @@ Si vous voulez installer les dépendances standard mais sans `fastapi-cloud-cli`
|
||||
|
||||
Il existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**.
|
||||
|
||||
Le **Guide d'utilisation avancé** s'appuie sur celui-ci, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
|
||||
Le **Guide d'utilisation avancé**, qui s'appuie sur cette base, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.
|
||||
|
||||
Mais vous devriez d'abord lire le **Tutoriel - Guide d'utilisation** (ce que vous êtes en train de lire en ce moment).
|
||||
Mais vous devez d'abord lire le **Tutoriel - Guide d'utilisation** (ce que vous êtes en train de lire en ce moment).
|
||||
|
||||
Il est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide d'utilisation**, puis l'étendre de différentes manières, selon vos besoins, en utilisant certaines des idées supplémentaires du **Guide d'utilisation avancé**.
|
||||
Il est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide d'utilisation**, puis l'étendre de différentes manières, en fonction de vos besoins, en utilisant certaines des idées supplémentaires du **Guide d'utilisation avancé**.
|
||||
|
||||
@@ -14,7 +14,7 @@ FastAPI a ajouté le support pour `Annotated` (et a commencé à le recommander)
|
||||
|
||||
Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d'utiliser `Annotated`.
|
||||
|
||||
Assurez-vous de [mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 au minimum avant d'utiliser `Annotated`.
|
||||
Assurez-vous de [Mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} à la version 0.95.1 à minima avant d'utiliser `Annotated`.
|
||||
|
||||
///
|
||||
|
||||
@@ -32,7 +32,7 @@ Un paramètre de chemin est toujours requis car il doit faire partie du chemin.
|
||||
|
||||
///
|
||||
|
||||
## Ordonnez les paramètres comme vous le souhaitez { #order-the-parameters-as-you-need }
|
||||
## Ordonner les paramètres comme vous le souhaitez { #order-the-parameters-as-you-need }
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
@@ -46,7 +46,7 @@ Et vous n'avez pas besoin de déclarer autre chose pour ce paramètre, donc vous
|
||||
|
||||
Mais vous avez toujours besoin d'utiliser `Path` pour le paramètre de chemin `item_id`. Et vous ne voulez pas utiliser `Annotated` pour une raison quelconque.
|
||||
|
||||
Python se plaindra si vous mettez une valeur avec une «défaut» avant une valeur qui n'a pas de «défaut».
|
||||
Python se plaindra si vous mettez une valeur avec une « valeur par défaut » avant une valeur qui n'a pas de « valeur par défaut ».
|
||||
|
||||
Mais vous pouvez les réorganiser, et avoir la valeur sans défaut (le paramètre de requête `q`) en premier.
|
||||
|
||||
@@ -60,7 +60,7 @@ Mais gardez à l'esprit que si vous utilisez `Annotated`, vous n'aurez pas ce pr
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *}
|
||||
|
||||
## Ordonnez les paramètres comme vous le souhaitez (astuces) { #order-the-parameters-as-you-need-tricks }
|
||||
## Ordonner les paramètres comme vous le souhaitez, astuces { #order-the-parameters-as-you-need-tricks }
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
@@ -77,7 +77,7 @@ Si vous voulez :
|
||||
* les avoir dans un ordre différent
|
||||
* ne pas utiliser `Annotated`
|
||||
|
||||
...Python a une petite syntaxe spéciale pour cela.
|
||||
... Python a une petite syntaxe spéciale pour cela.
|
||||
|
||||
Passez `*`, comme premier paramètre de la fonction.
|
||||
|
||||
@@ -95,7 +95,7 @@ Gardez à l'esprit que si vous utilisez `Annotated`, comme vous n'utilisez pas l
|
||||
|
||||
Avec `Query` et `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des contraintes numériques.
|
||||
|
||||
Ici, avec `ge=1`, `item_id` devra être un nombre entier «`g`reater than or `e`qual» à `1`.
|
||||
Ici, avec `ge=1`, `item_id` devra être un nombre entier « `g`reater than or `e`qual » à `1`.
|
||||
|
||||
{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Paramètres de chemin { #path-parameters }
|
||||
|
||||
Vous pouvez déclarer des «paramètres» ou «variables» de chemin avec la même syntaxe que celle utilisée par les chaînes de formatage Python :
|
||||
Vous pouvez déclarer des « paramètres » ou « variables » de chemin avec la même syntaxe utilisée par les chaînes de format Python :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *}
|
||||
|
||||
La valeur du paramètre de chemin `item_id` sera transmise à la fonction dans l'argument `item_id`.
|
||||
La valeur du paramètre de chemin `item_id` sera transmise à votre fonction dans l'argument `item_id`.
|
||||
|
||||
Donc, si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous verrez comme réponse :
|
||||
|
||||
@@ -20,32 +20,31 @@ Vous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en uti
|
||||
|
||||
Ici, `item_id` est déclaré comme `int`.
|
||||
|
||||
/// check | vérifier
|
||||
/// check | Vérifications
|
||||
|
||||
Ceci vous permettra d'obtenir des fonctionnalités de l'éditeur dans votre fonction, telles que des vérifications d'erreurs, de l'autocomplétion, etc.
|
||||
Cela vous apporte la prise en charge par l'éditeur dans votre fonction, avec vérifications d'erreurs, autocomplétion, etc.
|
||||
|
||||
///
|
||||
|
||||
## <abbr title="aussi connu sous le nom : sérialisation, parsing, marshalling">Conversion</abbr> de données { #data-conversion }
|
||||
## <abbr title="également appelé : sérialisation, parsing, marshalling">Conversion</abbr> de données { #data-conversion }
|
||||
|
||||
Si vous exécutez cet exemple et allez sur <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, vous aurez comme réponse :
|
||||
Si vous exécutez cet exemple et ouvrez votre navigateur sur <a href="http://127.0.0.1:8000/items/3" class="external-link" target="_blank">http://127.0.0.1:8000/items/3</a>, vous verrez comme réponse :
|
||||
|
||||
```JSON
|
||||
{"item_id":3}
|
||||
```
|
||||
|
||||
/// check | vérifier
|
||||
/// check | Vérifications
|
||||
|
||||
Comme vous l'avez remarqué, la valeur reçue par la fonction (et renvoyée ensuite) est `3`,
|
||||
en tant qu'entier (`int`) Python, pas la chaîne de caractères (`string`) «3».
|
||||
Remarquez que la valeur reçue par votre fonction (et renvoyée) est `3`, en tant qu'entier (`int`) Python, pas la chaîne de caractères « 3 ».
|
||||
|
||||
Donc, avec cette déclaration de type, **FastAPI** vous fournit un <abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">«parsing»</abbr> de la requête automatique.
|
||||
Ainsi, avec cette déclaration de type, **FastAPI** vous fournit automatiquement le <abbr title="conversion de la chaîne de caractères provenant d'une requête HTTP en données Python">« parsing »</abbr> de la requête.
|
||||
|
||||
///
|
||||
|
||||
## Validation de données { #data-validation }
|
||||
|
||||
Si vous allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous aurez une belle erreur HTTP :
|
||||
Mais si vous allez dans le navigateur sur <a href="http://127.0.0.1:8000/items/foo" class="external-link" target="_blank">http://127.0.0.1:8000/items/foo</a>, vous verrez une belle erreur HTTP :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -63,53 +62,47 @@ Si vous allez sur <a href="http://127.0.0.1:8000/items/foo" class="external-link
|
||||
}
|
||||
```
|
||||
|
||||
car le paramètre de chemin `item_id` possède comme valeur «foo», qui n'est pas un `int`.
|
||||
car le paramètre de chemin `item_id` a pour valeur « foo », qui n'est pas un `int`.
|
||||
|
||||
La même erreur se produira si vous passez un nombre flottant (`float`) et non un entier, comme ici
|
||||
<a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>.
|
||||
La même erreur apparaîtrait si vous fournissiez un `float` au lieu d'un `int`, comme ici : <a href="http://127.0.0.1:8000/items/4.2" class="external-link" target="_blank">http://127.0.0.1:8000/items/4.2</a>
|
||||
|
||||
/// check | vérifier
|
||||
/// check | Vérifications
|
||||
|
||||
Donc, avec ces mêmes déclarations de type Python, **FastAPI** vous fournit de la validation de données.
|
||||
Ainsi, avec la même déclaration de type Python, **FastAPI** vous fournit la validation de données.
|
||||
|
||||
Notez que l'erreur mentionne le point exact où la validation n'a pas réussi.
|
||||
Remarquez que l'erreur indique clairement l'endroit exact où la validation n'a pas réussi.
|
||||
|
||||
Ce qui est incroyablement utile au moment de développer et débugger du code qui interagit avec votre API.
|
||||
C'est incroyablement utile lors du développement et du débogage du code qui interagit avec votre API.
|
||||
|
||||
///
|
||||
|
||||
## Documentation { #documentation }
|
||||
|
||||
Et quand vous vous rendez sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, vous verrez la
|
||||
documentation générée automatiquement et interactive :
|
||||
Et lorsque vous ouvrez votre navigateur sur <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>, vous verrez une documentation d'API automatique et interactive comme :
|
||||
|
||||
<img src="/img/tutorial/path-params/image01.png">
|
||||
|
||||
/// check | vérifier
|
||||
/// check | Vérifications
|
||||
|
||||
À nouveau, en utilisant uniquement les déclarations de type Python, **FastAPI** vous fournit automatiquement une documentation interactive (intégrant Swagger UI).
|
||||
À nouveau, simplement avec cette même déclaration de type Python, **FastAPI** vous fournit une documentation interactive automatique (intégrant Swagger UI).
|
||||
|
||||
On voit bien dans la documentation que `item_id` est déclaré comme entier.
|
||||
Remarquez que le paramètre de chemin est déclaré comme entier.
|
||||
|
||||
///
|
||||
|
||||
## Les avantages d'avoir une documentation basée sur une norme, et la documentation alternative { #standards-based-benefits-alternative-documentation }
|
||||
## Les avantages d'une norme, documentation alternative { #standards-based-benefits-alternative-documentation }
|
||||
|
||||
Le schéma généré suivant la norme <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a>,
|
||||
il existe de nombreux outils compatibles.
|
||||
Et comme le schéma généré suit la norme <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a>, il existe de nombreux outils compatibles.
|
||||
|
||||
Grâce à cela, **FastAPI** lui-même fournit une documentation alternative (utilisant ReDoc), qui peut être lue
|
||||
sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> :
|
||||
Grâce à cela, **FastAPI** fournit lui-même une documentation d'API alternative (utilisant ReDoc), accessible sur <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> :
|
||||
|
||||
<img src="/img/tutorial/path-params/image02.png">
|
||||
|
||||
De la même façon, il existe bien d'autres outils compatibles, y compris des outils de génération de code
|
||||
pour de nombreux langages.
|
||||
De la même façon, il existe de nombreux outils compatibles, y compris des outils de génération de code pour de nombreux langages.
|
||||
|
||||
## Pydantic { #pydantic }
|
||||
|
||||
Toute la validation de données est effectuée en arrière-plan avec <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>,
|
||||
dont vous bénéficierez de tous les avantages. Vous savez donc que vous êtes entre de bonnes mains.
|
||||
Toute la validation de données est effectuée sous le capot par <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a>, vous en bénéficiez donc pleinement. Vous savez ainsi que vous êtes entre de bonnes mains.
|
||||
|
||||
Vous pouvez utiliser les mêmes déclarations de type avec `str`, `float`, `bool` et de nombreux autres types de données complexes.
|
||||
|
||||
@@ -117,87 +110,87 @@ Plusieurs d'entre eux sont explorés dans les prochains chapitres du tutoriel.
|
||||
|
||||
## L'ordre importe { #order-matters }
|
||||
|
||||
Quand vous créez des *opérations de chemin*, vous pouvez vous retrouver dans une situation où vous avez un chemin fixe.
|
||||
Quand vous créez des *chemins d'accès*, vous pouvez vous retrouver dans une situation avec un chemin fixe.
|
||||
|
||||
Tel que `/users/me`, disons pour récupérer les données sur l'utilisateur actuel.
|
||||
Par exemple `/users/me`, disons pour récupérer les données de l'utilisateur actuel.
|
||||
|
||||
Et vous avez un second chemin : `/users/{user_id}` pour récupérer de la donnée sur un utilisateur spécifique grâce à son identifiant d'utilisateur
|
||||
Et vous pouvez aussi avoir un chemin `/users/{user_id}` pour récupérer des données sur un utilisateur spécifique grâce à un identifiant d'utilisateur.
|
||||
|
||||
Les *opérations de chemin* étant évaluées dans l'ordre, il faut s'assurer que la fonction correspondant à `/users/me` est déclarée avant celle de `/users/{user_id}` :
|
||||
Comme les *chemins d'accès* sont évalués dans l'ordre, vous devez vous assurer que le chemin `/users/me` est déclaré avant celui de `/users/{user_id}` :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *}
|
||||
|
||||
Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, la fonction «croyant» qu'elle a reçu un paramètre `user_id` avec pour valeur «me».
|
||||
Sinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, « pensant » qu'il reçoit un paramètre `user_id` avec la valeur « me ».
|
||||
|
||||
De même, vous ne pouvez pas redéfinir une opération de chemin :
|
||||
De même, vous ne pouvez pas redéfinir un chemin d'accès :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *}
|
||||
|
||||
La première sera toujours utilisée car le chemin correspond d'abord.
|
||||
Le premier sera toujours utilisé puisque le chemin correspond en premier.
|
||||
|
||||
## Valeurs prédéfinies { #predefined-values }
|
||||
|
||||
Si vous avez une *opération de chemin* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles des paramètres soient prédéfinies, vous pouvez utiliser les <abbr title="Enumeration">`Enum`</abbr> de Python.
|
||||
Si vous avez un *chemin d'accès* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles de ce *paramètre de chemin* soient prédéfinies, vous pouvez utiliser une <abbr title="Enumeration">`Enum`</abbr> Python standard.
|
||||
|
||||
### Créer une classe `Enum` { #create-an-enum-class }
|
||||
|
||||
Importez `Enum` et créez une sous-classe qui hérite de `str` et de `Enum`.
|
||||
|
||||
En héritant de `str`, la documentation de l'API saura que les valeurs doivent être de type `string` et pourra donc l'afficher correctement.
|
||||
En héritant de `str`, la documentation de l'API saura que les valeurs doivent être de type `string` et pourra donc s'afficher correctement.
|
||||
|
||||
Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs autorisées pour cette énumération.
|
||||
Créez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs valides disponibles :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pour ceux qui se demandent, «AlexNet», «ResNet», et «LeNet» sont juste des noms de <abbr title="Techniquement, des architectures de modèles de Deep Learning">modèles</abbr> de Machine Learning.
|
||||
Si vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des noms de <abbr title="Techniquement, architectures de modèles de Deep Learning">modèles</abbr> de Machine Learning.
|
||||
|
||||
///
|
||||
|
||||
### Déclarer un *paramètre de chemin* { #declare-a-path-parameter }
|
||||
### Déclarer un paramètre de chemin { #declare-a-path-parameter }
|
||||
|
||||
Créez ensuite un *paramètre de chemin* avec une annotation de type désignant l'énumération créée précédemment (`ModelName`) :
|
||||
Créez ensuite un *paramètre de chemin* avec une annotation de type utilisant la classe d'énumération que vous avez créée (`ModelName`) :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *}
|
||||
|
||||
### Vérifier la documentation { #check-the-docs }
|
||||
### Consulter la documentation { #check-the-docs }
|
||||
|
||||
Les valeurs disponibles pour le *paramètre de chemin* sont bien prédéfinies, la documentation les affiche correctement :
|
||||
Comme les valeurs disponibles pour le *paramètre de chemin* sont prédéfinies, la documentation interactive peut les afficher clairement :
|
||||
|
||||
<img src="/img/tutorial/path-params/image03.png">
|
||||
|
||||
### Manipuler les *énumérations* Python { #working-with-python-enumerations }
|
||||
### Travailler avec les *énumérations* Python { #working-with-python-enumerations }
|
||||
|
||||
La valeur du *paramètre de chemin* sera un des «membres» de l'énumération.
|
||||
La valeur du *paramètre de chemin* sera un *membre d'énumération*.
|
||||
|
||||
#### Comparer les *membres d'énumération* { #compare-enumeration-members }
|
||||
#### Comparer des *membres d'énumération* { #compare-enumeration-members }
|
||||
|
||||
Vous pouvez comparer ce paramètre avec les membres de votre énumération `ModelName` :
|
||||
Vous pouvez le comparer avec le *membre d'énumération* dans votre enum `ModelName` :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *}
|
||||
|
||||
#### Récupérer la *valeur de l'énumération* { #get-the-enumeration-value }
|
||||
#### Obtenir la *valeur de l'énumération* { #get-the-enumeration-value }
|
||||
|
||||
Vous pouvez obtenir la valeur réelle d'un membre (une chaîne de caractères ici), avec `model_name.value`, ou en général, `votre_membre_d'enum.value` :
|
||||
Vous pouvez obtenir la valeur réelle (une `str` dans ce cas) avec `model_name.value`, ou en général, `votre_membre_d_enum.value` :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pouvez aussi accéder à la valeur «lenet» avec `ModelName.lenet.value`.
|
||||
Vous pouvez aussi accéder à la valeur « lenet » avec `ModelName.lenet.value`.
|
||||
|
||||
///
|
||||
|
||||
#### Retourner des *membres d'énumération* { #return-enumeration-members }
|
||||
|
||||
Vous pouvez retourner des *membres d'énumération* dans vos *opérations de chemin*, même imbriqués dans un corps JSON (e.g. un `dict`).
|
||||
Vous pouvez retourner des *membres d'énumération* depuis votre *chemin d'accès*, même imbriqués dans un corps JSON (par ex. un `dict`).
|
||||
|
||||
Ils seront convertis vers leurs valeurs correspondantes (chaînes de caractères ici) avant d'être transmis au client :
|
||||
Ils seront convertis vers leurs valeurs correspondantes (des chaînes de caractères ici) avant d'être renvoyés au client :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *}
|
||||
|
||||
Le client recevra une réponse JSON comme celle-ci :
|
||||
Dans votre client, vous recevrez une réponse JSON comme :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -208,23 +201,23 @@ Le client recevra une réponse JSON comme celle-ci :
|
||||
|
||||
## Paramètres de chemin contenant des chemins { #path-parameters-containing-paths }
|
||||
|
||||
Disons que vous avez une *opération de chemin* liée au chemin `/files/{file_path}`.
|
||||
Disons que vous avez un *chemin d'accès* avec un chemin `/files/{file_path}`.
|
||||
|
||||
Mais que `file_path` lui-même doit contenir un *chemin*, comme `home/johndoe/myfile.txt` par exemple.
|
||||
Mais vous avez besoin que `file_path` lui-même contienne un *chemin*, comme `home/johndoe/myfile.txt`.
|
||||
|
||||
Donc, l'URL pour ce fichier pourrait être : `/files/home/johndoe/myfile.txt`.
|
||||
Ainsi, l'URL pour ce fichier serait : `/files/home/johndoe/myfile.txt`.
|
||||
|
||||
### Support d'OpenAPI { #openapi-support }
|
||||
|
||||
OpenAPI ne supporte pas de manière de déclarer un *paramètre de chemin* contenant un *chemin* à l'intérieur, cela pouvant causer des scénarios difficiles à tester et définir.
|
||||
OpenAPI ne prend pas en charge une manière de déclarer un *paramètre de chemin* contenant un *chemin* à l'intérieur, car cela peut conduire à des scénarios difficiles à tester et à définir.
|
||||
|
||||
Néanmoins, cela reste faisable dans **FastAPI**, via les outils internes de Starlette.
|
||||
Néanmoins, vous pouvez toujours le faire dans **FastAPI**, en utilisant l'un des outils internes de Starlette.
|
||||
|
||||
Et la documentation fonctionne quand même, bien qu'aucune section ne soit ajoutée pour dire que le paramètre devrait contenir un *chemin*.
|
||||
Et la documentation fonctionnera quand même, même si aucune indication supplémentaire ne sera ajoutée pour dire que le paramètre doit contenir un chemin.
|
||||
|
||||
### Convertisseur de *chemin* { #path-convertor }
|
||||
### Convertisseur de chemin { #path-convertor }
|
||||
|
||||
En utilisant une option de Starlette directement, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :
|
||||
En utilisant une option directement depuis Starlette, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :
|
||||
|
||||
```
|
||||
/files/{file_path:path}
|
||||
@@ -232,13 +225,13 @@ En utilisant une option de Starlette directement, vous pouvez déclarer un *para
|
||||
|
||||
Dans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique que le paramètre doit correspondre à n'importe quel *chemin*.
|
||||
|
||||
Vous pouvez donc l'utiliser comme tel :
|
||||
Vous pouvez donc l'utiliser ainsi :
|
||||
|
||||
{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *}
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash au début (`/`).
|
||||
Vous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash initial (`/`).
|
||||
|
||||
Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double slash (`//`) entre `files` et `home`.
|
||||
|
||||
@@ -246,13 +239,13 @@ Dans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double sl
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Avec **FastAPI**, en utilisant les déclarations de type rapides, intuitives et standards de Python, vous bénéficiez de :
|
||||
Avec **FastAPI**, en utilisant des déclarations de type Python courtes, intuitives et standard, vous obtenez :
|
||||
|
||||
* Support de l'éditeur : vérification d'erreurs, autocomplétion, etc.
|
||||
* «<abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">Parsing</abbr>» de données
|
||||
* Support de l'éditeur : vérifications d'erreurs, autocomplétion, etc.
|
||||
* Données « <abbr title="conversion de la chaîne de caractères provenant d'une requête HTTP en données Python">parsing</abbr> »
|
||||
* Validation de données
|
||||
* Annotations d'API et documentation automatique
|
||||
|
||||
Et vous n'avez besoin de le déclarer qu'une fois.
|
||||
Et vous n'avez besoin de les déclarer qu'une seule fois.
|
||||
|
||||
C'est probablement l'avantage visible principal de **FastAPI** comparé aux autres frameworks (outre les performances pures).
|
||||
|
||||
@@ -6,26 +6,26 @@ Prenons cette application comme exemple :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}
|
||||
|
||||
Le paramètre de requête `q` est de type `str | None`, ce qui signifie qu'il est de type `str` mais peut aussi être `None`. D'ailleurs, la valeur par défaut est `None`, donc FastAPI saura qu'il n'est pas requis.
|
||||
Le paramètre de requête `q` est de type `str | None`, cela signifie qu’il est de type `str` mais peut aussi être `None`, et en effet, la valeur par défaut est `None`, donc FastAPI saura qu’il n’est pas requis.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
FastAPI saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.
|
||||
FastAPI saura que la valeur de `q` n’est pas requise grâce à la valeur par défaut `= None`.
|
||||
|
||||
Le fait d'avoir `str | None` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
|
||||
Avoir `str | None` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.
|
||||
|
||||
///
|
||||
|
||||
## Validation additionnelle { #additional-validation }
|
||||
|
||||
Nous allons imposer que, même si `q` est optionnel, dès qu'il est fourni, **sa longueur n'excède pas 50 caractères**.
|
||||
Nous allons imposer que, même si `q` est optionnel, dès qu’il est fourni, **sa longueur n’excède pas 50 caractères**.
|
||||
|
||||
### Importer `Query` et `Annotated` { #import-query-and-annotated }
|
||||
|
||||
Pour cela, importez d'abord :
|
||||
Pour ce faire, importez d’abord :
|
||||
|
||||
* `Query` depuis `fastapi`
|
||||
* `Annotated` depuis `typing`
|
||||
- `Query` depuis `fastapi`
|
||||
- `Annotated` depuis `typing`
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}
|
||||
|
||||
@@ -33,17 +33,17 @@ Pour cela, importez d'abord :
|
||||
|
||||
FastAPI a ajouté la prise en charge de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.
|
||||
|
||||
Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d'utiliser `Annotated`.
|
||||
Si vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d’utiliser `Annotated`.
|
||||
|
||||
Assurez-vous de [mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} vers au moins la 0.95.1 avant d'utiliser `Annotated`.
|
||||
Assurez-vous de [mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions){.internal-link target=_blank} vers au moins 0.95.1 avant d’utiliser `Annotated`.
|
||||
|
||||
///
|
||||
|
||||
## Utiliser `Annotated` dans le type pour le paramètre `q` { #use-annotated-in-the-type-for-the-q-parameter }
|
||||
|
||||
Vous vous souvenez, je vous ai dit plus tôt que `Annotated` pouvait être utilisé pour ajouter des métadonnées à vos paramètres dans l’[introduction aux types Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} ?
|
||||
Vous vous souvenez que je vous ai dit plus tôt que `Annotated` peut être utilisé pour ajouter des métadonnées à vos paramètres dans l’[Introduction aux types Python](../python-types.md#type-hints-with-metadata-annotations){.internal-link target=_blank} ?
|
||||
|
||||
Il est temps de l'utiliser avec FastAPI. 🚀
|
||||
C’est le moment de l’utiliser avec FastAPI. 🚀
|
||||
|
||||
Nous avions cette annotation de type :
|
||||
|
||||
@@ -63,7 +63,7 @@ q: Union[str, None] = None
|
||||
|
||||
////
|
||||
|
||||
Nous allons l'envelopper avec `Annotated`, ce qui donne :
|
||||
Ce que nous allons faire, c’est l’englober avec `Annotated`, de sorte que cela devienne :
|
||||
|
||||
//// tab | Python 3.10+
|
||||
|
||||
@@ -81,39 +81,39 @@ q: Annotated[Union[str, None]] = None
|
||||
|
||||
////
|
||||
|
||||
Ces deux versions signifient la même chose : `q` est un paramètre qui peut être un `str` ou `None`, et par défaut, il vaut `None`.
|
||||
Les deux versions signifient la même chose, `q` est un paramètre qui peut être une `str` ou `None`, et par défaut, c’est `None`.
|
||||
|
||||
Passons maintenant aux choses amusantes. 🎉
|
||||
|
||||
## Ajouter `Query` à `Annotated` dans le paramètre `q` { #add-query-to-annotated-in-the-q-parameter }
|
||||
|
||||
Maintenant que nous avons ce `Annotated` dans lequel nous pouvons mettre plus d'informations (dans ce cas une validation supplémentaire), ajoutez `Query` à l'intérieur de `Annotated`, et définissez le paramètre `max_length` à `50` :
|
||||
Maintenant que nous avons cet `Annotated` dans lequel nous pouvons mettre plus d’informations (dans ce cas une validation supplémentaire), ajoutez `Query` à l’intérieur de `Annotated`, et définissez le paramètre `max_length` à `50` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}
|
||||
|
||||
Notez que la valeur par défaut est toujours `None`, donc le paramètre est toujours optionnel.
|
||||
Remarquez que la valeur par défaut est toujours `None`, donc le paramètre est toujours optionnel.
|
||||
|
||||
Mais maintenant, avec `Query(max_length=50)` à l'intérieur de `Annotated`, nous indiquons à FastAPI que nous voulons une **validation supplémentaire** pour cette valeur, nous voulons qu'elle ait au maximum 50 caractères. 😎
|
||||
Mais maintenant, avec `Query(max_length=50)` à l’intérieur de `Annotated`, nous indiquons à FastAPI que nous voulons **une validation supplémentaire** pour cette valeur, nous voulons qu’elle ait au maximum 50 caractères. 😎
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Ici, nous utilisons `Query()` parce qu'il s'agit d'un **paramètre de requête**. Plus tard, nous verrons d'autres objets comme `Path()`, `Body()`, `Header()` et `Cookie()`, qui acceptent aussi les mêmes arguments que `Query()`.
|
||||
Ici nous utilisons `Query()` parce qu’il s’agit d’un **paramètre de requête**. Plus tard nous verrons d’autres comme `Path()`, `Body()`, `Header()` et `Cookie()`, qui acceptent également les mêmes arguments que `Query()`.
|
||||
|
||||
///
|
||||
|
||||
FastAPI va maintenant :
|
||||
|
||||
* **Valider** les données en s'assurant que la longueur maximale est de 50 caractères
|
||||
* Afficher une **erreur claire** au client lorsque les données ne sont pas valides
|
||||
* **Documenter** le paramètre dans l’*opération de chemin* du schéma OpenAPI (de sorte qu'il apparaisse dans **l'interface de documentation automatique**)
|
||||
- **Valider** les données en s’assurant que la longueur maximale est de 50 caractères
|
||||
- Afficher une **erreur claire** au client quand les données ne sont pas valides
|
||||
- **Documenter** le paramètre dans la *chemin d'accès* du schéma OpenAPI (il apparaîtra donc dans l’**interface de documentation automatique**)
|
||||
|
||||
## Alternative (ancien) : `Query` comme valeur par défaut { #alternative-old-query-as-the-default-value }
|
||||
## Alternative (ancienne) : `Query` comme valeur par défaut { #alternative-old-query-as-the-default-value }
|
||||
|
||||
Les versions précédentes de FastAPI (avant <abbr title="avant 2023-03">0.95.0</abbr>) vous obligeaient à utiliser `Query` comme valeur par défaut de votre paramètre, au lieu de le mettre dans `Annotated`. Il y a de fortes chances que vous voyiez du code qui l'utilise encore, donc je vais vous l'expliquer.
|
||||
Les versions précédentes de FastAPI (avant <abbr title="avant 2023-03">0.95.0</abbr>) exigeaient d’utiliser `Query` comme valeur par défaut de votre paramètre, au lieu de le mettre dans `Annotated`. Il y a de fortes chances que vous voyiez du code qui l’utilise encore, je vais donc vous l’expliquer.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pour un nouveau code et dès que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a de multiples avantages (expliqués ci-dessous) et aucun inconvénient. 🍰
|
||||
Pour du nouveau code et dès que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a de multiples avantages (expliqués ci-dessous) et aucun inconvénient. 🍰
|
||||
|
||||
///
|
||||
|
||||
@@ -121,7 +121,7 @@ Voici comment vous utiliseriez `Query()` comme valeur par défaut du paramètre
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}
|
||||
|
||||
Comme dans ce cas (sans utiliser `Annotated`) nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous devons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, cela sert le même objectif de définir cette valeur par défaut (au moins pour FastAPI).
|
||||
Comme, dans ce cas (sans utiliser `Annotated`), nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous devons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, cela sert le même objectif de définir cette valeur par défaut (au moins pour FastAPI).
|
||||
|
||||
Donc :
|
||||
|
||||
@@ -129,7 +129,7 @@ Donc :
|
||||
q: str | None = Query(default=None)
|
||||
```
|
||||
|
||||
... rend le paramètre optionnel, avec une valeur par défaut de `None`, ce qui est équivalent à :
|
||||
... rend le paramètre optionnel, avec une valeur par défaut de `None`, comme :
|
||||
|
||||
```Python
|
||||
q: str | None = None
|
||||
@@ -137,29 +137,29 @@ q: str | None = None
|
||||
|
||||
Mais la version avec `Query` le déclare explicitement comme étant un paramètre de requête.
|
||||
|
||||
Ensuite, nous pouvons passer d'autres paramètres à `Query`. Dans ce cas, le paramètre `max_length` qui s'applique aux chaînes de caractères :
|
||||
Ensuite, nous pouvons passer plus de paramètres à `Query`. Dans ce cas, le paramètre `max_length` qui s’applique aux chaînes de caractères :
|
||||
|
||||
```Python
|
||||
q: str | None = Query(default=None, max_length=50)
|
||||
```
|
||||
|
||||
Cela va valider les données, afficher une erreur claire lorsque les données ne sont pas valides, et documenter le paramètre dans l’*opération de chemin* du schéma OpenAPI.
|
||||
Cela validera les données, affichera une erreur claire lorsque les données ne sont pas valides et documentera le paramètre dans la *chemin d'accès* du schéma OpenAPI.
|
||||
|
||||
### `Query` comme valeur par défaut ou dans `Annotated` { #query-as-the-default-value-or-in-annotated }
|
||||
|
||||
Gardez à l'esprit qu'en utilisant `Query` à l'intérieur de `Annotated`, vous ne pouvez pas utiliser le paramètre `default` de `Query`.
|
||||
Gardez à l’esprit qu’en utilisant `Query` à l’intérieur de `Annotated`, vous ne pouvez pas utiliser le paramètre `default` de `Query`.
|
||||
|
||||
Utilisez plutôt la véritable valeur par défaut du paramètre de fonction. Sinon, ce serait incohérent.
|
||||
Utilisez à la place la valeur par défaut réelle du paramètre de fonction. Sinon, ce serait incohérent.
|
||||
|
||||
Par exemple, ceci n'est pas autorisé :
|
||||
Par exemple, ceci n’est pas autorisé :
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query(default="rick")] = "morty"
|
||||
```
|
||||
|
||||
... parce qu'il n'est pas clair si la valeur par défaut devrait être «rick» ou «morty».
|
||||
... parce qu’il n’est pas clair si la valeur par défaut doit être « rick » ou « morty ».
|
||||
|
||||
Ainsi, vous utiliseriez (de préférence) :
|
||||
Donc, vous utiliseriez (de préférence) :
|
||||
|
||||
```Python
|
||||
q: Annotated[str, Query()] = "rick"
|
||||
@@ -173,55 +173,55 @@ q: str = Query(default="rick")
|
||||
|
||||
### Avantages de `Annotated` { #advantages-of-annotated }
|
||||
|
||||
**Utiliser `Annotated` est recommandé** plutôt que la valeur par défaut dans les paramètres de fonction, c'est **mieux** pour plusieurs raisons. 🤓
|
||||
**L’utilisation de `Annotated` est recommandée** plutôt que la valeur par défaut dans les paramètres de fonction, c’est **mieux** pour plusieurs raisons. 🤓
|
||||
|
||||
La **valeur par défaut** du **paramètre de fonction** est la **véritable valeur par défaut**, c'est plus intuitif en Python en général. 😌
|
||||
La valeur **par défaut** du **paramètre de fonction** est la **vraie valeur par défaut**, c’est plus intuitif en Python en général. 😌
|
||||
|
||||
Vous pourriez **appeler** cette même fonction **ailleurs** sans FastAPI, et elle **fonctionnerait comme prévu**. S'il y a un paramètre **requis** (sans valeur par défaut), votre **éditeur** vous le signalera avec une erreur, **Python** se plaindra aussi si vous l'exécutez sans passer le paramètre requis.
|
||||
Vous pouvez **appeler** cette même fonction dans **d’autres endroits** sans FastAPI, et elle **fonctionnera comme prévu**. S’il y a un paramètre **requis** (sans valeur par défaut), votre **éditeur** vous le signalera avec une erreur, **Python** se plaindra aussi si vous l’exécutez sans passer le paramètre requis.
|
||||
|
||||
Lorsque vous n'utilisez pas `Annotated` et que vous utilisez à la place l’**(ancien) style de valeur par défaut**, si vous appelez cette fonction sans FastAPI **ailleurs**, vous devez **penser** à passer les arguments à la fonction pour qu'elle fonctionne correctement, sinon les valeurs seront différentes de ce à quoi vous vous attendez (par exemple `QueryInfo` ou quelque chose de similaire au lieu de `str`). Et votre éditeur ne se plaindra pas, et Python ne se plaindra pas en exécutant cette fonction, seulement lorsque les opérations internes échoueront.
|
||||
Quand vous n’utilisez pas `Annotated` et utilisez à la place l’**ancienne** méthode avec la **valeur par défaut**, si vous appelez cette fonction sans FastAPI dans **d’autres endroits**, vous devez **penser** à passer les arguments à la fonction pour qu’elle fonctionne correctement, sinon les valeurs seront différentes de ce que vous attendez (par ex. `QueryInfo` ou quelque chose de similaire au lieu d’une `str`). Et votre éditeur ne se plaindra pas, et Python ne se plaindra pas en exécutant cette fonction, seulement quand les opérations internes échoueront.
|
||||
|
||||
Comme `Annotated` peut avoir plus d'une annotation de métadonnées, vous pouvez même utiliser la même fonction avec d'autres outils, comme <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
|
||||
Comme `Annotated` peut avoir plus d’une annotation de métadonnées, vous pouvez maintenant même utiliser la même fonction avec d’autres outils, comme <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">Typer</a>. 🚀
|
||||
|
||||
## Ajouter plus de validations { #add-more-validations }
|
||||
|
||||
Vous pouvez aussi ajouter un paramètre `min_length` :
|
||||
Vous pouvez également ajouter un paramètre `min_length` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}
|
||||
|
||||
## Ajouter des expressions régulières { #add-regular-expressions }
|
||||
|
||||
Vous pouvez définir un `pattern` d’<abbr title="Une expression régulière, regex ou regexp est une suite de caractères qui définit un motif de recherche pour les chaînes de caractères.">expression régulière</abbr> auquel le paramètre doit correspondre :
|
||||
Vous pouvez définir un `pattern` d’<abbr title="Une expression régulière, regex ou regexp, est une suite de caractères qui définit un motif de recherche pour les chaînes de caractères.">expression régulière</abbr> auquel le paramètre doit correspondre :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}
|
||||
|
||||
Ce motif d'expression régulière vérifie que la valeur de paramètre reçue :
|
||||
Ce pattern d’expression régulière spécifique vérifie que la valeur reçue pour le paramètre :
|
||||
|
||||
* `^` : commence avec les caractères qui suivent, n'a pas de caractères avant.
|
||||
* `fixedquery` : a pour valeur exacte `fixedquery`.
|
||||
* `$` : se termine là, n'a pas d'autres caractères après `fixedquery`.
|
||||
- `^` : commence avec les caractères qui suivent, n’a pas de caractères avant.
|
||||
- `fixedquery` : a exactement la valeur `fixedquery`.
|
||||
- `$` : se termine là, n’a pas d’autres caractères après `fixedquery`.
|
||||
|
||||
Si vous vous sentez perdu avec toutes ces idées d’**«expression régulière»**, pas d'inquiétude. C'est un sujet difficile pour beaucoup. Vous pouvez déjà faire beaucoup de choses sans avoir besoin des expressions régulières.
|
||||
Si vous vous sentez perdu avec toutes ces idées d’**« expression régulière »**, pas d’inquiétude. C’est un sujet difficile pour beaucoup. Vous pouvez déjà faire beaucoup de choses sans avoir besoin d’expressions régulières.
|
||||
|
||||
Maintenant vous savez que, lorsque vous en avez besoin, vous pouvez les utiliser dans **FastAPI**.
|
||||
Désormais, vous savez que, lorsque vous en aurez besoin, vous pourrez les utiliser dans **FastAPI**.
|
||||
|
||||
## Valeurs par défaut { #default-values }
|
||||
|
||||
Vous pouvez, bien sûr, utiliser des valeurs par défaut autres que `None`.
|
||||
|
||||
Disons que vous voulez déclarer le paramètre de requête `q` avec un `min_length` de `3`, et avec une valeur par défaut de «fixedquery» :
|
||||
Disons que vous voulez déclarer le paramètre de requête `q` avec un `min_length` de `3`, et avec une valeur par défaut de « fixedquery » :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial005_an_py39.py hl[9] *}
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Avoir une valeur par défaut de n'importe quel type, y compris `None`, rend le paramètre optionnel (non requis).
|
||||
Avoir une valeur par défaut de n’importe quel type, y compris `None`, rend le paramètre optionnel (non requis).
|
||||
|
||||
///
|
||||
|
||||
## Paramètres requis { #required-parameters }
|
||||
|
||||
Quand nous n'avons pas besoin de déclarer plus de validations ou de métadonnées, nous pouvons rendre le paramètre de requête `q` requis simplement en ne déclarant pas de valeur par défaut, comme :
|
||||
Quand nous n’avons pas besoin de déclarer plus de validations ou de métadonnées, nous pouvons rendre le paramètre de requête `q` requis en n’indiquant simplement pas de valeur par défaut, comme :
|
||||
|
||||
```Python
|
||||
q: str
|
||||
@@ -233,7 +233,7 @@ au lieu de :
|
||||
q: str | None = None
|
||||
```
|
||||
|
||||
Mais nous le déclarons maintenant avec `Query`, par exemple ainsi :
|
||||
Mais maintenant nous le déclarons avec `Query`, par exemple ainsi :
|
||||
|
||||
```Python
|
||||
q: Annotated[str | None, Query(min_length=3)] = None
|
||||
@@ -243,31 +243,31 @@ Donc, lorsque vous avez besoin de déclarer une valeur comme requise tout en uti
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006_an_py39.py hl[9] *}
|
||||
|
||||
### Requis, peut être `None` { #required-can-be-none }
|
||||
### Requis, peut valoir `None` { #required-can-be-none }
|
||||
|
||||
Vous pouvez déclarer qu'un paramètre peut accepter `None`, mais qu'il est tout de même requis. Cela obligera les clients à envoyer une valeur, même si la valeur est `None`.
|
||||
Vous pouvez déclarer qu’un paramètre accepte `None`, mais qu’il est tout de même requis. Cela obligerait les clients à envoyer une valeur, même si la valeur est `None`.
|
||||
|
||||
Pour cela, vous pouvez déclarer que `None` est un type valide mais ne pas déclarer de valeur par défaut :
|
||||
Pour ce faire, vous pouvez déclarer que `None` est un type valide tout en ne déclarant pas de valeur par défaut :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}
|
||||
|
||||
## Liste de paramètres de requête / valeurs multiples { #query-parameter-list-multiple-values }
|
||||
|
||||
Quand vous définissez un paramètre de requête explicitement avec `Query`, vous pouvez aussi déclarer qu'il reçoit une liste de valeurs, autrement dit, des valeurs multiples.
|
||||
Quand vous définissez un paramètre de requête explicitement avec `Query`, vous pouvez aussi déclarer qu’il reçoit une liste de valeurs, autrement dit, qu’il reçoit des valeurs multiples.
|
||||
|
||||
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans l'URL, vous pouvez écrire :
|
||||
Par exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans l’URL, vous pouvez écrire :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}
|
||||
|
||||
Avec une URL comme :
|
||||
Ensuite, avec une URL comme :
|
||||
|
||||
```
|
||||
http://localhost:8000/items/?q=foo&q=bar
|
||||
```
|
||||
|
||||
vous recevrez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python au sein de votre *fonction d'opération de chemin*, dans le *paramètre de fonction* `q`.
|
||||
vous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python à l’intérieur de votre fonction de *chemin d'accès*, dans le *paramètre de fonction* `q`.
|
||||
|
||||
Donc, la réponse à cette URL serait :
|
||||
Donc, la réponse pour cette URL serait :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -280,17 +280,17 @@ Donc, la réponse à cette URL serait :
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pour déclarer un paramètre de requête de type `list`, comme dans l'exemple ci-dessus, vous devez explicitement utiliser `Query`, sinon cela sera interprété comme faisant partie du corps de la requête.
|
||||
Pour déclarer un paramètre de requête avec un type `list`, comme dans l’exemple ci-dessus, vous devez explicitement utiliser `Query`, sinon il serait interprété comme faisant partie du corps de la requête.
|
||||
|
||||
///
|
||||
|
||||
Les documents interactifs de l'API seront mis à jour en conséquence, pour autoriser plusieurs valeurs :
|
||||
L’interface de documentation interactive de l’API sera mise à jour en conséquence, pour autoriser plusieurs valeurs :
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image02.png">
|
||||
|
||||
### Liste de paramètres de requête / valeurs multiples avec valeurs par défaut { #query-parameter-list-multiple-values-with-defaults }
|
||||
|
||||
Vous pouvez aussi définir une `list` de valeurs par défaut si aucune n'est fournie :
|
||||
Vous pouvez également définir une `list` de valeurs par défaut si aucune n’est fournie :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial012_an_py39.py hl[9] *}
|
||||
|
||||
@@ -319,23 +319,23 @@ Vous pouvez aussi utiliser `list` directement au lieu de `list[str]` :
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Gardez à l'esprit que dans ce cas, FastAPI ne vérifiera pas le contenu de la liste.
|
||||
Gardez à l’esprit que dans ce cas, FastAPI ne vérifiera pas le contenu de la liste.
|
||||
|
||||
Par exemple, `list[int]` vérifierait (et documenterait) que le contenu de la liste est composé d'entiers. Mais `list` seul ne le ferait pas.
|
||||
Par exemple, `list[int]` vérifierait (et documenterait) que le contenu de la liste est composé d’entiers. Mais un simple `list` ne le ferait pas.
|
||||
|
||||
///
|
||||
|
||||
## Déclarer plus de métadonnées { #declare-more-metadata }
|
||||
|
||||
Vous pouvez ajouter plus d'informations sur le paramètre.
|
||||
Vous pouvez ajouter plus d’informations à propos du paramètre.
|
||||
|
||||
Ces informations seront incluses dans l'OpenAPI généré et utilisées par les interfaces utilisateur de la documentation et les outils externes.
|
||||
Ces informations seront incluses dans l’OpenAPI généré et utilisées par les interfaces de documentation et les outils externes.
|
||||
|
||||
/// note | Remarque
|
||||
|
||||
Gardez à l'esprit que différents outils peuvent avoir des niveaux de prise en charge d'OpenAPI différents.
|
||||
Gardez à l’esprit que différents outils peuvent avoir des niveaux de prise en charge d’OpenAPI différents.
|
||||
|
||||
Certains d'entre eux peuvent ne pas encore afficher toutes les informations supplémentaires déclarées, bien que, dans la plupart des cas, la fonctionnalité manquante soit déjà planifiée.
|
||||
Certains d’entre eux pourraient ne pas encore afficher toutes les informations supplémentaires déclarées, bien que, dans la plupart des cas, la fonctionnalité manquante soit déjà prévue au développement.
|
||||
|
||||
///
|
||||
|
||||
@@ -347,7 +347,7 @@ Et une `description` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}
|
||||
|
||||
## Alias de paramètres { #alias-parameters }
|
||||
## Paramètres avec alias { #alias-parameters }
|
||||
|
||||
Imaginez que vous vouliez que le paramètre soit `item-query`.
|
||||
|
||||
@@ -357,11 +357,11 @@ Comme dans :
|
||||
http://127.0.0.1:8000/items/?item-query=foobaritems
|
||||
```
|
||||
|
||||
Mais `item-query` n'est pas un nom de variable Python valide.
|
||||
Mais `item-query` n’est pas un nom de variable Python valide.
|
||||
|
||||
Le plus proche serait `item_query`.
|
||||
|
||||
Mais vous avez quand même besoin que ce soit exactement `item-query`...
|
||||
Mais vous avez quand même besoin que ce soit exactement `item-query` ...
|
||||
|
||||
Vous pouvez alors déclarer un `alias`, et cet alias sera utilisé pour trouver la valeur du paramètre :
|
||||
|
||||
@@ -369,15 +369,15 @@ Vous pouvez alors déclarer un `alias`, et cet alias sera utilisé pour trouver
|
||||
|
||||
## Déprécier des paramètres { #deprecating-parameters }
|
||||
|
||||
Disons maintenant que vous n'aimez plus ce paramètre.
|
||||
Disons que vous n’aimez plus ce paramètre.
|
||||
|
||||
Vous devez le laisser pendant un certain temps car des clients l'utilisent, mais vous voulez que les documents l'affichent clairement comme <abbr title="obsolète, il est recommandé de ne pas l'utiliser">déprécié</abbr>.
|
||||
Vous devez le laisser là quelque temps car des clients l’utilisent, mais vous voulez que les documents l’affichent clairement comme <abbr title="obsolète, recommandé de ne pas l’utiliser">déprécié</abbr>.
|
||||
|
||||
Passez alors le paramètre `deprecated=True` à `Query` :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}
|
||||
|
||||
Les documents l'afficheront ainsi :
|
||||
Les documents l’afficheront ainsi :
|
||||
|
||||
<img src="/img/tutorial/query-params-str-validations/image01.png">
|
||||
|
||||
@@ -389,85 +389,85 @@ Pour exclure un paramètre de requête du schéma OpenAPI généré (et donc, de
|
||||
|
||||
## Validation personnalisée { #custom-validation }
|
||||
|
||||
Il peut y avoir des cas où vous avez besoin d'une **validation personnalisée** qui ne peut pas être réalisée avec les paramètres présentés ci-dessus.
|
||||
Il peut y avoir des cas où vous devez faire une **validation personnalisée** qui ne peut pas être réalisée avec les paramètres montrés ci-dessus.
|
||||
|
||||
Dans ces cas, vous pouvez utiliser une **fonction de validation personnalisée** qui est appliquée après la validation normale (par exemple, après avoir validé que la valeur est une `str`).
|
||||
Dans ces cas, vous pouvez utiliser une **fonction de validation personnalisée** qui est appliquée après la validation normale (par ex. après avoir validé que la valeur est une `str`).
|
||||
|
||||
Vous pouvez y parvenir en utilisant <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`AfterValidator` de Pydantic</a> à l'intérieur de `Annotated`.
|
||||
Vous pouvez y parvenir en utilisant <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator" class="external-link" target="_blank">`AfterValidator` de Pydantic</a> à l’intérieur de `Annotated`.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Pydantic dispose aussi de <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> et d'autres. 🤓
|
||||
Pydantic a aussi <a href="https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator" class="external-link" target="_blank">`BeforeValidator`</a> et d’autres. 🤓
|
||||
|
||||
///
|
||||
|
||||
Par exemple, ce validateur personnalisé vérifie que l'identifiant d'item commence par `isbn-` pour un numéro de livre <abbr title="ISBN signifie International Standard Book Number – Numéro international normalisé du livre">ISBN</abbr> ou par `imdb-` pour un identifiant d'URL de film <abbr title="IMDB (Internet Movie Database) est un site web avec des informations sur les films">IMDB</abbr> :
|
||||
Par exemple, ce validateur personnalisé vérifie que l’ID d’item commence par `isbn-` pour un numéro de livre <abbr title="International Standard Book Number - Numéro international normalisé du livre">ISBN</abbr> ou par `imdb-` pour un ID d’URL de film <abbr title="IMDB (Internet Movie Database) est un site web contenant des informations sur les films">IMDB</abbr> :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}
|
||||
|
||||
/// info
|
||||
|
||||
Ceci est disponible avec Pydantic version 2 ou supérieure. 😎
|
||||
C’est disponible avec Pydantic version 2 ou supérieure. 😎
|
||||
|
||||
///
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Si vous devez effectuer un type de validation nécessitant une communication avec un **composant externe**, comme une base de données ou une autre API, vous devriez plutôt utiliser les **dépendances FastAPI**, que vous apprendrez à connaître plus tard.
|
||||
Si vous devez faire un type de validation qui nécessite de communiquer avec un **composant externe**, comme une base de données ou une autre API, vous devez plutôt utiliser les **Dépendances de FastAPI**, vous en apprendrez davantage plus tard.
|
||||
|
||||
Ces validateurs personnalisés sont destinés aux choses qui peuvent être vérifiées **uniquement** avec **les mêmes données** fournies dans la requête.
|
||||
Ces validateurs personnalisés sont destinés aux éléments qui peuvent être vérifiés **uniquement** avec les **mêmes données** fournies dans la requête.
|
||||
|
||||
///
|
||||
|
||||
### Comprendre ce code { #understand-that-code }
|
||||
|
||||
Le point important est simplement d'utiliser **`AfterValidator` avec une fonction à l'intérieur de `Annotated`**. N'hésitez pas à sauter cette partie. 🤸
|
||||
Le point important est simplement d’utiliser **`AfterValidator` avec une fonction à l’intérieur de `Annotated`**. N’hésitez pas à passer cette partie. 🤸
|
||||
|
||||
---
|
||||
|
||||
Mais si vous êtes curieux à propos de cet exemple de code spécifique et que vous êtes toujours captivé, voici quelques détails supplémentaires.
|
||||
Mais si vous êtes curieux de cet exemple de code spécifique et que vous êtes toujours partant, voici quelques détails supplémentaires.
|
||||
|
||||
#### Chaîne avec `value.startswith()` { #string-with-value-startswith }
|
||||
|
||||
L'avez-vous remarqué ? une chaîne utilisant `value.startswith()` peut prendre un tuple, et elle vérifiera chaque valeur du tuple :
|
||||
Avez-vous remarqué ? Une chaîne utilisant `value.startswith()` peut prendre un tuple, et elle vérifiera chaque valeur du tuple :
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}
|
||||
|
||||
#### Un élément aléatoire { #a-random-item }
|
||||
|
||||
Avec `data.items()` nous obtenons un <abbr title="Quelque chose que l'on peut parcourir avec une boucle for, comme une liste, un set, etc.">objet itérable</abbr> avec des tuples contenant la clé et la valeur pour chaque élément du dictionnaire.
|
||||
Avec `data.items()` nous obtenons un <abbr title="Quelque chose que l’on peut itérer avec une boucle for, comme une liste, un set, etc.">objet itérable</abbr> avec des tuples contenant la clé et la valeur pour chaque élément du dictionnaire.
|
||||
|
||||
Nous convertissons cet objet itérable en une véritable `list` avec `list(data.items())`.
|
||||
Nous convertissons cet objet itérable en une `list` propre avec `list(data.items())`.
|
||||
|
||||
Ensuite, avec `random.choice()` nous pouvons obtenir une **valeur aléatoire** depuis la liste, donc nous obtenons un tuple `(id, name)`. Ce sera quelque chose comme («imdb-tt0371724», «The Hitchhiker's Guide to the Galaxy»).
|
||||
Ensuite, avec `random.choice()` nous pouvons obtenir une **valeur aléatoire** depuis la liste, nous obtenons donc un tuple `(id, name)`. Ce sera quelque chose comme `("imdb-tt0371724", "The Hitchhiker's Guide to the Galaxy")`.
|
||||
|
||||
Nous **affectons ensuite ces deux valeurs** du tuple aux variables `id` et `name`.
|
||||
Puis nous **affectons ces deux valeurs** du tuple aux variables `id` et `name`.
|
||||
|
||||
Ainsi, si l'utilisateur n'a pas fourni d'identifiant d'item, il recevra tout de même une suggestion aléatoire.
|
||||
Ainsi, si l’utilisateur n’a pas fourni d’ID d’item, il recevra quand même une suggestion aléatoire.
|
||||
|
||||
... nous faisons tout cela en **une seule ligne simple**. 🤯 N'adorez-vous pas Python ? 🐍
|
||||
... nous faisons tout cela en **une seule ligne simple**. 🤯 Vous n’adorez pas Python ? 🐍
|
||||
|
||||
{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}
|
||||
|
||||
## Récapitulatif { #recap }
|
||||
|
||||
Vous pouvez déclarer des validations supplémentaires et des métadonnées pour vos paramètres.
|
||||
Vous pouvez déclarer des validations et des métadonnées supplémentaires pour vos paramètres.
|
||||
|
||||
Validations et métadonnées génériques :
|
||||
Validations et métadonnées génériques :
|
||||
|
||||
* `alias`
|
||||
* `title`
|
||||
* `description`
|
||||
* `deprecated`
|
||||
- `alias`
|
||||
- `title`
|
||||
- `description`
|
||||
- `deprecated`
|
||||
|
||||
Validations spécifiques aux chaînes de caractères :
|
||||
Validations spécifiques aux chaînes :
|
||||
|
||||
* `min_length`
|
||||
* `max_length`
|
||||
* `pattern`
|
||||
- `min_length`
|
||||
- `max_length`
|
||||
- `pattern`
|
||||
|
||||
Validations personnalisées en utilisant `AfterValidator`.
|
||||
Validations personnalisées avec `AfterValidator`.
|
||||
|
||||
Dans ces exemples, vous avez vu comment déclarer des validations pour des valeurs de `str`.
|
||||
Dans ces exemples, vous avez vu comment déclarer des validations pour des valeurs `str`.
|
||||
|
||||
Voir les prochains chapitres pour apprendre à déclarer des validations pour d'autres types, comme les nombres.
|
||||
Voyez les prochains chapitres pour apprendre à déclarer des validations pour d’autres types, comme les nombres.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Paramètres de requête { #query-parameters }
|
||||
|
||||
Lorsque vous déclarez d'autres paramètres de fonction qui ne font pas partie des paramètres de chemin, ils sont automatiquement interprétés comme des paramètres de «requête».
|
||||
Quand vous déclarez d'autres paramètres de fonction qui ne font pas partie des paramètres de chemin, ils sont automatiquement interprétés comme des paramètres de « query ».
|
||||
|
||||
{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *}
|
||||
|
||||
La partie appelée requête (ou «query») dans une URL est l'ensemble des paires clé-valeur placées après le `?`, séparées par des `&`.
|
||||
La query est l'ensemble des paires clé-valeur placées après le `?` dans une URL, séparées par des caractères `&`.
|
||||
|
||||
Par exemple, dans l'URL :
|
||||
|
||||
@@ -17,22 +17,22 @@ http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
* `skip` : avec une valeur de `0`
|
||||
* `limit` : avec une valeur de `10`
|
||||
|
||||
Faisant partie de l'URL, ces valeurs sont des chaînes de caractères (`str`).
|
||||
Comme ils font partie de l'URL, ce sont « naturellement » des chaînes de caractères.
|
||||
|
||||
Mais quand on les déclare avec des types Python (dans l'exemple précédent, en tant qu'`int`), elles sont converties dans les types renseignés.
|
||||
Mais lorsque vous les déclarez avec des types Python (dans l'exemple ci-dessus, en tant que `int`), ils sont convertis vers ce type et validés par rapport à celui-ci.
|
||||
|
||||
Toutes les fonctionnalités qui s'appliquent aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
|
||||
Tous les mêmes processus qui s'appliquaient aux paramètres de chemin s'appliquent aussi aux paramètres de requête :
|
||||
|
||||
* Prise en charge par l'éditeur (évidemment)
|
||||
* <abbr title="conversion de la chaîne de caractères venant de la requête HTTP en données Python">«parsing»</abbr> des données
|
||||
* Prise en charge de l'éditeur (évidemment)
|
||||
* <abbr title="conversion de la chaîne provenant d'une requête HTTP en données Python">« parsing »</abbr> des données
|
||||
* Validation des données
|
||||
* Documentation automatique
|
||||
|
||||
## Valeurs par défaut { #defaults }
|
||||
|
||||
Les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut.
|
||||
Comme les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut.
|
||||
|
||||
Dans l'exemple ci-dessus, ils ont des valeurs par défaut qui sont `skip=0` et `limit=10`.
|
||||
Dans l'exemple ci-dessus, ils ont des valeurs par défaut `skip=0` et `limit=10`.
|
||||
|
||||
Donc, accéder à l'URL :
|
||||
|
||||
@@ -40,34 +40,34 @@ Donc, accéder à l'URL :
|
||||
http://127.0.0.1:8000/items/
|
||||
```
|
||||
|
||||
serait équivalent à accéder à l'URL :
|
||||
serait équivalent à accéder à :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=0&limit=10
|
||||
```
|
||||
|
||||
Mais si vous accédez à, par exemple :
|
||||
Mais si vous accédez, par exemple, à :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/?skip=20
|
||||
```
|
||||
|
||||
Les valeurs des paramètres de votre fonction seront :
|
||||
Les valeurs des paramètres dans votre fonction seront :
|
||||
|
||||
* `skip=20` : car c'est la valeur déclarée dans l'URL.
|
||||
* `limit=10` : car `limit` n'a pas été déclaré dans l'URL, et que la valeur par défaut était `10`.
|
||||
* `skip=20` : car vous l'avez défini dans l'URL
|
||||
* `limit=10` : car c'était la valeur par défaut
|
||||
|
||||
## Paramètres optionnels { #optional-parameters }
|
||||
|
||||
De la même façon, vous pouvez définir des paramètres de requête comme optionnels, en leur donnant comme valeur par défaut `None` :
|
||||
De la même façon, vous pouvez déclarer des paramètres de requête optionnels, en définissant leur valeur par défaut à `None` :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}
|
||||
|
||||
Ici, le paramètre `q` sera optionnel, et aura `None` comme valeur par défaut.
|
||||
Dans ce cas, le paramètre de fonction `q` sera optionnel et vaudra `None` par défaut.
|
||||
|
||||
/// check | vérifier
|
||||
/// check | Vérifications
|
||||
|
||||
On peut voir que **FastAPI** est capable de détecter que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` n'en est pas un, c'est donc un paramètre de requête.
|
||||
Notez également que FastAPI est suffisamment intelligent pour remarquer que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` ne l'est pas, c'est donc un paramètre de requête.
|
||||
|
||||
///
|
||||
|
||||
@@ -77,7 +77,7 @@ Vous pouvez aussi déclarer des types `bool`, ils seront convertis :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}
|
||||
|
||||
Avec ce code, en allant sur :
|
||||
Dans ce cas, si vous allez sur :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo?short=1
|
||||
@@ -107,37 +107,37 @@ ou
|
||||
http://127.0.0.1:8000/items/foo?short=yes
|
||||
```
|
||||
|
||||
ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction considérera le paramètre `short` comme ayant une valeur booléenne à `True`. Sinon la valeur sera à `False`.
|
||||
ou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction verra le paramètre `short` avec une valeur `bool` à `True`. Sinon la valeur sera à `False`.
|
||||
|
||||
## Multiples paramètres de chemin et de requête { #multiple-path-and-query-parameters }
|
||||
|
||||
Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête dans la même fonction, **FastAPI** saura comment les gérer.
|
||||
Vous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête en même temps, FastAPI sait lequel est lequel.
|
||||
|
||||
Et vous n'avez pas besoin de les déclarer dans un ordre spécifique.
|
||||
|
||||
Ils seront détectés par leurs noms :
|
||||
Ils seront détectés par leur nom :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}
|
||||
|
||||
## Paramètres de requête requis { #required-query-parameters }
|
||||
|
||||
Quand vous déclarez une valeur par défaut pour un paramètre qui n'est pas un paramètre de chemin (actuellement, nous n'avons vu que les paramètres de requête), alors ce paramètre n'est pas requis.
|
||||
Quand vous déclarez une valeur par défaut pour des paramètres qui ne sont pas des paramètres de chemin (pour l'instant, nous n'avons vu que les paramètres de requête), alors ils ne sont pas requis.
|
||||
|
||||
Si vous ne voulez pas leur donner de valeur par défaut mais juste les rendre optionnels, utilisez `None` comme valeur par défaut.
|
||||
Si vous ne voulez pas leur donner de valeur spécifique mais simplement les rendre optionnels, définissez la valeur par défaut à `None`.
|
||||
|
||||
Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez juste ne pas y affecter de valeur par défaut :
|
||||
Mais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez simplement ne déclarer aucune valeur par défaut :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *}
|
||||
|
||||
Ici le paramètre `needy` est un paramètre requis (ou obligatoire) de type `str`.
|
||||
Ici, le paramètre de requête `needy` est un paramètre de requête requis de type `str`.
|
||||
|
||||
Si vous ouvrez une URL comme :
|
||||
Si vous ouvrez dans votre navigateur une URL comme :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item
|
||||
```
|
||||
|
||||
... sans ajouter le paramètre requis `needy`, vous verrez une erreur semblable à :
|
||||
... sans ajouter le paramètre requis `needy`, vous verrez une erreur comme :
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -155,7 +155,7 @@ http://127.0.0.1:8000/items/foo-item
|
||||
}
|
||||
```
|
||||
|
||||
La présence de `needy` étant nécessaire, vous auriez besoin de l'insérer dans l'URL :
|
||||
Comme `needy` est un paramètre requis, vous devez le définir dans l'URL :
|
||||
|
||||
```
|
||||
http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
@@ -170,18 +170,18 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
}
|
||||
```
|
||||
|
||||
Et bien sûr, vous pouvez définir certains paramètres comme requis, certains avec des valeurs par défaut et certains entièrement optionnels :
|
||||
Et bien sûr, vous pouvez définir certains paramètres comme requis, certains avec une valeur par défaut et certains entièrement optionnels :
|
||||
|
||||
{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}
|
||||
|
||||
Dans ce cas, on a 3 paramètres de requête :
|
||||
Dans ce cas, il y a 3 paramètres de requête :
|
||||
|
||||
* `needy`, requis et de type `str`.
|
||||
* `skip`, un `int` avec comme valeur par défaut `0`.
|
||||
* `needy`, un `str` requis.
|
||||
* `skip`, un `int` avec une valeur par défaut de `0`.
|
||||
* `limit`, un `int` optionnel.
|
||||
|
||||
/// tip | Astuce
|
||||
|
||||
Vous pouvez utiliser les `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#predefined-values){.internal-link target=_blank}.
|
||||
Vous pourriez aussi utiliser des `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#predefined-values){.internal-link target=_blank}.
|
||||
|
||||
///
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
# 追加のステータスコード
|
||||
# 追加のステータスコード { #additional-status-codes }
|
||||
|
||||
デフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返します。その `JSONResponse` の中には、 *path operation* が返した内容が入ります。
|
||||
デフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返し、*path operation* から返した内容をその `JSONResponse` の中に入れます。
|
||||
|
||||
それは、デフォルトのステータスコードか、 *path operation* でセットしたものを利用します。
|
||||
デフォルトのステータスコード、または *path operation* で設定したステータスコードが使用されます。
|
||||
|
||||
## 追加のステータスコード
|
||||
## 追加のステータスコード { #additional-status-codes_1 }
|
||||
|
||||
メインのステータスコードとは別に、他のステータスコードを返したい場合は、`Response` (`JSONResponse` など) に追加のステータスコードを設定して直接返します。
|
||||
メインのステータスコードとは別に追加のステータスコードを返したい場合は、`JSONResponse` のような `Response` を直接返し、追加のステータスコードを直接設定できます。
|
||||
|
||||
例えば、itemを更新し、成功した場合は200 "OK"のHTTPステータスコードを返す *path operation* を作りたいとします。
|
||||
たとえば、item を更新でき、成功時に HTTP ステータスコード 200 "OK" を返す *path operation* を作りたいとします。
|
||||
|
||||
しかし、新しいitemも許可したいです。itemが存在しない場合は、それらを作成して201 "Created"を返します。
|
||||
しかし、新しい item も受け付けたいとします。そして、item が以前存在しなかった場合には作成し、HTTP ステータスコード 201「Created」を返します。
|
||||
|
||||
これを達成するには、 `JSONResponse` をインポートし、 `status_code` を設定して直接内容を返します。
|
||||
これを実現するには、`JSONResponse` をインポートし、望む `status_code` を設定して、そこで内容を直接返します。
|
||||
|
||||
{* ../../docs_src/additional_status_codes/tutorial001.py hl[4,25] *}
|
||||
{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
上記の例のように `Response` を明示的に返す場合、それは直接返されます。
|
||||
上の例のように `Response` を直接返すと、それはそのまま返されます。
|
||||
|
||||
モデルなどはシリアライズされません。
|
||||
モデルなどによってシリアライズされません。
|
||||
|
||||
必要なデータが含まれていることや、値が有効なJSONであること (`JSONResponse` を使う場合) を確認してください。
|
||||
必要なデータが含まれていること、そして(`JSONResponse` を使用している場合)値が有効な JSON であることを確認してください。
|
||||
|
||||
///
|
||||
|
||||
/// note | 技術詳細
|
||||
|
||||
`from starlette.responses import JSONResponse` を利用することもできます。
|
||||
`from starlette.responses import JSONResponse` を使うこともできます。
|
||||
|
||||
**FastAPI** は `fastapi.responses` と同じ `starlette.responses` を、開発者の利便性のために提供しています。しかし有効なレスポンスはほとんどStarletteから来ています。 `status` についても同じです。
|
||||
**FastAPI** は開発者の利便性のために、`fastapi.responses` と同じ `starlette.responses` を提供しています。しかし、利用可能なレスポンスのほとんどは Starlette から直接提供されています。`status` も同様です。
|
||||
|
||||
///
|
||||
|
||||
## OpenAPIとAPIドキュメント
|
||||
## OpenAPI と API ドキュメント { #openapi-and-api-docs }
|
||||
|
||||
ステータスコードとレスポンスを直接返す場合、それらはOpenAPIスキーマ (APIドキュメント) には含まれません。なぜなら、FastAPIは何が返されるのか事前に知ることができないからです。
|
||||
追加のステータスコードとレスポンスを直接返す場合、それらは OpenAPI スキーマ(API ドキュメント)には含まれません。FastAPI には、事前に何が返されるかを知る方法がないからです。
|
||||
|
||||
しかし、 [Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコードの中にドキュメントを書くことができます。
|
||||
しかし、[Additional Responses](additional-responses.md){.internal-link target=_blank} を使ってコード内にドキュメント化できます。
|
||||
|
||||
@@ -1,34 +1,40 @@
|
||||
# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス
|
||||
# カスタムレスポンス - HTML、ストリーム、ファイル、その他のレスポンス { #custom-response-html-stream-file-others }
|
||||
|
||||
デフォルトでは、**FastAPI** は `JSONResponse` を使ってレスポンスを返します。
|
||||
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、 `Response` を直接返すことでこの挙動をオーバーライドできます。
|
||||
|
||||
しかし、`Response` を直接返すと、データは自動的に変換されず、ドキュメントも自動生成されません (例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど) 。
|
||||
しかし、`Response` を直接返すと(または `JSONResponse` のような任意のサブクラスを返すと)、データは自動的に変換されず(`response_model` を宣言していても)、ドキュメントも自動生成されません(例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど)。
|
||||
|
||||
しかし、*path operationデコレータ* に、使いたい `Response` を宣言することもできます。
|
||||
`response_class` パラメータを使用して、*path operation デコレータ* で使用したい `Response`(任意の `Response` サブクラス)を宣言することもできます。
|
||||
|
||||
*path operation関数* から返されるコンテンツは、その `Response` に含まれます。
|
||||
*path operation 関数* から返されるコンテンツは、その `Response` に含まれます。
|
||||
|
||||
そしてもし、`Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ (`application/json`) ならば、データは *path operationデコレータ* に宣言したPydantic `response_model` により自動的に変換 (もしくはフィルタ) されます。
|
||||
そしてその `Response` が、`JSONResponse` や `UJSONResponse` の場合のようにJSONメディアタイプ(`application/json`)なら、関数の返り値は *path operationデコレータ* に宣言した任意のPydantic `response_model` により自動的に変換(およびフィルタ)されます。
|
||||
|
||||
/// note | 備考
|
||||
|
||||
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIは何もコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。
|
||||
メディアタイプを指定せずにレスポンスクラスを利用すると、FastAPIはレスポンスにコンテンツがないことを期待します。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットが記載されません。
|
||||
|
||||
///
|
||||
|
||||
## `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` クラス (サブクラス) をインポートし、 *path operationデコレータ* に宣言します。
|
||||
使いたい `Response` クラス(サブクラス)をインポートし、*path operationデコレータ* に宣言します。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *}
|
||||
大きなレスポンスの場合、`Response` を直接返すほうが、辞書を返すよりもはるかに高速です。
|
||||
|
||||
これは、デフォルトではFastAPIがチュートリアルで説明した同じ[JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}を使って、内部の各アイテムを検査し、JSONとしてシリアライズ可能であることを確認するためです。これにより、例えばデータベースモデルのような**任意のオブジェクト**を返せます。
|
||||
|
||||
しかし、返そうとしているコンテンツが **JSONでシリアライズ可能**であることが確実なら、それを直接レスポンスクラスに渡して、FastAPIがレスポンスクラスへ渡す前に返却コンテンツを `jsonable_encoder` に通すことで発生する追加のオーバーヘッドを回避できます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用することもできます。
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利用されます。
|
||||
|
||||
この場合、HTTPヘッダー `Content-Type` には `application/json` がセットされます。
|
||||
|
||||
@@ -38,70 +44,70 @@
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
`ORJSONResponse` は、現在はFastAPIのみで利用可能で、Starletteでは利用できません。
|
||||
`ORJSONResponse` はFastAPIでのみ利用可能で、Starletteでは利用できません。
|
||||
|
||||
///
|
||||
|
||||
## HTMLレスポンス
|
||||
## HTMLレスポンス { #html-response }
|
||||
|
||||
**FastAPI** からHTMLを直接返す場合は、`HTMLResponse` を使います。
|
||||
|
||||
* `HTMLResponse` をインポートする。
|
||||
* *path operation* のパラメータ `content_type` に `HTMLResponse` を渡す。
|
||||
* *path operation デコレータ* のパラメータ `response_class` に `HTMLResponse` を渡す。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *}
|
||||
{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *}
|
||||
|
||||
/// info | 情報
|
||||
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するために利用されます。
|
||||
パラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも利用されます。
|
||||
|
||||
この場合、HTTPヘッダー `Content-Type` には `text/html` がセットされます。
|
||||
|
||||
そして、OpenAPIにはそのようにドキュメント化されます。
|
||||
そして、OpenAPIにはそのようにドキュメントされます。
|
||||
|
||||
///
|
||||
|
||||
### `Response` を返す
|
||||
### `Response` を返す { #return-a-response }
|
||||
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、レスポンスを直接返すことで、*path operation* の中でレスポンスをオーバーライドできます。
|
||||
[レスポンスを直接返す](response-directly.md){.internal-link target=_blank}で見たように、レスポンスを返すことで、*path operation* の中でレスポンスを直接オーバーライドすることもできます。
|
||||
|
||||
上記と同じ例において、 `HTMLResponse` を返すと、このようになります:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *}
|
||||
{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *}
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず (例えば、 `Content-Type` がドキュメントされない) 、自動的な対話的ドキュメントからも閲覧できません。
|
||||
*path operation関数* から直接返される `Response` は、OpenAPIにドキュメントされず(例えば、`Content-Type` がドキュメントされない)、自動的な対話的ドキュメントでも表示されません。
|
||||
|
||||
///
|
||||
|
||||
/// info | 情報
|
||||
|
||||
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返された `Response` オブジェクトに由来しています。
|
||||
もちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返された `Response` オブジェクトに由来します。
|
||||
|
||||
///
|
||||
|
||||
### OpenAPIドキュメントと `Response` のオーバーライド
|
||||
### OpenAPIドキュメントと `Response` のオーバーライド { #document-in-openapi-and-override-response }
|
||||
|
||||
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、 `response_class` パラメータを使い、 `Response` オブジェクトを返します。
|
||||
関数の中でレスポンスをオーバーライドしつつも、OpenAPI に「メディアタイプ」をドキュメント化したいなら、`response_class` パラメータを使用し、かつ `Response` オブジェクトを返します。
|
||||
|
||||
`response_class` はOpenAPIの *path operation* ドキュメントにのみ使用されますが、 `Response` はそのまま使用されます。
|
||||
`response_class` はOpenAPIの*path operation*のドキュメント化のためにのみ使用され、`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()` は、`str` のHTMLを返すのではなく `Response` を生成して返しています。
|
||||
この例では、関数 `generate_html_response()` は、`str` のHTMLを返すのではなく、`Response` を生成して返しています。
|
||||
|
||||
`generate_html_response()` を呼び出した結果を返すことにより、**FastAPI** の振る舞いを上書きする `Response` が既に返されています。
|
||||
`generate_html_response()` を呼び出した結果を返すことにより、デフォルトの **FastAPI** の挙動をオーバーライドする `Response` をすでに返しています。
|
||||
|
||||
しかし、一方では `response_class` に `HTMLResponse` を渡しているため、 **FastAPI** はOpenAPIや対話的ドキュメントでHTMLとして `text/html` でドキュメント化する方法を知っています。
|
||||
しかし、`response_class` にも `HTMLResponse` を渡しているため、**FastAPI** はOpenAPIと対話的ドキュメントで、`text/html` のHTMLとしてどのようにドキュメント化すればよいかを理解できます:
|
||||
|
||||
<img src="/img/tutorial/custom-response/image01.png">
|
||||
|
||||
## 利用可能なレスポンス
|
||||
## 利用可能なレスポンス { #available-responses }
|
||||
|
||||
以下が利用可能なレスポンスの一部です。
|
||||
|
||||
@@ -111,11 +117,11 @@
|
||||
|
||||
`from starlette.responses import HTMLResponse` も利用できます。
|
||||
|
||||
**FastAPI** は開発者の利便性のために `fastapi.responses` として `starlette.responses` と同じものを提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。
|
||||
**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。
|
||||
|
||||
///
|
||||
|
||||
### `Response`
|
||||
### `Response` { #response }
|
||||
|
||||
メインの `Response` クラスで、他の全てのレスポンスはこれを継承しています。
|
||||
|
||||
@@ -128,41 +134,53 @@
|
||||
* `headers` - 文字列の `dict` 。
|
||||
* `media_type` - メディアタイプを示す `str` 。例えば `"text/html"` 。
|
||||
|
||||
FastAPI (実際にはStarlette) は自動的にContent-Lengthヘッダーを含みます。また、media_typeに基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
|
||||
FastAPI(実際にはStarlette)は自動的にContent-Lengthヘッダーを含みます。また、`media_type` に基づいたContent-Typeヘッダーを含み、テキストタイプのためにcharsetを追加します。
|
||||
|
||||
{* ../../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` としてエンコードされたレスポンスを返します。
|
||||
データを受け取り、`application/json` としてエンコードされたレスポンスを返します。
|
||||
|
||||
上で読んだように、**FastAPI** のデフォルトのレスポンスとして利用されます。
|
||||
|
||||
### `ORJSONResponse`
|
||||
### `ORJSONResponse` { #orjsonresponse }
|
||||
|
||||
上で読んだように、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>を使った、高速な代替のJSONレスポンスです。
|
||||
|
||||
### `UJSONResponse`
|
||||
/// info | 情報
|
||||
|
||||
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>を使った、代替のJSONレスポンスです。
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装よりも作りこまれていません。
|
||||
これは、例えば `pip install orjson` で `orjson` をインストールする必要があります。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *}
|
||||
### `UJSONResponse` { #ujsonresponse }
|
||||
|
||||
<a href="https://github.com/ultrajson/ultrajson" class="external-link" target="_blank">`ujson`</a>を使った、代替のJSONレスポンスです。
|
||||
|
||||
/// info | 情報
|
||||
|
||||
これは、例えば `pip install ujson` で `ujson` をインストールする必要があります。
|
||||
|
||||
///
|
||||
|
||||
/// warning | 注意
|
||||
|
||||
`ujson` は、いくつかのエッジケースの取り扱いについて、Pythonにビルトインされた実装ほど注意深くありません。
|
||||
|
||||
///
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
@@ -170,33 +188,61 @@ FastAPI (実際にはStarlette) は自動的にContent-Lengthヘッダーを含
|
||||
|
||||
///
|
||||
|
||||
### `RedirectResponse`
|
||||
### `RedirectResponse` { #redirectresponse }
|
||||
|
||||
HTTPリダイレクトを返します。デフォルトでは307ステータスコード (Temporary Redirect) となります。
|
||||
HTTPリダイレクトを返します。デフォルトでは307ステータスコード(Temporary Redirect)となります。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *}
|
||||
`RedirectResponse` を直接返せます:
|
||||
|
||||
### `StreamingResponse`
|
||||
{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *}
|
||||
|
||||
非同期なジェネレータか通常のジェネレータ・イテレータを受け取り、レスポンスボディをストリームします。
|
||||
---
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *}
|
||||
または、`response_class` パラメータで使用できます:
|
||||
|
||||
#### `StreamingResponse` をファイルライクなオブジェクトとともに使う
|
||||
{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *}
|
||||
|
||||
ファイルライクなオブジェクト (例えば、 `open()` で返されたオブジェクト) がある場合、 `StreamingResponse` に含めて返すことができます。
|
||||
その場合、*path operation*関数からURLを直接返せます。
|
||||
|
||||
これにはクラウドストレージとの連携や映像処理など、多くのライブラリが含まれています。
|
||||
この場合に使用される `status_code` は `RedirectResponse` のデフォルトである `307` になります。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *}
|
||||
---
|
||||
|
||||
また、`status_code` パラメータを `response_class` パラメータと組み合わせて使うこともできます:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *}
|
||||
|
||||
### `StreamingResponse` { #streamingresponse }
|
||||
|
||||
非同期ジェネレータ、または通常のジェネレータ/イテレータを受け取り、レスポンスボディをストリームします。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *}
|
||||
|
||||
#### ファイルライクオブジェクトで `StreamingResponse` を使う { #using-streamingresponse-with-file-like-objects }
|
||||
|
||||
<a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> オブジェクト(例: `open()` で返されるオブジェクト)がある場合、そのfile-likeオブジェクトを反復処理するジェネレータ関数を作れます。
|
||||
|
||||
そうすれば、最初にすべてをメモリへ読み込む必要はなく、そのジェネレータ関数を `StreamingResponse` に渡して返せます。
|
||||
|
||||
これにはクラウドストレージとの連携、映像処理など、多くのライブラリが含まれます。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *}
|
||||
|
||||
1. これはジェネレータ関数です。内部に `yield` 文を含むため「ジェネレータ関数」です。
|
||||
2. `with` ブロックを使うことで、ジェネレータ関数が終わった後(つまりレスポンスの送信が完了した後)にfile-likeオブジェクトが確実にクローズされるようにします。
|
||||
3. この `yield from` は、`file_like` という名前のものを反復処理するように関数へ指示します。そして反復された各パートについて、そのパートをこのジェネレータ関数(`iterfile`)から来たものとして `yield` します。
|
||||
|
||||
つまり、内部的に「生成」の作業を別のものへ移譲するジェネレータ関数です。
|
||||
|
||||
このようにすることで `with` ブロックに入れられ、完了後にfile-likeオブジェクトが確実にクローズされます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
ここでは `async` や `await` をサポートしていない標準の `open()` を使っているので、通常の `def` でpath operationを宣言していることに注意してください。
|
||||
ここでは `async` と `await` をサポートしていない標準の `open()` を使っているため、通常の `def` でpath operationを宣言している点に注意してください。
|
||||
|
||||
///
|
||||
|
||||
### `FileResponse`
|
||||
### `FileResponse` { #fileresponse }
|
||||
|
||||
レスポンスとしてファイルを非同期的にストリームします。
|
||||
|
||||
@@ -204,29 +250,63 @@ HTTPリダイレクトを返します。デフォルトでは307ステータス
|
||||
|
||||
* `path` - ストリームするファイルのファイルパス。
|
||||
* `headers` - 含めたい任意のカスタムヘッダーの辞書。
|
||||
* `media_type` - メディアタイプを示す文字列。セットされなかった場合は、ファイル名やパスからメディアタイプが推察されます。
|
||||
* `filename` - セットされた場合、レスポンスの `Content-Disposition` に含まれます。
|
||||
* `media_type` - メディアタイプを示す文字列。未設定の場合、ファイル名やパスからメディアタイプが推測されます。
|
||||
* `filename` - 設定した場合、レスポンスの `Content-Disposition` に含まれます。
|
||||
|
||||
ファイルレスポンスには、適切な `Content-Length` 、 `Last-Modified` 、 `ETag` ヘッダーが含まれます。
|
||||
ファイルレスポンスには、適切な `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` パラメータを使うこともできます:
|
||||
|
||||
**FastAPI** クラスのインスタンスか `APIRouter` を生成するときに、デフォルトのレスポンスクラスを指定できます。
|
||||
{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *}
|
||||
|
||||
定義するためのパラメータは、 `default_response_class` です。
|
||||
この場合、*path operation*関数からファイルパスを直接返せます。
|
||||
|
||||
以下の例では、 **FastAPI** は、全ての *path operation* で `JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして利用します。
|
||||
## カスタムレスポンスクラス { #custom-response-class }
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *}
|
||||
`Response` を継承した独自のカスタムレスポンスクラスを作成して利用できます。
|
||||
|
||||
例えば、<a href="https://github.com/ijl/orjson" class="external-link" target="_blank">`orjson`</a>を使いたいが、同梱の `ORJSONResponse` クラスで使われていないカスタム設定も使いたいとします。
|
||||
|
||||
例えば、インデントされ整形されたJSONを返したいので、orjsonオプション `orjson.OPT_INDENT_2` を使いたいとします。
|
||||
|
||||
`CustomORJSONResponse` を作れます。主に必要なのは、コンテンツを `bytes` として返す `Response.render(content)` メソッドを作ることです:
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *}
|
||||
|
||||
これまでは次のように返していたものが:
|
||||
|
||||
```json
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
...このレスポンスでは次のように返されます:
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Hello World"
|
||||
}
|
||||
```
|
||||
|
||||
もちろん、JSONの整形よりも、これを活用するもっと良い方法が見つかるはずです。 😉
|
||||
|
||||
## デフォルトレスポンスクラス { #default-response-class }
|
||||
|
||||
**FastAPI** クラスのインスタンス、または `APIRouter` を作成する際に、デフォルトで使用するレスポンスクラスを指定できます。
|
||||
|
||||
これを定義するパラメータは `default_response_class` です。
|
||||
|
||||
以下の例では、**FastAPI** はすべての*path operation*で、`JSONResponse` の代わりに `ORJSONResponse` をデフォルトとして使います。
|
||||
|
||||
{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *}
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
前に見たように、 *path operation* の中で `response_class` をオーバーライドできます。
|
||||
これまでと同様に、*path operation*で `response_class` をオーバーライドできます。
|
||||
|
||||
///
|
||||
|
||||
## その他のドキュメント
|
||||
## その他のドキュメント { #additional-documentation }
|
||||
|
||||
また、OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}
|
||||
OpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}。
|
||||
|
||||
@@ -1,27 +1,21 @@
|
||||
# 高度なユーザーガイド
|
||||
# 高度なユーザーガイド { #advanced-user-guide }
|
||||
|
||||
## さらなる機能
|
||||
## さらなる機能 { #additional-features }
|
||||
|
||||
[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}により、**FastAPI**の主要な機能は十分に理解できたことでしょう。
|
||||
メインの[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}だけで、**FastAPI**の主要な機能を一通り把握するには十分なはずです。
|
||||
|
||||
以降のセクションでは、チュートリアルでは説明しきれなかったオプションや設定、および機能について説明します。
|
||||
以降のセクションでは、その他のオプション、設定、追加機能を見ていきます。
|
||||
|
||||
/// tip | 豆知識
|
||||
|
||||
以降のセクションは、 **必ずしも"応用編"ではありません**。
|
||||
以降のセクションは、**必ずしも「高度」ではありません**。
|
||||
|
||||
ユースケースによっては、その中から解決策を見つけられるかもしれません。
|
||||
また、あなたのユースケースに対する解決策が、その中のどれかにある可能性もあります。
|
||||
|
||||
///
|
||||
|
||||
## 先にチュートリアルを読む
|
||||
## 先にチュートリアルを読む { #read-the-tutorial-first }
|
||||
|
||||
[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}の知識があれば、**FastAPI**の主要な機能を利用することができます。
|
||||
メインの[チュートリアル - ユーザーガイド](../tutorial/index.md){.internal-link target=_blank}で得た知識があれば、**FastAPI**の機能の多くは引き続き利用できます。
|
||||
|
||||
以降のセクションは、すでにチュートリアルを読んで、その主要なアイデアを理解できていることを前提としています。
|
||||
|
||||
## テスト駆動開発のコース
|
||||
|
||||
このセクションの内容を補完するために脱初心者用コースを受けたい場合は、**TestDriven.io**による、<a href="https://testdriven.io/courses/tdd-fastapi/" class="external-link" target="_blank">Test-Driven Development with FastAPI and Docker</a>を確認するのがよいかもしれません。
|
||||
|
||||
現在、このコースで得られた利益の10%が**FastAPI**の開発のために寄付されています。🎉 😄
|
||||
また、以降のセクションでは、すでにそれを読んでいて、主要な考え方を理解していることを前提としています。
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user