diff --git a/.github/actions/comment-docs-preview-in-pr/Dockerfile b/.github/actions/comment-docs-preview-in-pr/Dockerfile index 4f20c5f10..14b0d0269 100644 --- a/.github/actions/comment-docs-preview-in-pr/Dockerfile +++ b/.github/actions/comment-docs-preview-in-pr/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7 +FROM python:3.9 RUN pip install httpx "pydantic==1.5.1" pygithub diff --git a/.github/actions/notify-translations/Dockerfile b/.github/actions/notify-translations/Dockerfile index fa4197e6a..b68b4bb1a 100644 --- a/.github/actions/notify-translations/Dockerfile +++ b/.github/actions/notify-translations/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7 +FROM python:3.9 RUN pip install httpx PyGithub "pydantic==1.5.1" "pyyaml>=5.3.1,<6.0.0" diff --git a/.github/actions/notify-translations/app/main.py b/.github/actions/notify-translations/app/main.py index 494fe6ad8..8ac1f233d 100644 --- a/.github/actions/notify-translations/app/main.py +++ b/.github/actions/notify-translations/app/main.py @@ -9,7 +9,7 @@ import httpx from github import Github from pydantic import BaseModel, BaseSettings, SecretStr -awaiting_label = "awaiting review" +awaiting_label = "awaiting-review" lang_all_label = "lang-all" approved_label = "approved-2" translations_path = Path(__file__).parent / "translations.yml" diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index dedf23fb9..51c069d9e 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -17,7 +17,7 @@ jobs: outputs: docs: ${{ steps.filter.outputs.docs }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # For pull requests it's not necessary to checkout the code but for master it is - uses: dorny/paths-filter@v2 id: filter @@ -28,6 +28,8 @@ jobs: - docs/** - docs_src/** - requirements-docs.txt + - .github/workflows/build-docs.yml + - .github/workflows/deploy-docs.yml langs: needs: - changes @@ -35,7 +37,7 @@ jobs: outputs: langs: ${{ steps.show-langs.outputs.langs }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -44,14 +46,19 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v06 + key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt', 'requirements-docs-tests.txt') }}-v06 - name: Install docs extras if: steps.cache.outputs.cache-hit != 'true' run: pip install -r requirements-docs.txt # Install MkDocs Material Insiders here just to put it in the cache for the rest of the steps - name: Install Material for MkDocs Insiders - if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true' - run: pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git + if: ( github.event_name != 'pull_request' || github.secret_source == 'Actions' ) && steps.cache.outputs.cache-hit != 'true' + run: | + pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git + pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/griffe-typing-deprecated.git + pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/mkdocstrings-python.git + - name: Verify README + run: python ./scripts/docs.py verify-readme - name: Export Language Codes id: show-langs run: | @@ -71,7 +78,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -80,13 +87,16 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt') }}-v06 + key: ${{ runner.os }}-python-docs-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml', 'requirements-docs.txt', 'requirements-docs-tests.txt') }}-v06 - name: Install docs extras if: steps.cache.outputs.cache-hit != 'true' run: pip install -r requirements-docs.txt - name: Install Material for MkDocs Insiders - if: ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false ) && steps.cache.outputs.cache-hit != 'true' - run: pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git + if: ( github.event_name != 'pull_request' || github.secret_source != 'Actions' ) && steps.cache.outputs.cache-hit != 'true' + run: | + pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/squidfunk/mkdocs-material-insiders.git + pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/griffe-typing-deprecated.git + pip install git+https://${{ secrets.FASTAPI_MKDOCS_MATERIAL_INSIDERS }}@github.com/pawamoy-insiders/mkdocstrings-python.git - name: Update Languages run: python ./scripts/docs.py update-languages - uses: actions/cache@v3 diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index dcd6d7107..155ebd0a8 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -14,14 +14,14 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Clean site run: | rm -rf ./site mkdir ./site - name: Download Artifact Docs id: download - uses: dawidd6/action-download-artifact@v2.27.0 + uses: dawidd6/action-download-artifact@v2.28.0 with: if_no_artifact_found: ignore github_token: ${{ secrets.FASTAPI_PREVIEW_DOCS_DOWNLOAD_ARTIFACTS }} diff --git a/.github/workflows/latest-changes.yml b/.github/workflows/latest-changes.yml index e38870f46..b9b550d5e 100644 --- a/.github/workflows/latest-changes.yml +++ b/.github/workflows/latest-changes.yml @@ -24,7 +24,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: # To allow latest-changes to commit to the main branch token: ${{ secrets.FASTAPI_LATEST_CHANGES }} @@ -34,9 +34,12 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} with: limit-access-to-actor: true - - uses: docker://tiangolo/latest-changes:0.0.3 + - uses: docker://tiangolo/latest-changes:0.2.0 + # - uses: tiangolo/latest-changes@main with: token: ${{ secrets.GITHUB_TOKEN }} latest_changes_file: docs/en/docs/release-notes.md - latest_changes_header: '## Latest Changes\n\n' + latest_changes_header: '## Latest Changes' + end_regex: '^## ' debug_logs: true + label_header_prefix: '### ' diff --git a/.github/workflows/notify-translations.yml b/.github/workflows/notify-translations.yml index 44ee83ec0..c0904ce48 100644 --- a/.github/workflows/notify-translations.yml +++ b/.github/workflows/notify-translations.yml @@ -23,7 +23,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Allow debugging with tmate - name: Setup tmate session uses: mxschmitt/action-tmate@v3 diff --git a/.github/workflows/people.yml b/.github/workflows/people.yml index 4480a1427..b0868771d 100644 --- a/.github/workflows/people.yml +++ b/.github/workflows/people.yml @@ -19,7 +19,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Ref: https://github.com/actions/runner/issues/2033 - name: Fix git safe.directory in container run: mkdir -p /home/runner/work/_temp/_github_home && printf "[safe]\n\tdirectory = /github/workspace" > /home/runner/work/_temp/_github_home/.gitconfig diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b84c5bf17..8cbd01b92 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,11 +13,11 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.7" + python-version: "3.10" # Issue ref: https://github.com/actions/setup-python/issues/436 # cache: "pip" cache-dependency-path: pyproject.toml @@ -32,7 +32,7 @@ jobs: - name: Build distribution run: python -m build - name: Publish - uses: pypa/gh-action-pypi-publish@v1.8.6 + uses: pypa/gh-action-pypi-publish@v1.8.10 with: password: ${{ secrets.PYPI_API_TOKEN }} - name: Dump GitHub context diff --git a/.github/workflows/smokeshow.yml b/.github/workflows/smokeshow.yml index 4e689d95c..38b44c413 100644 --- a/.github/workflows/smokeshow.yml +++ b/.github/workflows/smokeshow.yml @@ -24,7 +24,7 @@ jobs: - run: pip install smokeshow - - uses: dawidd6/action-download-artifact@v2.27.0 + - uses: dawidd6/action-download-artifact@v2.28.0 with: github_token: ${{ secrets.FASTAPI_SMOKESHOW_DOWNLOAD_ARTIFACTS }} workflow: test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a512a019..7ebb80efd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -29,7 +29,7 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v04 + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-pydantic-v2-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v07 - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' run: pip install -r requirements-tests.txt @@ -42,7 +42,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] pydantic-version: ["pydantic-v1", "pydantic-v2"] fail-fast: false steps: @@ -50,7 +50,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: @@ -62,7 +62,7 @@ jobs: id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt') }}-test-v04 + key: ${{ runner.os }}-python-${{ env.pythonLocation }}-${{ matrix.pydantic-version }}-${{ hashFiles('pyproject.toml', 'requirements-tests.txt', 'requirements-docs-tests.txt') }}-test-v07 - name: Install Dependencies if: steps.cache.outputs.cache-hit != 'true' run: pip install -r requirements-tests.txt @@ -92,7 +92,7 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: '3.8' diff --git a/.gitignore b/.gitignore index d380d16b7..9be494cec 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ archive.zip *~ .*.sw? .cache + +# macOS +.DS_Store diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f7085f72..a7f2fb3f2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,23 +13,13 @@ repos: - --unsafe - id: end-of-file-fixer - id: trailing-whitespace -- repo: https://github.com/asottile/pyupgrade - rev: v3.7.0 - hooks: - - id: pyupgrade - args: - - --py3-plus - - --keep-runtime-typing - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.0.275 + rev: v0.1.2 hooks: - id: ruff args: - --fix -- repo: https://github.com/psf/black - rev: 23.3.0 - hooks: - - id: black + - id: ruff-format ci: autofix_commit_msg: ๐ŸŽจ [pre-commit.ci] Auto format from pre-commit.com hooks autoupdate_commit_msg: โฌ† [pre-commit.ci] pre-commit autoupdate diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000..9028248b1 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,24 @@ +# This CITATION.cff file was generated with cffinit. +# Visit https://bit.ly/cffinit to generate yours today! + +cff-version: 1.2.0 +title: FastAPI +message: >- + If you use this software, please cite it using the + metadata from this file. +type: software +authors: + - given-names: Sebastiรกn + family-names: Ramรญrez + email: tiangolo@gmail.com +identifiers: +repository-code: 'https://github.com/tiangolo/fastapi' +url: 'https://fastapi.tiangolo.com' +abstract: >- + FastAPI framework, high performance, easy to learn, fast to code, + ready for production +keywords: + - fastapi + - pydantic + - starlette +license: MIT diff --git a/README.md b/README.md index 50f80ded6..2df5cba0b 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ --- -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.8+ based on standard Python type hints. The key features are: @@ -48,14 +48,20 @@ The key features are: - + + + + + - + + + @@ -117,7 +123,7 @@ If you are building a CLI app to be ## Requirements -Python 3.7+ +Python 3.8+ FastAPI stands on the shoulders of giants: @@ -333,7 +339,7 @@ You do that with standard modern Python types. You don't have to learn a new syntax, the methods or classes of a specific library, etc. -Just standard **Python 3.7+**. +Just standard **Python 3.8+**. For example, for an `int`: diff --git a/docs/de/docs/features.md b/docs/de/docs/features.md index f281afd1e..64fa8092d 100644 --- a/docs/de/docs/features.md +++ b/docs/de/docs/features.md @@ -25,7 +25,7 @@ Mit einer interaktiven API-Dokumentation und explorativen webbasierten Benutzers ### Nur modernes Python -Alles basiert auf **Python 3.6 Typ**-Deklarationen (dank Pydantic). Es muss keine neue Syntax gelernt werden, nur standardisiertes modernes Python. +Alles basiert auf **Python 3.8 Typ**-Deklarationen (dank Pydantic). Es muss keine neue Syntax gelernt werden, nur standardisiertes modernes Python. diff --git a/docs/em/docs/advanced/extending-openapi.md b/docs/em/docs/advanced/extending-openapi.md deleted file mode 100644 index 496a8d9de..000000000 --- a/docs/em/docs/advanced/extending-openapi.md +++ /dev/null @@ -1,314 +0,0 @@ -# โ†” ๐Ÿ—„ - -!!! warning - ๐Ÿ‘‰ ๐Ÿ‘ ๐Ÿง โš’. ๐Ÿ‘† ๐ŸŽฒ ๐Ÿ’ช ๐Ÿšถ โšซ๏ธ. - - ๐Ÿšฅ ๐Ÿ‘† ๐Ÿ“„ ๐Ÿ”ฐ - ๐Ÿ‘ฉโ€๐Ÿ’ป ๐Ÿฆฎ, ๐Ÿ‘† ๐Ÿ’ช ๐ŸŽฒ ๐Ÿšถ ๐Ÿ‘‰ ๐Ÿ“„. - - ๐Ÿšฅ ๐Ÿ‘† โช ๐Ÿ’ญ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ”€ ๐Ÿ— ๐Ÿ—„ ๐Ÿ”—, ๐Ÿ˜ฃ ๐Ÿ‘‚. - -๐Ÿ“ค ๐Ÿ’ผ ๐ŸŒโ” ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ’ช ๐Ÿ”€ ๐Ÿ— ๐Ÿ—„ ๐Ÿ”—. - -๐Ÿ‘‰ ๐Ÿ“„ ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ โ”. - -## ๐Ÿ˜ ๐Ÿ› ๏ธ - -๐Ÿ˜ (๐Ÿ”ข) ๐Ÿ› ๏ธ, โฉ. - -`FastAPI` ๐Ÿˆธ (๐Ÿ‘) โœ”๏ธ `.openapi()` ๐Ÿ‘ฉโ€๐Ÿ”ฌ ๐Ÿ‘ˆ ๐Ÿ“ˆ ๐Ÿ“จ ๐Ÿ—„ ๐Ÿ”—. - -๐Ÿ• ๐Ÿˆธ ๐ŸŽš ๐Ÿ—, *โžก ๐Ÿ› ๏ธ* `/openapi.json` (โš–๏ธ โšซ๏ธโ” ๐Ÿ‘† โš’ ๐Ÿ‘† `openapi_url`) ยฎ. - -โšซ๏ธ ๐Ÿ“จ ๐ŸŽป ๐Ÿ“จ โฎ๏ธ ๐Ÿ ๐Ÿˆธ `.openapi()` ๐Ÿ‘ฉโ€๐Ÿ”ฌ. - -๐Ÿ”ข, โšซ๏ธโ” ๐Ÿ‘ฉโ€๐Ÿ”ฌ `.openapi()` ๐Ÿ”จ โœ… ๐Ÿ  `.openapi_schema` ๐Ÿ‘€ ๐Ÿšฅ โšซ๏ธ โœ”๏ธ ๐ŸŽš & ๐Ÿ“จ ๐Ÿ‘ซ. - -๐Ÿšฅ โšซ๏ธ ๐Ÿšซ, โšซ๏ธ ๐Ÿ— ๐Ÿ‘ซ โš™๏ธ ๐Ÿš™ ๐Ÿ”ข `fastapi.openapi.utils.get_openapi`. - -& ๐Ÿ‘ˆ ๐Ÿ”ข `get_openapi()` ๐Ÿ“จ ๐Ÿ”ข: - -* `title`: ๐Ÿ—„ ๐Ÿ“›, ๐ŸŽฆ ๐Ÿฉบ. -* `version`: โฌ ๐Ÿ‘† ๐Ÿ› ๏ธ, โœ… `2.5.0`. -* `openapi_version`: โฌ ๐Ÿ—„ ๐Ÿ”ง โš™๏ธ. ๐Ÿ”ข, โช: `3.0.2`. -* `description`: ๐Ÿ“› ๐Ÿ‘† ๐Ÿ› ๏ธ. -* `routes`: ๐Ÿ“‡ ๐Ÿ›ฃ, ๐Ÿ‘ซ ๐Ÿ”  ยฎ *โžก ๐Ÿ› ๏ธ*. ๐Ÿ‘ซ โœŠ โšช๏ธโžก๏ธ `app.routes`. - -## ๐Ÿ”‘ ๐Ÿ”ข - -โš™๏ธ โ„น ๐Ÿ”›, ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐ŸŽ ๐Ÿš™ ๐Ÿ”ข ๐Ÿ— ๐Ÿ—„ ๐Ÿ”— & ๐Ÿ” ๐Ÿ”  ๐Ÿ• ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ’ช. - -๐Ÿ–ผ, โžก๏ธ ๐Ÿšฎ ๐Ÿ“„ ๐Ÿ—„ โ†” ๐Ÿ”Œ ๐Ÿ›ƒ ๐Ÿ”ฑ. - -### ๐Ÿ˜ **FastAPI** - -๐Ÿฅ‡, โœ ๐ŸŒ ๐Ÿ‘† **FastAPI** ๐Ÿˆธ ๐Ÿ›Ž: - -```Python hl_lines="1 4 7-9" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### ๐Ÿ— ๐Ÿ—„ ๐Ÿ”— - -โคด๏ธ, โš™๏ธ ๐ŸŽ ๐Ÿš™ ๐Ÿ”ข ๐Ÿ— ๐Ÿ—„ ๐Ÿ”—, ๐Ÿ”˜ `custom_openapi()` ๐Ÿ”ข: - -```Python hl_lines="2 15-20" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### ๐Ÿ”€ ๐Ÿ—„ ๐Ÿ”— - -๐Ÿ”œ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšฎ ๐Ÿ“„ โ†”, โŽ ๐Ÿ›ƒ `x-logo` `info` "๐ŸŽš" ๐Ÿ—„ ๐Ÿ”—: - -```Python hl_lines="21-23" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### ๐Ÿ’พ ๐Ÿ—„ ๐Ÿ”— - -๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿ  `.openapi_schema` "๐Ÿ’พ", ๐Ÿช ๐Ÿ‘† ๐Ÿ— ๐Ÿ”—. - -๐Ÿ‘ˆ ๐ŸŒŒ, ๐Ÿ‘† ๐Ÿˆธ ๐Ÿ† ๐Ÿšซ โœ”๏ธ ๐Ÿ— ๐Ÿ”— ๐Ÿ”  ๐Ÿ•ฐ ๐Ÿ‘ฉโ€๐Ÿ’ป ๐Ÿ“‚ ๐Ÿ‘† ๐Ÿ› ๏ธ ๐Ÿฉบ. - -โšซ๏ธ ๐Ÿ”œ ๐Ÿ— ๐Ÿ•ด ๐Ÿ•, & โคด๏ธ ๐ŸŽ ๐Ÿ’พ ๐Ÿ”— ๐Ÿ”œ โš™๏ธ โญ ๐Ÿ“จ. - -```Python hl_lines="13-14 24-25" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### ๐Ÿ” ๐Ÿ‘ฉโ€๐Ÿ”ฌ - -๐Ÿ”œ ๐Ÿ‘† ๐Ÿ’ช โŽ `.openapi()` ๐Ÿ‘ฉโ€๐Ÿ”ฌ โฎ๏ธ ๐Ÿ‘† ๐Ÿ†• ๐Ÿ”ข. - -```Python hl_lines="28" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### โœ… โšซ๏ธ - -๐Ÿ• ๐Ÿ‘† ๐Ÿšถ http://127.0.0.1:8000/redoc ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ‘ˆ ๐Ÿ‘† โš™๏ธ ๐Ÿ‘† ๐Ÿ›ƒ ๐Ÿ”ฑ (๐Ÿ‘‰ ๐Ÿ–ผ, **FastAPI**'โ“‚ ๐Ÿ”ฑ): - - - -## ๐Ÿ‘ค-๐Ÿ•ธ ๐Ÿ•ธ & ๐ŸŽš ๐Ÿฉบ - -๐Ÿ› ๏ธ ๐Ÿฉบ โš™๏ธ **๐Ÿฆ ๐ŸŽš** & **๐Ÿ“„**, & ๐Ÿ”  ๐Ÿ‘ˆ ๐Ÿ’ช ๐Ÿ•ธ & ๐ŸŽš ๐Ÿ“. - -๐Ÿ”ข, ๐Ÿ‘ˆ ๐Ÿ“ ๐Ÿฆ โšช๏ธโžก๏ธ ๐Ÿ’ฒ. - -โœ‹๏ธ โšซ๏ธ ๐Ÿ’ช ๐Ÿ›ƒ โšซ๏ธ, ๐Ÿ‘† ๐Ÿ’ช โš’ ๐ŸŽฏ ๐Ÿ’ฒ, โš–๏ธ ๐Ÿฆ ๐Ÿ“ ๐Ÿ‘†. - -๐Ÿ‘ˆ โš , ๐Ÿ–ผ, ๐Ÿšฅ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ‘† ๐Ÿ“ฑ ๐Ÿšง ๐Ÿ‘ท โช ๐Ÿ“ฑ, ๐Ÿต ๐Ÿ“‚ ๐Ÿ•ธ ๐Ÿ”, โš–๏ธ ๐Ÿ‡ง๐Ÿ‡ฟ ๐Ÿ•ธ. - -๐Ÿ“ฅ ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ โ” ๐Ÿฆ ๐Ÿ‘ˆ ๐Ÿ“ ๐Ÿ‘†, ๐ŸŽ FastAPI ๐Ÿ“ฑ, & ๐Ÿ”— ๐Ÿฉบ โš™๏ธ ๐Ÿ‘ซ. - -### ๐Ÿ— ๐Ÿ“ ๐Ÿ“Š - -โžก๏ธ ๐Ÿ’ฌ ๐Ÿ‘† ๐Ÿ— ๐Ÿ“ ๐Ÿ“Š ๐Ÿ‘€ ๐Ÿ’– ๐Ÿ‘‰: - -``` -. -โ”œโ”€โ”€ app -โ”‚ โ”œโ”€โ”€ __init__.py -โ”‚ โ”œโ”€โ”€ main.py -``` - -๐Ÿ”œ โœ ๐Ÿ“ ๐Ÿช ๐Ÿ“š ๐ŸŽป ๐Ÿ“. - -๐Ÿ‘† ๐Ÿ†• ๐Ÿ“ ๐Ÿ“Š ๐Ÿ’ช ๐Ÿ‘€ ๐Ÿ’– ๐Ÿ‘‰: - -``` -. -โ”œโ”€โ”€ app -โ”‚ย ย  โ”œโ”€โ”€ __init__.py -โ”‚ย ย  โ”œโ”€โ”€ main.py -โ””โ”€โ”€ static/ -``` - -### โฌ ๐Ÿ“ - -โฌ ๐ŸŽป ๐Ÿ“ ๐Ÿ’ช ๐Ÿฉบ & ๐Ÿšฎ ๐Ÿ‘ซ ๐Ÿ”› ๐Ÿ‘ˆ `static/` ๐Ÿ“. - -๐Ÿ‘† ๐Ÿ’ช ๐ŸŽฒ โ–ถ๏ธ๏ธ-๐Ÿ–Š ๐Ÿ”  ๐Ÿ”— & ๐Ÿ–Š ๐ŸŽ› ๐ŸŽ `Save link as...`. - -**๐Ÿฆ ๐ŸŽš** โš™๏ธ ๐Ÿ“: - -* `swagger-ui-bundle.js` -* `swagger-ui.css` - -& **๐Ÿ“„** โš™๏ธ ๐Ÿ“: - -* `redoc.standalone.js` - -โฎ๏ธ ๐Ÿ‘ˆ, ๐Ÿ‘† ๐Ÿ“ ๐Ÿ“Š ๐Ÿ’ช ๐Ÿ‘€ ๐Ÿ’–: - -``` -. -โ”œโ”€โ”€ app -โ”‚ย ย  โ”œโ”€โ”€ __init__.py -โ”‚ย ย  โ”œโ”€โ”€ main.py -โ””โ”€โ”€ static - โ”œโ”€โ”€ redoc.standalone.js - โ”œโ”€โ”€ swagger-ui-bundle.js - โ””โ”€โ”€ swagger-ui.css -``` - -### ๐Ÿฆ ๐ŸŽป ๐Ÿ“ - -* ๐Ÿ—„ `StaticFiles`. -* "๐Ÿ—ป" `StaticFiles()` ๐Ÿ‘ ๐ŸŽฏ โžก. - -```Python hl_lines="7 11" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -### ๐Ÿ’ฏ ๐ŸŽป ๐Ÿ“ - -โ–ถ๏ธ ๐Ÿ‘† ๐Ÿˆธ & ๐Ÿšถ http://127.0.0.1:8000/static/redoc.standalone.js. - -๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ“ถ ๐Ÿ“ ๐Ÿ•ธ ๐Ÿ“ **๐Ÿ“„**. - -โšซ๏ธ ๐Ÿ’ช โ–ถ๏ธ โฎ๏ธ ๐Ÿ•ณ ๐Ÿ’–: - -```JavaScript -/*! - * ReDoc - OpenAPI/Swagger-generated API Reference Documentation - * ------------------------------------------------------------- - * Version: "2.0.0-rc.18" - * Repo: https://github.com/Redocly/redoc - */ -!function(e,t){"object"==typeof exports&&"object"==typeof m - -... -``` - -๐Ÿ‘ˆ โœ” ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ’†โ€โ™‚ ๐Ÿ’ช ๐Ÿฆ ๐ŸŽป ๐Ÿ“ โšช๏ธโžก๏ธ ๐Ÿ‘† ๐Ÿ“ฑ, & ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿฅ‰ ๐ŸŽป ๐Ÿ“ ๐Ÿฉบ โ˜‘ ๐Ÿฅ‰. - -๐Ÿ”œ ๐Ÿ‘ฅ ๐Ÿ’ช ๐Ÿ”— ๐Ÿ“ฑ โš™๏ธ ๐Ÿ“š ๐ŸŽป ๐Ÿ“ ๐Ÿฉบ. - -### โŽ ๐Ÿง ๐Ÿฉบ - -๐Ÿฅ‡ ๐Ÿ” โŽ ๐Ÿง ๐Ÿฉบ, ๐Ÿ“š โš™๏ธ ๐Ÿ’ฒ ๐Ÿ”ข. - -โŽ ๐Ÿ‘ซ, โš’ ๐Ÿ‘ซ ๐Ÿ“› `None` ๐Ÿ•โ” ๐Ÿ— ๐Ÿ‘† `FastAPI` ๐Ÿ“ฑ: - -```Python hl_lines="9" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -### ๐Ÿ”Œ ๐Ÿ›ƒ ๐Ÿฉบ - -๐Ÿ”œ ๐Ÿ‘† ๐Ÿ’ช โœ *โžก ๐Ÿ› ๏ธ* ๐Ÿ›ƒ ๐Ÿฉบ. - -๐Ÿ‘† ๐Ÿ’ช ๐Ÿค-โš™๏ธ FastAPI ๐Ÿ”— ๐Ÿ”ข โœ ๐Ÿ•ธ ๐Ÿ“ƒ ๐Ÿฉบ, & ๐Ÿšถโ€โ™€๏ธ ๐Ÿ‘ซ ๐Ÿ’ช โŒ: - -* `openapi_url`: ๐Ÿ“› ๐ŸŒโ” ๐Ÿ•ธ ๐Ÿ“ƒ ๐Ÿฉบ ๐Ÿ’ช ๐Ÿคš ๐Ÿ—„ ๐Ÿ”— ๐Ÿ‘† ๐Ÿ› ๏ธ. ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿ“ฅ ๐Ÿ”ข `app.openapi_url`. -* `title`: ๐Ÿ“› ๐Ÿ‘† ๐Ÿ› ๏ธ. -* `oauth2_redirect_url`: ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ `app.swagger_ui_oauth2_redirect_url` ๐Ÿ“ฅ โš™๏ธ ๐Ÿ”ข. -* `swagger_js_url`: ๐Ÿ“› ๐ŸŒโ” ๐Ÿ•ธ ๐Ÿ‘† ๐Ÿฆ ๐ŸŽš ๐Ÿฉบ ๐Ÿ’ช ๐Ÿคš **๐Ÿ•ธ** ๐Ÿ“. ๐Ÿ‘‰ 1๏ธโƒฃ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ‘ ๐Ÿ“ฑ ๐Ÿ”œ ๐Ÿฆ. -* `swagger_css_url`: ๐Ÿ“› ๐ŸŒโ” ๐Ÿ•ธ ๐Ÿ‘† ๐Ÿฆ ๐ŸŽš ๐Ÿฉบ ๐Ÿ’ช ๐Ÿคš **๐ŸŽš** ๐Ÿ“. ๐Ÿ‘‰ 1๏ธโƒฃ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ‘ ๐Ÿ“ฑ ๐Ÿ”œ ๐Ÿฆ. - -& โžก ๐Ÿ“„... - -```Python hl_lines="2-6 14-22 25-27 30-36" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -!!! tip - *โžก ๐Ÿ› ๏ธ* `swagger_ui_redirect` ๐Ÿ‘ฉโ€๐ŸŽ“ ๐Ÿ•โ” ๐Ÿ‘† โš™๏ธ Oauth2๏ธโƒฃ. - - ๐Ÿšฅ ๐Ÿ‘† ๐Ÿ› ๏ธ ๐Ÿ‘† ๐Ÿ› ๏ธ โฎ๏ธ Oauth2๏ธโƒฃ ๐Ÿ•โ€๐Ÿฆบ, ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’ช ๐Ÿ”“ & ๐Ÿ‘Ÿ ๐Ÿ”™ ๐Ÿ› ๏ธ ๐Ÿฉบ โฎ๏ธ ๐Ÿ“Ž ๐ŸŽ“. & ๐Ÿ”— โฎ๏ธ โšซ๏ธ โš™๏ธ ๐ŸŽฐ Oauth2๏ธโƒฃ ๐Ÿค. - - ๐Ÿฆ ๐ŸŽš ๐Ÿ”œ ๐Ÿต โšซ๏ธ โ›… ๐ŸŽ‘ ๐Ÿ‘†, โœ‹๏ธ โšซ๏ธ ๐Ÿ’ช ๐Ÿ‘‰ "โŽ" ๐Ÿ‘ฉโ€๐ŸŽ“. - -### โœ *โžก ๐Ÿ› ๏ธ* ๐Ÿ’ฏ โšซ๏ธ - -๐Ÿ”œ, ๐Ÿ’ช ๐Ÿ’ฏ ๐Ÿ‘ˆ ๐ŸŒ ๐Ÿ‘ท, โœ *โžก ๐Ÿ› ๏ธ*: - -```Python hl_lines="39-41" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -### ๐Ÿ’ฏ โšซ๏ธ - -๐Ÿ”œ, ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’ช ๐Ÿ”Œ ๐Ÿ‘† ๐Ÿ“ป, ๐Ÿšถ ๐Ÿ‘† ๐Ÿฉบ http://127.0.0.1:8000/docs, & ๐Ÿ”ƒ ๐Ÿ“ƒ. - -& ๐Ÿต ๐Ÿ•ธ, ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’ช ๐Ÿ‘€ ๐Ÿฉบ ๐Ÿ‘† ๐Ÿ› ๏ธ & ๐Ÿ”— โฎ๏ธ โšซ๏ธ. - -## ๐Ÿ› ๏ธ ๐Ÿฆ ๐ŸŽš - -๐Ÿ‘† ๐Ÿ’ช ๐Ÿ”— โž• ๐Ÿฆ ๐ŸŽš ๐Ÿ”ข. - -๐Ÿ”— ๐Ÿ‘ซ, ๐Ÿšถโ€โ™€๏ธ `swagger_ui_parameters` โŒ ๐Ÿ•โ” ๐Ÿ— `FastAPI()` ๐Ÿ“ฑ ๐ŸŽš โš–๏ธ `get_swagger_ui_html()` ๐Ÿ”ข. - -`swagger_ui_parameters` ๐Ÿ“จ ๐Ÿ“– โฎ๏ธ ๐Ÿ“ณ ๐Ÿšถโ€โ™€๏ธ ๐Ÿฆ ๐ŸŽš ๐Ÿ”—. - -FastAPI ๐Ÿ—œ ๐Ÿ“ณ **๐ŸŽป** โš’ ๐Ÿ‘ซ ๐Ÿ”— โฎ๏ธ ๐Ÿ•ธ, ๐Ÿ‘ˆ โšซ๏ธโ” ๐Ÿฆ ๐ŸŽš ๐Ÿ’ช. - -### โŽ โ• ๐ŸŽฆ - -๐Ÿ–ผ, ๐Ÿ‘† ๐Ÿ’ช โŽ โ• ๐ŸŽฆ ๐Ÿฆ ๐ŸŽš. - -๐Ÿต ๐Ÿ”€ โš’, โ• ๐ŸŽฆ ๐Ÿ› ๏ธ ๐Ÿ”ข: - - - -โœ‹๏ธ ๐Ÿ‘† ๐Ÿ’ช โŽ โšซ๏ธ โš’ `syntaxHighlight` `False`: - -```Python hl_lines="3" -{!../../../docs_src/extending_openapi/tutorial003.py!} -``` - -...& โคด๏ธ ๐Ÿฆ ๐ŸŽš ๐Ÿ† ๐Ÿšซ ๐ŸŽฆ โ• ๐ŸŽฆ ๐Ÿšซ๐Ÿ”œ: - - - -### ๐Ÿ”€ ๐ŸŽข - -๐ŸŽ ๐ŸŒŒ ๐Ÿ‘† ๐Ÿ’ช โš’ โ• ๐ŸŽฆ ๐ŸŽข โฎ๏ธ ๐Ÿ”‘ `"syntaxHighlight.theme"` (๐Ÿ‘€ ๐Ÿ‘ˆ โšซ๏ธ โœ”๏ธ โฃ ๐Ÿ–•): - -```Python hl_lines="3" -{!../../../docs_src/extending_openapi/tutorial004.py!} -``` - -๐Ÿ‘ˆ ๐Ÿ“ณ ๐Ÿ”œ ๐Ÿ”€ โ• ๐ŸŽฆ ๐ŸŽจ ๐ŸŽข: - - - -### ๐Ÿ”€ ๐Ÿ”ข ๐Ÿฆ ๐ŸŽš ๐Ÿ”ข - -FastAPI ๐Ÿ”Œ ๐Ÿ”ข ๐Ÿ“ณ ๐Ÿ”ข โ˜‘ ๐ŸŒ… โš™๏ธ ๐Ÿ’ผ. - -โšซ๏ธ ๐Ÿ”Œ ๐Ÿ‘ซ ๐Ÿ”ข ๐Ÿ“ณ: - -```Python -{!../../../fastapi/openapi/docs.py[ln:7-13]!} -``` - -๐Ÿ‘† ๐Ÿ’ช ๐Ÿ” ๐Ÿ™† ๐Ÿ‘ซ โš’ ๐ŸŽ ๐Ÿ’ฒ โŒ `swagger_ui_parameters`. - -๐Ÿ–ผ, โŽ `deepLinking` ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšถโ€โ™€๏ธ ๐Ÿ‘‰ โš’ `swagger_ui_parameters`: - -```Python hl_lines="3" -{!../../../docs_src/extending_openapi/tutorial005.py!} -``` - -### ๐ŸŽ ๐Ÿฆ ๐ŸŽš ๐Ÿ”ข - -๐Ÿ‘€ ๐ŸŒ ๐ŸŽ ๐Ÿ’ช ๐Ÿ“ณ ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ, โœ ๐Ÿ›‚ ๐Ÿฉบ ๐Ÿฆ ๐ŸŽš ๐Ÿ”ข. - -### ๐Ÿ•ธ-๐Ÿ•ด โš’ - -๐Ÿฆ ๐ŸŽš โœ” ๐ŸŽ ๐Ÿ“ณ **๐Ÿ•ธ-๐Ÿ•ด** ๐ŸŽš (๐Ÿ–ผ, ๐Ÿ•ธ ๐Ÿ”ข). - -FastAPI ๐Ÿ”Œ ๐Ÿ‘ซ ๐Ÿ•ธ-๐Ÿ•ด `presets` โš’: - -```JavaScript -presets: [ - SwaggerUIBundle.presets.apis, - SwaggerUIBundle.SwaggerUIStandalonePreset -] -``` - -๐Ÿ‘ซ **๐Ÿ•ธ** ๐ŸŽš, ๐Ÿšซ ๐ŸŽป, ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšซ ๐Ÿšถโ€โ™€๏ธ ๐Ÿ‘ซ โšช๏ธโžก๏ธ ๐Ÿ ๐Ÿ“Ÿ ๐Ÿ”—. - -๐Ÿšฅ ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿ•ธ-๐Ÿ•ด ๐Ÿ“ณ ๐Ÿ’– ๐Ÿ“š, ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ 1๏ธโƒฃ ๐Ÿ‘ฉโ€๐Ÿ”ฌ ๐Ÿ”›. ๐Ÿ” ๐ŸŒ ๐Ÿฆ ๐ŸŽš *โžก ๐Ÿ› ๏ธ* & โŽ โœ ๐Ÿ™† ๐Ÿ•ธ ๐Ÿ‘† ๐Ÿ’ช. diff --git a/docs/em/docs/advanced/settings.md b/docs/em/docs/advanced/settings.md index bc50bf755..2ebe8ffcb 100644 --- a/docs/em/docs/advanced/settings.md +++ b/docs/em/docs/advanced/settings.md @@ -221,7 +221,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" uvicorn main:app ``` !!! tip - ๐Ÿ‘ฅ ๐Ÿ”œ ๐Ÿ”ฌ `@lru_cache()` ๐Ÿ–. + ๐Ÿ‘ฅ ๐Ÿ”œ ๐Ÿ”ฌ `@lru_cache` ๐Ÿ–. ๐Ÿ”œ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿค” `get_settings()` ๐Ÿ˜ ๐Ÿ”ข. @@ -254,7 +254,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" uvicorn main:app โœ‹๏ธ ๐Ÿ‡จ๐Ÿ‡ป ๐Ÿ“ ๐Ÿšซ ๐Ÿค™ โœ”๏ธ โœ”๏ธ ๐Ÿ‘ˆ โ˜‘ ๐Ÿ“. -Pydantic โœ”๏ธ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿ‘‚ โšช๏ธโžก๏ธ ๐Ÿ‘‰ ๐Ÿ†Ž ๐Ÿ“ โš™๏ธ ๐Ÿ”ข ๐Ÿ—ƒ. ๐Ÿ‘† ๐Ÿ’ช โœ ๐ŸŒ– Pydantic โš’: ๐Ÿ‡จ๐Ÿ‡ป (.๐Ÿ‡จ๐Ÿ‡ป) ๐Ÿ•โ€๐Ÿฆบ. +Pydantic โœ”๏ธ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿ‘‚ โšช๏ธโžก๏ธ ๐Ÿ‘‰ ๐Ÿ†Ž ๐Ÿ“ โš™๏ธ ๐Ÿ”ข ๐Ÿ—ƒ. ๐Ÿ‘† ๐Ÿ’ช โœ ๐ŸŒ– Pydantic โš’: ๐Ÿ‡จ๐Ÿ‡ป (.๐Ÿ‡จ๐Ÿ‡ป) ๐Ÿ•โ€๐Ÿฆบ. !!! tip ๐Ÿ‘‰ ๐Ÿ‘ท, ๐Ÿ‘† ๐Ÿ’ช `pip install python-dotenv`. @@ -302,7 +302,7 @@ def get_settings(): ๐Ÿ‘ฅ ๐Ÿ”œ โœ ๐Ÿ‘ˆ ๐ŸŽš ๐Ÿ”  ๐Ÿ“จ, & ๐Ÿ‘ฅ ๐Ÿ”œ ๐Ÿ‘‚ `.env` ๐Ÿ“ ๐Ÿ”  ๐Ÿ“จ. ๐Ÿ‘ถ ๐Ÿ‘ถ -โœ‹๏ธ ๐Ÿ‘ฅ โš™๏ธ `@lru_cache()` ๐Ÿ‘จโ€๐ŸŽจ ๐Ÿ”› ๐Ÿ”, `Settings` ๐ŸŽš ๐Ÿ”œ โœ ๐Ÿ•ด ๐Ÿ•, ๐Ÿฅ‡ ๐Ÿ•ฐ โšซ๏ธ ๐Ÿค™. ๐Ÿ‘ถ ๐Ÿ‘ถ +โœ‹๏ธ ๐Ÿ‘ฅ โš™๏ธ `@lru_cache` ๐Ÿ‘จโ€๐ŸŽจ ๐Ÿ”› ๐Ÿ”, `Settings` ๐ŸŽš ๐Ÿ”œ โœ ๐Ÿ•ด ๐Ÿ•, ๐Ÿฅ‡ ๐Ÿ•ฐ โšซ๏ธ ๐Ÿค™. ๐Ÿ‘ถ ๐Ÿ‘ถ ```Python hl_lines="1 10" {!../../../docs_src/settings/app03/main.py!} @@ -312,14 +312,14 @@ def get_settings(): #### `lru_cache` ๐Ÿ“ก โ„น -`@lru_cache()` ๐Ÿ”€ ๐Ÿ”ข โšซ๏ธ ๐ŸŽ€ ๐Ÿ“จ ๐ŸŽ ๐Ÿ’ฒ ๐Ÿ‘ˆ ๐Ÿ“จ ๐Ÿฅ‡ ๐Ÿ•ฐ, โ†ฉ๏ธ ๐Ÿ’ป โšซ๏ธ ๐Ÿ”„, ๐Ÿ› ๏ธ ๐Ÿ“Ÿ ๐Ÿ”ข ๐Ÿ”  ๐Ÿ•ฐ. +`@lru_cache` ๐Ÿ”€ ๐Ÿ”ข โšซ๏ธ ๐ŸŽ€ ๐Ÿ“จ ๐ŸŽ ๐Ÿ’ฒ ๐Ÿ‘ˆ ๐Ÿ“จ ๐Ÿฅ‡ ๐Ÿ•ฐ, โ†ฉ๏ธ ๐Ÿ’ป โšซ๏ธ ๐Ÿ”„, ๐Ÿ› ๏ธ ๐Ÿ“Ÿ ๐Ÿ”ข ๐Ÿ”  ๐Ÿ•ฐ. , ๐Ÿ”ข ๐Ÿ”› โšซ๏ธ ๐Ÿ”œ ๐Ÿ› ๏ธ ๐Ÿ• ๐Ÿ”  ๐ŸŒ€ โŒ. & โคด๏ธ ๐Ÿ’ฒ ๐Ÿ“จ ๐Ÿ”  ๐Ÿ‘ˆ ๐ŸŒ€ โŒ ๐Ÿ”œ โš™๏ธ ๐Ÿ”„ & ๐Ÿ”„ ๐Ÿ•โ” ๐Ÿ”ข ๐Ÿค™ โฎ๏ธ โšซ๏ธโ” ๐ŸŽ ๐ŸŒ€ โŒ. ๐Ÿ–ผ, ๐Ÿšฅ ๐Ÿ‘† โœ”๏ธ ๐Ÿ”ข: ```Python -@lru_cache() +@lru_cache def say_hi(name: str, salutation: str = "Ms."): return f"Hello {salutation} {name}" ``` @@ -371,7 +371,7 @@ participant execute as Execute function ๐Ÿ‘ˆ ๐ŸŒŒ, โšซ๏ธ ๐ŸŽญ ๐ŸŒ– ๐Ÿšฅ โšซ๏ธ ๐ŸŒ ๐Ÿ”ข. โœ‹๏ธ โšซ๏ธ โš™๏ธ ๐Ÿ”— ๐Ÿ”ข, โคด๏ธ ๐Ÿ‘ฅ ๐Ÿ’ช ๐Ÿ” โšซ๏ธ ๐Ÿ’ช ๐Ÿ”ฌ. -`@lru_cache()` ๐Ÿ• `functools` โ” ๐Ÿ• ๐Ÿ ๐Ÿฉ ๐Ÿ—ƒ, ๐Ÿ‘† ๐Ÿ’ช โœ ๐ŸŒ… ๐Ÿ”ƒ โšซ๏ธ ๐Ÿ ๐Ÿฉบ `@lru_cache()`. +`@lru_cache` ๐Ÿ• `functools` โ” ๐Ÿ• ๐Ÿ ๐Ÿฉ ๐Ÿ—ƒ, ๐Ÿ‘† ๐Ÿ’ช โœ ๐ŸŒ… ๐Ÿ”ƒ โšซ๏ธ ๐Ÿ ๐Ÿฉบ `@lru_cache`. ## ๐ŸŒƒ @@ -379,4 +379,4 @@ participant execute as Execute function * โš™๏ธ ๐Ÿ”— ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ“‰ ๐Ÿ”ฌ. * ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ `.env` ๐Ÿ“ โฎ๏ธ โšซ๏ธ. -* โš™๏ธ `@lru_cache()` โžก๏ธ ๐Ÿ‘† โŽ ๐Ÿ‘‚ ๐Ÿ‡จ๐Ÿ‡ป ๐Ÿ“ ๐Ÿ”„ & ๐Ÿ”„ ๐Ÿ”  ๐Ÿ“จ, โช ๐Ÿค ๐Ÿ‘† ๐Ÿ” โšซ๏ธ โฎ๏ธ ๐Ÿ”ฌ. +* โš™๏ธ `@lru_cache` โžก๏ธ ๐Ÿ‘† โŽ ๐Ÿ‘‚ ๐Ÿ‡จ๐Ÿ‡ป ๐Ÿ“ ๐Ÿ”„ & ๐Ÿ”„ ๐Ÿ”  ๐Ÿ“จ, โช ๐Ÿค ๐Ÿ‘† ๐Ÿ” โšซ๏ธ โฎ๏ธ ๐Ÿ”ฌ. diff --git a/docs/em/docs/async.md b/docs/em/docs/async.md index 13b362b5d..ddcae1573 100644 --- a/docs/em/docs/async.md +++ b/docs/em/docs/async.md @@ -409,11 +409,11 @@ async def read_burgers(): ### ๐Ÿ”— -๐ŸŽ โœ” [๐Ÿ”—](/tutorial/dependencies/index.md){.internal-link target=_blank}. ๐Ÿšฅ ๐Ÿ”— ๐Ÿฉ `def` ๐Ÿ”ข โ†ฉ๏ธ `async def`, โšซ๏ธ ๐Ÿƒ ๐Ÿ”ข ๐Ÿงต. +๐ŸŽ โœ” [๐Ÿ”—](./tutorial/dependencies/index.md){.internal-link target=_blank}. ๐Ÿšฅ ๐Ÿ”— ๐Ÿฉ `def` ๐Ÿ”ข โ†ฉ๏ธ `async def`, โšซ๏ธ ๐Ÿƒ ๐Ÿ”ข ๐Ÿงต. ### ๐ŸŽง-๐Ÿ”— -๐Ÿ‘† ๐Ÿ’ช โœ”๏ธ ๐Ÿ’— ๐Ÿ”— & [๐ŸŽง-๐Ÿ”—](/tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} ๐Ÿšซ ๐Ÿ”  ๐ŸŽ (๐Ÿ”ข ๐Ÿ”ข ๐Ÿ”‘), ๐Ÿ‘ซ ๐Ÿ’ช โœ โฎ๏ธ `async def` & โฎ๏ธ ๐Ÿ˜ `def`. โšซ๏ธ ๐Ÿ”œ ๐Ÿ‘ท, & ๐Ÿ• โœ โฎ๏ธ ๐Ÿ˜ `def` ๐Ÿ”œ ๐Ÿค™ ๐Ÿ”› ๐Ÿ”ข ๐Ÿงต (โšช๏ธโžก๏ธ ๐Ÿงต) โ†ฉ๏ธ โž– "โŒ›". +๐Ÿ‘† ๐Ÿ’ช โœ”๏ธ ๐Ÿ’— ๐Ÿ”— & [๐ŸŽง-๐Ÿ”—](./tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} ๐Ÿšซ ๐Ÿ”  ๐ŸŽ (๐Ÿ”ข ๐Ÿ”ข ๐Ÿ”‘), ๐Ÿ‘ซ ๐Ÿ’ช โœ โฎ๏ธ `async def` & โฎ๏ธ ๐Ÿ˜ `def`. โšซ๏ธ ๐Ÿ”œ ๐Ÿ‘ท, & ๐Ÿ• โœ โฎ๏ธ ๐Ÿ˜ `def` ๐Ÿ”œ ๐Ÿค™ ๐Ÿ”› ๐Ÿ”ข ๐Ÿงต (โšช๏ธโžก๏ธ ๐Ÿงต) โ†ฉ๏ธ โž– "โŒ›". ### ๐ŸŽ ๐Ÿš™ ๐Ÿ”ข diff --git a/docs/em/docs/deployment/concepts.md b/docs/em/docs/deployment/concepts.md index 8ce775411..162b68615 100644 --- a/docs/em/docs/deployment/concepts.md +++ b/docs/em/docs/deployment/concepts.md @@ -43,7 +43,7 @@ * โฎ๏ธ ๐Ÿ”ข ๐Ÿฆฒ ๐Ÿ’– Certbot ๐Ÿ“„ ๐Ÿ”• * โœณ * โฎ๏ธ ๐Ÿ”ข ๐Ÿฆฒ ๐Ÿ’– Certbot ๐Ÿ“„ ๐Ÿ”• -* Kubernete โฎ๏ธ ๐Ÿšง ๐Ÿ•น ๐Ÿ’– ๐Ÿ‘Œ +* Kubernetes โฎ๏ธ ๐Ÿšง ๐Ÿ•น ๐Ÿ’– ๐Ÿ‘Œ * โฎ๏ธ ๐Ÿ”ข ๐Ÿฆฒ ๐Ÿ’– ๐Ÿ›‚-๐Ÿ‘จโ€๐Ÿ’ผ ๐Ÿ“„ ๐Ÿ”• * ๐Ÿต ๐Ÿ”˜ โ˜ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿ• ๐Ÿ‘ซ ๐Ÿ•โ€๐Ÿฆบ (โœ ๐Ÿ”› ๐Ÿ‘ถ) @@ -115,7 +115,7 @@ ๐Ÿ–ผ ๐Ÿงฐ ๐Ÿ‘ˆ ๐Ÿ’ช ๐Ÿ‘‰ ๐Ÿ‘จโ€๐Ÿญ: * โ˜ -* Kubernete +* Kubernetes * โ˜ โœ * โ˜ ๐Ÿ ๐Ÿ“ณ * โœณ @@ -165,7 +165,7 @@ ๐Ÿ–ผ, ๐Ÿ‘‰ ๐Ÿ’ช ๐Ÿต: * โ˜ -* Kubernete +* Kubernetes * โ˜ โœ * โ˜ ๐Ÿ ๐Ÿ“ณ * โœณ @@ -233,15 +233,15 @@ * ๐Ÿ ๐Ÿ”œ **๐Ÿ› ๏ธ ๐Ÿ‘จโ€๐Ÿ’ผ** ๐Ÿ‘‚ ๐Ÿ”› **๐Ÿ“ข** & **โ›ด**, ๐Ÿงฌ ๐Ÿ”œ โœ”๏ธ **๐Ÿ’— Uvicorn ๐Ÿ‘จโ€๐Ÿญ ๐Ÿ› ๏ธ** * **Uvicorn** ๐Ÿ› ๏ธ **Uvicorn ๐Ÿ‘จโ€๐Ÿญ** * 1๏ธโƒฃ Uvicorn **๐Ÿ› ๏ธ ๐Ÿ‘จโ€๐Ÿ’ผ** ๐Ÿ”œ ๐Ÿ‘‚ ๐Ÿ”› **๐Ÿ“ข** & **โ›ด**, & โšซ๏ธ ๐Ÿ”œ โ–ถ๏ธ **๐Ÿ’— Uvicorn ๐Ÿ‘จโ€๐Ÿญ ๐Ÿ› ๏ธ** -* **Kubernete** & ๐ŸŽ ๐Ÿ“Ž **๐Ÿ“ฆ โš™๏ธ** +* **Kubernetes** & ๐ŸŽ ๐Ÿ“Ž **๐Ÿ“ฆ โš™๏ธ** * ๐Ÿ•ณ **โ˜** ๐Ÿงฝ ๐Ÿ”œ ๐Ÿ‘‚ ๐Ÿ”› **๐Ÿ“ข** & **โ›ด**. ๐Ÿงฌ ๐Ÿ”œ โœ”๏ธ **๐Ÿ’— ๐Ÿ“ฆ**, ๐Ÿ”  โฎ๏ธ **1๏ธโƒฃ Uvicorn ๐Ÿ› ๏ธ** ๐Ÿƒโ€โ™‚ * **โ˜ ๐Ÿ•โ€๐Ÿฆบ** ๐Ÿ‘ˆ ๐Ÿต ๐Ÿ‘‰ ๐Ÿ‘† * โ˜ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿ”œ ๐ŸŽฒ **๐Ÿต ๐Ÿงฌ ๐Ÿ‘†**. โšซ๏ธ ๐Ÿ”œ ๐ŸŽฒ โžก๏ธ ๐Ÿ‘† ๐Ÿ”ฌ **๐Ÿ› ๏ธ ๐Ÿƒ**, โš–๏ธ **๐Ÿ“ฆ ๐Ÿ–ผ** โš™๏ธ, ๐Ÿ™† ๐Ÿ’ผ, โšซ๏ธ ๐Ÿ”œ ๐ŸŒ… ๐ŸŽฒ **๐Ÿ‘ Uvicorn ๐Ÿ› ๏ธ**, & โ˜ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿ”œ ๐Ÿˆš ๐Ÿ” โšซ๏ธ. !!! tip - ๐Ÿšซ ๐Ÿ˜Ÿ ๐Ÿšฅ ๐Ÿ‘ซ ๐Ÿฌ ๐Ÿ”ƒ **๐Ÿ“ฆ**, โ˜, โš–๏ธ Kubernete ๐Ÿšซ โš’ ๐Ÿ“š ๐Ÿ”‘. + ๐Ÿšซ ๐Ÿ˜Ÿ ๐Ÿšฅ ๐Ÿ‘ซ ๐Ÿฌ ๐Ÿ”ƒ **๐Ÿ“ฆ**, โ˜, โš–๏ธ Kubernetes ๐Ÿšซ โš’ ๐Ÿ“š ๐Ÿ”‘. - ๐Ÿ‘ค ๐Ÿ”œ ๐Ÿ’ฌ ๐Ÿ‘† ๐ŸŒ… ๐Ÿ”ƒ ๐Ÿ“ฆ ๐Ÿ–ผ, โ˜, Kubernete, โ™’๏ธ. ๐Ÿ”ฎ ๐Ÿ“ƒ: [FastAPI ๐Ÿ“ฆ - โ˜](./docker.md){.internal-link target=_blank}. + ๐Ÿ‘ค ๐Ÿ”œ ๐Ÿ’ฌ ๐Ÿ‘† ๐ŸŒ… ๐Ÿ”ƒ ๐Ÿ“ฆ ๐Ÿ–ผ, โ˜, Kubernetes, โ™’๏ธ. ๐Ÿ”ฎ ๐Ÿ“ƒ: [FastAPI ๐Ÿ“ฆ - โ˜](./docker.md){.internal-link target=_blank}. ## โฎ๏ธ ๐Ÿ” โญ โ–ถ๏ธ @@ -268,7 +268,7 @@ ๐Ÿ“ฅ ๐Ÿ’ช ๐Ÿ’ญ: -* "๐Ÿ•‘ ๐Ÿ“ฆ" Kubernete ๐Ÿ‘ˆ ๐Ÿƒ โญ ๐Ÿ‘† ๐Ÿ“ฑ ๐Ÿ“ฆ +* "๐Ÿ•‘ ๐Ÿ“ฆ" Kubernetes ๐Ÿ‘ˆ ๐Ÿƒ โญ ๐Ÿ‘† ๐Ÿ“ฑ ๐Ÿ“ฆ * ๐ŸŽ‰ โœ ๐Ÿ‘ˆ ๐Ÿƒ โฎ๏ธ ๐Ÿ” & โคด๏ธ โ–ถ๏ธ ๐Ÿ‘† ๐Ÿˆธ * ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’ช ๐ŸŒŒ โ–ถ๏ธ/โ *๐Ÿ‘ˆ* ๐ŸŽ‰ โœ, ๐Ÿ” โŒ, โ™’๏ธ. diff --git a/docs/em/docs/deployment/deta.md b/docs/em/docs/deployment/deta.md deleted file mode 100644 index 89b6c4bdb..000000000 --- a/docs/em/docs/deployment/deta.md +++ /dev/null @@ -1,258 +0,0 @@ -# ๐Ÿ› ๏ธ FastAPI ๐Ÿ”› ๐Ÿช” - -๐Ÿ‘‰ ๐Ÿ“„ ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’ก โ” ๐Ÿ’ช ๐Ÿ› ๏ธ **FastAPI** ๐Ÿˆธ ๐Ÿ”› ๐Ÿช” โš™๏ธ ๐Ÿ†“ ๐Ÿ“„. ๐Ÿ‘ถ - -โšซ๏ธ ๐Ÿ”œ โœŠ ๐Ÿ‘† ๐Ÿ”ƒ **1๏ธโƒฃ0๏ธโƒฃ โฒ**. - -!!! info - ๐Ÿช” **FastAPI** ๐Ÿ’ฐ. ๐Ÿ‘ถ - -## ๐Ÿ”ฐ **FastAPI** ๐Ÿ“ฑ - -* โœ ๐Ÿ“ ๐Ÿ‘† ๐Ÿ“ฑ, ๐Ÿ–ผ, `./fastapideta/` & โ›” ๐Ÿ”˜ โšซ๏ธ. - -### FastAPI ๐Ÿ“Ÿ - -* โœ `main.py` ๐Ÿ“ โฎ๏ธ: - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int): - return {"item_id": item_id} -``` - -### ๐Ÿ“„ - -๐Ÿ”œ, ๐ŸŽ ๐Ÿ“ โœ ๐Ÿ“ `requirements.txt` โฎ๏ธ: - -```text -fastapi -``` - -!!! tip - ๐Ÿ‘† ๐Ÿšซ ๐Ÿ’ช โŽ Uvicorn ๐Ÿ› ๏ธ ๐Ÿ”› ๐Ÿช”, ๐Ÿ‘ ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ’š โŽ โšซ๏ธ ๐ŸŒ ๐Ÿ’ฏ ๐Ÿ‘† ๐Ÿ“ฑ. - -### ๐Ÿ“ ๐Ÿ“Š - -๐Ÿ‘† ๐Ÿ”œ ๐Ÿ”œ โœ”๏ธ 1๏ธโƒฃ ๐Ÿ“ `./fastapideta/` โฎ๏ธ 2๏ธโƒฃ ๐Ÿ“: - -``` -. -โ””โ”€โ”€ main.py -โ””โ”€โ”€ requirements.txt -``` - -## โœ ๐Ÿ†“ ๐Ÿช” ๐Ÿง - -๐Ÿ”œ โœ ๐Ÿ†“ ๐Ÿง ๐Ÿ”› ๐Ÿช”, ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ“ง & ๐Ÿ”. - -๐Ÿ‘† ๐Ÿšซ ๐Ÿ’ช ๐Ÿ’ณ. - -## โŽ โœณ - -๐Ÿ• ๐Ÿ‘† โœ”๏ธ ๐Ÿ‘† ๐Ÿง, โŽ ๐Ÿช” โœณ: - -=== "๐Ÿ’พ, ๐Ÿ‡ธ๐Ÿ‡ป" - -
- - ```console - $ curl -fsSL https://get.deta.dev/cli.sh | sh - ``` - -
- -=== "๐Ÿšช ๐Ÿ“‹" - -
- - ```console - $ iwr https://get.deta.dev/cli.ps1 -useb | iex - ``` - -
- -โฎ๏ธ โŽ โšซ๏ธ, ๐Ÿ“‚ ๐Ÿ†• ๐Ÿ“ถ ๐Ÿ‘ˆ โŽ โœณ ๐Ÿ”. - -๐Ÿ†• ๐Ÿ“ถ, โœ” ๐Ÿ‘ˆ โšซ๏ธ โ˜‘ โŽ โฎ๏ธ: - -
- -```console -$ deta --help - -Deta command line interface for managing deta micros. -Complete documentation available at https://docs.deta.sh - -Usage: - deta [flags] - deta [command] - -Available Commands: - auth Change auth settings for a deta micro - -... -``` - -
- -!!! tip - ๐Ÿšฅ ๐Ÿ‘† โœ”๏ธ โš  โŽ โœณ, โœ… ๐Ÿ›‚ ๐Ÿช” ๐Ÿฉบ. - -## ๐Ÿ’ณ โฎ๏ธ โœณ - -๐Ÿ”œ ๐Ÿ’ณ ๐Ÿช” โšช๏ธโžก๏ธ โœณ โฎ๏ธ: - -
- -```console -$ deta login - -Please, log in from the web page. Waiting.. -Logged in successfully. -``` - -
- -๐Ÿ‘‰ ๐Ÿ”œ ๐Ÿ“‚ ๐Ÿ•ธ ๐Ÿ–ฅ & ๐Ÿ”“ ๐Ÿ”. - -## ๐Ÿ› ๏ธ โฎ๏ธ ๐Ÿช” - -โญ, ๐Ÿ› ๏ธ ๐Ÿ‘† ๐Ÿˆธ โฎ๏ธ ๐Ÿช” โœณ: - -
- -```console -$ deta new - -Successfully created a new micro - -// Notice the "endpoint" ๐Ÿ” - -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} - -Adding dependencies... - - ----> 100% - - -Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 -``` - -
- -๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐ŸŽป ๐Ÿ“ง ๐ŸŽ: - -```JSON hl_lines="4" -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} -``` - -!!! tip - ๐Ÿ‘† ๐Ÿ› ๏ธ ๐Ÿ”œ โœ”๏ธ ๐ŸŽ `"endpoint"` ๐Ÿ“›. - -## โœ… โšซ๏ธ - -๐Ÿ”œ ๐Ÿ“‚ ๐Ÿ‘† ๐Ÿ–ฅ ๐Ÿ‘† `endpoint` ๐Ÿ“›. ๐Ÿ–ผ ๐Ÿ”› โšซ๏ธ `https://qltnci.deta.dev`, โœ‹๏ธ ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽ. - -๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐ŸŽป ๐Ÿ“จ โšช๏ธโžก๏ธ ๐Ÿ‘† FastAPI ๐Ÿ“ฑ: - -```JSON -{ - "Hello": "World" -} -``` - -& ๐Ÿ”œ ๐Ÿšถ `/docs` ๐Ÿ‘† ๐Ÿ› ๏ธ, ๐Ÿ–ผ ๐Ÿ”› โšซ๏ธ ๐Ÿ”œ `https://qltnci.deta.dev/docs`. - -โšซ๏ธ ๐Ÿ”œ ๐ŸŽฆ ๐Ÿ‘† ๐Ÿฉบ ๐Ÿ’–: - - - -## ๐Ÿ› ๏ธ ๐Ÿ“ข ๐Ÿ” - -๐Ÿ”ข, ๐Ÿช” ๐Ÿ”œ ๐Ÿต ๐Ÿค โš™๏ธ ๐Ÿช ๐Ÿ‘† ๐Ÿง. - -โœ‹๏ธ ๐Ÿ• ๐Ÿ‘† ๐Ÿ”œ, ๐Ÿ‘† ๐Ÿ’ช โš’ โšซ๏ธ ๐Ÿ“ข โฎ๏ธ: - -
- -```console -$ deta auth disable - -Successfully disabled http auth -``` - -
- -๐Ÿ”œ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ’ฐ ๐Ÿ‘ˆ ๐Ÿ“› โฎ๏ธ ๐Ÿ™† & ๐Ÿ‘ซ ๐Ÿ”œ ๐Ÿ’ช ๐Ÿ” ๐Ÿ‘† ๐Ÿ› ๏ธ. ๐Ÿ‘ถ - -## ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” - -ใŠ— โ— ๐Ÿ‘† ๐Ÿ› ๏ธ ๐Ÿ‘† FastAPI ๐Ÿ“ฑ ๐Ÿช” โ— ๐Ÿ‘ถ ๐Ÿ‘ถ - -, ๐Ÿ‘€ ๐Ÿ‘ˆ ๐Ÿช” โ˜‘ ๐Ÿต ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” ๐Ÿ‘†, ๐Ÿ‘† ๐Ÿšซ โœ”๏ธ โœŠ ๐Ÿ’… ๐Ÿ‘ˆ & ๐Ÿ’ช ๐Ÿ’ญ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ‘ฉโ€๐Ÿ’ป ๐Ÿ”œ โœ”๏ธ ๐Ÿ” ๐Ÿ—œ ๐Ÿ”—. ๐Ÿ‘ถ ๐Ÿ‘ถ - -## โœ… ๐Ÿ•ถ - -โšช๏ธโžก๏ธ ๐Ÿ‘† ๐Ÿฉบ ๐ŸŽš (๐Ÿ‘ซ ๐Ÿ”œ ๐Ÿ“› ๐Ÿ’– `https://qltnci.deta.dev/docs`) ๐Ÿ“จ ๐Ÿ“จ ๐Ÿ‘† *โžก ๐Ÿ› ๏ธ* `/items/{item_id}`. - -๐Ÿ–ผ โฎ๏ธ ๐Ÿ†” `5`. - -๐Ÿ”œ ๐Ÿšถ https://web.deta.sh. - -๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ“ค ๐Ÿ“„ โ—€๏ธ ๐Ÿค™ "โ—พ" โฎ๏ธ ๐Ÿ”  ๐Ÿ‘† ๐Ÿ“ฑ. - -๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ“‘ โฎ๏ธ "โ„น", & ๐Ÿ“‘ "๐Ÿ•ถ", ๐Ÿšถ ๐Ÿ“‘ "๐Ÿ•ถ". - -๐Ÿ“ค ๐Ÿ‘† ๐Ÿ’ช โœ” โฎ๏ธ ๐Ÿ“จ ๐Ÿ“จ ๐Ÿ‘† ๐Ÿ“ฑ. - -๐Ÿ‘† ๐Ÿ’ช โœ ๐Ÿ‘ซ & ๐Ÿค-๐Ÿคพ ๐Ÿ‘ซ. - - - -## ๐Ÿ’ก ๐ŸŒ… - -โ˜, ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ’š ๐Ÿช ๐Ÿ’ฝ ๐Ÿ‘† ๐Ÿ“ฑ ๐ŸŒŒ ๐Ÿ‘ˆ ๐Ÿ˜ฃ ๐Ÿ”˜ ๐Ÿ•ฐ. ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿช” ๐Ÿงข, โšซ๏ธ โœ”๏ธ ๐Ÿ‘ **๐Ÿ†“ ๐ŸŽš**. - -๐Ÿ‘† ๐Ÿ’ช โœ ๐ŸŒ… ๐Ÿช” ๐Ÿฉบ. - -## ๐Ÿ› ๏ธ ๐Ÿ”ง - -๐Ÿ‘Ÿ ๐Ÿ”™ ๐Ÿ”ง ๐Ÿ‘ฅ ๐Ÿ”ฌ [๐Ÿ› ๏ธ ๐Ÿ”ง](./concepts.md){.internal-link target=_blank}, ๐Ÿ“ฅ โ” ๐Ÿ”  ๐Ÿ‘ซ ๐Ÿ”œ ๐Ÿต โฎ๏ธ ๐Ÿช”: - -* **๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ”**: ๐Ÿต ๐Ÿช”, ๐Ÿ‘ซ ๐Ÿ”œ ๐Ÿค ๐Ÿ‘† ๐Ÿ“ & ๐Ÿต ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” ๐Ÿ”. -* **๐Ÿƒโ€โ™‚ ๐Ÿ”› ๐Ÿ•ด**: ๐Ÿต ๐Ÿช”, ๐Ÿ• ๐Ÿ‘ซ ๐Ÿ•โ€๐Ÿฆบ. -* **โ**: ๐Ÿต ๐Ÿช”, ๐Ÿ• ๐Ÿ‘ซ ๐Ÿ•โ€๐Ÿฆบ. -* **๐Ÿงฌ**: ๐Ÿต ๐Ÿช”, ๐Ÿ• ๐Ÿ‘ซ ๐Ÿ•โ€๐Ÿฆบ. -* **๐Ÿ’พ**: ๐Ÿ“‰ ๐Ÿ” ๐Ÿช”, ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ“ง ๐Ÿ‘ซ ๐Ÿ“ˆ โšซ๏ธ. -* **โฎ๏ธ ๐Ÿ” โญ โ–ถ๏ธ**: ๐Ÿšซ ๐Ÿ”— ๐Ÿ•โ€๐Ÿฆบ, ๐Ÿ‘† ๐Ÿ’ช โš’ โšซ๏ธ ๐Ÿ‘ท โฎ๏ธ ๐Ÿ‘ซ ๐Ÿ’พ โš™๏ธ โš–๏ธ ๐ŸŒ– โœ. - -!!! note - ๐Ÿช” ๐Ÿ”ง โš’ โšซ๏ธ โฉ (& ๐Ÿ†“) ๐Ÿ› ๏ธ ๐Ÿ™… ๐Ÿˆธ ๐Ÿ”œ. - - โšซ๏ธ ๐Ÿ’ช ๐Ÿ“‰ ๐Ÿ“š โš™๏ธ ๐Ÿ’ผ, โœ‹๏ธ ๐ŸŽ ๐Ÿ•ฐ, โšซ๏ธ ๐Ÿšซ ๐Ÿ•โ€๐Ÿฆบ ๐ŸŽ, ๐Ÿ’– โš™๏ธ ๐Ÿ”ข ๐Ÿ’ฝ (โ†–๏ธ โšช๏ธโžก๏ธ ๐Ÿช” ๐Ÿ‘ โ˜ ๐Ÿ’ฝ โš™๏ธ), ๐Ÿ›ƒ ๐Ÿ•น ๐ŸŽฐ, โ™’๏ธ. - - ๐Ÿ‘† ๐Ÿ’ช โœ ๐ŸŒ… โ„น ๐Ÿช” ๐Ÿฉบ ๐Ÿ‘€ ๐Ÿšฅ โšซ๏ธ โ–ถ๏ธ๏ธ โš’ ๐Ÿ‘†. diff --git a/docs/em/docs/deployment/docker.md b/docs/em/docs/deployment/docker.md index 51ece5599..f28735ed7 100644 --- a/docs/em/docs/deployment/docker.md +++ b/docs/em/docs/deployment/docker.md @@ -74,7 +74,7 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] , ๐Ÿ‘† ๐Ÿ”œ ๐Ÿƒ **๐Ÿ’— ๐Ÿ“ฆ** โฎ๏ธ ๐ŸŽ ๐Ÿ‘œ, ๐Ÿ’– ๐Ÿ’ฝ, ๐Ÿ ๐Ÿˆธ, ๐Ÿ•ธ ๐Ÿ’ฝ โฎ๏ธ ๐Ÿ˜ฅ ๐Ÿ•ธ ๐Ÿˆธ, & ๐Ÿ”— ๐Ÿ‘ซ ๐Ÿ‘ฏโ€โ™‚๏ธ ๐Ÿ“จ ๐Ÿ‘ซ ๐Ÿ”— ๐Ÿ•ธ. -๐ŸŒ ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ (๐Ÿ’– โ˜ โš–๏ธ Kubernete) โœ”๏ธ ๐Ÿ‘ซ ๐Ÿ•ธ โš’ ๐Ÿ› ๏ธ ๐Ÿ”˜ ๐Ÿ‘ซ. +๐ŸŒ ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ (๐Ÿ’– โ˜ โš–๏ธ Kubernetes) โœ”๏ธ ๐Ÿ‘ซ ๐Ÿ•ธ โš’ ๐Ÿ› ๏ธ ๐Ÿ”˜ ๐Ÿ‘ซ. ## ๐Ÿ“ฆ & ๐Ÿ› ๏ธ @@ -96,7 +96,7 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] ๐Ÿ‘‰ โšซ๏ธโ” ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’š **๐Ÿ† ๐Ÿ’ผ**, ๐Ÿ–ผ: -* โš™๏ธ **Kubernete** โš–๏ธ ๐ŸŽ ๐Ÿงฐ +* โš™๏ธ **Kubernetes** โš–๏ธ ๐ŸŽ ๐Ÿงฐ * ๐Ÿ•โ” ๐Ÿƒโ€โ™‚ ๐Ÿ”› **๐Ÿ“ ๐Ÿ‘ฒ** * โš™๏ธ โ˜ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿ‘ˆ ๐Ÿ”œ ๐Ÿƒ ๐Ÿ“ฆ ๐Ÿ–ผ ๐Ÿ‘†, โ™’๏ธ. @@ -395,7 +395,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] โšซ๏ธ ๐Ÿ’ช โž•1๏ธโƒฃ ๐Ÿ“ฆ, ๐Ÿ–ผ โฎ๏ธ Traefik, ๐Ÿšš **๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ”** & **๐Ÿง** ๐Ÿ› ๏ธ **๐Ÿ“„**. !!! tip - Traefik โœ”๏ธ ๐Ÿ› ๏ธ โฎ๏ธ โ˜, Kubernete, & ๐ŸŽ, โšซ๏ธ ๐Ÿ“ถ โฉ โš’ ๐Ÿ†™ & ๐Ÿ”— ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” ๐Ÿ‘† ๐Ÿ“ฆ โฎ๏ธ โšซ๏ธ. + Traefik โœ”๏ธ ๐Ÿ› ๏ธ โฎ๏ธ โ˜, Kubernetes, & ๐ŸŽ, โšซ๏ธ ๐Ÿ“ถ โฉ โš’ ๐Ÿ†™ & ๐Ÿ”— ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” ๐Ÿ‘† ๐Ÿ“ฆ โฎ๏ธ โšซ๏ธ. ๐Ÿ‘, ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” ๐Ÿ’ช ๐Ÿต โ˜ ๐Ÿ•โ€๐Ÿฆบ 1๏ธโƒฃ ๐Ÿ‘ซ ๐Ÿ•โ€๐Ÿฆบ (โช ๐Ÿƒ ๐Ÿˆธ ๐Ÿ“ฆ). @@ -403,7 +403,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] ๐Ÿ“ค ๐Ÿ›Ž โž•1๏ธโƒฃ ๐Ÿงฐ ๐Ÿˆš **โ–ถ๏ธ & ๐Ÿƒโ€โ™‚** ๐Ÿ‘† ๐Ÿ“ฆ. -โšซ๏ธ ๐Ÿ’ช **โ˜** ๐Ÿ”—, **โ˜ โœ**, **Kubernete**, **โ˜ ๐Ÿ•โ€๐Ÿฆบ**, โ™’๏ธ. +โšซ๏ธ ๐Ÿ’ช **โ˜** ๐Ÿ”—, **โ˜ โœ**, **Kubernetes**, **โ˜ ๐Ÿ•โ€๐Ÿฆบ**, โ™’๏ธ. ๐ŸŒ… (โš–๏ธ ๐ŸŒ) ๐Ÿ’ผ, ๐Ÿ“ค ๐Ÿ™… ๐ŸŽ› ๐Ÿ› ๏ธ ๐Ÿƒ ๐Ÿ“ฆ ๐Ÿ”› ๐Ÿ•ด & ๐Ÿ› ๏ธ โ ๐Ÿ”› โŒ. ๐Ÿ–ผ, โ˜, โšซ๏ธ ๐Ÿ“‹ โธ ๐ŸŽ› `--restart`. @@ -413,7 +413,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] ๐Ÿšฅ ๐Ÿ‘† โœ”๏ธ ๐ŸŒ‘ ๐ŸŽฐ โฎ๏ธ **โ˜**, โ˜ ๐Ÿ ๐Ÿ“ณ, ๐Ÿ––, โš–๏ธ โž•1๏ธโƒฃ ๐ŸŽ ๐Ÿ— โš™๏ธ ๐Ÿ› ๏ธ ๐Ÿ“Ž ๐Ÿ“ฆ ๐Ÿ”› ๐Ÿ’— ๐ŸŽฐ, โคด๏ธ ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ’š **๐Ÿต ๐Ÿงฌ** **๐ŸŒ‘ ๐ŸŽš** โ†ฉ๏ธ โš™๏ธ **๐Ÿ› ๏ธ ๐Ÿ‘จโ€๐Ÿ’ผ** (๐Ÿ’– ๐Ÿ โฎ๏ธ ๐Ÿ‘จโ€๐Ÿญ) ๐Ÿ”  ๐Ÿ“ฆ. -1๏ธโƒฃ ๐Ÿ“š ๐Ÿ“Ž ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ ๐Ÿ’– Kubernete ๐Ÿ›Ž โœ”๏ธ ๐Ÿ› ๏ธ ๐ŸŒŒ ๐Ÿšš **๐Ÿงฌ ๐Ÿ“ฆ** โช ๐Ÿ”— **๐Ÿ“ โš–** ๐Ÿ“จ ๐Ÿ“จ. ๐ŸŒ **๐ŸŒ‘ ๐ŸŽš**. +1๏ธโƒฃ ๐Ÿ“š ๐Ÿ“Ž ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ ๐Ÿ’– Kubernetes ๐Ÿ›Ž โœ”๏ธ ๐Ÿ› ๏ธ ๐ŸŒŒ ๐Ÿšš **๐Ÿงฌ ๐Ÿ“ฆ** โช ๐Ÿ”— **๐Ÿ“ โš–** ๐Ÿ“จ ๐Ÿ“จ. ๐ŸŒ **๐ŸŒ‘ ๐ŸŽš**. ๐Ÿ“š ๐Ÿ’ผ, ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ’š ๐Ÿ— **โ˜ ๐Ÿ–ผ โšช๏ธโžก๏ธ ๐Ÿ–Œ** [๐Ÿ”ฌ ๐Ÿ”›](#dockerfile), โŽ ๐Ÿ‘† ๐Ÿ”—, & ๐Ÿƒโ€โ™‚ **๐Ÿ‘ Uvicorn ๐Ÿ› ๏ธ** โ†ฉ๏ธ ๐Ÿƒโ€โ™‚ ๐Ÿ•ณ ๐Ÿ’– ๐Ÿ โฎ๏ธ Uvicorn ๐Ÿ‘จโ€๐Ÿญ. @@ -430,7 +430,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] ### 1๏ธโƒฃ ๐Ÿ“ โš™ - ๐Ÿ’— ๐Ÿ‘จโ€๐Ÿญ ๐Ÿ“ฆ -๐Ÿ•โ” ๐Ÿ‘ท โฎ๏ธ **Kubernete** โš–๏ธ ๐ŸŽ ๐Ÿ“Ž ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ, โš™๏ธ ๐Ÿ‘ซ ๐Ÿ”— ๐Ÿ•ธ ๐Ÿ› ๏ธ ๐Ÿ”œ โœ” ๐Ÿ‘ **๐Ÿ“ โš™** ๐Ÿ‘ˆ ๐Ÿ‘‚ ๐Ÿ”› ๐Ÿ‘‘ **โ›ด** ๐Ÿ“ถ ๐Ÿ“ป (๐Ÿ“จ) ๐ŸŽฒ **๐Ÿ’— ๐Ÿ“ฆ** ๐Ÿƒ ๐Ÿ‘† ๐Ÿ“ฑ. +๐Ÿ•โ” ๐Ÿ‘ท โฎ๏ธ **Kubernetes** โš–๏ธ ๐ŸŽ ๐Ÿ“Ž ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ, โš™๏ธ ๐Ÿ‘ซ ๐Ÿ”— ๐Ÿ•ธ ๐Ÿ› ๏ธ ๐Ÿ”œ โœ” ๐Ÿ‘ **๐Ÿ“ โš™** ๐Ÿ‘ˆ ๐Ÿ‘‚ ๐Ÿ”› ๐Ÿ‘‘ **โ›ด** ๐Ÿ“ถ ๐Ÿ“ป (๐Ÿ“จ) ๐ŸŽฒ **๐Ÿ’— ๐Ÿ“ฆ** ๐Ÿƒ ๐Ÿ‘† ๐Ÿ“ฑ. ๐Ÿ”  ๐Ÿ‘ซ ๐Ÿ“ฆ ๐Ÿƒโ€โ™‚ ๐Ÿ‘† ๐Ÿ“ฑ ๐Ÿ”œ ๐Ÿ›Ž โœ”๏ธ **1๏ธโƒฃ ๐Ÿ› ๏ธ** (โœ… Uvicorn ๐Ÿ› ๏ธ ๐Ÿƒ ๐Ÿ‘† FastAPI ๐Ÿˆธ). ๐Ÿ‘ซ ๐Ÿ”œ ๐ŸŒ **๐ŸŒ“ ๐Ÿ“ฆ**, ๐Ÿƒโ€โ™‚ ๐ŸŽ ๐Ÿ‘œ, โœ‹๏ธ ๐Ÿ”  โฎ๏ธ ๐Ÿšฎ ๐Ÿ‘ ๐Ÿ› ๏ธ, ๐Ÿ’พ, โ™’๏ธ. ๐Ÿ‘ˆ ๐ŸŒŒ ๐Ÿ‘† ๐Ÿ”œ โœŠ ๐Ÿ“ˆ **๐Ÿ› ๏ธ** **๐ŸŽ ๐Ÿš** ๐Ÿ’ฝ, โš–๏ธ **๐ŸŽ ๐ŸŽฐ**. @@ -489,7 +489,7 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] ๐Ÿšฅ ๐Ÿ‘† ๐Ÿƒ **๐Ÿ‘ ๐Ÿ› ๏ธ ๐Ÿ“ ๐Ÿ“ฆ** ๐Ÿ‘† ๐Ÿ”œ โœ”๏ธ ๐ŸŒ… โš–๏ธ ๐ŸŒ˜ ๐Ÿ‘-๐Ÿ”ฌ, โš–, & ๐Ÿ“‰ ๐Ÿ’ธ ๐Ÿ’พ ๐Ÿด ๐Ÿ”  ๐Ÿ‘ˆ ๐Ÿ“ฆ (๐ŸŒ… ๐ŸŒ˜ 1๏ธโƒฃ ๐Ÿšฅ ๐Ÿ‘ซ ๐Ÿ”). -& โคด๏ธ ๐Ÿ‘† ๐Ÿ’ช โš’ ๐Ÿ‘ˆ ๐ŸŽ ๐Ÿ’พ ๐Ÿ“‰ & ๐Ÿ“„ ๐Ÿ‘† ๐Ÿ“ณ ๐Ÿ‘† ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ (๐Ÿ–ผ **Kubernete**). ๐Ÿ‘ˆ ๐ŸŒŒ โšซ๏ธ ๐Ÿ”œ ๐Ÿ’ช **๐Ÿ” ๐Ÿ“ฆ** **๐Ÿ’ช ๐ŸŽฐ** โœŠ ๐Ÿ”˜ ๐Ÿง ๐Ÿ’ธ ๐Ÿ’พ ๐Ÿ’ช ๐Ÿ‘ซ, & ๐Ÿ’ธ ๐Ÿ’ช ๐ŸŽฐ ๐ŸŒ‘. +& โคด๏ธ ๐Ÿ‘† ๐Ÿ’ช โš’ ๐Ÿ‘ˆ ๐ŸŽ ๐Ÿ’พ ๐Ÿ“‰ & ๐Ÿ“„ ๐Ÿ‘† ๐Ÿ“ณ ๐Ÿ‘† ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ (๐Ÿ–ผ **Kubernetes**). ๐Ÿ‘ˆ ๐ŸŒŒ โšซ๏ธ ๐Ÿ”œ ๐Ÿ’ช **๐Ÿ” ๐Ÿ“ฆ** **๐Ÿ’ช ๐ŸŽฐ** โœŠ ๐Ÿ”˜ ๐Ÿง ๐Ÿ’ธ ๐Ÿ’พ ๐Ÿ’ช ๐Ÿ‘ซ, & ๐Ÿ’ธ ๐Ÿ’ช ๐ŸŽฐ ๐ŸŒ‘. ๐Ÿšฅ ๐Ÿ‘† ๐Ÿˆธ **๐Ÿ™…**, ๐Ÿ‘‰ ๐Ÿ”œ ๐ŸŽฒ **๐Ÿšซ โš **, & ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšซ ๐Ÿ’ช โœ” ๐Ÿ‹๏ธ ๐Ÿ’พ ๐Ÿ“‰. โœ‹๏ธ ๐Ÿšฅ ๐Ÿ‘† **โš™๏ธ ๐Ÿ“š ๐Ÿ’พ** (๐Ÿ–ผ โฎ๏ธ **๐ŸŽฐ ๐Ÿซ** ๐Ÿท), ๐Ÿ‘† ๐Ÿ”œ โœ… โ” ๐ŸŒ… ๐Ÿ’พ ๐Ÿ‘† ๐Ÿ˜ฉ & ๐Ÿ”† **๐Ÿ”ข ๐Ÿ“ฆ** ๐Ÿ‘ˆ ๐Ÿƒ **๐Ÿ”  ๐ŸŽฐ** (& ๐ŸŽฒ ๐Ÿšฎ ๐ŸŒ– ๐ŸŽฐ ๐Ÿ‘† ๐ŸŒ‘). @@ -497,14 +497,14 @@ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"] ## โฎ๏ธ ๐Ÿ” โญ โ–ถ๏ธ & ๐Ÿ“ฆ -๐Ÿšฅ ๐Ÿ‘† โš™๏ธ ๐Ÿ“ฆ (โœ… โ˜, Kubernete), โคด๏ธ ๐Ÿ“ค 2๏ธโƒฃ ๐Ÿ‘‘ ๐ŸŽฏ ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ. +๐Ÿšฅ ๐Ÿ‘† โš™๏ธ ๐Ÿ“ฆ (โœ… โ˜, Kubernetes), โคด๏ธ ๐Ÿ“ค 2๏ธโƒฃ ๐Ÿ‘‘ ๐ŸŽฏ ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ. ### ๐Ÿ’— ๐Ÿ“ฆ -๐Ÿšฅ ๐Ÿ‘† โœ”๏ธ **๐Ÿ’— ๐Ÿ“ฆ**, ๐ŸŽฒ ๐Ÿ”  1๏ธโƒฃ ๐Ÿƒ **๐Ÿ‘ ๐Ÿ› ๏ธ** (๐Ÿ–ผ, **Kubernete** ๐ŸŒ‘), โคด๏ธ ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ’š โœ”๏ธ **๐ŸŽ ๐Ÿ“ฆ** ๐Ÿ”จ ๐Ÿ‘ท **โฎ๏ธ ๐Ÿ“ถ** ๐Ÿ‘ ๐Ÿ“ฆ, ๐Ÿƒ ๐Ÿ‘ ๐Ÿ› ๏ธ, **โญ** ๐Ÿƒ ๐Ÿ” ๐Ÿ‘จโ€๐Ÿญ ๐Ÿ“ฆ. +๐Ÿšฅ ๐Ÿ‘† โœ”๏ธ **๐Ÿ’— ๐Ÿ“ฆ**, ๐ŸŽฒ ๐Ÿ”  1๏ธโƒฃ ๐Ÿƒ **๐Ÿ‘ ๐Ÿ› ๏ธ** (๐Ÿ–ผ, **Kubernetes** ๐ŸŒ‘), โคด๏ธ ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ’š โœ”๏ธ **๐ŸŽ ๐Ÿ“ฆ** ๐Ÿ”จ ๐Ÿ‘ท **โฎ๏ธ ๐Ÿ“ถ** ๐Ÿ‘ ๐Ÿ“ฆ, ๐Ÿƒ ๐Ÿ‘ ๐Ÿ› ๏ธ, **โญ** ๐Ÿƒ ๐Ÿ” ๐Ÿ‘จโ€๐Ÿญ ๐Ÿ“ฆ. !!! info - ๐Ÿšฅ ๐Ÿ‘† โš™๏ธ Kubernete, ๐Ÿ‘‰ ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ•‘ ๐Ÿ“ฆ. + ๐Ÿšฅ ๐Ÿ‘† โš™๏ธ Kubernetes, ๐Ÿ‘‰ ๐Ÿ”œ ๐ŸŽฒ ๐Ÿ•‘ ๐Ÿ“ฆ. ๐Ÿšฅ ๐Ÿ‘† โš™๏ธ ๐Ÿ’ผ ๐Ÿ“ค ๐Ÿ™…โ€โ™‚ โš  ๐Ÿƒโ€โ™‚ ๐Ÿ‘ˆ โฎ๏ธ ๐Ÿ“ถ **๐Ÿ’— ๐Ÿ•ฐ ๐Ÿ”—** (๐Ÿ–ผ ๐Ÿšฅ ๐Ÿ‘† ๐Ÿšซ ๐Ÿƒ ๐Ÿ’ฝ ๐Ÿ› ๏ธ, โœ‹๏ธ โœ… ๐Ÿšฅ ๐Ÿ’ฝ ๐Ÿ”œ), โคด๏ธ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšฎ ๐Ÿ‘ซ ๐Ÿ”  ๐Ÿ“ฆ โ–ถ๏ธ๏ธ โญ โ–ถ๏ธ ๐Ÿ‘‘ ๐Ÿ› ๏ธ. @@ -574,7 +574,7 @@ COPY ./app /app/app ### ๐Ÿ•โ” โš™๏ธ -๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ **๐Ÿšซ** โš™๏ธ ๐Ÿ‘‰ ๐Ÿ›‚ ๐Ÿงข ๐Ÿ–ผ (โš–๏ธ ๐Ÿ™† ๐ŸŽ ๐ŸŽ 1๏ธโƒฃ) ๐Ÿšฅ ๐Ÿ‘† โš™๏ธ **Kubernete** (โš–๏ธ ๐ŸŽ) & ๐Ÿ‘† โช โš’ **๐Ÿงฌ** ๐ŸŒ‘ ๐ŸŽš, โฎ๏ธ ๐Ÿ’— **๐Ÿ“ฆ**. ๐Ÿ“š ๐Ÿ’ผ, ๐Ÿ‘† ๐Ÿ‘ ๐Ÿ“† **๐Ÿ— ๐Ÿ–ผ โšช๏ธโžก๏ธ ๐Ÿ–Œ** ๐Ÿ”ฌ ๐Ÿ”›: [๐Ÿ— โ˜ ๐Ÿ–ผ FastAPI](#build-a-docker-image-for-fastapi). +๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ **๐Ÿšซ** โš™๏ธ ๐Ÿ‘‰ ๐Ÿ›‚ ๐Ÿงข ๐Ÿ–ผ (โš–๏ธ ๐Ÿ™† ๐ŸŽ ๐ŸŽ 1๏ธโƒฃ) ๐Ÿšฅ ๐Ÿ‘† โš™๏ธ **Kubernetes** (โš–๏ธ ๐ŸŽ) & ๐Ÿ‘† โช โš’ **๐Ÿงฌ** ๐ŸŒ‘ ๐ŸŽš, โฎ๏ธ ๐Ÿ’— **๐Ÿ“ฆ**. ๐Ÿ“š ๐Ÿ’ผ, ๐Ÿ‘† ๐Ÿ‘ ๐Ÿ“† **๐Ÿ— ๐Ÿ–ผ โšช๏ธโžก๏ธ ๐Ÿ–Œ** ๐Ÿ”ฌ ๐Ÿ”›: [๐Ÿ— โ˜ ๐Ÿ–ผ FastAPI](#build-a-docker-image-for-fastapi). ๐Ÿ‘‰ ๐Ÿ–ผ ๐Ÿ”œ โš  โœด๏ธ ๐ŸŽ ๐Ÿ’ผ ๐Ÿ”ฌ ๐Ÿ”› [๐Ÿ“ฆ โฎ๏ธ ๐Ÿ’— ๐Ÿ› ๏ธ & ๐ŸŽ ๐Ÿ’ผ](#containers-with-multiple-processes-and-special-cases). ๐Ÿ–ผ, ๐Ÿšฅ ๐Ÿ‘† ๐Ÿˆธ **๐Ÿ™… ๐Ÿฅƒ** ๐Ÿ‘ˆ โš’ ๐Ÿ”ข ๐Ÿ”ข ๐Ÿ› ๏ธ โš“๏ธ ๐Ÿ”› ๐Ÿ’ฝ ๐Ÿ‘ท ๐Ÿ‘, ๐Ÿ‘† ๐Ÿšซ ๐Ÿ’š ๐Ÿ˜ฅ โฎ๏ธ โŽ ๐Ÿ› ๏ธ ๐Ÿงฌ ๐ŸŒ‘ ๐ŸŽš, & ๐Ÿ‘† ๐Ÿšซ ๐Ÿƒ ๐ŸŒ… ๐ŸŒ˜ 1๏ธโƒฃ ๐Ÿ“ฆ โฎ๏ธ ๐Ÿ‘† ๐Ÿ“ฑ. โš–๏ธ ๐Ÿšฅ ๐Ÿ‘† ๐Ÿ› ๏ธ โฎ๏ธ **โ˜ โœ**, ๐Ÿƒ ๐Ÿ”› ๐Ÿ‘ ๐Ÿ’ฝ, โ™’๏ธ. @@ -585,7 +585,7 @@ COPY ./app /app/app ๐Ÿ–ผ: * โฎ๏ธ **โ˜ โœ** ๐Ÿ‘ ๐Ÿ’ฝ -* โฎ๏ธ **Kubernete** ๐ŸŒ‘ +* โฎ๏ธ **Kubernetes** ๐ŸŒ‘ * โฎ๏ธ โ˜ ๐Ÿ ๐Ÿ“ณ ๐ŸŒ‘ * โฎ๏ธ โž•1๏ธโƒฃ ๐Ÿงฐ ๐Ÿ’– ๐Ÿ–– * โฎ๏ธ โ˜ ๐Ÿ•โ€๐Ÿฆบ ๐Ÿ‘ˆ โœŠ ๐Ÿ‘† ๐Ÿ“ฆ ๐Ÿ–ผ & ๐Ÿ› ๏ธ โšซ๏ธ @@ -682,7 +682,7 @@ CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port" ## ๐ŸŒƒ -โš™๏ธ ๐Ÿ“ฆ โš™๏ธ (โœ… โฎ๏ธ **โ˜** & **Kubernete**) โšซ๏ธ โ–ถ๏ธ๏ธ ๐Ÿ“ถ ๐ŸŽฏ ๐Ÿต ๐ŸŒ **๐Ÿ› ๏ธ ๐Ÿ”ง**: +โš™๏ธ ๐Ÿ“ฆ โš™๏ธ (โœ… โฎ๏ธ **โ˜** & **Kubernetes**) โšซ๏ธ โ–ถ๏ธ๏ธ ๐Ÿ“ถ ๐ŸŽฏ ๐Ÿต ๐ŸŒ **๐Ÿ› ๏ธ ๐Ÿ”ง**: * ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ” * ๐Ÿƒโ€โ™‚ ๐Ÿ”› ๐Ÿ•ด diff --git a/docs/em/docs/deployment/server-workers.md b/docs/em/docs/deployment/server-workers.md index ca068d744..b7e58c4f4 100644 --- a/docs/em/docs/deployment/server-workers.md +++ b/docs/em/docs/deployment/server-workers.md @@ -18,9 +18,9 @@ ๐Ÿ“ฅ ๐Ÿ‘ค ๐Ÿ”œ ๐ŸŽฆ ๐Ÿ‘† โ” โš™๏ธ **๐Ÿ** โฎ๏ธ **Uvicorn ๐Ÿ‘จโ€๐Ÿญ ๐Ÿ› ๏ธ**. !!! info - ๐Ÿšฅ ๐Ÿ‘† โš™๏ธ ๐Ÿ“ฆ, ๐Ÿ–ผ โฎ๏ธ โ˜ โš–๏ธ Kubernete, ๐Ÿ‘ค ๐Ÿ”œ ๐Ÿ’ฌ ๐Ÿ‘† ๐ŸŒ… ๐Ÿ”ƒ ๐Ÿ‘ˆ โญ ๐Ÿ“ƒ: [FastAPI ๐Ÿ“ฆ - โ˜](./docker.md){.internal-link target=_blank}. + ๐Ÿšฅ ๐Ÿ‘† โš™๏ธ ๐Ÿ“ฆ, ๐Ÿ–ผ โฎ๏ธ โ˜ โš–๏ธ Kubernetes, ๐Ÿ‘ค ๐Ÿ”œ ๐Ÿ’ฌ ๐Ÿ‘† ๐ŸŒ… ๐Ÿ”ƒ ๐Ÿ‘ˆ โญ ๐Ÿ“ƒ: [FastAPI ๐Ÿ“ฆ - โ˜](./docker.md){.internal-link target=_blank}. - ๐ŸŽฏ, ๐Ÿ•โ” ๐Ÿƒ ๐Ÿ”› **Kubernete** ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ **๐Ÿšซ** ๐Ÿ’š โš™๏ธ ๐Ÿ & โ†ฉ๏ธ ๐Ÿƒ **๐Ÿ‘ Uvicorn ๐Ÿ› ๏ธ ๐Ÿ“ ๐Ÿ“ฆ**, โœ‹๏ธ ๐Ÿ‘ค ๐Ÿ”œ ๐Ÿ’ฌ ๐Ÿ‘† ๐Ÿ”ƒ โšซ๏ธ โช ๐Ÿ‘ˆ ๐Ÿ“ƒ. + ๐ŸŽฏ, ๐Ÿ•โ” ๐Ÿƒ ๐Ÿ”› **Kubernetes** ๐Ÿ‘† ๐Ÿ”œ ๐ŸŽฒ **๐Ÿšซ** ๐Ÿ’š โš™๏ธ ๐Ÿ & โ†ฉ๏ธ ๐Ÿƒ **๐Ÿ‘ Uvicorn ๐Ÿ› ๏ธ ๐Ÿ“ ๐Ÿ“ฆ**, โœ‹๏ธ ๐Ÿ‘ค ๐Ÿ”œ ๐Ÿ’ฌ ๐Ÿ‘† ๐Ÿ”ƒ โšซ๏ธ โช ๐Ÿ‘ˆ ๐Ÿ“ƒ. ## ๐Ÿ โฎ๏ธ Uvicorn ๐Ÿ‘จโ€๐Ÿญ @@ -167,7 +167,7 @@ $ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4 ๐Ÿ‘ค ๐Ÿ”œ ๐ŸŽฆ ๐Ÿ‘† **๐Ÿ›‚ โ˜ ๐Ÿ–ผ** ๐Ÿ‘ˆ ๐Ÿ”Œ **๐Ÿ โฎ๏ธ Uvicorn ๐Ÿ‘จโ€๐Ÿญ** & ๐Ÿ”ข ๐Ÿ“ณ ๐Ÿ‘ˆ ๐Ÿ’ช โš  ๐Ÿ™… ๐Ÿ’ผ. -๐Ÿ“ค ๐Ÿ‘ค ๐Ÿ”œ ๐ŸŽฆ ๐Ÿ‘† โ” **๐Ÿ— ๐Ÿ‘† ๐Ÿ‘ ๐Ÿ–ผ โšช๏ธโžก๏ธ ๐Ÿ–Œ** ๐Ÿƒ ๐Ÿ‘ Uvicorn ๐Ÿ› ๏ธ (๐Ÿต ๐Ÿ). โšซ๏ธ ๐Ÿ™… ๐Ÿ› ๏ธ & ๐ŸŽฒ โšซ๏ธโ” ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’š ๐Ÿ•โ” โš™๏ธ ๐Ÿ“Ž ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ ๐Ÿ’– **Kubernete**. +๐Ÿ“ค ๐Ÿ‘ค ๐Ÿ”œ ๐ŸŽฆ ๐Ÿ‘† โ” **๐Ÿ— ๐Ÿ‘† ๐Ÿ‘ ๐Ÿ–ผ โšช๏ธโžก๏ธ ๐Ÿ–Œ** ๐Ÿƒ ๐Ÿ‘ Uvicorn ๐Ÿ› ๏ธ (๐Ÿต ๐Ÿ). โšซ๏ธ ๐Ÿ™… ๐Ÿ› ๏ธ & ๐ŸŽฒ โšซ๏ธโ” ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ’š ๐Ÿ•โ” โš™๏ธ ๐Ÿ“Ž ๐Ÿ“ฆ ๐Ÿงพ โš™๏ธ ๐Ÿ’– **Kubernetes**. ## ๐ŸŒƒ @@ -175,4 +175,4 @@ $ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4 ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿ‘‰ ๐Ÿงฐ & ๐Ÿ’ญ ๐Ÿšฅ ๐Ÿ‘† โš’ ๐Ÿ†™ **๐Ÿ‘† ๐Ÿ‘ ๐Ÿ› ๏ธ โš™๏ธ** โช โœŠ ๐Ÿ’… ๐ŸŽ ๐Ÿ› ๏ธ ๐Ÿ”ง ๐Ÿ‘†. -โœ… ๐Ÿ‘… โญ ๐Ÿ“ƒ ๐Ÿ’ก ๐Ÿ”ƒ **FastAPI** โฎ๏ธ ๐Ÿ“ฆ (โœ… โ˜ & Kubernete). ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ‘ˆ ๐Ÿ‘ˆ ๐Ÿงฐ โœ”๏ธ ๐Ÿ™… ๐ŸŒŒ โŽ ๐ŸŽ **๐Ÿ› ๏ธ ๐Ÿ”ง** ๐Ÿ‘. ๐Ÿ‘ถ +โœ… ๐Ÿ‘… โญ ๐Ÿ“ƒ ๐Ÿ’ก ๐Ÿ”ƒ **FastAPI** โฎ๏ธ ๐Ÿ“ฆ (โœ… โ˜ & Kubernetes). ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ‘ˆ ๐Ÿ‘ˆ ๐Ÿงฐ โœ”๏ธ ๐Ÿ™… ๐ŸŒŒ โŽ ๐ŸŽ **๐Ÿ› ๏ธ ๐Ÿ”ง** ๐Ÿ‘. ๐Ÿ‘ถ diff --git a/docs/em/docs/external-links.md b/docs/em/docs/external-links.md index 4440b1f12..5ba668bfa 100644 --- a/docs/em/docs/external-links.md +++ b/docs/em/docs/external-links.md @@ -11,77 +11,21 @@ ## ๐Ÿ“„ -### ๐Ÿ‡ช๐Ÿ‡ธ +{% for section_name, section_content in external_links.items() %} -{% if external_links %} -{% for article in external_links.articles.english %} +## {{ section_name }} + +{% for lang_name, lang_content in section_content.items() %} + +### {{ lang_name }} + +{% for item in lang_content %} + +* {{ item.title }} by {{ item.author }}. -* {{ article.title }} {{ article.author }}. {% endfor %} -{% endif %} - -### ๐Ÿ‡ฏ๐Ÿ‡ต - -{% if external_links %} -{% for article in external_links.articles.japanese %} - -* {{ article.title }} {{ article.author }}. {% endfor %} -{% endif %} - -### ๐Ÿ‡ป๐Ÿ‡ณ - -{% if external_links %} -{% for article in external_links.articles.vietnamese %} - -* {{ article.title }} {{ article.author }}. {% endfor %} -{% endif %} - -### ๐Ÿ‡ท๐Ÿ‡บ - -{% if external_links %} -{% for article in external_links.articles.russian %} - -* {{ article.title }} {{ article.author }}. -{% endfor %} -{% endif %} - -### ๐Ÿ‡ฉ๐Ÿ‡ช - -{% if external_links %} -{% for article in external_links.articles.german %} - -* {{ article.title }} {{ article.author }}. -{% endfor %} -{% endif %} - -### ๐Ÿ‡น๐Ÿ‡ผ - -{% if external_links %} -{% for article in external_links.articles.taiwanese %} - -* {{ article.title }} {{ article.author }}. -{% endfor %} -{% endif %} - -## ๐Ÿ“ป - -{% if external_links %} -{% for article in external_links.podcasts.english %} - -* {{ article.title }} {{ article.author }}. -{% endfor %} -{% endif %} - -## ๐Ÿ’ฌ - -{% if external_links %} -{% for article in external_links.talks.english %} - -* {{ article.title }} {{ article.author }}. -{% endfor %} -{% endif %} ## ๐Ÿ— diff --git a/docs/em/docs/help-fastapi.md b/docs/em/docs/help-fastapi.md index d7b66185d..b998ade42 100644 --- a/docs/em/docs/help-fastapi.md +++ b/docs/em/docs/help-fastapi.md @@ -231,8 +231,6 @@ โš™๏ธ ๐Ÿ’ฌ ๐Ÿ•ด ๐ŸŽ ๐Ÿข ๐Ÿ’ฌ. -๐Ÿ“ค โฎ๏ธ ๐ŸฅŠ ๐Ÿ’ฌ, โœ‹๏ธ โšซ๏ธ ๐Ÿšซ โœ”๏ธ ๐Ÿ“ป & ๐Ÿง โš’, ๐Ÿ’ฌ ๐ŸŒ– โš , ๐Ÿ˜ง ๐Ÿ”œ ๐Ÿ‘ โš™๏ธ. - ### ๐Ÿšซ โš™๏ธ ๐Ÿ’ฌ โ” โœ”๏ธ ๐Ÿคฏ ๐Ÿ‘ˆ ๐Ÿ’ฌ โœ” ๐ŸŒ… "๐Ÿ†“ ๐Ÿ’ฌ", โšซ๏ธ โฉ ๐Ÿ’ญ โ” ๐Ÿ‘ˆ ๐Ÿ’โ€โ™‚๏ธ ๐Ÿข & ๐ŸŒ… โš  โ”,, ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšซ ๐Ÿ“จ โ”. diff --git a/docs/em/docs/advanced/conditional-openapi.md b/docs/em/docs/how-to/conditional-openapi.md similarity index 100% rename from docs/em/docs/advanced/conditional-openapi.md rename to docs/em/docs/how-to/conditional-openapi.md diff --git a/docs/em/docs/advanced/custom-request-and-route.md b/docs/em/docs/how-to/custom-request-and-route.md similarity index 100% rename from docs/em/docs/advanced/custom-request-and-route.md rename to docs/em/docs/how-to/custom-request-and-route.md diff --git a/docs/em/docs/how-to/extending-openapi.md b/docs/em/docs/how-to/extending-openapi.md new file mode 100644 index 000000000..6b3bc0075 --- /dev/null +++ b/docs/em/docs/how-to/extending-openapi.md @@ -0,0 +1,90 @@ +# โ†” ๐Ÿ—„ + +!!! warning + ๐Ÿ‘‰ ๐Ÿ‘ ๐Ÿง โš’. ๐Ÿ‘† ๐ŸŽฒ ๐Ÿ’ช ๐Ÿšถ โšซ๏ธ. + + ๐Ÿšฅ ๐Ÿ‘† ๐Ÿ“„ ๐Ÿ”ฐ - ๐Ÿ‘ฉโ€๐Ÿ’ป ๐Ÿฆฎ, ๐Ÿ‘† ๐Ÿ’ช ๐ŸŽฒ ๐Ÿšถ ๐Ÿ‘‰ ๐Ÿ“„. + + ๐Ÿšฅ ๐Ÿ‘† โช ๐Ÿ’ญ ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ”€ ๐Ÿ— ๐Ÿ—„ ๐Ÿ”—, ๐Ÿ˜ฃ ๐Ÿ‘‚. + +๐Ÿ“ค ๐Ÿ’ผ ๐ŸŒโ” ๐Ÿ‘† ๐Ÿ’ช ๐Ÿ’ช ๐Ÿ”€ ๐Ÿ— ๐Ÿ—„ ๐Ÿ”—. + +๐Ÿ‘‰ ๐Ÿ“„ ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ โ”. + +## ๐Ÿ˜ ๐Ÿ› ๏ธ + +๐Ÿ˜ (๐Ÿ”ข) ๐Ÿ› ๏ธ, โฉ. + +`FastAPI` ๐Ÿˆธ (๐Ÿ‘) โœ”๏ธ `.openapi()` ๐Ÿ‘ฉโ€๐Ÿ”ฌ ๐Ÿ‘ˆ ๐Ÿ“ˆ ๐Ÿ“จ ๐Ÿ—„ ๐Ÿ”—. + +๐Ÿ• ๐Ÿˆธ ๐ŸŽš ๐Ÿ—, *โžก ๐Ÿ› ๏ธ* `/openapi.json` (โš–๏ธ โšซ๏ธโ” ๐Ÿ‘† โš’ ๐Ÿ‘† `openapi_url`) ยฎ. + +โšซ๏ธ ๐Ÿ“จ ๐ŸŽป ๐Ÿ“จ โฎ๏ธ ๐Ÿ ๐Ÿˆธ `.openapi()` ๐Ÿ‘ฉโ€๐Ÿ”ฌ. + +๐Ÿ”ข, โšซ๏ธโ” ๐Ÿ‘ฉโ€๐Ÿ”ฌ `.openapi()` ๐Ÿ”จ โœ… ๐Ÿ  `.openapi_schema` ๐Ÿ‘€ ๐Ÿšฅ โšซ๏ธ โœ”๏ธ ๐ŸŽš & ๐Ÿ“จ ๐Ÿ‘ซ. + +๐Ÿšฅ โšซ๏ธ ๐Ÿšซ, โšซ๏ธ ๐Ÿ— ๐Ÿ‘ซ โš™๏ธ ๐Ÿš™ ๐Ÿ”ข `fastapi.openapi.utils.get_openapi`. + +& ๐Ÿ‘ˆ ๐Ÿ”ข `get_openapi()` ๐Ÿ“จ ๐Ÿ”ข: + +* `title`: ๐Ÿ—„ ๐Ÿ“›, ๐ŸŽฆ ๐Ÿฉบ. +* `version`: โฌ ๐Ÿ‘† ๐Ÿ› ๏ธ, โœ… `2.5.0`. +* `openapi_version`: โฌ ๐Ÿ—„ ๐Ÿ”ง โš™๏ธ. ๐Ÿ”ข, โช: `3.0.2`. +* `description`: ๐Ÿ“› ๐Ÿ‘† ๐Ÿ› ๏ธ. +* `routes`: ๐Ÿ“‡ ๐Ÿ›ฃ, ๐Ÿ‘ซ ๐Ÿ”  ยฎ *โžก ๐Ÿ› ๏ธ*. ๐Ÿ‘ซ โœŠ โšช๏ธโžก๏ธ `app.routes`. + +## ๐Ÿ”‘ ๐Ÿ”ข + +โš™๏ธ โ„น ๐Ÿ”›, ๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐ŸŽ ๐Ÿš™ ๐Ÿ”ข ๐Ÿ— ๐Ÿ—„ ๐Ÿ”— & ๐Ÿ” ๐Ÿ”  ๐Ÿ• ๐Ÿ‘ˆ ๐Ÿ‘† ๐Ÿ’ช. + +๐Ÿ–ผ, โžก๏ธ ๐Ÿšฎ ๐Ÿ“„ ๐Ÿ—„ โ†” ๐Ÿ”Œ ๐Ÿ›ƒ ๐Ÿ”ฑ. + +### ๐Ÿ˜ **FastAPI** + +๐Ÿฅ‡, โœ ๐ŸŒ ๐Ÿ‘† **FastAPI** ๐Ÿˆธ ๐Ÿ›Ž: + +```Python hl_lines="1 4 7-9" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### ๐Ÿ— ๐Ÿ—„ ๐Ÿ”— + +โคด๏ธ, โš™๏ธ ๐ŸŽ ๐Ÿš™ ๐Ÿ”ข ๐Ÿ— ๐Ÿ—„ ๐Ÿ”—, ๐Ÿ”˜ `custom_openapi()` ๐Ÿ”ข: + +```Python hl_lines="2 15-20" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### ๐Ÿ”€ ๐Ÿ—„ ๐Ÿ”— + +๐Ÿ”œ ๐Ÿ‘† ๐Ÿ’ช ๐Ÿšฎ ๐Ÿ“„ โ†”, โŽ ๐Ÿ›ƒ `x-logo` `info` "๐ŸŽš" ๐Ÿ—„ ๐Ÿ”—: + +```Python hl_lines="21-23" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### ๐Ÿ’พ ๐Ÿ—„ ๐Ÿ”— + +๐Ÿ‘† ๐Ÿ’ช โš™๏ธ ๐Ÿ  `.openapi_schema` "๐Ÿ’พ", ๐Ÿช ๐Ÿ‘† ๐Ÿ— ๐Ÿ”—. + +๐Ÿ‘ˆ ๐ŸŒŒ, ๐Ÿ‘† ๐Ÿˆธ ๐Ÿ† ๐Ÿšซ โœ”๏ธ ๐Ÿ— ๐Ÿ”— ๐Ÿ”  ๐Ÿ•ฐ ๐Ÿ‘ฉโ€๐Ÿ’ป ๐Ÿ“‚ ๐Ÿ‘† ๐Ÿ› ๏ธ ๐Ÿฉบ. + +โšซ๏ธ ๐Ÿ”œ ๐Ÿ— ๐Ÿ•ด ๐Ÿ•, & โคด๏ธ ๐ŸŽ ๐Ÿ’พ ๐Ÿ”— ๐Ÿ”œ โš™๏ธ โญ ๐Ÿ“จ. + +```Python hl_lines="13-14 24-25" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### ๐Ÿ” ๐Ÿ‘ฉโ€๐Ÿ”ฌ + +๐Ÿ”œ ๐Ÿ‘† ๐Ÿ’ช โŽ `.openapi()` ๐Ÿ‘ฉโ€๐Ÿ”ฌ โฎ๏ธ ๐Ÿ‘† ๐Ÿ†• ๐Ÿ”ข. + +```Python hl_lines="28" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### โœ… โšซ๏ธ + +๐Ÿ• ๐Ÿ‘† ๐Ÿšถ http://127.0.0.1:8000/redoc ๐Ÿ‘† ๐Ÿ”œ ๐Ÿ‘€ ๐Ÿ‘ˆ ๐Ÿ‘† โš™๏ธ ๐Ÿ‘† ๐Ÿ›ƒ ๐Ÿ”ฑ (๐Ÿ‘‰ ๐Ÿ–ผ, **FastAPI**'โ“‚ ๐Ÿ”ฑ): + + diff --git a/docs/em/docs/advanced/graphql.md b/docs/em/docs/how-to/graphql.md similarity index 100% rename from docs/em/docs/advanced/graphql.md rename to docs/em/docs/how-to/graphql.md diff --git a/docs/em/docs/advanced/sql-databases-peewee.md b/docs/em/docs/how-to/sql-databases-peewee.md similarity index 100% rename from docs/em/docs/advanced/sql-databases-peewee.md rename to docs/em/docs/how-to/sql-databases-peewee.md diff --git a/docs/em/docs/index.md b/docs/em/docs/index.md index ea8a9d41c..c7df28160 100644 --- a/docs/em/docs/index.md +++ b/docs/em/docs/index.md @@ -27,7 +27,7 @@ --- -FastAPI ๐Ÿ›, โฉ (โ†•-๐ŸŽญ), ๐Ÿ•ธ ๐Ÿ› ๏ธ ๐Ÿ— ๐Ÿ› ๏ธ โฎ๏ธ ๐Ÿ 3๏ธโƒฃ.7๏ธโƒฃ โž• โš“๏ธ ๐Ÿ”› ๐Ÿฉ ๐Ÿ ๐Ÿ†Ž ๐Ÿ”‘. +FastAPI ๐Ÿ›, โฉ (โ†•-๐ŸŽญ), ๐Ÿ•ธ ๐Ÿ› ๏ธ ๐Ÿ— ๐Ÿ› ๏ธ โฎ๏ธ ๐Ÿ 3๏ธโƒฃ.8๏ธโƒฃ โž• โš“๏ธ ๐Ÿ”› ๐Ÿฉ ๐Ÿ ๐Ÿ†Ž ๐Ÿ”‘. ๐Ÿ”‘ โš’: diff --git a/docs/em/docs/project-generation.md b/docs/em/docs/project-generation.md index 5fd667ad1..ae959e1d5 100644 --- a/docs/em/docs/project-generation.md +++ b/docs/em/docs/project-generation.md @@ -79,6 +79,6 @@ * **๐ŸŒˆ** ๐Ÿ•œ ๐Ÿท ๐Ÿ› ๏ธ. * **โ˜ ๐Ÿง  ๐Ÿ”Ž** ๐Ÿ“จ ๐Ÿ“ ๐Ÿ—. * **๐Ÿญ ๐Ÿ”œ** ๐Ÿ ๐Ÿ•ธ ๐Ÿ’ฝ โš™๏ธ Uvicorn & ๐Ÿ. -* **โ˜ ๐Ÿ‘ฉโ€๐Ÿ’ป** Kubernete (๐Ÿฆฒ) ๐Ÿ†‘/๐Ÿ’ฟ ๐Ÿ› ๏ธ ๐Ÿ—. +* **โ˜ ๐Ÿ‘ฉโ€๐Ÿ’ป** Kubernetes (๐Ÿฆฒ) ๐Ÿ†‘/๐Ÿ’ฟ ๐Ÿ› ๏ธ ๐Ÿ—. * **๐Ÿคธโ€โ™‚** ๐Ÿ’ช โš’ 1๏ธโƒฃ ๐ŸŒˆ ๐Ÿ— ๐Ÿ‡ช๐Ÿ‡ธ โฎ๏ธ ๐Ÿ— ๐Ÿ–ฅ. * **๐Ÿ’ช ๐Ÿง** ๐ŸŽ ๐Ÿท ๐Ÿ› ๏ธ (Pytorch, ๐Ÿ‡ธ๐Ÿ‡ฒ), ๐Ÿšซ ๐ŸŒˆ. diff --git a/docs/em/docs/tutorial/query-params-str-validations.md b/docs/em/docs/tutorial/query-params-str-validations.md index d6b67bd51..f0e455abe 100644 --- a/docs/em/docs/tutorial/query-params-str-validations.md +++ b/docs/em/docs/tutorial/query-params-str-validations.md @@ -371,7 +371,7 @@ http://localhost:8000/items/ === "๐Ÿ 3๏ธโƒฃ.1๏ธโƒฃ0๏ธโƒฃ & ๐Ÿ”›" - ```Python hl_lines="12" + ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!} ``` @@ -421,7 +421,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems === "๐Ÿ 3๏ธโƒฃ.1๏ธโƒฃ0๏ธโƒฃ & ๐Ÿ”›" - ```Python hl_lines="17" + ```Python hl_lines="16" {!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!} ``` diff --git a/docs/en/data/external_links.yml b/docs/en/data/external_links.yml index a7f766d16..726e7eae7 100644 --- a/docs/en/data/external_links.yml +++ b/docs/en/data/external_links.yml @@ -1,5 +1,5 @@ -articles: - english: +Articles: + English: - author: Adejumo Ridwan Suleiman author_link: https://www.linkedin.com/in/adejumoridwan/ link: https://medium.com/python-in-plain-english/build-an-sms-spam-classifier-serverless-database-with-faunadb-and-fastapi-23dbb275bc5b @@ -236,7 +236,7 @@ articles: author_link: https://medium.com/@krishnardt365 link: https://medium.com/@krishnardt365/fastapi-docker-and-postgres-91943e71be92 title: Fastapi, Docker(Docker compose) and Postgres - german: + German: - author: Marcel Sander (actidoo) author_link: https://www.actidoo.com link: https://www.actidoo.com/de/blog/python-fastapi-domain-driven-design @@ -249,7 +249,7 @@ articles: author_link: https://hellocoding.de/autor/felix-schuermeyer/ link: https://hellocoding.de/blog/coding-language/python/fastapi title: REST-API Programmieren mittels Python und dem FastAPI Modul - japanese: + Japanese: - author: '@bee2' author_link: https://qiita.com/bee2 link: https://qiita.com/bee2/items/75d9c0d7ba20e7a4a0e9 @@ -298,7 +298,7 @@ articles: author_link: https://qiita.com/mtitg link: https://qiita.com/mtitg/items/47770e9a562dd150631d title: FastAPI๏ฝœDBๆŽฅ็ถšใ—ใฆCRUDใ™ใ‚‹Python่ฃฝAPIใ‚ตใƒผใƒใƒผใ‚’ๆง‹็ฏ‰ - russian: + Russian: - author: Troy Kรถhler author_link: https://www.linkedin.com/in/trkohler/ link: https://trkohler.com/fast-api-introduction-to-framework @@ -311,18 +311,18 @@ articles: author_link: https://habr.com/ru/users/57uff3r/ link: https://habr.com/ru/post/454440/ title: 'ะœะตะปะบะฐั ะฟะธั‚ะพะฝัั‡ะฐั ั€ะฐะดะพัั‚ัŒ #2: Starlette - ะกะพะปะธะดะฝะฐั ะฟั€ะธะผะพั‡ะบะฐ โ€“ FastAPI' - vietnamese: + Vietnamese: - author: Nguyแป…n Nhรขn author_link: https://fullstackstation.com/author/figonking/ link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/ title: 'FASTAPI: TRIแป‚N KHAI BแบฐNG DOCKER' - taiwanese: + Taiwanese: - author: Leon author_link: http://editor.leonh.space/ link: https://editor.leonh.space/2022/tortoise/ title: 'Tortoise ORM / FastAPI ๆ•ดๅˆๅฟซ้€Ÿ็ญ†่จ˜' -podcasts: - english: +Podcasts: + English: - author: Podcast.`__init__` author_link: https://www.pythonpodcast.com/ link: https://www.pythonpodcast.com/fastapi-web-application-framework-episode-259/ @@ -331,8 +331,8 @@ podcasts: author_link: https://pythonbytes.fm/ link: https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855 title: FastAPI on PythonBytes -talks: - english: +Talks: + English: - author: Sebastiรกn Ramรญrez (tiangolo) author_link: https://twitter.com/tiangolo link: https://www.youtube.com/watch?v=PnpTY1f4k2U diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index 3a68ba62b..b9d74ea7b 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -1,7 +1,13 @@ sponsors: -- - login: cryptapi +- - login: bump-sh + avatarUrl: https://avatars.githubusercontent.com/u/33217836?v=4 + url: https://github.com/bump-sh + - login: cryptapi avatarUrl: https://avatars.githubusercontent.com/u/44925437?u=61369138589bc7fee6c417f3fbd50fbd38286cc4&v=4 url: https://github.com/cryptapi + - login: porter-dev + avatarUrl: https://avatars.githubusercontent.com/u/62078005?v=4 + url: https://github.com/porter-dev - login: fern-api avatarUrl: https://avatars.githubusercontent.com/u/102944815?v=4 url: https://github.com/fern-api @@ -17,6 +23,9 @@ sponsors: - - login: mikeckennedy avatarUrl: https://avatars.githubusercontent.com/u/2035561?u=1bb18268bcd4d9249e1f783a063c27df9a84c05b&v=4 url: https://github.com/mikeckennedy + - login: ndimares + avatarUrl: https://avatars.githubusercontent.com/u/6267663?u=cfb27efde7a7212be8142abb6c058a1aeadb41b1&v=4 + url: https://github.com/ndimares - login: deta avatarUrl: https://avatars.githubusercontent.com/u/47275976?v=4 url: https://github.com/deta @@ -32,12 +41,6 @@ sponsors: - login: VincentParedes avatarUrl: https://avatars.githubusercontent.com/u/103889729?v=4 url: https://github.com/VincentParedes -- - login: arcticfly - avatarUrl: https://avatars.githubusercontent.com/u/41524992?u=03c88529a86cf51f7a380e890d84d84c71468848&v=4 - url: https://github.com/arcticfly -- - login: getsentry - avatarUrl: https://avatars.githubusercontent.com/u/1396951?v=4 - url: https://github.com/getsentry - - login: acsone avatarUrl: https://avatars.githubusercontent.com/u/7601056?v=4 url: https://github.com/acsone @@ -50,9 +53,6 @@ sponsors: - login: marvin-robot avatarUrl: https://avatars.githubusercontent.com/u/41086007?u=091c5cb75af363123d66f58194805a97220ee1a7&v=4 url: https://github.com/marvin-robot - - login: Flint-company - avatarUrl: https://avatars.githubusercontent.com/u/48908872?u=355cd3d8992d4be8173058e7000728757c55ad49&v=4 - url: https://github.com/Flint-company - login: BoostryJP avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4 url: https://github.com/BoostryJP @@ -77,9 +77,6 @@ sponsors: - login: AccentDesign avatarUrl: https://avatars.githubusercontent.com/u/2429332?v=4 url: https://github.com/AccentDesign - - login: RodneyU215 - avatarUrl: https://avatars.githubusercontent.com/u/3329665?u=ec6a9adf8e7e8e306eed7d49687c398608d1604f&v=4 - url: https://github.com/RodneyU215 - login: americanair avatarUrl: https://avatars.githubusercontent.com/u/12281813?v=4 url: https://github.com/americanair @@ -92,15 +89,9 @@ sponsors: - login: primer-io avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4 url: https://github.com/primer-io -- - login: indeedeng - avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4 - url: https://github.com/indeedeng - - login: iguit0 - avatarUrl: https://avatars.githubusercontent.com/u/12905770?u=63a1a96d1e6c27d85c4f946b84836599de047f65&v=4 - url: https://github.com/iguit0 - - login: JacobKochems - avatarUrl: https://avatars.githubusercontent.com/u/41692189?u=a75f62ddc0d060ee6233a91e19c433d2687b8eb6&v=4 - url: https://github.com/JacobKochems +- - login: NateXVI + avatarUrl: https://avatars.githubusercontent.com/u/48195620?u=4bc8751ae50cb087c40c1fe811764aa070b9eea6&v=4 + url: https://github.com/NateXVI - - login: Kludex avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex @@ -113,9 +104,6 @@ sponsors: - login: jstanden avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4 url: https://github.com/jstanden - - login: dekoza - avatarUrl: https://avatars.githubusercontent.com/u/210980?u=c03c78a8ae1039b500dfe343665536ebc51979b2&v=4 - url: https://github.com/dekoza - login: pamelafox avatarUrl: https://avatars.githubusercontent.com/u/297042?v=4 url: https://github.com/pamelafox @@ -143,9 +131,6 @@ sponsors: - login: mickaelandrieu avatarUrl: https://avatars.githubusercontent.com/u/1247388?u=599f6e73e452a9453f2bd91e5c3100750e731ad4&v=4 url: https://github.com/mickaelandrieu - - login: jonakoudijs - avatarUrl: https://avatars.githubusercontent.com/u/1906344?u=5ca0c9a1a89b6a2ba31abe35c66bdc07af60a632&v=4 - url: https://github.com/jonakoudijs - login: Shark009 avatarUrl: https://avatars.githubusercontent.com/u/3163309?u=0c6f4091b0eda05c44c390466199826e6dc6e431&v=4 url: https://github.com/Shark009 @@ -200,12 +185,12 @@ sponsors: - login: hiancdtrsnm avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4 url: https://github.com/hiancdtrsnm - - login: Shackelford-Arden - avatarUrl: https://avatars.githubusercontent.com/u/7362263?v=4 - url: https://github.com/Shackelford-Arden - login: wdwinslow avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 url: https://github.com/wdwinslow + - login: jsoques + avatarUrl: https://avatars.githubusercontent.com/u/12414216?u=620921d94196546cc8b9eae2cc4cbc3f95bab42f&v=4 + url: https://github.com/jsoques - login: joeds13 avatarUrl: https://avatars.githubusercontent.com/u/13631604?u=628eb122e08bef43767b3738752b883e8e7f6259&v=4 url: https://github.com/joeds13 @@ -227,9 +212,9 @@ sponsors: - login: Filimoa avatarUrl: https://avatars.githubusercontent.com/u/21352040?u=0be845711495bbd7b756e13fcaeb8efc1ebd78ba&v=4 url: https://github.com/Filimoa - - login: LarryGF - avatarUrl: https://avatars.githubusercontent.com/u/26148349?u=431bb34d36d41c172466252242175281ae132152&v=4 - url: https://github.com/LarryGF + - login: rahulsalgare + avatarUrl: https://avatars.githubusercontent.com/u/21974430?u=ade6f182b94554ab8491d7421de5e78f711dcaf8&v=4 + url: https://github.com/rahulsalgare - login: BrettskiPy avatarUrl: https://avatars.githubusercontent.com/u/30988215?u=d8a94a67e140d5ee5427724b292cc52d8827087a&v=4 url: https://github.com/BrettskiPy @@ -239,15 +224,15 @@ sponsors: - login: Leay15 avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4 url: https://github.com/Leay15 + - login: dvlpjrs + avatarUrl: https://avatars.githubusercontent.com/u/32254642?u=fbd6ad0324d4f1eb6231cf775be1c7bd4404e961&v=4 + url: https://github.com/dvlpjrs - login: ygorpontelo avatarUrl: https://avatars.githubusercontent.com/u/32963605?u=35f7103f9c4c4c2589ae5737ee882e9375ef072e&v=4 url: https://github.com/ygorpontelo - login: ProteinQure avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4 url: https://github.com/ProteinQure - - login: askurihin - avatarUrl: https://avatars.githubusercontent.com/u/37978981?v=4 - url: https://github.com/askurihin - login: arleybri18 avatarUrl: https://avatars.githubusercontent.com/u/39681546?u=5c028f81324b0e8c73b3c15bc4e7b0218d2ba0c3&v=4 url: https://github.com/arleybri18 @@ -266,18 +251,12 @@ sponsors: - login: dudikbender avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=3a57542938ebfd57579a0111db2b297e606d9681&v=4 url: https://github.com/dudikbender - - login: thisistheplace - avatarUrl: https://avatars.githubusercontent.com/u/57633545?u=a3f3a7f8ace8511c6c067753f6eb6aee0db11ac6&v=4 - url: https://github.com/thisistheplace - login: yakkonaut avatarUrl: https://avatars.githubusercontent.com/u/60633704?u=90a71fd631aa998ba4a96480788f017c9904e07b&v=4 url: https://github.com/yakkonaut - login: patsatsia avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=3271b85f7a37b479c8d0ae0a235182e83c166edf&v=4 url: https://github.com/patsatsia - - login: daverin - avatarUrl: https://avatars.githubusercontent.com/u/70378377?u=6d1814195c0de7162820eaad95a25b423a3869c0&v=4 - url: https://github.com/daverin - login: anthonycepeda avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=4252c6b6dc5024af502a823a3ac5e7a03a69963f&v=4 url: https://github.com/anthonycepeda @@ -290,9 +269,6 @@ sponsors: - login: pyt3h avatarUrl: https://avatars.githubusercontent.com/u/99658549?v=4 url: https://github.com/pyt3h - - login: Dagmaara - avatarUrl: https://avatars.githubusercontent.com/u/115501964?v=4 - url: https://github.com/Dagmaara - - login: SebTota avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4 url: https://github.com/SebTota @@ -305,6 +281,9 @@ sponsors: - login: bryanculbertson avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4 url: https://github.com/bryanculbertson + - login: yourkin + avatarUrl: https://avatars.githubusercontent.com/u/178984?u=b43a7e5f8818f7d9083d3b110118d9c27d48a794&v=4 + url: https://github.com/yourkin - login: slafs avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 url: https://github.com/slafs @@ -320,15 +299,15 @@ sponsors: - login: securancy avatarUrl: https://avatars.githubusercontent.com/u/606673?v=4 url: https://github.com/securancy - - login: hardbyte - avatarUrl: https://avatars.githubusercontent.com/u/855189?u=aa29e92f34708814d6b67fcd47ca4cf2ce1c04ed&v=4 - url: https://github.com/hardbyte - login: browniebroke avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4 url: https://github.com/browniebroke - login: janfilips avatarUrl: https://avatars.githubusercontent.com/u/870699?u=80702ec63f14e675cd4cdcc6ce3821d2ed207fd7&v=4 url: https://github.com/janfilips + - login: dodo5522 + avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4 + url: https://github.com/dodo5522 - login: WillHogan avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=7036c064cf29781470573865264ec8e60b6b809f&v=4 url: https://github.com/WillHogan @@ -374,9 +353,6 @@ sponsors: - login: katnoria avatarUrl: https://avatars.githubusercontent.com/u/7674948?u=09767eb13e07e09496c5fee4e5ce21d9eac34a56&v=4 url: https://github.com/katnoria - - login: mattwelke - avatarUrl: https://avatars.githubusercontent.com/u/7719209?u=80f02a799323b1472b389b836d95957c93a6d856&v=4 - url: https://github.com/mattwelke - login: harsh183 avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4 url: https://github.com/harsh183 @@ -422,6 +398,9 @@ sponsors: - login: jangia avatarUrl: https://avatars.githubusercontent.com/u/17927101?u=9261b9bb0c3e3bb1ecba43e8915dc58d8c9a077e&v=4 url: https://github.com/jangia + - login: timzaz + avatarUrl: https://avatars.githubusercontent.com/u/19709244?u=264d7db95c28156363760229c30ee1116efd4eeb&v=4 + url: https://github.com/timzaz - login: shuheng-liu avatarUrl: https://avatars.githubusercontent.com/u/22414322?u=813c45f30786c6b511b21a661def025d8f7b609e&v=4 url: https://github.com/shuheng-liu @@ -431,12 +410,18 @@ sponsors: - login: kxzk avatarUrl: https://avatars.githubusercontent.com/u/25046261?u=e185e58080090f9e678192cd214a14b14a2b232b&v=4 url: https://github.com/kxzk + - login: nisutec + avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4 + url: https://github.com/nisutec - login: hoenie-ams avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4 url: https://github.com/hoenie-ams - login: joerambo avatarUrl: https://avatars.githubusercontent.com/u/26282974?v=4 url: https://github.com/joerambo + - login: msniezynski + avatarUrl: https://avatars.githubusercontent.com/u/27588547?u=0e3be5ac57dcfdf124f470bcdf74b5bf79af1b6c&v=4 + url: https://github.com/msniezynski - login: rlnchow avatarUrl: https://avatars.githubusercontent.com/u/28018479?u=a93ca9cf1422b9ece155784a72d5f2fdbce7adff&v=4 url: https://github.com/rlnchow @@ -450,7 +435,7 @@ sponsors: avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4 url: https://github.com/engineerjoe440 - login: bnkc - avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=527044d90b5ebb7f8dad517db5da1f45253b774b&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=1a104991a2ea90bfe304bc0b9ef191c7e4891a0e&v=4 url: https://github.com/bnkc - login: declon avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4 @@ -458,6 +443,12 @@ sponsors: - login: miraedbswo avatarUrl: https://avatars.githubusercontent.com/u/36796047?u=9e7a5b3e558edc61d35d0f9dfac37541bae7f56d&v=4 url: https://github.com/miraedbswo + - login: DSMilestone6538 + avatarUrl: https://avatars.githubusercontent.com/u/37230924?u=f299dce910366471523155e0cb213356d34aadc1&v=4 + url: https://github.com/DSMilestone6538 + - login: curegit + avatarUrl: https://avatars.githubusercontent.com/u/37978051?u=1733c322079118c0cdc573c03d92813f50a9faec&v=4 + url: https://github.com/curegit - login: kristiangronberg avatarUrl: https://avatars.githubusercontent.com/u/42678548?v=4 url: https://github.com/kristiangronberg @@ -482,6 +473,12 @@ sponsors: - login: 0417taehyun avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4 url: https://github.com/0417taehyun + - login: romabozhanovgithub + avatarUrl: https://avatars.githubusercontent.com/u/67696229?u=e4b921eef096415300425aca249348f8abb78ad7&v=4 + url: https://github.com/romabozhanovgithub + - login: mbukeRepo + avatarUrl: https://avatars.githubusercontent.com/u/70356088?u=d2eb23e2b222a3b316c4183b05a3236b32819dc2&v=4 + url: https://github.com/mbukeRepo - - login: ssbarnea avatarUrl: https://avatars.githubusercontent.com/u/102495?u=b4bf6818deefe59952ac22fec6ed8c76de1b8f7c&v=4 url: https://github.com/ssbarnea @@ -494,21 +491,18 @@ sponsors: - login: sadikkuzu avatarUrl: https://avatars.githubusercontent.com/u/23168063?u=d179c06bb9f65c4167fcab118526819f8e0dac17&v=4 url: https://github.com/sadikkuzu - - login: ruizdiazever - avatarUrl: https://avatars.githubusercontent.com/u/29817086?u=2df54af55663d246e3a4dc8273711c37f1adb117&v=4 - url: https://github.com/ruizdiazever - login: samnimoh avatarUrl: https://avatars.githubusercontent.com/u/33413170?u=147bc516be6cb647b28d7e3b3fea3a018a331145&v=4 url: https://github.com/samnimoh - login: danburonline avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4 url: https://github.com/danburonline - - login: iharshgor - avatarUrl: https://avatars.githubusercontent.com/u/35490011?u=2dea054476e752d9e92c9d71a9a7cc919b1c2f8e&v=4 - url: https://github.com/iharshgor - login: rwxd avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4 url: https://github.com/rwxd - - login: ThomasPalma1 - avatarUrl: https://avatars.githubusercontent.com/u/66331874?u=5763f7402d784ba189b60d704ff5849b4d0a63fb&v=4 - url: https://github.com/ThomasPalma1 + - login: shywn-mrk + avatarUrl: https://avatars.githubusercontent.com/u/51455763?u=389e2608e4056fe5e1f23e9ad56a9415277504d3&v=4 + url: https://github.com/shywn-mrk + - login: almeida-matheus + avatarUrl: https://avatars.githubusercontent.com/u/66216198?u=54335eaa0ced626be5c1ff52fead1ebc032286ec&v=4 + url: https://github.com/almeida-matheus diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index 89d189564..db06cbdaf 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -1,16 +1,16 @@ maintainers: - login: tiangolo - answers: 1849 - prs: 466 + answers: 1868 + prs: 496 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4 url: https://github.com/tiangolo experts: - login: Kludex - count: 463 + count: 501 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: dmontagu - count: 239 + count: 240 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 url: https://github.com/dmontagu - login: Mause @@ -26,7 +26,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 url: https://github.com/JarroVGIT - login: jgould22 - count: 157 + count: 168 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 - login: euri10 @@ -38,7 +38,7 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: iudeen - count: 121 + count: 122 avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 url: https://github.com/iudeen - login: raphaelauv @@ -61,38 +61,42 @@ experts: count: 49 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen -- login: insomnes - count: 45 - avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 - url: https://github.com/insomnes -- login: yinziyan1206 - count: 45 - avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4 - url: https://github.com/yinziyan1206 - login: acidjunk count: 45 avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 url: https://github.com/acidjunk +- login: insomnes + count: 45 + avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 + url: https://github.com/insomnes - login: Dustyposa count: 45 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa - login: adriangb - count: 44 + count: 45 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 url: https://github.com/adriangb -- login: frankie567 - count: 43 - avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4 - url: https://github.com/frankie567 +- login: yinziyan1206 + count: 44 + avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4 + url: https://github.com/yinziyan1206 - login: odiseo0 count: 43 avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4 url: https://github.com/odiseo0 +- login: frankie567 + count: 43 + avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=c159fe047727aedecbbeeaa96a1b03ceb9d39add&v=4 + url: https://github.com/frankie567 - login: includeamin count: 40 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin +- login: chbndrhnns + count: 38 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: STeveShary count: 37 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 @@ -101,10 +105,10 @@ experts: count: 35 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 url: https://github.com/krishnardt -- login: chbndrhnns - count: 35 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns +- login: n8sty + count: 32 + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty - login: panla count: 32 avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4 @@ -121,22 +125,22 @@ experts: count: 25 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 url: https://github.com/wshayes -- login: acnebs - count: 23 - avatarUrl: https://avatars.githubusercontent.com/u/9054108?v=4 - url: https://github.com/acnebs - login: SirTelemak count: 23 avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4 url: https://github.com/SirTelemak +- login: acnebs + count: 23 + avatarUrl: https://avatars.githubusercontent.com/u/9054108?v=4 + url: https://github.com/acnebs - login: rafsaf count: 21 - avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=5fe59a56e1f2f9ccd8005d71752a8276f133ae1a&v=4 url: https://github.com/rafsaf -- login: n8sty +- login: JavierSanchezCastro count: 20 - avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 - url: https://github.com/n8sty + avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 + url: https://github.com/JavierSanchezCastro - login: nsidnev count: 20 avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4 @@ -145,6 +149,10 @@ experts: count: 20 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt +- login: chrisK824 + count: 19 + avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4 + url: https://github.com/chrisK824 - login: zoliknemet count: 18 avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4 @@ -153,6 +161,10 @@ experts: count: 18 avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 url: https://github.com/retnikt +- login: ebottos94 + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4 + url: https://github.com/ebottos94 - login: Hultner count: 17 avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 @@ -169,6 +181,10 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/16540232?u=05d2beb8e034d584d0a374b99d8826327bd7f614&v=4 url: https://github.com/caeser1996 +- login: nymous + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4 + url: https://github.com/nymous - login: jonatasoli count: 16 avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4 @@ -181,47 +197,23 @@ experts: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4 url: https://github.com/abhint -- login: nymous - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4 - url: https://github.com/nymous -- login: ghost - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/10137?u=b1951d34a583cf12ec0d3b0781ba19be97726318&v=4 - url: https://github.com/ghost -- login: simondale00 - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/33907262?v=4 - url: https://github.com/simondale00 -- login: jorgerpo - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4 - url: https://github.com/jorgerpo last_month_active: - login: Kludex - count: 24 + count: 8 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex -- login: jgould22 - count: 17 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 -- login: arjwilliams - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/22227620?v=4 - url: https://github.com/arjwilliams -- login: Ahmed-Abdou14 +- login: n8sty + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty +- login: chrisK824 count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/104530599?u=05365b155a1ff911532e8be316acfad2e0736f98&v=4 - url: https://github.com/Ahmed-Abdou14 -- login: iudeen + avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4 + url: https://github.com/chrisK824 +- login: danielfcollier count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 - url: https://github.com/iudeen -- login: mikeedjones - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/4087139?u=cc4a242896ac2fcf88a53acfaf190d0fe0a1f0c9&v=4 - url: https://github.com/mikeedjones + avatarUrl: https://avatars.githubusercontent.com/u/38995330?u=5799be795fc310f75f3a5fe9242307d59b194520&v=4 + url: https://github.com/danielfcollier top_contributors: - login: waynerv count: 25 @@ -236,21 +228,21 @@ top_contributors: avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex - login: jaystone776 - count: 17 + count: 18 avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 url: https://github.com/jaystone776 - login: dmontagu - count: 16 + count: 17 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 url: https://github.com/dmontagu +- login: Xewus + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 + url: https://github.com/Xewus - login: euri10 count: 13 avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4 url: https://github.com/euri10 -- login: Xewus - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 - url: https://github.com/Xewus - login: mariacamilagl count: 12 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 @@ -307,6 +299,10 @@ top_contributors: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4 url: https://github.com/ComicShrimp +- login: tamtam-fitness + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/62091034?u=8da19a6bd3d02f5d6ba30c7247d5b46c98dd1403&v=4 + url: https://github.com/tamtam-fitness - login: jekirl count: 4 avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4 @@ -347,19 +343,27 @@ top_contributors: count: 4 avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4 url: https://github.com/ivan-abc +- login: rostik1410 + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/11443899?u=e26a635c2ba220467b308a326a579b8ccf4a8701&v=4 + url: https://github.com/rostik1410 top_reviewers: - login: Kludex - count: 136 + count: 139 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4 url: https://github.com/Kludex +- login: yezz123 + count: 80 + avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4 + url: https://github.com/yezz123 - login: BilalAlpaslan count: 79 avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4 url: https://github.com/BilalAlpaslan -- login: yezz123 - count: 78 - avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=d7062cbc6eb7671d5dc9cc0e32a24ae335e0f225&v=4 - url: https://github.com/yezz123 +- login: iudeen + count: 54 + avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 + url: https://github.com/iudeen - login: tokusumi count: 51 avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4 @@ -372,22 +376,18 @@ top_reviewers: count: 47 avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4 url: https://github.com/Laineyzhang55 -- login: iudeen - count: 46 - avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4 - url: https://github.com/iudeen - login: ycd count: 45 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4 url: https://github.com/ycd +- login: Xewus + count: 44 + avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 + url: https://github.com/Xewus - login: cikay count: 41 avatarUrl: https://avatars.githubusercontent.com/u/24587499?u=e772190a051ab0eaa9c8542fcff1892471638f2b&v=4 url: https://github.com/cikay -- login: Xewus - count: 38 - avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4 - url: https://github.com/Xewus - login: JarroVGIT count: 34 avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 @@ -460,6 +460,10 @@ top_reviewers: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4 url: https://github.com/axel584 +- login: Alexandrhub + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4 + url: https://github.com/Alexandrhub - login: DevDae count: 16 avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4 @@ -472,18 +476,18 @@ top_reviewers: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4 url: https://github.com/delhi09 -- login: Alexandrhub - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4 - url: https://github.com/Alexandrhub - login: sh0nk count: 13 avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4 url: https://github.com/sh0nk - login: peidrao count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=5b94b548ef0002ef3219d7c07ac0fac17c6201a2&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=a66902b40c13647d0ed0e573d598128240a4dd04&v=4 url: https://github.com/peidrao +- login: wdh99 + count: 13 + avatarUrl: https://avatars.githubusercontent.com/u/108172295?u=8a8fb95d5afe3e0fa33257b2aecae88d436249eb&v=4 + url: https://github.com/wdh99 - login: r0b2g1t count: 13 avatarUrl: https://avatars.githubusercontent.com/u/5357541?u=6428442d875d5d71aaa1bb38bb11c4be1a526bc2&v=4 @@ -500,10 +504,6 @@ top_reviewers: count: 11 avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=789927ee09cfabd752d3bd554fa6baf4850d2777&v=4 url: https://github.com/solomein-sv -- login: wdh99 - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/108172295?u=8a8fb95d5afe3e0fa33257b2aecae88d436249eb&v=4 - url: https://github.com/wdh99 - login: mariacamilagl count: 10 avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4 diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index 6d9119520..121a3b761 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -5,12 +5,21 @@ gold: - url: https://platform.sh/try-it-now/?utm_source=fastapi-signup&utm_medium=banner&utm_campaign=FastAPI-signup-June-2023 title: "Build, run and scale your apps on a modern, reliable, and secure PaaS." img: https://fastapi.tiangolo.com/img/sponsors/platform-sh.png - - url: https://www.buildwithfern.com/?utm_source=tiangolo&utm_medium=website&utm_campaign=main-badge - title: Fern | SDKs and API docs - img: https://fastapi.tiangolo.com/img/sponsors/fern.svg - url: https://www.porter.run title: Deploy FastAPI on AWS with a few clicks img: https://fastapi.tiangolo.com/img/sponsors/porter.png + - url: https://bump.sh/fastapi?utm_source=fastapi&utm_medium=referral&utm_campaign=sponsor + title: Automate FastAPI documentation generation with Bump.sh + img: https://fastapi.tiangolo.com/img/sponsors/bump-sh.svg + - url: https://reflex.dev + title: Reflex + img: https://fastapi.tiangolo.com/img/sponsors/reflex.png + - url: https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge + title: "Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files" + img: https://fastapi.tiangolo.com/img/sponsors/scalar.svg + - url: https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge + title: Auth, user management and more for your B2B product + img: https://fastapi.tiangolo.com/img/sponsors/propelauth.png silver: - url: https://www.deta.sh/?ref=fastapi title: The launchpad for all your (team's) ideas @@ -27,19 +36,22 @@ silver: - url: https://careers.powens.com/ title: Powens is hiring! img: https://fastapi.tiangolo.com/img/sponsors/powens.png - - url: https://www.svix.com/ - title: Svix - Webhooks as a service - img: https://fastapi.tiangolo.com/img/sponsors/svix.svg - url: https://databento.com/ title: Pay as you go for market data img: https://fastapi.tiangolo.com/img/sponsors/databento.svg + - url: https://speakeasyapi.dev?utm_source=fastapi+repo&utm_medium=github+sponsorship + title: SDKs for your API | Speakeasy + img: https://fastapi.tiangolo.com/img/sponsors/speakeasy.png + - url: https://www.svix.com/ + title: Svix - Webhooks as a service + img: https://fastapi.tiangolo.com/img/sponsors/svix.svg + - url: https://www.codacy.com/?utm_source=github&utm_medium=sponsors&utm_id=pioneers + title: Take code reviews from hours to minutes + img: https://fastapi.tiangolo.com/img/sponsors/codacy.png bronze: - url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source title: Biosecurity risk assessments made easy. img: https://fastapi.tiangolo.com/img/sponsors/exoflare.png - - url: https://www.flint.sh - title: IT expertise, consulting and development by passionate people - img: https://fastapi.tiangolo.com/img/sponsors/flint.png - url: https://bit.ly/3JJ7y5C title: Build cross-modal and multimodal applications on the cloud img: https://fastapi.tiangolo.com/img/sponsors/jina2.svg diff --git a/docs/en/data/sponsors_badge.yml b/docs/en/data/sponsors_badge.yml index 7c3bb2f47..4078454a8 100644 --- a/docs/en/data/sponsors_badge.yml +++ b/docs/en/data/sponsors_badge.yml @@ -12,10 +12,14 @@ logins: - ObliviousAI - Doist - nihpo - - svix - armand-sauzay - databento-bot + - databento - nanram22 - Flint-company - porter-dev - fern-api + - ndimares + - svixhq + - Alek99 + - codacy diff --git a/docs/en/docs/about/index.md b/docs/en/docs/about/index.md new file mode 100644 index 000000000..27b78696b --- /dev/null +++ b/docs/en/docs/about/index.md @@ -0,0 +1,3 @@ +# About + +About FastAPI, its design, inspiration and more. ๐Ÿค“ diff --git a/docs/en/docs/advanced/additional-status-codes.md b/docs/en/docs/advanced/additional-status-codes.md index 416444d3b..0ce275343 100644 --- a/docs/en/docs/advanced/additional-status-codes.md +++ b/docs/en/docs/advanced/additional-status-codes.md @@ -26,7 +26,7 @@ To achieve that, import `JSONResponse`, and return your content there directly, {!> ../../../docs_src/additional_status_codes/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 26" {!> ../../../docs_src/additional_status_codes/tutorial001_an.py!} @@ -41,7 +41,7 @@ To achieve that, import `JSONResponse`, and return your content there directly, {!> ../../../docs_src/additional_status_codes/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/advanced/advanced-dependencies.md b/docs/en/docs/advanced/advanced-dependencies.md index 402c5d755..0cffab56d 100644 --- a/docs/en/docs/advanced/advanced-dependencies.md +++ b/docs/en/docs/advanced/advanced-dependencies.md @@ -24,13 +24,13 @@ To do that, we declare a method `__call__`: {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/dependencies/tutorial011_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -51,13 +51,13 @@ And now, we can use `__init__` to declare the parameters of the instance that we {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/dependencies/tutorial011_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -78,13 +78,13 @@ We could create an instance of this class with: {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17" {!> ../../../docs_src/dependencies/tutorial011_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -113,13 +113,13 @@ checker(q="somequery") {!> ../../../docs_src/dependencies/tutorial011_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="21" {!> ../../../docs_src/dependencies/tutorial011_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/advanced/extending-openapi.md b/docs/en/docs/advanced/extending-openapi.md deleted file mode 100644 index bec184dee..000000000 --- a/docs/en/docs/advanced/extending-openapi.md +++ /dev/null @@ -1,318 +0,0 @@ -# Extending OpenAPI - -!!! warning - This is a rather advanced feature. You probably can skip it. - - If you are just following the tutorial - user guide, you can probably skip this section. - - If you already know that you need to modify the generated OpenAPI schema, continue reading. - -There are some cases where you might need to modify the generated OpenAPI schema. - -In this section you will see how. - -## The normal process - -The normal (default) process, is as follows. - -A `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema. - -As part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered. - -It just returns a JSON response with the result of the application's `.openapi()` method. - -By default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them. - -If it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`. - -And that function `get_openapi()` receives as parameters: - -* `title`: The OpenAPI title, shown in the docs. -* `version`: The version of your API, e.g. `2.5.0`. -* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`. -* `summary`: A short summary of the API. -* `description`: The description of your API, this can include markdown and will be shown in the docs. -* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`. - -!!! info - The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above. - -## Overriding the defaults - -Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need. - -For example, let's add ReDoc's OpenAPI extension to include a custom logo. - -### Normal **FastAPI** - -First, write all your **FastAPI** application as normally: - -```Python hl_lines="1 4 7-9" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### Generate the OpenAPI schema - -Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function: - -```Python hl_lines="2 15-21" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### Modify the OpenAPI schema - -Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema: - -```Python hl_lines="22-24" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### Cache the OpenAPI schema - -You can use the property `.openapi_schema` as a "cache", to store your generated schema. - -That way, your application won't have to generate the schema every time a user opens your API docs. - -It will be generated only once, and then the same cached schema will be used for the next requests. - -```Python hl_lines="13-14 25-26" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### Override the method - -Now you can replace the `.openapi()` method with your new function. - -```Python hl_lines="29" -{!../../../docs_src/extending_openapi/tutorial001.py!} -``` - -### Check it - -Once you go to http://127.0.0.1:8000/redoc you will see that you are using your custom logo (in this example, **FastAPI**'s logo): - - - -## Self-hosting JavaScript and CSS for docs - -The API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files. - -By default, those files are served from a CDN. - -But it's possible to customize it, you can set a specific CDN, or serve the files yourself. - -That's useful, for example, if you need your app to keep working even while offline, without open Internet access, or in a local network. - -Here you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them. - -### Project file structure - -Let's say your project file structure looks like this: - -``` -. -โ”œโ”€โ”€ app -โ”‚ โ”œโ”€โ”€ __init__.py -โ”‚ โ”œโ”€โ”€ main.py -``` - -Now create a directory to store those static files. - -Your new file structure could look like this: - -``` -. -โ”œโ”€โ”€ app -โ”‚ย ย  โ”œโ”€โ”€ __init__.py -โ”‚ย ย  โ”œโ”€โ”€ main.py -โ””โ”€โ”€ static/ -``` - -### Download the files - -Download the static files needed for the docs and put them on that `static/` directory. - -You can probably right-click each link and select an option similar to `Save link as...`. - -**Swagger UI** uses the files: - -* `swagger-ui-bundle.js` -* `swagger-ui.css` - -And **ReDoc** uses the file: - -* `redoc.standalone.js` - -After that, your file structure could look like: - -``` -. -โ”œโ”€โ”€ app -โ”‚ย ย  โ”œโ”€โ”€ __init__.py -โ”‚ย ย  โ”œโ”€โ”€ main.py -โ””โ”€โ”€ static - โ”œโ”€โ”€ redoc.standalone.js - โ”œโ”€โ”€ swagger-ui-bundle.js - โ””โ”€โ”€ swagger-ui.css -``` - -### Serve the static files - -* Import `StaticFiles`. -* "Mount" a `StaticFiles()` instance in a specific path. - -```Python hl_lines="7 11" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -### Test the static files - -Start your application and go to http://127.0.0.1:8000/static/redoc.standalone.js. - -You should see a very long JavaScript file for **ReDoc**. - -It could start with something like: - -```JavaScript -/*! - * ReDoc - OpenAPI/Swagger-generated API Reference Documentation - * ------------------------------------------------------------- - * Version: "2.0.0-rc.18" - * Repo: https://github.com/Redocly/redoc - */ -!function(e,t){"object"==typeof exports&&"object"==typeof m - -... -``` - -That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place. - -Now we can configure the app to use those static files for the docs. - -### Disable the automatic docs - -The first step is to disable the automatic docs, as those use the CDN by default. - -To disable them, set their URLs to `None` when creating your `FastAPI` app: - -```Python hl_lines="9" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -### Include the custom docs - -Now you can create the *path operations* for the custom docs. - -You can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments: - -* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`. -* `title`: the title of your API. -* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default. -* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the one that your own app is now serving. -* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the one that your own app is now serving. - -And similarly for ReDoc... - -```Python hl_lines="2-6 14-22 25-27 30-36" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -!!! tip - The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2. - - If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication. - - Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper. - -### Create a *path operation* to test it - -Now, to be able to test that everything works, create a *path operation*: - -```Python hl_lines="39-41" -{!../../../docs_src/extending_openapi/tutorial002.py!} -``` - -### Test it - -Now, you should be able to disconnect your WiFi, go to your docs at http://127.0.0.1:8000/docs, and reload the page. - -And even without Internet, you would be able to see the docs for your API and interact with it. - -## Configuring Swagger UI - -You can configure some extra Swagger UI parameters. - -To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function. - -`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly. - -FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs. - -### Disable Syntax Highlighting - -For example, you could disable syntax highlighting in Swagger UI. - -Without changing the settings, syntax highlighting is enabled by default: - - - -But you can disable it by setting `syntaxHighlight` to `False`: - -```Python hl_lines="3" -{!../../../docs_src/extending_openapi/tutorial003.py!} -``` - -...and then Swagger UI won't show the syntax highlighting anymore: - - - -### Change the Theme - -The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle): - -```Python hl_lines="3" -{!../../../docs_src/extending_openapi/tutorial004.py!} -``` - -That configuration would change the syntax highlighting color theme: - - - -### Change Default Swagger UI Parameters - -FastAPI includes some default configuration parameters appropriate for most of the use cases. - -It includes these default configurations: - -```Python -{!../../../fastapi/openapi/docs.py[ln:7-13]!} -``` - -You can override any of them by setting a different value in the argument `swagger_ui_parameters`. - -For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`: - -```Python hl_lines="3" -{!../../../docs_src/extending_openapi/tutorial005.py!} -``` - -### Other Swagger UI Parameters - -To see all the other possible configurations you can use, read the official docs for Swagger UI parameters. - -### JavaScript-only settings - -Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions). - -FastAPI also includes these JavaScript-only `presets` settings: - -```JavaScript -presets: [ - SwaggerUIBundle.presets.apis, - SwaggerUIBundle.SwaggerUIStandalonePreset -] -``` - -These are **JavaScript** objects, not strings, so you can't pass them from Python code directly. - -If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need. diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md index 3fed48b0b..e8d771f71 100644 --- a/docs/en/docs/advanced/generate-clients.md +++ b/docs/en/docs/advanced/generate-clients.md @@ -12,10 +12,17 @@ A common tool is openapi-typescript-codegen. -Another option you could consider for several languages is Fern. +## Client and SDK Generators - Sponsor -!!! info - Fern is also a FastAPI sponsor. ๐Ÿ˜Ž๐ŸŽ‰ +There are also some **company-backed** Client and SDK generators based on OpenAPI (FastAPI), in some cases they can offer you **additional features** on top of high-quality generated SDKs/clients. + +Some of them also โœจ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} โœจ, this ensures the continued and healthy **development** of FastAPI and its **ecosystem**. + +And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good service** but also want to make sure you have a **good and healthy framework**, FastAPI. ๐Ÿ™‡ + +For example, you might want to try Speakeasy. + +There are also several other companies offering similar services that you can search and find online. ๐Ÿค“ ## Generate a TypeScript Frontend Client @@ -27,7 +34,7 @@ Let's start with a simple FastAPI application: {!> ../../../docs_src/generate_clients/tutorial001_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-11 14-15 18 19 23" {!> ../../../docs_src/generate_clients/tutorial001.py!} @@ -80,7 +87,7 @@ It could look like this: "description": "", "main": "index.js", "scripts": { - "generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios" + "generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes" }, "author": "", "license": "", @@ -99,7 +106,7 @@ After having that NPM `generate-client` script there, you can run it with: $ npm run generate-client frontend-app@1.0.0 generate-client /home/user/code/frontend-app -> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios +> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios --useOptions --useUnionTypes ``` @@ -139,7 +146,7 @@ For example, you could have a section for **items** and another section for **us {!> ../../../docs_src/generate_clients/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="23 28 36" {!> ../../../docs_src/generate_clients/tutorial002.py!} @@ -196,7 +203,7 @@ You can then pass that custom function to **FastAPI** as the `generate_unique_id {!> ../../../docs_src/generate_clients/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8-9 12" {!> ../../../docs_src/generate_clients/tutorial003.py!} @@ -239,7 +246,7 @@ Now as the end result is in a file `openapi.json`, you would modify the `package "description": "", "main": "index.js", "scripts": { - "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios" + "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios --useOptions --useUnionTypes" }, "author": "", "license": "", diff --git a/docs/en/docs/advanced/index.md b/docs/en/docs/advanced/index.md index 467f0833e..d8dcd4ca6 100644 --- a/docs/en/docs/advanced/index.md +++ b/docs/en/docs/advanced/index.md @@ -17,8 +17,17 @@ You could still use most of the features in **FastAPI** with the knowledge from And the next sections assume you already read it, and assume that you know those main ideas. -## TestDriven.io course +## External Courses -If you would like to take an advanced-beginner course to complement this section of the docs, you might want to check: Test-Driven Development with FastAPI and Docker by **TestDriven.io**. +Although the [Tutorial - User Guide](../tutorial/){.internal-link target=_blank} and this **Advanced User Guide** are written as a guided tutorial (like a book) and should be enough for you to **learn FastAPI**, you might want to complement it with additional courses. -They are currently donating 10% of all profits to the development of **FastAPI**. ๐ŸŽ‰ ๐Ÿ˜„ +Or it might be the case that you just prefer to take other courses because they adapt better to your learning style. + +Some course providers โœจ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} โœจ, this ensures the continued and healthy **development** of FastAPI and its **ecosystem**. + +And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good learning experience** but also want to make sure you have a **good and healthy framework**, FastAPI. ๐Ÿ™‡ + +You might want to try their courses: + +* Talk Python Training +* Test-Driven Development diff --git a/docs/en/docs/advanced/security/http-basic-auth.md b/docs/en/docs/advanced/security/http-basic-auth.md index 8177a4b28..6f9002f60 100644 --- a/docs/en/docs/advanced/security/http-basic-auth.md +++ b/docs/en/docs/advanced/security/http-basic-auth.md @@ -26,13 +26,13 @@ Then, when you type that username and password, the browser sends them in the he {!> ../../../docs_src/security/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="2 7 11" {!> ../../../docs_src/security/tutorial006_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -65,13 +65,13 @@ Then we can use `secrets.compare_digest()` to ensure that `credentials.username` {!> ../../../docs_src/security/tutorial007_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 12-24" {!> ../../../docs_src/security/tutorial007_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -148,13 +148,13 @@ After detecting that the credentials are incorrect, return an `HTTPException` wi {!> ../../../docs_src/security/tutorial007_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="26-30" {!> ../../../docs_src/security/tutorial007_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/advanced/security/oauth2-scopes.md b/docs/en/docs/advanced/security/oauth2-scopes.md index 41cd61683..304a46090 100644 --- a/docs/en/docs/advanced/security/oauth2-scopes.md +++ b/docs/en/docs/advanced/security/oauth2-scopes.md @@ -68,7 +68,7 @@ First, let's quickly see the parts that change from the examples in the main **T {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="2 4 8 12 47 65 106 108-116 122-125 129-135 140 156" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -92,7 +92,7 @@ First, let's quickly see the parts that change from the examples in the main **T {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -121,7 +121,7 @@ The `scopes` parameter receives a `dict` with each scope as a key and the descri {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="63-66" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -146,7 +146,7 @@ The `scopes` parameter receives a `dict` with each scope as a key and the descri {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -188,7 +188,7 @@ And we return the scopes as part of the JWT token. {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="156" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -212,7 +212,7 @@ And we return the scopes as part of the JWT token. {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -254,7 +254,7 @@ In this case, it requires the scope `me` (it could require more than one scope). {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 140 171" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -278,7 +278,7 @@ In this case, it requires the scope `me` (it could require more than one scope). {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -320,7 +320,7 @@ This `SecurityScopes` class is similar to `Request` (`Request` was used to get t {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8 106" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -344,7 +344,7 @@ This `SecurityScopes` class is similar to `Request` (`Request` was used to get t {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -377,7 +377,7 @@ In this exception, we include the scopes required (if any) as a string separated {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="106 108-116" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -401,7 +401,7 @@ In this exception, we include the scopes required (if any) as a string separated {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -436,7 +436,7 @@ We also verify that we have a user with that username, and if not, we raise that {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="47 117-128" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -460,7 +460,7 @@ We also verify that we have a user with that username, and if not, we raise that {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -487,7 +487,7 @@ For this, we use `security_scopes.scopes`, that contains a `list` with all these {!> ../../../docs_src/security/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="129-135" {!> ../../../docs_src/security/tutorial005_an.py!} @@ -511,7 +511,7 @@ For this, we use `security_scopes.scopes`, that contains a `list` with all these {!> ../../../docs_src/security/tutorial005_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/advanced/settings.md b/docs/en/docs/advanced/settings.md index 8f6c7da93..f6db8d2b1 100644 --- a/docs/en/docs/advanced/settings.md +++ b/docs/en/docs/advanced/settings.md @@ -260,13 +260,13 @@ Now we create a dependency that returns a new `config.Settings()`. {!> ../../../docs_src/settings/app02_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="6 12-13" {!> ../../../docs_src/settings/app02_an/main.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -276,7 +276,7 @@ Now we create a dependency that returns a new `config.Settings()`. ``` !!! tip - We'll discuss the `@lru_cache()` in a bit. + We'll discuss the `@lru_cache` in a bit. For now you can assume `get_settings()` is a normal function. @@ -288,13 +288,13 @@ And then we can require it from the *path operation function* as a dependency an {!> ../../../docs_src/settings/app02_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17 19-21" {!> ../../../docs_src/settings/app02_an/main.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -326,7 +326,7 @@ This practice is common enough that it has a name, these environment variables a But a dotenv file doesn't really have to have that exact filename. -Pydantic has support for reading from these types of files using an external library. You can read more at Pydantic Settings: Dotenv (.env) support. +Pydantic has support for reading from these types of files using an external library. You can read more at Pydantic Settings: Dotenv (.env) support. !!! tip For this to work, you need to `pip install python-dotenv`. @@ -388,7 +388,7 @@ def get_settings(): we would create that object for each request, and we would be reading the `.env` file for each request. โš ๏ธ -But as we are using the `@lru_cache()` decorator on top, the `Settings` object will be created only once, the first time it's called. โœ”๏ธ +But as we are using the `@lru_cache` decorator on top, the `Settings` object will be created only once, the first time it's called. โœ”๏ธ === "Python 3.9+" @@ -396,13 +396,13 @@ But as we are using the `@lru_cache()` decorator on top, the `Settings` object w {!> ../../../docs_src/settings/app03_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 11" {!> ../../../docs_src/settings/app03_an/main.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -415,14 +415,14 @@ Then for any subsequent calls of `get_settings()` in the dependencies for the ne #### `lru_cache` Technical Details -`@lru_cache()` modifies the function it decorates to return the same value that was returned the first time, instead of computing it again, executing the code of the function every time. +`@lru_cache` modifies the function it decorates to return the same value that was returned the first time, instead of computing it again, executing the code of the function every time. So, the function below it will be executed once for each combination of arguments. And then the values returned by each of those combinations of arguments will be used again and again whenever the function is called with exactly the same combination of arguments. For example, if you have a function: ```Python -@lru_cache() +@lru_cache def say_hi(name: str, salutation: str = "Ms."): return f"Hello {salutation} {name}" ``` @@ -474,7 +474,7 @@ In the case of our dependency `get_settings()`, the function doesn't even take a That way, it behaves almost as if it was just a global variable. But as it uses a dependency function, then we can override it easily for testing. -`@lru_cache()` is part of `functools` which is part of Python's standard library, you can read more about it in the Python docs for `@lru_cache()`. +`@lru_cache` is part of `functools` which is part of Python's standard library, you can read more about it in the Python docs for `@lru_cache`. ## Recap @@ -482,4 +482,4 @@ You can use Pydantic Settings to handle the settings or configurations for your * By using a dependency you can simplify testing. * You can use `.env` files with it. -* Using `@lru_cache()` lets you avoid reading the dotenv file again and again for each request, while allowing you to override it during testing. +* Using `@lru_cache` lets you avoid reading the dotenv file again and again for each request, while allowing you to override it during testing. diff --git a/docs/en/docs/advanced/testing-dependencies.md b/docs/en/docs/advanced/testing-dependencies.md index ee48a735d..57dd87f56 100644 --- a/docs/en/docs/advanced/testing-dependencies.md +++ b/docs/en/docs/advanced/testing-dependencies.md @@ -40,7 +40,7 @@ And then **FastAPI** will call that override instead of the original dependency. {!> ../../../docs_src/dependency_testing/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="29-30 33" {!> ../../../docs_src/dependency_testing/tutorial001_an.py!} @@ -55,7 +55,7 @@ And then **FastAPI** will call that override instead of the original dependency. {!> ../../../docs_src/dependency_testing/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/advanced/websockets.md b/docs/en/docs/advanced/websockets.md index 94cf191d2..49b8fba89 100644 --- a/docs/en/docs/advanced/websockets.md +++ b/docs/en/docs/advanced/websockets.md @@ -124,7 +124,7 @@ They work the same way as for other FastAPI endpoints/*path operations*: {!> ../../../docs_src/websockets/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="69-70 83" {!> ../../../docs_src/websockets/tutorial002_an.py!} @@ -139,7 +139,7 @@ They work the same way as for other FastAPI endpoints/*path operations*: {!> ../../../docs_src/websockets/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -191,7 +191,7 @@ When a WebSocket connection is closed, the `await websocket.receive_text()` will {!> ../../../docs_src/websockets/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="81-83" {!> ../../../docs_src/websockets/tutorial003.py!} diff --git a/docs/en/docs/alternatives.md b/docs/en/docs/alternatives.md index a777ddb98..0f074ccf3 100644 --- a/docs/en/docs/alternatives.md +++ b/docs/en/docs/alternatives.md @@ -119,8 +119,6 @@ That's why when talking about version 2.0 it's common to say "Swagger", and for These two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of additional alternative user interfaces for OpenAPI (that you can use with **FastAPI**). - For example, you could try Fern which is also a FastAPI sponsor. ๐Ÿ˜Ž๐ŸŽ‰ - ### Flask REST frameworks There are several Flask REST frameworks, but after investing the time and work into investigating them, I found that many are discontinued or abandoned, with several standing issues that made them unfit. diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 3d4b1956a..2ead1f2db 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -409,11 +409,11 @@ Still, in both situations, chances are that **FastAPI** will [still be faster](/ ### Dependencies -The same applies for [dependencies](/tutorial/dependencies/index.md){.internal-link target=_blank}. If a dependency is a standard `def` function instead of `async def`, it is run in the external threadpool. +The same applies for [dependencies](./tutorial/dependencies/index.md){.internal-link target=_blank}. If a dependency is a standard `def` function instead of `async def`, it is run in the external threadpool. ### Sub-dependencies -You can have multiple dependencies and [sub-dependencies](/tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requiring each other (as parameters of the function definitions), some of them might be created with `async def` and some with normal `def`. It would still work, and the ones created with normal `def` would be called on an external thread (from the threadpool) instead of being "awaited". +You can have multiple dependencies and [sub-dependencies](./tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} requiring each other (as parameters of the function definitions), some of them might be created with `async def` and some with normal `def`. It would still work, and the ones created with normal `def` would be called on an external thread (from the threadpool) instead of being "awaited". ### Other utility functions diff --git a/docs/en/docs/css/custom.css b/docs/en/docs/css/custom.css index 066b51725..187040792 100644 --- a/docs/en/docs/css/custom.css +++ b/docs/en/docs/css/custom.css @@ -144,3 +144,39 @@ code { margin-top: 2em; margin-bottom: 2em; } + +/* Screenshots */ +/* +Simulate a browser window frame. +Inspired by Termynal's CSS tricks with modifications +*/ + +.screenshot { + display: block; + background-color: #d3e0de; + border-radius: 4px; + padding: 45px 5px 5px; + position: relative; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.screenshot img { + display: block; + border-radius: 2px; +} + +.screenshot:before { + content: ''; + position: absolute; + top: 15px; + left: 15px; + display: inline-block; + width: 15px; + height: 15px; + border-radius: 50%; + /* A little hack to display the window buttons in one pseudo element. */ + background: #d9515d; + -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; + box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; +} diff --git a/docs/en/docs/deployment/cloud.md b/docs/en/docs/deployment/cloud.md new file mode 100644 index 000000000..b2836aeb4 --- /dev/null +++ b/docs/en/docs/deployment/cloud.md @@ -0,0 +1,17 @@ +# Deploy FastAPI on Cloud Providers + +You can use virtually **any cloud provider** to deploy your FastAPI application. + +In most of the cases, the main cloud providers have guides to deploy FastAPI with them. + +## Cloud Providers - Sponsors + +Some cloud providers โœจ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} โœจ, this ensures the continued and healthy **development** of FastAPI and its **ecosystem**. + +And it shows their true commitment to FastAPI and its **community** (you), as they not only want to provide you a **good service** but also want to make sure you have a **good and healthy framework**, FastAPI. ๐Ÿ™‡ + +You might want to try their services and follow their guides: + +* Platform.sh +* Porter +* Deta diff --git a/docs/en/docs/deployment/deta.md b/docs/en/docs/deployment/deta.md deleted file mode 100644 index 229d7fd5d..000000000 --- a/docs/en/docs/deployment/deta.md +++ /dev/null @@ -1,391 +0,0 @@ -# Deploy FastAPI on Deta Space - -In this section you will learn how to easily deploy a **FastAPI** application on Deta Space, for free. ๐ŸŽ - -It will take you about **10 minutes** to deploy an API that you can use. After that, you can optionally release it to anyone. - -Let's dive in. - -!!! info - Deta is a **FastAPI** sponsor. ๐ŸŽ‰ - -## A simple **FastAPI** app - -* To start, create an empty directory with the name of your app, for example `./fastapi-deta/`, and then navigate into it. - -```console -$ mkdir fastapi-deta -$ cd fastapi-deta -``` - -### FastAPI code - -* Create a `main.py` file with: - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int): - return {"item_id": item_id} -``` - -### Requirements - -Now, in the same directory create a file `requirements.txt` with: - -```text -fastapi -uvicorn[standard] -``` - -### Directory structure - -You will now have a directory `./fastapi-deta/` with two files: - -``` -. -โ””โ”€โ”€ main.py -โ””โ”€โ”€ requirements.txt -``` - -## Create a free **Deta Space** account - -Next, create a free account on Deta Space, you just need an email and password. - -You don't even need a credit card, but make sure **Developer Mode** is enabled when you sign up. - - -## Install the CLI - -Once you have your account, install the Deta Space CLI: - -=== "Linux, macOS" - -
- - ```console - $ curl -fsSL https://get.deta.dev/space-cli.sh | sh - ``` - -
- -=== "Windows PowerShell" - -
- - ```console - $ iwr https://get.deta.dev/space-cli.ps1 -useb | iex - ``` - -
- -After installing it, open a new terminal so that the installed CLI is detected. - -In a new terminal, confirm that it was correctly installed with: - -
- -```console -$ space --help - -Deta command line interface for managing deta micros. -Complete documentation available at https://deta.space/docs - -Usage: - space [flags] - space [command] - -Available Commands: - help Help about any command - link link code to project - login login to space - new create new project - push push code for project - release create release for a project - validate validate spacefile in dir - version Space CLI version -... -``` - -
- -!!! tip - If you have problems installing the CLI, check the official Deta Space Documentation. - -## Login with the CLI - -In order to authenticate your CLI with Deta Space, you will need an access token. - -To obtain this token, open your Deta Space Canvas, open the **Teletype** (command bar at the bottom of the Canvas), and then click on **Settings**. From there, select **Generate Token** and copy the resulting token. - - - -Now run `space login` from the Space CLI. Upon pasting the token into the CLI prompt and pressing enter, you should see a confirmation message. - -
- -```console -$ space login - -To authenticate the Space CLI with your Space account, generate a new access token in your Space settings and paste it below: - -# Enter access token (41 chars) >$ ***************************************** - -๐Ÿ‘ Login Successful! -``` - -
- -## Create a new project in Space - -Now that you've authenticated with the Space CLI, use it to create a new Space Project: - -```console -$ space new - -# What is your project's name? >$ fastapi-deta -``` - -The Space CLI will ask you to name the project, we will call ours `fastapi-deta`. - -Then, it will try to automatically detect which framework or language you are using, showing you what it finds. In our case it will identify the Python app with the following message, prompting you to confirm: - -```console -โš™๏ธ No Spacefile found, trying to auto-detect configuration ... -๐Ÿ‘‡ Deta detected the following configuration: - -Micros: -name: fastapi-deta - L src: . - L engine: python3.9 - -# Do you want to bootstrap "fastapi-deta" with this configuration? (y/n)$ y -``` - -After you confirm, your project will be created in Deta Space inside a special app called Builder. Builder is a toolbox that helps you to create and manage your apps in Deta Space. - -The CLI will also create a `Spacefile` locally in the `fastapi-deta` directory. The Spacefile is a configuration file which tells Deta Space how to run your app. The `Spacefile` for your app will be as follows: - -```yaml -v: 0 -micros: - - name: fastapi-deta - src: . - engine: python3.9 -``` - -It is a `yaml` file, and you can use it to add features like scheduled tasks or modify how your app functions, which we'll do later. To learn more, read the `Spacefile` documentation. - -!!! tip - The Space CLI will also create a hidden `.space` folder in your local directory to link your local environment with Deta Space. This folder should not be included in your version control and will automatically be added to your `.gitignore` file, if you have initialized a Git repository. - -## Define the run command in the Spacefile - -The `run` command in the Spacefile tells Space what command should be executed to start your app. In this case it would be `uvicorn main:app`. - -```diff -v: 0 -micros: - - name: fastapi-deta - src: . - engine: python3.9 -+ run: uvicorn main:app -``` - -## Deploy to Deta Space - -To get your FastAPI live in the cloud, use one more CLI command: - -
- -```console -$ space push - ----> 100% - -build complete... created revision: satyr-jvjk - -โœ” Successfully pushed your code and created a new Revision! -โ„น Updating your development instance with the latest Revision, it will be available on your Canvas shortly. -``` -
- -This command will package your code, upload all the necessary files to Deta Space, and run a remote build of your app, resulting in a **revision**. Whenever you run `space push` successfully, a live instance of your API is automatically updated with the latest revision. - -!!! tip - You can manage your revisions by opening your project in the Builder app. The live copy of your API will be visible under the **Develop** tab in Builder. - -## Check it - -The live instance of your API will also be added automatically to your Canvas (the dashboard) on Deta Space. - - - -Click on the new app called `fastapi-deta`, and it will open your API in a new browser tab on a URL like `https://fastapi-deta-gj7ka8.deta.app/`. - -You will get a JSON response from your FastAPI app: - -```JSON -{ - "Hello": "World" -} -``` - -And now you can head over to the `/docs` of your API. For this example, it would be `https://fastapi-deta-gj7ka8.deta.app/docs`. - - - -## Enable public access - -Deta will handle authentication for your account using cookies. By default, every app or API that you `push` or install to your Space is personal - it's only accessible to you. - -But you can also make your API public using the `Spacefile` from earlier. - -With a `public_routes` parameter, you can specify which paths of your API should be available to the public. - -Set your `public_routes` to `"*"` to open every route of your API to the public: - -```yaml -v: 0 -micros: - - name: fastapi-deta - src: . - engine: python3.9 - public_routes: - - "/*" -``` - -Then run `space push` again to update your live API on Deta Space. - -Once it deploys, you can share your URL with anyone and they will be able to access your API. ๐Ÿš€ - -## HTTPS - -Congrats! You deployed your FastAPI app to Deta Space! ๐ŸŽ‰ ๐Ÿฐ - -Also, notice that Deta Space correctly handles HTTPS for you, so you don't have to take care of that and can be sure that your users will have a secure encrypted connection. โœ… ๐Ÿ”’ - -## Create a release - -Space also allows you to publish your API. When you publish it, anyone else can install their own copy of your API, in their own Deta Space cloud. - -To do so, run `space release` in the Space CLI to create an **unlisted release**: - -
- -```console -$ space release - -# Do you want to use the latest revision (buzzard-hczt)? (y/n)$ y - -~ Creating a Release with the latest Revision - ----> 100% - -creating release... -publishing release in edge locations.. -completed... -released: fastapi-deta-exp-msbu -https://deta.space/discovery/r/5kjhgyxewkdmtotx - - Lift off -- successfully created a new Release! - Your Release is available globally on 5 Deta Edges - Anyone can install their own copy of your app. -``` -
- -This command publishes your revision as a release and gives you a link. Anyone you give this link to can install your API. - - -You can also make your app publicly discoverable by creating a **listed release** with `space release --listed` in the Space CLI: - -
- -```console -$ space release --listed - -# Do you want to use the latest revision (buzzard-hczt)? (y/n)$ y - -~ Creating a listed Release with the latest Revision ... - -creating release... -publishing release in edge locations.. -completed... -released: fastapi-deta-exp-msbu -https://deta.space/discovery/@user/fastapi-deta - - Lift off -- successfully created a new Release! - Your Release is available globally on 5 Deta Edges - Anyone can install their own copy of your app. - Listed on Discovery for others to find! -``` -
- -This will allow anyone to find and install your app via Deta Discovery. Read more about releasing your app in the docs. - -## Check runtime logs - -Deta Space also lets you inspect the logs of every app you build or install. - -Add some logging functionality to your app by adding a `print` statement to your `main.py` file. - -```py -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int): - print(item_id) - return {"item_id": item_id} -``` - -The code within the `read_item` function includes a print statement that will output the `item_id` that is included in the URL. Send a request to your _path operation_ `/items/{item_id}` from the docs UI (which will have a URL like `https://fastapi-deta-gj7ka8.deta.app/docs`), using an ID like `5` as an example. - -Now go to your Space's Canvas. Click on the context menu (`...`) of your live app instance, and then click on **View Logs**. Here you can view your app's logs, sorted by time. - - - -## Learn more - -At some point, you will probably want to store some data for your app in a way that persists through time. For that you can use Deta Base and Deta Drive, both of which have a generous **free tier**. - -You can also read more in the Deta Space Documentation. - -!!! tip - If you have any Deta related questions, comments, or feedback, head to the Deta Discord server. - - -## Deployment Concepts - -Coming back to the concepts we discussed in [Deployments Concepts](./concepts.md){.internal-link target=_blank}, here's how each of them would be handled with Deta Space: - -- **HTTPS**: Handled by Deta Space, they will give you a subdomain and handle HTTPS automatically. -- **Running on startup**: Handled by Deta Space, as part of their service. -- **Restarts**: Handled by Deta Space, as part of their service. -- **Replication**: Handled by Deta Space, as part of their service. -- **Authentication**: Handled by Deta Space, as part of their service. -- **Memory**: Limit predefined by Deta Space, you could contact them to increase it. -- **Previous steps before starting**: Can be configured using the `Spacefile`. - -!!! note - Deta Space is designed to make it easy and free to build cloud applications for yourself. Then you can optionally share them with anyone. - - It can simplify several use cases, but at the same time, it doesn't support others, like using external databases (apart from Deta's own NoSQL database system), custom virtual machines, etc. - - You can read more details in the Deta Space Documentation to see if it's the right choice for you. diff --git a/docs/en/docs/deployment/server-workers.md b/docs/en/docs/deployment/server-workers.md index 4ccd9d9f6..2df9f3d43 100644 --- a/docs/en/docs/deployment/server-workers.md +++ b/docs/en/docs/deployment/server-workers.md @@ -90,7 +90,9 @@ Let's see what each of those options mean: ``` * So, the colon in `main:app` would be equivalent to the Python `import` part in `from main import app`. + * `--workers`: The number of worker processes to use, each will run a Uvicorn worker, in this case, 4 workers. + * `--worker-class`: The Gunicorn-compatible worker class to use in the worker processes. * Here we pass the class that Gunicorn can import and use with: diff --git a/docs/en/docs/external-links.md b/docs/en/docs/external-links.md index 0c91470bc..b89021ee2 100644 --- a/docs/en/docs/external-links.md +++ b/docs/en/docs/external-links.md @@ -9,79 +9,21 @@ Here's an incomplete list of some of them. !!! tip If you have an article, project, tool, or anything related to **FastAPI** that is not yet listed here, create a Pull Request adding it. -## Articles +{% for section_name, section_content in external_links.items() %} -### English +## {{ section_name }} -{% if external_links %} -{% for article in external_links.articles.english %} +{% for lang_name, lang_content in section_content.items() %} + +### {{ lang_name }} + +{% for item in lang_content %} + +* {{ item.title }} by {{ item.author }}. -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### Japanese - -{% if external_links %} -{% for article in external_links.articles.japanese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### Vietnamese - -{% if external_links %} -{% for article in external_links.articles.vietnamese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### Russian - -{% if external_links %} -{% for article in external_links.articles.russian %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -### German - -{% if external_links %} -{% for article in external_links.articles.german %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -### Taiwanese - -{% if external_links %} -{% for article in external_links.articles.taiwanese %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## Podcasts - -{% if external_links %} -{% for article in external_links.podcasts.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## Talks - -{% if external_links %} -{% for article in external_links.talks.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} ## Projects diff --git a/docs/en/docs/fastapi-people.md b/docs/en/docs/fastapi-people.md index 20caaa1ee..7e26358d8 100644 --- a/docs/en/docs/fastapi-people.md +++ b/docs/en/docs/fastapi-people.md @@ -1,3 +1,8 @@ +--- +hide: + - navigation +--- + # FastAPI People FastAPI has an amazing community that welcomes people from all backgrounds. diff --git a/docs/en/docs/features.md b/docs/en/docs/features.md index 98f37b534..6f13b03bb 100644 --- a/docs/en/docs/features.md +++ b/docs/en/docs/features.md @@ -1,3 +1,8 @@ +--- +hide: + - navigation +--- + # Features ## FastAPI features diff --git a/docs/en/docs/help-fastapi.md b/docs/en/docs/help-fastapi.md index e977dba20..8199c9b9a 100644 --- a/docs/en/docs/help-fastapi.md +++ b/docs/en/docs/help-fastapi.md @@ -231,8 +231,6 @@ Join the ๐Ÿ‘ฅ Gitter chat, but as it doesn't have channels and advanced features, conversations are more difficult, so Discord is now the recommended system. - ### Don't use the chat for questions Have in mind that as chats allow more "free conversation", it's easy to ask questions that are too general and more difficult to answer, so, you might not receive answers. diff --git a/docs/en/docs/help/index.md b/docs/en/docs/help/index.md new file mode 100644 index 000000000..5ee7df2fe --- /dev/null +++ b/docs/en/docs/help/index.md @@ -0,0 +1,3 @@ +# Help + +Help and get help, contribute, get involved. ๐Ÿค diff --git a/docs/en/docs/advanced/async-sql-databases.md b/docs/en/docs/how-to/async-sql-encode-databases.md similarity index 98% rename from docs/en/docs/advanced/async-sql-databases.md rename to docs/en/docs/how-to/async-sql-encode-databases.md index 12549a190..697167f79 100644 --- a/docs/en/docs/advanced/async-sql-databases.md +++ b/docs/en/docs/how-to/async-sql-encode-databases.md @@ -1,4 +1,4 @@ -# Async SQL (Relational) Databases +# Async SQL (Relational) Databases with Encode/Databases !!! info These docs are about to be updated. ๐ŸŽ‰ diff --git a/docs/en/docs/advanced/conditional-openapi.md b/docs/en/docs/how-to/conditional-openapi.md similarity index 100% rename from docs/en/docs/advanced/conditional-openapi.md rename to docs/en/docs/how-to/conditional-openapi.md diff --git a/docs/en/docs/how-to/configure-swagger-ui.md b/docs/en/docs/how-to/configure-swagger-ui.md new file mode 100644 index 000000000..f36ba5ba8 --- /dev/null +++ b/docs/en/docs/how-to/configure-swagger-ui.md @@ -0,0 +1,78 @@ +# Configure Swagger UI + +You can configure some extra Swagger UI parameters. + +To configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function. + +`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly. + +FastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs. + +## Disable Syntax Highlighting + +For example, you could disable syntax highlighting in Swagger UI. + +Without changing the settings, syntax highlighting is enabled by default: + + + +But you can disable it by setting `syntaxHighlight` to `False`: + +```Python hl_lines="3" +{!../../../docs_src/configure_swagger_ui/tutorial001.py!} +``` + +...and then Swagger UI won't show the syntax highlighting anymore: + + + +## Change the Theme + +The same way you could set the syntax highlighting theme with the key `"syntaxHighlight.theme"` (notice that it has a dot in the middle): + +```Python hl_lines="3" +{!../../../docs_src/configure_swagger_ui/tutorial002.py!} +``` + +That configuration would change the syntax highlighting color theme: + + + +## Change Default Swagger UI Parameters + +FastAPI includes some default configuration parameters appropriate for most of the use cases. + +It includes these default configurations: + +```Python +{!../../../fastapi/openapi/docs.py[ln:7-13]!} +``` + +You can override any of them by setting a different value in the argument `swagger_ui_parameters`. + +For example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`: + +```Python hl_lines="3" +{!../../../docs_src/configure_swagger_ui/tutorial003.py!} +``` + +## Other Swagger UI Parameters + +To see all the other possible configurations you can use, read the official docs for Swagger UI parameters. + +## JavaScript-only settings + +Swagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions). + +FastAPI also includes these JavaScript-only `presets` settings: + +```JavaScript +presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIBundle.SwaggerUIStandalonePreset +] +``` + +These are **JavaScript** objects, not strings, so you can't pass them from Python code directly. + +If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need. diff --git a/docs/en/docs/how-to/custom-docs-ui-assets.md b/docs/en/docs/how-to/custom-docs-ui-assets.md new file mode 100644 index 000000000..9726be2c7 --- /dev/null +++ b/docs/en/docs/how-to/custom-docs-ui-assets.md @@ -0,0 +1,199 @@ +# Custom Docs UI Static Assets (Self-Hosting) + +The API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files. + +By default, those files are served from a CDN. + +But it's possible to customize it, you can set a specific CDN, or serve the files yourself. + +## Custom CDN for JavaScript and CSS + +Let's say that you want to use a different CDN, for example you want to use `https://unpkg.com/`. + +This could be useful if for example you live in a country that restricts some URLs. + +### Disable the automatic docs + +The first step is to disable the automatic docs, as by default, those use the default CDN. + +To disable them, set their URLs to `None` when creating your `FastAPI` app: + +```Python hl_lines="8" +{!../../../docs_src/custom_docs_ui/tutorial001.py!} +``` + +### Include the custom docs + +Now you can create the *path operations* for the custom docs. + +You can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments: + +* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`. +* `title`: the title of your API. +* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default. +* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the custom CDN URL. +* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the custom CDN URL. + +And similarly for ReDoc... + +```Python hl_lines="2-6 11-19 22-24 27-33" +{!../../../docs_src/custom_docs_ui/tutorial001.py!} +``` + +!!! tip + The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2. + + If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication. + + Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper. + +### Create a *path operation* to test it + +Now, to be able to test that everything works, create a *path operation*: + +```Python hl_lines="36-38" +{!../../../docs_src/custom_docs_ui/tutorial001.py!} +``` + +### Test it + +Now, you should be able to go to your docs at http://127.0.0.1:8000/docs, and reload the page, it will load those assets from the new CDN. + +## Self-hosting JavaScript and CSS for docs + +Self-hosting the JavaScript and CSS could be useful if, for example, you need your app to keep working even while offline, without open Internet access, or in a local network. + +Here you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them. + +### Project file structure + +Let's say your project file structure looks like this: + +``` +. +โ”œโ”€โ”€ app +โ”‚ โ”œโ”€โ”€ __init__.py +โ”‚ โ”œโ”€โ”€ main.py +``` + +Now create a directory to store those static files. + +Your new file structure could look like this: + +``` +. +โ”œโ”€โ”€ app +โ”‚ย ย  โ”œโ”€โ”€ __init__.py +โ”‚ย ย  โ”œโ”€โ”€ main.py +โ””โ”€โ”€ static/ +``` + +### Download the files + +Download the static files needed for the docs and put them on that `static/` directory. + +You can probably right-click each link and select an option similar to `Save link as...`. + +**Swagger UI** uses the files: + +* `swagger-ui-bundle.js` +* `swagger-ui.css` + +And **ReDoc** uses the file: + +* `redoc.standalone.js` + +After that, your file structure could look like: + +``` +. +โ”œโ”€โ”€ app +โ”‚ย ย  โ”œโ”€โ”€ __init__.py +โ”‚ย ย  โ”œโ”€โ”€ main.py +โ””โ”€โ”€ static + โ”œโ”€โ”€ redoc.standalone.js + โ”œโ”€โ”€ swagger-ui-bundle.js + โ””โ”€โ”€ swagger-ui.css +``` + +### Serve the static files + +* Import `StaticFiles`. +* "Mount" a `StaticFiles()` instance in a specific path. + +```Python hl_lines="7 11" +{!../../../docs_src/custom_docs_ui/tutorial002.py!} +``` + +### Test the static files + +Start your application and go to http://127.0.0.1:8000/static/redoc.standalone.js. + +You should see a very long JavaScript file for **ReDoc**. + +It could start with something like: + +```JavaScript +/*! + * ReDoc - OpenAPI/Swagger-generated API Reference Documentation + * ------------------------------------------------------------- + * Version: "2.0.0-rc.18" + * Repo: https://github.com/Redocly/redoc + */ +!function(e,t){"object"==typeof exports&&"object"==typeof m + +... +``` + +That confirms that you are being able to serve static files from your app, and that you placed the static files for the docs in the correct place. + +Now we can configure the app to use those static files for the docs. + +### Disable the automatic docs for static files + +The same as when using a custom CDN, the first step is to disable the automatic docs, as those use the CDN by default. + +To disable them, set their URLs to `None` when creating your `FastAPI` app: + +```Python hl_lines="9" +{!../../../docs_src/custom_docs_ui/tutorial002.py!} +``` + +### Include the custom docs for static files + +And the same way as with a custom CDN, now you can create the *path operations* for the custom docs. + +Again, you can re-use FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments: + +* `openapi_url`: the URL where the HTML page for the docs can get the OpenAPI schema for your API. You can use here the attribute `app.openapi_url`. +* `title`: the title of your API. +* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default. +* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. **This is the one that your own app is now serving**. +* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. **This is the one that your own app is now serving**. + +And similarly for ReDoc... + +```Python hl_lines="2-6 14-22 25-27 30-36" +{!../../../docs_src/custom_docs_ui/tutorial002.py!} +``` + +!!! tip + The *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2. + + If you integrate your API with an OAuth2 provider, you will be able to authenticate and come back to the API docs with the acquired credentials. And interact with it using the real OAuth2 authentication. + + Swagger UI will handle it behind the scenes for you, but it needs this "redirect" helper. + +### Create a *path operation* to test static files + +Now, to be able to test that everything works, create a *path operation*: + +```Python hl_lines="39-41" +{!../../../docs_src/custom_docs_ui/tutorial002.py!} +``` + +### Test Static Files UI + +Now, you should be able to disconnect your WiFi, go to your docs at http://127.0.0.1:8000/docs, and reload the page. + +And even without Internet, you would be able to see the docs for your API and interact with it. diff --git a/docs/en/docs/advanced/custom-request-and-route.md b/docs/en/docs/how-to/custom-request-and-route.md similarity index 100% rename from docs/en/docs/advanced/custom-request-and-route.md rename to docs/en/docs/how-to/custom-request-and-route.md diff --git a/docs/en/docs/how-to/extending-openapi.md b/docs/en/docs/how-to/extending-openapi.md new file mode 100644 index 000000000..a18fd737e --- /dev/null +++ b/docs/en/docs/how-to/extending-openapi.md @@ -0,0 +1,87 @@ +# Extending OpenAPI + +There are some cases where you might need to modify the generated OpenAPI schema. + +In this section you will see how. + +## The normal process + +The normal (default) process, is as follows. + +A `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema. + +As part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered. + +It just returns a JSON response with the result of the application's `.openapi()` method. + +By default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them. + +If it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`. + +And that function `get_openapi()` receives as parameters: + +* `title`: The OpenAPI title, shown in the docs. +* `version`: The version of your API, e.g. `2.5.0`. +* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`. +* `summary`: A short summary of the API. +* `description`: The description of your API, this can include markdown and will be shown in the docs. +* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`. + +!!! info + The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above. + +## Overriding the defaults + +Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need. + +For example, let's add ReDoc's OpenAPI extension to include a custom logo. + +### Normal **FastAPI** + +First, write all your **FastAPI** application as normally: + +```Python hl_lines="1 4 7-9" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### Generate the OpenAPI schema + +Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function: + +```Python hl_lines="2 15-21" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### Modify the OpenAPI schema + +Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema: + +```Python hl_lines="22-24" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### Cache the OpenAPI schema + +You can use the property `.openapi_schema` as a "cache", to store your generated schema. + +That way, your application won't have to generate the schema every time a user opens your API docs. + +It will be generated only once, and then the same cached schema will be used for the next requests. + +```Python hl_lines="13-14 25-26" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### Override the method + +Now you can replace the `.openapi()` method with your new function. + +```Python hl_lines="29" +{!../../../docs_src/extending_openapi/tutorial001.py!} +``` + +### Check it + +Once you go to http://127.0.0.1:8000/redoc you will see that you are using your custom logo (in this example, **FastAPI**'s logo): + + diff --git a/docs/en/docs/how-to/general.md b/docs/en/docs/how-to/general.md new file mode 100644 index 000000000..04367c6b7 --- /dev/null +++ b/docs/en/docs/how-to/general.md @@ -0,0 +1,39 @@ +# General - How To - Recipes + +Here are several pointers to other places in the docs, for general or frequent questions. + +## Filter Data - Security + +To ensure that you don't return more data than you should, read the docs for [Tutorial - Response Model - Return Type](../tutorial/response-model.md){.internal-link target=_blank}. + +## Documentation Tags - OpenAPI + +To add tags to your *path operations*, and group them in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Tags](../tutorial/path-operation-configuration.md#tags){.internal-link target=_blank}. + +## Documentation Summary and Description - OpenAPI + +To add a summary and description to your *path operations*, and show them in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Summary and Description](../tutorial/path-operation-configuration.md#summary-and-description){.internal-link target=_blank}. + +## Documentation Response description - OpenAPI + +To define the description of the response, shown in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Response description](../tutorial/path-operation-configuration.md#response-description){.internal-link target=_blank}. + +## Documentation Deprecate a *Path Operation* - OpenAPI + +To deprecate a *path operation*, and show it in the docs UI, read the docs for [Tutorial - Path Operation Configurations - Deprecation](../tutorial/path-operation-configuration.md#deprecate-a-path-operation){.internal-link target=_blank}. + +## Convert any Data to JSON-compatible + +To convert any data to JSON-compatible, read the docs for [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md){.internal-link target=_blank}. + +## OpenAPI Metadata - Docs + +To add metadata to your OpenAPI schema, including a license, version, contact, etc, read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md){.internal-link target=_blank}. + +## OpenAPI Custom URL + +To customize the OpenAPI URL (or remove it), read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#openapi-url){.internal-link target=_blank}. + +## OpenAPI Docs URLs + +To update the URLs used for the automatically generated docs user interfaces, read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#docs-urls){.internal-link target=_blank}. diff --git a/docs/en/docs/advanced/graphql.md b/docs/en/docs/how-to/graphql.md similarity index 100% rename from docs/en/docs/advanced/graphql.md rename to docs/en/docs/how-to/graphql.md diff --git a/docs/en/docs/how-to/index.md b/docs/en/docs/how-to/index.md new file mode 100644 index 000000000..ec7fd38f8 --- /dev/null +++ b/docs/en/docs/how-to/index.md @@ -0,0 +1,11 @@ +# How To - Recipes + +Here you will see different recipes or "how to" guides for **several topics**. + +Most of these ideas would be more or less **independent**, and in most cases you should only need to study them if they apply directly to **your project**. + +If something seems interesting and useful to your project, go ahead and check it, but otherwise, you might probably just skip them. + +!!! tip + + If you want to **learn FastAPI** in a structured way (recommended), go and read the [Tutorial - User Guide](../tutorial/index.md){.internal-link target=_blank} chapter by chapter instead. diff --git a/docs/en/docs/advanced/nosql-databases.md b/docs/en/docs/how-to/nosql-databases-couchbase.md similarity index 99% rename from docs/en/docs/advanced/nosql-databases.md rename to docs/en/docs/how-to/nosql-databases-couchbase.md index 606db35c7..ae6ad604b 100644 --- a/docs/en/docs/advanced/nosql-databases.md +++ b/docs/en/docs/how-to/nosql-databases-couchbase.md @@ -1,4 +1,4 @@ -# NoSQL (Distributed / Big Data) Databases +# NoSQL (Distributed / Big Data) Databases with Couchbase !!! info These docs are about to be updated. ๐ŸŽ‰ diff --git a/docs/en/docs/how-to/separate-openapi-schemas.md b/docs/en/docs/how-to/separate-openapi-schemas.md new file mode 100644 index 000000000..10be1071a --- /dev/null +++ b/docs/en/docs/how-to/separate-openapi-schemas.md @@ -0,0 +1,231 @@ +# Separate OpenAPI Schemas for Input and Output or Not + +When using **Pydantic v2**, the generated OpenAPI is a bit more exact and **correct** than before. ๐Ÿ˜Ž + +In fact, in some cases, it will even have **two JSON Schemas** in OpenAPI for the same Pydantic model, for input and output, depending on if they have **default values**. + +Let's see how that works and how to change it if you need to do that. + +## Pydantic Models for Input and Output + +Let's say you have a Pydantic model with default values, like this one: + +=== "Python 3.10+" + + ```Python hl_lines="7" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-7]!} + + # Code below omitted ๐Ÿ‘‡ + ``` + +
+ ๐Ÿ‘€ Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!} + ``` + +
+ +=== "Python 3.9+" + + ```Python hl_lines="9" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-9]!} + + # Code below omitted ๐Ÿ‘‡ + ``` + +
+ ๐Ÿ‘€ Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!} + ``` + +
+ +=== "Python 3.8+" + + ```Python hl_lines="9" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-9]!} + + # Code below omitted ๐Ÿ‘‡ + ``` + +
+ ๐Ÿ‘€ Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!} + ``` + +
+ +### Model for Input + +If you use this model as an input like here: + +=== "Python 3.10+" + + ```Python hl_lines="14" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py[ln:1-15]!} + + # Code below omitted ๐Ÿ‘‡ + ``` + +
+ ๐Ÿ‘€ Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!} + ``` + +
+ +=== "Python 3.9+" + + ```Python hl_lines="16" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py[ln:1-17]!} + + # Code below omitted ๐Ÿ‘‡ + ``` + +
+ ๐Ÿ‘€ Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!} + ``` + +
+ +=== "Python 3.8+" + + ```Python hl_lines="16" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py[ln:1-17]!} + + # Code below omitted ๐Ÿ‘‡ + ``` + +
+ ๐Ÿ‘€ Full file preview + + ```Python + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!} + ``` + +
+ +...then the `description` field will **not be required**. Because it has a default value of `None`. + +### Input Model in Docs + +You can confirm that in the docs, the `description` field doesn't have a **red asterisk**, it's not marked as required: + +
+ +
+ +### Model for Output + +But if you use the same model as an output, like here: + +=== "Python 3.10+" + + ```Python hl_lines="19" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="21" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="21" + {!> ../../../docs_src/separate_openapi_schemas/tutorial001.py!} + ``` + +...then because `description` has a default value, if you **don't return anything** for that field, it will still have that **default value**. + +### Model for Output Response Data + +If you interact with the docs and check the response, even though the code didn't add anything in one of the `description` fields, the JSON response contains the default value (`null`): + +
+ +
+ +This means that it will **always have a value**, it's just that sometimes the value could be `None` (or `null` in JSON). + +That means that, clients using your API don't have to check if the value exists or not, they can **assume the field will always be there**, but just that in some cases it will have the default value of `None`. + +The way to describe this in OpenAPI, is to mark that field as **required**, because it will always be there. + +Because of that, the JSON Schema for a model can be different depending on if it's used for **input or output**: + +* for **input** the `description` will **not be required** +* for **output** it will be **required** (and possibly `None`, or in JSON terms, `null`) + +### Model for Output in Docs + +You can check the output model in the docs too, **both** `name` and `description` are marked as **required** with a **red asterisk**: + +
+ +
+ +### Model for Input and Output in Docs + +And if you check all the available Schemas (JSON Schemas) in OpenAPI, you will see that there are two, one `Item-Input` and one `Item-Output`. + +For `Item-Input`, `description` is **not required**, it doesn't have a red asterisk. + +But for `Item-Output`, `description` is **required**, it has a red asterisk. + +
+ +
+ +With this feature from **Pydantic v2**, your API documentation is more **precise**, and if you have autogenerated clients and SDKs, they will be more precise too, with a better **developer experience** and consistency. ๐ŸŽ‰ + +## Do not Separate Schemas + +Now, there are some cases where you might want to have the **same schema for input and output**. + +Probably the main use case for this is if you already have some autogenerated client code/SDKs and you don't want to update all the autogenerated client code/SDKs yet, you probably will want to do it at some point, but maybe not right now. + +In that case, you can disable this feature in **FastAPI**, with the parameter `separate_input_output_schemas=False`. + +!!! info + Support for `separate_input_output_schemas` was added in FastAPI `0.102.0`. ๐Ÿค“ + +=== "Python 3.10+" + + ```Python hl_lines="10" + {!> ../../../docs_src/separate_openapi_schemas/tutorial002_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="12" + {!> ../../../docs_src/separate_openapi_schemas/tutorial002_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="12" + {!> ../../../docs_src/separate_openapi_schemas/tutorial002.py!} + ``` + +### Same Schema for Input and Output Models in Docs + +And now there will be one single schema for input and output for the model, only `Item`, and it will have `description` as **not required**: + +
+ +
+ +This is the same behavior as in Pydantic v1. ๐Ÿค“ diff --git a/docs/en/docs/advanced/sql-databases-peewee.md b/docs/en/docs/how-to/sql-databases-peewee.md similarity index 99% rename from docs/en/docs/advanced/sql-databases-peewee.md rename to docs/en/docs/how-to/sql-databases-peewee.md index 6a469634f..b0ab7c633 100644 --- a/docs/en/docs/advanced/sql-databases-peewee.md +++ b/docs/en/docs/how-to/sql-databases-peewee.md @@ -12,6 +12,8 @@ Because Pewee doesn't play well with anything async and there are better alternatives, I won't update these docs for Pydantic v2, they are kept for now only for historical purposes. + The examples here are no longer tested in CI (as they were before). + If you are starting a project from scratch, you are probably better off with SQLAlchemy ORM ([SQL (Relational) Databases](../tutorial/sql-databases.md){.internal-link target=_blank}), or any other async ORM. If you already have a code base that uses Peewee ORM, you can check here how to use it with **FastAPI**. @@ -361,7 +363,7 @@ It will have the database connection open at the beginning and will just wait so This will easily let you test that your app with Peewee and FastAPI is behaving correctly with all the stuff about threads. -If you want to check how Peewee would break your app if used without modification, go the the `sql_app/database.py` file and comment the line: +If you want to check how Peewee would break your app if used without modification, go the `sql_app/database.py` file and comment the line: ```Python # db._state = PeeweeConnectionState() diff --git a/docs/en/docs/img/sponsors/bump-sh-banner.png b/docs/en/docs/img/sponsors/bump-sh-banner.png new file mode 100755 index 000000000..e75c0facd Binary files /dev/null and b/docs/en/docs/img/sponsors/bump-sh-banner.png differ diff --git a/docs/en/docs/img/sponsors/bump-sh-banner.svg b/docs/en/docs/img/sponsors/bump-sh-banner.svg new file mode 100644 index 000000000..c8ec7675a --- /dev/null +++ b/docs/en/docs/img/sponsors/bump-sh-banner.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/img/sponsors/bump-sh.png b/docs/en/docs/img/sponsors/bump-sh.png new file mode 100755 index 000000000..61817e86f Binary files /dev/null and b/docs/en/docs/img/sponsors/bump-sh.png differ diff --git a/docs/en/docs/img/sponsors/bump-sh.svg b/docs/en/docs/img/sponsors/bump-sh.svg new file mode 100644 index 000000000..053e54b1d --- /dev/null +++ b/docs/en/docs/img/sponsors/bump-sh.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/en/docs/img/sponsors/codacy.png b/docs/en/docs/img/sponsors/codacy.png new file mode 100644 index 000000000..baa615c2a Binary files /dev/null and b/docs/en/docs/img/sponsors/codacy.png differ diff --git a/docs/en/docs/img/sponsors/propelauth-banner.png b/docs/en/docs/img/sponsors/propelauth-banner.png new file mode 100644 index 000000000..7a1bb2580 Binary files /dev/null and b/docs/en/docs/img/sponsors/propelauth-banner.png differ diff --git a/docs/en/docs/img/sponsors/propelauth.png b/docs/en/docs/img/sponsors/propelauth.png new file mode 100644 index 000000000..8234d631f Binary files /dev/null and b/docs/en/docs/img/sponsors/propelauth.png differ diff --git a/docs/en/docs/img/sponsors/reflex-banner.png b/docs/en/docs/img/sponsors/reflex-banner.png new file mode 100644 index 000000000..3095c3a7b Binary files /dev/null and b/docs/en/docs/img/sponsors/reflex-banner.png differ diff --git a/docs/en/docs/img/sponsors/reflex.png b/docs/en/docs/img/sponsors/reflex.png new file mode 100644 index 000000000..59c46a110 Binary files /dev/null and b/docs/en/docs/img/sponsors/reflex.png differ diff --git a/docs/en/docs/img/sponsors/scalar-banner.svg b/docs/en/docs/img/sponsors/scalar-banner.svg new file mode 100644 index 000000000..bab74e2d7 --- /dev/null +++ b/docs/en/docs/img/sponsors/scalar-banner.svg @@ -0,0 +1 @@ + diff --git a/docs/en/docs/img/sponsors/scalar.svg b/docs/en/docs/img/sponsors/scalar.svg new file mode 100644 index 000000000..174c57ee2 --- /dev/null +++ b/docs/en/docs/img/sponsors/scalar.svg @@ -0,0 +1 @@ + diff --git a/docs/en/docs/img/sponsors/speakeasy.png b/docs/en/docs/img/sponsors/speakeasy.png new file mode 100644 index 000000000..001b4b4ca Binary files /dev/null and b/docs/en/docs/img/sponsors/speakeasy.png differ diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png new file mode 100644 index 000000000..aa085f88d Binary files /dev/null and b/docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png differ diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png new file mode 100644 index 000000000..672ef1d2b Binary files /dev/null and b/docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png differ diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png new file mode 100644 index 000000000..81340fbec Binary files /dev/null and b/docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png differ diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png new file mode 100644 index 000000000..fc2302aa7 Binary files /dev/null and b/docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png differ diff --git a/docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png b/docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png new file mode 100644 index 000000000..674dd0b2e Binary files /dev/null and b/docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png differ diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index ebd74bc8f..3660e74e3 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -1,3 +1,12 @@ +--- +hide: + - navigation +--- + + +

FastAPI

@@ -27,7 +36,7 @@ --- -FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. +FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.8+ based on standard Python type hints. The key features are: @@ -115,7 +124,7 @@ If you are building a CLI app to be ## Requirements -Python 3.7+ +Python 3.8+ FastAPI stands on the shoulders of giants: @@ -331,7 +340,7 @@ You do that with standard modern Python types. You don't have to learn a new syntax, the methods or classes of a specific library, etc. -Just standard **Python 3.7+**. +Just standard **Python 3.8+**. For example, for an `int`: diff --git a/docs/en/docs/js/chat.js b/docs/en/docs/js/chat.js deleted file mode 100644 index debdef4da..000000000 --- a/docs/en/docs/js/chat.js +++ /dev/null @@ -1,3 +0,0 @@ -((window.gitter = {}).chat = {}).options = { - room: 'tiangolo/fastapi' -}; diff --git a/docs/en/docs/learn/index.md b/docs/en/docs/learn/index.md new file mode 100644 index 000000000..d056fb320 --- /dev/null +++ b/docs/en/docs/learn/index.md @@ -0,0 +1,5 @@ +# Learn + +Here are the introductory sections and the tutorials to learn **FastAPI**. + +You could consider this a **book**, a **course**, the **official** and recommended way to learn FastAPI. ๐Ÿ˜Ž diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 693613a36..cdd22ea4a 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -182,7 +182,7 @@ For example, let's define a variable to be a `list` of `str`. {!> ../../../docs_src/python_types/tutorial006_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" From `typing`, import `List` (with a capital `L`): @@ -230,7 +230,7 @@ You would do the same to declare `tuple`s and `set`s: {!> ../../../docs_src/python_types/tutorial007_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial007.py!} @@ -255,7 +255,7 @@ The second type parameter is for the values of the `dict`: {!> ../../../docs_src/python_types/tutorial008_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial008.py!} @@ -281,7 +281,7 @@ In Python 3.10 there's also a **new syntax** where you can put the possible type {!> ../../../docs_src/python_types/tutorial008b_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial008b.py!} @@ -311,13 +311,13 @@ This also means that in Python 3.10, you can use `Something | None`: {!> ../../../docs_src/python_types/tutorial009_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial009.py!} ``` -=== "Python 3.6+ alternative" +=== "Python 3.8+ alternative" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial009b.py!} @@ -375,10 +375,10 @@ These types that take type parameters in square brackets are called **Generic ty * `set` * `dict` - And the same as with Python 3.6, from the `typing` module: + And the same as with Python 3.8, from the `typing` module: * `Union` - * `Optional` (the same as with Python 3.6) + * `Optional` (the same as with Python 3.8) * ...and others. In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the vertical bar (`|`) to declare unions of types, that's a lot better and simpler. @@ -392,13 +392,13 @@ These types that take type parameters in square brackets are called **Generic ty * `set` * `dict` - And the same as with Python 3.6, from the `typing` module: + And the same as with Python 3.8, from the `typing` module: * `Union` * `Optional` * ...and others. -=== "Python 3.6+" +=== "Python 3.8+" * `List` * `Tuple` @@ -458,7 +458,7 @@ An example from the official Pydantic docs: {!> ../../../docs_src/python_types/tutorial011_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/python_types/tutorial011.py!} @@ -486,7 +486,7 @@ Python also has a feature that allows putting **additional metadata** in these t {!> ../../../docs_src/python_types/tutorial013_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" In versions below Python 3.9, you import `Annotated` from `typing_extensions`. diff --git a/docs/en/docs/reference/apirouter.md b/docs/en/docs/reference/apirouter.md new file mode 100644 index 000000000..b779ad291 --- /dev/null +++ b/docs/en/docs/reference/apirouter.md @@ -0,0 +1,25 @@ +# `APIRouter` class + +Here's the reference information for the `APIRouter` class, with all its parameters, +attributes and methods. + +You can import the `APIRouter` class directly from `fastapi`: + +```python +from fastapi import APIRouter +``` + +::: fastapi.APIRouter + options: + members: + - websocket + - include_router + - get + - put + - post + - delete + - options + - head + - patch + - trace + - on_event diff --git a/docs/en/docs/reference/background.md b/docs/en/docs/reference/background.md new file mode 100644 index 000000000..e0c0be899 --- /dev/null +++ b/docs/en/docs/reference/background.md @@ -0,0 +1,13 @@ +# Background Tasks - `BackgroundTasks` + +You can declare a parameter in a *path operation function* or dependency function +with the type `BackgroundTasks`, and then you can use it to schedule the execution +of background tasks after the response is sent. + +You can import it directly from `fastapi`: + +```python +from fastapi import BackgroundTasks +``` + +::: fastapi.BackgroundTasks diff --git a/docs/en/docs/reference/dependencies.md b/docs/en/docs/reference/dependencies.md new file mode 100644 index 000000000..099968267 --- /dev/null +++ b/docs/en/docs/reference/dependencies.md @@ -0,0 +1,32 @@ +# Dependencies - `Depends()` and `Security()` + +## `Depends()` + +Dependencies are handled mainly with the special function `Depends()` that takes a +callable. + +Here is the reference for it and its parameters. + +You can import it directly from `fastapi`: + +```python +from fastapi import Depends +``` + +::: fastapi.Depends + +## `Security()` + +For many scenarios, you can handle security (authorization, authentication, etc.) with +dependencies, using `Depends()`. + +But when you want to also declare OAuth2 scopes, you can use `Security()` instead of +`Depends()`. + +You can import `Security()` directly from `fastapi`: + +```python +from fastapi import Security +``` + +::: fastapi.Security diff --git a/docs/en/docs/reference/encoders.md b/docs/en/docs/reference/encoders.md new file mode 100644 index 000000000..28df2e43a --- /dev/null +++ b/docs/en/docs/reference/encoders.md @@ -0,0 +1,3 @@ +# Encoders - `jsonable_encoder` + +::: fastapi.encoders.jsonable_encoder diff --git a/docs/en/docs/reference/exceptions.md b/docs/en/docs/reference/exceptions.md new file mode 100644 index 000000000..adc9b91ce --- /dev/null +++ b/docs/en/docs/reference/exceptions.md @@ -0,0 +1,22 @@ +# Exceptions - `HTTPException` and `WebSocketException` + +These are the exceptions that you can raise to show errors to the client. + +When you raise an exception, as would happen with normal Python, the rest of the +excecution is aborted. This way you can raise these exceptions from anywhere in the +code to abort a request and show the error to the client. + +You can use: + +* `HTTPException` +* `WebSocketException` + +These exceptions can be imported directly from `fastapi`: + +```python +from fastapi import HTTPException, WebSocketException +``` + +::: fastapi.HTTPException + +::: fastapi.WebSocketException diff --git a/docs/en/docs/reference/fastapi.md b/docs/en/docs/reference/fastapi.md new file mode 100644 index 000000000..8b87664cb --- /dev/null +++ b/docs/en/docs/reference/fastapi.md @@ -0,0 +1,32 @@ +# `FastAPI` class + +Here's the reference information for the `FastAPI` class, with all its parameters, +attributes and methods. + +You can import the `FastAPI` class directly from `fastapi`: + +```python +from fastapi import FastAPI +``` + +::: fastapi.FastAPI + options: + members: + - openapi_version + - webhooks + - state + - dependency_overrides + - openapi + - websocket + - include_router + - get + - put + - post + - delete + - options + - head + - patch + - trace + - on_event + - middleware + - exception_handler diff --git a/docs/en/docs/reference/httpconnection.md b/docs/en/docs/reference/httpconnection.md new file mode 100644 index 000000000..43dfc46f9 --- /dev/null +++ b/docs/en/docs/reference/httpconnection.md @@ -0,0 +1,13 @@ +# `HTTPConnection` class + +When you want to define dependencies that should be compatible with both HTTP and +WebSockets, you can define a parameter that takes an `HTTPConnection` instead of a +`Request` or a `WebSocket`. + +You can import it from `fastapi.requests`: + +```python +from fastapi.requests import HTTPConnection +``` + +::: fastapi.requests.HTTPConnection diff --git a/docs/en/docs/reference/index.md b/docs/en/docs/reference/index.md new file mode 100644 index 000000000..512d5c25c --- /dev/null +++ b/docs/en/docs/reference/index.md @@ -0,0 +1,7 @@ +# Reference - Code API + +Here's the reference or code API, the classes, functions, parameters, attributes, and +all the FastAPI parts you can use in your applications. + +If you want to **learn FastAPI** you are much better off reading the +[FastAPI Tutorial](https://fastapi.tiangolo.com/tutorial/). diff --git a/docs/en/docs/reference/middleware.md b/docs/en/docs/reference/middleware.md new file mode 100644 index 000000000..89704d3c8 --- /dev/null +++ b/docs/en/docs/reference/middleware.md @@ -0,0 +1,46 @@ +# Middleware + +There are several middlewares available provided by Starlette directly. + +Read more about them in the +[FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/). + +::: fastapi.middleware.cors.CORSMiddleware + +It can be imported from `fastapi`: + +```python +from fastapi.middleware.cors import CORSMiddleware +``` + +::: fastapi.middleware.gzip.GZipMiddleware + +It can be imported from `fastapi`: + +```python +from fastapi.middleware.gzip import GZipMiddleware +``` + +::: fastapi.middleware.httpsredirect.HTTPSRedirectMiddleware + +It can be imported from `fastapi`: + +```python +from fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware +``` + +::: fastapi.middleware.trustedhost.TrustedHostMiddleware + +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 +``` diff --git a/docs/en/docs/reference/openapi/docs.md b/docs/en/docs/reference/openapi/docs.md new file mode 100644 index 000000000..ab620833e --- /dev/null +++ b/docs/en/docs/reference/openapi/docs.md @@ -0,0 +1,11 @@ +# OpenAPI `docs` + +Utilities to handle OpenAPI automatic UI documentation, including Swagger UI (by default at `/docs`) and ReDoc (by default at `/redoc`). + +::: fastapi.openapi.docs.get_swagger_ui_html + +::: fastapi.openapi.docs.get_redoc_html + +::: fastapi.openapi.docs.get_swagger_ui_oauth2_redirect_html + +::: fastapi.openapi.docs.swagger_ui_default_parameters diff --git a/docs/en/docs/reference/openapi/index.md b/docs/en/docs/reference/openapi/index.md new file mode 100644 index 000000000..e2b313f15 --- /dev/null +++ b/docs/en/docs/reference/openapi/index.md @@ -0,0 +1,5 @@ +# OpenAPI + +There are several utilities to handle OpenAPI. + +You normally don't need to use them unless you have a specific advanced use case that requires it. diff --git a/docs/en/docs/reference/openapi/models.md b/docs/en/docs/reference/openapi/models.md new file mode 100644 index 000000000..4a6b0770e --- /dev/null +++ b/docs/en/docs/reference/openapi/models.md @@ -0,0 +1,5 @@ +# OpenAPI `models` + +OpenAPI Pydantic models used to generate and validate the generated OpenAPI. + +::: fastapi.openapi.models diff --git a/docs/en/docs/reference/parameters.md b/docs/en/docs/reference/parameters.md new file mode 100644 index 000000000..8f77f0161 --- /dev/null +++ b/docs/en/docs/reference/parameters.md @@ -0,0 +1,36 @@ +# Request Parameters + +Here's the reference information for the request parameters. + +These are the special functions that you can put in *path operation function* +parameters or dependency functions with `Annotated` to get data from the request. + +It includes: + +* `Query()` +* `Path()` +* `Body()` +* `Cookie()` +* `Header()` +* `Form()` +* `File()` + +You can import them all directly from `fastapi`: + +```python +from fastapi import Body, Cookie, File, Form, Header, Path, Query +``` + +::: fastapi.Query + +::: fastapi.Path + +::: fastapi.Body + +::: fastapi.Cookie + +::: fastapi.Header + +::: fastapi.Form + +::: fastapi.File diff --git a/docs/en/docs/reference/request.md b/docs/en/docs/reference/request.md new file mode 100644 index 000000000..91ec7d37b --- /dev/null +++ b/docs/en/docs/reference/request.md @@ -0,0 +1,18 @@ +# `Request` class + +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. + +You can import it directly from `fastapi`: + +```python +from fastapi import Request +``` + +!!! tip + When you want to define dependencies that should be compatible with both HTTP and + WebSockets, you can define a parameter that takes an `HTTPConnection` instead of a + `Request` or a `WebSocket`. + +::: fastapi.Request diff --git a/docs/en/docs/reference/response.md b/docs/en/docs/reference/response.md new file mode 100644 index 000000000..916254583 --- /dev/null +++ b/docs/en/docs/reference/response.md @@ -0,0 +1,15 @@ +# `Response` class + +You can declare a parameter in a *path operation function* or dependency to be of type +`Response` and then you can set data for the response like headers or cookies. + +You can also use it directly to create an instance of it and return it from your *path +operations*. + +You can import it directly from `fastapi`: + +```python +from fastapi import Response +``` + +::: fastapi.Response diff --git a/docs/en/docs/reference/responses.md b/docs/en/docs/reference/responses.md new file mode 100644 index 000000000..2cbbd8963 --- /dev/null +++ b/docs/en/docs/reference/responses.md @@ -0,0 +1,166 @@ +# Custom Response Classes - File, HTML, Redirect, Streaming, etc. + +There are several custom response classes you can use to create an instance and return +them directly from your *path operations*. + +Read more about it in the +[FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/). + +You can import them directly from `fastapi.responses`: + +```python +from fastapi.responses import ( + FileResponse, + HTMLResponse, + JSONResponse, + ORJSONResponse, + PlainTextResponse, + RedirectResponse, + Response, + StreamingResponse, + UJSONResponse, +) +``` + +## FastAPI Responses + +There are a couple of custom FastAPI response classes, you can use them to optimize JSON performance. + +::: fastapi.responses.UJSONResponse + options: + members: + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +::: fastapi.responses.ORJSONResponse + options: + members: + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +## Starlette Responses + +::: fastapi.responses.FileResponse + options: + members: + - chunk_size + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +::: fastapi.responses.HTMLResponse + options: + members: + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +::: fastapi.responses.JSONResponse + options: + members: + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +::: fastapi.responses.PlainTextResponse + options: + members: + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +::: fastapi.responses.RedirectResponse + options: + members: + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +::: fastapi.responses.Response + options: + members: + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie + +::: fastapi.responses.StreamingResponse + options: + members: + - body_iterator + - charset + - status_code + - media_type + - body + - background + - raw_headers + - render + - init_headers + - headers + - set_cookie + - delete_cookie diff --git a/docs/en/docs/reference/security/index.md b/docs/en/docs/reference/security/index.md new file mode 100644 index 000000000..ff86e9e30 --- /dev/null +++ b/docs/en/docs/reference/security/index.md @@ -0,0 +1,76 @@ +# Security Tools + +When you need to declare dependencies with OAuth2 scopes you use `Security()`. + +But you still need to define what is the dependable, the callable that you pass as +a parameter to `Depends()` or `Security()`. + +There are multiple tools that you can use to create those dependables, and they get +integrated into OpenAPI so they are shown in the automatic docs UI, they can be used +by automatically generated clients and SDKs, etc. + +You can import them from `fastapi.security`: + +```python +from fastapi.security import ( + APIKeyCookie, + APIKeyHeader, + APIKeyQuery, + HTTPAuthorizationCredentials, + HTTPBasic, + HTTPBasicCredentials, + HTTPBearer, + HTTPDigest, + OAuth2, + OAuth2AuthorizationCodeBearer, + OAuth2PasswordBearer, + OAuth2PasswordRequestForm, + OAuth2PasswordRequestFormStrict, + OpenIdConnect, + SecurityScopes, +) +``` + +## API Key Security Schemes + +::: fastapi.security.APIKeyCookie + +::: fastapi.security.APIKeyHeader + +::: fastapi.security.APIKeyQuery + +## HTTP Authentication Schemes + +::: fastapi.security.HTTPBasic + +::: fastapi.security.HTTPBearer + +::: fastapi.security.HTTPDigest + +## HTTP Credentials + +::: fastapi.security.HTTPAuthorizationCredentials + +::: fastapi.security.HTTPBasicCredentials + +## OAuth2 Authentication + +::: fastapi.security.OAuth2 + +::: fastapi.security.OAuth2AuthorizationCodeBearer + +::: fastapi.security.OAuth2PasswordBearer + +## OAuth2 Password Form + +::: fastapi.security.OAuth2PasswordRequestForm + +::: fastapi.security.OAuth2PasswordRequestFormStrict + +## OAuth2 Security Scopes in Dependencies + +::: fastapi.security.SecurityScopes + +## OpenID Connect + +::: fastapi.security.OpenIdConnect diff --git a/docs/en/docs/reference/staticfiles.md b/docs/en/docs/reference/staticfiles.md new file mode 100644 index 000000000..ce66f17b3 --- /dev/null +++ b/docs/en/docs/reference/staticfiles.md @@ -0,0 +1,14 @@ +# Static Files - `StaticFiles` + +You can use the `StaticFiles` class to serve static files, like JavaScript, CSS, images, etc. + +Read more about it in the +[FastAPI docs for Static Files](https://fastapi.tiangolo.com/tutorial/static-files/). + +You can import it directly from `fastapi.staticfiles`: + +```python +from fastapi.staticfiles import StaticFiles +``` + +::: fastapi.staticfiles.StaticFiles diff --git a/docs/en/docs/reference/status.md b/docs/en/docs/reference/status.md new file mode 100644 index 000000000..54fba9387 --- /dev/null +++ b/docs/en/docs/reference/status.md @@ -0,0 +1,39 @@ +# Status Codes + +You can import the `status` module from `fastapi`: + +```python +from fastapi import status +``` + +`status` is provided directly by Starlette. + +It containes a group of named constants (variables) with integer status codes. + +For example: + +* 200: `status.HTTP_200_OK` +* 403: `status.HTTP_403_FORBIDDEN` +* etc. + +It can be convenient to quickly access HTTP (and WebSocket) status codes in your app, +using autocompletion for the name without having to remember the integer status codes +by memory. + +Read more about it in the +[FastAPI docs about Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + +## Example + +```python +from fastapi import FastAPI, status + +app = FastAPI() + + +@app.get("/items/", status_code=status.HTTP_418_IM_A_TEAPOT) +def read_items(): + return [{"name": "Plumbus"}, {"name": "Portal Gun"}] +``` + +::: fastapi.status diff --git a/docs/en/docs/reference/templating.md b/docs/en/docs/reference/templating.md new file mode 100644 index 000000000..c865badfc --- /dev/null +++ b/docs/en/docs/reference/templating.md @@ -0,0 +1,14 @@ +# Templating - `Jinja2Templates` + +You can use the `Jinja2Templates` class to render Jinja templates. + +Read more about it in the +[FastAPI docs for Templates](https://fastapi.tiangolo.com/advanced/templates/). + +You can import it directly from `fastapi.templating`: + +```python +from fastapi.templating import Jinja2Templates +``` + +::: fastapi.templating.Jinja2Templates diff --git a/docs/en/docs/reference/testclient.md b/docs/en/docs/reference/testclient.md new file mode 100644 index 000000000..e391d964a --- /dev/null +++ b/docs/en/docs/reference/testclient.md @@ -0,0 +1,14 @@ +# Test Client - `TestClient` + +You can use the `TestClient` class to test FastAPI applications without creating an actual HTTP and socket connection, just communicating directly with the FastAPI code. + +Read more about it in the +[FastAPI docs for Testing](https://fastapi.tiangolo.com/tutorial/testing/). + +You can import it directly from `fastapi.testclient`: + +```python +from fastapi.testclient import TestClient +``` + +::: fastapi.testclient.TestClient diff --git a/docs/en/docs/reference/uploadfile.md b/docs/en/docs/reference/uploadfile.md new file mode 100644 index 000000000..45c644b18 --- /dev/null +++ b/docs/en/docs/reference/uploadfile.md @@ -0,0 +1,23 @@ +# `UploadFile` class + +You can define *path operation function* parameters to be of the type `UploadFile` +to receive files from the request. + +You can import it directly from `fastapi`: + +```python +from fastapi import UploadFile +``` + +::: fastapi.UploadFile + options: + members: + - file + - filename + - size + - headers + - content_type + - read + - write + - seek + - close diff --git a/docs/en/docs/reference/websockets.md b/docs/en/docs/reference/websockets.md new file mode 100644 index 000000000..2a0469467 --- /dev/null +++ b/docs/en/docs/reference/websockets.md @@ -0,0 +1,70 @@ +# WebSockets + +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. + +It is provided directly by Starlette, but you can import it from `fastapi`: + +```python +from fastapi import WebSocket +``` + +!!! tip + When you want to define dependencies that should be compatible with both HTTP and + WebSockets, you can define a parameter that takes an `HTTPConnection` instead of a + `Request` or a `WebSocket`. + +::: fastapi.WebSocket + options: + members: + - scope + - app + - url + - base_url + - headers + - query_params + - path_params + - cookies + - client + - state + - url_for + - client_state + - application_state + - receive + - send + - accept + - receive_text + - receive_bytes + - receive_json + - iter_text + - iter_bytes + - iter_json + - send_text + - send_bytes + - 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. + +Provided directly by Starlette, but you can import it from `fastapi`: + +```python +from fastapi.websockets import WebSocketDisconnect, WebSocketState +``` + +::: fastapi.websockets.WebSocketDisconnect + +::: fastapi.websockets.WebSocketState diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9570bef36..835df984c 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -1,7 +1,187 @@ +--- +hide: + - navigation +--- + # Release Notes ## Latest Changes +## 0.105.0 + +### Features + +* โœจ Add support for multiple Annotated annotations, e.g. `Annotated[str, Field(), Query()]`. PR [#10773](https://github.com/tiangolo/fastapi/pull/10773) by [@tiangolo](https://github.com/tiangolo). + +### Refactors + +* ๐Ÿ”ฅ Remove unused NoneType. PR [#10774](https://github.com/tiangolo/fastapi/pull/10774) by [@tiangolo](https://github.com/tiangolo). + +### Docs + +* ๐Ÿ“ Tweak default suggested configs for generating clients. PR [#10736](https://github.com/tiangolo/fastapi/pull/10736) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* ๐Ÿ”ง Update sponsors, add Scalar. PR [#10728](https://github.com/tiangolo/fastapi/pull/10728) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors, add PropelAuth. PR [#10760](https://github.com/tiangolo/fastapi/pull/10760) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ‘ท Update build docs, verify README on CI. PR [#10750](https://github.com/tiangolo/fastapi/pull/10750) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors, remove Fern. PR [#10729](https://github.com/tiangolo/fastapi/pull/10729) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors, add Codacy. PR [#10677](https://github.com/tiangolo/fastapi/pull/10677) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors, add Reflex. PR [#10676](https://github.com/tiangolo/fastapi/pull/10676) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ“ Update release notes, move and check latest-changes. PR [#10588](https://github.com/tiangolo/fastapi/pull/10588) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ‘ท Upgrade latest-changes GitHub Action. PR [#10587](https://github.com/tiangolo/fastapi/pull/10587) by [@tiangolo](https://github.com/tiangolo). + +## 0.104.1 + +### Fixes + +* ๐Ÿ“Œ Pin Swagger UI version to 5.9.0 temporarily to handle a bug crashing it in 5.9.1. PR [#10529](https://github.com/tiangolo/fastapi/pull/10529) by [@alejandraklachquin](https://github.com/alejandraklachquin). + * This is not really a bug in FastAPI but in Swagger UI, nevertheless pinning the version will work while a solution is found on the [Swagger UI side](https://github.com/swagger-api/swagger-ui/issues/9337). + +### Docs + +* ๐Ÿ“ Update data structure and render for external-links. PR [#10495](https://github.com/tiangolo/fastapi/pull/10495) by [@tiangolo](https://github.com/tiangolo). +* โœ๏ธ Fix link to SPDX license identifier in `docs/en/docs/tutorial/metadata.md`. PR [#10433](https://github.com/tiangolo/fastapi/pull/10433) by [@worldworm](https://github.com/worldworm). +* ๐Ÿ“ Update example validation error from Pydantic v1 to match Pydantic v2 in `docs/en/docs/tutorial/path-params.md`. PR [#10043](https://github.com/tiangolo/fastapi/pull/10043) by [@giuliowaitforitdavide](https://github.com/giuliowaitforitdavide). +* โœ๏ธ Fix typos in emoji docs and in some source examples. PR [#10438](https://github.com/tiangolo/fastapi/pull/10438) by [@afuetterer](https://github.com/afuetterer). +* โœ๏ธ Fix typo in `docs/en/docs/reference/dependencies.md`. PR [#10465](https://github.com/tiangolo/fastapi/pull/10465) by [@suravshresth](https://github.com/suravshresth). +* โœ๏ธ Fix typos and rewordings in `docs/en/docs/tutorial/body-nested-models.md`. PR [#10468](https://github.com/tiangolo/fastapi/pull/10468) by [@yogabonito](https://github.com/yogabonito). +* ๐Ÿ“ Update docs, remove references to removed `pydantic.Required` in `docs/en/docs/tutorial/query-params-str-validations.md`. PR [#10469](https://github.com/tiangolo/fastapi/pull/10469) by [@yogabonito](https://github.com/yogabonito). +* โœ๏ธ Fix typo in `docs/en/docs/reference/index.md`. PR [#10467](https://github.com/tiangolo/fastapi/pull/10467) by [@tarsil](https://github.com/tarsil). +* ๐Ÿ”ฅ Remove unnecessary duplicated docstrings. PR [#10484](https://github.com/tiangolo/fastapi/pull/10484) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* โœ๏ธ Update Pydantic links to dotenv support. PR [#10511](https://github.com/tiangolo/fastapi/pull/10511) by [@White-Mask](https://github.com/White-Mask). +* โœ๏ธ Update links in `docs/en/docs/async.md` and `docs/zh/docs/async.md` to make them relative. PR [#10498](https://github.com/tiangolo/fastapi/pull/10498) by [@hasnatsajid](https://github.com/hasnatsajid). +* โœ๏ธ Fix links in `docs/em/docs/async.md`. PR [#10507](https://github.com/tiangolo/fastapi/pull/10507) by [@hasnatsajid](https://github.com/hasnatsajid). +* โœ๏ธ Fix typo in `docs/em/docs/index.md`, Python 3.8. PR [#10521](https://github.com/tiangolo/fastapi/pull/10521) by [@kerriop](https://github.com/kerriop). +* โฌ† Bump pillow from 9.5.0 to 10.1.0. PR [#10446](https://github.com/tiangolo/fastapi/pull/10446) by [@dependabot[bot]](https://github.com/apps/dependabot). +* โฌ† Update mkdocs-material requirement from <9.0.0,>=8.1.4 to >=8.1.4,<10.0.0. PR [#5862](https://github.com/tiangolo/fastapi/pull/5862) by [@dependabot[bot]](https://github.com/apps/dependabot). +* โฌ† Bump mkdocs-material from 9.1.21 to 9.4.7. PR [#10545](https://github.com/tiangolo/fastapi/pull/10545) by [@dependabot[bot]](https://github.com/apps/dependabot). +* ๐Ÿ‘ท Install MkDocs Material Insiders only when secrets are available, for Dependabot. PR [#10544](https://github.com/tiangolo/fastapi/pull/10544) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors badges, Databento. PR [#10519](https://github.com/tiangolo/fastapi/pull/10519) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ‘ท Adopt Ruff format. PR [#10517](https://github.com/tiangolo/fastapi/pull/10517) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Add `CITATION.cff` file for academic citations. PR [#10496](https://github.com/tiangolo/fastapi/pull/10496) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ› Fix overriding MKDocs theme lang in hook. PR [#10490](https://github.com/tiangolo/fastapi/pull/10490) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ฅ Drop/close Gitter chat. Questions should go to GitHub Discussions, free conversations to Discord.. PR [#10485](https://github.com/tiangolo/fastapi/pull/10485) by [@tiangolo](https://github.com/tiangolo). + +## 0.104.0 + +## Features + +* โœจ Add reference (code API) docs with PEP 727, add subclass with custom docstrings for `BackgroundTasks`, refactor docs structure. PR [#10392](https://github.com/tiangolo/fastapi/pull/10392) by [@tiangolo](https://github.com/tiangolo). New docs at [FastAPI Reference - Code API](https://fastapi.tiangolo.com/reference/). + +## Upgrades + +* โฌ†๏ธ Drop support for Python 3.7, require Python 3.8 or above. PR [#10442](https://github.com/tiangolo/fastapi/pull/10442) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* โฌ† Bump dawidd6/action-download-artifact from 2.27.0 to 2.28.0. PR [#10268](https://github.com/tiangolo/fastapi/pull/10268) by [@dependabot[bot]](https://github.com/apps/dependabot). +* โฌ† Bump actions/checkout from 3 to 4. PR [#10208](https://github.com/tiangolo/fastapi/pull/10208) by [@dependabot[bot]](https://github.com/apps/dependabot). +* โฌ† Bump pypa/gh-action-pypi-publish from 1.8.6 to 1.8.10. PR [#10061](https://github.com/tiangolo/fastapi/pull/10061) by [@dependabot[bot]](https://github.com/apps/dependabot). +* ๐Ÿ”ง Update sponsors, Bump.sh images. PR [#10381](https://github.com/tiangolo/fastapi/pull/10381) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ‘ฅ Update FastAPI People. PR [#10363](https://github.com/tiangolo/fastapi/pull/10363) by [@tiangolo](https://github.com/tiangolo). + +## 0.103.2 + +### Refactors + +* โฌ†๏ธ Upgrade compatibility with Pydantic v2.4, new renamed functions and JSON Schema input/output models with default values. PR [#10344](https://github.com/tiangolo/fastapi/pull/10344) by [@tiangolo](https://github.com/tiangolo). + +### Translations + +* ๐ŸŒ Add Ukrainian translation for `docs/uk/docs/tutorial/extra-data-types.md`. PR [#10132](https://github.com/tiangolo/fastapi/pull/10132) by [@ArtemKhymenko](https://github.com/ArtemKhymenko). +* ๐ŸŒ Fix typos in French translations for `docs/fr/docs/advanced/path-operation-advanced-configuration.md`, `docs/fr/docs/alternatives.md`, `docs/fr/docs/async.md`, `docs/fr/docs/features.md`, `docs/fr/docs/help-fastapi.md`, `docs/fr/docs/index.md`, `docs/fr/docs/python-types.md`, `docs/fr/docs/tutorial/body.md`, `docs/fr/docs/tutorial/first-steps.md`, `docs/fr/docs/tutorial/query-params.md`. PR [#10154](https://github.com/tiangolo/fastapi/pull/10154) by [@s-rigaud](https://github.com/s-rigaud). +* ๐ŸŒ Add Chinese translation for `docs/zh/docs/async.md`. PR [#5591](https://github.com/tiangolo/fastapi/pull/5591) by [@mkdir700](https://github.com/mkdir700). +* ๐ŸŒ Update Chinese translation for `docs/tutorial/security/simple-oauth2.md`. PR [#3844](https://github.com/tiangolo/fastapi/pull/3844) by [@jaystone776](https://github.com/jaystone776). +* ๐ŸŒ Add Korean translation for `docs/ko/docs/deployment/cloud.md`. PR [#10191](https://github.com/tiangolo/fastapi/pull/10191) by [@Sion99](https://github.com/Sion99). +* ๐ŸŒ Add Japanese translation for `docs/ja/docs/deployment/https.md`. PR [#10298](https://github.com/tiangolo/fastapi/pull/10298) by [@tamtam-fitness](https://github.com/tamtam-fitness). +* ๐ŸŒ Fix typo in Russian translation for `docs/ru/docs/tutorial/body-fields.md`. PR [#10224](https://github.com/tiangolo/fastapi/pull/10224) by [@AlertRED](https://github.com/AlertRED). +* ๐ŸŒ Add Polish translation for `docs/pl/docs/help-fastapi.md`. PR [#10121](https://github.com/tiangolo/fastapi/pull/10121) by [@romabozhanovgithub](https://github.com/romabozhanovgithub). +* ๐ŸŒ Add Russian translation for `docs/ru/docs/tutorial/header-params.md`. PR [#10226](https://github.com/tiangolo/fastapi/pull/10226) by [@AlertRED](https://github.com/AlertRED). +* ๐ŸŒ Add Chinese translation for `docs/zh/docs/deployment/versions.md`. PR [#10276](https://github.com/tiangolo/fastapi/pull/10276) by [@xzmeng](https://github.com/xzmeng). + +### Internal + +* ๐Ÿ”ง Update sponsors, remove Flint. PR [#10349](https://github.com/tiangolo/fastapi/pull/10349) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Rename label "awaiting review" to "awaiting-review" to simplify search queries. PR [#10343](https://github.com/tiangolo/fastapi/pull/10343) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors, enable Svix (revert #10228). PR [#10253](https://github.com/tiangolo/fastapi/pull/10253) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors, remove Svix. PR [#10228](https://github.com/tiangolo/fastapi/pull/10228) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ”ง Update sponsors, add Bump.sh. PR [#10227](https://github.com/tiangolo/fastapi/pull/10227) by [@tiangolo](https://github.com/tiangolo). + +## 0.103.1 + +### Fixes + +* ๐Ÿ“Œ Pin AnyIO to < 4.0.0 to handle an incompatibility while upgrading to Starlette 0.31.1. PR [#10194](https://github.com/tiangolo/fastapi/pull/10194) by [@tiangolo](https://github.com/tiangolo). + +### Docs + +* โœ๏ธ Fix validation parameter name in docs, from `regex` to `pattern`. PR [#10085](https://github.com/tiangolo/fastapi/pull/10085) by [@pablodorrio](https://github.com/pablodorrio). +* โœ๏ธ Fix indent format in `docs/en/docs/deployment/server-workers.md`. PR [#10066](https://github.com/tiangolo/fastapi/pull/10066) by [@tamtam-fitness](https://github.com/tamtam-fitness). +* โœ๏ธ Fix Pydantic examples in tutorial for Python types. PR [#9961](https://github.com/tiangolo/fastapi/pull/9961) by [@rahulsalgare](https://github.com/rahulsalgare). +* โœ๏ธ Fix link to Pydantic docs in `docs/en/docs/tutorial/extra-data-types.md`. PR [#10155](https://github.com/tiangolo/fastapi/pull/10155) by [@hasnatsajid](https://github.com/hasnatsajid). +* โœ๏ธ Fix typo in `docs/en/docs/tutorial/handling-errors.md`. PR [#10170](https://github.com/tiangolo/fastapi/pull/10170) by [@poupapaa](https://github.com/poupapaa). +* โœ๏ธ Fix typo in `docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md`. PR [#10172](https://github.com/tiangolo/fastapi/pull/10172) by [@ragul-kachiappan](https://github.com/ragul-kachiappan). + +### Translations + +* ๐ŸŒ Remove duplicate line in translation for `docs/pt/docs/tutorial/path-params.md`. PR [#10126](https://github.com/tiangolo/fastapi/pull/10126) by [@LecoOliveira](https://github.com/LecoOliveira). +* ๐ŸŒ Add Yoruba translation for `docs/yo/docs/index.md`. PR [#10033](https://github.com/tiangolo/fastapi/pull/10033) by [@AfolabiOlaoluwa](https://github.com/AfolabiOlaoluwa). +* ๐ŸŒ Add Ukrainian translation for `docs/uk/docs/python-types.md`. PR [#10080](https://github.com/tiangolo/fastapi/pull/10080) by [@rostik1410](https://github.com/rostik1410). +* ๐ŸŒ Add Vietnamese translations for `docs/vi/docs/tutorial/first-steps.md` and `docs/vi/docs/tutorial/index.md`. PR [#10088](https://github.com/tiangolo/fastapi/pull/10088) by [@magiskboy](https://github.com/magiskboy). +* ๐ŸŒ Add Ukrainian translation for `docs/uk/docs/alternatives.md`. PR [#10060](https://github.com/tiangolo/fastapi/pull/10060) by [@whysage](https://github.com/whysage). +* ๐ŸŒ Add Ukrainian translation for `docs/uk/docs/tutorial/index.md`. PR [#10079](https://github.com/tiangolo/fastapi/pull/10079) by [@rostik1410](https://github.com/rostik1410). +* โœ๏ธ Fix typos in `docs/en/docs/how-to/separate-openapi-schemas.md` and `docs/en/docs/tutorial/schema-extra-example.md`. PR [#10189](https://github.com/tiangolo/fastapi/pull/10189) by [@xzmeng](https://github.com/xzmeng). +* ๐ŸŒ Add Chinese translation for `docs/zh/docs/advanced/generate-clients.md`. PR [#9883](https://github.com/tiangolo/fastapi/pull/9883) by [@funny-cat-happy](https://github.com/funny-cat-happy). + +### Refactors + +* โœ๏ธ Fix typos in comment in `fastapi/applications.py`. PR [#10045](https://github.com/tiangolo/fastapi/pull/10045) by [@AhsanSheraz](https://github.com/AhsanSheraz). +* โœ… Add missing test for OpenAPI examples, it was missing in coverage. PR [#10188](https://github.com/tiangolo/fastapi/pull/10188) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* ๐Ÿ‘ฅ Update FastAPI People. PR [#10186](https://github.com/tiangolo/fastapi/pull/10186) by [@tiangolo](https://github.com/tiangolo). + +## 0.103.0 + +### Features + +* โœจ Add support for `openapi_examples` in all FastAPI parameters. PR [#10152](https://github.com/tiangolo/fastapi/pull/10152) by [@tiangolo](https://github.com/tiangolo). + * New docs: [OpenAPI-specific examples](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#openapi-specific-examples). + +### Docs + +* ๐Ÿ“ Add note to docs about Separate Input and Output Schemas with FastAPI version. PR [#10150](https://github.com/tiangolo/fastapi/pull/10150) by [@tiangolo](https://github.com/tiangolo). + +## 0.102.0 + +### Features + +* โœจ Add support for disabling the separation of input and output JSON Schemas in OpenAPI with Pydantic v2 with `separate_input_output_schemas=False`. PR [#10145](https://github.com/tiangolo/fastapi/pull/10145) by [@tiangolo](https://github.com/tiangolo). + * New docs [Separate OpenAPI Schemas for Input and Output or Not](https://fastapi.tiangolo.com/how-to/separate-openapi-schemas/). + * This PR also includes a new setup (internal tools) for generating screenshots for the docs. + +### Refactors + +* โ™ป๏ธ Refactor tests for new Pydantic 2.2.1. PR [#10115](https://github.com/tiangolo/fastapi/pull/10115) by [@tiangolo](https://github.com/tiangolo). + +### Docs + +* ๐Ÿ“ Add new docs section, How To - Recipes, move docs that don't have to be read by everyone to How To. PR [#10114](https://github.com/tiangolo/fastapi/pull/10114) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ“ Update Advanced docs, add links to sponsor courses. PR [#10113](https://github.com/tiangolo/fastapi/pull/10113) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ“ Update docs for generating clients. PR [#10112](https://github.com/tiangolo/fastapi/pull/10112) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ“ Tweak MkDocs and add redirects. PR [#10111](https://github.com/tiangolo/fastapi/pull/10111) by [@tiangolo](https://github.com/tiangolo). +* ๐Ÿ“ Restructure docs for cloud providers, include links to sponsors. PR [#10110](https://github.com/tiangolo/fastapi/pull/10110) by [@tiangolo](https://github.com/tiangolo). + +### Internal + +* ๐Ÿ”ง Update sponsors, add Speakeasy. PR [#10098](https://github.com/tiangolo/fastapi/pull/10098) by [@tiangolo](https://github.com/tiangolo). + ## 0.101.1 ### Fixes diff --git a/docs/en/docs/resources/index.md b/docs/en/docs/resources/index.md new file mode 100644 index 000000000..8c7cac43b --- /dev/null +++ b/docs/en/docs/resources/index.md @@ -0,0 +1,3 @@ +# Resources + +Additional resources, external links, articles and more. โœˆ๏ธ diff --git a/docs/en/docs/tutorial/background-tasks.md b/docs/en/docs/tutorial/background-tasks.md index 178297192..bc8e2af6a 100644 --- a/docs/en/docs/tutorial/background-tasks.md +++ b/docs/en/docs/tutorial/background-tasks.md @@ -69,7 +69,7 @@ Using `BackgroundTasks` also works with the dependency injection system, you can {!> ../../../docs_src/background_tasks/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14 16 23 26" {!> ../../../docs_src/background_tasks/tutorial002_an.py!} @@ -84,7 +84,7 @@ Using `BackgroundTasks` also works with the dependency injection system, you can {!> ../../../docs_src/background_tasks/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/bigger-applications.md b/docs/en/docs/tutorial/bigger-applications.md index 26d26475f..1cf7e50e0 100644 --- a/docs/en/docs/tutorial/bigger-applications.md +++ b/docs/en/docs/tutorial/bigger-applications.md @@ -118,13 +118,13 @@ We will now use a simple dependency to read a custom `X-Token` header: {!> ../../../docs_src/bigger_applications/app_an_py39/dependencies.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 5-7" {!> ../../../docs_src/bigger_applications/app_an/dependencies.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/body-fields.md b/docs/en/docs/tutorial/body-fields.md index 8966032ff..55e67fdd6 100644 --- a/docs/en/docs/tutorial/body-fields.md +++ b/docs/en/docs/tutorial/body-fields.md @@ -18,7 +18,7 @@ First, you have to import it: {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4" {!> ../../../docs_src/body_fields/tutorial001_an.py!} @@ -33,7 +33,7 @@ First, you have to import it: {!> ../../../docs_src/body_fields/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -61,7 +61,7 @@ You can then use `Field` with model attributes: {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12-15" {!> ../../../docs_src/body_fields/tutorial001_an.py!} @@ -76,7 +76,7 @@ You can then use `Field` with model attributes: {!> ../../../docs_src/body_fields/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/body-multiple-params.md b/docs/en/docs/tutorial/body-multiple-params.md index b214092c9..ebef8eeaa 100644 --- a/docs/en/docs/tutorial/body-multiple-params.md +++ b/docs/en/docs/tutorial/body-multiple-params.md @@ -20,7 +20,7 @@ And you can also declare body parameters as optional, by setting the default to {!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="19-21" {!> ../../../docs_src/body_multiple_params/tutorial001_an.py!} @@ -35,7 +35,7 @@ And you can also declare body parameters as optional, by setting the default to {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -68,7 +68,7 @@ But you can also declare multiple body parameters, e.g. `item` and `user`: {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/body_multiple_params/tutorial002.py!} @@ -123,7 +123,7 @@ But you can instruct **FastAPI** to treat it as another body key using `Body`: {!> ../../../docs_src/body_multiple_params/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/body_multiple_params/tutorial003_an.py!} @@ -138,7 +138,7 @@ But you can instruct **FastAPI** to treat it as another body key using `Body`: {!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -197,7 +197,7 @@ For example: {!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="28" {!> ../../../docs_src/body_multiple_params/tutorial004_an.py!} @@ -212,7 +212,7 @@ For example: {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -250,7 +250,7 @@ as in: {!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/body_multiple_params/tutorial005_an.py!} @@ -265,7 +265,7 @@ as in: {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md index ffa0c0d0e..387f0de9a 100644 --- a/docs/en/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -12,7 +12,7 @@ You can define an attribute to be a subtype. For example, a Python `list`: {!> ../../../docs_src/body_nested_models/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14" {!> ../../../docs_src/body_nested_models/tutorial001.py!} @@ -73,7 +73,7 @@ So, in our example, we can make `tags` be specifically a "list of strings": {!> ../../../docs_src/body_nested_models/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14" {!> ../../../docs_src/body_nested_models/tutorial002.py!} @@ -99,7 +99,7 @@ Then we can declare `tags` as a set of strings: {!> ../../../docs_src/body_nested_models/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 14" {!> ../../../docs_src/body_nested_models/tutorial003.py!} @@ -137,7 +137,7 @@ For example, we can define an `Image` model: {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-11" {!> ../../../docs_src/body_nested_models/tutorial004.py!} @@ -159,7 +159,7 @@ And then we can use it as the type of an attribute: {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/body_nested_models/tutorial004.py!} @@ -183,18 +183,18 @@ This would mean that **FastAPI** would expect a body similar to: Again, doing just that declaration, with **FastAPI** you get: -* Editor support (completion, etc), even for nested models +* Editor support (completion, etc.), even for nested models * Data conversion * Data validation * Automatic documentation ## Special types and validation -Apart from normal singular types like `str`, `int`, `float`, etc. You can use more complex singular types that inherit from `str`. +Apart from normal singular types like `str`, `int`, `float`, etc. you can use more complex singular types that inherit from `str`. To see all the options you have, checkout the docs for Pydantic's exotic types. You will see some examples in the next chapter. -For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `HttpUrl`: +For example, as in the `Image` model we have a `url` field, we can declare it to be an instance of Pydantic's `HttpUrl` instead of a `str`: === "Python 3.10+" @@ -208,7 +208,7 @@ For example, as in the `Image` model we have a `url` field, we can declare it to {!> ../../../docs_src/body_nested_models/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 10" {!> ../../../docs_src/body_nested_models/tutorial005.py!} @@ -218,7 +218,7 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op ## Attributes with lists of submodels -You can also use Pydantic models as subtypes of `list`, `set`, etc: +You can also use Pydantic models as subtypes of `list`, `set`, etc.: === "Python 3.10+" @@ -232,13 +232,13 @@ You can also use Pydantic models as subtypes of `list`, `set`, etc: {!> ../../../docs_src/body_nested_models/tutorial006_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/body_nested_models/tutorial006.py!} ``` -This will expect (convert, validate, document, etc) a JSON body like: +This will expect (convert, validate, document, etc.) a JSON body like: ```JSON hl_lines="11" { @@ -283,7 +283,7 @@ You can define arbitrarily deeply nested models: {!> ../../../docs_src/body_nested_models/tutorial007_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 14 20 23 27" {!> ../../../docs_src/body_nested_models/tutorial007.py!} @@ -314,7 +314,7 @@ as in: {!> ../../../docs_src/body_nested_models/tutorial008_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15" {!> ../../../docs_src/body_nested_models/tutorial008.py!} @@ -334,15 +334,15 @@ But you don't have to worry about them either, incoming dicts are converted auto ## Bodies of arbitrary `dict`s -You can also declare a body as a `dict` with keys of some type and values of other type. +You can also declare a body as a `dict` with keys of some type and values of some other type. -Without having to know beforehand what are the valid field/attribute names (as would be the case with Pydantic models). +This way, you don't have to know beforehand what the valid field/attribute names are (as would be the case with Pydantic models). This would be useful if you want to receive keys that you don't already know. --- -Other useful case is when you want to have keys of other type, e.g. `int`. +Another useful case is when you want to have keys of another type (e.g., `int`). That's what we are going to see here. @@ -354,7 +354,7 @@ In this case, you would accept any `dict` as long as it has `int` keys with `flo {!> ../../../docs_src/body_nested_models/tutorial009_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/body_nested_models/tutorial009.py!} diff --git a/docs/en/docs/tutorial/body-updates.md b/docs/en/docs/tutorial/body-updates.md index a32948db1..3341f2d5d 100644 --- a/docs/en/docs/tutorial/body-updates.md +++ b/docs/en/docs/tutorial/body-updates.md @@ -18,7 +18,7 @@ You can use the `jsonable_encoder` to convert the input data to data that can be {!> ../../../docs_src/body_updates/tutorial001_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="30-35" {!> ../../../docs_src/body_updates/tutorial001.py!} @@ -79,7 +79,7 @@ Then you can use this to generate a `dict` with only the data that was set (sent {!> ../../../docs_src/body_updates/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="34" {!> ../../../docs_src/body_updates/tutorial002.py!} @@ -103,7 +103,7 @@ Like `stored_item_model.copy(update=update_data)`: {!> ../../../docs_src/body_updates/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="35" {!> ../../../docs_src/body_updates/tutorial002.py!} @@ -136,7 +136,7 @@ In summary, to apply partial updates you would: {!> ../../../docs_src/body_updates/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="30-37" {!> ../../../docs_src/body_updates/tutorial002.py!} diff --git a/docs/en/docs/tutorial/body.md b/docs/en/docs/tutorial/body.md index 172b91fdf..67ba48f1e 100644 --- a/docs/en/docs/tutorial/body.md +++ b/docs/en/docs/tutorial/body.md @@ -25,7 +25,7 @@ First, you need to import `BaseModel` from `pydantic`: {!> ../../../docs_src/body/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4" {!> ../../../docs_src/body/tutorial001.py!} @@ -43,7 +43,7 @@ Use standard Python types for all the attributes: {!> ../../../docs_src/body/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="7-11" {!> ../../../docs_src/body/tutorial001.py!} @@ -81,7 +81,7 @@ To add it to your *path operation*, declare it the same way you declared path an {!> ../../../docs_src/body/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/body/tutorial001.py!} @@ -155,7 +155,7 @@ Inside of the function, you can access all the attributes of the model object di {!> ../../../docs_src/body/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="21" {!> ../../../docs_src/body/tutorial002.py!} @@ -173,7 +173,7 @@ You can declare path parameters and request body at the same time. {!> ../../../docs_src/body/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17-18" {!> ../../../docs_src/body/tutorial003.py!} @@ -191,7 +191,7 @@ You can also declare **body**, **path** and **query** parameters, all at the sam {!> ../../../docs_src/body/tutorial004_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/body/tutorial004.py!} diff --git a/docs/en/docs/tutorial/cookie-params.md b/docs/en/docs/tutorial/cookie-params.md index 111e93458..3436a7df3 100644 --- a/docs/en/docs/tutorial/cookie-params.md +++ b/docs/en/docs/tutorial/cookie-params.md @@ -18,7 +18,7 @@ First import `Cookie`: {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/cookie_params/tutorial001_an.py!} @@ -33,7 +33,7 @@ First import `Cookie`: {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -60,7 +60,7 @@ The first value is the default value, you can pass all the extra validation or a {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/cookie_params/tutorial001_an.py!} @@ -75,7 +75,7 @@ The first value is the default value, you can pass all the extra validation or a {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md index 498d935fe..842f2adf6 100644 --- a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md @@ -18,7 +18,7 @@ In the previous example, we were returning a `dict` from our dependency ("depend {!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12" {!> ../../../docs_src/dependencies/tutorial001_an.py!} @@ -33,7 +33,7 @@ In the previous example, we were returning a `dict` from our dependency ("depend {!> ../../../docs_src/dependencies/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -115,7 +115,7 @@ Then, we can change the dependency "dependable" `common_parameters` from above t {!> ../../../docs_src/dependencies/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12-16" {!> ../../../docs_src/dependencies/tutorial002_an.py!} @@ -130,7 +130,7 @@ Then, we can change the dependency "dependable" `common_parameters` from above t {!> ../../../docs_src/dependencies/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -153,7 +153,7 @@ Pay attention to the `__init__` method used to create the instance of the class: {!> ../../../docs_src/dependencies/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="13" {!> ../../../docs_src/dependencies/tutorial002_an.py!} @@ -168,7 +168,7 @@ Pay attention to the `__init__` method used to create the instance of the class: {!> ../../../docs_src/dependencies/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -191,7 +191,7 @@ Pay attention to the `__init__` method used to create the instance of the class: {!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/dependencies/tutorial001_an.py!} @@ -206,7 +206,7 @@ Pay attention to the `__init__` method used to create the instance of the class: {!> ../../../docs_src/dependencies/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -241,7 +241,7 @@ Now you can declare your dependency using this class. {!> ../../../docs_src/dependencies/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/dependencies/tutorial002_an.py!} @@ -256,7 +256,7 @@ Now you can declare your dependency using this class. {!> ../../../docs_src/dependencies/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -271,7 +271,7 @@ Now you can declare your dependency using this class. Notice how we write `CommonQueryParams` twice in the above code: -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -280,7 +280,7 @@ Notice how we write `CommonQueryParams` twice in the above code: commons: CommonQueryParams = Depends(CommonQueryParams) ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -300,13 +300,13 @@ From it is that FastAPI will extract the declared parameters and that is what Fa In this case, the first `CommonQueryParams`, in: -=== "Python 3.6+" +=== "Python 3.8+" ```Python commons: Annotated[CommonQueryParams, ... ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -319,13 +319,13 @@ In this case, the first `CommonQueryParams`, in: You could actually write just: -=== "Python 3.6+" +=== "Python 3.8+" ```Python commons: Annotated[Any, Depends(CommonQueryParams)] ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -348,7 +348,7 @@ You could actually write just: {!> ../../../docs_src/dependencies/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/dependencies/tutorial003_an.py!} @@ -363,7 +363,7 @@ You could actually write just: {!> ../../../docs_src/dependencies/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -380,7 +380,7 @@ But declaring the type is encouraged as that way your editor will know what will But you see that we are having some code repetition here, writing `CommonQueryParams` twice: -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -389,7 +389,7 @@ But you see that we are having some code repetition here, writing `CommonQueryPa commons: CommonQueryParams = Depends(CommonQueryParams) ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -401,13 +401,13 @@ For those specific cases, you can do the following: Instead of writing: -=== "Python 3.6+" +=== "Python 3.8+" ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -418,13 +418,13 @@ Instead of writing: ...you write: -=== "Python 3.6+" +=== "Python 3.8+" ```Python commons: Annotated[CommonQueryParams, Depends()] ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -449,7 +449,7 @@ The same example would then look like: {!> ../../../docs_src/dependencies/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/dependencies/tutorial004_an.py!} @@ -464,7 +464,7 @@ The same example would then look like: {!> ../../../docs_src/dependencies/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md b/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md index 935555339..eaab51d1b 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md @@ -20,13 +20,13 @@ It should be a `list` of `Depends()`: {!> ../../../docs_src/dependencies/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/dependencies/tutorial006_an.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -35,7 +35,7 @@ It should be a `list` of `Depends()`: {!> ../../../docs_src/dependencies/tutorial006.py!} ``` -These dependencies will be executed/solved the same way normal dependencies. But their value (if they return any) won't be passed to your *path operation function*. +These dependencies will be executed/solved the same way as normal dependencies. But their value (if they return any) won't be passed to your *path operation function*. !!! tip Some editors check for unused function parameters, and show them as errors. @@ -63,13 +63,13 @@ They can declare request requirements (like headers) or other sub-dependencies: {!> ../../../docs_src/dependencies/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="7 12" {!> ../../../docs_src/dependencies/tutorial006_an.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -88,13 +88,13 @@ These dependencies can `raise` exceptions, the same as normal dependencies: {!> ../../../docs_src/dependencies/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 14" {!> ../../../docs_src/dependencies/tutorial006_an.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -115,13 +115,13 @@ So, you can re-use a normal dependency (that returns a value) you already use so {!> ../../../docs_src/dependencies/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10 15" {!> ../../../docs_src/dependencies/tutorial006_an.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index 8a5422ac8..fe18f1f1d 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -72,13 +72,13 @@ For example, `dependency_c` can have a dependency on `dependency_b`, and `depend {!> ../../../docs_src/dependencies/tutorial008_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="5 13 21" {!> ../../../docs_src/dependencies/tutorial008_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -99,13 +99,13 @@ And, in turn, `dependency_b` needs the value from `dependency_a` (here named `de {!> ../../../docs_src/dependencies/tutorial008_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17-18 25-26" {!> ../../../docs_src/dependencies/tutorial008_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/dependencies/global-dependencies.md b/docs/en/docs/tutorial/dependencies/global-dependencies.md index 0989b31d4..0dcf73176 100644 --- a/docs/en/docs/tutorial/dependencies/global-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/global-dependencies.md @@ -12,13 +12,13 @@ In that case, they will be applied to all the *path operations* in the applicati {!> ../../../docs_src/dependencies/tutorial012_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="16" {!> ../../../docs_src/dependencies/tutorial012_an.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/dependencies/index.md b/docs/en/docs/tutorial/dependencies/index.md index f6f4bced0..bc98cb26e 100644 --- a/docs/en/docs/tutorial/dependencies/index.md +++ b/docs/en/docs/tutorial/dependencies/index.md @@ -43,7 +43,7 @@ It is just a function that can take all the same parameters that a *path operati {!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-12" {!> ../../../docs_src/dependencies/tutorial001_an.py!} @@ -58,7 +58,7 @@ It is just a function that can take all the same parameters that a *path operati {!> ../../../docs_src/dependencies/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -106,7 +106,7 @@ And then it just returns a `dict` containing those values. {!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/dependencies/tutorial001_an.py!} @@ -121,7 +121,7 @@ And then it just returns a `dict` containing those values. {!> ../../../docs_src/dependencies/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -146,7 +146,7 @@ The same way you use `Body`, `Query`, etc. with your *path operation function* p {!> ../../../docs_src/dependencies/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="16 21" {!> ../../../docs_src/dependencies/tutorial001_an.py!} @@ -161,7 +161,7 @@ The same way you use `Body`, `Query`, etc. with your *path operation function* p {!> ../../../docs_src/dependencies/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -231,7 +231,7 @@ But because we are using `Annotated`, we can store that `Annotated` value in a v {!> ../../../docs_src/dependencies/tutorial001_02_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15 19 24" {!> ../../../docs_src/dependencies/tutorial001_02_an.py!} diff --git a/docs/en/docs/tutorial/dependencies/sub-dependencies.md b/docs/en/docs/tutorial/dependencies/sub-dependencies.md index b50de1a46..1cb469a80 100644 --- a/docs/en/docs/tutorial/dependencies/sub-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/sub-dependencies.md @@ -22,7 +22,7 @@ You could create a first dependency ("dependable") like: {!> ../../../docs_src/dependencies/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-10" {!> ../../../docs_src/dependencies/tutorial005_an.py!} @@ -37,7 +37,7 @@ You could create a first dependency ("dependable") like: {!> ../../../docs_src/dependencies/tutorial005_py310.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -66,7 +66,7 @@ Then you can create another dependency function (a "dependable") that at the sam {!> ../../../docs_src/dependencies/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14" {!> ../../../docs_src/dependencies/tutorial005_an.py!} @@ -81,7 +81,7 @@ Then you can create another dependency function (a "dependable") that at the sam {!> ../../../docs_src/dependencies/tutorial005_py310.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -113,7 +113,7 @@ Then we can use the dependency with: {!> ../../../docs_src/dependencies/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/dependencies/tutorial005_an.py!} @@ -128,7 +128,7 @@ Then we can use the dependency with: {!> ../../../docs_src/dependencies/tutorial005_py310.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -161,14 +161,14 @@ And it will save the returned value in a ../../../docs_src/encoder/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="5 22" {!> ../../../docs_src/encoder/tutorial001.py!} diff --git a/docs/en/docs/tutorial/extra-data-types.md b/docs/en/docs/tutorial/extra-data-types.md index 7d6ffbc78..fd7a99af3 100644 --- a/docs/en/docs/tutorial/extra-data-types.md +++ b/docs/en/docs/tutorial/extra-data-types.md @@ -49,7 +49,7 @@ Here are some of the additional data types you can use: * `Decimal`: * Standard Python `Decimal`. * In requests and responses, handled the same as a `float`. -* You can check all the valid pydantic data types here: Pydantic data types. +* You can check all the valid pydantic data types here: Pydantic data types. ## Example @@ -67,7 +67,7 @@ Here's an example *path operation* with parameters using some of the above types {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 3 13-17" {!> ../../../docs_src/extra_data_types/tutorial001_an.py!} @@ -82,7 +82,7 @@ Here's an example *path operation* with parameters using some of the above types {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -105,7 +105,7 @@ Note that the parameters inside the function have their natural data type, and y {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="19-20" {!> ../../../docs_src/extra_data_types/tutorial001_an.py!} @@ -120,7 +120,7 @@ Note that the parameters inside the function have their natural data type, and y {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/extra-models.md b/docs/en/docs/tutorial/extra-models.md index e91e879e4..590d095bd 100644 --- a/docs/en/docs/tutorial/extra-models.md +++ b/docs/en/docs/tutorial/extra-models.md @@ -23,7 +23,7 @@ Here's a general idea of how the models could look like with their password fiel {!> ../../../docs_src/extra_models/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41" {!> ../../../docs_src/extra_models/tutorial001.py!} @@ -164,7 +164,7 @@ That way, we can declare just the differences between the models (with plaintext {!> ../../../docs_src/extra_models/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 15-16 19-20 23-24" {!> ../../../docs_src/extra_models/tutorial002.py!} @@ -187,7 +187,7 @@ To do that, use the standard Python type hint ../../../docs_src/extra_models/tutorial003.py!} @@ -219,7 +219,7 @@ For that, use the standard Python `typing.List` (or just `list` in Python 3.9 an {!> ../../../docs_src/extra_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 20" {!> ../../../docs_src/extra_models/tutorial004.py!} @@ -239,7 +239,7 @@ In this case, you can use `typing.Dict` (or just `dict` in Python 3.9 and above) {!> ../../../docs_src/extra_models/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 8" {!> ../../../docs_src/extra_models/tutorial005.py!} diff --git a/docs/en/docs/tutorial/handling-errors.md b/docs/en/docs/tutorial/handling-errors.md index 8c30326ce..a03029e81 100644 --- a/docs/en/docs/tutorial/handling-errors.md +++ b/docs/en/docs/tutorial/handling-errors.md @@ -1,6 +1,6 @@ # Handling Errors -There are many situations in where you need to notify an error to a client that is using your API. +There are many situations in which you need to notify an error to a client that is using your API. This client could be a browser with a frontend, a code from someone else, an IoT device, etc. diff --git a/docs/en/docs/tutorial/header-params.md b/docs/en/docs/tutorial/header-params.md index 9e928cdc6..bbba90998 100644 --- a/docs/en/docs/tutorial/header-params.md +++ b/docs/en/docs/tutorial/header-params.md @@ -18,7 +18,7 @@ First import `Header`: {!> ../../../docs_src/header_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/header_params/tutorial001_an.py!} @@ -33,7 +33,7 @@ First import `Header`: {!> ../../../docs_src/header_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -60,7 +60,7 @@ The first value is the default value, you can pass all the extra validation or a {!> ../../../docs_src/header_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/header_params/tutorial001_an.py!} @@ -75,7 +75,7 @@ The first value is the default value, you can pass all the extra validation or a {!> ../../../docs_src/header_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -120,7 +120,7 @@ If for some reason you need to disable automatic conversion of underscores to hy {!> ../../../docs_src/header_params/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12" {!> ../../../docs_src/header_params/tutorial002_an.py!} @@ -135,7 +135,7 @@ If for some reason you need to disable automatic conversion of underscores to hy {!> ../../../docs_src/header_params/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -169,7 +169,7 @@ For example, to declare a header of `X-Token` that can appear more than once, yo {!> ../../../docs_src/header_params/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/header_params/tutorial003_an.py!} @@ -193,7 +193,7 @@ For example, to declare a header of `X-Token` that can appear more than once, yo {!> ../../../docs_src/header_params/tutorial003_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/metadata.md b/docs/en/docs/tutorial/metadata.md index e75b4a0b9..504204e98 100644 --- a/docs/en/docs/tutorial/metadata.md +++ b/docs/en/docs/tutorial/metadata.md @@ -14,7 +14,7 @@ You can set the following fields that are used in the OpenAPI specification and | `version` | `string` | The version of the API. This is the version of your own application, not of OpenAPI. For example `2.5.0`. | | `terms_of_service` | `str` | A URL to the Terms of Service for the API. If provided, this has to be a URL. | | `contact` | `dict` | The contact information for the exposed API. It can contain several fields.
contact fields
ParameterTypeDescription
namestrThe identifying name of the contact person/organization.
urlstrThe URL pointing to the contact information. MUST be in the format of a URL.
emailstrThe email address of the contact person/organization. MUST be in the format of an email address.
| -| `license_info` | `dict` | The license information for the exposed API. It can contain several fields.
license_info fields
ParameterTypeDescription
namestrREQUIRED (if a license_info is set). The license name used for the API.
identifierstrAn SPDX license expression for the API. The identifier field is mutually exclusive of the url field. Available since OpenAPI 3.1.0, FastAPI 0.99.0.
urlstrA URL to the license used for the API. MUST be in the format of a URL.
| +| `license_info` | `dict` | The license information for the exposed API. It can contain several fields.
license_info fields
ParameterTypeDescription
namestrREQUIRED (if a license_info is set). The license name used for the API.
identifierstrAn SPDX license expression for the API. The identifier field is mutually exclusive of the url field. Available since OpenAPI 3.1.0, FastAPI 0.99.0.
urlstrA URL to the license used for the API. MUST be in the format of a URL.
| You can set them as follows: diff --git a/docs/en/docs/tutorial/path-operation-configuration.md b/docs/en/docs/tutorial/path-operation-configuration.md index 7d4d4bcca..babf85acb 100644 --- a/docs/en/docs/tutorial/path-operation-configuration.md +++ b/docs/en/docs/tutorial/path-operation-configuration.md @@ -25,7 +25,7 @@ But if you don't remember what each number code is for, you can use the shortcut {!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3 17" {!> ../../../docs_src/path_operation_configuration/tutorial001.py!} @@ -54,7 +54,7 @@ You can add tags to your *path operation*, pass the parameter `tags` with a `lis {!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17 22 27" {!> ../../../docs_src/path_operation_configuration/tutorial002.py!} @@ -92,7 +92,7 @@ You can add a `summary` and `description`: {!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20-21" {!> ../../../docs_src/path_operation_configuration/tutorial003.py!} @@ -116,7 +116,7 @@ You can write
../../../docs_src/path_operation_configuration/tutorial004.py!} @@ -142,7 +142,7 @@ You can specify the response description with the parameter `response_descriptio {!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="21" {!> ../../../docs_src/path_operation_configuration/tutorial005.py!} diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md index 9255875d6..57ad20b13 100644 --- a/docs/en/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -18,7 +18,7 @@ First, import `Path` from `fastapi`, and import `Annotated`: {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3-4" {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!} @@ -33,7 +33,7 @@ First, import `Path` from `fastapi`, and import `Annotated`: {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -67,7 +67,7 @@ For example, to declare a `title` metadata value for the path parameter `item_id {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!} @@ -82,7 +82,7 @@ For example, to declare a `title` metadata value for the path parameter `item_id {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -117,7 +117,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names, So, you can declare your function as: -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -134,7 +134,7 @@ But have in mind that if you use `Annotated`, you won't have this problem, it wo {!> ../../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial002_an.py!} @@ -174,7 +174,7 @@ Have in mind that if you use `Annotated`, as you are not using function paramete {!> ../../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial003_an.py!} @@ -192,13 +192,13 @@ Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than o {!> ../../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial004_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -220,13 +220,13 @@ The same applies for: {!> ../../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial005_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -251,13 +251,13 @@ And the same for lt. {!> ../../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12" {!> ../../../docs_src/path_params_numeric_validations/tutorial006_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/path-params.md b/docs/en/docs/tutorial/path-params.md index 6594a7a8b..847b56334 100644 --- a/docs/en/docs/tutorial/path-params.md +++ b/docs/en/docs/tutorial/path-params.md @@ -46,16 +46,18 @@ But if you go to the browser at ../../../docs_src/query_params_str_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params_str_validations/tutorial001.py!} @@ -42,7 +42,7 @@ To achieve that, first import: {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" In versions of Python below Python 3.9 you import `Annotated` from `typing_extensions`. @@ -73,7 +73,7 @@ We had this type annotation: q: str | None = None ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python q: Union[str, None] = None @@ -87,7 +87,7 @@ What we will do is wrap that with `Annotated`, so it becomes: q: Annotated[str | None] = None ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python q: Annotated[Union[str, None]] = None @@ -107,7 +107,7 @@ Now that we have this `Annotated` where we can put more metadata, add `Query` to {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!} @@ -138,7 +138,7 @@ This is how you would use `Query()` as the default value of your function parame {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params_str_validations/tutorial002.py!} @@ -251,7 +251,7 @@ You can also add a parameter `min_length`: {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial003_an.py!} @@ -266,7 +266,7 @@ You can also add a parameter `min_length`: {!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -291,7 +291,7 @@ You can define a ../../../docs_src/query_params_str_validations/tutorial004_an.py!} @@ -306,7 +306,7 @@ You can define a ../../../docs_src/query_params_str_validations/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial005_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -405,13 +405,13 @@ So, when you need to declare a value as required while using `Query`, you can si {!> ../../../docs_src/query_params_str_validations/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial006_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -435,13 +435,13 @@ There's an alternative way to explicitly declare that a value is required. You c {!> ../../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial006b_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -475,7 +475,7 @@ To do that, you can declare that `None` is a valid type but still use `...` as t {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial006c_an.py!} @@ -490,7 +490,7 @@ To do that, you can declare that `None` is a valid type but still use `...` as t {!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -502,33 +502,8 @@ To do that, you can declare that `None` is a valid type but still use `...` as t !!! tip Pydantic, which is what powers all the data validation and serialization in FastAPI, has a special behavior when you use `Optional` or `Union[Something, None]` without a default value, you can read more about it in the Pydantic docs about Required Optional fields. -### Use Pydantic's `Required` instead of Ellipsis (`...`) - -If you feel uncomfortable using `...`, you can also import and use `Required` from Pydantic: - -=== "Python 3.9+" - - ```Python hl_lines="4 10" - {!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!} - ``` - -=== "Python 3.6+" - - ```Python hl_lines="2 9" - {!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!} - ``` - -=== "Python 3.6+ non-Annotated" - - !!! tip - Prefer to use the `Annotated` version if possible. - - ```Python hl_lines="2 8" - {!> ../../../docs_src/query_params_str_validations/tutorial006d.py!} - ``` - !!! tip - Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...` nor `Required`. + Remember that in most of the cases, when something is required, you can simply omit the default, so you normally don't have to use `...`. ## Query parameter list / multiple values @@ -548,7 +523,7 @@ For example, to declare a query parameter `q` that can appear multiple times in {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial011_an.py!} @@ -572,7 +547,7 @@ For example, to declare a query parameter `q` that can appear multiple times in {!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -617,7 +592,7 @@ And you can also define a default `list` of values if none are provided: {!> ../../../docs_src/query_params_str_validations/tutorial012_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial012_an.py!} @@ -632,7 +607,7 @@ And you can also define a default `list` of values if none are provided: {!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -668,13 +643,13 @@ You can also use `list` directly instead of `List[str]` (or `list[str]` in Pytho {!> ../../../docs_src/query_params_str_validations/tutorial013_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial013_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -713,7 +688,7 @@ You can add a `title`: {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial007_an.py!} @@ -728,7 +703,7 @@ You can add a `title`: {!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -751,7 +726,7 @@ And a `description`: {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15" {!> ../../../docs_src/query_params_str_validations/tutorial008_an.py!} @@ -762,11 +737,11 @@ And a `description`: !!! tip Prefer to use the `Annotated` version if possible. - ```Python hl_lines="12" + ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -805,7 +780,7 @@ Then you can declare an `alias`, and that alias is what will be used to find the {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial009_an.py!} @@ -820,7 +795,7 @@ Then you can declare an `alias`, and that alias is what will be used to find the {!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -849,7 +824,7 @@ Then pass the parameter `deprecated=True` to `Query`: {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/query_params_str_validations/tutorial010_an.py!} @@ -860,11 +835,11 @@ Then pass the parameter `deprecated=True` to `Query`: !!! tip Prefer to use the `Annotated` version if possible. - ```Python hl_lines="17" + ```Python hl_lines="16" {!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -893,7 +868,7 @@ To exclude a query parameter from the generated OpenAPI schema (and thus, from t {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial014_an.py!} @@ -908,7 +883,7 @@ To exclude a query parameter from the generated OpenAPI schema (and thus, from t {!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -932,7 +907,7 @@ Validations specific for strings: * `min_length` * `max_length` -* `regex` +* `pattern` In these examples you saw how to declare validations for `str` values. diff --git a/docs/en/docs/tutorial/query-params.md b/docs/en/docs/tutorial/query-params.md index 0b74b10f8..bc3b11948 100644 --- a/docs/en/docs/tutorial/query-params.md +++ b/docs/en/docs/tutorial/query-params.md @@ -69,7 +69,7 @@ The same way, you can declare optional query parameters, by setting their defaul {!> ../../../docs_src/query_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params/tutorial002.py!} @@ -90,7 +90,7 @@ You can also declare `bool` types, and they will be converted: {!> ../../../docs_src/query_params/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params/tutorial003.py!} @@ -143,7 +143,7 @@ They will be detected by name: {!> ../../../docs_src/query_params/tutorial004_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8 10" {!> ../../../docs_src/query_params/tutorial004.py!} @@ -173,16 +173,18 @@ http://127.0.0.1:8000/items/foo-item ```JSON { - "detail": [ - { - "loc": [ - "query", - "needy" - ], - "msg": "field required", - "type": "value_error.missing" - } - ] + "detail": [ + { + "type": "missing", + "loc": [ + "query", + "needy" + ], + "msg": "Field required", + "input": null, + "url": "https://errors.pydantic.dev/2.1/v/missing" + } + ] } ``` @@ -209,7 +211,7 @@ And of course, you can define some parameters as required, some as having a defa {!> ../../../docs_src/query_params/tutorial006_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params/tutorial006.py!} diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index 1fe1e7a33..c85a68ed6 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -19,13 +19,13 @@ Import `File` and `UploadFile` from `fastapi`: {!> ../../../docs_src/request_files/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1" {!> ../../../docs_src/request_files/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -44,13 +44,13 @@ Create file parameters the same way you would for `Body` or `Form`: {!> ../../../docs_src/request_files/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/request_files/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -85,13 +85,13 @@ Define a file parameter with a type of `UploadFile`: {!> ../../../docs_src/request_files/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="13" {!> ../../../docs_src/request_files/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -181,7 +181,7 @@ You can make a file optional by using standard type annotations and setting a de {!> ../../../docs_src/request_files/tutorial001_02_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10 18" {!> ../../../docs_src/request_files/tutorial001_02_an.py!} @@ -196,7 +196,7 @@ You can make a file optional by using standard type annotations and setting a de {!> ../../../docs_src/request_files/tutorial001_02_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -215,13 +215,13 @@ You can also use `File()` with `UploadFile`, for example, to set additional meta {!> ../../../docs_src/request_files/tutorial001_03_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8 14" {!> ../../../docs_src/request_files/tutorial001_03_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -244,7 +244,7 @@ To use that, declare a list of `bytes` or `UploadFile`: {!> ../../../docs_src/request_files/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11 16" {!> ../../../docs_src/request_files/tutorial002_an.py!} @@ -259,7 +259,7 @@ To use that, declare a list of `bytes` or `UploadFile`: {!> ../../../docs_src/request_files/tutorial002_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -285,7 +285,7 @@ And the same way as before, you can use `File()` to set additional parameters, e {!> ../../../docs_src/request_files/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12 19-21" {!> ../../../docs_src/request_files/tutorial003_an.py!} @@ -300,7 +300,7 @@ And the same way as before, you can use `File()` to set additional parameters, e {!> ../../../docs_src/request_files/tutorial003_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/request-forms-and-files.md b/docs/en/docs/tutorial/request-forms-and-files.md index 1818946c4..a58291dc8 100644 --- a/docs/en/docs/tutorial/request-forms-and-files.md +++ b/docs/en/docs/tutorial/request-forms-and-files.md @@ -15,13 +15,13 @@ You can define files and form fields at the same time using `File` and `Form`. {!> ../../../docs_src/request_forms_and_files/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1" {!> ../../../docs_src/request_forms_and_files/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -40,13 +40,13 @@ Create file and form parameters the same way you would for `Body` or `Query`: {!> ../../../docs_src/request_forms_and_files/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-11" {!> ../../../docs_src/request_forms_and_files/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/request-forms.md b/docs/en/docs/tutorial/request-forms.md index 5d441a614..0e8ac5f4f 100644 --- a/docs/en/docs/tutorial/request-forms.md +++ b/docs/en/docs/tutorial/request-forms.md @@ -17,13 +17,13 @@ Import `Form` from `fastapi`: {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1" {!> ../../../docs_src/request_forms/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -42,13 +42,13 @@ Create form parameters the same way you would for `Body` or `Query`: {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/request_forms/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index 2181cfb5a..d6d3d61cb 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -16,7 +16,7 @@ You can use **type annotations** the same way you would for input data in functi {!> ../../../docs_src/response_model/tutorial001_01_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18 23" {!> ../../../docs_src/response_model/tutorial001_01.py!} @@ -65,7 +65,7 @@ You can use the `response_model` parameter in any of the *path operations*: {!> ../../../docs_src/response_model/tutorial001_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17 22 24-27" {!> ../../../docs_src/response_model/tutorial001.py!} @@ -101,7 +101,7 @@ Here we are declaring a `UserIn` model, it will contain a plaintext password: {!> ../../../docs_src/response_model/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11" {!> ../../../docs_src/response_model/tutorial002.py!} @@ -121,7 +121,7 @@ And we are using this model to declare our input and the same model to declare o {!> ../../../docs_src/response_model/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/response_model/tutorial002.py!} @@ -146,7 +146,7 @@ We can instead create an input model with the plaintext password and an output m {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11 16" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -160,7 +160,7 @@ Here, even though our *path operation function* is returning the same input user {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -174,7 +174,7 @@ Here, even though our *path operation function* is returning the same input user {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -208,7 +208,7 @@ And in those cases, we can use classes and inheritance to take advantage of func {!> ../../../docs_src/response_model/tutorial003_01_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-13 15-16 20" {!> ../../../docs_src/response_model/tutorial003_01.py!} @@ -284,7 +284,7 @@ The same would happen if you had something like a . - You can set `"json_schema_extra"` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`. + You can set `"json_schema_extra"` with a `dict` containing any additional data you would like to show up in the generated JSON Schema, including `examples`. === "Pydantic v1" In Pydantic version 1, you would use an internal class `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization. - You can set `schema_extra` with a `dict` containing any additonal data you would like to show up in the generated JSON Schema, including `examples`. + You can set `schema_extra` with a `dict` containing any additional data you would like to show up in the generated JSON Schema, including `examples`. !!! tip You could use the same technique to extend the JSON Schema and add your own custom extra info. @@ -68,13 +68,13 @@ When using `Field()` with Pydantic models, you can also declare additional `exam {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 10-13" {!> ../../../docs_src/schema_extra_example/tutorial002.py!} ``` -## `examples` in OpenAPI +## `examples` in JSON Schema - OpenAPI When using any of: @@ -86,7 +86,7 @@ When using any of: * `Form()` * `File()` -you can also declare a group of `examples` with additional information that will be added to **OpenAPI**. +you can also declare a group of `examples` with additional information that will be added to their **JSON Schemas** inside of **OpenAPI**. ### `Body` with `examples` @@ -104,7 +104,7 @@ Here we pass `examples` containing one example of the data expected in `Body()`: {!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="23-30" {!> ../../../docs_src/schema_extra_example/tutorial003_an.py!} @@ -119,7 +119,7 @@ Here we pass `examples` containing one example of the data expected in `Body()`: {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -150,7 +150,7 @@ You can of course also pass multiple `examples`: {!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24-39" {!> ../../../docs_src/schema_extra_example/tutorial004_an.py!} @@ -165,7 +165,7 @@ You can of course also pass multiple `examples`: {!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -174,9 +174,84 @@ You can of course also pass multiple `examples`: {!> ../../../docs_src/schema_extra_example/tutorial004.py!} ``` -### Examples in the docs UI +When you do this, the examples will be part of the internal **JSON Schema** for that body data. -With `examples` added to `Body()` the `/docs` would look like: +Nevertheless, at the time of writing this, Swagger UI, the tool in charge of showing the docs UI, doesn't support showing multiple examples for the data in **JSON Schema**. But read below for a workaround. + +### OpenAPI-specific `examples` + +Since before **JSON Schema** supported `examples` OpenAPI had support for a different field also called `examples`. + +This **OpenAPI-specific** `examples` goes in another section in the OpenAPI specification. It goes in the **details for each *path operation***, not inside each JSON Schema. + +And Swagger UI has supported this particular `examples` field for a while. So, you can use it to **show** different **examples in the docs UI**. + +The shape of this OpenAPI-specific field `examples` is a `dict` with **multiple examples** (instead of a `list`), each with extra information that will be added to **OpenAPI** too. + +This doesn't go inside of each JSON Schema contained in OpenAPI, this goes outside, in the *path operation* directly. + +### Using the `openapi_examples` Parameter + +You can declare the OpenAPI-specific `examples` in FastAPI with the parameter `openapi_examples` for: + +* `Path()` +* `Query()` +* `Header()` +* `Cookie()` +* `Body()` +* `Form()` +* `File()` + +The keys of the `dict` identify each example, and each value is another `dict`. + +Each specific example `dict` in the `examples` can contain: + +* `summary`: Short description for the example. +* `description`: A long description that can contain Markdown text. +* `value`: This is the actual example shown, e.g. a `dict`. +* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. + +You can use it like this: + +=== "Python 3.10+" + + ```Python hl_lines="23-49" + {!> ../../../docs_src/schema_extra_example/tutorial005_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="23-49" + {!> ../../../docs_src/schema_extra_example/tutorial005_an_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="24-50" + {!> ../../../docs_src/schema_extra_example/tutorial005_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="19-45" + {!> ../../../docs_src/schema_extra_example/tutorial005_py310.py!} + ``` + +=== "Python 3.8+ non-Annotated" + + !!! tip + Prefer to use the `Annotated` version if possible. + + ```Python hl_lines="21-47" + {!> ../../../docs_src/schema_extra_example/tutorial005.py!} + ``` + +### OpenAPI Examples in the Docs UI + +With `openapi_examples` added to `Body()` the `/docs` would look like: @@ -210,20 +285,8 @@ OpenAPI also added `example` and `examples` fields to other parts of the specifi * `File()` * `Form()` -### OpenAPI's `examples` field - -The shape of this field `examples` from OpenAPI is a `dict` with **multiple examples**, each with extra information that will be added to **OpenAPI** too. - -The keys of the `dict` identify each example, and each value is another `dict`. - -Each specific example `dict` in the `examples` can contain: - -* `summary`: Short description for the example. -* `description`: A long description that can contain Markdown text. -* `value`: This is the actual example shown, e.g. a `dict`. -* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. - -This applies to those other parts of the OpenAPI specification apart from JSON Schema. +!!! info + This old OpenAPI-specific `examples` parameter is now `openapi_examples` since FastAPI `0.103.0`. ### JSON Schema's `examples` field @@ -250,6 +313,12 @@ In versions of FastAPI before 0.99.0 (0.99.0 and above use the newer OpenAPI 3.1 But now that FastAPI 0.99.0 and above uses OpenAPI 3.1.0, that uses JSON Schema 2020-12, and Swagger UI 5.0.0 and above, everything is more consistent and the examples are included in JSON Schema. +### Swagger UI and OpenAPI-specific `examples` + +Now, as Swagger UI didn't support multiple JSON Schema examples (as of 2023-08-26), users didn't have a way to show multiple examples in the docs. + +To solve that, FastAPI `0.103.0` **added support** for declaring the same old **OpenAPI-specific** `examples` field with the new parameter `openapi_examples`. ๐Ÿค“ + ### Summary I used to say I didn't like history that much... and look at me now giving "tech history" lessons. ๐Ÿ˜… diff --git a/docs/en/docs/tutorial/security/first-steps.md b/docs/en/docs/tutorial/security/first-steps.md index 5765cf2d6..2f39f1ec2 100644 --- a/docs/en/docs/tutorial/security/first-steps.md +++ b/docs/en/docs/tutorial/security/first-steps.md @@ -26,13 +26,13 @@ Copy the example in a file `main.py`: {!> ../../../docs_src/security/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/security/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -140,13 +140,13 @@ When we create an instance of the `OAuth2PasswordBearer` class we pass in the `t {!> ../../../docs_src/security/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="7" {!> ../../../docs_src/security/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -191,13 +191,13 @@ Now you can pass that `oauth2_scheme` in a dependency with `Depends`. {!> ../../../docs_src/security/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/security/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/security/get-current-user.md b/docs/en/docs/tutorial/security/get-current-user.md index 1a8c5d9a8..e99a800c6 100644 --- a/docs/en/docs/tutorial/security/get-current-user.md +++ b/docs/en/docs/tutorial/security/get-current-user.md @@ -8,13 +8,13 @@ In the previous chapter the security system (which is based on the dependency in {!> ../../../docs_src/security/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/security/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -45,7 +45,7 @@ The same way we use Pydantic to declare bodies, we can use it anywhere else: {!> ../../../docs_src/security/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="5 13-17" {!> ../../../docs_src/security/tutorial002_an.py!} @@ -60,7 +60,7 @@ The same way we use Pydantic to declare bodies, we can use it anywhere else: {!> ../../../docs_src/security/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -91,7 +91,7 @@ The same as we were doing before in the *path operation* directly, our new depen {!> ../../../docs_src/security/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="26" {!> ../../../docs_src/security/tutorial002_an.py!} @@ -106,7 +106,7 @@ The same as we were doing before in the *path operation* directly, our new depen {!> ../../../docs_src/security/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -131,7 +131,7 @@ The same as we were doing before in the *path operation* directly, our new depen {!> ../../../docs_src/security/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20-23 27-28" {!> ../../../docs_src/security/tutorial002_an.py!} @@ -146,7 +146,7 @@ The same as we were doing before in the *path operation* directly, our new depen {!> ../../../docs_src/security/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -171,7 +171,7 @@ So now we can use the same `Depends` with our `get_current_user` in the *path op {!> ../../../docs_src/security/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="32" {!> ../../../docs_src/security/tutorial002_an.py!} @@ -186,7 +186,7 @@ So now we can use the same `Depends` with our `get_current_user` in the *path op {!> ../../../docs_src/security/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -253,7 +253,7 @@ And all these thousands of *path operations* can be as small as 3 lines: {!> ../../../docs_src/security/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="31-33" {!> ../../../docs_src/security/tutorial002_an.py!} @@ -268,7 +268,7 @@ And all these thousands of *path operations* can be as small as 3 lines: {!> ../../../docs_src/security/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index deb722b96..0a347fed3 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -121,7 +121,7 @@ And another one to authenticate and return a user. {!> ../../../docs_src/security/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="7 49 56-57 60-61 70-76" {!> ../../../docs_src/security/tutorial004_an.py!} @@ -136,7 +136,7 @@ And another one to authenticate and return a user. {!> ../../../docs_src/security/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -188,7 +188,7 @@ Create a utility function to generate a new access token. {!> ../../../docs_src/security/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="6 13-15 29-31 79-87" {!> ../../../docs_src/security/tutorial004_an.py!} @@ -203,7 +203,7 @@ Create a utility function to generate a new access token. {!> ../../../docs_src/security/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -232,7 +232,7 @@ If the token is invalid, return an HTTP error right away. {!> ../../../docs_src/security/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="90-107" {!> ../../../docs_src/security/tutorial004_an.py!} @@ -247,7 +247,7 @@ If the token is invalid, return an HTTP error right away. {!> ../../../docs_src/security/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -274,7 +274,7 @@ Create a real JWT access token and return it {!> ../../../docs_src/security/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="118-133" {!> ../../../docs_src/security/tutorial004_an.py!} @@ -289,7 +289,7 @@ Create a real JWT access token and return it {!> ../../../docs_src/security/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/security/simple-oauth2.md b/docs/en/docs/tutorial/security/simple-oauth2.md index abcf6b667..88edc9eab 100644 --- a/docs/en/docs/tutorial/security/simple-oauth2.md +++ b/docs/en/docs/tutorial/security/simple-oauth2.md @@ -61,7 +61,7 @@ First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depe {!> ../../../docs_src/security/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 79" {!> ../../../docs_src/security/tutorial003_an.py!} @@ -76,7 +76,7 @@ First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depe {!> ../../../docs_src/security/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -134,7 +134,7 @@ For the error, we use the exception `HTTPException`: {!> ../../../docs_src/security/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3 80-82" {!> ../../../docs_src/security/tutorial003_an.py!} @@ -149,7 +149,7 @@ For the error, we use the exception `HTTPException`: {!> ../../../docs_src/security/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -194,7 +194,7 @@ So, the thief won't be able to try to use those same passwords in another system {!> ../../../docs_src/security/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="83-86" {!> ../../../docs_src/security/tutorial003_an.py!} @@ -209,7 +209,7 @@ So, the thief won't be able to try to use those same passwords in another system {!> ../../../docs_src/security/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -264,7 +264,7 @@ For this simple example, we are going to just be completely insecure and return {!> ../../../docs_src/security/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="88" {!> ../../../docs_src/security/tutorial003_an.py!} @@ -279,7 +279,7 @@ For this simple example, we are going to just be completely insecure and return {!> ../../../docs_src/security/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. @@ -321,7 +321,7 @@ So, in our endpoint, we will only get a user if the user exists, was correctly a {!> ../../../docs_src/security/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="59-67 70-75 95" {!> ../../../docs_src/security/tutorial003_an.py!} @@ -336,7 +336,7 @@ So, in our endpoint, we will only get a user if the user exists, was correctly a {!> ../../../docs_src/security/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index 6e0e5dc06..010244bbf 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -281,7 +281,7 @@ But for security, the `password` won't be in other Pydantic *models*, for exampl {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3 6-8 11-12 23-24 27-28" {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -325,7 +325,7 @@ Not only the IDs of those items, but all the data that we defined in the Pydanti {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15-17 31-34" {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -354,7 +354,7 @@ In the `Config` class, set the attribute `orm_mode = True`. {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15 19-20 31 36-37" {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -494,7 +494,7 @@ In a very simplistic way create the database tables: {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -528,7 +528,7 @@ Our dependency will create a new SQLAlchemy `SessionLocal` that will be used in {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15-20" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -553,7 +553,7 @@ This will then give us better editor support inside the *path operation function {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24 32 38 47 53" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -574,7 +574,7 @@ Now, finally, here's the standard **FastAPI** *path operations* code. {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="23-28 31-34 37-42 45-49 52-55" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -673,7 +673,7 @@ For example, in a background task worker with ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -693,7 +693,7 @@ For example, in a background task worker with ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -752,7 +752,7 @@ The middleware we'll add (just a function) will create a new SQLAlchemy `Session {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14-22" {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!} diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index ec133a4d0..3f8dd69a1 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -122,7 +122,7 @@ Both *path operations* require an `X-Token` header. {!> ../../../docs_src/app_testing/app_b_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/app_testing/app_b_an/main.py!} @@ -137,7 +137,7 @@ Both *path operations* require an `X-Token` header. {!> ../../../docs_src/app_testing/app_b_py310/main.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index a66b6c147..a64eff269 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -30,6 +30,7 @@ theme: - content.code.annotate - content.code.copy - content.code.select + - navigation.tabs icon: repo: fontawesome/brands/github-alt logo: img/icon-white.svg @@ -42,134 +43,184 @@ plugins: search: null markdownextradata: data: ../en/data + redirects: + redirect_maps: + deployment/deta.md: deployment/cloud.md + advanced/sql-databases-peewee.md: how-to/sql-databases-peewee.md + advanced/async-sql-databases.md: how-to/async-sql-encode-databases.md + advanced/nosql-databases.md: how-to/nosql-databases-couchbase.md + advanced/graphql.md: how-to/graphql.md + advanced/custom-request-and-route.md: how-to/custom-request-and-route.md + advanced/conditional-openapi.md: how-to/conditional-openapi.md + advanced/extending-openapi.md: how-to/extending-openapi.md + mkdocstrings: + handlers: + python: + options: + extensions: + - griffe_typingdoc + show_root_heading: true + show_if_no_docstring: true + preload_modules: [httpx, starlette] + inherited_members: true + members_order: source + separate_signature: true + unwrap_annotated: true + filters: ["!^_"] + merge_init_into_class: true + docstring_section_style: spacy + signature_crossrefs: true + show_symbol_type_heading: true + show_symbol_type_toc: true nav: - FastAPI: index.md -- Languages: - - en: / - - de: /de/ - - em: /em/ - - es: /es/ - - fa: /fa/ - - fr: /fr/ - - he: /he/ - - id: /id/ - - ja: /ja/ - - ko: /ko/ - - pl: /pl/ - - pt: /pt/ - - ru: /ru/ - - tr: /tr/ - - uk: /uk/ - - vi: /vi/ - - zh: /zh/ - features.md +- Learn: + - learn/index.md + - python-types.md + - async.md + - Tutorial - User Guide: + - tutorial/index.md + - tutorial/first-steps.md + - tutorial/path-params.md + - tutorial/query-params.md + - tutorial/body.md + - tutorial/query-params-str-validations.md + - tutorial/path-params-numeric-validations.md + - tutorial/body-multiple-params.md + - tutorial/body-fields.md + - tutorial/body-nested-models.md + - tutorial/schema-extra-example.md + - tutorial/extra-data-types.md + - tutorial/cookie-params.md + - tutorial/header-params.md + - tutorial/response-model.md + - tutorial/extra-models.md + - tutorial/response-status-code.md + - tutorial/request-forms.md + - tutorial/request-files.md + - tutorial/request-forms-and-files.md + - tutorial/handling-errors.md + - tutorial/path-operation-configuration.md + - tutorial/encoder.md + - tutorial/body-updates.md + - Dependencies: + - tutorial/dependencies/index.md + - tutorial/dependencies/classes-as-dependencies.md + - tutorial/dependencies/sub-dependencies.md + - tutorial/dependencies/dependencies-in-path-operation-decorators.md + - tutorial/dependencies/global-dependencies.md + - tutorial/dependencies/dependencies-with-yield.md + - Security: + - tutorial/security/index.md + - tutorial/security/first-steps.md + - tutorial/security/get-current-user.md + - tutorial/security/simple-oauth2.md + - tutorial/security/oauth2-jwt.md + - tutorial/middleware.md + - tutorial/cors.md + - tutorial/sql-databases.md + - tutorial/bigger-applications.md + - tutorial/background-tasks.md + - tutorial/metadata.md + - tutorial/static-files.md + - tutorial/testing.md + - tutorial/debugging.md + - Advanced User Guide: + - advanced/index.md + - advanced/path-operation-advanced-configuration.md + - advanced/additional-status-codes.md + - advanced/response-directly.md + - advanced/custom-response.md + - advanced/additional-responses.md + - advanced/response-cookies.md + - advanced/response-headers.md + - advanced/response-change-status-code.md + - advanced/advanced-dependencies.md + - Advanced Security: + - advanced/security/index.md + - advanced/security/oauth2-scopes.md + - advanced/security/http-basic-auth.md + - advanced/using-request-directly.md + - advanced/dataclasses.md + - advanced/middleware.md + - advanced/sub-applications.md + - advanced/behind-a-proxy.md + - advanced/templates.md + - advanced/websockets.md + - advanced/events.md + - advanced/testing-websockets.md + - advanced/testing-events.md + - advanced/testing-dependencies.md + - advanced/testing-database.md + - advanced/async-tests.md + - advanced/settings.md + - advanced/openapi-callbacks.md + - advanced/openapi-webhooks.md + - advanced/wsgi.md + - advanced/generate-clients.md + - Deployment: + - deployment/index.md + - deployment/versions.md + - deployment/https.md + - deployment/manually.md + - deployment/concepts.md + - deployment/cloud.md + - deployment/server-workers.md + - deployment/docker.md + - How To - Recipes: + - how-to/index.md + - how-to/general.md + - how-to/sql-databases-peewee.md + - how-to/async-sql-encode-databases.md + - how-to/nosql-databases-couchbase.md + - how-to/graphql.md + - how-to/custom-request-and-route.md + - how-to/conditional-openapi.md + - how-to/extending-openapi.md + - how-to/separate-openapi-schemas.md + - how-to/custom-docs-ui-assets.md + - how-to/configure-swagger-ui.md +- Reference (Code API): + - reference/index.md + - reference/fastapi.md + - reference/parameters.md + - reference/status.md + - reference/uploadfile.md + - reference/exceptions.md + - reference/dependencies.md + - reference/apirouter.md + - reference/background.md + - reference/request.md + - reference/websockets.md + - reference/httpconnection.md + - reference/response.md + - reference/responses.md + - reference/middleware.md + - OpenAPI: + - reference/openapi/index.md + - reference/openapi/docs.md + - reference/openapi/models.md + - reference/security/index.md + - reference/encoders.md + - reference/staticfiles.md + - reference/templating.md + - reference/testclient.md - fastapi-people.md -- python-types.md -- Tutorial - User Guide: - - tutorial/index.md - - tutorial/first-steps.md - - tutorial/path-params.md - - tutorial/query-params.md - - tutorial/body.md - - tutorial/query-params-str-validations.md - - tutorial/path-params-numeric-validations.md - - tutorial/body-multiple-params.md - - tutorial/body-fields.md - - tutorial/body-nested-models.md - - tutorial/schema-extra-example.md - - tutorial/extra-data-types.md - - tutorial/cookie-params.md - - tutorial/header-params.md - - tutorial/response-model.md - - tutorial/extra-models.md - - tutorial/response-status-code.md - - tutorial/request-forms.md - - tutorial/request-files.md - - tutorial/request-forms-and-files.md - - tutorial/handling-errors.md - - tutorial/path-operation-configuration.md - - tutorial/encoder.md - - tutorial/body-updates.md - - Dependencies: - - tutorial/dependencies/index.md - - tutorial/dependencies/classes-as-dependencies.md - - tutorial/dependencies/sub-dependencies.md - - tutorial/dependencies/dependencies-in-path-operation-decorators.md - - tutorial/dependencies/global-dependencies.md - - tutorial/dependencies/dependencies-with-yield.md - - Security: - - tutorial/security/index.md - - tutorial/security/first-steps.md - - tutorial/security/get-current-user.md - - tutorial/security/simple-oauth2.md - - tutorial/security/oauth2-jwt.md - - tutorial/middleware.md - - tutorial/cors.md - - tutorial/sql-databases.md - - tutorial/bigger-applications.md - - tutorial/background-tasks.md - - tutorial/metadata.md - - tutorial/static-files.md - - tutorial/testing.md - - tutorial/debugging.md -- Advanced User Guide: - - advanced/index.md - - advanced/path-operation-advanced-configuration.md - - advanced/additional-status-codes.md - - advanced/response-directly.md - - advanced/custom-response.md - - advanced/additional-responses.md - - advanced/response-cookies.md - - advanced/response-headers.md - - advanced/response-change-status-code.md - - advanced/advanced-dependencies.md - - Advanced Security: - - advanced/security/index.md - - advanced/security/oauth2-scopes.md - - advanced/security/http-basic-auth.md - - advanced/using-request-directly.md - - advanced/dataclasses.md - - advanced/middleware.md - - advanced/sql-databases-peewee.md - - advanced/async-sql-databases.md - - advanced/nosql-databases.md - - advanced/sub-applications.md - - advanced/behind-a-proxy.md - - advanced/templates.md - - advanced/graphql.md - - advanced/websockets.md - - advanced/events.md - - advanced/custom-request-and-route.md - - advanced/testing-websockets.md - - advanced/testing-events.md - - advanced/testing-dependencies.md - - advanced/testing-database.md - - advanced/async-tests.md - - advanced/settings.md - - advanced/conditional-openapi.md - - advanced/extending-openapi.md - - advanced/openapi-callbacks.md - - advanced/openapi-webhooks.md - - advanced/wsgi.md - - advanced/generate-clients.md -- async.md -- Deployment: - - deployment/index.md - - deployment/versions.md - - deployment/https.md - - deployment/manually.md - - deployment/concepts.md - - deployment/deta.md - - deployment/server-workers.md - - deployment/docker.md -- project-generation.md -- alternatives.md -- history-design-future.md -- external-links.md -- benchmarks.md -- help-fastapi.md -- newsletter.md -- contributing.md +- Resources: + - resources/index.md + - project-generation.md + - external-links.md + - newsletter.md +- About: + - about/index.md + - alternatives.md + - history-design-future.md + - benchmarks.md +- Help: + - help/index.md + - help-fastapi.md + - contributing.md - release-notes.md markdown_extensions: toc: @@ -178,9 +229,9 @@ markdown_extensions: guess_lang: false mdx_include: base_path: docs - admonition: - codehilite: - extra: + admonition: null + codehilite: null + extra: null pymdownx.superfences: custom_fences: - name: mermaid @@ -188,8 +239,8 @@ markdown_extensions: format: !!python/name:pymdownx.superfences.fence_code_format '' pymdownx.tabbed: alternate_style: true - attr_list: - md_in_html: + attr_list: null + md_in_html: null extra: analytics: provider: google @@ -240,8 +291,12 @@ extra: name: tr - Tรผrkรงe - link: /uk/ name: uk + - link: /ur/ + name: ur - link: /vi/ name: vi - Tiแบฟng Viแป‡t + - link: /yo/ + name: yo - Yorรนbรก - link: /zh/ name: zh - ๆฑ‰่ฏญ extra_css: diff --git a/docs/en/overrides/main.html b/docs/en/overrides/main.html index 983d7eb3e..476b43676 100644 --- a/docs/en/overrides/main.html +++ b/docs/en/overrides/main.html @@ -34,18 +34,36 @@ - + + + + {% endblock %} diff --git a/docs/es/docs/features.md b/docs/es/docs/features.md index 5d6b6509a..d05c4f73e 100644 --- a/docs/es/docs/features.md +++ b/docs/es/docs/features.md @@ -25,7 +25,7 @@ Documentaciรณn interactiva de la API e interfaces web de exploraciรณn. Hay mรบlt ### Simplemente Python moderno -Todo estรก basado en las declaraciones de tipo de **Python 3.6** estรกndar (gracias a Pydantic). No necesitas aprender una sintรกxis nueva, solo Python moderno. +Todo estรก basado en las declaraciones de tipo de **Python 3.8** estรกndar (gracias a Pydantic). No necesitas aprender una sintรกxis nueva, solo Python moderno. Si necesitas un repaso de 2 minutos de cรณmo usar los tipos de Python (asรญ no uses FastAPI) prueba el tutorial corto: [Python Types](python-types.md){.internal-link target=_blank}. diff --git a/docs/es/docs/index.md b/docs/es/docs/index.md index 5b75880c0..30a575577 100644 --- a/docs/es/docs/index.md +++ b/docs/es/docs/index.md @@ -23,7 +23,7 @@ **Cรณdigo Fuente**: https://github.com/tiangolo/fastapi --- -FastAPI es un web framework moderno y rรกpido (de alto rendimiento) para construir APIs con Python 3.6+ basado en las anotaciones de tipos estรกndar de Python. +FastAPI es un web framework moderno y rรกpido (de alto rendimiento) para construir APIs con Python 3.8+ basado en las anotaciones de tipos estรกndar de Python. Sus caracterรญsticas principales son: @@ -106,7 +106,7 @@ Si estรกs construyendo un app de Objets d'opรฉration. + La spรฉcification OpenAPI appelle ces mรฉtadonnรฉes des Objets d'opรฉration. Il contient toutes les informations sur le *chemin* et est utilisรฉ pour gรฉnรฉrer automatiquement la documentation. diff --git a/docs/fr/docs/alternatives.md b/docs/fr/docs/alternatives.md index ee20438c3..8e58a3dfa 100644 --- a/docs/fr/docs/alternatives.md +++ b/docs/fr/docs/alternatives.md @@ -387,7 +387,7 @@ Gรฉrer toute la validation des donnรฉes, leur sรฉrialisation et la documentation ### Starlette -Starlette est un framework/toolkit lรฉger ASGI, qui est idรฉal pour construire des services asyncio performants. +Starlette est un framework/toolkit lรฉger ASGI, qui est idรฉal pour construire des services asyncio performants. Il est trรจs simple et intuitif. Il est conรงu pour รชtre facilement extensible et avoir des composants modulaires. diff --git a/docs/fr/docs/async.md b/docs/fr/docs/async.md index db88c4663..af4d6ca06 100644 --- a/docs/fr/docs/async.md +++ b/docs/fr/docs/async.md @@ -250,7 +250,7 @@ Par exemple : ### Concurrence + Parallรฉlisme : Web + Machine Learning -Avec **FastAPI** vous pouvez bรฉnรฉficier de la concurrence qui est trรจs courante en developement web (c'est l'attrait principal de NodeJS). +Avec **FastAPI** vous pouvez bรฉnรฉficier de la concurrence qui est trรจs courante en dรฉveloppement web (c'est l'attrait principal de NodeJS). Mais vous pouvez aussi profiter du parallรฉlisme et multiprocessing afin de gรฉrer des charges **CPU bound** qui sont rรฉcurrentes dans les systรจmes de *Machine Learning*. diff --git a/docs/fr/docs/deployment/deta.md b/docs/fr/docs/deployment/deta.md deleted file mode 100644 index cceb7b058..000000000 --- a/docs/fr/docs/deployment/deta.md +++ /dev/null @@ -1,245 +0,0 @@ -# Dรฉployer FastAPI sur Deta - -Dans cette section, vous apprendrez ร  dรฉployer facilement une application **FastAPI** sur Deta en utilisant le plan tarifaire gratuit. ๐ŸŽ - -Cela vous prendra environ **10 minutes**. - -!!! info - Deta sponsorise **FastAPI**. ๐ŸŽ‰ - -## Une application **FastAPI** de base - -* Crรฉez un rรฉpertoire pour votre application, par exemple `./fastapideta/` et dรฉplacez-vous dedans. - -### Le code FastAPI - -* Crรฉer un fichier `main.py` avecย : - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int): - return {"item_id": item_id} -``` - -### Dรฉpendances - -Maintenant, dans le mรชme rรฉpertoire, crรฉez un fichier `requirements.txt` avecย : - -```text -fastapi -``` - -!!! tip "Astuce" - Il n'est pas nรฉcessaire d'installer Uvicorn pour dรฉployer sur Deta, bien qu'il soit probablement souhaitable de l'installer localement pour tester votre application. - -### Structure du rรฉpertoire - -Vous aurez maintenant un rรฉpertoire `./fastapideta/` avec deux fichiersย : - -``` -. -โ””โ”€โ”€ main.py -โ””โ”€โ”€ requirements.txt -``` - -## Crรฉer un compte gratuit sur Deta - -Crรฉez maintenant un compte gratuit -sur Deta, vous avez juste besoin d'une adresse email et d'un mot de passe. - -Vous n'avez mรชme pas besoin d'une carte de crรฉdit. - -## Installer le CLI (Interface en Ligne de Commande) - -Une fois que vous avez votre compte, installez le CLI de Deta : - -=== "Linux, macOS" - -
- - ```console - $ curl -fsSL https://get.deta.dev/cli.sh | sh - ``` - -
- -=== "Windows PowerShell" - -
- - ```console - $ iwr https://get.deta.dev/cli.ps1 -useb | iex - ``` - -
- -Aprรจs l'avoir installรฉ, ouvrez un nouveau terminal afin que la nouvelle installation soit dรฉtectรฉe. - -Dans un nouveau terminal, confirmez qu'il a รฉtรฉ correctement installรฉ avecย : - -
- -```console -$ deta --help - -Deta command line interface for managing deta micros. -Complete documentation available at https://docs.deta.sh - -Usage: - deta [flags] - deta [command] - -Available Commands: - auth Change auth settings for a deta micro - -... -``` - -
- -!!! tip "Astuce" - Si vous rencontrez des problรจmes pour installer le CLI, consultez la documentation officielle de Deta (en anglais). - -## Connexion avec le CLI - -Maintenant, connectez-vous ร  Deta depuis le CLI avecย : - -
- -```console -$ deta login - -Please, log in from the web page. Waiting.. -Logged in successfully. -``` - -
- -Cela ouvrira un navigateur web et permettra une authentification automatique. - -## Dรฉployer avec Deta - -Ensuite, dรฉployez votre application avec le CLI de Detaย : - -
- -```console -$ deta new - -Successfully created a new micro - -// Notice the "endpoint" ๐Ÿ” - -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} - -Adding dependencies... - - ----> 100% - - -Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 -``` - -
- -Vous verrez un message JSON similaire ร ย : - -```JSON hl_lines="4" -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} -``` - -!!! tip "Astuce" - Votre dรฉploiement aura une URL `"endpoint"` diffรฉrente. - -## Vรฉrifiez - -Maintenant, dans votre navigateur ouvrez votre URL `endpoint`. Dans l'exemple ci-dessus, c'รฉtait -`https://qltnci.deta.dev`, mais la vรดtre sera diffรฉrente. - -Vous verrez la rรฉponse JSON de votre application FastAPIย : - -```JSON -{ - "Hello": "World" -} -``` - -Et maintenant naviguez vers `/docs` dans votre API, dans l'exemple ci-dessus ce serait `https://qltnci.deta.dev/docs`. - -Vous verrez votre documentation comme suitย : - - - -## Activer l'accรจs public - -Par dรฉfaut, Deta va gรฉrer l'authentification en utilisant des cookies pour votre compte. - -Mais une fois que vous รชtes prรชt, vous pouvez le rendre public avecย : - -
- -```console -$ deta auth disable - -Successfully disabled http auth -``` - -
- -Maintenant, vous pouvez partager cette URL avec n'importe qui et ils seront en mesure d'accรฉder ร  votre API. ๐Ÿš€ - -## HTTPS - -Fรฉlicitationsโ€ฏ! Vous avez dรฉployรฉ votre application FastAPI sur Detaโ€ฏ! ๐ŸŽ‰ ๐Ÿฐ - -Remarquez รฉgalement que Deta gรจre correctement HTTPS pour vous, vous n'avez donc pas ร  vous en occuper et pouvez รชtre sรปr que vos clients auront une connexion cryptรฉe sรฉcurisรฉe. โœ… ๐Ÿ”’ - -## Vรฉrifiez le Visor - -ร€ partir de l'interface graphique de votre documentation (dans une URL telle que `https://qltnci.deta.dev/docs`) -envoyez une requรชte ร  votre *opรฉration de chemin* `/items/{item_id}`. - -Par exemple avec l'ID `5`. - -Allez maintenant sur https://web.deta.sh. - -Vous verrez qu'il y a une section ร  gauche appelรฉe "Micros" avec chacune de vos applications. - -Vous verrez un onglet avec "Details", et aussi un onglet "Visor", allez ร  l'onglet "Visor". - -Vous pouvez y consulter les requรชtes rรฉcentes envoyรฉes ร  votre application. - -Vous pouvez รฉgalement les modifier et les relancer. - - - -## En savoir plus - -ร€ un moment donnรฉ, vous voudrez probablement stocker certaines donnรฉes pour votre application d'une maniรจre qui -persiste dans le temps. Pour cela, vous pouvez utiliser Deta Base, il dispose รฉgalement d'un gรฉnรฉreux **plan gratuit**. - -Vous pouvez รฉgalement en lire plus dans la documentation Deta. diff --git a/docs/fr/docs/external-links.md b/docs/fr/docs/external-links.md index 002e6d2b2..37b8c5b13 100644 --- a/docs/fr/docs/external-links.md +++ b/docs/fr/docs/external-links.md @@ -9,70 +9,21 @@ Voici une liste incomplรจte de certains d'entre eux. !!! tip "Astuce" Si vous avez un article, projet, outil, ou quoi que ce soit liรฉ ร  **FastAPI** qui n'est actuellement pas listรฉ ici, crรฉez une Pull Request l'ajoutant. -## Articles +{% for section_name, section_content in external_links.items() %} -### Anglais +## {{ section_name }} -{% if external_links %} -{% for article in external_links.articles.english %} +{% for lang_name, lang_content in section_content.items() %} + +### {{ lang_name }} + +{% for item in lang_content %} + +* {{ item.title }} by {{ item.author }}. -* {{ article.title }} par {{ article.author }}. {% endfor %} -{% endif %} - -### Japonais - -{% if external_links %} -{% for article in external_links.articles.japanese %} - -* {{ article.title }} par {{ article.author }}. {% endfor %} -{% endif %} - -### Vietnamien - -{% if external_links %} -{% for article in external_links.articles.vietnamese %} - -* {{ article.title }} par {{ article.author }}. {% endfor %} -{% endif %} - -### Russe - -{% if external_links %} -{% for article in external_links.articles.russian %} - -* {{ article.title }} par {{ article.author }}. -{% endfor %} -{% endif %} - -### Allemand - -{% if external_links %} -{% for article in external_links.articles.german %} - -* {{ article.title }} par {{ article.author }}. -{% endfor %} -{% endif %} - -## Podcasts - -{% if external_links %} -{% for article in external_links.podcasts.english %} - -* {{ article.title }} par {{ article.author }}. -{% endfor %} -{% endif %} - -## Confรฉrences - -{% if external_links %} -{% for article in external_links.talks.english %} - -* {{ article.title }} par {{ article.author }}. -{% endfor %} -{% endif %} ## Projets diff --git a/docs/fr/docs/features.md b/docs/fr/docs/features.md index dcc0e39ed..0c1f6269a 100644 --- a/docs/fr/docs/features.md +++ b/docs/fr/docs/features.md @@ -25,7 +25,7 @@ Documentation d'API interactive et interface web d'exploration. Comme le framewo ### Faite en python moderne -Tout est basรฉ sur la dรฉclaration de type standard de **Python 3.6** (grรขce ร  Pydantic). Pas de nouvelles syntaxes ร  apprendre. Juste du Python standard et moderne. +Tout est basรฉ sur la dรฉclaration de type standard de **Python 3.8** (grรขce ร  Pydantic). Pas de nouvelles syntaxes ร  apprendre. Juste du Python standard et moderne. Si vous souhaitez un rappel de 2 minutes sur l'utilisation des types en Python (mรชme si vous ne comptez pas utiliser FastAPI), jetez un oeil au tutoriel suivant: [Python Types](python-types.md){.internal-link target=_blank}. @@ -71,9 +71,9 @@ my_second_user: User = User(**second_user_data) Tout le framework a รฉtรฉ conรงu pour รชtre facile et intuitif d'utilisation, toutes les dรฉcisions de design ont รฉtรฉ testรฉes sur de nombreux รฉditeurs avant mรชme de commencer le dรฉveloppement final afin d'assurer la meilleure expรฉrience de dรฉveloppement possible. -Dans le dernier sondage effectuรฉ auprรจs de dรฉveloppeurs python il รฉtait clair que la fonctionnalitรฉ la plus utilisรฉe est "l'autocomplรจtion". +Dans le dernier sondage effectuรฉ auprรจs de dรฉveloppeurs python il รฉtait clair que la fonctionnalitรฉ la plus utilisรฉe est "lโ€™autocomplรฉtion". -Tout le framwork **FastAPI** a รฉtรฉ conรงu avec cela en tรชte. L'autocomplรฉtion fonctionne partout. +Tout le framework **FastAPI** a รฉtรฉ conรงu avec cela en tรชte. L'autocomplรฉtion fonctionne partout. Vous devrez rarement revenir ร  la documentation. @@ -136,7 +136,7 @@ FastAPI contient un systรจme simple mais extrรชmement puissant d'Starlette. Le code utilisant Starlette que vous ajouterez fonctionnera donc aussi. -En fait, `FastAPI` est un sous compposant de `Starlette`. Donc, si vous savez dรฉjร  comment utiliser Starlette, la plupart des fonctionnalitรฉs fonctionneront de la mรชme maniรจre. +En fait, `FastAPI` est un sous composant de `Starlette`. Donc, si vous savez dรฉjร  comment utiliser Starlette, la plupart des fonctionnalitรฉs fonctionneront de la mรชme maniรจre. Avec **FastAPI** vous aurez toutes les fonctionnalitรฉs de **Starlette** (FastAPI est juste Starlette sous stรฉroรฏdes): -* Des performances vraiments impressionnantes. C'est l'un des framework Python les plus rapide, ร  รฉgalitรฉ avec **NodeJS** et **GO**. +* Des performances vraiment impressionnantes. C'est l'un des framework Python les plus rapide, ร  รฉgalitรฉ avec **NodeJS** et **GO**. * Le support des **WebSockets**. * Le support de **GraphQL**. * Les tรขches d'arriรจre-plan. @@ -180,7 +180,7 @@ Inclus des librairies externes basรฉes, aussi, sur Pydantic, servent d' dรฉcorateur de validation * 100% de couverture de test. diff --git a/docs/fr/docs/help-fastapi.md b/docs/fr/docs/help-fastapi.md index 0995721e1..525c699f5 100644 --- a/docs/fr/docs/help-fastapi.md +++ b/docs/fr/docs/help-fastapi.md @@ -36,8 +36,8 @@ Vous pouvez : * Me suivre sur **Twitter**. * Dites-moi comment vous utilisez FastAPI (j'adore entendre รงa). * Entendre quand je fais des annonces ou que je lance de nouveaux outils. -* Vous connectez ร  moi sur **Linkedin**. - * Etre notifiรฉ quand je fais des annonces ou que je lance de nouveaux outils (bien que j'utilise plus souvent Twitte ๐Ÿคทโ€โ™‚). +* Vous connectez ร  moi sur **LinkedIn**. + * Etre notifiรฉ quand je fais des annonces ou que je lance de nouveaux outils (bien que j'utilise plus souvent Twitter ๐Ÿคทโ€โ™‚). * Lire ce que jโ€™รฉcris (ou me suivre) sur **Dev.to** ou **Medium**. * Lire d'autres idรฉes, articles, et sur les outils que j'ai crรฉรฉs. * Suivez-moi pour lire quand je publie quelque chose de nouveau. @@ -84,24 +84,6 @@ Vous pouvez - Rejoindre le chat ร  https://gitter.im/tiangolo/fastapi - - -Rejoignez le chat sur Gitter: https://gitter.im/tiangolo/fastapi. - -Vous pouvez y avoir des conversations rapides avec d'autres personnes, aider les autres, partager des idรฉes, etc. - -Mais gardez ร  l'esprit que, comme il permet une "conversation plus libre", il est facile de poser des questions trop gรฉnรฉrales et plus difficiles ร  rรฉpondre, de sorte que vous risquez de ne pas recevoir de rรฉponses. - -Dans les Issues de GitHub, le modรจle vous guidera pour รฉcrire la bonne question afin que vous puissiez plus facilement obtenir une bonne rรฉponse, ou mรชme rรฉsoudre le problรจme vous-mรชme avant mรชme de le poser. Et dans GitHub, je peux m'assurer que je rรฉponds toujours ร  tout, mรชme si cela prend du temps. Je ne peux pas faire cela personnellement avec le chat Gitter. ๐Ÿ˜… - -Les conversations dans Gitter ne sont pas non plus aussi facilement consultables que dans GitHub, de sorte que les questions et les rรฉponses peuvent se perdre dans la conversation. - -De l'autre cรดtรฉ, il y a plus de 1000 personnes dans le chat, il y a donc de fortes chances que vous y trouviez quelqu'un ร  qui parler, presque tout le temps. ๐Ÿ˜„ - ## Parrainer l'auteur Vous pouvez รฉgalement soutenir financiรจrement l'auteur (moi) via GitHub sponsors. diff --git a/docs/fr/docs/index.md b/docs/fr/docs/index.md index 7c7547be1..f732fc74c 100644 --- a/docs/fr/docs/index.md +++ b/docs/fr/docs/index.md @@ -27,7 +27,7 @@ --- -FastAPI est un framework web moderne et rapide (haute performance) pour la crรฉation d'API avec Python 3.7+, 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 3.8+, basรฉ sur les annotations de type standard de Python. Les principales fonctionnalitรฉs sont : @@ -115,7 +115,7 @@ Si vous souhaitez construire une application en-tรชtes.**, **cookies**, **champs de formulaire** et **fichiers**. * L'utilisation de **contraintes de validation** comme `maximum_length` ou `regex`. -* Un **systรฉme d'injection de dรฉpendance ** trรจs puissant et facile ร  utiliser . +* Un **systรจme d'injection de dรฉpendance ** trรจs puissant et facile ร  utiliser . * Sรฉcuritรฉ et authentification, y compris la prise en charge de **OAuth2** avec les **jetons JWT** et l'authentification **HTTP Basic**. * Des techniques plus avancรฉes (mais tout aussi faciles) pour dรฉclarer les **modรจles JSON profondรฉment imbriquรฉs** (grรขce ร  Pydantic). * Intรฉgration de **GraphQL** avec Strawberry et d'autres bibliothรจques. @@ -450,7 +450,7 @@ Utilisรฉes par Pydantic: Utilisรฉes par Starlette : * requests - Obligatoire si vous souhaitez utiliser `TestClient`. -* jinja2 - Obligatoire si vous souhaitez utiliser la configuration de template par defaut. +* jinja2 - Obligatoire si vous souhaitez utiliser la configuration de template par dรฉfaut. * python-multipart - Obligatoire si vous souhaitez supporter le "dรฉcodage" de formulaire avec `request.form()`. * itsdangerous - Obligatoire pour la prise en charge de `SessionMiddleware`. * pyyaml - Obligatoire pour le support `SchemaGenerator` de Starlette (vous n'en avez probablement pas besoin avec FastAPI). diff --git a/docs/fr/docs/python-types.md b/docs/fr/docs/python-types.md index 4008ed96f..f49fbafd3 100644 --- a/docs/fr/docs/python-types.md +++ b/docs/fr/docs/python-types.md @@ -119,7 +119,7 @@ Comme l'รฉditeur connaรฎt le type des variables, vous n'avez pas seulement l'aut -Maintenant que vous avez connaissance du problรจme, convertissez `age` en chaine de caractรจres grรขce ร  `str(age)` : +Maintenant que vous avez connaissance du problรจme, convertissez `age` en chaรฎne de caractรจres grรขce ร  `str(age)` : ```Python hl_lines="2" {!../../../docs_src/python_types/tutorial004.py!} diff --git a/docs/fr/docs/tutorial/body.md b/docs/fr/docs/tutorial/body.md index 1e732d336..89720c973 100644 --- a/docs/fr/docs/tutorial/body.md +++ b/docs/fr/docs/tutorial/body.md @@ -98,7 +98,7 @@ Et vous obtenez aussi de la vรฉrification d'erreur pour les opรฉrations incorrec -Ce n'est pas un hasard, ce framework entier a รฉtรฉ bati avec ce design comme objectif. +Ce n'est pas un hasard, ce framework entier a รฉtรฉ bรขti avec ce design comme objectif. Et cela a รฉtรฉ rigoureusement testรฉ durant la phase de design, avant toute implรฉmentation, pour s'assurer que cela fonctionnerait avec tous les รฉditeurs. diff --git a/docs/fr/docs/tutorial/first-steps.md b/docs/fr/docs/tutorial/first-steps.md index 224c340c6..e98283f1e 100644 --- a/docs/fr/docs/tutorial/first-steps.md +++ b/docs/fr/docs/tutorial/first-steps.md @@ -170,7 +170,7 @@ Si vous crรฉez votre app avec : {!../../../docs_src/first_steps/tutorial002.py!} ``` -Et la mettez dans un fichier `main.py`, alors vous appeleriez `uvicorn` avec : +Et la mettez dans un fichier `main.py`, alors vous appelleriez `uvicorn` avec :
diff --git a/docs/fr/docs/tutorial/query-params.md b/docs/fr/docs/tutorial/query-params.md index 7bf3b9e79..962135f63 100644 --- a/docs/fr/docs/tutorial/query-params.md +++ b/docs/fr/docs/tutorial/query-params.md @@ -75,7 +75,7 @@ Ici, le paramรจtre `q` sera optionnel, et aura `None` comme valeur par dรฉfaut. !!! note **FastAPI** saura que `q` est optionnel grรขce au `=None`. - Le `Optional` dans `Optional[str]` n'est pas utilisรฉ par **FastAPI** (**FastAPI** n'en utilisera que la partie `str`), mais il servira tout de mรชme ร  votre editeur de texte pour dรฉtecter des erreurs dans votre code. + Le `Optional` dans `Optional[str]` n'est pas utilisรฉ par **FastAPI** (**FastAPI** n'en utilisera que la partie `str`), mais il servira tout de mรชme ร  votre รฉditeur de texte pour dรฉtecter des erreurs dans votre code. ## Conversion des types des paramรจtres de requรชte diff --git a/docs/ja/docs/deployment/deta.md b/docs/ja/docs/deployment/deta.md deleted file mode 100644 index 723f169a0..000000000 --- a/docs/ja/docs/deployment/deta.md +++ /dev/null @@ -1,240 +0,0 @@ -# Deta ใซใƒ‡ใƒ—ใƒญใ‚ค - -ใ“ใฎใ‚ปใ‚ฏใ‚ทใƒงใƒณใงใฏใ€**FastAPI** ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚’ Deta ใฎ็„กๆ–™ใƒ—ใƒฉใƒณใ‚’ๅˆฉ็”จใ—ใฆใ€็ฐกๅ˜ใซใƒ‡ใƒ—ใƒญใ‚คใ™ใ‚‹ๆ–นๆณ•ใ‚’ๅญฆ็ฟ’ใ—ใพใ™ใ€‚๐ŸŽ - -ๆ‰€่ฆๆ™‚้–“ใฏ็ด„**10ๅˆ†**ใงใ™ใ€‚ - -!!! info "ๅ‚™่€ƒ" - Deta ใฏ **FastAPI** ใฎใ‚นใƒใƒณใ‚ตใƒผใงใ™ใ€‚๐ŸŽ‰ - -## ใƒ™ใƒผใ‚ทใƒƒใ‚ฏใช **FastAPI** ใ‚ขใƒ—ใƒช - -* ใ‚ขใƒ—ใƒชใฎใŸใ‚ใฎใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒช (ไพ‹ใˆใฐ `./fastapideta/`) ใ‚’ไฝœๆˆใ—ใ€ใใฎไธญใซๅ…ฅใฃใฆใใ ใ•ใ„ใ€‚ - -### FastAPI ใฎใ‚ณใƒผใƒ‰ - -* ไปฅไธ‹ใฎ `main.py` ใƒ•ใ‚กใ‚คใƒซใ‚’ไฝœๆˆใ—ใฆใใ ใ•ใ„: - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int): - return {"item_id": item_id} -``` - -### Requirements - -ใงใฏใ€ๅŒใ˜ใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชใซไปฅไธ‹ใฎ `requirements.txt` ใƒ•ใ‚กใ‚คใƒซใ‚’ไฝœๆˆใ—ใฆใใ ใ•ใ„: - -```text -fastapi -``` - -!!! tip "่ฑ†็Ÿฅ่ญ˜" - ใ‚ขใƒ—ใƒชใฎใƒญใƒผใ‚ซใƒซใƒ†ใ‚นใƒˆใฎใŸใ‚ใซ Uvicorn ใ‚’ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใŸใใชใ‚‹ใ‹ใ‚‚ใ—ใ‚Œใพใ›ใ‚“ใŒใ€Deta ใธใฎใƒ‡ใƒ—ใƒญใ‚คใซใฏไธ่ฆใงใ™ใ€‚ - -### ใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชๆง‹้€  - -ไปฅไธ‹ใฎ2ใคใฎใƒ•ใ‚กใ‚คใƒซใจ1ใคใฎ `./fastapideta/` ใƒ‡ใ‚ฃใƒฌใ‚ฏใƒˆใƒชใŒใ‚ใ‚‹ใฏใšใงใ™: - -``` -. -โ””โ”€โ”€ main.py -โ””โ”€โ”€ requirements.txt -``` - -## Detaใฎ็„กๆ–™ใ‚ขใ‚ซใ‚ฆใƒณใƒˆใฎไฝœๆˆ - -ใใ‚Œใงใฏใ€Detaใฎ็„กๆ–™ใ‚ขใ‚ซใ‚ฆใƒณใƒˆใ‚’ไฝœๆˆใ—ใพใ—ใ‚‡ใ†ใ€‚ๅฟ…่ฆใชใ‚‚ใฎใฏใƒกใƒผใƒซใ‚ขใƒ‰ใƒฌใ‚นใจใƒ‘ใ‚นใƒฏใƒผใƒ‰ใ ใ‘ใงใ™ใ€‚ - -ใ‚ฏใƒฌใ‚ธใƒƒใƒˆใ‚ซใƒผใƒ‰ใ•ใˆๅฟ…่ฆใ‚ใ‚Šใพใ›ใ‚“ใ€‚ - -## CLIใฎใ‚คใƒณใ‚นใƒˆใƒผใƒซ - -ใ‚ขใ‚ซใ‚ฆใƒณใƒˆใ‚’ๅ–ๅพ—ใ—ใŸใ‚‰ใ€Deta CLI ใ‚’ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใฆใใ ใ•ใ„: - -=== "Linux, macOS" - -
- - ```console - $ curl -fsSL https://get.deta.dev/cli.sh | sh - ``` - -
- -=== "Windows PowerShell" - -
- - ```console - $ iwr https://get.deta.dev/cli.ps1 -useb | iex - ``` - -
- -ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใŸใ‚‰ใ€ใ‚คใƒณใ‚นใƒˆใƒผใƒซใ—ใŸ CLI ใ‚’ๆœ‰ๅŠนใซใ™ใ‚‹ใŸใ‚ใซๆ–ฐใŸใชใ‚ฟใƒผใƒŸใƒŠใƒซใ‚’้–‹ใ„ใฆใใ ใ•ใ„ใ€‚ - -ๆ–ฐใŸใชใ‚ฟใƒผใƒŸใƒŠใƒซไธŠใงใ€ๆญฃใ—ใใ‚คใƒณใ‚นใƒˆใƒผใƒซใ•ใ‚ŒใŸใ‹็ขบ่ชใ—ใพใ™: - -
- -```console -$ deta --help - -Deta command line interface for managing deta micros. -Complete documentation available at https://docs.deta.sh - -Usage: - deta [flags] - deta [command] - -Available Commands: - auth Change auth settings for a deta micro - -... -``` - -
- -!!! tip "่ฑ†็Ÿฅ่ญ˜" - CLI ใฎใ‚คใƒณใ‚นใƒˆใƒผใƒซใซๅ•้กŒใŒ็™บ็”Ÿใ—ใŸๅ ดๅˆใฏใ€Deta ๅ…ฌๅผใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’ๅ‚็…งใ—ใฆใใ ใ•ใ„ใ€‚ - -## CLIใงใƒญใ‚ฐใ‚คใƒณ - -CLI ใ‹ใ‚‰ Deta ใซใƒญใ‚ฐใ‚คใƒณใ—ใฆใฟใพใ—ใ‚‡ใ†: - -
- -```console -$ deta login - -Please, log in from the web page. Waiting.. -Logged in successfully. -``` - -
- -่‡ชๅ‹•็š„ใซใ‚ฆใ‚งใƒ–ใƒ–ใƒฉใ‚ฆใ‚ถใŒ้–‹ใ„ใฆใ€่ช่จผๅ‡ฆ็†ใŒ่กŒใ‚ใ‚Œใพใ™ใ€‚ - -## Deta ใงใƒ‡ใƒ—ใƒญใ‚ค - -ๆฌกใซใ€ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚’ Deta CLIใงใƒ‡ใƒ—ใƒญใ‚คใ—ใพใ—ใ‚‡ใ†: - -
- -```console -$ deta new - -Successfully created a new micro - -// Notice the "endpoint" ๐Ÿ” - -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} - -Adding dependencies... - - ----> 100% - - -Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 -``` - -
- -ๆฌกใฎใ‚ˆใ†ใชJSONใƒกใƒƒใ‚ปใƒผใ‚ธใŒ่กจ็คบใ•ใ‚Œใพใ™: - -```JSON hl_lines="4" -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} -``` - -!!! tip "่ฑ†็Ÿฅ่ญ˜" - ใ‚ใชใŸใฎใƒ‡ใƒ—ใƒญใ‚คใงใฏ็•ฐใชใ‚‹ `"endpoint"` URLใŒ่กจ็คบใ•ใ‚Œใ‚‹ใงใ—ใ‚‡ใ†ใ€‚ - -## ็ขบ่ช - -ใใ‚Œใงใฏใ€`endpoint` URLใ‚’ใƒ–ใƒฉใ‚ฆใ‚ถใง้–‹ใ„ใฆใฟใพใ—ใ‚‡ใ†ใ€‚ไธŠ่จ˜ใฎไพ‹ใงใฏ `https://qltnci.deta.dev` ใงใ™ใŒใ€ใ‚ใชใŸใฎURLใฏ็•ฐใชใ‚‹ใฏใšใงใ™ใ€‚ - -FastAPIใ‚ขใƒ—ใƒชใ‹ใ‚‰่ฟ”ใฃใฆใใŸJSONใƒฌใ‚นใƒใƒณใ‚นใŒ่กจ็คบใ•ใ‚Œใพใ™: - -```JSON -{ - "Hello": "World" -} -``` - -ใใ—ใฆ `/docs` ใธ็งปๅ‹•ใ—ใฆใใ ใ•ใ„ใ€‚ไธŠ่จ˜ใฎไพ‹ใงใฏใ€`https://qltnci.deta.dev/docs` ใงใ™ใ€‚ - -ๆฌกใฎใ‚ˆใ†ใชใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใŒ่กจ็คบใ•ใ‚Œใพใ™: - - - -## ใƒ‘ใƒ–ใƒชใƒƒใ‚ฏใ‚ขใ‚ฏใ‚ปใ‚นใฎๆœ‰ๅŠนๅŒ– - -ใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใงใฏใ€Deta ใฏใ‚ฏใƒƒใ‚ญใƒผใ‚’็”จใ„ใฆใ‚ขใ‚ซใ‚ฆใƒณใƒˆใฎ่ช่จผใ‚’่กŒใ„ใพใ™ใ€‚ - -ใ—ใ‹ใ—ใ€ๆบ–ๅ‚™ใŒๆ•ดใˆใฐใ€ไปฅไธ‹ใฎๆง˜ใซๅ…ฌ้–‹ใงใใพใ™: - -
- -```console -$ deta auth disable - -Successfully disabled http auth -``` - -
- -ใ“ใ“ใงใ€URLใ‚’ๅ…ฑๆœ‰ใ™ใ‚‹ใจAPIใซใ‚ขใ‚ฏใ‚ปใ‚นใงใใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ™ใ€‚๐Ÿš€ - -## HTTPS - -ใŠใ‚ใงใจใ†ใ”ใ–ใ„ใพใ™๏ผใ‚ใชใŸใฎ FastAPI ใ‚ขใƒ—ใƒชใŒ Deta ใธใƒ‡ใƒ—ใƒญใ‚คใ•ใ‚Œใพใ—ใŸ๏ผ๐ŸŽ‰ ๐Ÿฐ - -ใพใŸใ€DetaใŒHTTPSใ‚’ๆญฃใ—ใๅ‡ฆ็†ใ™ใ‚‹ใŸใ‚ใ€ใใฎๅ‡ฆ็†ใ‚’่กŒใ†ๅฟ…่ฆใŒใชใใ€ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใฏๆš—ๅทๅŒ–ใ•ใ‚ŒใŸๅฎ‰ๅ…จใช้€šไฟกใŒๅˆฉ็”จใงใใพใ™ใ€‚โœ… ๐Ÿ”’ - -## Visor ใ‚’็ขบ่ช - -ใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆUI (`https://qltnci.deta.dev/docs` ใฎใ‚ˆใ†ใชURLใซใ‚ใ‚‹) ใฏ *path operation* `/items/{item_id}` ใธใƒชใ‚ฏใ‚จใ‚นใƒˆใ‚’้€ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ - -ID `5` ใฎไพ‹ใ‚’็คบใ—ใพใ™ใ€‚ - -ใพใšใ€https://web.deta.sh ใธใ‚ขใ‚ฏใ‚ปใ‚นใ—ใพใ™ใ€‚ - -ๅทฆๅดใซๅ„ใ‚ขใƒ—ใƒชใฎ ใ€ŒMicrosใ€ ใจใ„ใ†ใ‚ปใ‚ฏใ‚ทใƒงใƒณใŒ่กจ็คบใ•ใ‚Œใพใ™ใ€‚ - -ใพใŸใ€ใ€ŒDetailsใ€ใ‚„ใ€ŒVisorใ€ใ‚ฟใƒ–ใŒ่กจ็คบใ•ใ‚Œใฆใ„ใพใ™ใ€‚ใ€ŒVisorใ€ใ‚ฟใƒ–ใธ็งปๅ‹•ใ—ใฆใใ ใ•ใ„ใ€‚ - -ใใ“ใงใ‚ขใƒ—ใƒชใซ้€ใ‚‰ใ‚ŒใŸ็›ด่ฟ‘ใฎใƒชใ‚ฏใ‚จใ‚นใƒˆใŒ่ชฟในใ‚‰ใ‚Œใพใ™ใ€‚ - -ใพใŸใ€ใใ‚Œใ‚‰ใ‚’็ทจ้›†ใ—ใฆใƒชใƒ—ใƒฌใ‚คใงใใพใ™ใ€‚ - - - -## ใ•ใ‚‰ใซ่ฉณใ—ใ็Ÿฅใ‚‹ - -ๆง˜ใ€…ใช็ฎ‡ๆ‰€ใงๆฐธ็ถš็š„ใซใƒ‡ใƒผใ‚ฟใ‚’ไฟๅญ˜ใ—ใŸใใชใ‚‹ใงใ—ใ‚‡ใ†ใ€‚ใใฎใŸใ‚ใซใฏ Deta Base ใ‚’ไฝฟ็”จใงใใพใ™ใ€‚ๆƒœใ—ใฟใชใ„ **็„กๆ–™ๅˆฉ็”จๆž ** ใ‚‚ใ‚ใ‚Šใพใ™ใ€‚ - -่ฉณใ—ใใฏ Deta ใƒ‰ใ‚ญใƒฅใƒกใƒณใƒˆใ‚’ๅ‚็…งใ—ใฆใใ ใ•ใ„ใ€‚ diff --git a/docs/ja/docs/deployment/https.md b/docs/ja/docs/deployment/https.md new file mode 100644 index 000000000..a291f870f --- /dev/null +++ b/docs/ja/docs/deployment/https.md @@ -0,0 +1,200 @@ +# HTTPS ใซใคใ„ใฆ + +HTTPSใฏๅ˜ใซใ€Œๆœ‰ๅŠนใ€ใ‹ใ€Œ็„กๅŠนใ€ใ‹ใงๆฑบใพใ‚‹ใ‚‚ใฎใ ใจๆ€ใ„ใŒใกใงใ™ใ€‚ + +ใ—ใ‹ใ—ใ€ใใ‚Œใ‚ˆใ‚Šใ‚‚ใฏใ‚‹ใ‹ใซ่ค‡้›‘ใงใ™ใ€‚ + +!!! tip + ใ‚‚ใ—ๆ€ฅใ„ใงใ„ใŸใ‚Šใ€HTTPSใฎไป•็ต„ใฟใซใคใ„ใฆๆฐ—ใซใ—ใชใ„ใฎใงใ‚ใ‚Œใฐใ€ๆฌกใฎใ‚ปใ‚ฏใ‚ทใƒงใƒณใซ้€ฒใฟใ€ใ•ใพใ–ใพใชใƒ†ใ‚ฏใƒ‹ใƒƒใ‚ฏใ‚’ไฝฟใฃใฆใ™ในใฆใ‚’ใ‚ปใƒƒใƒˆใ‚ขใƒƒใƒ—ใ™ใ‚‹ใ‚นใƒ†ใƒƒใƒ—ใƒปใƒใ‚คใƒปใ‚นใƒ†ใƒƒใƒ—ใฎๆ‰‹้ †ใ‚’ใ”่ฆงใใ ใ•ใ„ใ€‚ + +ๅˆฉ็”จ่€…ใฎ่ฆ–็‚นใ‹ใ‚‰ **HTTPS ใฎๅŸบๆœฌใ‚’ๅญฆใถ**ใซๅฝ“ใŸใฃใฆใฏใ€ๆฌกใฎใƒชใ‚ฝใƒผใ‚นใ‚’ใ‚ชใ‚นใ‚นใƒกใ—ใพใ™: https://howhttps.works/. + +ใ•ใฆใ€**้–‹็™บ่€…ใฎ่ฆ–็‚น**ใ‹ใ‚‰ใ€HTTPSใซใคใ„ใฆ่€ƒใˆใ‚‹้š›ใซๅฟต้ ญใซ็ฝฎใในใใ“ใจใ‚’ใ„ใใคใ‹ใฟใฆใ„ใใพใ—ใ‚‡ใ†๏ผš + +* HTTPSใฎๅ ดๅˆใ€**ใ‚ตใƒผใƒ**ใฏ**็ฌฌไธ‰่€…**ใซใ‚ˆใฃใฆ็”Ÿๆˆใ•ใ‚ŒใŸ**ใ€Œ่จผๆ˜Žๆ›ธใ€ใ‚’ๆŒใค**ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ + * ใ“ใ‚Œใ‚‰ใฎ่จผๆ˜Žๆ›ธใฏใ€Œ็”Ÿๆˆใ€ใ•ใ‚ŒใŸใ‚‚ใฎใงใฏใชใใ€ๅฎŸ้š›ใซใฏ็ฌฌไธ‰่€…ใ‹ใ‚‰**ๅ–ๅพ—**ใ•ใ‚ŒใŸใ‚‚ใฎใงใ™ใ€‚ +* ่จผๆ˜Žๆ›ธใซใฏ**ๆœ‰ๅŠนๆœŸ้™**ใŒใ‚ใ‚Šใพใ™ใ€‚ + * ใคใพใ‚Šใ„ใšใ‚ŒๅคฑๅŠนใ—ใพใ™ใ€‚ + * ใใฎใŸใ‚**ๆ›ดๆ–ฐ**ใ‚’ใ—ใ€็ฌฌไธ‰่€…ใ‹ใ‚‰**ๅ†ๅบฆๅ–ๅพ—**ใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ +* ๆŽฅ็ถšใฎๆš—ๅทๅŒ–ใฏ**TCPใƒฌใƒ™ใƒซ**ใง่กŒใ‚ใ‚Œใพใ™ใ€‚ + * ใใ‚Œใฏ**HTTPใฎ1ใคไธ‹**ใฎใƒฌใ‚คใƒคใƒผใงใ™ใ€‚ + * ใคใพใ‚Šใ€**่จผๆ˜Žๆ›ธใจๆš—ๅทๅŒ–**ใฎๅ‡ฆ็†ใฏใ€**HTTPใฎๅ‰**ใซ่กŒใ‚ใ‚Œใพใ™ใ€‚ +* **TCPใฏ "ใƒ‰ใƒกใ‚คใƒณ "ใซใคใ„ใฆ็Ÿฅใ‚Šใพใ›ใ‚“**ใ€‚IPใ‚ขใƒ‰ใƒฌใ‚นใซใคใ„ใฆใฎใฟ็Ÿฅใฃใฆใ„ใพใ™ใ€‚ + * ่ฆๆฑ‚ใ•ใ‚ŒใŸ**็‰นๅฎšใฎใƒ‰ใƒกใ‚คใƒณ**ใซ้–ขใ™ใ‚‹ๆƒ…ๅ ฑใฏใ€**HTTPใƒ‡ใƒผใ‚ฟ**ใซๅ…ฅใ‚Šใพใ™ใ€‚ +* **HTTPS่จผๆ˜Žๆ›ธ**ใฏใ€**็‰นๅฎšใฎใƒ‰ใƒกใ‚คใƒณ**ใ‚’ใ€Œ่จผๆ˜Žใ€ใ—ใพใ™ใŒใ€ใƒ—ใƒญใƒˆใ‚ณใƒซใจๆš—ๅทๅŒ–ใฏTCPใƒฌใƒ™ใƒซใง่กŒใ‚ใ‚Œใ€ใฉใฎใƒ‰ใƒกใ‚คใƒณใŒๆ‰ฑใ‚ใ‚Œใฆใ„ใ‚‹ใ‹ใ‚’**็Ÿฅใ‚‹ๅ‰**ใซ่กŒใ‚ใ‚Œใพใ™ใ€‚ +* **ใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใงใฏ**ใ€**IPใ‚ขใƒ‰ใƒฌใ‚นใ”ใจใซ1ใคใฎHTTPS่จผๆ˜Žๆ›ธ**ใ—ใ‹ๆŒใฆใชใ„ใ“ใจใซใชใ‚Šใพใ™ใ€‚ + * ใ“ใ‚Œใฏใ€ใ‚ตใƒผใƒใƒผใฎ่ฆๆจกใ‚„ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎ่ฆๆจกใซๅฏ„ใ‚Šใพใ›ใ‚“ใ€‚ + * ใ—ใ‹ใ—ใ€ใ“ใ‚Œใซใฏ**่งฃๆฑบ็ญ–**ใŒใ‚ใ‚Šใพใ™ใ€‚ +* **TLS**ใƒ—ใƒญใƒˆใ‚ณใƒซ(HTTPใฎๅ‰ใซใ€TCPใƒฌใƒ™ใƒซใงๆš—ๅทๅŒ–ใ‚’ๅ‡ฆ็†ใ™ใ‚‹ใ‚‚ใฎ)ใซใฏใ€**SNI**ใจๅ‘ผใฐใ‚Œใ‚‹**ๆ‹กๅผต**ใŒใ‚ใ‚Šใพใ™ใ€‚ + * ใ“ใฎSNIๆ‹กๅผตๆฉŸ่ƒฝใซใ‚ˆใ‚Šใ€1ใคใฎใ‚ตใƒผใƒใƒผ๏ผˆ**ๅ˜ไธ€ใฎIPใ‚ขใƒ‰ใƒฌใ‚น**ใ‚’ๆŒใค๏ผ‰ใŒ**่ค‡ๆ•ฐใฎHTTPS่จผๆ˜Žๆ›ธ**ใ‚’ๆŒใกใ€**่ค‡ๆ•ฐใฎHTTPSใƒ‰ใƒกใ‚คใƒณ/ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณ**ใซใ‚ตใƒผใƒ“ใ‚นใ‚’ๆไพ›ใงใใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ™ใ€‚ + * ใ“ใ‚ŒใŒๆฉŸ่ƒฝใ™ใ‚‹ใŸใ‚ใซใฏใ€**ใƒ‘ใƒ–ใƒชใƒƒใ‚ฏIPใ‚ขใƒ‰ใƒฌใ‚น**ใงใƒชใƒƒใ‚นใƒณใ—ใฆใ„ใ‚‹ใ€ใ‚ตใƒผใƒใƒผไธŠใงๅ‹•ไฝœใ—ใฆใ„ใ‚‹**ๅ˜ไธ€ใฎ**ใ‚ณใƒณใƒใƒผใƒใƒณใƒˆ(ใƒ—ใƒญใ‚ฐใƒฉใƒ )ใŒใ€ใ‚ตใƒผใƒใƒผๅ†…ใฎ**ใ™ในใฆใฎHTTPS่จผๆ˜Žๆ›ธ**ใ‚’ๆŒใฃใฆใ„ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ + +* ใ‚ปใ‚ญใƒฅใ‚ขใชๆŽฅ็ถšใ‚’ๅ–ๅพ—ใ—ใŸ**ๅพŒ**ใงใ‚‚ใ€้€šไฟกใƒ—ใƒญใƒˆใ‚ณใƒซใฏ**HTTPใฎใพใพ**ใงใ™ใ€‚ + * ใ‚ณใƒณใƒ†ใƒณใƒ„ใฏ**HTTPใƒ—ใƒญใƒˆใ‚ณใƒซ**ใง้€ไฟกใ•ใ‚Œใฆใ„ใ‚‹ใซใ‚‚ใ‹ใ‹ใ‚ใ‚‰ใšใ€**ๆš—ๅทๅŒ–**ใ•ใ‚Œใฆใ„ใพใ™ใ€‚ + + +ใ‚ตใƒผใƒใƒผ๏ผˆใƒžใ‚ทใƒณใ€ใƒ›ใ‚นใƒˆใชใฉ๏ผ‰ไธŠใง**1ใคใฎใƒ—ใƒญใ‚ฐใƒฉใƒ /HTTPใ‚ตใƒผใƒใƒผ**ใ‚’ๅฎŸ่กŒใ•ใ›ใ€**HTTPSใซ้–ขใ™ใ‚‹ๅ…จใฆใฎใ“ใจ**ใ‚’็ฎก็†ใ™ใ‚‹ใฎใŒไธ€่ˆฌ็š„ใงใ™ใ€‚ + +**ๆš—ๅทๅŒ–ใ•ใ‚ŒใŸ HTTPS ใƒชใ‚ฏใ‚จใ‚นใƒˆ** ใ‚’ๅ—ไฟกใ—ใ€**ๅพฉๅทๅŒ–ใ•ใ‚ŒใŸ HTTP ใƒชใ‚ฏใ‚จใ‚นใƒˆ** ใ‚’ๅŒใ˜ใ‚ตใƒผใƒใƒผใงๅฎŸ่กŒใ•ใ‚Œใฆใ„ใ‚‹ๅฎŸ้š›ใฎ HTTP ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณ๏ผˆใ“ใฎๅ ดๅˆใฏ **FastAPI** ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณ๏ผ‰ใซ้€ไฟกใ—ใ€ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‹ใ‚‰ **HTTP ใƒฌใ‚นใƒใƒณใ‚น** ใ‚’ๅ—ใ‘ๅ–ใ‚Šใ€้ฉๅˆ‡ใช **HTTPS ่จผๆ˜Žๆ›ธ** ใ‚’ไฝฟ็”จใ—ใฆ **ๆš—ๅทๅŒ–** ใ—ใ€ใใ—ใฆ**HTTPS** ใ‚’ไฝฟ็”จใ—ใฆใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใซ้€ใ‚Š่ฟ”ใ—ใพใ™ใ€‚ + +ใ“ใฎใ‚ตใƒผใƒใƒผใฏใ—ใฐใ—ใฐ **TLS Termination Proxy**ใจๅ‘ผใฐใ‚Œใพใ™ใ€‚ + +TLS Termination Proxyใจใ—ใฆไฝฟใˆใ‚‹ใ‚ชใƒ—ใ‚ทใƒงใƒณใซใฏใ€ไปฅไธ‹ใฎใ‚ˆใ†ใชใ‚‚ใฎใŒใ‚ใ‚Šใพใ™๏ผš + +* Traefik๏ผˆ่จผๆ˜Žๆ›ธใฎๆ›ดๆ–ฐใ‚‚ๅฏพๅฟœ๏ผ‰ +* Caddy (่จผๆ˜Žๆ›ธใฎๆ›ดๆ–ฐใ‚‚ๅฏพๅฟœ) +* Nginx +* HAProxy + + +## Let's Encrypt + +Let's Encryptไปฅๅ‰ใฏใ€ใ“ใ‚Œใ‚‰ใฎ**HTTPS่จผๆ˜Žๆ›ธ**ใฏไฟก้ ผใงใใ‚‹็ฌฌไธ‰่€…ใซใ‚ˆใฃใฆ่ฒฉๅฃฒใ•ใ‚Œใฆใ„ใพใ—ใŸใ€‚ + +ใ“ใ‚Œใ‚‰ใฎ่จผๆ˜Žๆ›ธใ‚’ๅ–ๅพ—ใ™ใ‚‹ใŸใ‚ใฎๆ‰‹็ถšใใฏ้ขๅ€’ใงใ€ใ‹ใชใ‚Šใฎๆ›ธ้กžใ‚’ๅฟ…่ฆใจใ—ใ€่จผๆ˜Žๆ›ธใฏใ‹ใชใ‚Š้ซ˜ไพกใชใ‚‚ใฎใงใ—ใŸใ€‚ + +ใ—ใ‹ใ—ใใฎๅพŒใ€**Let's Encrypt** ใŒไฝœใ‚‰ใ‚Œใพใ—ใŸใ€‚ + +ใ“ใ‚ŒใฏLinux Foundationใฎใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใ‹ใ‚‰็”Ÿใพใ‚ŒใŸใ‚‚ใฎใงใ™ใ€‚ ่‡ชๅ‹•ๅŒ–ใ•ใ‚ŒใŸๆ–นๆณ•ใงใ€**HTTPS่จผๆ˜Žๆ›ธใ‚’็„กๆ–™ใง**ๆไพ›ใ—ใพใ™ใ€‚ใ“ใ‚Œใ‚‰ใฎ่จผๆ˜Žๆ›ธใฏใ€ใ™ในใฆใฎๆจ™ๆบ–็š„ใชๆš—ๅทๅŒ–ใ‚ปใ‚ญใƒฅใƒชใƒ†ใ‚ฃใ‚’ไฝฟ็”จใ—ใ€ใพใŸ็Ÿญๅ‘ฝ๏ผˆ็ด„3ใƒถๆœˆ๏ผ‰ใงใ™ใŒใ€ใ“ใ†ใ„ใฃใŸๅฏฟๅ‘ฝใฎ็Ÿญใ•ใซใ‚ˆใฃใฆใ€**ใ‚ปใ‚ญใƒฅใƒชใƒ†ใ‚ฃใฏๅฎŸ้š›ใซๅ„ชใ‚Œใฆใ„ใพใ™**ใ€‚ + +ใƒ‰ใƒกใ‚คใƒณใฏๅฎ‰ๅ…จใซๆคœ่จผใ•ใ‚Œใ€่จผๆ˜Žๆ›ธใฏ่‡ชๅ‹•็š„ใซ็”Ÿๆˆใ•ใ‚Œใพใ™ใ€‚ใพใŸใ€่จผๆ˜Žๆ›ธใฎๆ›ดๆ–ฐใ‚‚่‡ชๅ‹•ๅŒ–ใ•ใ‚Œใพใ™ใ€‚ + +ใ“ใฎใ‚ขใ‚คใƒ‡ใ‚ขใฏใ€ใ“ใ‚Œใ‚‰ใฎ่จผๆ˜Žๆ›ธใฎๅ–ๅพ—ใจๆ›ดๆ–ฐใ‚’่‡ชๅ‹•ๅŒ–ใ™ใ‚‹ใ“ใจใงใ€**ๅฎ‰ๅ…จใชHTTPSใ‚’ใ€็„กๆ–™ใงใ€ๆฐธ้ ใซ**ๅˆฉ็”จใงใใ‚‹ใ‚ˆใ†ใซใ™ใ‚‹ใ“ใจใงใ™ใ€‚ + +## ้–‹็™บ่€…ใฎใŸใ‚ใฎ HTTPS + +ใ“ใ“ใงใฏใ€HTTPS APIใŒใฉใฎใ‚ˆใ†ใซ่ฆ‹ใˆใ‚‹ใ‹ใฎไพ‹ใ‚’ใ€ไธปใซ้–‹็™บ่€…ใซใจใฃใฆ้‡่ฆใชใ‚ขใ‚คใƒ‡ใ‚ขใซๆณจๆ„ใ‚’ๆ‰•ใ„ใชใŒใ‚‰ใ€ใ‚นใƒ†ใƒƒใƒ—ใƒปใƒใ‚คใƒปใ‚นใƒ†ใƒƒใƒ—ใง่ชฌๆ˜Žใ—ใพใ™ใ€‚ + +### ใƒ‰ใƒกใ‚คใƒณๅ + +ใ‚นใƒ†ใƒƒใƒ—ใฎๅˆใ‚ใฏใ€**ใƒ‰ใƒกใ‚คใƒณๅ**ใ‚’**ๅ–ๅพ—ใ™ใ‚‹ใ“ใจ**ใ‹ใ‚‰ๅง‹ใพใ‚‹ใงใ—ใ‚‡ใ†ใ€‚ใใฎๅพŒใ€DNSใ‚ตใƒผใƒใƒผ๏ผˆใŠใใ‚‰ใๅŒใ˜ใ‚ฏใƒฉใ‚ฆใƒ‰ใƒ—ใƒญใƒใ‚คใƒ€ใƒผ๏ผ‰ใซ่จญๅฎšใ—ใพใ™ใ€‚ + +ใŠใใ‚‰ใใ‚ฏใƒฉใ‚ฆใƒ‰ใ‚ตใƒผใƒใƒผ๏ผˆไปฎๆƒณใƒžใ‚ทใƒณ๏ผ‰ใ‹ใใ‚Œใซ้กžใ™ใ‚‹ใ‚‚ใฎใ‚’ๆ‰‹ใซๅ…ฅใ‚Œใ€ๅ›บๅฎšใฎ **ใƒ‘ใƒ–ใƒชใƒƒใ‚ฏIPใ‚ขใƒ‰ใƒฌใ‚น**ใ‚’ๆŒใคใ“ใจใซใชใ‚‹ใงใ—ใ‚‡ใ†ใ€‚ + +DNSใ‚ตใƒผใƒใƒผใงใฏใ€**ๅ–ๅพ—ใ—ใŸใƒ‰ใƒกใ‚คใƒณ**ใ‚’ใ‚ใชใŸใฎใ‚ตใƒผใƒใƒผใฎใƒ‘ใƒ—ใƒชใƒƒใ‚ฏ**IPใ‚ขใƒ‰ใƒฌใ‚น**ใซๅ‘ใ‘ใ‚‹ใƒฌใ‚ณใƒผใƒ‰๏ผˆใ€Œ`Aใƒฌใ‚ณใƒผใƒ‰`ใ€๏ผ‰ใ‚’่จญๅฎšใ—ใพใ™ใ€‚ + +ใ“ใ‚ŒใฏใŠใใ‚‰ใใ€ๆœ€ๅˆใฎ1ๅ›žใ ใ‘ใ‚ใ‚Šใ€ใ™ในใฆใ‚’ใ‚ปใƒƒใƒˆใ‚ขใƒƒใƒ—ใ™ใ‚‹ใจใใซ่กŒใ†ใงใ—ใ‚‡ใ†ใ€‚ + +!!! tip + ใƒ‰ใƒกใ‚คใƒณๅใฎ่ฉฑใฏHTTPSใซ้–ขใ™ใ‚‹่ฉฑใฎใฏใ‚‹ใ‹ๅ‰ใซใ‚ใ‚Šใพใ™ใŒใ€ใ™ในใฆใŒใƒ‰ใƒกใ‚คใƒณใจIPใ‚ขใƒ‰ใƒฌใ‚นใซไพๅญ˜ใ™ใ‚‹ใŸใ‚ใ€ใ“ใ“ใง่จ€ๅŠใ™ใ‚‹ไพกๅ€คใŒใ‚ใ‚Šใพใ™ใ€‚ + +### DNS + +ใงใฏใ€ๅฎŸ้š›ใฎHTTPSใฎ้ƒจๅˆ†ใซๆณจ็›ฎใ—ใฆใฟใ‚ˆใ†ใ€‚ + +ใพใšใ€ใƒ–ใƒฉใ‚ฆใ‚ถใฏ**DNSใ‚ตใƒผใƒใƒผ**ใซ**ใƒ‰ใƒกใ‚คใƒณใซๅฏพใ™ใ‚‹IP**ใŒไฝ•ใงใ‚ใ‚‹ใ‹ใ‚’็ขบ่ชใ—ใพใ™ใ€‚ไปŠๅ›žใฏใ€`someapp.example.com`ใจใ—ใพใ™ใ€‚ + +DNSใ‚ตใƒผใƒใƒผใฏใ€ใƒ–ใƒฉใ‚ฆใ‚ถใซ็‰นๅฎšใฎ**IPใ‚ขใƒ‰ใƒฌใ‚น**ใ‚’ไฝฟ็”จใ™ใ‚‹ใ‚ˆใ†ใซๆŒ‡็คบใ—ใพใ™ใ€‚ใ“ใฎIPใ‚ขใƒ‰ใƒฌใ‚นใฏใ€DNSใ‚ตใƒผใƒใƒผใง่จญๅฎšใ—ใŸใ€ใ‚ใชใŸใฎใ‚ตใƒผใƒใƒผใŒไฝฟ็”จใ™ใ‚‹ใƒ‘ใƒ–ใƒชใƒƒใ‚ฏIPใ‚ขใƒ‰ใƒฌใ‚นใซใชใ‚Šใพใ™ใ€‚ + + + +### TLS Handshake ใฎ้–‹ๅง‹ + +ใƒ–ใƒฉใ‚ฆใ‚ถใฏIPใ‚ขใƒ‰ใƒฌใ‚นใจ**ใƒใƒผใƒˆ443**๏ผˆHTTPSใƒใƒผใƒˆ๏ผ‰ใง้€šไฟกใ—ใพใ™ใ€‚ + +้€šไฟกใฎๆœ€ๅˆใฎ้ƒจๅˆ†ใฏใ€ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใจใ‚ตใƒผใƒใƒผ้–“ใฎๆŽฅ็ถšใ‚’็ขบ็ซ‹ใ—ใ€ไฝฟ็”จใ™ใ‚‹ๆš—ๅท้ตใชใฉใ‚’ๆฑบใ‚ใ‚‹ใ ใ‘ใงใ™ใ€‚ + + + +TLSๆŽฅ็ถšใ‚’็ขบ็ซ‹ใ™ใ‚‹ใŸใ‚ใฎใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใจใ‚ตใƒผใƒใƒผ้–“ใฎใ“ใฎใ‚„ใ‚Šใจใ‚Šใฏใ€**TLSใƒใƒณใƒ‰ใ‚ทใ‚งใ‚คใ‚ฏ**ใจๅ‘ผใฐใ‚Œใพใ™ใ€‚ + +### SNIๆ‹กๅผตๆฉŸ่ƒฝไป˜ใใฎTLS + +ใ‚ตใƒผใƒใƒผๅ†…ใฎ**1ใคใฎใƒ—ใƒญใ‚ปใ‚น**ใ ใ‘ใŒใ€็‰นๅฎš ใฎ**IPใ‚ขใƒ‰ใƒฌใ‚น**ใฎ็‰นๅฎšใฎ**ใƒใƒผใƒˆ** ใงๅพ…ใกๅ—ใ‘ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + +ๅŒใ˜IPใ‚ขใƒ‰ใƒฌใ‚นใฎไป–ใฎใƒใƒผใƒˆใงไป–ใฎใƒ—ใƒญใ‚ปใ‚นใŒใƒชใƒƒใ‚นใƒณใ—ใฆใ„ใ‚‹ๅฏ่ƒฝๆ€งใ‚‚ใ‚ใ‚Šใพใ™ใŒใ€IPใ‚ขใƒ‰ใƒฌใ‚นใจใƒใƒผใƒˆใฎ็ต„ใฟๅˆใ‚ใ›ใ”ใจใซ1ใคใ ใ‘ใงใ™ใ€‚ + +TLS๏ผˆHTTPS๏ผ‰ใฏใƒ‡ใƒ•ใ‚ฉใƒซใƒˆใง`443`ใจใ„ใ†็‰นๅฎšใฎใƒใƒผใƒˆใ‚’ไฝฟ็”จใ™ใ‚‹ใ€‚ใคใพใ‚Šใ€ใ“ใ‚ŒใŒๅฟ…่ฆใชใƒใƒผใƒˆใงใ™ใ€‚ + +ใ“ใฎใƒใƒผใƒˆใ‚’ใƒชใƒƒใ‚นใƒณใงใใ‚‹ใฎใฏ1ใคใฎใƒ—ใƒญใ‚ปใ‚นใ ใ‘ใชใฎใงใ€ใ“ใ‚Œใ‚’ๅฎŸ่กŒใ™ใ‚‹ใƒ—ใƒญใ‚ปใ‚นใฏ**TLS Termination Proxy**ใจใชใ‚Šใพใ™ใ€‚ + +TLS Termination Proxyใฏใ€1ใคไปฅไธŠใฎ**TLS่จผๆ˜Žๆ›ธ**๏ผˆHTTPS่จผๆ˜Žๆ›ธ๏ผ‰ใซใ‚ขใ‚ฏใ‚ปใ‚นใงใใพใ™ใ€‚ + +ๅ‰่ฟฐใ—ใŸ**SNIๆ‹กๅผตๆฉŸ่ƒฝ**ใ‚’ไฝฟ็”จใ—ใฆใ€TLS Termination Proxy ใฏใ€ๅˆฉ็”จๅฏ่ƒฝใชTLS (HTTPS)่จผๆ˜Žๆ›ธใฎใฉใ‚Œใ‚’ๆŽฅ็ถšๅ…ˆใจใ—ใฆไฝฟ็”จใ™ในใใ‹ใ‚’ใƒใ‚งใƒƒใ‚ฏใ—ใ€ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใŒๆœŸๅพ…ใ™ใ‚‹ใƒ‰ใƒกใ‚คใƒณใซไธ€่‡ดใ™ใ‚‹ใ‚‚ใฎใ‚’ไฝฟ็”จใ—ใพใ™ใ€‚ + +ไปŠๅ›žใฏใ€`someapp.example.com`ใฎ่จผๆ˜Žๆ›ธใ‚’ไฝฟใ†ใ“ใจใซใชใ‚Šใพใ™ใ€‚ + + + +ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใฏใ€ใใฎTLS่จผๆ˜Žๆ›ธใ‚’็”Ÿๆˆใ—ใŸใ‚จใƒณใƒ†ใ‚ฃใƒ†ใ‚ฃ๏ผˆใ“ใฎๅ ดๅˆใฏLet's Encryptใงใ™ใŒใ€ใ“ใ‚Œใซใคใ„ใฆใฏๅพŒ่ฟฐใ—ใพใ™๏ผ‰ใ‚’ใ™ใงใซ**ไฟก้ ผ**ใ—ใฆใ„ใ‚‹ใŸใ‚ใ€ใใฎ่จผๆ˜Žๆ›ธใŒๆœ‰ๅŠนใงใ‚ใ‚‹ใ“ใจใ‚’**ๆคœ่จผ**ใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + +ๆฌกใซ่จผๆ˜Žๆ›ธใ‚’ไฝฟ็”จใ—ใฆใ€ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใจTLS Termination Proxy ใฏใ€ **TCP้€šไฟก**ใฎๆฎ‹ใ‚Šใ‚’**ใฉใฎใ‚ˆใ†ใซๆš—ๅทๅŒ–ใ™ใ‚‹ใ‹ใ‚’ๆฑบๅฎš**ใ—ใพใ™ใ€‚ใ“ใ‚Œใง**TLSใƒใƒณใƒ‰ใ‚ทใ‚งใ‚คใ‚ฏ**ใฎ้ƒจๅˆ†ใŒๅฎŒไบ†ใ—ใพใ™ใ€‚ + +ใ“ใฎๅพŒใ€ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใจใ‚ตใƒผใƒใƒผใฏ**ๆš—ๅทๅŒ–ใ•ใ‚ŒใŸTCPๆŽฅ็ถš**ใ‚’ๆŒใกใพใ™ใ€‚ใใ—ใฆใ€ใใฎๆŽฅ็ถšใ‚’ไฝฟใฃใฆๅฎŸ้š›ใฎ**HTTP้€šไฟก**ใ‚’้–‹ๅง‹ใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + +ใ“ใ‚ŒใŒ**HTTPS**ใงใ‚ใ‚Šใ€็ด”็ฒ‹ใช๏ผˆๆš—ๅทๅŒ–ใ•ใ‚Œใฆใ„ใชใ„๏ผ‰TCPๆŽฅ็ถšใงใฏใชใใ€**ใ‚ปใ‚ญใƒฅใ‚ขใชTLSๆŽฅ็ถš**ใฎไธญใซ**HTTP**ใŒใ‚ใ‚‹ใ ใ‘ใงใ™ใ€‚ + +!!! tip + ้€šไฟกใฎๆš—ๅทๅŒ–ใฏใ€HTTPใƒฌใƒ™ใƒซใงใฏใชใใ€**TCPใƒฌใƒ™ใƒซ**ใง่กŒใ‚ใ‚Œใ‚‹ใ“ใจใซๆณจๆ„ใ—ใฆใใ ใ•ใ„ใ€‚ + +### HTTPS ใƒชใ‚ฏใ‚จใ‚นใƒˆ + +ใ“ใ‚Œใงใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใจใ‚ตใƒผใƒใƒผ๏ผˆๅ…ทไฝ“็š„ใซใฏใƒ–ใƒฉใ‚ฆใ‚ถใจTLS Termination Proxy๏ผ‰ใฏ**ๆš—ๅทๅŒ–ใ•ใ‚ŒใŸTCPๆŽฅ็ถš**ใ‚’ๆŒใคใ“ใจใซใชใ‚Šใ€**HTTP้€šไฟก**ใ‚’้–‹ๅง‹ใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + +ใใ“ใงใ€ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆใฏ**HTTPSใƒชใ‚ฏใ‚จใ‚นใƒˆ**ใ‚’้€ไฟกใ—ใพใ™ใ€‚ใ“ใ‚Œใฏใ€ๆš—ๅทๅŒ–ใ•ใ‚ŒใŸTLSใ‚ณใƒใ‚ฏใ‚ทใƒงใƒณใ‚’ไป‹ใ—ใŸๅ˜ใชใ‚‹HTTPใƒชใ‚ฏใ‚จใ‚นใƒˆใงใ™ใ€‚ + + + +### ใƒชใ‚ฏใ‚จใ‚นใƒˆใฎๅพฉๅทๅŒ– + +TLS Termination Proxy ใฏใ€ๅˆๆ„ใŒๅ–ใ‚Œใฆใ„ใ‚‹ๆš—ๅทๅŒ–ใ‚’ไฝฟ็”จใ—ใฆใ€**ใƒชใ‚ฏใ‚จใ‚นใƒˆใ‚’ๅพฉๅทๅŒ–**ใ—ใ€**ใƒ—ใƒฌใƒผใƒณ (ๅพฉๅทๅŒ–ใ•ใ‚ŒใŸ) HTTP ใƒชใ‚ฏใ‚จใ‚นใƒˆ** ใ‚’ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚’ๅฎŸ่กŒใ—ใฆใ„ใ‚‹ใƒ—ใƒญใ‚ปใ‚น (ไพ‹ใˆใฐใ€FastAPI ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚’ๅฎŸ่กŒใ—ใฆใ„ใ‚‹ Uvicorn ใ‚’ๆŒใคใƒ—ใƒญใ‚ปใ‚น) ใซ้€ไฟกใ—ใพใ™ใ€‚ + + + +### HTTP ใƒฌใ‚นใƒใƒณใ‚น + +ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฏใƒชใ‚ฏใ‚จใ‚นใƒˆใ‚’ๅ‡ฆ็†ใ—ใ€**ใƒ—ใƒฌใƒผใƒณ(ๆš—ๅทๅŒ–ใ•ใ‚Œใฆใ„ใชใ„)HTTPใƒฌใ‚นใƒใƒณใ‚น** ใ‚’TLS Termination Proxyใซ้€ไฟกใ—ใพใ™ใ€‚ + + + +### HTTPS ใƒฌใ‚นใƒใƒณใ‚น + +TLS Termination Proxyใฏๆฌกใซใ€ไบ‹ๅ‰ใซๅˆๆ„ใŒๅ–ใ‚Œใฆใ„ใ‚‹ๆš—ๅท(`someapp.example.com`ใฎ่จผๆ˜Žๆ›ธใ‹ใ‚‰ๅง‹ใพใ‚‹)ใ‚’ไฝฟใฃใฆ**ใƒฌใ‚นใƒใƒณใ‚นใ‚’ๆš—ๅทๅŒ–ใ—**ใ€ใƒ–ใƒฉใ‚ฆใ‚ถใซ้€ใ‚Š่ฟ”ใ™ใ€‚ + +ใใฎๅพŒใƒ–ใƒฉใ‚ฆใ‚ถใงใฏใ€ใƒฌใ‚นใƒใƒณใ‚นใŒๆœ‰ๅŠนใงๆญฃใ—ใ„ๆš—ๅทใ‚ญใƒผใงๆš—ๅทๅŒ–ใ•ใ‚Œใฆใ„ใ‚‹ใ“ใจใชใฉใ‚’ๆคœ่จผใ—ใพใ™ใ€‚ใใ—ใฆใ€ใƒ–ใƒฉใ‚ฆใ‚ถใฏใƒฌใ‚นใƒใƒณใ‚นใ‚’**ๅพฉๅทๅŒ–**ใ—ใฆๅ‡ฆ็†ใ—ใพใ™ใ€‚ + + + +ใ‚ฏใƒฉใ‚คใ‚ขใƒณใƒˆ๏ผˆใƒ–ใƒฉใ‚ฆใ‚ถ๏ผ‰ใฏใ€ใƒฌใ‚นใƒใƒณใ‚นใŒๆญฃใ—ใ„ใ‚ตใƒผใƒใƒผใ‹ใ‚‰ๆฅใŸใ“ใจใ‚’็Ÿฅใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ ใชใœใชใ‚‰ใ€ใใฎใ‚ตใƒผใƒใƒผใฏใ€ไปฅๅ‰ใซ**HTTPS่จผๆ˜Žๆ›ธ**ใ‚’ไฝฟใฃใฆๅˆๆ„ใ—ใŸๆš—ๅทใ‚’ไฝฟใฃใฆใ„ใ‚‹ใ‹ใ‚‰ใงใ™ใ€‚ + +### ่ค‡ๆ•ฐใฎใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณ + +ๅŒใ˜ใ‚ตใƒผใƒใƒผ๏ผˆใพใŸใฏ่ค‡ๆ•ฐใฎใ‚ตใƒผใƒใƒผ๏ผ‰ใซใ€ไพ‹ใˆใฐไป–ใฎAPIใƒ—ใƒญใ‚ฐใƒฉใƒ ใ‚„ใƒ‡ใƒผใ‚ฟใƒ™ใƒผใ‚นใชใฉใ€**่ค‡ๆ•ฐใฎใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณ**ใŒๅญ˜ๅœจใ™ใ‚‹ๅฏ่ƒฝๆ€งใŒใ‚ใ‚Šใพใ™ใ€‚ + +็‰นๅฎšใฎIPใจใƒใƒผใƒˆ๏ผˆใ“ใฎไพ‹ใงใฏTLS Termination Proxy๏ผ‰ใ‚’ๆ‰ฑใ†ใ“ใจใŒใงใใ‚‹ใฎใฏ1ใคใฎใƒ—ใƒญใ‚ปใ‚นใ ใ‘ใงใ™ใŒใ€ไป–ใฎใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณ/ใƒ—ใƒญใ‚ปใ‚นใ‚‚ใ€ๅŒใ˜**ใƒ‘ใƒ–ใƒชใƒƒใ‚ฏIPใจใƒใƒผใƒˆ**ใฎ็ต„ใฟๅˆใ‚ใ›ใ‚’ไฝฟ็”จใ—ใ‚ˆใ†ใจใ—ใชใ„้™ใ‚Šใ€ใ‚ตใƒผใƒใƒผไธŠใงๅฎŸ่กŒใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + + + +ใใ†ใ™ใ‚Œใฐใ€TLS Termination Proxy ใฏใ€**่ค‡ๆ•ฐใฎใƒ‰ใƒกใ‚คใƒณ**ใ‚„่ค‡ๆ•ฐใฎใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎHTTPSใจ่จผๆ˜Žๆ›ธใ‚’ๅ‡ฆ็†ใ—ใ€ใใ‚Œใžใ‚Œใฎใ‚ฑใƒผใ‚นใง้ฉๅˆ‡ใชใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใซใƒชใ‚ฏใ‚จใ‚นใƒˆใ‚’้€ไฟกใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + +### ่จผๆ˜Žๆ›ธใฎๆ›ดๆ–ฐ + +ๅฐ†ๆฅใฎใ‚ใ‚‹ๆ™‚็‚นใงใ€ๅ„่จผๆ˜Žๆ›ธใฏ๏ผˆๅ–ๅพ—ๅพŒ็ด„3ใƒถๆœˆใง๏ผ‰**ๅคฑๅŠน**ใ—ใพใ™ใ€‚ + +ใใฎๅพŒใ€Let's Encryptใจ้€šไฟกใ™ใ‚‹ๅˆฅใฎใƒ—ใƒญใ‚ฐใƒฉใƒ ๏ผˆๅˆฅใฎใƒ—ใƒญใ‚ฐใƒฉใƒ ใงใ‚ใ‚‹ๅ ดๅˆใ‚‚ใ‚ใ‚Œใฐใ€ๅŒใ˜TLS Termination Proxyใงใ‚ใ‚‹ๅ ดๅˆใ‚‚ใ‚ใ‚‹๏ผ‰ใซใ‚ˆใฃใฆใ€่จผๆ˜Žๆ›ธใ‚’ๆ›ดๆ–ฐใ—ใพใ™ใ€‚ + + + +**TLS่จผๆ˜Žๆ›ธ**ใฏใ€IPใ‚ขใƒ‰ใƒฌใ‚นใงใฏใชใใ€**ใƒ‰ใƒกใ‚คใƒณๅใซ้–ข้€ฃไป˜ใ‘ใ‚‰ใ‚Œใฆ**ใ„ใพใ™ใ€‚ + +ใ—ใŸใŒใฃใฆใ€่จผๆ˜Žๆ›ธใ‚’ๆ›ดๆ–ฐใ™ใ‚‹ใŸใ‚ใซใ€ๆ›ดๆ–ฐใƒ—ใƒญใ‚ฐใƒฉใƒ ใฏใ€่ช่จผๅฑ€๏ผˆLet's Encrypt๏ผ‰ใซๅฏพใ—ใฆใ€**ใใฎใƒ‰ใƒกใ‚คใƒณใŒๆœฌๅฝ“ใซใ€Œๆ‰€ๆœ‰ใ€ใ—ใ€็ฎก็†ใ—ใฆใ„ใ‚‹**ใ“ใจใ‚’**่จผๆ˜Ž**ใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ + +ใใฎใŸใ‚ใซใ€ใพใŸใ•ใพใ–ใพใชใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎใƒ‹ใƒผใ‚บใซๅฏพๅฟœใ™ใ‚‹ใŸใ‚ใซใ€ใ„ใใคใ‹ใฎๆ–นๆณ•ใŒใ‚ใ‚Šใพใ™ใ€‚ใ‚ˆใไฝฟใ‚ใ‚Œใ‚‹ๆ–นๆณ•ใจใ—ใฆใฏ: + +* **ใ„ใใคใ‹ใฎDNSใƒฌใ‚ณใƒผใƒ‰ใ‚’ไฟฎๆญฃใ—ใพใ™ใ€‚** + * ใ“ใ‚Œใ‚’ใ™ใ‚‹ใŸใ‚ใซใฏใ€ๆ›ดๆ–ฐใƒ—ใƒญใ‚ฐใƒฉใƒ ใฏDNSใƒ—ใƒญใƒใ‚คใƒ€ใƒผใฎAPIใ‚’ใ‚ตใƒใƒผใƒˆใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ใ—ใŸใŒใฃใฆใ€ไฝฟ็”จใ—ใฆใ„ใ‚‹DNSใƒ—ใƒญใƒใ‚คใƒ€ใƒผใซใ‚ˆใฃใฆใฏใ€ใ“ใฎใ‚ชใƒ—ใ‚ทใƒงใƒณใŒไฝฟใˆใ‚‹ๅ ดๅˆใ‚‚ใ‚ใ‚Œใฐใ€ไฝฟใˆใชใ„ๅ ดๅˆใ‚‚ใ‚ใ‚Šใพใ™ใ€‚ +* ใƒ‰ใƒกใ‚คใƒณใซ้–ข้€ฃไป˜ใ‘ใ‚‰ใ‚ŒใŸใƒ‘ใƒ–ใƒชใƒƒใ‚ฏIPใ‚ขใƒ‰ใƒฌใ‚นไธŠใงใ€๏ผˆๅฐ‘ใชใใจใ‚‚่จผๆ˜Žๆ›ธๅ–ๅพ—ใƒ—ใƒญใ‚ปใ‚นไธญใฏ๏ผ‰**ใ‚ตใƒผใƒใƒผ**ใจใ—ใฆๅฎŸ่กŒใ—ใพใ™ใ€‚ + * ไธŠใง่ฟฐในใŸใ‚ˆใ†ใซใ€็‰นๅฎšใฎIPใจใƒใƒผใƒˆใงใƒชใƒƒใ‚นใƒณใงใใ‚‹ใƒ—ใƒญใ‚ปใ‚นใฏ1ใคใ ใ‘ใงใ™ใ€‚ + * ใ“ใ‚Œใฏใ€ๅŒใ˜TLS Termination ProxyใŒ่จผๆ˜Žๆ›ธใฎๆ›ดๆ–ฐๅ‡ฆ็†ใ‚‚่กŒใ†ๅ ดๅˆใซ้žๅธธใซไพฟๅˆฉใช็†็”ฑใฎ1ใคใงใ™ใ€‚ + * ใใ†ใงใชใ‘ใ‚Œใฐใ€TLS Termination Proxyใ‚’ไธ€ๆ™‚็š„ใซๅœๆญขใ—ใ€่จผๆ˜Žๆ›ธใ‚’ๅ–ๅพ—ใ™ใ‚‹ใŸใ‚ใซๆ›ดๆ–ฐใƒ—ใƒญใ‚ฐใƒฉใƒ ใ‚’่ตทๅ‹•ใ—ใ€TLS Termination Proxyใง่จผๆ˜Žๆ›ธใ‚’่จญๅฎšใ—ใ€TLS Termination Proxyใ‚’ๅ†่ตทๅ‹•ใ—ใชใ‘ใ‚Œใฐใชใ‚‰ใชใ„ใ‹ใ‚‚ใ—ใ‚Œใพใ›ใ‚“ใ€‚TLS Termination ProxyใŒๅœๆญขใ—ใฆใ„ใ‚‹้–“ใฏใ‚ขใƒ—ใƒชใŒๅˆฉ็”จใงใใชใใชใ‚‹ใŸใ‚ใ€ใ“ใ‚Œใฏ็†ๆƒณ็š„ใงใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ + + +ใ‚ขใƒ—ใƒชใ‚’ๆไพ›ใ—ใชใŒใ‚‰ใ“ใฎใ‚ˆใ†ใชๆ›ดๆ–ฐๅ‡ฆ็†ใ‚’่กŒใ†ใ“ใจใฏใ€ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒปใ‚ตใƒผใƒใƒผ๏ผˆUvicornใชใฉ๏ผ‰ใงTLS่จผๆ˜Žๆ›ธใ‚’็›ดๆŽฅไฝฟ็”จใ™ใ‚‹ใฎใงใฏใชใใ€TLS Termination Proxyใ‚’ไฝฟ็”จใ—ใฆ**HTTPSใ‚’ๅ‡ฆ็†ใ™ใ‚‹ๅˆฅใฎใ‚ทใ‚นใƒ†ใƒ **ใ‚’็”จๆ„ใ—ใŸใใชใ‚‹ไธปใช็†็”ฑใฎ1ใคใงใ™ใ€‚ + +## ใพใจใ‚ + +**HTTPS**ใ‚’ๆŒใคใ“ใจใฏ้žๅธธใซ้‡่ฆใงใ‚ใ‚Šใ€ใปใจใ‚“ใฉใฎๅ ดๅˆใ€ใ‹ใชใ‚Š**ใ‚ฏใƒชใƒ†ใ‚ฃใ‚ซใƒซ**ใงใ™ใ€‚้–‹็™บ่€…ใจใ—ใฆ HTTPS ใซ้–ขใ‚ใ‚‹ๅŠดๅŠ›ใฎใปใจใ‚“ใฉใฏใ€ใ“ใ‚Œใ‚‰ใฎ**ๆฆ‚ๅฟตใจใใฎไป•็ต„ใฟใ‚’็†่งฃใ™ใ‚‹**ใ“ใจใงใ™ใ€‚ + +ใ—ใ‹ใ—ใ€ใฒใจใŸใณ**้–‹็™บ่€…ๅ‘ใ‘HTTPS**ใฎๅŸบๆœฌ็š„ใชๆƒ…ๅ ฑใ‚’็Ÿฅใ‚Œใฐใ€็ฐกๅ˜ใชๆ–นๆณ•ใงใ™ในใฆใ‚’็ฎก็†ใ™ใ‚‹ใŸใ‚ใซใ€ใ•ใพใ–ใพใชใƒ„ใƒผใƒซใ‚’็ต„ใฟๅˆใ‚ใ›ใฆ่จญๅฎšใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚ + +ๆฌกใฎ็ซ ใงใฏใ€**FastAPI** ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใฎใŸใ‚ใซ **HTTPS** ใ‚’ใ‚ปใƒƒใƒˆใ‚ขใƒƒใƒ—ใ™ใ‚‹ๆ–นๆณ•ใซใคใ„ใฆใ€ใ„ใใคใ‹ใฎๅ…ทไฝ“ไพ‹ใ‚’็ดนไป‹ใ—ใพใ™ใ€‚๐Ÿ”’ diff --git a/docs/ja/docs/external-links.md b/docs/ja/docs/external-links.md index 6703f5fc2..aca5d5b34 100644 --- a/docs/ja/docs/external-links.md +++ b/docs/ja/docs/external-links.md @@ -9,70 +9,21 @@ !!! tip "่ฑ†็Ÿฅ่ญ˜" ใ“ใ“ใซใพใ ่ผ‰ใฃใฆใ„ใชใ„**FastAPI**ใซ้–ข้€ฃใ™ใ‚‹่จ˜ไบ‹ใ€ใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆใ€ใƒ„ใƒผใƒซใชใฉใŒใ‚ใ‚‹ๅ ดๅˆใฏใ€ ใƒ—ใƒซใƒชใ‚ฏใ‚จใ‚นใƒˆใ—ใฆไธ‹ใ•ใ„ใ€‚ -## ่จ˜ไบ‹ +{% for section_name, section_content in external_links.items() %} -### ่‹ฑ่ชž +## {{ section_name }} -{% if external_links %} -{% for article in external_links.articles.english %} +{% for lang_name, lang_content in section_content.items() %} + +### {{ lang_name }} + +{% for item in lang_content %} + +* {{ item.title }} by {{ item.author }}. -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### ๆ—ฅๆœฌ่ชž - -{% if external_links %} -{% for article in external_links.articles.japanese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### ใƒ™ใƒˆใƒŠใƒ ่ชž - -{% if external_links %} -{% for article in external_links.articles.vietnamese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### ใƒญใ‚ทใ‚ข่ชž - -{% if external_links %} -{% for article in external_links.articles.russian %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -### ใƒ‰ใ‚คใƒ„่ชž - -{% if external_links %} -{% for article in external_links.articles.german %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## ใƒใƒƒใƒ‰ใ‚ญใƒฃใ‚นใƒˆ - -{% if external_links %} -{% for article in external_links.podcasts.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## ใƒˆใƒผใ‚ฏ - -{% if external_links %} -{% for article in external_links.talks.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} ## ใƒ—ใƒญใ‚ธใ‚งใ‚ฏใƒˆ diff --git a/docs/ja/docs/features.md b/docs/ja/docs/features.md index a40b48cf0..853364f11 100644 --- a/docs/ja/docs/features.md +++ b/docs/ja/docs/features.md @@ -24,7 +24,7 @@ ### ็พไปฃ็š„ใชPython -FastAPIใฎๆฉŸ่ƒฝใฏใ™ในใฆใ€ๆจ™ๆบ–ใฎPython 3.6ๅž‹ๅฎฃ่จ€ใซๅŸบใฅใ„ใฆใ„ใพใ™๏ผˆPydanticใฎๅŠŸ็ธพ๏ผ‰ใ€‚ๆ–ฐใ—ใ„ๆง‹ๆ–‡ใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ใŸใ ใฎ็พไปฃ็š„ใชๆจ™ๆบ–ใฎPythonใงใ™ใ€‚ +FastAPIใฎๆฉŸ่ƒฝใฏใ™ในใฆใ€ๆจ™ๆบ–ใฎPython 3.8ๅž‹ๅฎฃ่จ€ใซๅŸบใฅใ„ใฆใ„ใพใ™๏ผˆPydanticใฎๅŠŸ็ธพ๏ผ‰ใ€‚ๆ–ฐใ—ใ„ๆง‹ๆ–‡ใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚ใŸใ ใฎ็พไปฃ็š„ใชๆจ™ๆบ–ใฎPythonใงใ™ใ€‚ ๏ผˆFastAPIใ‚’ไฝฟ็”จใ—ใชใ„ๅ ดๅˆใงใ‚‚๏ผ‰Pythonใฎๅž‹ใฎไฝฟ็”จๆ–นๆณ•ใซใคใ„ใฆ็ฐกๅ˜ใชๅพฉ็ฟ’ใŒๅฟ…่ฆใชๅ ดๅˆใฏใ€็Ÿญใ„ใƒใƒฅใƒผใƒˆใƒชใ‚ขใƒซ๏ผˆ[Python Types](python-types.md){.internal-link target=_blank}๏ผ‰ใ‚’ๅ‚็…งใ—ใฆใใ ใ•ใ„ใ€‚ diff --git a/docs/ja/docs/help-fastapi.md b/docs/ja/docs/help-fastapi.md index 166acb586..e753b7ce3 100644 --- a/docs/ja/docs/help-fastapi.md +++ b/docs/ja/docs/help-fastapi.md @@ -82,20 +82,6 @@ GitHubใƒฌใƒใ‚ธใƒˆใƒชใงhttps://gitter.im/tiangolo/fastapi. - -ใใ“ใงใ€ไป–ใฎไบบใจๆ‰‹ๆ—ฉใไผš่ฉฑใ—ใŸใ‚Šใ€ๆ‰‹ๅŠฉใ‘ใ‚„ใ‚ขใ‚คใƒ‡ใ‚ขใฎๅ…ฑๆœ‰ใชใฉใŒใงใใพใ™ใ€‚ - -ใ—ใ‹ใ—ใ€ใ€Œ่‡ช็”ฑใชไผš่ฉฑใ€ใŒ่จฑๅฎนใ•ใ‚Œใฆใ„ใ‚‹ใฎใงไธ€่ˆฌ็š„ใ™ใŽใฆๅ›ž็ญ”ใŒ้›ฃใ—ใ„่ณชๅ•ใ‚‚ใ—ใ‚„ใ™ใใชใ‚Šใพใ™ใ€‚ใใฎใ›ใ„ใงๅ›ž็ญ”ใ‚’ๅพ—ใ‚‰ใ‚Œใชใ„ใ‹ใ‚‚ใ—ใ‚Œใพใ›ใ‚“ใ€‚ - -GitHub issuesใงใฏ่‰ฏใ„ๅ›ž็ญ”ใ‚’ๅพ—ใ‚„ใ™ใ„่ณชๅ•ใŒใงใใ‚‹ใ‚ˆใ†ใซใ€ใ‚‚ใ—ใใฏใ€่ณชๅ•ใ™ใ‚‹ๅ‰ใซ่‡ช่บซใง่งฃๆฑบใงใใ‚‹ใ‚ˆใ†ใซใƒ†ใƒณใƒ—ใƒฌใƒผใƒˆใŒใ‚ฌใ‚คใƒ‰ใ—ใฆใใ‚Œใพใ™ใ€‚ใใ—ใฆใ€GitHubใงใฏใŸใจใˆๆ™‚้–“ใŒใ‹ใ‹ใฃใฆใ‚‚ๅ…จใฆใซ็ญ”ใˆใฆใ„ใ‚‹ใ‹็ขบ่ชใงใใพใ™ใ€‚ๅ€‹ไบบ็š„ใซใฏGitterใƒใƒฃใƒƒใƒˆใงใฏๅŒใ˜ใ“ใจใฏใงใใชใ„ใงใ™ใ€‚๐Ÿ˜… - -Gitterใงใฎไผš่ฉฑใฏGitHubใปใฉ็ฐกๅ˜ใซๆคœ็ดขใงใใชใ„ใฎใงใ€่ณชๅ•ใจๅ›ž็ญ”ใŒไผš่ฉฑใฎไธญใซๅŸ‹ใ‚‚ใ‚Œใฆใ—ใพใ„ใพใ™ใ€‚ - -ไธ€ๆ–นใ€ใƒใƒฃใƒƒใƒˆใซใฏ1000ไบบไปฅไธŠใ„ใ‚‹ใฎใงใ€ใ„ใคใงใ‚‚่ฉฑใ—็›ธๆ‰‹ใŒ่ฆ‹ใคใ‹ใ‚‹ๅฏ่ƒฝๆ€งใŒ้ซ˜ใ„ใงใ™ใ€‚๐Ÿ˜„ - ## ้–‹็™บ่€…ใฎใ‚นใƒใƒณใ‚ตใƒผใซใชใ‚‹ GitHub sponsorsใ‚’้€šใ—ใฆ้–‹็™บ่€…ใ‚’็ตŒๆธˆ็š„ใซใ‚ตใƒใƒผใƒˆใงใใพใ™ใ€‚ diff --git a/docs/ja/docs/advanced/conditional-openapi.md b/docs/ja/docs/how-to/conditional-openapi.md similarity index 100% rename from docs/ja/docs/advanced/conditional-openapi.md rename to docs/ja/docs/how-to/conditional-openapi.md diff --git a/docs/ja/docs/index.md b/docs/ja/docs/index.md index a9c381a23..f340fdb87 100644 --- a/docs/ja/docs/index.md +++ b/docs/ja/docs/index.md @@ -107,7 +107,7 @@ FastAPI ใฏใ€Pythonใฎๆจ™ๆบ–ใงใ‚ใ‚‹ๅž‹ใƒ’ใƒณใƒˆใซๅŸบใฅใ„ใฆPython 3.6 ไปฅ ## ๅฟ…่ฆๆกไปถ -Python 3.7+ +Python 3.8+ FastAPI ใฏๅทจไบบใฎ่‚ฉใฎไธŠใซ็ซ‹ใฃใฆใ„ใพใ™ใ€‚ diff --git a/docs/ko/docs/deployment/cloud.md b/docs/ko/docs/deployment/cloud.md new file mode 100644 index 000000000..f2b965a91 --- /dev/null +++ b/docs/ko/docs/deployment/cloud.md @@ -0,0 +1,17 @@ +# FastAPI๋ฅผ ํด๋ผ์šฐ๋“œ ์ œ๊ณต์—…์ฒด์—์„œ ๋ฐฐํฌํ•˜๊ธฐ + +์‚ฌ์‹ค์ƒ ๊ฑฐ์˜ **๋ชจ๋“  ํด๋ผ์šฐ๋“œ ์ œ๊ณต์—…์ฒด**๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ถ„์˜ FastAPI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ, ์ฃผ์š” ํด๋ผ์šฐ๋“œ ์ œ๊ณต์—…์ฒด์—์„œ๋Š” FastAPI๋ฅผ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ€์ด๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. + +## ํด๋ผ์šฐ๋“œ ์ œ๊ณต์—…์ฒด - ํ›„์›์ž๋“ค + +๋ช‡๋ช‡ ํด๋ผ์šฐ๋“œ ์ œ๊ณต์—…์ฒด๋“ค์€ [**FastAPI๋ฅผ ํ›„์›ํ•˜๋ฉฐ**](../help-fastapi.md#sponsor-the-author){.internal-link target=_blank} โœจ, ์ด๋ฅผ ํ†ตํ•ด FastAPI์™€ FastAPI **์ƒํƒœ๊ณ„**๊ฐ€ ์ง€์†์ ์ด๊ณ  ๊ฑด์ „ํ•œ **๋ฐœ์ „**์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +์ด๋Š” FastAPI์™€ **์ปค๋ฎค๋‹ˆํ‹ฐ** (์—ฌ๋Ÿฌ๋ถ„)์— ๋Œ€ํ•œ ์ง„์ •ํ•œ ํ—Œ์‹ ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ์—ฌ๋Ÿฌ๋ถ„์—๊ฒŒ **์ข‹์€ ์„œ๋น„์Šค**๋ฅผ ์ œ๊ณตํ•  ๋ฟ ๋งŒ์ด ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ๋ถ„์ด **ํ›Œ๋ฅญํ•˜๊ณ  ๊ฑด๊ฐ•ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์ธ** FastAPI ๋ฅผ ์‚ฌ์šฉํ•˜๊ธธ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๐Ÿ™‡ + +์•„๋ž˜์™€ ๊ฐ™์€ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๊ณ  ๊ฐ ์„œ๋น„์Šค์˜ ๊ฐ€์ด๋“œ๋ฅผ ๋”ฐ๋ฅผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค: + +* Platform.sh +* Porter +* Deta diff --git a/docs/ko/docs/index.md b/docs/ko/docs/index.md index a6991a9b8..7ce938106 100644 --- a/docs/ko/docs/index.md +++ b/docs/ko/docs/index.md @@ -107,7 +107,7 @@ FastAPI๋Š” ํ˜„๋Œ€์ ์ด๊ณ , ๋น ๋ฅด๋ฉฐ(๊ณ ์„ฑ๋Šฅ), ํŒŒ์ด์ฌ ํ‘œ์ค€ ํƒ€์ž… ํžŒํŠธ ## ์š”๊ตฌ์‚ฌํ•ญ -Python 3.7+ +Python 3.8+ FastAPI๋Š” ๊ฑฐ์ธ๋“ค์˜ ์–ด๊นจ ์œ„์— ์„œ ์žˆ์Šต๋‹ˆ๋‹ค: diff --git a/docs/pl/docs/features.md b/docs/pl/docs/features.md index 49d362dd9..ed10af9bc 100644 --- a/docs/pl/docs/features.md +++ b/docs/pl/docs/features.md @@ -25,7 +25,7 @@ Interaktywna dokumentacja i webowe interfejsy do eksploracji API. Z racji tego, ### Nowoczesny Python -Wszystko opiera siฤ™ na standardowych deklaracjach typu **Python 3.6** (dziฤ™ki Pydantic). Brak nowej skล‚adni do uczenia. Po prostu standardowy, wspรณล‚czesny Python. +Wszystko opiera siฤ™ na standardowych deklaracjach typu **Python 3.8** (dziฤ™ki Pydantic). Brak nowej skล‚adni do uczenia. Po prostu standardowy, wspรณล‚czesny Python. Jeล›li potrzebujesz szybkiego przypomnienia jak uลผywaฤ‡ deklaracji typรณw w Pythonie (nawet jeล›li nie uลผywasz FastAPI), sprawdลบ krรณtki samouczek: [Python Types](python-types.md){.internal-link target=_blank}. diff --git a/docs/pl/docs/help-fastapi.md b/docs/pl/docs/help-fastapi.md new file mode 100644 index 000000000..3d02a8741 --- /dev/null +++ b/docs/pl/docs/help-fastapi.md @@ -0,0 +1,263 @@ +# Pomรณลผ FastAPI - Uzyskaj pomoc + +Czy podoba Ci siฤ™ **FastAPI**? + +Czy chciaล‚byล› pomรณc FastAPI, jego uลผytkownikom i autorowi? + +Moลผe napotkaล‚eล› na trudnoล›ci z **FastAPI** i potrzebujesz pomocy? + +Istnieje kilka bardzo ล‚atwych sposobรณw, aby pomรณc (czasami wystarczy jedno lub dwa klikniฤ™cia). + +Istnieje rรณwnieลผ kilka sposobรณw uzyskania pomocy. + +## Zapisz siฤ™ do newslettera + +Moลผesz zapisaฤ‡ siฤ™ do rzadkiego [newslettera o **FastAPI i jego przyjacioล‚ach**](/newsletter/){.internal-link target=_blank}, aby byฤ‡ na bieลผฤ…co z: + +* Aktualnoล›ciami o FastAPI i przyjacioล‚ach ๐Ÿš€ +* Przewodnikami ๐Ÿ“ +* Funkcjami โœจ +* Przeล‚omowymi zmianami ๐Ÿšจ +* Poradami i sztuczkami โœ… + +## ลšledลบ FastAPI na Twitterze + +ลšledลบ @fastapi na **Twitterze** aby byฤ‡ na bieลผฤ…co z najnowszymi wiadomoล›ciami o **FastAPI**. ๐Ÿฆ + +## Dodaj gwiazdkฤ™ **FastAPI** na GitHubie + +Moลผesz "dodaฤ‡ gwiazdkฤ™" FastAPI na GitHubie (klikajฤ…c przycisk gwiazdki w prawym gรณrnym rogu): https://github.com/tiangolo/fastapi. โญ๏ธ + +Dodajฤ…c gwiazdkฤ™, inni uลผytkownicy bฤ™dฤ… mogli ล‚atwiej znaleลบฤ‡ projekt i zobaczyฤ‡, ลผe byล‚ juลผ przydatny dla innych. + +## Obserwuj repozytorium GitHub w poszukiwaniu nowych wydaล„ + +Moลผesz "obserwowaฤ‡" FastAPI na GitHubie (klikajฤ…c przycisk "obserwuj" w prawym gรณrnym rogu): https://github.com/tiangolo/fastapi. ๐Ÿ‘€ + +Wybierz opcjฤ™ "Tylko wydania". + +Dziฤ™ki temu bฤ™dziesz otrzymywaฤ‡ powiadomienia (na swรณj adres e-mail) za kaลผdym razem, gdy pojawi siฤ™ nowe wydanie (nowa wersja) **FastAPI** z poprawkami bล‚ฤ™dรณw i nowymi funkcjami. + +## Skontaktuj siฤ™ z autorem + +Moลผesz skontaktowaฤ‡ siฤ™ ze mnฤ… (Sebastiรกn Ramรญrez / `tiangolo`), autorem. + +Moลผesz: + +* ลšledziฤ‡ mnie na **GitHubie**. + * Zobacz inne projekty open source, ktรณre stworzyล‚em, a mogฤ… byฤ‡ dla Ciebie pomocne. + * ลšledลบ mnie, aby dostaฤ‡ powiadomienie, gdy utworzฤ™ nowy projekt open source. +* ลšledziฤ‡ mnie na **Twitterze** lub na Mastodonie. + * Napisz mi, w jaki sposรณb korzystasz z FastAPI (uwielbiam o tym czytaฤ‡). + * Dowiedz siฤ™, gdy ogล‚oszฤ™ coล› nowego lub wypuszczฤ™ nowe narzฤ™dzia. + * Moลผesz takลผe ล›ledziฤ‡ @fastapi na Twitterze (to oddzielne konto). +* Nawiฤ…ลผ ze mnฤ… kontakt na **Linkedinie**. + * Dowiedz siฤ™, gdy ogล‚oszฤ™ coล› nowego lub wypuszczฤ™ nowe narzฤ™dzia (chociaลผ czฤ™ล›ciej korzystam z Twittera ๐Ÿคทโ€โ™‚). +* Czytaj moje posty (lub ล›ledลบ mnie) na **Dev.to** lub na **Medium**. + * Czytaj o innych pomysล‚ach, artykuล‚ach i dowiedz siฤ™ o narzฤ™dziach, ktรณre stworzyล‚em. + * ลšledลบ mnie, by wiedzieฤ‡ gdy opublikujฤ™ coล› nowego. + +## Napisz tweeta o **FastAPI** + +Napisz tweeta o **FastAPI** i powiedz czemu Ci siฤ™ podoba. ๐ŸŽ‰ + +Uwielbiam czytaฤ‡ w jaki sposรณb **FastAPI** jest uลผywane, co Ci siฤ™ w nim podobaล‚o, w jakim projekcie/firmie go uลผywasz itp. + +## Gล‚osuj na FastAPI + +* Gล‚osuj na **FastAPI** w Slant. +* Gล‚osuj na **FastAPI** w AlternativeTo. +* Powiedz, ลผe uลผywasz **FastAPI** na StackShare. + +## Pomagaj innym, odpowiadajฤ…c na ich pytania na GitHubie + +Moลผesz sprรณbowaฤ‡ pomรณc innym, odpowiadajฤ…c w: + +* Dyskusjach na GitHubie +* Problemach na GitHubie + +W wielu przypadkach moลผesz juลผ znaฤ‡ odpowiedลบ na te pytania. ๐Ÿค“ + +Jeล›li pomoลผesz wielu ludziom, moลผesz zostaฤ‡ oficjalnym [Ekspertem FastAPI](fastapi-people.md#experts){.internal-link target=_blank}. ๐ŸŽ‰ + +Pamiฤ™taj tylko o najwaลผniejszym: bฤ…dลบ ลผyczliwy. Ludzie przychodzฤ… sfrustrowani i w wielu przypadkach nie zadajฤ… pytaล„ w najlepszy sposรณb, ale mimo to postaraj siฤ™ byฤ‡ dla nich jak najbardziej ลผyczliwy. ๐Ÿค— + +Chciaล‚bym, by spoล‚ecznoล›ฤ‡ **FastAPI** byล‚a ลผyczliwa i przyjazna. Nie akceptuj przeล›ladowania ani braku szacunku wobec innych. Dbajmy o siebie nawzajem. + +--- + +Oto, jak pomรณc innym z pytaniami (w dyskusjach lub problemach): + +### Zrozum pytanie + +* Upewnij siฤ™, czy rozumiesz **cel** i przypadek uลผycia osoby pytajฤ…cej. + +* Nastฤ™pnie sprawdลบ, czy pytanie (wiฤ™kszoล›ฤ‡ to pytania) jest **jasne**. + +* W wielu przypadkach zadane pytanie dotyczy rozwiฤ…zania wymyล›lonego przez uลผytkownika, ale moลผe istnieฤ‡ **lepsze** rozwiฤ…zanie. Jeล›li dokล‚adnie zrozumiesz problem i przypadek uลผycia, byฤ‡ moลผe bฤ™dziesz mรณgล‚ zaproponowaฤ‡ lepsze **alternatywne rozwiฤ…zanie**. + +* Jeล›li nie rozumiesz pytania, poproล› o wiฤ™cej **szczegรณล‚รณw**. + +### Odtwรณrz problem + +W wiฤ™kszoล›ci przypadkรณw problem wynika z **autorskiego kodu** osoby pytajฤ…cej. + +Czฤ™sto pytajฤ…cy umieszczajฤ… tylko fragment kodu, niewystarczajฤ…cy do **odtworzenia problemu**. + +* Moลผesz poprosiฤ‡ ich o dostarczenie minimalnego, odtwarzalnego przykล‚adu, ktรณry moลผesz **skopiowaฤ‡ i wkleiฤ‡** i uruchomiฤ‡ lokalnie, aby zobaczyฤ‡ ten sam bล‚ฤ…d lub zachowanie, ktรณre widzฤ…, lub lepiej zrozumieฤ‡ ich przypadki uลผycia. + +* Jeล›li jesteล› wyjฤ…tkowo pomocny, moลผesz sprรณbowaฤ‡ **stworzyฤ‡ taki przykล‚ad** samodzielnie, opierajฤ…c siฤ™ tylko na opisie problemu. Miej na uwadze, ลผe moลผe to zajฤ…ฤ‡ duลผo czasu i lepiej moลผe byฤ‡ najpierw poprosiฤ‡ ich o wyjaล›nienie problemu. + +### Proponuj rozwiฤ…zania + +* Po zrozumieniu pytania moลผesz podaฤ‡ im moลผliwฤ… **odpowiedลบ**. + +* W wielu przypadkach lepiej zrozumieฤ‡ ich **podstawowy problem lub przypadek uลผycia**, poniewaลผ moลผe istnieฤ‡ lepszy sposรณb rozwiฤ…zania niลผ to, co prรณbujฤ… zrobiฤ‡. + +### Poproล› o zamkniฤ™cie + +Jeล›li odpowiedzฤ…, jest duลผa szansa, ลผe rozwiฤ…zaล‚eล› ich problem, gratulacje, **jesteล› bohaterem**! ๐Ÿฆธ + +* Jeล›li Twoja odpowiedลบ rozwiฤ…zaล‚a problem, moลผesz poprosiฤ‡ o: + + * W Dyskusjach na GitHubie: oznaczenie komentarza jako **odpowiedลบ**. + * W Problemach na GitHubie: **zamkniฤ™cie** problemu. + +## Obserwuj repozytorium na GitHubie + +Moลผesz "obserwowaฤ‡" FastAPI na GitHubie (klikajฤ…c przycisk "obserwuj" w prawym gรณrnym rogu): https://github.com/tiangolo/fastapi. ๐Ÿ‘€ + +Jeล›li wybierzesz "Obserwuj" zamiast "Tylko wydania", otrzymasz powiadomienia, gdy ktoล› utworzy nowy problem lub pytanie. Moลผesz rรณwnieลผ okreล›liฤ‡, ลผe chcesz byฤ‡ powiadamiany tylko o nowych problemach, dyskusjach, PR-ach itp. + +Nastฤ™pnie moลผesz sprรณbowaฤ‡ pomรณc rozwiฤ…zaฤ‡ te problemy. + +## Zadawaj pytania + +Moลผesz utworzyฤ‡ nowe pytanie w repozytorium na GitHubie, na przykล‚ad aby: + +* Zadaฤ‡ **pytanie** lub zapytaฤ‡ o **problem**. +* Zaproponowaฤ‡ nowฤ… **funkcjฤ™**. + +**Uwaga**: jeล›li to zrobisz, poproszฤ™ Ciฤ™ rรณwnieลผ o pomoc innym. ๐Ÿ˜‰ + +## Przeglฤ…daj Pull Requesty + +Moลผesz pomรณc mi w przeglฤ…daniu pull requestรณw autorstwa innych osรณb. + +Jak wczeล›niej wspomniaล‚em, postaraj siฤ™ byฤ‡ jak najbardziej ลผyczliwy. ๐Ÿค— + +--- + +Oto, co warto mieฤ‡ na uwadze podczas oceny pull requestu: + +### Zrozum problem + +* Najpierw upewnij siฤ™, ลผe **rozumiesz problem**, ktรณry prรณbuje rozwiฤ…zaฤ‡ pull request. Moลผe byฤ‡ osadzony w wiฤ™kszym kontekล›cie w GitHubowej dyskusji lub problemie. + +* Jest teลผ duลผa szansa, ลผe pull request nie jest konieczny, poniewaลผ problem moลผna rozwiฤ…zaฤ‡ w **inny sposรณb**. Wtedy moลผesz to zasugerowaฤ‡ lub o to zapytaฤ‡. + +### Nie martw siฤ™ stylem + +* Nie przejmuj siฤ™ zbytnio rzeczami takimi jak style wiadomoล›ci commitรณw, przy wcielaniu pull requesta ล‚ฤ…czฤ™ commity i modyfikujฤ™ opis sumarycznego commita rฤ™cznie. + +* Nie przejmuj siฤ™ rรณwnieลผ stylem kodu, automatyczne narzฤ™dzia w repozytorium sprawdzajฤ… to samodzielnie. + +A jeล›li istnieje jakaล› konkretna potrzeba dotyczฤ…ca stylu lub spรณjnoล›ci, sam poproszฤ™ o zmiany lub dodam commity z takimi zmianami. + +### Sprawdลบ kod + +* Przeczytaj kod, zastanรณw siฤ™ czy ma sens, **uruchom go lokalnie** i potwierdลบ czy faktycznie rozwiฤ…zuje problem. + +* Nastฤ™pnie dodaj **komentarz** z informacjฤ… o tym, ลผe sprawdziล‚eล› kod, dziฤ™ki temu bฤ™dฤ™ miaล‚ pewnoล›ฤ‡, ลผe faktycznie go sprawdziล‚eล›. + +!!! info + Niestety, nie mogฤ™ ล›lepo ufaฤ‡ PR-om, nawet jeล›li majฤ… kilka zatwierdzeล„. + + Kilka razy zdarzyล‚o siฤ™, ลผe PR-y miaล‚y 3, 5 lub wiฤ™cej zatwierdzeล„ (prawdopodobnie dlatego, ลผe opis obiecuje rozwiฤ…zanie waลผnego problemu), ale gdy sam sprawdziล‚em danego PR-a, okazaล‚ siฤ™ byฤ‡ zbugowany lub nie rozwiฤ…zywaล‚ problemu, ktรณry rzekomo miaล‚ rozwiฤ…zywaฤ‡. ๐Ÿ˜… + + Dlatego tak waลผne jest, abyล› faktycznie przeczytaล‚ i uruchomiล‚ kod oraz napisaล‚ w komentarzu, ลผe to zrobiล‚eล›. ๐Ÿค“ + +* Jeล›li PR moลผna uproล›ciฤ‡ w jakiล› sposรณb, moลผesz o to poprosiฤ‡, ale nie ma potrzeby byฤ‡ zbyt wybrednym, moลผe byฤ‡ wiele subiektywnych punktรณw widzenia (a ja teลผ bฤ™dฤ™ miaล‚ swรณj ๐Ÿ™ˆ), wiฤ™c lepiej ลผebyล› skupiล‚ siฤ™ na kluczowych rzeczach. + +### Testy + +* Pomรณลผ mi sprawdziฤ‡, czy PR ma **testy**. + +* Sprawdลบ, czy testy **nie przechodzฤ…** przed PR. ๐Ÿšจ + +* Nastฤ™pnie sprawdลบ, czy testy **przechodzฤ…** po PR. โœ… + +* Wiele PR-รณw nie ma testรณw, moลผesz **przypomnieฤ‡** im o dodaniu testรณw, a nawet **zaproponowaฤ‡** samemu jakieล› testy. To jedna z rzeczy, ktรณre pochล‚aniajฤ… najwiฤ™cej czasu i moลผesz w tym bardzo pomรณc. + +* Nastฤ™pnie skomentuj rรณwnieลผ to, czego sprรณbowaล‚eล›, wtedy bฤ™dฤ™ wiedziaล‚, ลผe to sprawdziล‚eล›. ๐Ÿค“ + +## Utwรณrz Pull Request + +Moลผesz [wnieล›ฤ‡ wkล‚ad](contributing.md){.internal-link target=_blank} do kodu ลบrรณdล‚owego za pomocฤ… Pull Requestu, na przykล‚ad: + +* Naprawiฤ‡ literรณwkฤ™, ktรณrฤ… znalazล‚eล› w dokumentacji. +* Podzieliฤ‡ siฤ™ artykuล‚em, filmem lub podcastem, ktรณry stworzyล‚eล› lub znalazล‚eล› na temat FastAPI, edytujฤ…c ten plik. + * Upewnij siฤ™, ลผe dodajesz swรณj link na poczฤ…tku odpowiedniej sekcji. +* Pomรณc w [tล‚umaczeniu dokumentacji](contributing.md#translations){.internal-link target=_blank} na Twรณj jฤ™zyk. + * Moลผesz rรณwnieลผ pomรณc w weryfikacji tล‚umaczeล„ stworzonych przez innych. +* Zaproponowaฤ‡ nowe sekcje dokumentacji. +* Naprawiฤ‡ istniejฤ…cy problem/bล‚ฤ…d. + * Upewnij siฤ™, ลผe dodajesz testy. +* Dodaฤ‡ nowฤ… funkcjฤ™. + * Upewnij siฤ™, ลผe dodajesz testy. + * Upewnij siฤ™, ลผe dodajesz dokumentacjฤ™, jeล›li jest to istotne. + +## Pomรณลผ w utrzymaniu FastAPI + +Pomรณลผ mi utrzymaฤ‡ **FastAPI**! ๐Ÿค“ + +Jest wiele pracy do zrobienia, a w wiฤ™kszoล›ci przypadkรณw **TY** moลผesz to zrobiฤ‡. + +Gล‚รณwne zadania, ktรณre moลผesz wykonaฤ‡ teraz to: + +* [Pomรณc innym z pytaniami na GitHubie](#help-others-with-questions-in-github){.internal-link target=_blank} (zobacz sekcjฤ™ powyลผej). +* [Oceniaฤ‡ Pull Requesty](#review-pull-requests){.internal-link target=_blank} (zobacz sekcjฤ™ powyลผej). + +Te dwie czynnoล›ci **zajmujฤ… najwiฤ™cej czasu**. To gล‚รณwna praca zwiฤ…zana z utrzymaniem FastAPI. + +Jeล›li moลผesz mi w tym pomรณc, **pomoลผesz mi utrzymaฤ‡ FastAPI** i zapewnisz ลผe bฤ™dzie **rozwijaฤ‡ siฤ™ szybciej i lepiej**. ๐Ÿš€ + +## Doล‚ฤ…cz do czatu + +Doล‚ฤ…cz do ๐Ÿ‘ฅ serwera czatu na Discordzie ๐Ÿ‘ฅ i spฤ™dzaj czas z innymi w spoล‚ecznoล›ci FastAPI. + +!!! wskazรณwka + Jeล›li masz pytania, zadaj je w Dyskusjach na GitHubie, jest duลผo wiฤ™ksza szansa, ลผe otrzymasz pomoc od [Ekspertรณw FastAPI](fastapi-people.md#experts){.internal-link target=_blank}. + + Uลผywaj czatu tylko do innych ogรณlnych rozmรณw. + +### Nie zadawaj pytaล„ na czacie + +Miej na uwadze, ลผe poniewaลผ czaty pozwalajฤ… na bardziej "swobodnฤ… rozmowฤ™", ล‚atwo jest zadawaฤ‡ pytania, ktรณre sฤ… zbyt ogรณlne i trudniejsze do odpowiedzi, wiฤ™c moลผesz nie otrzymaฤ‡ odpowiedzi. + +Na GitHubie szablon poprowadzi Ciฤ™ do napisania odpowiedniego pytania, dziฤ™ki czemu ล‚atwiej uzyskasz dobrฤ… odpowiedลบ, a nawet rozwiฤ…ลผesz problem samodzielnie, zanim zapytasz. Ponadto na GitHubie mogฤ™ siฤ™ upewniฤ‡, ลผe zawsze odpowiadam na wszystko, nawet jeล›li zajmuje to trochฤ™ czasu. Osobiล›cie nie mogฤ™ tego zrobiฤ‡ z systemami czatu. ๐Ÿ˜… + +Rozmรณw w systemach czatu nie moลผna tak ล‚atwo przeszukiwaฤ‡, jak na GitHubie, wiฤ™c pytania i odpowiedzi mogฤ… zaginฤ…ฤ‡ w rozmowie. A tylko te na GitHubie liczฤ… siฤ™ do zostania [Ekspertem FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, wiฤ™c najprawdopodobniej otrzymasz wiฤ™cej uwagi na GitHubie. + +Z drugiej strony w systemach czatu sฤ… tysiฤ…ce uลผytkownikรณw, wiฤ™c jest duลผa szansa, ลผe znajdziesz tam kogoล› do rozmowy, prawie w kaลผdej chwili. ๐Ÿ˜„ + +## Wspieraj autora + +Moลผesz rรณwnieลผ finansowo wesprzeฤ‡ autora (mnie) poprzez sponsoring na GitHubie. + +Tam moลผesz postawiฤ‡ mi kawฤ™ โ˜•๏ธ aby podziฤ™kowaฤ‡. ๐Ÿ˜„ + +Moลผesz takลผe zostaฤ‡ srebrnym lub zล‚otym sponsorem FastAPI. ๐Ÿ…๐ŸŽ‰ + +## Wspieraj narzฤ™dzia, ktรณre napฤ™dzajฤ… FastAPI + +Jak widziaล‚eล› w dokumentacji, FastAPI stoi na ramionach gigantรณw, Starlette i Pydantic. + +Moลผesz rรณwnieลผ wesprzeฤ‡: + +* Samuel Colvin (Pydantic) +* Encode (Starlette, Uvicorn) + +--- + +Dziฤ™kujฤ™! ๐Ÿš€ diff --git a/docs/pl/docs/index.md b/docs/pl/docs/index.md index bade7a88c..43a20383c 100644 --- a/docs/pl/docs/index.md +++ b/docs/pl/docs/index.md @@ -106,7 +106,7 @@ Jeลผeli tworzysz aplikacje CLI< ## Wymagania -Python 3.7+ +Python 3.8+ FastAPI oparty jest na: @@ -321,7 +321,7 @@ Robisz to tak samo jak ze standardowymi typami w Pythonie. Nie musisz sie uczyฤ‡ ลผadnej nowej skล‚adni, metod lub klas ze specyficznych bibliotek itp. -Po prostu standardowy **Python 3.6+**. +Po prostu standardowy **Python 3.8+**. Na przykล‚ad, dla danych typu `int`: diff --git a/docs/pt/docs/deployment/deta.md b/docs/pt/docs/deployment/deta.md deleted file mode 100644 index 9271bba42..000000000 --- a/docs/pt/docs/deployment/deta.md +++ /dev/null @@ -1,258 +0,0 @@ -# Implantaรงรฃo FastAPI na Deta - -Nessa seรงรฃo vocรช aprenderรก sobre como realizar a implantaรงรฃo de uma aplicaรงรฃo **FastAPI** na Deta utilizando o plano gratuito. ๐ŸŽ - -Isso tudo levarรก aproximadamente **10 minutos**. - -!!! info "Informaรงรฃo" - Deta รฉ uma patrocinadora do **FastAPI**. ๐ŸŽ‰ - -## Uma aplicaรงรฃo **FastAPI** simples - -* Crie e entre em um diretรณrio para a sua aplicaรงรฃo, por exemplo, `./fastapideta/`. - -### Cรณdigo FastAPI - -* Crie o arquivo `main.py` com: - -```Python -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/") -def read_root(): - return {"Hello": "World"} - - -@app.get("/items/{item_id}") -def read_item(item_id: int): - return {"item_id": item_id} -``` - -### Requisitos - -Agora, no mesmo diretรณrio crie o arquivo `requirements.txt` com: - -```text -fastapi -``` - -!!! tip "Dica" - Vocรช nรฃo precisa instalar Uvicorn para realizar a implantaรงรฃo na Deta, embora provavelmente queira instalรก-lo para testar seu aplicativo localmente. - -### Estrutura de diretรณrio - -Agora vocรช terรก o diretรณrio `./fastapideta/` com dois arquivos: - -``` -. -โ””โ”€โ”€ main.py -โ””โ”€โ”€ requirements.txt -``` - -## Crie uma conta gratuita na Deta - -Agora crie uma conta gratuita na Deta, vocรช precisarรก apenas de um email e senha. - -Vocรช nem precisa de um cartรฃo de crรฉdito. - -## Instale a CLI - -Depois de ter sua conta criada, instale Deta CLI: - -=== "Linux, macOS" - -
- - ```console - $ curl -fsSL https://get.deta.dev/cli.sh | sh - ``` - -
- -=== "Windows PowerShell" - -
- - ```console - $ iwr https://get.deta.dev/cli.ps1 -useb | iex - ``` - -
- -Apรณs a instalaรงรฃo, abra um novo terminal para que a CLI seja detectada. - -Em um novo terminal, confirme se foi instalado corretamente com: - -
- -```console -$ deta --help - -Deta command line interface for managing deta micros. -Complete documentation available at https://docs.deta.sh - -Usage: - deta [flags] - deta [command] - -Available Commands: - auth Change auth settings for a deta micro - -... -``` - -
- -!!! tip "Dica" - Se vocรช tiver problemas ao instalar a CLI, verifique a documentaรงรฃo oficial da Deta. - -## Login pela CLI - -Agora faรงa login na Deta pela CLI com: - -
- -```console -$ deta login - -Please, log in from the web page. Waiting.. -Logged in successfully. -``` - -
- -Isso abrirรก um navegador da Web e autenticarรก automaticamente. - -## Implantaรงรฃo com Deta - -Em seguida, implante seu aplicativo com a Deta CLI: - -
- -```console -$ deta new - -Successfully created a new micro - -// Notice the "endpoint" ๐Ÿ” - -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} - -Adding dependencies... - - ----> 100% - - -Successfully installed fastapi-0.61.1 pydantic-1.7.2 starlette-0.13.6 -``` - -
- -Vocรช verรก uma mensagem JSON semelhante a: - -```JSON hl_lines="4" -{ - "name": "fastapideta", - "runtime": "python3.7", - "endpoint": "https://qltnci.deta.dev", - "visor": "enabled", - "http_auth": "enabled" -} -``` - -!!! tip "Dica" - Sua implantaรงรฃo terรก um URL `"endpoint"` diferente. - -## Confira - -Agora, abra seu navegador na URL do `endpoint`. No exemplo acima foi `https://qltnci.deta.dev`, mas o seu serรก diferente. - -Vocรช verรก a resposta JSON do seu aplicativo FastAPI: - -```JSON -{ - "Hello": "World" -} -``` - -Agora vรก para o `/docs` da sua API, no exemplo acima seria `https://qltnci.deta.dev/docs`. - -Ele mostrarรก sua documentaรงรฃo como: - - - -## Permitir acesso pรบblico - -Por padrรฃo, a Deta lidarรก com a autenticaรงรฃo usando cookies para sua conta. - -Mas quando estiver pronto, vocรช pode tornรก-lo pรบblico com: - -
- -```console -$ deta auth disable - -Successfully disabled http auth -``` - -
- -Agora vocรช pode compartilhar essa URL com qualquer pessoa e elas conseguirรฃo acessar sua API. ๐Ÿš€ - -## HTTPS - -Parabรฉns! Vocรช realizou a implantaรงรฃo do seu app FastAPI na Deta! ๐ŸŽ‰ ๐Ÿฐ - -Alรฉm disso, observe que a Deta lida corretamente com HTTPS para vocรช, para que vocรช nรฃo precise cuidar disso e tenha a certeza de que seus clientes terรฃo uma conexรฃo criptografada segura. โœ… ๐Ÿ”’ - -## Verifique o Visor - -Na UI da sua documentaรงรฃo (vocรช estarรก em um URL como `https://qltnci.deta.dev/docs`) envie um request para *operaรงรฃo de rota* `/items/{item_id}`. - -Por exemplo com ID `5`. - -Agora vรก para https://web.deta.sh. - -Vocรช verรก que hรก uma seรงรฃo ร  esquerda chamada "Micros" com cada um dos seus apps. - -Vocรช verรก uma aba com "Detalhes", e tambรฉm a aba "Visor", vรก para "Visor". - -Lรก vocรช pode inspecionar as solicitaรงรตes recentes enviadas ao seu aplicativo. - -Vocรช tambรฉm pode editรก-los e reproduzi-los novamente. - - - -## Saiba mais - -Em algum momento, vocรช provavelmente desejarรก armazenar alguns dados para seu aplicativo de uma forma que persista ao longo do tempo. Para isso vocรช pode usar Deta Base, que tambรฉm tem um generoso **nรญvel gratuito**. - -Vocรช tambรฉm pode ler mais na documentaรงรฃo da Deta. - -## Conceitos de implantaรงรฃo - -Voltando aos conceitos que discutimos em [Deployments Concepts](./concepts.md){.internal-link target=_blank}, veja como cada um deles seria tratado com a Deta: - -* **HTTPS**: Realizado pela Deta, eles fornecerรฃo um subdomรญnio e lidarรฃo com HTTPS automaticamente. -* **Executando na inicializaรงรฃo**: Realizado pela Deta, como parte de seu serviรงo. -* **Reinicializaรงรฃo**: Realizado pela Deta, como parte de seu serviรงo. -* **Replicaรงรฃo**: Realizado pela Deta, como parte de seu serviรงo. -* **Memรณria**: Limite predefinido pela Deta, vocรช pode contatรก-los para aumentรก-lo. -* **Etapas anteriores a inicializaรงรฃo**: Nรฃo suportado diretamente, vocรช pode fazรช-lo funcionar com o sistema Cron ou scripts adicionais. - -!!! note "Nota" - O Deta foi projetado para facilitar (e gratuitamente) a implantaรงรฃo rรกpida de aplicativos simples. - - Ele pode simplificar vรกrios casos de uso, mas, ao mesmo tempo, nรฃo suporta outros, como o uso de bancos de dados externos (alรฉm do prรณprio sistema de banco de dados NoSQL da Deta), mรกquinas virtuais personalizadas, etc. - - Vocรช pode ler mais detalhes na documentaรงรฃo da Deta para ver se รฉ a escolha certa para vocรช. diff --git a/docs/pt/docs/external-links.md b/docs/pt/docs/external-links.md index 6ec6c3a27..77ec32351 100644 --- a/docs/pt/docs/external-links.md +++ b/docs/pt/docs/external-links.md @@ -9,70 +9,21 @@ Aqui tem uma lista, incompleta, de algumas delas. !!! tip "Dica" Se vocรช tem um artigo, projeto, ferramenta ou qualquer coisa relacionada ao **FastAPI** que ainda nรฃo estรก listada aqui, crie um _Pull Request_ adicionando ele. -## Artigos +{% for section_name, section_content in external_links.items() %} -### Inglรชs +## {{ section_name }} -{% if external_links %} -{% for article in external_links.articles.english %} +{% for lang_name, lang_content in section_content.items() %} + +### {{ lang_name }} + +{% for item in lang_content %} + +* {{ item.title }} by {{ item.author }}. -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### Japonรชs - -{% if external_links %} -{% for article in external_links.articles.japanese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### Vietnamita - -{% if external_links %} -{% for article in external_links.articles.vietnamese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### Russo - -{% if external_links %} -{% for article in external_links.articles.russian %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -### Alemรฃo - -{% if external_links %} -{% for article in external_links.articles.german %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## Podcasts - -{% if external_links %} -{% for article in external_links.podcasts.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## Palestras - -{% if external_links %} -{% for article in external_links.talks.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} ## Projetos diff --git a/docs/pt/docs/features.md b/docs/pt/docs/features.md index bd0db8e76..822992c5b 100644 --- a/docs/pt/docs/features.md +++ b/docs/pt/docs/features.md @@ -25,7 +25,7 @@ Documentaรงรฃo interativa da API e navegaรงรฃo _web_ da interface de usuรกrio. C ### Apenas Python moderno -Tudo รฉ baseado no padrรฃo das declaraรงรตes de **tipos do Python 3.6** (graรงas ao Pydantic). Nenhuma sintaxe nova para aprender. Apenas o padrรฃo moderno do Python. +Tudo รฉ baseado no padrรฃo das declaraรงรตes de **tipos do Python 3.8** (graรงas ao Pydantic). Nenhuma sintaxe nova para aprender. Apenas o padrรฃo moderno do Python. Se vocรช precisa refrescar a memรณria rapidamente sobre como usar tipos do Python (mesmo que vocรช nรฃo use o FastAPI), confira esse rรกpido tutorial: [Tipos do Python](python-types.md){.internal-link target=_blank}. diff --git a/docs/pt/docs/help-fastapi.md b/docs/pt/docs/help-fastapi.md index d82ce3414..d04905197 100644 --- a/docs/pt/docs/help-fastapi.md +++ b/docs/pt/docs/help-fastapi.md @@ -114,8 +114,6 @@ do FastAPI. Use o chat apenas para outro tipo de assunto. -Tambรฉm existe o chat do Gitter, porรฉm ele nรฃo possuรญ canais e recursos avanรงados, conversas sรฃo mais engessadas, por isso o Discord รฉ mais recomendado. - ### Nรฃo faรงa perguntas no chat Tenha em mente que os chats permitem uma "conversa mais livre", dessa forma รฉ muito fรกcil fazer perguntas que sรฃo muito genรฉricas e dificeรญs de responder, assim vocรช pode acabar nรฃo sendo respondido. diff --git a/docs/pt/docs/index.md b/docs/pt/docs/index.md index 591e7f3d4..d1e64b3b9 100644 --- a/docs/pt/docs/index.md +++ b/docs/pt/docs/index.md @@ -24,7 +24,7 @@ --- -FastAPI รฉ um moderno e rรกpido (alta performance) _framework web_ para construรงรฃo de APIs com Python 3.6 ou superior, baseado nos _type hints_ padrรตes do Python. +FastAPI รฉ um moderno e rรกpido (alta performance) _framework web_ para construรงรฃo de APIs com Python 3.8 ou superior, baseado nos _type hints_ padrรตes do Python. Os recursos chave sรฃo: @@ -100,7 +100,7 @@ Se vocรช estiver construindo uma aplicaรงรฃo ../../../docs_src/body_multiple_params/tutorial001.py!} @@ -44,7 +44,7 @@ Mas vocรช pode tambรฉm declarar mรบltiplos parรขmetros de corpo, por exemplo, `i {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/body_multiple_params/tutorial002.py!} @@ -87,7 +87,7 @@ Se vocรช declarรก-lo como รฉ, porque รฉ um valor singular, o **FastAPI** assumir Mas vocรช pode instruir o **FastAPI** para tratรก-lo como outra chave do corpo usando `Body`: -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/body_multiple_params/tutorial003.py!} @@ -143,7 +143,7 @@ Por exemplo: {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="27" {!> ../../../docs_src/body_multiple_params/tutorial004.py!} @@ -172,7 +172,7 @@ como em: {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17" {!> ../../../docs_src/body_multiple_params/tutorial005.py!} diff --git a/docs/pt/docs/tutorial/encoder.md b/docs/pt/docs/tutorial/encoder.md index bb4483fdc..b9bfbf63b 100644 --- a/docs/pt/docs/tutorial/encoder.md +++ b/docs/pt/docs/tutorial/encoder.md @@ -26,7 +26,7 @@ A funรงรฃo recebe um objeto, como um modelo Pydantic e retorna uma versรฃo compa {!> ../../../docs_src/encoder/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="5 22" {!> ../../../docs_src/encoder/tutorial001.py!} diff --git a/docs/pt/docs/tutorial/extra-models.md b/docs/pt/docs/tutorial/extra-models.md index dd5407eb2..1343a3ae4 100644 --- a/docs/pt/docs/tutorial/extra-models.md +++ b/docs/pt/docs/tutorial/extra-models.md @@ -17,7 +17,7 @@ Isso รฉ especialmente o caso para modelos de usuรกrios, porque: Aqui estรก uma ideia geral de como os modelos poderiam parecer com seus campos de senha e os lugares onde sรฃo usados: -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41" {!> ../../../docs_src/extra_models/tutorial001.py!} @@ -158,7 +158,7 @@ Toda conversรฃo de dados, validaรงรฃo, documentaรงรฃo, etc. ainda funcionarรก no Dessa forma, podemos declarar apenas as diferenรงas entre os modelos (com `password` em texto claro, com `hashed_password` e sem senha): -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="9 15-16 19-20 23-24" {!> ../../../docs_src/extra_models/tutorial002.py!} @@ -181,7 +181,7 @@ Para fazer isso, use a dica de tipo padrรฃo do Python `Union`, inclua o tipo mais especรญfico primeiro, seguido pelo tipo menos especรญfico. No exemplo abaixo, o tipo mais especรญfico `PlaneItem` vem antes de `CarItem` em `Union[PlaneItem, CarItem]`. -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="1 14-15 18-20 33" {!> ../../../docs_src/extra_models/tutorial003.py!} @@ -213,7 +213,7 @@ Da mesma forma, vocรช pode declarar respostas de listas de objetos. Para isso, use o padrรฃo Python `typing.List` (ou simplesmente `list` no Python 3.9 e superior): -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="1 20" {!> ../../../docs_src/extra_models/tutorial004.py!} @@ -233,7 +233,7 @@ Isso รฉ รบtil se vocรช nรฃo souber os nomes de campo / atributo vรกlidos (que se Neste caso, vocรช pode usar `typing.Dict` (ou simplesmente dict no Python 3.9 e superior): -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="1 8" {!> ../../../docs_src/extra_models/tutorial005.py!} diff --git a/docs/pt/docs/tutorial/header-params.md b/docs/pt/docs/tutorial/header-params.md index bc8843327..4bdfb7e9c 100644 --- a/docs/pt/docs/tutorial/header-params.md +++ b/docs/pt/docs/tutorial/header-params.md @@ -12,7 +12,7 @@ Primeiro importe `Header`: {!> ../../../docs_src/header_params/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/header_params/tutorial001.py!} @@ -30,7 +30,7 @@ O primeiro valor รฉ o valor padrรฃo, vocรช pode passar todas as validaรงรตes adi {!> ../../../docs_src/header_params/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/header_params/tutorial001.py!} @@ -66,7 +66,7 @@ Se por algum motivo vocรช precisar desabilitar a conversรฃo automรกtica de subli {!> ../../../docs_src/header_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/header_params/tutorial002.py!} @@ -97,7 +97,7 @@ Por exemplo, para declarar um cabeรงalho de `X-Token` que pode aparecer mais de {!> ../../../docs_src/header_params/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/header_params/tutorial003.py!} diff --git a/docs/pt/docs/tutorial/path-operation-configuration.md b/docs/pt/docs/tutorial/path-operation-configuration.md index e0a23f665..13a87240f 100644 --- a/docs/pt/docs/tutorial/path-operation-configuration.md +++ b/docs/pt/docs/tutorial/path-operation-configuration.md @@ -13,7 +13,7 @@ Vocรช pode passar diretamente o cรณdigo `int`, como `404`. Mas se vocรช nรฃo se lembrar o que cada cรณdigo numรฉrico significa, pode usar as constantes de atalho em `status`: -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="3 17" {!> ../../../docs_src/path_operation_configuration/tutorial001.py!} @@ -42,7 +42,7 @@ Esse cรณdigo de status serรก usado na resposta e serรก adicionado ao esquema Ope Vocรช pode adicionar tags para sua *operaรงรฃo de rota*, passe o parรขmetro `tags` com uma `list` de `str` (comumente apenas um `str`): -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="17 22 27" {!> ../../../docs_src/path_operation_configuration/tutorial002.py!} @@ -80,7 +80,7 @@ Nestes casos, pode fazer sentido armazenar as tags em um `Enum`. Vocรช pode adicionar um `summary` e uma `description`: -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="20-21" {!> ../../../docs_src/path_operation_configuration/tutorial003.py!} @@ -104,7 +104,7 @@ Como as descriรงรตes tendem a ser longas e cobrir vรกrias linhas, vocรช pode dec Vocรช pode escrever Markdown na docstring, ele serรก interpretado e exibido corretamente (levando em conta a indentaรงรฃo da docstring). -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="19-27" {!> ../../../docs_src/path_operation_configuration/tutorial004.py!} @@ -131,7 +131,7 @@ Ela serรก usada nas documentaรงรตes interativas: Vocรช pode especificar a descriรงรฃo da resposta com o parรขmetro `response_description`: -=== "Python 3.6 and above" +=== "Python 3.8 and above" ```Python hl_lines="21" {!> ../../../docs_src/path_operation_configuration/tutorial005.py!} diff --git a/docs/pt/docs/tutorial/path-params-numeric-validations.md b/docs/pt/docs/tutorial/path-params-numeric-validations.md index ec9b74b30..eb0d31dc3 100644 --- a/docs/pt/docs/tutorial/path-params-numeric-validations.md +++ b/docs/pt/docs/tutorial/path-params-numeric-validations.md @@ -12,7 +12,7 @@ Primeiro, importe `Path` de `fastapi`: {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!} @@ -30,7 +30,7 @@ Por exemplo para declarar um valor de metadado `title` para o parรขmetro de rota {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/path_params_numeric_validations/tutorial001.py!} diff --git a/docs/pt/docs/tutorial/path-params.md b/docs/pt/docs/tutorial/path-params.md index 5de3756ed..cd8c18858 100644 --- a/docs/pt/docs/tutorial/path-params.md +++ b/docs/pt/docs/tutorial/path-params.md @@ -236,7 +236,6 @@ Entรฃo, vocรช poderia usar ele com: Com o **FastAPI**, usando as declaraรงรตes de tipo do Python, vocรช obtรฉm: * Suporte no editor: verificaรงรฃo de erros, e opรงรฃo de autocompletar, etc. -* Parsing de dados * "Parsing" de dados * Validaรงรฃo de dados * Anotaรงรฃo da API e documentaรงรฃo automรกtica diff --git a/docs/pt/docs/tutorial/query-params.md b/docs/pt/docs/tutorial/query-params.md index 3ada4fd21..08bb99dbc 100644 --- a/docs/pt/docs/tutorial/query-params.md +++ b/docs/pt/docs/tutorial/query-params.md @@ -69,7 +69,7 @@ Da mesma forma, vocรช pode declarar parรขmetros de consulta opcionais, definindo {!> ../../../docs_src/query_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params/tutorial002.py!} @@ -91,7 +91,7 @@ Vocรช tambรฉm pode declarar tipos `bool`, e eles serรฃo convertidos: {!> ../../../docs_src/query_params/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params/tutorial003.py!} @@ -143,7 +143,7 @@ Eles serรฃo detectados pelo nome: {!> ../../../docs_src/query_params/tutorial004_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8 10" {!> ../../../docs_src/query_params/tutorial004.py!} @@ -209,7 +209,7 @@ E claro, vocรช pode definir alguns parรขmetros como obrigatรณrios, alguns possui {!> ../../../docs_src/query_params/tutorial006_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params/tutorial006.py!} diff --git a/docs/ru/docs/external-links.md b/docs/ru/docs/external-links.md index 4daf65898..2448ef82e 100644 --- a/docs/ru/docs/external-links.md +++ b/docs/ru/docs/external-links.md @@ -9,70 +9,21 @@ !!! tip ะ•ัะปะธ ัƒ ะฒะฐั ะตัั‚ัŒ ัั‚ะฐั‚ัŒั, ะฟั€ะพะตะบั‚, ะธะฝัั‚ั€ัƒะผะตะฝั‚ ะธะปะธ ั‡ั‚ะพ-ะปะธะฑะพ, ัะฒัะทะฐะฝะฝะพะต ั **FastAPI**, ั‡ั‚ะพ ะตั‰ะต ะฝะต ะฟะตั€ะตั‡ะธัะปะตะฝะพ ะทะดะตััŒ, ัะพะทะดะฐะนั‚ะต Pull Request. -## ะกั‚ะฐั‚ัŒะธ +{% for section_name, section_content in external_links.items() %} -### ะะฐ ะฐะฝะณะปะธะนัะบะพะผ +## {{ section_name }} -{% if external_links %} -{% for article in external_links.articles.english %} +{% for lang_name, lang_content in section_content.items() %} + +### {{ lang_name }} + +{% for item in lang_content %} + +* {{ item.title }} by {{ item.author }}. -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### ะะฐ ัะฟะพะฝัะบะพะผ - -{% if external_links %} -{% for article in external_links.articles.japanese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### ะะฐ ะฒัŒะตั‚ะฝะฐะผัะบะพะผ - -{% if external_links %} -{% for article in external_links.articles.vietnamese %} - -* {{ article.title }} by {{ article.author }}. {% endfor %} -{% endif %} - -### ะะฐ ั€ัƒััะบะพะผ - -{% if external_links %} -{% for article in external_links.articles.russian %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -### ะะฐ ะฝะตะผะตั†ะบะพะผ - -{% if external_links %} -{% for article in external_links.articles.german %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## ะŸะพะดะบะฐัั‚ั‹ - -{% if external_links %} -{% for article in external_links.podcasts.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} - -## Talks - -{% if external_links %} -{% for article in external_links.talks.english %} - -* {{ article.title }} by {{ article.author }}. -{% endfor %} -{% endif %} ## ะŸั€ะพะตะบั‚ั‹ diff --git a/docs/ru/docs/features.md b/docs/ru/docs/features.md index e18f7bc87..97841cc83 100644 --- a/docs/ru/docs/features.md +++ b/docs/ru/docs/features.md @@ -27,7 +27,7 @@ ### ะขะพะปัŒะบะพ ัะพะฒั€ะตะผะตะฝะฝั‹ะน Python -ะ’ัะต ัั‚ะธ ะฒะพะทะผะพะถะฝะพัั‚ะธ ะพัะฝะพะฒะฐะฝั‹ ะฝะฐ ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ั… **ะฐะฝะฝะพั‚ะฐั†ะธัั… ั‚ะธะฟะพะฒ Python 3.6** (ะฑะปะฐะณะพะดะฐั€ั Pydantic). ะะต ะฝัƒะถะฝะพ ะธะทัƒั‡ะฐั‚ัŒ ะฝะพะฒั‹ะน ัะธะฝั‚ะฐะบัะธั. ะขะพะปัŒะบะพ ะปะธัˆัŒ ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ะน ัะพะฒั€ะตะผะตะฝะฝั‹ะน Python. +ะ’ัะต ัั‚ะธ ะฒะพะทะผะพะถะฝะพัั‚ะธ ะพัะฝะพะฒะฐะฝั‹ ะฝะฐ ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ั… **ะฐะฝะฝะพั‚ะฐั†ะธัั… ั‚ะธะฟะพะฒ Python 3.8** (ะฑะปะฐะณะพะดะฐั€ั Pydantic). ะะต ะฝัƒะถะฝะพ ะธะทัƒั‡ะฐั‚ัŒ ะฝะพะฒั‹ะน ัะธะฝั‚ะฐะบัะธั. ะขะพะปัŒะบะพ ะปะธัˆัŒ ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ะน ัะพะฒั€ะตะผะตะฝะฝั‹ะน Python. ะ•ัะปะธ ะฒะฐะผ ะฝัƒะถะฝะพ ะพัะฒะตะถะธั‚ัŒ ะทะฝะฐะฝะธั, ะบะฐะบ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฐะฝะฝะพั‚ะฐั†ะธะธ ั‚ะธะฟะพะฒ ะฒ Python (ะดะฐะถะต ะตัะปะธ ะฒั‹ ะฝะต ะธัะฟะพะปัŒะทัƒะตั‚ะต FastAPI), ะฒั‹ะดะตะปะธั‚ะต 2 ะผะธะฝัƒั‚ั‹ ะธ ะฟั€ะพัะผะพั‚ั€ะธั‚ะต ะบั€ะฐั‚ะบะพะต ั€ัƒะบะพะฒะพะดัั‚ะฒะพ: [ะ’ะฒะตะดะตะฝะธะต ะฒ ะฐะฝะฝะพั‚ะฐั†ะธะธ ั‚ะธะฟะพะฒ Pythonยถ ](python-types.md){.internal-link target=_blank}. diff --git a/docs/ru/docs/help-fastapi.md b/docs/ru/docs/help-fastapi.md index a69e37bd8..65ff768d1 100644 --- a/docs/ru/docs/help-fastapi.md +++ b/docs/ru/docs/help-fastapi.md @@ -223,8 +223,6 @@ ะ˜ัะฟะพะปัŒะทัƒะนั‚ะต ัั‚ะพั‚ ั‡ะฐั‚ ั‚ะพะปัŒะบะพ ะดะปั ะฑะตัะตะด ะฝะฐ ะพั‚ะฒะปะตั‡ั‘ะฝะฝั‹ะต ั‚ะตะผั‹. -ะกัƒั‰ะตัั‚ะฒัƒะตั‚ ั‚ะฐะบะถะต ั‡ะฐั‚ ะฒ Gitter, ะฝะพ ะฟะพัะบะพะปัŒะบัƒ ะฒ ะฝะตะผ ะฝะตั‚ ะบะฐะฝะฐะปะพะฒ ะธ ั€ะฐััˆะธั€ะตะฝะฝั‹ั… ั„ัƒะฝะบั†ะธะน, ะพะฑั‰ะตะฝะธะต ะฒ ะฝั‘ะผ ัะปะพะถะฝะตะต, ะฟะพั‚ะพะผัƒ ั€ะตะบะพะผะตะฝะดัƒะตะผะพะน ัะธัั‚ะตะผะพะน ัะฒะปัะตั‚ัั Discord. - ### ะะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ั‡ะฐั‚ั‹ ะดะปั ะฒะพะฟั€ะพัะพะฒ ะ˜ะผะตะนั‚ะต ะฒ ะฒะธะดัƒ, ั‡ั‚ะพ ั‡ะฐั‚ั‹ ะฟะพะทะฒะพะปััŽั‚ ะฑะพะปัŒัˆะต "ัะฒะพะฑะพะดะฝะพะณะพ ะพะฑั‰ะตะฝะธั", ะฟะพั‚ะพะผัƒ ั‚ะฐะผ ะปะตะณะบะพ ะทะฐะดะฐะฒะฐั‚ัŒ ะฒะพะฟั€ะพัั‹, ะบะพั‚ะพั€ั‹ะต ัะปะธัˆะบะพะผ ะพะฑั‰ะธะต ะธ ะฝะฐ ะบะพั‚ะพั€ั‹ะต ั‚ั€ัƒะดะฝะตะต ะพั‚ะฒะตั‚ะธั‚ัŒ, ั‚ะฐะบ ั‡ั‚ะพ ะ’ั‹ ะผะพะถะตั‚ะต ะฝะต ะฟะพะปัƒั‡ะธั‚ัŒ ะฝัƒะถะฝั‹ะต ะ’ะฐะผ ะพั‚ะฒะตั‚ั‹. diff --git a/docs/ru/docs/index.md b/docs/ru/docs/index.md index 30c32e046..97a3947bd 100644 --- a/docs/ru/docs/index.md +++ b/docs/ru/docs/index.md @@ -27,7 +27,7 @@ --- -FastAPI โ€” ัั‚ะพ ัะพะฒั€ะตะผะตะฝะฝั‹ะน, ะฑั‹ัั‚ั€ั‹ะน (ะฒั‹ัะพะบะพะฟั€ะพะธะทะฒะพะดะธั‚ะตะปัŒะฝั‹ะน) ะฒะตะฑ-ั„ั€ะตะนะผะฒะพั€ะบ ะดะปั ัะพะทะดะฐะฝะธั API ะธัะฟะพะปัŒะทัƒั Python 3.6+, ะฒ ะพัะฝะพะฒะต ะบะพั‚ะพั€ะพะณะพ ะปะตะถะธั‚ ัั‚ะฐะฝะดะฐั€ั‚ะฝะฐั ะฐะฝะฝะพั‚ะฐั†ะธั ั‚ะธะฟะพะฒ Python. +FastAPI โ€” ัั‚ะพ ัะพะฒั€ะตะผะตะฝะฝั‹ะน, ะฑั‹ัั‚ั€ั‹ะน (ะฒั‹ัะพะบะพะฟั€ะพะธะทะฒะพะดะธั‚ะตะปัŒะฝั‹ะน) ะฒะตะฑ-ั„ั€ะตะนะผะฒะพั€ะบ ะดะปั ัะพะทะดะฐะฝะธั API ะธัะฟะพะปัŒะทัƒั Python 3.8+, ะฒ ะพัะฝะพะฒะต ะบะพั‚ะพั€ะพะณะพ ะปะตะถะธั‚ ัั‚ะฐะฝะดะฐั€ั‚ะฝะฐั ะฐะฝะฝะพั‚ะฐั†ะธั ั‚ะธะฟะพะฒ Python. ะšะปัŽั‡ะตะฒั‹ะต ะพัะพะฑะตะฝะฝะพัั‚ะธ: @@ -109,7 +109,7 @@ FastAPI โ€” ัั‚ะพ ัะพะฒั€ะตะผะตะฝะฝั‹ะน, ะฑั‹ัั‚ั€ั‹ะน (ะฒั‹ัะพะบะพะฟั€ะพะธ ## ะ—ะฐะฒะธัะธะผะพัั‚ะธ -Python 3.7+ +Python 3.8+ FastAPI ัั‚ะพะธั‚ ะฝะฐ ะฟะปะตั‡ะฐั… ะณะธะณะฐะฝั‚ะพะฒ: @@ -325,7 +325,7 @@ def update_item(item_id: int, item: Item): ะ’ะฐะผ ะฝะต ะฝัƒะถะฝะพ ะธะทัƒั‡ะฐั‚ัŒ ะฝะพะฒั‹ะน ัะธะฝั‚ะฐะบัะธั, ะผะตั‚ะพะดั‹ ะธะปะธ ะบะปะฐััั‹ ะบะพะฝะบั€ะตั‚ะฝะพะน ะฑะธะฑะปะธะพั‚ะตะบะธ ะธ ั‚. ะด. -ะขะพะปัŒะบะพ ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ะน **Python 3.6+**. +ะขะพะปัŒะบะพ ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ะน **Python 3.8+**. ะะฐะฟั€ะธะผะตั€, ะดะปั `int`: diff --git a/docs/ru/docs/tutorial/background-tasks.md b/docs/ru/docs/tutorial/background-tasks.md index 81efda786..7a3cf6d83 100644 --- a/docs/ru/docs/tutorial/background-tasks.md +++ b/docs/ru/docs/tutorial/background-tasks.md @@ -63,7 +63,7 @@ {!> ../../../docs_src/background_tasks/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="13 15 22 25" {!> ../../../docs_src/background_tasks/tutorial002.py!} diff --git a/docs/ru/docs/tutorial/body-fields.md b/docs/ru/docs/tutorial/body-fields.md index 674b8bde4..02a598004 100644 --- a/docs/ru/docs/tutorial/body-fields.md +++ b/docs/ru/docs/tutorial/body-fields.md @@ -12,7 +12,7 @@ {!> ../../../docs_src/body_fields/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4" {!> ../../../docs_src/body_fields/tutorial001.py!} @@ -31,13 +31,13 @@ {!> ../../../docs_src/body_fields/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11-14" {!> ../../../docs_src/body_fields/tutorial001.py!} ``` -ะคัƒะฝะบั†ะธั `Field` ั€ะฐะฑะพั‚ะฐะตั‚ ั‚ะฐะบ ะถะต, ะบะฐะบ `Query`, `Path` ะธ `Body`, ัƒ ะตะต ั‚ะฐะบะธะต ะถะต ะฟะฐั€ะฐะผะตั‚ั€ั‹ ะธ ั‚.ะด. +ะคัƒะฝะบั†ะธั `Field` ั€ะฐะฑะพั‚ะฐะตั‚ ั‚ะฐะบ ะถะต, ะบะฐะบ `Query`, `Path` ะธ `Body`, ัƒ ะฝะตั‘ ั‚ะฐะบะธะต ะถะต ะฟะฐั€ะฐะผะตั‚ั€ั‹ ะธ ั‚.ะด. !!! note "ะขะตั…ะฝะธั‡ะตัะบะธะต ะดะตั‚ะฐะปะธ" ะะฐ ัะฐะผะพะผ ะดะตะปะต, `Query`, `Path` ะธ ะดั€ัƒะณะธะต ั„ัƒะฝะบั†ะธะธ, ะบะพั‚ะพั€ั‹ะต ะฒั‹ ัƒะฒะธะดะธั‚ะต ะฒ ะดะฐะปัŒะฝะตะนัˆะตะผ, ัะพะทะดะฐัŽั‚ ะพะฑัŠะตะบั‚ั‹ ะฟะพะดะบะปะฐััะพะฒ ะพะฑั‰ะตะณะพ ะบะปะฐััะฐ `Param`, ะบะพั‚ะพั€ั‹ะน ัะฐะผ ะฟะพ ัะตะฑะต ัะฒะปัะตั‚ัั ะฟะพะดะบะปะฐััะพะผ `FieldInfo` ะธะท Pydantic. diff --git a/docs/ru/docs/tutorial/body-multiple-params.md b/docs/ru/docs/tutorial/body-multiple-params.md index a20457092..e52ef6f6f 100644 --- a/docs/ru/docs/tutorial/body-multiple-params.md +++ b/docs/ru/docs/tutorial/body-multiple-params.md @@ -20,7 +20,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="19-21" {!> ../../../docs_src/body_multiple_params/tutorial001_an.py!} @@ -35,7 +35,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! ะ—ะฐะผะตั‚ะบะฐ ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated`, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. @@ -68,7 +68,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/body_multiple_params/tutorial002.py!} @@ -123,7 +123,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/body_multiple_params/tutorial003_an.py!} @@ -138,7 +138,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! ะ—ะฐะผะตั‚ะบะฐ ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ `Annotated` ะฒะตั€ัะธัŽ, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. @@ -197,7 +197,7 @@ q: str | None = None {!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="28" {!> ../../../docs_src/body_multiple_params/tutorial004_an.py!} @@ -212,7 +212,7 @@ q: str | None = None {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! ะ—ะฐะผะตั‚ะบะฐ ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ `Annotated` ะฒะตั€ัะธัŽ, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. @@ -250,7 +250,7 @@ item: Item = Body(embed=True) {!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/body_multiple_params/tutorial005_an.py!} @@ -265,7 +265,7 @@ item: Item = Body(embed=True) {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! ะ—ะฐะผะตั‚ะบะฐ ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ `Annotated` ะฒะตั€ัะธัŽ, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. diff --git a/docs/ru/docs/tutorial/body-nested-models.md b/docs/ru/docs/tutorial/body-nested-models.md index 6435e316f..a6d123d30 100644 --- a/docs/ru/docs/tutorial/body-nested-models.md +++ b/docs/ru/docs/tutorial/body-nested-models.md @@ -12,7 +12,7 @@ {!> ../../../docs_src/body_nested_models/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14" {!> ../../../docs_src/body_nested_models/tutorial001.py!} @@ -73,7 +73,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14" {!> ../../../docs_src/body_nested_models/tutorial002.py!} @@ -99,7 +99,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 14" {!> ../../../docs_src/body_nested_models/tutorial003.py!} @@ -137,7 +137,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-11" {!> ../../../docs_src/body_nested_models/tutorial004.py!} @@ -159,7 +159,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/body_nested_models/tutorial004.py!} @@ -208,7 +208,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 10" {!> ../../../docs_src/body_nested_models/tutorial005.py!} @@ -232,7 +232,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial006_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/body_nested_models/tutorial006.py!} @@ -283,7 +283,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial007_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 14 20 23 27" {!> ../../../docs_src/body_nested_models/tutorial007.py!} @@ -314,7 +314,7 @@ images: list[Image] {!> ../../../docs_src/body_nested_models/tutorial008_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15" {!> ../../../docs_src/body_nested_models/tutorial008.py!} @@ -354,7 +354,7 @@ images: list[Image] {!> ../../../docs_src/body_nested_models/tutorial009_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/body_nested_models/tutorial009.py!} diff --git a/docs/ru/docs/tutorial/cookie-params.md b/docs/ru/docs/tutorial/cookie-params.md index a6f2caa26..5f99458b6 100644 --- a/docs/ru/docs/tutorial/cookie-params.md +++ b/docs/ru/docs/tutorial/cookie-params.md @@ -12,7 +12,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/cookie_params/tutorial001.py!} @@ -30,7 +30,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/cookie_params/tutorial001.py!} diff --git a/docs/ru/docs/tutorial/dependencies/global-dependencies.md b/docs/ru/docs/tutorial/dependencies/global-dependencies.md index 870d42cf5..eb1b4d7c1 100644 --- a/docs/ru/docs/tutorial/dependencies/global-dependencies.md +++ b/docs/ru/docs/tutorial/dependencies/global-dependencies.md @@ -12,13 +12,13 @@ {!> ../../../docs_src/dependencies/tutorial012_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="16" {!> ../../../docs_src/dependencies/tutorial012_an.py!} ``` -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ 'Annotated' ะฒะตั€ัะธัŽ, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. diff --git a/docs/ru/docs/tutorial/extra-data-types.md b/docs/ru/docs/tutorial/extra-data-types.md index efcbcb38a..0f613a6b2 100644 --- a/docs/ru/docs/tutorial/extra-data-types.md +++ b/docs/ru/docs/tutorial/extra-data-types.md @@ -55,7 +55,7 @@ ะ’ะพั‚ ะฟั€ะธะผะตั€ *ะพะฟะตั€ะฐั†ะธะธ ะฟัƒั‚ะธ* ั ะฟะฐั€ะฐะผะตั‚ั€ะฐะผะธ, ะบะพั‚ะพั€ั‹ะน ะดะตะผะพะฝัั‚ั€ะธั€ัƒะตั‚ ะฝะตะบะพั‚ะพั€ั‹ะต ะธะท ะฒั‹ัˆะตะฟะตั€ะตั‡ะธัะปะตะฝะฝั‹ั… ั‚ะธะฟะพะฒ. -=== "Python 3.6 ะธ ะฒั‹ัˆะต" +=== "Python 3.8 ะธ ะฒั‹ัˆะต" ```Python hl_lines="1 3 12-16" {!> ../../../docs_src/extra_data_types/tutorial001.py!} @@ -69,7 +69,7 @@ ะžะฑั€ะฐั‚ะธั‚ะต ะฒะฝะธะผะฐะฝะธะต, ั‡ั‚ะพ ะฟะฐั€ะฐะผะตั‚ั€ั‹ ะฒะฝัƒั‚ั€ะธ ั„ัƒะฝะบั†ะธะธ ะธะผะตัŽั‚ ัะฒะพะน ะตัั‚ะตัั‚ะฒะตะฝะฝั‹ะน ั‚ะธะฟ ะดะฐะฝะฝั‹ั…, ะธ ะฒั‹, ะฝะฐะฟั€ะธะผะตั€, ะผะพะถะตั‚ะต ะฒั‹ะฟะพะปะฝัั‚ัŒ ะพะฑั‹ั‡ะฝั‹ะต ะผะฐะฝะธะฟัƒะปัั†ะธะธ ั ะดะฐั‚ะฐะผะธ, ั‚ะฐะบะธะต ะบะฐะบ: -=== "Python 3.6 ะธ ะฒั‹ัˆะต" +=== "Python 3.8 ะธ ะฒั‹ัˆะต" ```Python hl_lines="18-19" {!> ../../../docs_src/extra_data_types/tutorial001.py!} diff --git a/docs/ru/docs/tutorial/extra-models.md b/docs/ru/docs/tutorial/extra-models.md index a346f7432..30176b4e3 100644 --- a/docs/ru/docs/tutorial/extra-models.md +++ b/docs/ru/docs/tutorial/extra-models.md @@ -23,7 +23,7 @@ {!> ../../../docs_src/extra_models/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41" {!> ../../../docs_src/extra_models/tutorial001.py!} @@ -164,7 +164,7 @@ UserInDB( {!> ../../../docs_src/extra_models/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 15-16 19-20 23-24" {!> ../../../docs_src/extra_models/tutorial002.py!} @@ -187,7 +187,7 @@ UserInDB( {!> ../../../docs_src/extra_models/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 14-15 18-20 33" {!> ../../../docs_src/extra_models/tutorial003.py!} @@ -219,7 +219,7 @@ some_variable: PlaneItem | CarItem {!> ../../../docs_src/extra_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 20" {!> ../../../docs_src/extra_models/tutorial004.py!} @@ -239,7 +239,7 @@ some_variable: PlaneItem | CarItem {!> ../../../docs_src/extra_models/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 8" {!> ../../../docs_src/extra_models/tutorial005.py!} diff --git a/docs/ru/docs/tutorial/header-params.md b/docs/ru/docs/tutorial/header-params.md new file mode 100644 index 000000000..1be4ac707 --- /dev/null +++ b/docs/ru/docs/tutorial/header-params.md @@ -0,0 +1,227 @@ +# Header-ะฟะฐั€ะฐะผะตั‚ั€ั‹ + +ะ’ั‹ ะผะพะถะตั‚ะต ะพะฟั€ะตะดะตะปะธั‚ัŒ ะฟะฐั€ะฐะผะตั‚ั€ั‹ ะทะฐะณะพะปะพะฒะบะฐ ั‚ะฐะบะธะผ ะถะต ะพะฑั€ะฐะทะพะผ, ะบะฐะบ ะฒั‹ ะพะฟั€ะตะดะตะปัะตั‚ะต ะฟะฐั€ะฐะผะตั‚ั€ั‹ `Query`, `Path` ะธ `Cookie`. + +## ะ˜ะผะฟะพั€ั‚ `Header` + +ะกะฟะตั€ะฒะฐ ะธะผะฟะพั€ั‚ะธั€ัƒะนั‚ะต `Header`: + +=== "Python 3.10+" + + ```Python hl_lines="3" + {!> ../../../docs_src/header_params/tutorial001_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="3" + {!> ../../../docs_src/header_params/tutorial001_an_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="3" + {!> ../../../docs_src/header_params/tutorial001_an.py!} + ``` + +=== "Python 3.10+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="1" + {!> ../../../docs_src/header_params/tutorial001_py310.py!} + ``` + +=== "Python 3.8+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="3" + {!> ../../../docs_src/header_params/tutorial001.py!} + ``` + +## ะžะฑัŠัะฒะปะตะฝะธะต ะฟะฐั€ะฐะผะตั‚ั€ะพะฒ `Header` + +ะ—ะฐั‚ะตะผ ะพะฑัŠัะฒะธั‚ะต ะฟะฐั€ะฐะผะตั‚ั€ั‹ ะทะฐะณะพะปะพะฒะบะฐ, ะธัะฟะพะปัŒะทัƒั ั‚ัƒ ะถะต ัั‚ั€ัƒะบั‚ัƒั€ัƒ, ั‡ั‚ะพ ะธ ั `Path`, `Query` ะธ `Cookie`. + +ะŸะตั€ะฒะพะต ะทะฝะฐั‡ะตะฝะธะต ัะฒะปัะตั‚ัั ะทะฝะฐั‡ะตะฝะธะตะผ ะฟะพ ัƒะผะพะปั‡ะฐะฝะธัŽ, ะฒั‹ ะผะพะถะตั‚ะต ะฟะตั€ะตะดะฐั‚ัŒ ะฒัะต ะดะพะฟะพะปะฝะธั‚ะตะปัŒะฝั‹ะต ะฟะฐั€ะฐะผะตั‚ั€ั‹ ะฒะฐะปะธะดะฐั†ะธะธ ะธะปะธ ะฐะฝะฝะพั‚ะฐั†ะธะธ: + +=== "Python 3.10+" + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial001_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial001_an_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="10" + {!> ../../../docs_src/header_params/tutorial001_an.py!} + ``` + +=== "Python 3.10+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="7" + {!> ../../../docs_src/header_params/tutorial001_py310.py!} + ``` + +=== "Python 3.8+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial001.py!} + ``` + +!!! note "ะขะตั…ะฝะธั‡ะตัะบะธะต ะดะตั‚ะฐะปะธ" + `Header` - ัั‚ะพ "ั€ะพะดัั‚ะฒะตะฝะฝั‹ะน" ะบะปะฐัั `Path`, `Query` ะธ `Cookie`. ะžะฝ ั‚ะฐะบะถะต ะฝะฐัะปะตะดัƒะตั‚ัั ะพั‚ ั‚ะพะณะพ ะถะต ะพะฑั‰ะตะณะพ ะบะปะฐััะฐ `Param`. + + ะะพ ะฟะพะผะฝะธั‚ะต, ั‡ั‚ะพ ะบะพะณะดะฐ ะฒั‹ ะธะผะฟะพั€ั‚ะธั€ัƒะตั‚ะต `Query`, `Path`, `Header` ะธ ะดั€ัƒะณะธะต ะธะท `fastapi`, ะฝะฐ ัะฐะผะพะผ ะดะตะปะต ัั‚ะพ ั„ัƒะฝะบั†ะธะธ, ะบะพั‚ะพั€ั‹ะต ะฒะพะทะฒั€ะฐั‰ะฐัŽั‚ ัะฟะตั†ะธะฐะปัŒะฝั‹ะต ะบะปะฐััั‹. + +!!! info "ะ”ะพะฟะพะปะฝะธั‚ะตะปัŒะฝะฐั ะธะฝั„ะพั€ะผะฐั†ะธั" + ะงั‚ะพะฑั‹ ะพะฑัŠัะฒะธั‚ัŒ ะทะฐะณะพะปะพะฒะบะธ, ะฒะฐะถะฝะพ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ `Header`, ะธะฝะฐั‡ะต ะฟะฐั€ะฐะผะตั‚ั€ั‹ ะธะฝั‚ะตั€ะฟั€ะตั‚ะธั€ัƒัŽั‚ัั ะบะฐะบ query-ะฟะฐั€ะฐะผะตั‚ั€ั‹. + +## ะะฒั‚ะพะผะฐั‚ะธั‡ะตัะบะพะต ะฟั€ะตะพะฑั€ะฐะทะพะฒะฐะฝะธะต + +`Header` ะพะฑะปะฐะดะฐะตั‚ ะฝะตะฑะพะปัŒัˆะพะน ะดะพะฟะพะปะฝะธั‚ะตะปัŒะฝะพะน ั„ัƒะฝะบั†ะธะพะฝะฐะปัŒะฝะพัั‚ัŒัŽ ะฒ ะดะพะฟะพะปะฝะตะฝะธะต ะบ ั‚ะพะผัƒ, ั‡ั‚ะพ ะฟั€ะตะดะพัั‚ะฐะฒะปััŽั‚ `Path`, `Query` ะธ `Cookie`. + +ะ‘ะพะปัŒัˆะธะฝัั‚ะฒะพ ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ั… ะทะฐะณะพะปะพะฒะบะพะฒ ั€ะฐะทะดะตะปะตะฝั‹ ัะธะผะฒะพะปะพะผ "ะดะตั„ะธั", ั‚ะฐะบะถะต ะธะทะฒะตัั‚ะฝั‹ะผ ะบะฐะบ "ะผะธะฝัƒั" (`-`). + +ะะพ ะฟะตั€ะตะผะตะฝะฝะฐั ะฒั€ะพะดะต `user-agent` ะฝะตะดะพะฟัƒัั‚ะธะผะฐ ะฒ Python. + +ะŸะพ ัƒะผะพะปั‡ะฐะฝะธัŽ `Header` ะฟั€ะตะพะฑั€ะฐะทัƒะตั‚ ัะธะผะฒะพะปั‹ ะธะผะตะฝ ะฟะฐั€ะฐะผะตั‚ั€ะพะฒ ะธะท ัะธะผะฒะพะปะฐ ะฟะพะดั‡ะตั€ะบะธะฒะฐะฝะธั (`_`) ะฒ ะดะตั„ะธั (`-`) ะดะปั ะธะทะฒะปะตั‡ะตะฝะธั ะธ ะดะพะบัƒะผะตะฝั‚ะธั€ะพะฒะฐะฝะธั ะทะฐะณะพะปะพะฒะบะพะฒ. + +ะšั€ะพะผะต ั‚ะพะณะพ, HTTP-ะทะฐะณะพะปะพะฒะบะธ ะฝะต ั‡ัƒะฒัั‚ะฒะธั‚ะตะปัŒะฝั‹ ะบ ั€ะตะณะธัั‚ั€ัƒ, ะฟะพัั‚ะพะผัƒ ะฒั‹ ะผะพะถะตั‚ะต ะพะฑัŠัะฒะธั‚ัŒ ะธั… ะฒ ัั‚ะฐะฝะดะฐั€ั‚ะฝะพะผ ัั‚ะธะปะต Python (ั‚ะฐะบะถะต ะธะทะฒะตัั‚ะฝะพะผ ะบะฐะบ "snake_case"). + +ะขะฐะบะธะผ ะพะฑั€ะฐะทะพะผ ะฒั‹ ะผะพะถะตั‚ะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ `user_agent`, ะบะฐะบ ะพะฑั‹ั‡ะฝะพ, ะฒ ะบะพะดะต Python, ะฒะผะตัั‚ะพ ั‚ะพะณะพ, ั‡ั‚ะพะฑั‹ ะฒะฒะพะดะธั‚ัŒ ะทะฐะณะปะฐะฒะฝั‹ะต ะฑัƒะบะฒั‹ ะบะฐะบ `User_Agent` ะธะปะธ ั‡ั‚ะพ-ั‚ะพ ะฟะพะดะพะฑะฝะพะต. + +ะ•ัะปะธ ะฟะพ ะบะฐะบะพะน-ะปะธะฑะพ ะฟั€ะธั‡ะธะฝะต ะฒะฐะผ ะฝะตะพะฑั…ะพะดะธะผะพ ะพั‚ะบะปัŽั‡ะธั‚ัŒ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะตัะบะพะต ะฟั€ะตะพะฑั€ะฐะทะพะฒะฐะฝะธะต ะฟะพะดั‡ะตั€ะบะธะฒะฐะฝะธะน ะฒ ะดะตั„ะธัั‹, ัƒัั‚ะฐะฝะพะฒะธั‚ะต ะดะปั ะฟะฐั€ะฐะผะตั‚ั€ะฐ `convert_underscores` ะฒ `Header` ะทะฝะฐั‡ะตะฝะธะต `False`: + +=== "Python 3.10+" + + ```Python hl_lines="10" + {!> ../../../docs_src/header_params/tutorial002_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="11" + {!> ../../../docs_src/header_params/tutorial002_an_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="12" + {!> ../../../docs_src/header_params/tutorial002_an.py!} + ``` + +=== "Python 3.10+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="8" + {!> ../../../docs_src/header_params/tutorial002_py310.py!} + ``` + +=== "Python 3.8+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="10" + {!> ../../../docs_src/header_params/tutorial002.py!} + ``` + +!!! warning "ะ’ะฝะธะผะฐะฝะธะต" + ะŸั€ะตะถะดะต ั‡ะตะผ ัƒัั‚ะฐะฝะพะฒะธั‚ัŒ ะดะปั `convert_underscores` ะทะฝะฐั‡ะตะฝะธะต `False`, ะธะผะตะนั‚ะต ะฒ ะฒะธะดัƒ, ั‡ั‚ะพ ะฝะตะบะพั‚ะพั€ั‹ะต HTTP-ะฟั€ะพะบัะธ ะธ ัะตั€ะฒะตั€ั‹ ะทะฐะฟั€ะตั‰ะฐัŽั‚ ะธัะฟะพะปัŒะทะพะฒะฐะฝะธะต ะทะฐะณะพะปะพะฒะบะพะฒ ั ะฟะพะดั‡ะตั€ะบะธะฒะฐะฝะธะตะผ. + +## ะŸะพะฒั‚ะพั€ััŽั‰ะธะตัั ะทะฐะณะพะปะพะฒะบะธ + +ะ•ัั‚ัŒ ะฒะพะทะผะพะถะฝะพัั‚ัŒ ะฟะพะปัƒั‡ะฐั‚ัŒ ะฝะตัะบะพะปัŒะบะพ ะทะฐะณะพะปะพะฒะบะพะฒ ั ะพะดะฝะธะผ ะธ ั‚ะตะผ ะถะต ะธะผะตะฝะตะผ, ะฝะพ ั€ะฐะทะฝั‹ะผะธ ะทะฝะฐั‡ะตะฝะธัะผะธ. + +ะ’ั‹ ะผะพะถะตั‚ะต ะพะฟั€ะตะดะตะปะธั‚ัŒ ัั‚ะธ ัะปัƒั‡ะฐะธ, ะธัะฟะพะปัŒะทัƒั ัะฟะธัะพะบ ะฒ ะพะฑัŠัะฒะปะตะฝะธะธ ั‚ะธะฟะฐ. + +ะ’ั‹ ะฟะพะปัƒั‡ะธั‚ะต ะฒัะต ะทะฝะฐั‡ะตะฝะธั ะธะท ะฟะพะฒั‚ะพั€ััŽั‰ะตะณะพัั ะทะฐะณะพะปะพะฒะบะฐ ะฒ ะฒะธะดะต `list` Python. + +ะะฐะฟั€ะธะผะตั€, ั‡ั‚ะพะฑั‹ ะพะฑัŠัะฒะธั‚ัŒ ะทะฐะณะพะปะพะฒะพะบ `X-Token`, ะบะพั‚ะพั€ั‹ะน ะผะพะถะตั‚ ะฟะพัะฒะปัั‚ัŒัั ะฑะพะปะตะต ะพะดะฝะพะณะพ ั€ะฐะทะฐ, ะฒั‹ ะผะพะถะตั‚ะต ะฝะฐะฟะธัะฐั‚ัŒ: + +=== "Python 3.10+" + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial003_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial003_an_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="10" + {!> ../../../docs_src/header_params/tutorial003_an.py!} + ``` + +=== "Python 3.10+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="7" + {!> ../../../docs_src/header_params/tutorial003_py310.py!} + ``` + +=== "Python 3.9+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial003_py39.py!} + ``` + +=== "Python 3.8+ ะฑะตะท Annotated" + + !!! tip "ะŸะพะดัะบะฐะทะบะฐ" + ะŸั€ะตะดะฟะพั‡ั‚ะธั‚ะตะปัŒะฝะตะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั ะฐะฝะฝะพั‚ะฐั†ะธะตะน, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. + + ```Python hl_lines="9" + {!> ../../../docs_src/header_params/tutorial003.py!} + ``` + +ะ•ัะปะธ ะฒั‹ ะฒะทะฐะธะผะพะดะตะนัั‚ะฒัƒะตั‚ะต ั ัั‚ะพะน *ะพะฟะตั€ะฐั†ะธะตะน ะฟัƒั‚ะธ*, ะพั‚ะฟั€ะฐะฒะปัั ะดะฒะฐ HTTP-ะทะฐะณะพะปะพะฒะบะฐ, ั‚ะฐะบะธั… ะบะฐะบ: + +``` +X-Token: foo +X-Token: bar +``` + +ะžั‚ะฒะตั‚ ะฑั‹ะป ะฑั‹ ั‚ะฐะบะธะผ: + +```JSON +{ + "X-Token values": [ + "bar", + "foo" + ] +} +``` + +## ะ ะตะทัŽะผะต + +ะžะฑัŠัะฒะปัะนั‚ะต ะทะฐะณะพะปะพะฒะบะธ ั ะฟะพะผะพั‰ัŒัŽ `Header`, ะธัะฟะพะปัŒะทัƒั ั‚ะพั‚ ะถะต ะพะฑั‰ะธะน ัˆะฐะฑะปะพะฝ, ะบะฐะบ ะฟั€ะธ `Query`, `Path` ะธ `Cookie`. + +ะ˜ ะฝะต ะฑะตัะฟะพะบะพะนั‚ะตััŒ ะพ ัะธะผะฒะพะปะฐั… ะฟะพะดั‡ะตั€ะบะธะฒะฐะฝะธั ะฒ ะฒะฐัˆะธั… ะฟะตั€ะตะผะตะฝะฝั‹ั…, **FastAPI** ะฟะพะทะฐะฑะพั‚ะธั‚ัั ะพะฑ ะธั… ะฟั€ะตะพะฑั€ะฐะทะพะฒะฐะฝะธะธ. diff --git a/docs/ru/docs/tutorial/path-operation-configuration.md b/docs/ru/docs/tutorial/path-operation-configuration.md index 013903add..db99409f4 100644 --- a/docs/ru/docs/tutorial/path-operation-configuration.md +++ b/docs/ru/docs/tutorial/path-operation-configuration.md @@ -25,7 +25,7 @@ {!> ../../../docs_src/path_operation_configuration/tutorial001_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3 17" {!> ../../../docs_src/path_operation_configuration/tutorial001.py!} @@ -54,7 +54,7 @@ {!> ../../../docs_src/path_operation_configuration/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17 22 27" {!> ../../../docs_src/path_operation_configuration/tutorial002.py!} @@ -92,7 +92,7 @@ {!> ../../../docs_src/path_operation_configuration/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20-21" {!> ../../../docs_src/path_operation_configuration/tutorial003.py!} @@ -116,7 +116,7 @@ {!> ../../../docs_src/path_operation_configuration/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="19-27" {!> ../../../docs_src/path_operation_configuration/tutorial004.py!} @@ -142,7 +142,7 @@ {!> ../../../docs_src/path_operation_configuration/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="21" {!> ../../../docs_src/path_operation_configuration/tutorial005.py!} diff --git a/docs/ru/docs/tutorial/path-params-numeric-validations.md b/docs/ru/docs/tutorial/path-params-numeric-validations.md index 0d034ef34..bd2c29d0a 100644 --- a/docs/ru/docs/tutorial/path-params-numeric-validations.md +++ b/docs/ru/docs/tutorial/path-params-numeric-validations.md @@ -18,7 +18,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3-4" {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!} @@ -33,7 +33,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -67,7 +67,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!} @@ -82,7 +82,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -117,7 +117,7 @@ ะŸะพัั‚ะพะผัƒ ะฒั‹ ะผะพะถะตั‚ะต ะพะฟั€ะตะดะตะปะธั‚ัŒ ั„ัƒะฝะบั†ะธัŽ ั‚ะฐะบ: -=== "Python 3.6 ะฑะตะท Annotated" +=== "Python 3.8 ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -134,7 +134,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial002_an.py!} @@ -174,7 +174,7 @@ Python ะฝะต ะฑัƒะดะตั‚ ะฝะธั‡ะตะณะพ ะดะตะปะฐั‚ัŒ ั `*`, ะฝะพ ะพะฝ ะฑัƒะดะตั‚ ะท {!> ../../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial003_an.py!} @@ -192,13 +192,13 @@ Python ะฝะต ะฑัƒะดะตั‚ ะฝะธั‡ะตะณะพ ะดะตะปะฐั‚ัŒ ั `*`, ะฝะพ ะพะฝ ะฑัƒะดะตั‚ ะท {!> ../../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial004_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -220,13 +220,13 @@ Python ะฝะต ะฑัƒะดะตั‚ ะฝะธั‡ะตะณะพ ะดะตะปะฐั‚ัŒ ั `*`, ะฝะพ ะพะฝ ะฑัƒะดะตั‚ ะท {!> ../../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/path_params_numeric_validations/tutorial005_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -251,13 +251,13 @@ Python ะฝะต ะฑัƒะดะตั‚ ะฝะธั‡ะตะณะพ ะดะตะปะฐั‚ัŒ ั `*`, ะฝะพ ะพะฝ ะฑัƒะดะตั‚ ะท {!> ../../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12" {!> ../../../docs_src/path_params_numeric_validations/tutorial006_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md index 68042db63..cc826b871 100644 --- a/docs/ru/docs/tutorial/query-params-str-validations.md +++ b/docs/ru/docs/tutorial/query-params-str-validations.md @@ -10,7 +10,7 @@ {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params_str_validations/tutorial001.py!} @@ -42,7 +42,7 @@ Query-ะฟะฐั€ะฐะผะตั‚ั€ `q` ะธะผะตะตั‚ ั‚ะธะฟ `Union[str, None]` (ะธะปะธ `str | N {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ะ’ ะฒะตั€ัะธัั… Python ะฝะธะถะต Python 3.9 `Annotation` ะธะผะฟะพั€ั‚ะธั€ัƒะตั‚ัั ะธะท `typing_extensions`. @@ -66,7 +66,7 @@ Query-ะฟะฐั€ะฐะผะตั‚ั€ `q` ะธะผะตะตั‚ ั‚ะธะฟ `Union[str, None]` (ะธะปะธ `str | N q: str | None = None ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python q: Union[str, None] = None @@ -80,7 +80,7 @@ Query-ะฟะฐั€ะฐะผะตั‚ั€ `q` ะธะผะตะตั‚ ั‚ะธะฟ `Union[str, None]` (ะธะปะธ `str | N q: Annotated[str | None] = None ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python q: Annotated[Union[str, None]] = None @@ -100,7 +100,7 @@ Query-ะฟะฐั€ะฐะผะตั‚ั€ `q` ะธะผะตะตั‚ ั‚ะธะฟ `Union[str, None]` (ะธะปะธ `str | N {!> ../../../docs_src/query_params_str_validations/tutorial002_an_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial002_an.py!} @@ -131,7 +131,7 @@ Query-ะฟะฐั€ะฐะผะตั‚ั€ `q` ะธะผะตะตั‚ ั‚ะธะฟ `Union[str, None]` (ะธะปะธ `str | N {!> ../../../docs_src/query_params_str_validations/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params_str_validations/tutorial002.py!} @@ -244,7 +244,7 @@ q: str = Query(default="rick") {!> ../../../docs_src/query_params_str_validations/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial003_an.py!} @@ -259,7 +259,7 @@ q: str = Query(default="rick") {!> ../../../docs_src/query_params_str_validations/tutorial003_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -284,7 +284,7 @@ q: str = Query(default="rick") {!> ../../../docs_src/query_params_str_validations/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12" {!> ../../../docs_src/query_params_str_validations/tutorial004_an.py!} @@ -299,7 +299,7 @@ q: str = Query(default="rick") {!> ../../../docs_src/query_params_str_validations/tutorial004_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -330,13 +330,13 @@ q: str = Query(default="rick") {!> ../../../docs_src/query_params_str_validations/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial005_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -384,13 +384,13 @@ q: Union[str, None] = None {!> ../../../docs_src/query_params_str_validations/tutorial006_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial006_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -414,13 +414,13 @@ q: Union[str, None] = None {!> ../../../docs_src/query_params_str_validations/tutorial006b_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial006b_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -454,7 +454,7 @@ q: Union[str, None] = None {!> ../../../docs_src/query_params_str_validations/tutorial006c_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial006c_an.py!} @@ -469,7 +469,7 @@ q: Union[str, None] = None {!> ../../../docs_src/query_params_str_validations/tutorial006c_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -491,13 +491,13 @@ q: Union[str, None] = None {!> ../../../docs_src/query_params_str_validations/tutorial006d_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="2 9" {!> ../../../docs_src/query_params_str_validations/tutorial006d_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -527,7 +527,7 @@ q: Union[str, None] = None {!> ../../../docs_src/query_params_str_validations/tutorial011_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial011_an.py!} @@ -551,7 +551,7 @@ q: Union[str, None] = None {!> ../../../docs_src/query_params_str_validations/tutorial011_py39.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -596,7 +596,7 @@ http://localhost:8000/items/?q=foo&q=bar {!> ../../../docs_src/query_params_str_validations/tutorial012_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial012_an.py!} @@ -611,7 +611,7 @@ http://localhost:8000/items/?q=foo&q=bar {!> ../../../docs_src/query_params_str_validations/tutorial012_py39.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -647,13 +647,13 @@ http://localhost:8000/items/ {!> ../../../docs_src/query_params_str_validations/tutorial013_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/query_params_str_validations/tutorial013_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -692,7 +692,7 @@ http://localhost:8000/items/ {!> ../../../docs_src/query_params_str_validations/tutorial007_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial007_an.py!} @@ -707,7 +707,7 @@ http://localhost:8000/items/ {!> ../../../docs_src/query_params_str_validations/tutorial007_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -730,7 +730,7 @@ http://localhost:8000/items/ {!> ../../../docs_src/query_params_str_validations/tutorial008_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15" {!> ../../../docs_src/query_params_str_validations/tutorial008_an.py!} @@ -741,11 +741,11 @@ http://localhost:8000/items/ !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. - ```Python hl_lines="12" + ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial008_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -784,7 +784,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems {!> ../../../docs_src/query_params_str_validations/tutorial009_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params_str_validations/tutorial009_an.py!} @@ -799,7 +799,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems {!> ../../../docs_src/query_params_str_validations/tutorial009_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -828,7 +828,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems {!> ../../../docs_src/query_params_str_validations/tutorial010_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/query_params_str_validations/tutorial010_an.py!} @@ -839,11 +839,11 @@ http://127.0.0.1:8000/items/?item-query=foobaritems !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. - ```Python hl_lines="17" + ```Python hl_lines="16" {!> ../../../docs_src/query_params_str_validations/tutorial010_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. @@ -872,7 +872,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems {!> ../../../docs_src/query_params_str_validations/tutorial014_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/query_params_str_validations/tutorial014_an.py!} @@ -887,7 +887,7 @@ http://127.0.0.1:8000/items/?item-query=foobaritems {!> ../../../docs_src/query_params_str_validations/tutorial014_py310.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated` ะตัะปะธ ะฒะพะทะผะพะถะฝะพ. diff --git a/docs/ru/docs/tutorial/query-params.md b/docs/ru/docs/tutorial/query-params.md index 68333ec56..6e885cb65 100644 --- a/docs/ru/docs/tutorial/query-params.md +++ b/docs/ru/docs/tutorial/query-params.md @@ -69,7 +69,7 @@ http://127.0.0.1:8000/items/?skip=20 {!> ../../../docs_src/query_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params/tutorial002.py!} @@ -90,7 +90,7 @@ http://127.0.0.1:8000/items/?skip=20 {!> ../../../docs_src/query_params/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params/tutorial003.py!} @@ -143,7 +143,7 @@ http://127.0.0.1:8000/items/foo?short=yes {!> ../../../docs_src/query_params/tutorial004_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8 10" {!> ../../../docs_src/query_params/tutorial004.py!} @@ -209,7 +209,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy {!> ../../../docs_src/query_params/tutorial006_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/query_params/tutorial006.py!} diff --git a/docs/ru/docs/tutorial/request-forms.md b/docs/ru/docs/tutorial/request-forms.md index a20cf78e0..0fc9e4eda 100644 --- a/docs/ru/docs/tutorial/request-forms.md +++ b/docs/ru/docs/tutorial/request-forms.md @@ -17,13 +17,13 @@ {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1" {!> ../../../docs_src/request_forms/tutorial001_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ 'Annotated' ะฒะตั€ัะธัŽ, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. @@ -42,13 +42,13 @@ {!> ../../../docs_src/request_forms/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="8" {!> ../../../docs_src/request_forms/tutorial001_an.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ 'Annotated' ะฒะตั€ัะธัŽ, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. diff --git a/docs/ru/docs/tutorial/response-model.md b/docs/ru/docs/tutorial/response-model.md index c5e111790..38b45e2a5 100644 --- a/docs/ru/docs/tutorial/response-model.md +++ b/docs/ru/docs/tutorial/response-model.md @@ -16,7 +16,7 @@ FastAPI ะฟะพะทะฒะพะปัะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ **ะฐะฝะฝะพั‚ะฐั†ะธะธ ั‚ะธะฟ {!> ../../../docs_src/response_model/tutorial001_01_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18 23" {!> ../../../docs_src/response_model/tutorial001_01.py!} @@ -65,7 +65,7 @@ FastAPI ะฑัƒะดะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ัั‚ะพั‚ ะฒะพะทะฒั€ะฐั‰ะฐะตะผั‹ะน ั‚ {!> ../../../docs_src/response_model/tutorial001_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17 22 24-27" {!> ../../../docs_src/response_model/tutorial001.py!} @@ -101,7 +101,7 @@ FastAPI ะฑัƒะดะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะทะฝะฐั‡ะตะฝะธะต `response_model` ะด {!> ../../../docs_src/response_model/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11" {!> ../../../docs_src/response_model/tutorial002.py!} @@ -120,7 +120,7 @@ FastAPI ะฑัƒะดะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะทะฝะฐั‡ะตะฝะธะต `response_model` ะด {!> ../../../docs_src/response_model/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/response_model/tutorial002.py!} @@ -145,7 +145,7 @@ FastAPI ะฑัƒะดะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะทะฝะฐั‡ะตะฝะธะต `response_model` ะด {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11 16" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -159,7 +159,7 @@ FastAPI ะฑัƒะดะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะทะฝะฐั‡ะตะฝะธะต `response_model` ะด {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -173,7 +173,7 @@ FastAPI ะฑัƒะดะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะทะฝะฐั‡ะตะฝะธะต `response_model` ะด {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -207,7 +207,7 @@ FastAPI ะฑัƒะดะตั‚ ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะทะฝะฐั‡ะตะฝะธะต `response_model` ะด {!> ../../../docs_src/response_model/tutorial003_01_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-13 15-16 20" {!> ../../../docs_src/response_model/tutorial003_01.py!} @@ -283,7 +283,7 @@ FastAPI ัะพะฒะผะตัั‚ะฝะพ ั Pydantic ะฒั‹ะฟะพะปะฝะธั‚ ะฝะตะบะพั‚ะพั€ัƒัŽ ะผะฐ {!> ../../../docs_src/response_model/tutorial003_04_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/response_model/tutorial003_04.py!} @@ -305,7 +305,7 @@ FastAPI ัะพะฒะผะตัั‚ะฝะพ ั Pydantic ะฒั‹ะฟะพะปะฝะธั‚ ะฝะตะบะพั‚ะพั€ัƒัŽ ะผะฐ {!> ../../../docs_src/response_model/tutorial003_05_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/response_model/tutorial003_05.py!} @@ -329,7 +329,7 @@ FastAPI ัะพะฒะผะตัั‚ะฝะพ ั Pydantic ะฒั‹ะฟะพะปะฝะธั‚ ะฝะตะบะพั‚ะพั€ัƒัŽ ะผะฐ {!> ../../../docs_src/response_model/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11 13-14" {!> ../../../docs_src/response_model/tutorial004.py!} @@ -359,7 +359,7 @@ FastAPI ัะพะฒะผะตัั‚ะฝะพ ั Pydantic ะฒั‹ะฟะพะปะฝะธั‚ ะฝะตะบะพั‚ะพั€ัƒัŽ ะผะฐ {!> ../../../docs_src/response_model/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/response_model/tutorial004.py!} @@ -446,7 +446,7 @@ FastAPI ะดะพัั‚ะฐั‚ะพั‡ะฝะพ ัƒะผะตะฝ (ะฝะฐ ัะฐะผะพะผ ะดะตะปะต, ัั‚ะพ ะทะฐัะป {!> ../../../docs_src/response_model/tutorial005_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="31 37" {!> ../../../docs_src/response_model/tutorial005.py!} @@ -467,7 +467,7 @@ FastAPI ะดะพัั‚ะฐั‚ะพั‡ะฝะพ ัƒะผะตะฝ (ะฝะฐ ัะฐะผะพะผ ะดะตะปะต, ัั‚ะพ ะทะฐัะป {!> ../../../docs_src/response_model/tutorial006_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="31 37" {!> ../../../docs_src/response_model/tutorial006.py!} diff --git a/docs/ru/docs/tutorial/schema-extra-example.md b/docs/ru/docs/tutorial/schema-extra-example.md index a0363b9ba..a13ab5935 100644 --- a/docs/ru/docs/tutorial/schema-extra-example.md +++ b/docs/ru/docs/tutorial/schema-extra-example.md @@ -14,7 +14,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15-23" {!> ../../../docs_src/schema_extra_example/tutorial001.py!} @@ -39,7 +39,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 10-13" {!> ../../../docs_src/schema_extra_example/tutorial002.py!} @@ -78,7 +78,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="23-28" {!> ../../../docs_src/schema_extra_example/tutorial003_an.py!} @@ -93,7 +93,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ะ—ะฐะผะตั‚ะบะฐ ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated`, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. @@ -133,7 +133,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24-50" {!> ../../../docs_src/schema_extra_example/tutorial004_an.py!} @@ -148,7 +148,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ะ—ะฐะผะตั‚ะบะฐ ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตั€ัะธัŽ ั `Annotated`, ะตัะปะธ ัั‚ะพ ะฒะพะทะผะพะถะฝะพ. diff --git a/docs/ru/docs/tutorial/testing.md b/docs/ru/docs/tutorial/testing.md index 3f9005112..ca47a6f51 100644 --- a/docs/ru/docs/tutorial/testing.md +++ b/docs/ru/docs/tutorial/testing.md @@ -122,7 +122,7 @@ {!> ../../../docs_src/app_testing/app_b_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/app_testing/app_b_an/main.py!} @@ -137,7 +137,7 @@ {!> ../../../docs_src/app_testing/app_b_py310/main.py!} ``` -=== "Python 3.6+ ะฑะตะท Annotated" +=== "Python 3.8+ ะฑะตะท Annotated" !!! tip "ะŸะพะดัะบะฐะทะบะฐ" ะŸะพ ะฒะพะทะผะพะถะฝะพัั‚ะธ ะธัะฟะพะปัŒะทัƒะนั‚ะต ะฒะตั€ัะธัŽ ั `Annotated`. diff --git a/docs/tr/docs/features.md b/docs/tr/docs/features.md index f8220fb58..8b143ffe7 100644 --- a/docs/tr/docs/features.md +++ b/docs/tr/docs/features.md @@ -27,7 +27,7 @@ OpenAPI standartlarฤฑna dayalฤฑ olan bir framework olarak, geliลŸtiricilerin bir ### Sadece modern Python -Tamamiyle standartlar **Python 3.6**'nฤฑn type hintlerine dayanฤฑyor (Pydantic'in sayesinde). Yeni bir syntax รถฤŸrenmene gerek yok. Sadece modern Python. +Tamamiyle standartlar **Python 3.8**'nฤฑn type hintlerine dayanฤฑyor (Pydantic'in sayesinde). Yeni bir syntax รถฤŸrenmene gerek yok. Sadece modern Python. EฤŸer Python type hintlerini bilmiyorsan veya bir hatฤฑrlatmaya ihtiyacฤฑn var ise(FastAPI kullanmasan bile) ลŸu iki dakikalฤฑk kรผรงรผk bilgilendirici iรงeriฤŸe bir gรถz at: [Python Types](python-types.md){.internal-link target=_blank}. diff --git a/docs/tr/docs/index.md b/docs/tr/docs/index.md index e74efbc2f..e61f5b82c 100644 --- a/docs/tr/docs/index.md +++ b/docs/tr/docs/index.md @@ -24,7 +24,7 @@ --- -FastAPI, Python 3.6+'nฤฑn standart type hintlerine dayanan modern ve hฤฑzlฤฑ (yรผksek performanslฤฑ) API'lar oluลŸturmak iรงin kullanฤฑlabilecek web framework'รผ. +FastAPI, Python 3.8+'nฤฑn standart type hintlerine dayanan modern ve hฤฑzlฤฑ (yรผksek performanslฤฑ) API'lar oluลŸturmak iรงin kullanฤฑlabilecek web framework'รผ. Ana รถzellikleri: @@ -115,7 +115,7 @@ EฤŸer API yerine komut satฤฑrฤฑ uygulamasฤฑ ## Gereksinimler -Python 3.7+ +Python 3.8+ FastAPI iki devin omuzlarฤฑ รผstรผnde duruyor: @@ -331,7 +331,7 @@ Type-hinting iลŸlemini Python dilindeki standart veri tipleri ile yapabilirsin Yeni bir syntax'e alฤฑลŸmana gerek yok, metodlar ve classlar zaten spesifik kรผtรผphanelere ait. -Sadece standart **Python 3.6+**. +Sadece standart **Python 3.8+**. ร–rnek olarak, `int` tanฤฑmlamak iรงin: diff --git a/docs/uk/docs/alternatives.md b/docs/uk/docs/alternatives.md new file mode 100644 index 000000000..e71257976 --- /dev/null +++ b/docs/uk/docs/alternatives.md @@ -0,0 +1,412 @@ +# ะะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะธ, ะฝะฐั‚ั…ะฝะตะฝะฝั ั‚ะฐ ะฟะพั€ั–ะฒะฝัะฝะฝั + +ะฉะพ ะฝะฐะดะธั…ะฝัƒะปะพ ะฝะฐ ัั‚ะฒะพั€ะตะฝะฝั **FastAPI**, ัะบะธะน ะฒั–ะฝ ัƒ ะฟะพั€ั–ะฝัะฝะฝั– ะท ั–ะฝัˆะธะผะธ ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฐะผะธ ั‚ะฐ ั‡ะพะณะพ ะฒั–ะฝ ัƒ ะฝะธั… ะฝะฐะฒั‡ะธะฒัั. + +## ะ’ัั‚ัƒะฟ + +**FastAPI** ะฝะต ั–ัะฝัƒะฒะฐะปะพ ะฑ, ัะบะฑะธ ะฝะต ะฟะพะฟะตั€ะตะดะฝั– ั€ะพะฑะพั‚ะธ ั–ะฝัˆะธั…. + +ะ ะฐะฝั–ัˆะต ะฑัƒะปะพ ัั‚ะฒะพั€ะตะฝะพ ะฑะฐะณะฐั‚ะพ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ, ัะบั– ะฝะฐะดะธั…ะฝัƒะปะธ ะฝะฐ ะนะพะณะพ ัั‚ะฒะพั€ะตะฝะฝั. + +ะฏ ะบั–ะปัŒะบะฐ ั€ะพะบั–ะฒ ัƒะฝะธะบะฐะฒ ัั‚ะฒะพั€ะตะฝะฝั ะฝะพะฒะพะณะพ ั„ั€ะตะนะผะฒะพั€ะบัƒ. ะกะฟะพั‡ะฐั‚ะบัƒ ั ัะฟั€ะพะฑัƒะฒะฐะฒ ะฒะธั€ั–ัˆะธั‚ะธ ะฒัั– ั„ัƒะฝะบั†ั–ั—, ะพั…ะพะฟะปะตะฝั– **FastAPI**, ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ ะฑะฐะณะฐั‚ะพ ั€ั–ะทะฝะธั… ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ, ะฟะปะฐะณั–ะฝั–ะฒ ั‚ะฐ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ. + +ะะปะต ะฒ ัะบะธะนััŒ ะผะพะผะตะฝั‚ ะฝะต ะฑัƒะปะพ ั–ะฝัˆะพะณะพ ะฒะธั…ะพะดัƒ, ะพะบั€ั–ะผ ัั‚ะฒะพั€ะตะฝะฝั ั‡ะพะณะพััŒ, ั‰ะพ ะฝะฐะดะฐะฒะฐะปะพ ะฑ ัƒัั– ั†ั– ั„ัƒะฝะบั†ั–ั—, ะฒะทัะฒัˆะธ ะฝะฐะนะบั€ะฐั‰ั– ั–ะดะตั— ะท ะฟะพะฟะตั€ะตะดะฝั–ั… ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ ั– ะฟะพั”ะดะฝะฐะฒัˆะธ ั—ั… ะฝะฐะนะบั€ะฐั‰ะธะผ ั‡ะธะฝะพะผ, ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ ะผะพะฒะฝั– ั„ัƒะฝะบั†ั–ั—, ัะบั– ะฝะฐะฒั–ั‚ัŒ ะฝะต ะฑัƒะปะธ ะดะพัั‚ัƒะฟะฝั– ั€ะฐะฝั–ัˆะต (Python 3.6+ ะฟั–ะดะบะฐะทะบะธ ั‚ะธะฟั–ะฒ). + +## ะŸะพะฟะตั€ะตะดะฝั– ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะธ + +### Django + +ะฆะต ะฝะฐะนะฟะพะฟัƒะปัั€ะฝั–ัˆะธะน ั„ั€ะตะนะผะฒะพั€ะบ Python, ัะบะธะน ะบะพั€ะธัั‚ัƒั”ั‚ัŒัั ัˆะธั€ะพะบะพัŽ ะดะพะฒั–ั€ะพัŽ. ะ’ั–ะฝ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ะดะปั ัั‚ะฒะพั€ะตะฝะฝั ั‚ะฐะบะธั… ัะธัั‚ะตะผ, ัะบ Instagram. + +ะ’ั–ะฝ ะฒั–ะดะฝะพัะฝะพ ั‚ั–ัะฝะพ ะฟะพะฒโ€™ัะทะฐะฝะธะน ะท ั€ะตะปัั†ั–ะนะฝะธะผะธ ะฑะฐะทะฐะผะธ ะดะฐะฝะธั… (ะฝะฐะฟั€ะธะบะปะฐะด, MySQL ะฐะฑะพ PostgreSQL), ั‚ะพะผัƒ ะผะฐั‚ะธ ะฑะฐะทัƒ ะดะฐะฝะธั… NoSQL (ะฝะฐะฟั€ะธะบะปะฐะด, Couchbase, MongoDB, Cassandra ั‚ะพั‰ะพ) ัะบ ะพัะฝะพะฒะฝะธะน ะผะตั…ะฐะฝั–ะทะผ ะทะฑะตั€ั–ะณะฐะฝะฝั ะฝะต ะดัƒะถะต ะฟั€ะพัั‚ะพ. + +ะ’ั–ะฝ ะฑัƒะฒ ัั‚ะฒะพั€ะตะฝะธะน ะดะปั ัั‚ะฒะพั€ะตะฝะฝั HTML ัƒ ัะตั€ะฒะตั€ะฝั–ะน ั‡ะฐัั‚ะธะฝั–, ะฐ ะฝะต ะดะปั ัั‚ะฒะพั€ะตะฝะฝั API, ัะบั– ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‚ัŒัั ััƒั‡ะฐัะฝะธะผ ั–ะฝั‚ะตั€ั„ะตะนัะพะผ (ัะบ-ะพั‚ React, Vue.js ั– Angular) ะฐะฑะพ ั–ะฝัˆะธะผะธ ัะธัั‚ะตะผะฐะผะธ (ัะบ-ะพั‚ IoT ะฟั€ะธัั‚ั€ะพั—), ัะบั– ัะฟั–ะปะบัƒัŽั‚ัŒัั ะท ะฝะธะผ. + +### Django REST Framework + +ะคั€ะตะนะผะฒะพั€ะบ Django REST ะฑัƒะฒ ัั‚ะฒะพั€ะตะฝะธะน ัะบ ะณะฝัƒั‡ะบะธะน ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะฐั€ั–ะน ะดะปั ัั‚ะฒะพั€ะตะฝะฝั ะฒะตะฑ-ั–ะฝั‚ะตั€ั„ะตะนัั–ะฒ API ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ Django ะฒ ะพัะฝะพะฒั–, ั‰ะพะฑ ะฟะพะบั€ะฐั‰ะธั‚ะธ ะนะพะณะพ ะผะพะถะปะธะฒะพัั‚ั– API. + +ะ™ะพะณะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‚ัŒ ะฑะฐะณะฐั‚ะพ ะบะพะผะฟะฐะฝั–ะน, ะฒะบะปัŽั‡ะฐัŽั‡ะธ Mozilla, Red Hat ั– Eventbrite. + +ะฆะต ะฑัƒะฒ ะพะดะธะฝ ั–ะท ะฟะตั€ัˆะธั… ะฟั€ะธะบะปะฐะดั–ะฒ **ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั— ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— API**, ั– ัะฐะผะต ั†ะต ะฑัƒะปะฐ ะพะดะฝะฐ ะท ะฟะตั€ัˆะธั… ั–ะดะตะน, ัะบะฐ ะฝะฐะดะธั…ะฝัƒะปะฐ ะฝะฐ ยซะฟะพัˆัƒะบยป **FastAPI**. + +!!! ะŸั€ะธะผั–ั‚ะบะฐ + Django REST Framework ัั‚ะฒะพั€ะธะฒ ะขะพะผ ะšั€ั–ัั‚ั–. ะขะพะน ัะฐะผะธะน ั‚ะฒะพั€ะตั†ัŒ Starlette ั– Uvicorn, ะฝะฐ ัะบะธั… ะฑะฐะทัƒั”ั‚ัŒัั **FastAPI**. + + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะœะฐั‚ะธ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะธะน ะฒะตะฑ-ั–ะฝั‚ะตั€ั„ะตะนั ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— API. + +### Flask + +Flask โ€” ั†ะต ยซะผั–ะบั€ะพั„ั€ะตะนะผะฒะพั€ะบยป, ะฒั–ะฝ ะฝะต ะฒะบะปัŽั‡ะฐั” ั–ะฝั‚ะตะณั€ะฐั†ั–ัŽ ะฑะฐะทะธ ะดะฐะฝะธั…, ะฐ ั‚ะฐะบะพะถ ะฑะฐะณะฐั‚ะพ ั€ะตั‡ะตะน, ัะบั– ะทะฐ ะทะฐะผะพะฒั‡ัƒะฒะฐะฝะฝัะผ ั” ะฒ Django. + +ะฆั ะฟั€ะพัั‚ะพั‚ะฐ ั‚ะฐ ะณะฝัƒั‡ะบั–ัั‚ัŒ ะดะพะทะฒะพะปััŽั‚ัŒ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะฑะฐะทะธ ะดะฐะฝะธั… NoSQL ัะบ ะพัะฝะพะฒะฝัƒ ัะธัั‚ะตะผัƒ ะทะฑะตั€ั–ะณะฐะฝะฝั ะดะฐะฝะธั…. + +ะžัะบั–ะปัŒะบะธ ะฒั–ะฝ ะดัƒะถะต ะฟั€ะพัั‚ะธะน, ะฒั–ะฝ ะฟะพั€ั–ะฒะฝัะฝะพ ะปะตะณะบะธะน ั‚ะฐ ั–ะฝั‚ัƒั—ั‚ะธะฒะฝะธะน ะดะปั ะพัะฒะพั”ะฝะฝั, ั…ะพั‡ะฐ ะฒ ะดะตัะบะธั… ะผะพะผะตะฝั‚ะฐั… ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั ัั‚ะฐั” ะดะตั‰ะพ ั‚ะตั…ะฝั–ั‡ะฝะพัŽ. + +ะ’ั–ะฝ ั‚ะฐะบะพะถ ะทะฐะทะฒะธั‡ะฐะน ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ะดะปั ั–ะฝัˆะธั… ะฟั€ะพะณั€ะฐะผ, ัะบะธะผ ะฝะต ะพะฑะพะฒโ€™ัะทะบะพะฒะพ ะฟะพั‚ั€ั–ะฑะฝะฐ ะฑะฐะทะฐ ะดะฐะฝะธั…, ะบะตั€ัƒะฒะฐะฝะฝั ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐะผะธ ะฐะฑะพ ะฑัƒะดัŒ-ัะบะฐ ะท ะฑะฐะณะฐั‚ัŒะพั… ั„ัƒะฝะบั†ั–ะน, ัะบั– ั” ะฟะพะฟะตั€ะตะดะฝัŒะพ ะฒะฑัƒะดะพะฒะฐะฝะธะผะธ ะฒ Django. ะฅะพั‡ะฐ ะฑะฐะณะฐั‚ะพ ะท ั†ะธั… ั„ัƒะฝะบั†ั–ะน ะผะพะถะฝะฐ ะดะพะดะฐั‚ะธ ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ะฟะปะฐะณั–ะฝั–ะฒ. + +ะ’ั–ะดะพะบั€ะตะผะปะตะฝะฝั ั‡ะฐัั‚ะธะฝ ะฑัƒะปะพ ะบะปัŽั‡ะพะฒะพัŽ ะพัะพะฑะปะธะฒั–ัั‚ัŽ, ัะบัƒ ั ั…ะพั‚ั–ะฒ ะทะฑะตั€ะตะณั‚ะธ, ะฟั€ะธ ั†ัŒะพะผัƒ ะทะฐะปะธัˆะฐัŽั‡ะธััŒ ยซะผั–ะบั€ะพั„ั€ะตะนะผะฒะพั€ะบะพะผยป, ัะบะธะน ะผะพะถะฝะฐ ั€ะพะทัˆะธั€ะธั‚ะธ, ั‰ะพะฑ ะพั…ะพะฟะธั‚ะธ ัะฐะผะต ั‚ะต, ั‰ะพ ะฟะพั‚ั€ั–ะฑะฝะพ. + +ะ’ั€ะฐั…ะพะฒัƒัŽั‡ะธ ะฟั€ะพัั‚ะพั‚ัƒ Flask, ะฒั–ะฝ ะทะดะฐะฒะฐะฒัั ั…ะพั€ะพัˆะธะผ ะฟั–ะดั…ะพะดะพะผ ะดะปั ัั‚ะฒะพั€ะตะฝะฝั API. ะะฐัั‚ัƒะฟะฝะธะผ, ั‰ะพ ะทะฝะฐะนัˆะพะฒ, ะฑัƒะฒ ยซDjango REST Frameworkยป ะดะปั Flask. + +!!! ะŸะตั€ะตะณะปัะฝั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะ‘ัƒั‚ะธ ะผั–ะบั€ะพั„ั€ะตะนะผะพะฒะพั€ะบะพะผ. ะ—ั€ะพะฑะธั‚ะธ ะปะตะณะบะธะผ ะบะพะผะฑั–ะฝัƒะฒะฐะฝะฝั ั‚ะฐ ะฟะพั”ะดะฝะฐะฝะฝั ะฝะตะพะฑั…ั–ะดะฝะธั… ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ ั‚ะฐ ั‡ะฐัั‚ะธะฝ. + + ะœะฐั‚ะธ ะฟั€ะพัั‚ัƒ ั‚ะฐ ะปะตะณะบัƒ ัƒ ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั– ัะธัั‚ะตะผัƒ ะผะฐั€ัˆั€ัƒั‚ะธะทะฐั†ั–ั—. + + +### Requests + +**FastAPI** ะฝะฐัะฟั€ะฐะฒะดั– ะฝะต ั” ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะพัŽ **Requests**. ะกั„ะตั€ะฐ ั—ั… ะทะฐัั‚ะพััƒะฒะฐะฝะฝั ะดัƒะถะต ั€ั–ะทะฝะฐ. + +ะะฐัะฟั€ะฐะฒะดั– ั†ั–ะปะบะพะผ ะทะฒะธั‡ะฝะฐ ั€ั–ั‡ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ Requests *ะฒัะตั€ะตะดะธะฝั–* ะฟั€ะพะณั€ะฐะผะธ FastAPI. + +ะะปะต ะฒัะต ะถ FastAPI ั‡ะตั€ะฟะฐะฒ ะฝะฐั‚ั…ะฝะตะฝะฝั ะท Requests. + +**Requests** โ€” ั†ะต ะฑั–ะฑะปั–ะพั‚ะตะบะฐ ะดะปั *ะฒะทะฐั”ะผะพะดั–ั—* ะท API (ัะบ ะบะปั–ั”ะฝั‚), ะฐ **FastAPI** โ€” ั†ะต ะฑั–ะฑะปั–ะพั‚ะตะบะฐ ะดะปั *ัั‚ะฒะพั€ะตะฝะฝั* API (ัะบ ัะตั€ะฒะตั€). + +ะ’ะพะฝะธ ะฑั–ะปัŒัˆ-ะผะตะฝัˆ ะทะฝะฐั…ะพะดัั‚ัŒัั ะฝะฐ ะฟั€ะพั‚ะธะปะตะถะฝะธั… ะบั–ะฝั†ัั…, ะดะพะฟะพะฒะฝัŽัŽั‡ะธ ะพะดะฝะฐ ะพะดะฝัƒ. + +Requests ะผะฐัŽั‚ัŒ ะดัƒะถะต ะฟั€ะพัั‚ะธะน ั‚ะฐ ั–ะฝั‚ัƒั—ั‚ะธะฒะฝะพ ะทั€ะพะทัƒะผั–ะปะธะน ะดะธะทะฐะนะฝ, ะดัƒะถะต ะฟั€ะพัั‚ะธะน ัƒ ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั–, ะท ั€ะพะทัƒะผะฝะธะผะธ ะฟะฐั€ะฐะผะตั‚ั€ะฐะผะธ ะทะฐ ะทะฐะผะพะฒั‡ัƒะฒะฐะฝะฝัะผ. ะะปะต ะฒ ั‚ะพะน ะถะต ั‡ะฐั ะฒั–ะฝ ะดัƒะถะต ะฟะพั‚ัƒะถะฝะธะน ั– ะฝะฐะปะฐัˆั‚ะพะฒัƒั”ั‚ัŒัั. + +ะžััŒ ั‡ะพะผัƒ, ัะบ ัะบะฐะทะฐะฝะพ ะฝะฐ ะพั„ั–ั†ั–ะนะฝะพะผัƒ ัะฐะนั‚ั–: + +> Requests ั” ะพะดะฝะธะผ ั–ะท ะฝะฐะนะฑั–ะปัŒัˆ ะทะฐะฒะฐะฝั‚ะฐะถัƒะฒะฐะฝะธั… ะฟะฐะบะตั‚ั–ะฒ Python ัƒัั–ั… ั‡ะฐัั–ะฒ + +ะ’ะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะนะพะณะพ ะดัƒะถะต ะฟั€ะพัั‚ะพ. ะะฐะฟั€ะธะบะปะฐะด, ั‰ะพะฑ ะฒะธะบะพะฝะฐั‚ะธ ะทะฐะฟะธั‚ `GET`, ะฒะธ ะฟะพะฒะธะฝะฝั– ะฝะฐะฟะธัะฐั‚ะธ: + +```Python +response = requests.get("http://example.com/some/url") +``` + +ะ’ั–ะดะฟะพะฒั–ะดะฝะฐ ะพะฟะตั€ะฐั†ั–ั *ั€ะพัƒั‚ัƒ* API FastAPI ะผะพะถะต ะฒะธะณะปัะดะฐั‚ะธ ั‚ะฐะบ: + +```Python hl_lines="1" +@app.get("/some/url") +def read_url(): + return {"message": "Hello World"} +``` + +ะ—ะฒะตั€ะฝั–ั‚ัŒ ัƒะฒะฐะณัƒ ะฝะฐ ัั…ะพะถั–ัั‚ัŒ ัƒ `requests.get(...)` ั– `@app.get(...)`. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + * ะœะฐะนั‚ะต ะฟั€ะพัั‚ะธะน ั‚ะฐ ั–ะฝั‚ัƒั—ั‚ะธะฒะฝะพ ะทั€ะพะทัƒะผั–ะปะธะน API. + * ะ’ะธะบะพั€ะธัั‚ะพะฒัƒะนั‚ะต ั–ะผะตะฝะฐ (ะพะฟะตั€ะฐั†ั–ั—) ะผะตั‚ะพะดั–ะฒ HTTP ะฑะตะทะฟะพัะตั€ะตะดะฝัŒะพ, ะฟั€ะพัั‚ะธะผ ั‚ะฐ ั–ะฝั‚ัƒั—ั‚ะธะฒะฝะพ ะทั€ะพะทัƒะผั–ะปะธะผ ัะฟะพัะพะฑะพะผ. + * ะ ะพะทัƒะผะฝั– ะฟะฐั€ะฐะผะตั‚ั€ะธ ะทะฐ ะทะฐะผะพะฒั‡ัƒะฒะฐะฝะฝัะผ, ะฐะปะต ะฟะพั‚ัƒะถะฝั– ะฝะฐะปะฐัˆั‚ัƒะฒะฐะฝะฝั. + + +### Swagger / OpenAPI + +ะ“ะพะปะพะฒะฝะพัŽ ั„ัƒะฝะบั†ั–ั”ัŽ, ัะบัƒ ั ั…ะพั‚ั–ะฒ ะฒั–ะด Django REST Framework, ะฑัƒะปะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะฐ API ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั. + +ะŸะพั‚ั–ะผ ั ะฒะธัะฒะธะฒ, ั‰ะพ ั–ัะฝัƒั” ัั‚ะฐะฝะดะฐั€ั‚ ะดะปั ะดะพะบัƒะผะตะฝั‚ัƒะฒะฐะฝะฝั API ะท ะฒะธะบะพั€ะธัั‚ะฐะฝะฝัะผ JSON (ะฐะฑะพ YAML, ั€ะพะทัˆะธั€ะตะฝะฝั JSON) ะฟั–ะด ะฝะฐะทะฒะพัŽ Swagger. + +ะ† ะฒะถะต ะฑัƒะฒ ัั‚ะฒะพั€ะตะฝะธะน ะฒะตะฑ-ั–ะฝั‚ะตั€ั„ะตะนั ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ ะดะปั Swagger API. ะžั‚ะถะต, ะผะพะถะปะธะฒั–ัั‚ัŒ ะณะตะฝะตั€ัƒะฒะฐั‚ะธ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ัŽ Swagger ะดะปั API ะดะพะทะฒะพะปะธั‚ัŒ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ั†ะตะน ะฒะตะฑ-ั–ะฝั‚ะตั€ั„ะตะนั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ. + +ะฃ ัะบะธะนััŒ ะผะพะผะตะฝั‚ Swagger ะฑัƒะปะพ ะฟะตั€ะตะดะฐะฝะพ Linux Foundation, ั‰ะพะฑ ะฟะตั€ะตะนะผะตะฝัƒะฒะฐั‚ะธ ะนะพะณะพ ะฝะฐ OpenAPI. + +ะขะพะผัƒ, ะบะพะปะธ ะณะพะฒะพั€ัั‚ัŒ ะฟั€ะพ ะฒะตั€ัั–ัŽ 2.0, ะฟั€ะธะนะฝัั‚ะพ ะณะพะฒะพั€ะธั‚ะธ ยซSwaggerยป, ะฐ ะฟั€ะพ ะฒะตั€ัั–ัŽ 3+ ยซOpenAPIยป. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะŸั€ะธะนะฝัั‚ะธ ั– ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะฒั–ะดะบั€ะธั‚ะธะน ัั‚ะฐะฝะดะฐั€ั‚ ะดะปั ัะฟะตั†ะธั„ั–ะบะฐั†ั–ะน API ะทะฐะผั–ัั‚ัŒ ัะฟะตั†ั–ะฐะปัŒะฝะพั— ัั…ะตะผะธ. + + ะ†ะฝั‚ะตะณั€ัƒะฒะฐั‚ะธ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะธ ั–ะฝั‚ะตั€ั„ะตะนััƒ ะฝะฐ ะพัะฝะพะฒั– ัั‚ะฐะฝะดะฐั€ั‚ั–ะฒ: + + * ะ†ะฝั‚ะตั€ั„ะตะนั Swagger + * ReDoc + + ะฆั– ะดะฒะฐ ะฑัƒะปะพ ะพะฑั€ะฐะฝะพ ั‡ะตั€ะตะท ั‚ะต, ั‰ะพ ะฒะพะฝะธ ะดะพัะธั‚ัŒ ะฟะพะฟัƒะปัั€ะฝั– ั‚ะฐ ัั‚ะฐะฑั–ะปัŒะฝั–, ะฐะปะต, ะฒะธะบะพะฝะฐะฒัˆะธ ัˆะฒะธะดะบะธะน ะฟะพัˆัƒะบ, ะฒะธ ะผะพะถะตั‚ะต ะทะฝะฐะนั‚ะธ ะดะตััั‚ะบะธ ะดะพะดะฐั‚ะบะพะฒะธั… ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฝะธั… ั–ะฝั‚ะตั€ั„ะตะนัั–ะฒ ะดะปั OpenAPI (ัะบั– ะผะพะถะฝะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะท **FastAPI**). + +### ะคั€ะตะนะผะฒะพั€ะบะธ REST ะดะปั Flask + +ะ†ัะฝัƒั” ะบั–ะปัŒะบะฐ ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ Flask REST, ะฐะปะต, ะฒะธั‚ั€ะฐั‚ะธะฒัˆะธ ั‡ะฐั ั– ั€ะพะฑะพั‚ัƒ ะฝะฐ ั—ั… ะดะพัะปั–ะดะถะตะฝะฝั, ั ะฒะธัะฒะธะฒ, ั‰ะพ ะฑะฐะณะฐั‚ะพ ะท ะฝะธั… ะฟั€ะธะฟะธะฝะตะฝะพ ะฐะฑะพ ะทะฐะปะธัˆะตะฝะพ, ะท ะบั–ะปัŒะบะพะผะฐ ะฟะพัั‚ั–ะนะฝะธะผะธ ะฟั€ะพะฑะปะตะผะฐะผะธ, ัะบั– ะทั€ะพะฑะธะปะธ ั—ั… ะฝะตะฟั€ะธะดะฐั‚ะฝะธะผะธ. + +### Marshmallow + +ะžะดะฝั–ั”ัŽ ะท ะณะพะปะพะฒะฝะธั… ั„ัƒะฝะบั†ั–ะน, ะฝะตะพะฑั…ั–ะดะฝะธั… ะดะปั ัะธัั‚ะตะผ API, ั” "ัะตั€ั–ะฐะปั–ะทะฐั†ั–ั", ัะบะฐ ะฑะตั€ะต ะดะฐะฝั– ะท ะบะพะดัƒ (Python) ั– ะฟะตั€ะตั‚ะฒะพั€ัŽั” ั—ั… ะฝะฐ ั‰ะพััŒ, ั‰ะพ ะผะพะถะฝะฐ ะฝะฐะดั–ัะปะฐั‚ะธ ั‡ะตั€ะตะท ะผะตั€ะตะถัƒ. ะะฐะฟั€ะธะบะปะฐะด, ะฟะตั€ะตั‚ะฒะพั€ะตะฝะฝั ะพะฑโ€™ั”ะบั‚ะฐ, ั‰ะพ ะผั–ัั‚ะธั‚ัŒ ะดะฐะฝั– ะท ะฑะฐะทะธ ะดะฐะฝะธั…, ะฝะฐ ะพะฑโ€™ั”ะบั‚ JSON. ะŸะตั€ะตั‚ะฒะพั€ะตะฝะฝั ะพะฑโ€™ั”ะบั‚ั–ะฒ `datetime` ะฝะฐ ัั‚ั€ะพะบะธ ั‚ะพั‰ะพ. + +ะ†ะฝัˆะพัŽ ะฒะฐะถะปะธะฒะพัŽ ั„ัƒะฝะบั†ั–ั”ัŽ, ะฝะตะพะฑั…ั–ะดะฝะพัŽ ะดะปั API, ั” ะฟะตั€ะตะฒั–ั€ะบะฐ ะดะฐะฝะธั…, ัะบะฐ ะทะฐะฑะตะทะฟะตั‡ัƒั” ะดั–ะนัะฝั–ัั‚ัŒ ะดะฐะฝะธั… ะทะฐ ะฟะตะฒะฝะธะผะธ ะฟะฐั€ะฐะผะตั‚ั€ะฐะผะธ. ะะฐะฟั€ะธะบะปะฐะด, ั‰ะพ ะดะตัะบะต ะฟะพะปะต ั” `int`, ะฐ ะฝะต ะดะตัะบะฐ ะฒะธะฟะฐะดะบะพะฒะฐ ัั‚ั€ะพะบะฐ. ะฆะต ะพัะพะฑะปะธะฒะพ ะบะพั€ะธัะฝะพ ะดะปั ะฒั…ั–ะดะฝะธั… ะดะฐะฝะธั…. + +ะ‘ะตะท ัะธัั‚ะตะผะธ ะฟะตั€ะตะฒั–ั€ะบะธ ะดะฐะฝะธั… ะฒะฐะผ ะดะพะฒะตะปะพัั ะฑ ะฒะธะบะพะฝัƒะฒะฐั‚ะธ ะฒัั– ะฟะตั€ะตะฒั–ั€ะบะธ ะฒั€ัƒั‡ะฝัƒ, ัƒ ะบะพะดั–. + +Marshmallow ัั‚ะฒะพั€ะตะฝะพ ะดะปั ะทะฐะฑะตะทะฟะตั‡ะตะฝะฝั ั†ะธั… ั„ัƒะฝะบั†ั–ะน. ะฆะต ั‡ัƒะดะพะฒะฐ ะฑั–ะฑะปั–ะพั‚ะตะบะฐ, ั– ั ั‡ะฐัั‚ะพ ะฝะตัŽ ะบะพั€ะธัั‚ัƒะฒะฐะฒัั ั€ะฐะฝั–ัˆะต. + +ะะปะต ะฒั–ะฝ ะฑัƒะฒ ัั‚ะฒะพั€ะตะฝะธะน ะดะพ ั‚ะพะณะพ, ัะบ ั–ัะฝัƒะฒะฐะปะธ ะฟั–ะดะบะฐะทะบะธ ั‚ะธะฟัƒ Python. ะžั‚ะถะต, ั‰ะพะฑ ะฒะธะทะฝะฐั‡ะธั‚ะธ ะบะพะถะฝัƒ ัั…ะตะผัƒ, ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ัะฟะตั†ั–ะฐะปัŒะฝั– ัƒั‚ะธะปั–ั‚ะธ ั‚ะฐ ะบะปะฐัะธ, ะฝะฐะดะฐะฝั– Marshmallow. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะ’ะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะบะพะด ะดะปั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพะณะพ ะฒะธะทะฝะฐั‡ะตะฝะฝั "ัั…ะตะผ", ัะบั– ะฝะฐะดะฐัŽั‚ัŒ ั‚ะธะฟะธ ะดะฐะฝะธั… ั– ะฟะตั€ะตะฒั–ั€ะบัƒ. + +### Webargs + +ะ†ะฝัˆะพัŽ ะฒะฐะถะปะธะฒะพัŽ ั„ัƒะฝะบั†ั–ั”ัŽ, ะฝะตะพะฑั…ั–ะดะฝะพัŽ ะดะปั API, ั” ะฐะฝะฐะปั–ะท ะดะฐะฝะธั… ั–ะท ะฒั…ั–ะดะฝะธั… ะทะฐะฟะธั‚ั–ะฒ. + +Webargs โ€” ั†ะต ั–ะฝัั‚ั€ัƒะผะตะฝั‚, ัั‚ะฒะพั€ะตะฝะธะน, ั‰ะพะฑ ะทะฐะฑะตะทะฟะตั‡ะธั‚ะธ ั†ะต ะฟะพะฒะตั€ั… ะบั–ะปัŒะบะพั… ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ, ะฒะบะปัŽั‡ะฐัŽั‡ะธ Flask. + +ะ’ั–ะฝ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” Marshmallow ะฒ ะพัะฝะพะฒั– ะดะปั ะฟะตั€ะตะฒั–ั€ะบะธ ะดะฐะฝะธั…. ะ† ัั‚ะฒะพั€ะตะฝะธะน ั‚ะธะผะธ ะถ ั€ะพะทั€ะพะฑะฝะธะบะฐะผะธ. + +ะฆะต ั‡ัƒะดะพะฒะธะน ั–ะฝัั‚ั€ัƒะผะตะฝั‚, ั– ั ั‚ะฐะบะพะถ ั‡ะฐัั‚ะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะฒ ะนะพะณะพ, ะฟะตั€ัˆ ะฝั–ะถ ัั‚ะฒะพั€ะธั‚ะธ **FastAPI**. + +!!! ะ†ะฝั„ะพั€ะผะฐั†ั–ั + Webargs ะฑัƒะฒ ัั‚ะฒะพั€ะตะฝะธะน ั‚ะธะผะธ ะถ ั€ะพะทั€ะพะฑะฝะธะบะฐะผะธ Marshmallow. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะœะฐั‚ะธ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝัƒ ะฟะตั€ะตะฒั–ั€ะบัƒ ะดะฐะฝะธั… ะฒั…ั–ะดะฝะพะณะพ ะทะฐะฟะธั‚ัƒ. + +### APISpec + +Marshmallow ั– Webargs ะทะฐะฑะตะทะฟะตั‡ัƒัŽั‚ัŒ ะฟะตั€ะตะฒั–ั€ะบัƒ, ะฐะฝะฐะปั–ะท ั– ัะตั€ั–ะฐะปั–ะทะฐั†ั–ัŽ ัะบ ะฟะปะฐะณั–ะฝะธ. + +ะะปะต ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั ะดะพัั– ะฒั–ะดััƒั‚ะฝั. ะŸะพั‚ั–ะผ ะฑัƒะปะพ ัั‚ะฒะพั€ะตะฝะพ APISpec. + +ะฆะต ะฟะปะฐะณั–ะฝ ะดะปั ะฑะฐะณะฐั‚ัŒะพั… ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ (ั‚ะฐะบะพะถ ั” ะฟะปะฐะณั–ะฝ ะดะปั Starlette). + +ะŸั€ะธะฝั†ะธะฟ ั€ะพะฑะพั‚ะธ ะฟะพะปัะณะฐั” ะฒ ั‚ะพะผัƒ, ั‰ะพ ะฒะธ ะฟะธัˆะตั‚ะต ะฒะธะทะฝะฐั‡ะตะฝะฝั ัั…ะตะผะธ, ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ ั„ะพั€ะผะฐั‚ YAML, ัƒ docstring ะบะพะถะฝะพั— ั„ัƒะฝะบั†ั–ั—, ั‰ะพ ะพะฑั€ะพะฑะปัั” ะผะฐั€ัˆั€ัƒั‚. + +ะ† ะฒั–ะฝ ะณะตะฝะตั€ัƒั” ัั…ะตะผะธ OpenAPI. + +ะขะฐะบ ั†ะต ะฟั€ะฐั†ัŽั” ัƒ Flask, Starlette, Responder ั‚ะพั‰ะพ. + +ะะปะต ะฟะพั‚ั–ะผ ะผะธ ะทะฝะพะฒัƒ ะผะฐั”ะผะพ ะฟั€ะพะฑะปะตะผัƒ ะฝะฐัะฒะฝะพัั‚ั– ะผั–ะบั€ะพัะธะฝั‚ะฐะบัะธััƒ ะฒัะตั€ะตะดะธะฝั– Python ัั‚ั€ะพะบะธ (ะฒะตะปะธะบะธะน YAML). + +ะ ะตะดะฐะบั‚ะพั€ ั‚ัƒั‚ ะฝั–ั‡ะธะผ ะฝะต ะผะพะถะต ะดะพะฟะพะผะพะณั‚ะธ. ะ† ัะบั‰ะพ ะผะธ ะทะผั–ะฝะธะผะพ ะฟะฐั€ะฐะผะตั‚ั€ะธ ั‡ะธ ัั…ะตะผะธ Marshmallow ั– ะทะฐะฑัƒะดะตะผะพ ั‚ะฐะบะพะถ ะทะผั–ะฝะธั‚ะธ ั†ัŽ ัั‚ั€ะพะบัƒ ะดะพะบัƒะผะตะฝั‚ะฐ YAML, ะทะณะตะฝะตั€ะพะฒะฐะฝะฐ ัั…ะตะผะฐ ะฑัƒะดะต ะทะฐัั‚ะฐั€ั–ะปะพัŽ. + +!!! ะ†ะฝั„ะพั€ะผะฐั†ั–ั + APISpec ะฑัƒะฒ ัั‚ะฒะพั€ะตะฝะธะน ั‚ะธะผะธ ะถ ั€ะพะทั€ะพะฑะฝะธะบะฐะผะธ Marshmallow. + + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะŸั–ะดั‚ั€ะธะผัƒะฒะฐั‚ะธ ะฒั–ะดะบั€ะธั‚ะธะน ัั‚ะฐะฝะดะฐั€ั‚ API, OpenAPI. + +### Flask-apispec + +ะฆะต ะฟะปะฐะณั–ะฝ Flask, ัะบะธะน ะพะฑโ€™ั”ะดะฝัƒั” Webargs, Marshmallow ั– APISpec. + +ะ’ั–ะฝ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ั–ะฝั„ะพั€ะผะฐั†ั–ัŽ ะท Webargs ั– Marshmallow ะดะปั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพะณะพ ัั‚ะฒะพั€ะตะฝะฝั ัั…ะตะผ OpenAPI ะทะฐ ะดะพะฟะพะผะพะณะพัŽ APISpec. + +ะฆะต ั‡ัƒะดะพะฒะธะน ั–ะฝัั‚ั€ัƒะผะตะฝั‚, ะดัƒะถะต ะฝะตะดะพะพั†ั–ะฝะตะฝะธะน. ะ’ั–ะฝ ะผะฐั” ะฑัƒั‚ะธ ะฝะฐะฑะฐะณะฐั‚ะพ ะฟะพะฟัƒะปัั€ะฝั–ัˆะธะผ, ะฝั–ะถ ะฑะฐะณะฐั‚ะพ ะฟะปะฐะณั–ะฝั–ะฒ Flask. ะฆะต ะผะพะถะต ะฑัƒั‚ะธ ะฟะพะฒโ€™ัะทะฐะฝะพ ะท ั‚ะธะผ, ั‰ะพ ะนะพะณะพ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั ะฝะฐะดั‚ะพ ัั‚ะธัะปะฐ ะน ะฐะฑัั‚ั€ะฐะบั‚ะฝะฐ. + +ะฆะต ะฒะธั€ั–ัˆะธะปะพ ะฝะตะพะฑั…ั–ะดะฝั–ัั‚ัŒ ะฟะธัะฐั‚ะธ YAML (ั–ะฝัˆะธะน ัะธะฝั‚ะฐะบัะธั) ะฒัะตั€ะตะดะธะฝั– ั€ัะดะบั–ะฒ ะดะพะบัƒะผะตะฝั‚ั–ะฒ Python. + +ะฆั ะบะพะผะฑั–ะฝะฐั†ั–ั Flask, Flask-apispec ั–ะท Marshmallow ั– Webargs ะฑัƒะปะฐ ะผะพั—ะผ ัƒะปัŽะฑะปะตะฝะธะผ ะฑะตะบะตะฝะด-ัั‚ะตะบะพะผ ะดะพ ัั‚ะฒะพั€ะตะฝะฝั **FastAPI**. + +ะ‡ั– ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั ะฟั€ะธะทะฒะตะปะพ ะดะพ ัั‚ะฒะพั€ะตะฝะฝั ะบั–ะปัŒะบะพั… ะณะตะฝะตั€ะฐั‚ะพั€ั–ะฒ ะฟะพะฒะฝะพะณะพ ัั‚ะตะบะฐ Flask. ะฆะต ะพัะฝะพะฒะฝะธะน ัั‚ะตะบ, ัะบะธะน ั (ั‚ะฐ ะบั–ะปัŒะบะฐ ะทะพะฒะฝั–ัˆะฝั–ั… ะบะพะผะฐะฝะด) ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะฒ ะดะพัั–: + +* https://github.com/tiangolo/full-stack +* https://github.com/tiangolo/full-stack-flask-couchbase +* https://github.com/tiangolo/full-stack-flask-couchdb + +ะ† ั†ั– ัะฐะผั– ะณะตะฝะตั€ะฐั‚ะพั€ะธ ะฟะพะฒะฝะพะณะพ ัั‚ะตะบัƒ ะฑัƒะปะธ ะพัะฝะพะฒะพัŽ [**FastAPI** ะณะตะฝะตั€ะฐั‚ะพั€ั–ะฒ ะฟั€ะพะตะบั‚ั–ะฒ](project-generation.md){.internal-link target=_blank}. + +!!! ะ†ะฝั„ะพั€ะผะฐั†ั–ั + Flask-apispec ะฑัƒะฒ ัั‚ะฒะพั€ะตะฝะธะน ั‚ะธะผะธ ะถ ั€ะพะทั€ะพะฑะฝะธะบะฐะผะธ Marshmallow. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะกั‚ะฒะพั€ะตะฝะฝั ัั…ะตะผะธ OpenAPI ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะท ั‚ะพะณะพ ัะฐะผะพะณะพ ะบะพะดัƒ, ัะบะธะน ะฒะธะทะฝะฐั‡ะฐั” ัะตั€ั–ะฐะปั–ะทะฐั†ั–ัŽ ั‚ะฐ ะฟะตั€ะตะฒั–ั€ะบัƒ. + +### NestJS (ั‚ะฐ Angular) + +ะฆะต ะฝะฐะฒั–ั‚ัŒ ะฝะต Python, NestJS โ€” ั†ะต ั„ั€ะตะนะผะฒะพั€ะบ NodeJS JavaScript (TypeScript), ะฝะฐั‚ั…ะฝะตะฝะฝะธะน Angular. + +ะฆะต ะดะพััะณะฐั” ั‡ะพะณะพััŒ ะฟะพะดั–ะฑะฝะพะณะพ ะดะพ ั‚ะพะณะพ, ั‰ะพ ะผะพะถะฝะฐ ะทั€ะพะฑะธั‚ะธ ะท Flask-apispec. + +ะ’ั–ะฝ ะผะฐั” ั–ะฝั‚ะตะณั€ะพะฒะฐะฝัƒ ัะธัั‚ะตะผัƒ ะฒะฟั€ะพะฒะฐะดะถะตะฝะฝั ะทะฐะปะตะถะฝะพัั‚ะตะน, ะฝะฐั‚ั…ะฝะตะฝะฝัƒ Angular two. ะ’ั–ะฝ ะฟะพั‚ั€ะตะฑัƒั” ะฟะพะฟะตั€ะตะดะฝัŒะพั— ั€ะตั”ัั‚ั€ะฐั†ั–ั— ยซinjectablesยป (ัะบ ั– ะฒัั– ั–ะฝัˆั– ัะธัั‚ะตะผะธ ะฒะฟั€ะพะฒะฐะดะถะตะฝะฝั ะทะฐะปะตะถะฝะพัั‚ะตะน, ัะบั– ั ะทะฝะฐัŽ), ั‚ะพะผัƒ ั†ะต ะทะฑั–ะปัŒัˆัƒั” ะฑะฐะณะฐั‚ะพัะปั–ะฒะฝั–ัั‚ัŒ ั‚ะฐ ะฟะพะฒั‚ะพั€ะตะฝะฝั ะบะพะดัƒ. + +ะžัะบั–ะปัŒะบะธ ะฟะฐั€ะฐะผะตั‚ั€ะธ ะพะฟะธัะฐะฝั– ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ั‚ะธะฟั–ะฒ TypeScript (ะฟะพะดั–ะฑะฝะพ ะดะพ ะฟั–ะดะบะฐะทะพะบ ั‚ะธะฟัƒ Python), ะฟั–ะดั‚ั€ะธะผะบะฐ ั€ะตะดะฐะบั‚ะพั€ะฐ ะดะพัะธั‚ัŒ ั…ะพั€ะพัˆะฐ. + +ะะปะต ะพัะบั–ะปัŒะบะธ ะดะฐะฝั– TypeScript ะฝะต ะทะฑะตั€ั–ะณะฐัŽั‚ัŒัั ะฟั–ัะปั ะบะพะผะฟั–ะปัั†ั–ั— ะฒ JavaScript, ะฒะพะฝะธ ะฝะต ะผะพะถัƒั‚ัŒ ะฟะพะบะปะฐะดะฐั‚ะธัั ะฝะฐ ั‚ะธะฟะธ ะดะปั ะฒะธะทะฝะฐั‡ะตะฝะฝั ะฟะตั€ะตะฒั–ั€ะบะธ, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ั— ั‚ะฐ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— ะพะดะฝะพั‡ะฐัะฝะพ. ะงะตั€ะตะท ั†ะต ั‚ะฐ ะดะตัะบั– ะดะธะทะฐะนะฝะตั€ััŒะบั– ั€ั–ัˆะตะฝะฝั, ั‰ะพะฑ ะพั‚ั€ะธะผะฐั‚ะธ ะฟะตั€ะตะฒั–ั€ะบัƒ, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ัŽ ั‚ะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝัƒ ะณะตะฝะตั€ะฐั†ั–ัŽ ัั…ะตะผะธ, ะฟะพั‚ั€ั–ะฑะฝะพ ะดะพะดะฐั‚ะธ ะดะตะบะพั€ะฐั‚ะพั€ะธ ะฒ ะฑะฐะณะฐั‚ัŒะพั… ะผั–ัั†ัั…. ะขะฐะบะธะผ ั‡ะธะฝะพะผ ะบะพะด ัั‚ะฐั” ะดะพัะธั‚ัŒ ะฑะฐะณะฐั‚ะพัะปั–ะฒะฝะธะผ. + +ะ’ั–ะฝ ะฝะต ะดัƒะถะต ะดะพะฑั€ะต ะพะฑั€ะพะฑะปัั” ะฒะบะปะฐะดะตะฝั– ะผะพะดะตะปั–. ะžั‚ะถะต, ัะบั‰ะพ ั‚ั–ะปะพ JSON ัƒ ะทะฐะฟะธั‚ั– ั” ะพะฑโ€™ั”ะบั‚ะพะผ JSON ั–ะท ะฒะฝัƒั‚ั€ั–ัˆะฝั–ะผะธ ะฟะพะปัะผะธ, ัะบั–, ัƒ ัะฒะพัŽ ั‡ะตั€ะณัƒ, ั” ะฒะบะปะฐะดะตะฝะธะผะธ ะพะฑโ€™ั”ะบั‚ะฐะผะธ JSON, ะนะพะณะพ ะฝะตะผะพะถะปะธะฒะพ ะฝะฐะปะตะถะฝะธะผ ั‡ะธะฝะพะผ ะทะฐะดะพะบัƒะผะตะฝั‚ัƒะฒะฐั‚ะธ ั‚ะฐ ะฟะตั€ะตะฒั–ั€ะธั‚ะธ. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะ’ะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ั‚ะธะฟะธ Python, ั‰ะพะฑ ะผะฐั‚ะธ ั‡ัƒะดะพะฒัƒ ะฟั–ะดั‚ั€ะธะผะบัƒ ั€ะตะดะฐะบั‚ะพั€ะฐ. + + ะœะฐั‚ะธ ะฟะพั‚ัƒะถะฝัƒ ัะธัั‚ะตะผัƒ ะฒะฟั€ะพะฒะฐะดะถะตะฝะฝั ะทะฐะปะตะถะฝะพัั‚ะตะน. ะ—ะฝะฐะนะดั–ั‚ัŒ ัะฟะพัั–ะฑ ะทะฒะตัั‚ะธ ะดะพ ะผั–ะฝั–ะผัƒะผัƒ ะฟะพะฒั‚ะพั€ะตะฝะฝั ะบะพะดัƒ. + +### Sanic + +ะฆะต ะฑัƒะฒ ะพะดะธะฝ ั–ะท ะฟะตั€ัˆะธั… ะฝะฐะดะทะฒะธั‡ะฐะนะฝะพ ัˆะฒะธะดะบะธั… ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ Python ะฝะฐ ะพัะฝะพะฒั– `asyncio`. ะ’ั–ะฝ ะฑัƒะฒ ะดัƒะถะต ัั…ะพะถะธะน ะฝะฐ Flask. + +!!! ะŸั€ะธะผั–ั‚ะบะฐ "ะขะตั…ะฝั–ั‡ะฝั– ะดะตั‚ะฐะปั–" + ะ’ั–ะฝ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะฒ `uvloop` ะทะฐะผั–ัั‚ัŒ ัั‚ะฐะฝะดะฐั€ั‚ะฝะพะณะพ ั†ะธะบะปัƒ Python `asyncio`. ะžััŒ ั‰ะพ ะทั€ะพะฑะธะปะพ ะนะพะณะพ ั‚ะฐะบะธะผ ัˆะฒะธะดะบะธะผ. + + ะฆะต ัะฒะฝะพ ะฝะฐะดะธั…ะฝัƒะปะพ Uvicorn ั– Starlette, ัะบั– ะทะฐั€ะฐะท ัˆะฒะธะดัˆั– ะทะฐ Sanic ัƒ ะฒั–ะดะบั€ะธั‚ะธั… ั‚ะตัั‚ะฐั…. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะ—ะฝะฐะนั‚ะธ ัะฟะพัั–ะฑ ะพั‚ั€ะธะผะฐั‚ะธ ะฑะพะถะตะฒั–ะปัŒะฝัƒ ะฟั€ะพะดัƒะบั‚ะธะฒะฝั–ัั‚ัŒ. + + ะžััŒ ั‡ะพะผัƒ **FastAPI** ะฑะฐะทัƒั”ั‚ัŒัั ะฝะฐ Starlette, ะพัะบั–ะปัŒะบะธ ั†ะต ะฝะฐะนัˆะฒะธะดัˆะฐ ะดะพัั‚ัƒะฟะฝะฐ ัั‚ั€ัƒะบั‚ัƒั€ะฐ (ะฟะตั€ะตะฒั–ั€ะตะฝะฐ ั‚ะตัั‚ะฐะผะธ ัั‚ะพั€ะพะฝะฝั–ั… ั€ะพะทั€ะพะฑะฝะธะบั–ะฒ). + +### Falcon + +Falcon โ€” ั‰ะต ะพะดะธะฝ ะฒะธัะพะบะพะฟั€ะพะดัƒะบั‚ะธะฒะฝะธะน ั„ั€ะตะนะผะฒะพั€ะบ Python, ะฒั–ะฝ ั€ะพะทั€ะพะฑะปะตะฝะธะน ัะบ ะผั–ะฝั–ะผะฐะปัŒะฝะธะน ั– ะฟั€ะฐั†ัŽั” ัะบ ะพัะฝะพะฒะฐ ั–ะฝัˆะธั… ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ, ั‚ะฐะบะธั… ัะบ Hug. + +ะ’ั–ะฝ ั€ะพะทั€ะพะฑะปะตะฝะธะน ั‚ะฐะบะธะผ ั‡ะธะฝะพะผ, ั‰ะพะฑ ะผะฐั‚ะธ ั„ัƒะฝะบั†ั–ั—, ัะบั– ะพั‚ั€ะธะผัƒัŽั‚ัŒ ะดะฒะฐ ะฟะฐั€ะฐะผะตั‚ั€ะธ, ะพะดะธะฝ ยซะทะฐะฟะธั‚ยป ั– ะพะดะธะฝ ยซะฒั–ะดะฟะพะฒั–ะดัŒยป. ะŸะพั‚ั–ะผ ะฒะธ ยซั‡ะธั‚ะฐั”ั‚ะตยป ั‡ะฐัั‚ะธะฝะธ ะทะฐะฟะธั‚ัƒ ั‚ะฐ ยซะทะฐะฟะธััƒั”ั‚ะตยป ั‡ะฐัั‚ะธะฝะธ ัƒ ะฒั–ะดะฟะพะฒั–ะดัŒ. ะงะตั€ะตะท ั‚ะฐะบะธะน ะดะธะทะฐะนะฝ ะฝะตะผะพะถะปะธะฒะพ ะพะณะพะปะพัะธั‚ะธ ะฟะฐั€ะฐะผะตั‚ั€ะธ ะทะฐะฟะธั‚ัƒ ั‚ะฐ ั‚ั–ะปะฐ ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ัั‚ะฐะฝะดะฐั€ั‚ะฝะธั… ะฟั–ะดะบะฐะทะพะบ ั‚ะธะฟัƒ Python ัะบ ะฟะฐั€ะฐะผะตั‚ั€ะธ ั„ัƒะฝะบั†ั–ั—. + +ะขะฐะบะธะผ ั‡ะธะฝะพะผ, ะฟะตั€ะตะฒั–ั€ะบะฐ ะดะฐะฝะธั…, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ั ั‚ะฐ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั ะฟะพะฒะธะฝะฝั– ะฒะธะบะพะฝัƒะฒะฐั‚ะธัั ะฒ ะบะพะดั–, ะฐ ะฝะต ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ. ะะฑะพ ะฒะพะฝะธ ะฟะพะฒะธะฝะฝั– ะฑัƒั‚ะธ ั€ะตะฐะปั–ะทะพะฒะฐะฝั– ัะบ ั„ั€ะตะนะผะฒะพั€ะบ ะฟะพะฒะตั€ั… Falcon, ัะบ Hug. ะขะฐะบะฐ ัะฐะผะฐ ะฒั–ะดะผั–ะฝะฝั–ัั‚ัŒ ัะฟะพัั‚ะตั€ั–ะณะฐั”ั‚ัŒัั ะฒ ั–ะฝัˆะธั… ั„ั€ะตะนะผะฒะพั€ะบะฐั…, ะฝะฐั‚ั…ะฝะตะฝะฝะธั… ะดะธะทะฐะนะฝะพะผ Falcon, ั‰ะพ ะผะฐัŽั‚ัŒ ะพะดะธะฝ ะพะฑโ€™ั”ะบั‚ ะทะฐะฟะธั‚ัƒ ั‚ะฐ ะพะดะธะฝ ะพะฑโ€™ั”ะบั‚ ะฒั–ะดะฟะพะฒั–ะดั– ัะบ ะฟะฐั€ะฐะผะตั‚ั€ะธ. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะ—ะฝะฐะนั‚ะธ ัะฟะพัะพะฑะธ ะพั‚ั€ะธะผะฐั‚ะธ ั‡ัƒะดะพะฒัƒ ะฟั€ะพะดัƒะบั‚ะธะฒะฝั–ัั‚ัŒ. + + ะ ะฐะทะพะผ ั–ะท Hug (ะพัะบั–ะปัŒะบะธ Hug ะฑะฐะทัƒั”ั‚ัŒัั ะฝะฐ Falcon) ะฝะฐะดะธั…ะฝัƒะฒ **FastAPI** ะพะณะพะปะพัะธั‚ะธ ะฟะฐั€ะฐะผะตั‚ั€ `response` ัƒ ั„ัƒะฝะบั†ั–ัั…. + + ะฅะพั‡ะฐ ัƒ FastAPI ั†ะต ะฝะตะพะฑะพะฒโ€™ัะทะบะพะฒะพ, ั– ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ะฒ ะพัะฝะพะฒะฝะพะผัƒ ะดะปั ะฒัั‚ะฐะฝะพะฒะปะตะฝะฝั ะทะฐะณะพะปะพะฒะบั–ะฒ, ั„ะฐะนะปั–ะฒ cookie ั‚ะฐ ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฝะธั… ะบะพะดั–ะฒ ัั‚ะฐะฝัƒ. + +### Molten + +ะฏ ะฒั–ะดะบั€ะธะฒ ะดะปั ัะตะฑะต Molten ะฝะฐ ะฟะตั€ัˆะธั… ะตั‚ะฐะฟะฐั… ัั‚ะฒะพั€ะตะฝะฝั **FastAPI**. ะ† ะฒั–ะฝ ะผะฐั” ะดะพัะธั‚ัŒ ัั…ะพะถั– ั–ะดะตั—: + +* ะ‘ะฐะทัƒั”ั‚ัŒัั ะฝะฐ ะฟั–ะดะบะฐะทะบะฐั… ั‚ะธะฟัƒ Python. +* ะŸะตั€ะตะฒั–ั€ะบะฐ ั‚ะฐ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั ั†ะธั… ั‚ะธะฟั–ะฒ. +* ะกะธัั‚ะตะผะฐ ะฒะฟั€ะพะฒะฐะดะถะตะฝะฝั ะทะฐะปะตะถะฝะพัั‚ะตะน. + +ะ’ั–ะฝ ะฝะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ะฟะตั€ะตะฒั–ั€ะบัƒ ะดะฐะฝะธั…, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ัŽ ั‚ะฐ ะฑั–ะฑะปั–ะพั‚ะตะบัƒ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— ัั‚ะพั€ะพะฝะฝั–ั… ั€ะพะทั€ะพะฑะฝะธะบั–ะฒ, ัะบ Pydantic, ะฒั–ะฝ ะผะฐั” ัะฒะพัŽ ะฒะปะฐัะฝัƒ. ะขะฐะบะธะผ ั‡ะธะฝะพะผ, ั†ั– ะฒะธะทะฝะฐั‡ะตะฝะฝั ั‚ะธะฟั–ะฒ ะดะฐะฝะธั… ะฝะต ะผะพะถะฝะฐ ะฑัƒะปะพ ะฑ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะฟะพะฒั‚ะพั€ะฝะพ ั‚ะฐะบ ะปะตะณะบะพ. + +ะฆะต ะฒะธะผะฐะณะฐั” ั‚ั€ะพั…ะธ ะฑั–ะปัŒัˆ ะดะพะบะปะฐะดะฝะธั… ะบะพะฝั„ั–ะณัƒั€ะฐั†ั–ะน. ะ† ะพัะบั–ะปัŒะบะธ ะฒั–ะฝ ะทะฐัะฝะพะฒะฐะฝะธะน ะฝะฐ WSGI (ะทะฐะผั–ัั‚ัŒ ASGI), ะฒั–ะฝ ะฝะต ะฟั€ะธะทะฝะฐั‡ะตะฝะธะน ะดะปั ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั ะฒะธัะพะบะพะฟั€ะพะดัƒะบั‚ะธะฒะฝะธั… ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ, ั‚ะฐะบะธั… ัะบ Uvicorn, Starlette ั– Sanic. + +ะกะธัั‚ะตะผะฐ ะฒะฟั€ะพะฒะฐะดะถะตะฝะฝั ะทะฐะปะตะถะฝะพัั‚ะตะน ะฒะธะผะฐะณะฐั” ะฟะพะฟะตั€ะตะดะฝัŒะพั— ั€ะตั”ัั‚ั€ะฐั†ั–ั— ะทะฐะปะตะถะฝะพัั‚ะตะน, ั– ะทะฐะปะตะถะฝะพัั‚ั– ะฒะธั€ั–ัˆัƒัŽั‚ัŒัั ะฝะฐ ะพัะฝะพะฒั– ะพะณะพะปะพัˆะตะฝะธั… ั‚ะธะฟั–ะฒ. ะžั‚ะถะต, ะฝะตะผะพะถะปะธะฒะพ ะพะณะพะปะพัะธั‚ะธ ะฑั–ะปัŒัˆะต ะฝั–ะถ ะพะดะธะฝ ยซะบะพะผะฟะพะฝะตะฝั‚ยป, ัะบะธะน ะฝะฐะดะฐั” ะฟะตะฒะฝะธะน ั‚ะธะฟ. + +ะœะฐั€ัˆั€ัƒั‚ะธ ะพะณะพะปะพัˆัƒัŽั‚ัŒัั ะฒ ะพะดะฝะพะผัƒ ะผั–ัั†ั– ะท ะฒะธะบะพั€ะธัั‚ะฐะฝะฝัะผ ั„ัƒะฝะบั†ั–ะน, ะพะณะพะปะพัˆะตะฝะธั… ะฒ ั–ะฝัˆะธั… ะผั–ัั†ัั… (ะทะฐะผั–ัั‚ัŒ ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั ะดะตะบะพั€ะฐั‚ะพั€ั–ะฒ, ัะบั– ะผะพะถะฝะฐ ั€ะพะทะผั–ัั‚ะธั‚ะธ ะฑะตะทะฟะพัะตั€ะตะดะฝัŒะพ ะฟะพะฒะตั€ั… ั„ัƒะฝะบั†ั–ั—, ัะบะฐ ะพะฑั€ะพะฑะปัั” ะบั–ะฝั†ะตะฒัƒ ั‚ะพั‡ะบัƒ). ะฆะต ะฑะปะธะถั‡ะต ะดะพ ั‚ะพะณะพ, ัะบ ั†ะต ั€ะพะฑะธั‚ัŒ Django, ะฝั–ะถ ะดะพ Flask (ั– Starlette). ะ’ั–ะฝ ั€ะพะทะดั–ะปัั” ะฒ ะบะพะดั– ั€ะตั‡ั–, ัะบั– ะฒั–ะดะฝะพัะฝะพ ั‚ั–ัะฝะพ ะฟะพะฒโ€™ัะทะฐะฝั–. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะ’ะธะทะฝะฐั‡ะธั‚ะธ ะดะพะดะฐั‚ะบะพะฒั– ะฟะตั€ะตะฒั–ั€ะบะธ ะดะปั ั‚ะธะฟั–ะฒ ะดะฐะฝะธั…, ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ ะทะฝะฐั‡ะตะฝะฝั "ะทะฐ ะทะฐะผะพะฒั‡ัƒะฒะฐะฝะฝัะผ" ะฐั‚ั€ะธะฑัƒั‚ั–ะฒ ะผะพะดะตะปั–. ะฆะต ะฟะพะบั€ะฐั‰ัƒั” ะฟั–ะดั‚ั€ะธะผะบัƒ ั€ะตะดะฐะบั‚ะพั€ะฐ, ะฐ ั€ะฐะฝั–ัˆะต ะฒะพะฝะฐ ะฑัƒะปะฐ ะฝะตะดะพัั‚ัƒะฟะฝะฐ ะฒ Pydantic. + + ะฆะต ั„ะฐะบั‚ะธั‡ะฝะพ ะฝะฐะดะธั…ะฝัƒะปะพ ะพะฝะพะฒะธั‚ะธ ั‡ะฐัั‚ะธะฝะธ Pydantic, ั‰ะพะฑ ะฟั–ะดั‚ั€ะธะผัƒะฒะฐั‚ะธ ั‚ะพะน ัะฐะผะธะน ัั‚ะธะปัŒ ะพะณะพะปะพัˆะตะฝะฝั ะฟะตั€ะตะฒั–ั€ะบะธ (ะฒัั– ั†ั– ั„ัƒะฝะบั†ั–ั— ะฒะถะต ะดะพัั‚ัƒะฟะฝั– ะฒ Pydantic). + +### Hug + +Hug ะฑัƒะฒ ะพะดะฝะธะผ ั–ะท ะฟะตั€ัˆะธั… ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ, ัะบะธะน ั€ะตะฐะปั–ะทัƒะฒะฐะฒ ะพะณะพะปะพัˆะตะฝะฝั ั‚ะธะฟั–ะฒ ะฟะฐั€ะฐะผะตั‚ั€ั–ะฒ API ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ะฟั–ะดะบะฐะทะพะบ ั‚ะธะฟัƒ Python. ะฆะต ะฑัƒะปะฐ ั‡ัƒะดะพะฒะฐ ั–ะดะตั, ัะบะฐ ะฝะฐะดะธั…ะฝัƒะปะฐ ั–ะฝัˆั– ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะธ ะทั€ะพะฑะธั‚ะธ ั‚ะต ัะฐะผะต. + +ะ’ั–ะฝ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะฒ ัะฟะตั†ั–ะฐะปัŒะฝั– ั‚ะธะฟะธ ัƒ ัะฒะพั—ั… ะพะณะพะปะพัˆะตะฝะฝัั… ะทะฐะผั–ัั‚ัŒ ัั‚ะฐะฝะดะฐั€ั‚ะฝะธั… ั‚ะธะฟั–ะฒ Python, ะฐะปะต ั†ะต ะฒัะต ะพะดะฝะพ ะฑัƒะฒ ะฒะตะปะธั‡ะตะทะฝะธะน ะบั€ะพะบ ะฒะฟะตั€ะตะด. + +ะฆะต ั‚ะฐะบะพะถ ะฑัƒะฒ ะพะดะธะฝ ั–ะท ะฟะตั€ัˆะธั… ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ, ัะบะธะน ะณะตะฝะตั€ัƒะฒะฐะฒ ัะฟะตั†ั–ะฐะปัŒะฝัƒ ัั…ะตะผัƒ, ั‰ะพ ะพะณะพะปะพัˆัƒะฒะฐะปะฐ ะฒะตััŒ API ัƒ JSON. + +ะ’ั–ะฝ ะฝะต ะฑะฐะทัƒะฒะฐะฒัั ะฝะฐ ั‚ะฐะบะธั… ัั‚ะฐะฝะดะฐั€ั‚ะฐั…, ัะบ OpenAPI ั‚ะฐ JSON Schema. ะขะพะผัƒ ะฑัƒะปะพ ะฑ ะฝะตะฟั€ะพัั‚ะพ ั–ะฝั‚ะตะณั€ัƒะฒะฐั‚ะธ ะนะพะณะพ ะท ั–ะฝัˆะธะผะธ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะฐะผะธ, ัะบ-ะพั‚ Swagger UI. ะะปะต ะทะฝะพะฒัƒ ะถ ั‚ะฐะบะธ, ั†ะต ะฑัƒะปะฐ ะดัƒะถะต ั–ะฝะฝะพะฒะฐั†ั–ะนะฝะฐ ั–ะดะตั. + +ะ’ั–ะฝ ะผะฐั” ั†ั–ะบะฐะฒัƒ ะฝะตะทะฒะธั‡ะฐะนะฝัƒ ั„ัƒะฝะบั†ั–ัŽ: ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ ั‚ัƒ ัะฐะผัƒ ัั‚ั€ัƒะบั‚ัƒั€ัƒ, ะผะพะถะฝะฐ ัั‚ะฒะพั€ัŽะฒะฐั‚ะธ API, ะฐ ั‚ะฐะบะพะถ CLI. + +ะžัะบั–ะปัŒะบะธ ะฒั–ะฝ ะทะฐัะฝะพะฒะฐะฝะธะน ะฝะฐ ะฟะพะฟะตั€ะตะดะฝัŒะพะผัƒ ัั‚ะฐะฝะดะฐั€ั‚ั– ะดะปั ัะธะฝั…ั€ะพะฝะฝะธั… ะฒะตะฑ-ั„ั€ะตะนะผะฒะพั€ะบั–ะฒ Python (WSGI), ะฒั–ะฝ ะฝะต ะผะพะถะต ะฟั€ะฐั†ัŽะฒะฐั‚ะธ ะท Websockets ั‚ะฐ ั–ะฝัˆะธะผะธ ั€ะตั‡ะฐะผะธ, ั…ะพั‡ะฐ ะฒั–ะฝ ั‚ะฐะบะพะถ ะผะฐั” ะฒะธัะพะบัƒ ะฟั€ะพะดัƒะบั‚ะธะฒะฝั–ัั‚ัŒ. + +!!! ะ†ะฝั„ะพั€ะผะฐั†ั–ั + Hug ัั‚ะฒะพั€ะธะฒ ะขั–ะผะพั‚ั– ะšั€ะพัะปั–, ั‚ะพะน ัะฐะผะธะน ั‚ะฒะพั€ะตั†ัŒ `isort`, ั‡ัƒะดะพะฒะธะน ั–ะฝัั‚ั€ัƒะผะตะฝั‚ ะดะปั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพะณะพ ัะพั€ั‚ัƒะฒะฐะฝะฝั ั–ะผะฟะพั€ั‚ัƒ ัƒ ั„ะฐะนะปะฐั… Python. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + Hug ะฝะฐะดะธั…ะฝัƒะฒ ั‡ะฐัั‚ะธะฝัƒ APIStar ั– ะฑัƒะฒ ะพะดะฝะธะผ ั–ะท ะฝะฐะนะฑั–ะปัŒัˆ ะฟะตั€ัะฟะตะบั‚ะธะฒะฝะธั… ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ, ะฟะพั€ัะด ั–ะท APIStar. + + Hug ะฝะฐะดะธั…ะฝัƒะฒ **FastAPI** ะฝะฐ ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั ะฟั–ะดะบะฐะทะพะบ ั‚ะธะฟัƒ Python ะดะปั ะพะณะพะปะพัˆะตะฝะฝั ะฟะฐั€ะฐะผะตั‚ั€ั–ะฒ ั– ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพะณะพ ัั‚ะฒะพั€ะตะฝะฝั ัั…ะตะผะธ, ั‰ะพ ะฒะธะทะฝะฐั‡ะฐั” API. + + Hug ะฝะฐะดะธั…ะฝัƒะฒ **FastAPI** ะพะณะพะปะพัะธั‚ะธ ะฟะฐั€ะฐะผะตั‚ั€ `response` ัƒ ั„ัƒะฝะบั†ั–ัั… ะดะปั ะฒัั‚ะฐะฝะพะฒะปะตะฝะฝั ะทะฐะณะพะปะพะฒะบั–ะฒ ั– ั„ะฐะนะปั–ะฒ cookie. + +### APIStar (<= 0,5) + +ะ‘ะตะทะฟะพัะตั€ะตะดะฝัŒะพ ะฟะตั€ะตะด ั‚ะธะผ, ัะบ ะฒะธั€ั–ัˆะธั‚ะธ ัั‚ะฒะพั€ะธั‚ะธ **FastAPI**, ั ะทะฝะฐะนัˆะพะฒ ัะตั€ะฒะตั€ **APIStar**. ะ’ั–ะฝ ะผะฐะฒ ะผะฐะนะถะต ะฒัะต, ั‰ะพ ั ัˆัƒะบะฐะฒ, ั– ะผะฐะฒ ั‡ัƒะดะพะฒะธะน ะดะธะทะฐะนะฝ. + +ะฆะต ะฑัƒะปะฐ ะพะดะฝะฐ ะท ะฟะตั€ัˆะธั… ั€ะตะฐะปั–ะทะฐั†ั–ะน ั„ั€ะตะนะผะฒะพั€ะบัƒ, ั‰ะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ะฟั–ะดะบะฐะทะบะธ ั‚ะธะฟัƒ Python ะดะปั ะพะณะพะปะพัˆะตะฝะฝั ะฟะฐั€ะฐะผะตั‚ั€ั–ะฒ ั– ะทะฐะฟะธั‚ั–ะฒ, ัะบัƒ ั ะบะพะปะธ-ะฝะตะฑัƒะดัŒ ะฑะฐั‡ะธะฒ (ะดะพ NestJS ั– Molten). ะฏ ะทะฝะฐะนัˆะพะฒ ะนะพะณะพ ะฑั–ะปัŒัˆ-ะผะตะฝัˆ ะพะดะฝะพั‡ะฐัะฝะพ ะท Hug. ะะปะต APIStar ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะฒ ัั‚ะฐะฝะดะฐั€ั‚ OpenAPI. + +ะ’ั–ะฝ ะผะฐะฒ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝัƒ ะฟะตั€ะตะฒั–ั€ะบัƒ ะดะฐะฝะธั…, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ัŽ ะดะฐะฝะธั… ั– ะณะตะฝะตั€ะฐั†ั–ัŽ ัั…ะตะผะธ OpenAPI ะฝะฐ ะพัะฝะพะฒั– ะฟั–ะดะบะฐะทะพะบ ั‚ะพะณะพ ัะฐะผะพะณะพ ั‚ะธะฟัƒ ะฒ ะบั–ะปัŒะบะพั… ะผั–ัั†ัั…. + +ะ’ะธะทะฝะฐั‡ะตะฝะฝั ัั…ะตะผะธ ั‚ั–ะปะฐ ะฝะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะปะธ ั‚ั– ัะฐะผั– ะฟั–ะดะบะฐะทะบะธ ั‚ะธะฟัƒ Python, ัะบ Pydantic, ะฒะพะฝะพ ะฑัƒะปะพ ั‚ั€ะพั…ะธ ัั…ะพะถะต ะฝะฐ Marshmallow, ั‚ะพะผัƒ ะฟั–ะดั‚ั€ะธะผะบะฐ ั€ะตะดะฐะบั‚ะพั€ะฐ ะฑัƒะปะฐ ะฑ ะฝะต ั‚ะฐะบะพัŽ ั…ะพั€ะพัˆะพัŽ, ะฐะปะต ะฒัะต ะถ APIStar ะฑัƒะฒ ะฝะฐะนะบั€ะฐั‰ะธะผ ะดะพัั‚ัƒะฟะฝะธะผ ะฒะฐั€ั–ะฐะฝั‚ะพะผ. + +ะ’ั–ะฝ ะผะฐะฒ ะฝะฐะนะบั€ะฐั‰ั– ะฟะพะบะฐะทะฝะธะบะธ ะฟั€ะพะดัƒะบั‚ะธะฒะฝะพัั‚ั– ะฝะฐ ั‚ะพะน ั‡ะฐั (ะฟะตั€ะตะฒะตั€ัˆะธะฒ ะปะธัˆะต Starlette). + +ะกะฟะพั‡ะฐั‚ะบัƒ ะฒั–ะฝ ะฝะต ะผะฐะฒ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพะณะพ ะฒะตะฑ-ั–ะฝั‚ะตั€ั„ะตะนััƒ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— API, ะฐะปะต ั ะทะฝะฐะฒ, ั‰ะพ ะผะพะถัƒ ะดะพะดะฐั‚ะธ ะดะพ ะฝัŒะพะณะพ ั–ะฝั‚ะตั€ั„ะตะนั ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ Swagger. + +ะ’ั–ะฝ ะผะฐะฒ ัะธัั‚ะตะผัƒ ะฒะฒะตะดะตะฝะฝั ะทะฐะปะตะถะฝะพัั‚ะตะน. ะ’ั–ะฝ ะฒะธะผะฐะณะฐะฒ ะฟะพะฟะตั€ะตะดะฝัŒะพั— ั€ะตั”ัั‚ั€ะฐั†ั–ั— ะบะพะผะฟะพะฝะตะฝั‚ั–ะฒ, ัะบ ั– ั–ะฝัˆั– ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะธ, ั€ะพะทะณะปัะฝัƒั‚ั– ะฒะธั‰ะต. ะะปะต ะฒัะต ะพะดะฝะพ ั†ะต ะฑัƒะปะฐ ั‡ัƒะดะพะฒะฐ ั„ัƒะฝะบั†ั–ั. + +ะฏ ะฝั–ะบะพะปะธ ะฝะต ะผั–ะณ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะนะพะณะพ ะฒ ะฟะพะฒะฝะพั†ั–ะฝะฝะพะผัƒ ะฟั€ะพะตะบั‚ั–, ะพัะบั–ะปัŒะบะธ ะฒั–ะฝ ะฝะต ะผะฐะฒ ั–ะฝั‚ะตะณั€ะฐั†ั–ั— ะฑะตะทะฟะตะบะธ, ั‚ะพะผัƒ ั ะฝะต ะผั–ะณ ะทะฐะผั–ะฝะธั‚ะธ ะฒัั– ั„ัƒะฝะบั†ั–ั—, ัะบั– ะผะฐะฒ, ะณะตะฝะตั€ะฐั‚ะพั€ะฐะผะธ ะฟะพะฒะฝะพะณะพ ัั‚ะตะบัƒ ะฝะฐ ะพัะฝะพะฒั– Flask-apispec. ะฃ ะผะพั—ั… ะฝะตะฒะธะบะพะฝะฐะฝะธั… ะฟั€ะพะตะบั‚ะฐั… ั ะผะฐะฒ ัั‚ะฒะพั€ะธั‚ะธ ะทะฐะฟะธั‚ ะฝะฐ ะฒะธะปัƒั‡ะตะฝะฝั, ะดะพะดะฐะฒัˆะธ ั†ัŽ ั„ัƒะฝะบั†ั–ัŽ. + +ะะปะต ะฟะพั‚ั–ะผ ั„ะพะบัƒั ะฟั€ะพะตะบั‚ัƒ ะทะผั–ะฝะธะฒัั. + +ะฆะต ะฒะถะต ะฝะต ะฑัƒะฒ ะฒะตะฑ-ั„ั€ะตะนะผะฒะพั€ะบ API, ะพัะบั–ะปัŒะบะธ ั‚ะฒะพั€ั†ัŽ ะฟะพั‚ั€ั–ะฑะฝะพ ะฑัƒะปะพ ะทะพัะตั€ะตะดะธั‚ะธัั ะฝะฐ Starlette. + +ะขะตะฟะตั€ APIStar โ€” ั†ะต ะฝะฐะฑั–ั€ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ ะดะปั ะฟะตั€ะตะฒั–ั€ะบะธ ัะฟะตั†ะธั„ั–ะบะฐั†ั–ะน OpenAPI, ะฐ ะฝะต ะฒะตะฑ-ั„ั€ะตะนะผะฒะพั€ะบ. + +!!! ะ†ะฝั„ะพั€ะผะฐั†ั–ั + APIStar ัั‚ะฒะพั€ะธะฒ ะขะพะผ ะšั€ั–ัั‚ั–. ะขะพะน ัะฐะผะธะน ั…ะปะพะฟะตั†ัŒ, ัะบะธะน ัั‚ะฒะพั€ะธะฒ: + + * Django REST Framework + * Starlette (ะฝะฐ ัะบะพะผัƒ ะฑะฐะทัƒั”ั‚ัŒัั **FastAPI**) + * Uvicorn (ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั Starlette ั– **FastAPI**) + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "ะะฐะดะธั…ะฝัƒะปะพ **FastAPI** ะฝะฐ" + ะ†ัะฝัƒะฒะฐั‚ะธ. + + ะ†ะดะตัŽ ะพะณะพะปะพัˆะตะฝะฝั ะบั–ะปัŒะบะพั… ั€ะตั‡ะตะน (ะฟะตั€ะตะฒั–ั€ะบะธ ะดะฐะฝะธั…, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ั— ั‚ะฐ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั—) ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ั‚ะธั… ัะฐะผะธั… ั‚ะธะฟั–ะฒ Python, ัะบั– ะฒ ั‚ะพะน ะถะต ั‡ะฐั ะทะฐะฑะตะทะฟะตั‡ัƒะฒะฐะปะธ ั‡ัƒะดะพะฒัƒ ะฟั–ะดั‚ั€ะธะผะบัƒ ั€ะตะดะฐะบั‚ะพั€ะฐ, ั ะฒะฒะฐะถะฐะฒ ะณะตะฝั–ะฐะปัŒะฝะพัŽ ั–ะดะตั”ัŽ. + + ะ† ะฟั–ัะปั ั‚ั€ะธะฒะฐะปะพะณะพ ะฟะพัˆัƒะบัƒ ะฟะพะดั–ะฑะฝะพั— ัั‚ั€ัƒะบั‚ัƒั€ะธ ั‚ะฐ ั‚ะตัั‚ัƒะฒะฐะฝะฝั ะฑะฐะณะฐั‚ัŒะพั… ั€ั–ะทะฝะธั… ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒ, APIStar ัั‚ะฐะฒ ะฝะฐะนะบั€ะฐั‰ะธะผ ะดะพัั‚ัƒะฟะฝะธะผ ะฒะฐั€ั–ะฐะฝั‚ะพะผ. + + ะŸะพั‚ั–ะผ APIStar ะฟะตั€ะตัั‚ะฐะฒ ั–ัะฝัƒะฒะฐั‚ะธ ัะบ ัะตั€ะฒะตั€, ั– ะฑัƒะปะพ ัั‚ะฒะพั€ะตะฝะพ Starlette, ัะบะธะน ัั‚ะฐะฒ ะฝะพะฒะพัŽ ะบั€ะฐั‰ะพัŽ ะพัะฝะพะฒะพัŽ ะดะปั ั‚ะฐะบะพั— ัะธัั‚ะตะผะธ. ะฆะต ัั‚ะฐะปะพ ะพัั‚ะฐะฝะฝั–ะผ ะดะถะตั€ะตะปะพะผ ะฝะฐั‚ั…ะฝะตะฝะฝั ะดะปั ัั‚ะฒะพั€ะตะฝะฝั **FastAPI**. ะฏ ะฒะฒะฐะถะฐัŽ **FastAPI** ยซะดัƒั…ะพะฒะฝะธะผ ัะฟะฐะดะบะพั”ะผั†ะตะผยป APIStar, ัƒะดะพัะบะพะฝะฐะปัŽัŽั‡ะธ ั‚ะฐ ั€ะพะทัˆะธั€ัŽัŽั‡ะธ ั„ัƒะฝะบั†ั–ั—, ัะธัั‚ะตะผัƒ ะฒะฒะตะดะตะฝะฝั ั‚ะตะบัั‚ัƒ ั‚ะฐ ั–ะฝัˆั– ั‡ะฐัั‚ะธะฝะธ ะฝะฐ ะพัะฝะพะฒั– ะดะพัะฒั–ะดัƒ, ะพั‚ั€ะธะผะฐะฝะพะณะพ ะฒั–ะด ัƒัั–ั… ั†ะธั… ะฟะพะฟะตั€ะตะดะฝั–ั… ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ. + +## ะ’ะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั **FastAPI** + +### Pydantic + +Pydantic โ€” ั†ะต ะฑั–ะฑะปั–ะพั‚ะตะบะฐ ะดะปั ะฒะธะทะฝะฐั‡ะตะฝะฝั ะฟะตั€ะตะฒั–ั€ะบะธ ะดะฐะฝะธั…, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ั— ั‚ะฐ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— (ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ัั…ะตะผะธ JSON) ะฝะฐ ะพัะฝะพะฒั– ะฟั–ะดะบะฐะทะพะบ ั‚ะธะฟัƒ Python. + +ะฆะต ั€ะพะฑะธั‚ัŒ ะนะพะณะพ ะฝะฐะดะทะฒะธั‡ะฐะนะฝะพ ั–ะฝั‚ัƒั—ั‚ะธะฒะฝะธะผ. + +ะ™ะพะณะพ ะผะพะถะฝะฐ ะฟะพั€ั–ะฒะฝัั‚ะธ ะท Marshmallow. ะฅะพั‡ะฐ ะฒั–ะฝ ัˆะฒะธะดัˆะธะน ะทะฐ Marshmallow ัƒ ั‚ะตัั‚ะฐั…. ะžัะบั–ะปัŒะบะธ ะฒั–ะฝ ะฑะฐะทัƒั”ั‚ัŒัั ะฝะฐ ั‚ะธั… ัะฐะผะธั… ะฟั–ะดะบะฐะทะบะฐั… ั‚ะธะฟัƒ Python, ะฟั–ะดั‚ั€ะธะผะบะฐ ั€ะตะดะฐะบั‚ะพั€ะฐ ั‡ัƒะดะพะฒะฐ. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "**FastAPI** ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ะนะพะณะพ ะดะปั" + ะ’ะธะบะพะฝะฐะฝะฝั ะฟะตั€ะตะฒั–ั€ะบะธ ะฒัั–ั… ะดะฐะฝะธั…, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ั— ะดะฐะฝะธั… ั– ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั— ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ัŽ ะผะพะดะตะปั– (ะฝะฐ ะพัะฝะพะฒั– ัั…ะตะผะธ JSON). + + ะŸะพั‚ั–ะผ **FastAPI** ะฑะตั€ะต ั†ั– ะดะฐะฝั– ัั…ะตะผะธ JSON ั– ั€ะพะทะผั–ั‰ัƒั” ั—ั… ัƒ OpenAPI, ะพะบั€ะตะผะพ ะฒั–ะด ัƒัั–ั… ั–ะฝัˆะธั… ั€ะตั‡ะตะน, ัะบั– ะฒั–ะฝ ั€ะพะฑะธั‚ัŒ. + +### Starlette + +Starlette โ€” ั†ะต ะปะตะณะบะธะน ั„ั€ะตะนะผะฒะพั€ะบ/ะฝะฐะฑั–ั€ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ ASGI, ัะบะธะน ั–ะดะตะฐะปัŒะฝะพ ะฟั–ะดั…ะพะดะธั‚ัŒ ะดะปั ัั‚ะฒะพั€ะตะฝะฝั ะฒะธัะพะบะพะฟั€ะพะดัƒะบั‚ะธะฒะฝะธั… asyncio ัะตั€ะฒั–ัั–ะฒ. + +ะ’ั–ะฝ ะดัƒะถะต ะฟั€ะพัั‚ะธะน ั‚ะฐ ั–ะฝั‚ัƒั—ั‚ะธะฒะฝะพ ะทั€ะพะทัƒะผั–ะปะธะน. ะ™ะพะณะพ ั€ะพะทั€ะพะฑะปะตะฝะพ ั‚ะฐะบะธะผ ั‡ะธะฝะพะผ, ั‰ะพะฑ ะนะพะณะพ ะผะพะถะฝะฐ ะฑัƒะปะพ ะปะตะณะบะพ ั€ะพะทัˆะธั€ัŽะฒะฐั‚ะธ ั‚ะฐ ะผะฐั‚ะธ ะผะพะดัƒะปัŒะฝั– ะบะพะผะฟะพะฝะตะฝั‚ะธ. + +ะ’ั–ะฝ ะผะฐั”: + +* ะกะตั€ะนะพะทะฝะพ ะฒั€ะฐะถะฐัŽั‡ัƒ ะฟั€ะพะดัƒะบั‚ะธะฒะฝั–ัั‚ัŒ. +* ะŸั–ะดั‚ั€ะธะผะบัƒ WebSocket. +* ะคะพะฝะพะฒั– ะทะฐะฒะดะฐะฝะฝั ะฒ ะฟั€ะพั†ะตัั–. +* ะŸะพะดั–ั— ะทะฐะฟัƒัะบัƒ ั‚ะฐ ะทะฐะฒะตั€ัˆะตะฝะฝั ั€ะพะฑะพั‚ะธ. +* ะขะตัั‚ะพะฒะพะณะพ ะบะปั–ั”ะฝั‚ะฐ, ะฟะพะฑัƒะดะพะฒะฐะฝะธะน ะฝะฐ HTTPX. +* CORS, GZip, ัั‚ะฐั‚ะธั‡ะฝั– ั„ะฐะนะปะธ, ะฟะพั‚ะพะบะพะฒั– ะฒั–ะดะฟะพะฒั–ะดั–. +* ะŸั–ะดั‚ั€ะธะผะบัƒ ัะตะฐะฝัั–ะฒ ั– ั„ะฐะนะปั–ะฒ cookie. +* 100% ะฟะพะบั€ะธั‚ั‚ั ั‚ะตัั‚ะพะผ. +* 100% ะฐะฝะพั‚ะพะฒะฐะฝัƒ ะบะพะดะพะฒัƒ ะฑะฐะทัƒ. +* ะšั–ะปัŒะบะฐ ะถะพั€ัั‚ะบะธั… ะทะฐะปะตะถะฝะพัั‚ะตะน. + +Starlette ะฝะฐั€ะฐะทั– ั” ะฝะฐะนัˆะฒะธะดัˆะธะผ ั„ั€ะตะนะผะฒะพั€ะบะพะผ Python ั–ะท ะฟะตั€ะตะฒั–ั€ะตะฝะธั…. ะŸะตั€ะตะฒะตั€ัˆัƒั” ะปะธัˆะต Uvicorn, ัะบะธะน ั” ะฝะต ั„ั€ะตะนะผะฒะพั€ะบะพะผ, ะฐ ัะตั€ะฒะตั€ะพะผ. + +Starlette ะฝะฐะดะฐั” ะฒัั– ะพัะฝะพะฒะฝั– ั„ัƒะฝะบั†ั–ั— ะฒะตะฑ-ะผั–ะบั€ะพั„ั€ะตะนะผะฒะพั€ะบัƒ. + +ะะปะต ะฒั–ะฝ ะฝะต ะทะฐะฑะตะทะฟะตั‡ัƒั” ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั— ะฟะตั€ะตะฒั–ั€ะบะธ ะดะฐะฝะธั…, ัะตั€ั–ะฐะปั–ะทะฐั†ั–ั— ั‡ะธ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั—. + +ะฆะต ะพะดะฝะฐ ะท ะณะพะปะพะฒะฝะธั… ั€ะตั‡ะตะน, ัะบั– **FastAPI** ะดะพะดะฐั” ะทะฒะตั€ั…ัƒ, ะฒัะต ะฝะฐ ะพัะฝะพะฒั– ะฟั–ะดะบะฐะทะพะบ ั‚ะธะฟัƒ Python (ะท ะฒะธะบะพั€ะธัั‚ะฐะฝะฝัะผ Pydantic). ะฆะต, ะฐ ั‚ะฐะบะพะถ ัะธัั‚ะตะผะฐ ะฒะฟั€ะพะฒะฐะดะถะตะฝะฝั ะทะฐะปะตะถะฝะพัั‚ะตะน, ัƒั‚ะธะปั–ั‚ะธ ะฑะตะทะฟะตะบะธ, ัั‚ะฒะพั€ะตะฝะฝั ัั…ะตะผะธ OpenAPI ั‚ะพั‰ะพ. + +!!! ะŸั€ะธะผั–ั‚ะบะฐ "ะขะตั…ะฝั–ั‡ะฝั– ะดะตั‚ะฐะปั–" + ASGI โ€” ั†ะต ะฝะพะฒะธะน ยซัั‚ะฐะฝะดะฐั€ั‚ยป, ัะบะธะน ั€ะพะทั€ะพะฑะปัั”ั‚ัŒัั ั‡ะปะตะฝะฐะผะธ ะพัะฝะพะฒะฝะพั— ะบะพะผะฐะฝะดะธ Django. ะฆะต ั‰ะต ะฝะต ยซัั‚ะฐะฝะดะฐั€ั‚ Pythonยป (PEP), ั…ะพั‡ะฐ ะฒะพะฝะธ ะฒ ะฟั€ะพั†ะตัั– ั†ัŒะพะณะพ. + + ะขะธะผ ะฝะต ะผะตะฝัˆ, ะฒั–ะฝ ัƒะถะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ัะบ ยซัั‚ะฐะฝะดะฐั€ั‚ยป ะบั–ะปัŒะบะพะผะฐ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะฐะผะธ. ะฆะต ะทะฝะฐั‡ะฝะพ ะฟะพะบั€ะฐั‰ัƒั” ััƒะผั–ัะฝั–ัั‚ัŒ, ะพัะบั–ะปัŒะบะธ ะฒะธ ะผะพะถะตั‚ะต ะฟะตั€ะตะบะปัŽั‡ะธั‚ะธ Uvicorn ะฝะฐ ะฑัƒะดัŒ-ัะบะธะน ั–ะฝัˆะธะน ัะตั€ะฒะตั€ ASGI (ะฝะฐะฟั€ะธะบะปะฐะด, Daphne ะฐะฑะพ Hypercorn), ะฐะฑะพ ะฒะธ ะผะพะถะตั‚ะต ะดะพะดะฐั‚ะธ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะธ, ััƒะผั–ัะฝั– ะท ASGI, ัะบ-ะพั‚ `python-socketio`. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "**FastAPI** ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ะนะพะณะพ ะดะปั" + ะšะตั€ัƒะฒะฐะฝะฝั ะฒัั–ะผะฐ ะพัะฝะพะฒะฝะธะผะธ ะฒะตะฑ-ั‡ะฐัั‚ะธะฝะฐะผะธ. ะ”ะพะดะฐะฒะฐะฝะฝั ั„ัƒะฝะบั†ั–ะน ะทะฒะตั€ั…ัƒ. + + ะกะฐะผ ะบะปะฐั `FastAPI` ะฑะตะทะฟะพัะตั€ะตะดะฝัŒะพ ัƒัะฟะฐะดะบะพะฒัƒั” ะบะปะฐั `Starlette`. + + ะžั‚ะถะต, ัƒัะต, ั‰ะพ ะฒะธ ะผะพะถะตั‚ะต ั€ะพะฑะธั‚ะธ ะทั– Starlette, ะฒะธ ะผะพะถะตั‚ะต ั€ะพะฑะธั‚ะธ ั†ะต ะฑะตะทะฟะพัะตั€ะตะดะฝัŒะพ ะทะฐ ะดะพะฟะพะผะพะณะพัŽ **FastAPI**, ะพัะบั–ะปัŒะบะธ ั†ะต, ะฟะพ ััƒั‚ั–, Starlette ะฝะฐ ัั‚ะตั€ะพั—ะดะฐั…. + +### Uvicorn + +Uvicorn โ€” ั†ะต ะฑะปะธัะบะฐะฒะธั‡ะฝะธะน ัะตั€ะฒะตั€ ASGI, ะฟะพะฑัƒะดะพะฒะฐะฝะธะน ะฝะฐ uvloop ั– httptools. + +ะฆะต ะฝะต ะฒะตะฑ-ั„ั€ะตะนะผะฒะพั€ะบ, ะฐ ัะตั€ะฒะตั€. ะะฐะฟั€ะธะบะปะฐะด, ะฒั–ะฝ ะฝะต ะฝะฐะดะฐั” ั–ะฝัั‚ั€ัƒะผะตะฝั‚ั–ะฒ ะดะปั ะผะฐั€ัˆั€ัƒั‚ะธะทะฐั†ั–ั—. ะฆะต ั‚ะต, ั‰ะพ ั„ั€ะตะนะผะฒะพั€ะบ ะฝะฐ ะบัˆั‚ะฐะปั‚ Starlette (ะฐะฑะพ **FastAPI**) ะทะฐะฑะตะทะฟะตั‡ะธั‚ัŒ ะฟะพะฒะตั€ั… ะฝัŒะพะณะพ. + +ะฆะต ั€ะตะบะพะผะตะฝะดะพะฒะฐะฝะธะน ัะตั€ะฒะตั€ ะดะปั Starlette ั– **FastAPI**. + +!!! ะŸะตั€ะตะณะปัะฝัŒั‚ะต "**FastAPI** ั€ะตะบะพะผะตะฝะดัƒั” ั†ะต ัะบ" + ะžัะฝะพะฒะฝะธะน ะฒะตะฑ-ัะตั€ะฒะตั€ ะดะปั ะทะฐะฟัƒัะบัƒ ะฟั€ะพะณั€ะฐะผ **FastAPI**. + + ะ’ะธ ะผะพะถะตั‚ะต ะฟะพั”ะดะฝะฐั‚ะธ ะนะพะณะพ ะท Gunicorn, ั‰ะพะฑ ะผะฐั‚ะธ ะฐัะธะฝั…ั€ะพะฝะฝะธะน ะฑะฐะณะฐั‚ะพะฟั€ะพั†ะตัะฝะธะน ัะตั€ะฒะตั€. + + ะ”ะพะดะฐั‚ะบะพะฒัƒ ั–ะฝั„ะพั€ะผะฐั†ั–ัŽ ะดะธะฒ. ัƒ ั€ะพะทะดั–ะปั– [ะ ะพะทะณะพั€ั‚ะฐะฝะฝั](deployment/index.md){.internal-link target=_blank}. + +## ะžั€ั–ั”ะฝั‚ะธั€ะธ ั‚ะฐ ัˆะฒะธะดะบั–ัั‚ัŒ + +ะฉะพะฑ ะทั€ะพะทัƒะผั–ั‚ะธ, ะฟะพั€ั–ะฒะฝัั‚ะธ ั‚ะฐ ะฟะพะฑะฐั‡ะธั‚ะธ ั€ั–ะทะฝะธั†ัŽ ะผั–ะถ Uvicorn, Starlette ั– FastAPI, ะฟะตั€ะตะณะปัะฝัŒั‚ะต ั€ะพะทะดั–ะป ะฟั€ะพ [ะ‘ะตะฝั‡ะผะฐั€ะบะธ](benchmarks.md){.internal-link target=_blank}. diff --git a/docs/uk/docs/python-types.md b/docs/uk/docs/python-types.md new file mode 100644 index 000000000..6c8e29016 --- /dev/null +++ b/docs/uk/docs/python-types.md @@ -0,0 +1,448 @@ +# ะ’ัั‚ัƒะฟ ะดะพ ั‚ะธะฟั–ะฒ Python + +Python ะฟั–ะดั‚ั€ะธะผัƒั” ะดะพะดะฐั‚ะบะพะฒั– "ะฟั–ะดะบะฐะทะบะธ ั‚ะธะฟัƒ" ("type hints") (ั‚ะฐะบะพะถ ะทะฒะฐะฝั– "ะฐะฝะพั‚ะฐั†ั–ัะผะธ ั‚ะธะฟัƒ" ("type annotations")). + +ะฆั– **"type hints"** ั” ัะฟะตั†ั–ะฐะปัŒะฝะธะผ ัะธะฝั‚ะฐะบัะธัะพะผ, ั‰ะพ ะดะพะทะฒะพะปัั” ะพะณะพะปะพัˆัƒะฒะฐั‚ะธ ั‚ะธะฟ ะทะผั–ะฝะฝะพั—. + +ะ—ะฐ ะดะพะฟะพะผะพะณะพัŽ ะพะณะพะปะพัˆะตะฝะฝั ั‚ะธะฟั–ะฒ ะดะปั ะฒะฐัˆะธั… ะทะผั–ะฝะฝะธั…, ั€ะตะดะฐะบั‚ะพั€ะธ ั‚ะฐ ั–ะฝัั‚ั€ัƒะผะตะฝั‚ะธ ะผะพะถัƒั‚ัŒ ะฝะฐะดะฐั‚ะธ ะฒะฐะผ ะบั€ะฐั‰ัƒ ะฟั–ะดั‚ั€ะธะผะบัƒ. + +ะฆะต ะฟั€ะพัั‚ะพ **ัˆะฒะธะดะบะธะน ะฟะพัั–ะฑะฝะธะบ / ะฝะฐะณะฐะดัƒะฒะฐะฝะฝั** ะฟั€ะพ ะฐะฝะพั‚ะฐั†ั–ั— ั‚ะธะฟั–ะฒ ัƒ Python. ะ’ั–ะฝ ะฟะพะบั€ะธะฒะฐั” ะปะธัˆะต ะผั–ะฝั–ะผัƒะผ, ะฝะตะพะฑั…ั–ะดะฝะธะน ั‰ะพะฑ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ั—ั… ะท **FastAPI**... ั‰ะพ ะฝะฐัะฟั€ะฐะฒะดั– ะดัƒะถะต ะผะฐะปะพ. + +**FastAPI** ะฟะพะฒะฝั–ัั‚ัŽ ะฑะฐะทัƒั”ั‚ัŒัั ะฝะฐ ั†ะธั… ะฐะฝะพั‚ะฐั†ั–ัั… ั‚ะธะฟั–ะฒ, ะฒะพะฝะธ ะดะฐัŽั‚ัŒ ะนะพะผัƒ ะฑะฐะณะฐั‚ะพ ะฟะตั€ะตะฒะฐะณ. + +ะะปะต ะฝะฐะฒั–ั‚ัŒ ัะบั‰ะพ ะฒะธ ะฝั–ะบะพะปะธ ะฝะต ะฒะธะบะพั€ะธัั‚ะฐั”ั‚ะต **FastAPI**, ะฒะฐะผ ะฑัƒะดะต ะบะพั€ะธัะฝะพ ะดั–ะทะฝะฐั‚ะธััŒ ั‚ั€ะพั…ะธ ะฟั€ะพ ะฝะธั…. + +!!! note + ะฏะบั‰ะพ ะฒะธ ะตะบัะฟะตั€ั‚ ัƒ Python ั– ะฒะธ ะฒะถะต ะทะฝะฐั”ั‚ะต ัƒัะต ะฟั€ะพ ะฐะฝะพั‚ะฐั†ั–ั— ั‚ะธะฟั–ะฒ - ะฟะตั€ะตะนะดั–ั‚ัŒ ะดะพ ะฝะฐัั‚ัƒะฟะฝะพะณะพ ั€ะพะทะดั–ะปัƒ. + +## ะœะพั‚ะธะฒะฐั†ั–ั + +ะ”ะฐะฒะฐะนั‚ะต ะฟะพั‡ะฝะตะผะพ ะท ะฟั€ะพัั‚ะพะณะพ ะฟั€ะธะบะปะฐะดัƒ: + +```Python +{!../../../docs_src/python_types/tutorial001.py!} +``` + +ะ’ะธะบะปะธะบ ั†ั–ั”ั— ะฟั€ะพะณั€ะฐะผะธ ะฒะธะฒะพะดะธั‚ัŒ: + +``` +John Doe +``` + +ะคัƒะฝะบั†ั–ั ะฒะธะบะพะฝัƒั” ะฝะฐัั‚ัƒะฟะฝะต: + +* ะ‘ะตั€ะต `first_name` ั‚ะฐ `last_name`. +* ะšะพะฝะฒะตั€ั‚ัƒั” ะบะพะถะฝัƒ ะปั–ั‚ะตั€ัƒ ะบะพะถะฝะพะณะพ ัะปะพะฒะฐ ัƒ ะฒะตั€ั…ะฝั–ะน ั€ะตะณั–ัั‚ั€ ะทะฐ ะดะพะฟะพะผะพะณะพัŽ `title()`. +* ะšะพะฝะบะฐั‚ะตะฝัƒั” ั—ั… ั€ะฐะทะพะผ ั–ะท ะฟั€ะพะฑั–ะปะพะผ ะฟะพ ัะตั€ะตะดะธะฝั–. + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial001.py!} +``` + +### ะ ะตะดะฐะณัƒะนั‚ะต ั†ะต + +ะฆะต ะดัƒะถะต ะฟั€ะพัั‚ะฐ ะฟั€ะพะณั€ะฐะผะฐ. + +ะะปะต ั‚ะตะฟะตั€ ัƒัะฒั–ั‚ัŒ, ั‰ะพ ะฒะธ ะฟะธัะฐะปะธ ั†ะต ะท ะฝัƒะปั. + +ะฃ ะฟะตะฒะฝะธะน ะผะพะผะตะฝั‚ ะฒะธ ั€ะพะทะฟะพั‡ะฐะปะธ ะฑ ะฒะธะทะฝะฐั‡ะตะฝะฝั ั„ัƒะฝะบั†ั–ั—, ัƒ ะฒะฐั ะฑัƒะปะธ ะฑ ะณะพั‚ะพะฒั– ะฟะฐั€ะฐะผะตั‚ั€ะธ... + +ะะปะต ั‚ะพะดั– ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ ะฒะธะบะปะธะบะฐั‚ะธ "ั‚ะพะน ะผะตั‚ะพะด, ัะบะธะน ะฟะตั€ะตะฒะพะดะธั‚ัŒ ะฟะตั€ัˆัƒ ะปั–ั‚ะตั€ัƒ ัƒ ะฒะตั€ั…ะฝั–ะน ั€ะตะณั–ัั‚ั€". + +ะฆะต ะฑัƒะดะต `upper`? ะงะธ `uppercase`? `first_uppercase`? `capitalize`? + +ะขะพะดั– ะฒะธ ัะฟั€ะพะฑัƒั”ั‚ะต ะดะฐะฒะฝัŒะพะณะพ ะดั€ัƒะณะฐ ะฟั€ะพะณั€ะฐะผั–ัั‚ะฐ - ะฐะฒั‚ะพะทะฐะฟะพะฒะฝะตะฝะฝั ั€ะตะดะฐะบั‚ะพั€ะฐ ะบะพะดัƒ. + +ะ’ะธ ะฝะฐะดั€ัƒะบัƒั”ั‚ะต ะฟะตั€ัˆะธะน ะฟะฐั€ะฐะผะตั‚ั€ ั„ัƒะฝะบั†ั–ั—, `first_name`, ั‚ะพะดั– ะบั€ะฐะฟะบัƒ (`.`), ะฐ ั‚ะพะดั– ะฝะฐั‚ะธัะฝะตั‚ะต `Ctrl+Space`, ั‰ะพะฑ ะทะฐะฟัƒัั‚ะธั‚ะธ ะฐะฒั‚ะพะทะฐะฟะพะฒะฝะตะฝะฝั. + +ะะปะต, ะฝะฐ ะถะฐะปัŒ, ะฒะธ ะฝะต ะพั‚ั€ะธะผะฐั”ั‚ะต ะฝั–ั‡ะพะณะพ ะบะพั€ะธัะฝะพะณะพ: + + + +### ะ”ะพะดะฐะนั‚ะต ั‚ะธะฟะธ + +ะ”ะฐะฒะฐะนั‚ะต ะทะผั–ะฝะธะผะพ ะพะดะธะฝ ั€ัะดะพะบ ะท ะฟะพะฟะตั€ะตะดะฝัŒะพั— ะฒะตั€ัั–ั—. + +ะœะธ ะทะผั–ะฝะธะผะพ ัะฐะผะต ั†ะตะน ั„ั€ะฐะณะผะตะฝั‚, ะฟะฐั€ะฐะผะตั‚ั€ะธ ั„ัƒะฝะบั†ั–ั—, ะท: + +```Python + first_name, last_name +``` + +ะฝะฐ: + +```Python + first_name: str, last_name: str +``` + +ะžััŒ ั– ะฒัะต. + +ะฆะต "type hints": + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial002.py!} +``` + +ะฆะต ะฝะต ั‚ะต ัะฐะผะต, ั‰ะพ ะพะณะพะปะพัˆะตะฝะฝั ะทะฝะฐั‡ะตะฝัŒ ะทะฐ ะทะฐะผะพะฒั‡ัƒะฒะฐะฝะฝัะผ, ัะบ ั†ะต ะฑัƒะปะพ ะฑ ะท: + +```Python + first_name="john", last_name="doe" +``` + +ะฆะต ะทะพะฒัั–ะผ ั–ะฝัˆะต. + +ะœะธ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ะผะพ ะดะฒะพะบั€ะฐะฟะบัƒ (`:`), ะฝะต ะดะพั€ั–ะฒะฝัŽั” (`=`). + +ะ† ะดะพะดะฐะฒะฐะฝะฝั ะฐะฝะพั‚ะฐั†ั–ั— ั‚ะธะฟัƒ ะทะฐะทะฒะธั‡ะฐะน ะฝะต ะทะผั–ะฝัŽั” ั‚ะพะณะพ, ั‰ะพ ัั‚ะฐะปะพััŒ ะฑะธ ะฑะตะท ะฝะธั…. + +ะะปะต ั‚ะตะฟะตั€, ัƒัะฒั–ั‚ัŒ ั‰ะพ ะฒะธ ะฟะพัะตั€ะตะด ะฟั€ะพั†ะตััƒ ัั‚ะฒะพั€ะตะฝะฝั ั„ัƒะฝะบั†ั–ั—, ะฐะปะต ะท ะฐะฝะพั‚ะฐั†ั–ัะผะธ ั‚ะธะฟั–ะฒ. + +ะ’ ั†ะตะน ะถะต ะผะพะผะตะฝั‚, ะฒะธ ัะฟั€ะพะฑัƒั”ั‚ะต ะฒะธะบะปะธะบะฐั‚ะธ ะฐะฒั‚ะพะทะฐะฟะพะฒะฝะตะฝะฝั ะท ะดะพะฟะพะผะพะณะพัŽ `Ctrl+Space` ั– ะฟะพะฑะฐั‡ะธั‚ะต: + + + +ะ ะฐะทะพะผ ะท ั†ะธะผ, ะฒะธ ะผะพะถะตั‚ะต ะฟั€ะพะบั€ัƒั‡ัƒะฒะฐั‚ะธ, ะฟะตั€ะตะณะปัะดะฐั‚ะธ ะพะฟั†ั–ั—, ะดะพะฟะพะบะธ ะฒะธ ะฝะต ะทะฝะฐะนะดะตั‚ะต ะพะดะฝัƒ, ั‰ะพ ะทะฒัƒั‡ะธั‚ัŒ ัั…ะพะถะต: + + + +## ะ‘ั–ะปัŒัˆะต ะผะพั‚ะธะฒะฐั†ั–ั— + +ะŸะตั€ะตะฒั–ั€ั‚ะต ั†ัŽ ั„ัƒะฝะบั†ั–ัŽ, ะฒะพะฝะฐ ะฒะถะต ะผะฐั” ะฐะฝะพั‚ะฐั†ั–ัŽ ั‚ะธะฟัƒ: + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial003.py!} +``` + +ะžัะบั–ะปัŒะบะธ ั€ะตะดะฐะบั‚ะพั€ ะทะฝะฐั” ั‚ะธะฟะธ ะทะผั–ะฝะฝะธั…, ะฒะธ ะฝะต ั‚ั–ะปัŒะบะธ ะพั‚ั€ะธะผะฐั”ั‚ะต ะฐะฒั‚ะพะทะฐะฟะพะฒะฝะตะฝะฝั, ะฒะธ ั‚ะฐะบะพะถ ะพั‚ั€ะธะผะฐั”ั‚ะต ะฟะตั€ะตะฒั–ั€ะบัƒ ะฟะพะผะธะปะพะบ: + + + +ะขะตะฟะตั€ ะฒะธ ะทะฝะฐั”ั‚ะต, ั‰ะพะฑ ะฒะธะฟั€ะฐะฒะธั‚ะธ ั†ะต, ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ `age` ัƒ ัั‚ั€ะพะบัƒ ะท ะดะพะฟะพะผะพะณะพัŽ `str(age)`: + +```Python hl_lines="2" +{!../../../docs_src/python_types/tutorial004.py!} +``` + +## ะžะณะพะปะพัˆะตะฝะฝั ั‚ะธะฟั–ะฒ + +ะฉะพะนะฝะพ ะฒะธ ะฟะพะฑะฐั‡ะธะปะธ ะพัะฝะพะฒะฝะต ะผั–ัั†ะต ะดะปั ะพะณะพะปะพัˆะตะฝะฝั ะฐะฝะพั‚ะฐั†ั–ะน ั‚ะธะฟัƒ. ะฏะบ ะฟะฐั€ะฐะผะตั‚ั€ะธ ั„ัƒะฝะบั†ั–ั—. + +ะฆะต ั‚ะฐะบะพะถ ะพัะฝะพะฒะฝะต ะผั–ัั†ะต, ะดะต ะฒะธ ะฑ ั—ั… ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะปะธ ัƒ **FastAPI**. + +### ะŸั€ะพัั‚ั– ั‚ะธะฟะธ + +ะ’ะธ ะผะพะถะตั‚ะต ะพะณะพะปะพัˆัƒะฒะฐั‚ะธ ัƒัั– ัั‚ะฐะฝะดะฐั€ั‚ะฝั– ั‚ะธะฟะธ ัƒ Python, ะฝะต ั‚ั–ะปัŒะบะธ `str`. + +ะ’ะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ, ะฝะฐะฟั€ะธะบะปะฐะด: + +* `int` +* `float` +* `bool` +* `bytes` + +```Python hl_lines="1" +{!../../../docs_src/python_types/tutorial005.py!} +``` + +### Generic-ั‚ะธะฟะธ ะท ะฟะฐั€ะฐะผะตั‚ั€ะฐะผะธ ั‚ะธะฟั–ะฒ + +ะ†ัะฝัƒัŽั‚ัŒ ะดะตัะบั– ัั‚ั€ัƒะบั‚ัƒั€ะธ ะดะฐะฝะธั…, ัะบั– ะผะพะถัƒั‚ัŒ ะผั–ัั‚ะธั‚ะธ ั–ะฝัˆั– ะทะฝะฐั‡ะตะฝะฝั, ะฝะฐะฟั€ะธะบะปะฐะด `dict`, `list`, `set` ั‚ะฐ `tuple`. ะ† ะฒะฝัƒั‚ั€ั–ัˆะฝั– ะทะฝะฐั‡ะตะฝะฝั ั‚ะฐะบะพะถ ะผะพะถัƒั‚ัŒ ะผะฐั‚ะธ ัะฒั–ะน ั‚ะธะฟ. + +ะฆั– ั‚ะธะฟะธ, ัะบั– ะผะฐัŽั‚ัŒ ะฒะฝัƒั‚ั€ั–ัˆะฝั– ั‚ะธะฟะธ, ะฝะฐะทะธะฒะฐัŽั‚ัŒัั "**generic**" ั‚ะธะฟะฐะผะธ. ะ† ะพะณะพะปะพัะธั‚ะธ ั—ั… ะผะพะถะฝะฐ ะฝะฐะฒั–ั‚ัŒ ั–ะท ะฒะฝัƒั‚ั€ั–ัˆะฝั–ะผะธ ั‚ะธะฟะฐะผะธ. + +ะฉะพะฑ ะพะณะพะปะพัะธั‚ะธ ั†ั– ั‚ะธะฟะธ ั‚ะฐ ะฒะฝัƒั‚ั€ั–ัˆะฝั– ั‚ะธะฟะธ, ะฒะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ัั‚ะฐะฝะดะฐั€ั‚ะฝะธะน ะผะพะดัƒะปัŒ Python `typing`. ะ’ั–ะฝ ั–ัะฝัƒั” ัะฟะตั†ั–ะฐะปัŒะฝะพ ะดะปั ะฟั–ะดั‚ั€ะธะผะบะธ ะฐะฝะพั‚ะฐั†ั–ะน ั‚ะธะฟั–ะฒ. + +#### ะะพะฒั–ัˆั– ะฒะตั€ัั–ั— Python + +ะกะธะฝั‚ะฐะบัะธั ั–ะท ะฒะธะบะพั€ะธัั‚ะฐะฝะฝัะผ `typing` **ััƒะผั–ัะฝะธะน** ะท ัƒัั–ะผะฐ ะฒะตั€ัั–ัะผะธ, ะฒั–ะด Python 3.6 ะดะพ ะพัั‚ะฐะฝะฝั–ั…, ะฒะบะปัŽั‡ะฐัŽั‡ะธ Python 3.9, Python 3.10 ั‚ะพั‰ะพ. + +ะฃ ะผั–ั€ัƒ ั€ะพะทะฒะธั‚ะบัƒ Python **ะฝะพะฒั–ัˆั– ะฒะตั€ัั–ั—** ะผะฐัŽั‚ัŒ ะฟะพะบั€ะฐั‰ะตะฝัƒ ะฟั–ะดั‚ั€ะธะผะบัƒ ะฐะฝะพั‚ะฐั†ั–ะน ั‚ะธะฟั–ะฒ ั– ะฒ ะฑะฐะณะฐั‚ัŒะพั… ะฒะธะฟะฐะดะบะฐั… ะฒะฐะผ ะฝะฐะฒั–ั‚ัŒ ะฝะต ะฟะพั‚ั€ั–ะฑะฝะพ ะฑัƒะดะต ั–ะผะฟะพั€ั‚ัƒะฒะฐั‚ะธ ั‚ะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะผะพะดัƒะปัŒ `typing` ะดะปั ะพะณะพะปะพัˆะตะฝะฝั ะฐะฝะพั‚ะฐั†ั–ะน ั‚ะธะฟัƒ. + +ะฏะบั‰ะพ ะฒะธ ะผะพะถะตั‚ะต ะฒะธะฑั€ะฐั‚ะธ ะฝะพะฒั–ัˆัƒ ะฒะตั€ัั–ัŽ Python ะดะปั ัะฒะพะณะพ ะฟั€ะพะตะบั‚ัƒ, ะฒะธ ะทะผะพะถะตั‚ะต ัะบะพั€ะธัั‚ะฐั‚ะธัั ั†ั–ั”ัŽ ะดะพะดะฐั‚ะบะพะฒะพัŽ ะฟั€ะพัั‚ะพั‚ะพัŽ. ะ”ะธะฒั–ั‚ัŒัั ะบั–ะปัŒะบะฐ ะฟั€ะธะบะปะฐะดั–ะฒ ะฝะธะถั‡ะต. + +#### List (ัะฟะธัะพะบ) + +ะะฐะฟั€ะธะบะปะฐะด, ะดะฐะฒะฐะนั‚ะต ะฒะธะทะฝะฐั‡ะธะผะพ ะทะผั–ะฝะฝัƒ, ัะบะฐ ะฑัƒะดะต `list` ั–ะท `str`. + +=== "Python 3.8 ั– ะฒะธั‰ะต" + + ะ— ะผะพะดัƒะปั `typing`, ั–ะผะฟะพั€ั‚ัƒั”ะผะพ `List` (ะท ะฒะตะปะธะบะพั— ะปั–ั‚ะตั€ะธ `L`): + + ``` Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial006.py!} + ``` + + ะžะณะพะปะพัะธะผะพ ะทะผั–ะฝะฝัƒ ะท ั‚ะธะผ ัะฐะผะธะผ ัะธะฝั‚ะฐะบัะธัะพะผ ะดะฒะพะบั€ะฐะฟะบะธ (`:`). + + ะฏะบ ั‚ะธะฟ ะฒะบะฐะถะตะผะพ `List`, ัะบะธะน ะฒะธ ั–ะผะฟะพั€ั‚ัƒะฒะฐะปะธ ะท `typing`. + + ะžัะบั–ะปัŒะบะธ ัะฟะธัะพะบ ั” ั‚ะธะฟะพะผ, ัะบะธะน ะผั–ัั‚ะธั‚ัŒ ะดะตัะบั– ะฒะฝัƒั‚ั€ั–ัˆะฝั– ั‚ะธะฟะธ, ะฒะธ ะฟะพะผั–ั‰ะฐั”ั‚ะต ั—ั… ัƒ ะบะฒะฐะดั€ะฐั‚ะฝั– ะดัƒะถะบะธ: + + ```Python hl_lines="4" + {!> ../../../docs_src/python_types/tutorial006.py!} + ``` + +=== "Python 3.9 ั– ะฒะธั‰ะต" + + ะžะณะพะปะพัะธะผะพ ะทะผั–ะฝะฝัƒ ะท ั‚ะธะผ ัะฐะผะธะผ ัะธะฝั‚ะฐะบัะธัะพะผ ะดะฒะพะบั€ะฐะฟะบะธ (`:`). + + ะฏะบ ั‚ะธะฟ ะฒะบะฐะถะตะผะพ `list`. + + ะžัะบั–ะปัŒะบะธ ัะฟะธัะพะบ ั” ั‚ะธะฟะพะผ, ัะบะธะน ะผั–ัั‚ะธั‚ัŒ ะดะตัะบั– ะฒะฝัƒั‚ั€ั–ัˆะฝั– ั‚ะธะฟะธ, ะฒะธ ะฟะพะผั–ั‰ะฐั”ั‚ะต ั—ั… ัƒ ะบะฒะฐะดั€ะฐั‚ะฝั– ะดัƒะถะบะธ: + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial006_py39.py!} + ``` + +!!! info + ะฆั– ะฒะฝัƒั‚ั€ั–ัˆะฝั– ั‚ะธะฟะธ ะฒ ะบะฒะฐะดั€ะฐั‚ะฝะธั… ะดัƒะถะบะฐั… ะฝะฐะทะธะฒะฐัŽั‚ัŒัั "ะฟะฐั€ะฐะผะตั‚ั€ะฐะผะธ ั‚ะธะฟัƒ". + + ะฃ ั†ัŒะพะผัƒ ะฒะธะฟะฐะดะบัƒ, `str` ั†ะต ะฟะฐั€ะฐะผะตั‚ั€ ั‚ะธะฟัƒ ะฟะตั€ะตะดะฐะฝะธะน ัƒ `List` (ะฐะฑะพ `list` ัƒ Python 3.9 ั– ะฒะธั‰ะต). + +ะฆะต ะพะทะฝะฐั‡ะฐั”: "ะทะผั–ะฝะฝะฐ `items` ั†ะต `list`, ั– ะบะพะถะตะฝ ะท ะตะปะตะผะตะฝั‚ั–ะฒ ัƒ ั†ัŒะพะผัƒ ัะฟะธัะบัƒ - `str`". + +!!! tip + ะฏะบั‰ะพ ะฒะธ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ะต Python 3.9 ั– ะฒะธั‰ะต, ะฒะฐะผ ะฝะต ะฟะพั‚ั€ั–ะฑะฝะพ ั–ะผะฟะพั€ั‚ัƒะฒะฐั‚ะธ `List` ะท `typing`, ะฒะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะฝะฐั‚ะพะผั–ัั‚ัŒ ั‚ะธะฟ `list`. + +ะ—ั€ะพะฑะธะฒัˆะธ ั†ะต, ะฒะฐัˆ ั€ะตะดะฐะบั‚ะพั€ ะผะพะถะต ะฝะฐะดะฐั‚ะธ ะฟั–ะดั‚ั€ะธะผะบัƒ ะฝะฐะฒั–ั‚ัŒ ะฟั–ะด ั‡ะฐั ะพะฑั€ะพะฑะบะธ ะตะปะตะผะตะฝั‚ั–ะฒ ะทั– ัะฟะธัะบัƒ: + + + +ะ‘ะตะท ั‚ะธะฟั–ะฒ ั†ัŒะพะณะพ ะผะฐะนะถะต ะฝะตะผะพะถะปะธะฒะพ ะดะพััะณั‚ะธ. + +ะ—ะฒะตั€ะฝั–ั‚ัŒ ัƒะฒะฐะณัƒ, ั‰ะพ ะทะผั–ะฝะฝะฐ `item` ั” ะพะดะฝะธะผ ั–ะท ะตะปะตะผะตะฝั‚ั–ะฒ ัƒ ัะฟะธัะบัƒ `items`. + +ะ† ะฒัะต ะถ ั€ะตะดะฐะบั‚ะพั€ ะทะฝะฐั”, ั‰ะพ ั†ะต `str`, ั– ะฝะฐะดะฐั” ะฟั–ะดั‚ั€ะธะผะบัƒ ะดะปั ั†ัŒะพะณะพ. + +#### Tuple and Set (ะบะพั€ั‚ะตะถ ั‚ะฐ ะฝะฐะฑั–ั€) + +ะ’ะธ ะฟะพะฒะธะฝะฝั– ะทั€ะพะฑะธั‚ะธ ั‚ะต ะถ ัะฐะผะต, ั‰ะพะฑ ะพะณะพะปะพัะธั‚ะธ `tuple` ั– `set`: + +=== "Python 3.8 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial007.py!} + ``` + +=== "Python 3.9 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial007_py39.py!} + ``` + +ะฆะต ะพะทะฝะฐั‡ะฐั”: + +* ะ—ะผั–ะฝะฝะฐ `items_t` ั†ะต `tuple` ะท 3 ะตะปะตะผะตะฝั‚ะฐะผะธ, `int`, ั‰ะต `int`, ั‚ะฐ `str`. +* ะ—ะผั–ะฝะฝะฐ `items_s` ั†ะต `set`, ั– ะบะพะถะตะฝ ะนะพะณะพ ะตะปะตะผะตะฝั‚ ั‚ะธะฟัƒ `bytes`. + +#### Dict (ัะปะพะฒะฝะธะบ) + +ะฉะพะฑ ะพะณะพะปะพัะธั‚ะธ `dict`, ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ ะฟะตั€ะตะดะฐั‚ะธ 2 ะฟะฐั€ะฐะผะตั‚ั€ะธ ั‚ะธะฟัƒ, ั€ะพะทะดั–ะปะตะฝั– ะบะพะผะฐะผะธ. + +ะŸะตั€ัˆะธะน ะฟะฐั€ะฐะผะตั‚ั€ ั‚ะธะฟัƒ ะดะปั ะบะปัŽั‡ะฐ ัƒ `dict`. + +ะ”ั€ัƒะณะธะน ะฟะฐั€ะฐะผะตั‚ั€ ั‚ะธะฟัƒ ะดะปั ะทะฝะฐั‡ะตะฝะฝั ัƒ `dict`: + +=== "Python 3.8 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial008.py!} + ``` + +=== "Python 3.9 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial008_py39.py!} + ``` + +ะฆะต ะพะทะฝะฐั‡ะฐั”: + +* ะ—ะผั–ะฝะฝะฐ `prices` ั†ะต `dict`: + * ะšะปัŽั‡ั– ั†ัŒะพะณะพ `dict` ั‚ะธะฟัƒ `str` (ะฝะฐะฟั€ะธะบะปะฐะด, ะฝะฐะทะฒะฐ ะบะพะถะฝะพะณะพ ะตะปะตะผะตะฝั‚ัƒ). + * ะ—ะฝะฐั‡ะตะฝะฝั ั†ัŒะพะณะพ `dict` ั‚ะธะฟัƒ `float` (ะฝะฐะฟั€ะธะบะปะฐะด, ั†ั–ะฝะฐ ะบะพะถะฝะพะณะพ ะตะปะตะผะตะฝั‚ัƒ). + +#### Union (ะพะฑ'ั”ะดะฝะฐะฝะฝั) + +ะ’ะธ ะผะพะถะตั‚ะต ะพะณะพะปะพัะธั‚ะธ, ั‰ะพ ะทะผั–ะฝะฝะฐ ะผะพะถะต ะฑัƒั‚ะธ ะฑัƒะดัŒ-ัะบะธะผ ั–ะท **ะบั–ะปัŒะบะพั… ั‚ะธะฟั–ะฒ**, ะฝะฐะฟั€ะธะบะปะฐะด, `int` ะฐะฑะพ `str`. + +ะฃ Python 3.6 ั– ะฒะธั‰ะต (ะฒะบะปัŽั‡ะฐัŽั‡ะธ Python 3.10) ะฒะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ั‚ะธะฟ `Union` ะท `typing` ั– ะฒัั‚ะฐะฒะปัั‚ะธ ะฒ ะบะฒะฐะดั€ะฐั‚ะฝั– ะดัƒะถะบะธ ะผะพะถะปะธะฒั– ั‚ะธะฟะธ, ัะบั– ะผะพะถะฝะฐ ะฟั€ะธะนะฝัั‚ะธ. + +ะฃ Python 3.10 ั‚ะฐะบะพะถ ั” **ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฝะธะน ัะธะฝั‚ะฐะบัะธั**, ัƒ ัะบะพะผัƒ ะฒะธ ะผะพะถะตั‚ะต ั€ะพะทะดั–ะปะธั‚ะธ ะผะพะถะปะธะฒั– ั‚ะธะฟะธ ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ะฒะตั€ั‚ะธะบะฐะปัŒะฝะพั— ัะผัƒะณะธ (`|`). + +=== "Python 3.8 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial008b.py!} + ``` + +=== "Python 3.10 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial008b_py310.py!} + ``` + +ะ’ ะพะฑะพั… ะฒะธะฟะฐะดะบะฐั… ั†ะต ะพะทะฝะฐั‡ะฐั”, ั‰ะพ `item` ะผะพะถะต ะฑัƒั‚ะธ `int` ะฐะฑะพ `str`. + +#### Possibly `None` (Optional) + +ะ’ะธ ะผะพะถะตั‚ะต ะพะณะพะปะพัะธั‚ะธ, ั‰ะพ ะทะฝะฐั‡ะตะฝะฝั ะผะพะถะต ะผะฐั‚ะธ ั‚ะธะฟ, ะฝะฐะฟั€ะธะบะปะฐะด `str`, ะฐะปะต ั‚ะฐะบะพะถ ะผะพะถะต ะฑัƒั‚ะธ `None`. + +ะฃ Python 3.6 ั– ะฒะธั‰ะต (ะฒะบะปัŽั‡ะฐัŽั‡ะธ Python 3.10) ะฒะธ ะผะพะถะตั‚ะต ะพะณะพะปะพัะธั‚ะธ ะนะพะณะพ, ั–ะผะฟะพั€ั‚ัƒะฒะฐะฒัˆะธ ั‚ะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ `Optional` ะท ะผะพะดัƒะปั `typing`. + +```Python hl_lines="1 4" +{!../../../docs_src/python_types/tutorial009.py!} +``` + +ะ’ะธะบะพั€ะธัั‚ะฐะฝะฝั `Optional[str]` ะทะฐะผั–ัั‚ัŒ ะฟั€ะพัั‚ะพ `str` ะดะพะทะฒะพะปะธั‚ัŒ ั€ะตะดะฐะบั‚ะพั€ัƒ ะดะพะฟะพะผะพะณั‚ะธ ะฒะฐะผ ะฒะธัะฒะธั‚ะธ ะฟะพะผะธะปะบะธ, ะบะพะปะธ ะฒะธ ะผะพะณะปะธ ะฑ ะฒะฒะฐะถะฐั‚ะธ, ั‰ะพ ะทะฝะฐั‡ะตะฝะฝัะผ ะทะฐะฒะถะดะธ ั” `str`, ั…ะพั‡ะฐ ะฝะฐัะฟั€ะฐะฒะดั– ะฒะพะฝะพ ั‚ะฐะบะพะถ ะผะพะถะต ะฑัƒั‚ะธ `None`. + +`Optional[Something]` ะฝะฐัะฟั€ะฐะฒะดั– ั” ัะบะพั€ะพั‡ะตะฝะฝัะผ ะดะปั `Union[Something, None]`, ะฒะพะฝะธ ะตะบะฒั–ะฒะฐะปะตะฝั‚ะฝั–. + +ะฆะต ั‚ะฐะบะพะถ ะพะทะฝะฐั‡ะฐั”, ั‰ะพ ะฒ Python 3.10 ะฒะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `Something | None`: + +=== "Python 3.8 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial009.py!} + ``` + +=== "Python 3.8 ั– ะฒะธั‰ะต - ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฐ" + + ```Python hl_lines="1 4" + {!> ../../../docs_src/python_types/tutorial009b.py!} + ``` + +=== "Python 3.10 ั– ะฒะธั‰ะต" + + ```Python hl_lines="1" + {!> ../../../docs_src/python_types/tutorial009_py310.py!} + ``` + +#### Generic ั‚ะธะฟะธ + +ะฆั– ั‚ะธะฟะธ, ัะบั– ะฟั€ะธะนะผะฐัŽั‚ัŒ ะฟะฐั€ะฐะผะตั‚ั€ะธ ั‚ะธะฟัƒ ัƒ ะบะฒะฐะดั€ะฐั‚ะฝะธั… ะดัƒะถะบะฐั…, ะฝะฐะทะธะฒะฐัŽั‚ัŒัั **Generic types** or **Generics**, ะฝะฐะฟั€ะธะบะปะฐะด: + +=== "Python 3.8 ั– ะฒะธั‰ะต" + + * `List` + * `Tuple` + * `Set` + * `Dict` + * `Union` + * `Optional` + * ...ั‚ะฐ ั–ะฝัˆั–. + +=== "Python 3.9 ั– ะฒะธั‰ะต" + + ะ’ะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ั‚ั– ัะฐะผั– ะฒะฑัƒะดะพะฒะฐะฝั– ั‚ะธะฟะธ, ัะบ generic (ะท ะบะฒะฐะดั€ะฐั‚ะฝะธะผะธ ะดัƒะถะบะฐะผะธ ั‚ะฐ ั‚ะธะฟะฐะผะธ ะฒัะตั€ะตะดะธะฝั–): + + * `list` + * `tuple` + * `set` + * `dict` + + ะ† ั‚ะต ัะฐะผะต, ั‰ะพ ะน ัƒ Python 3.8, ั–ะท ะผะพะดัƒะปั `typing`: + + * `Union` + * `Optional` + * ...ั‚ะฐ ั–ะฝัˆั–. + +=== "Python 3.10 ั– ะฒะธั‰ะต" + + ะ’ะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ั‚ั– ัะฐะผั– ะฒะฑัƒะดะพะฒะฐะฝั– ั‚ะธะฟะธ, ัะบ generic (ะท ะบะฒะฐะดั€ะฐั‚ะฝะธะผะธ ะดัƒะถะบะฐะผะธ ั‚ะฐ ั‚ะธะฟะฐะผะธ ะฒัะตั€ะตะดะธะฝั–): + + * `list` + * `tuple` + * `set` + * `dict` + + ะ† ั‚ะต ัะฐะผะต, ั‰ะพ ะน ัƒ Python 3.8, ั–ะท ะผะพะดัƒะปั `typing`: + + * `Union` + * `Optional` (ั‚ะฐะบ ัะฐะผะพ ัะบ ัƒ Python 3.8) + * ...ั‚ะฐ ั–ะฝัˆั–. + + ะฃ Python 3.10, ัะบ ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฐ ะฒะธะบะพั€ะธัั‚ะฐะฝะฝัŽ `Union` ั‚ะฐ `Optional`, ะฒะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะฒะตั€ั‚ะธะบะฐะปัŒะฝัƒ ัะผัƒะณัƒ (`|`) ั‰ะพะฑ ะพะณะพะปะพัะธั‚ะธ ะพะฑ'ั”ะดะฝะฐะฝะฝั ั‚ะธะฟั–ะฒ. + +### ะšะปะฐัะธ ัะบ ั‚ะธะฟะธ + +ะ’ะธ ั‚ะฐะบะพะถ ะผะพะถะตั‚ะต ะพะณะพะปะพัะธั‚ะธ ะบะปะฐั ัะบ ั‚ะธะฟ ะทะผั–ะฝะฝะพั—. + +ะกะบะฐะถั–ะผะพ, ัƒ ะฒะฐั ั” ะบะปะฐั `Person` ะท ั–ะผสผัะผ: + +```Python hl_lines="1-3" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +ะŸะพั‚ั–ะผ ะฒะธ ะผะพะถะตั‚ะต ะพะณะพะปะพัะธั‚ะธ ะทะผั–ะฝะฝัƒ ั‚ะธะฟัƒ `Person`: + +```Python hl_lines="6" +{!../../../docs_src/python_types/tutorial010.py!} +``` + +ะ† ะทะฝะพะฒัƒ ะถ ั‚ะฐะบะธ, ะฒะธ ะพั‚ั€ะธะผัƒั”ั‚ะต ะฒััŽ ะฟั–ะดั‚ั€ะธะผะบัƒ ั€ะตะดะฐะบั‚ะพั€ะฐ: + + + +## Pydantic ะผะพะดะตะปั– + +Pydantic ั†ะต ะฑั–ะฑะปั–ะพั‚ะตะบะฐ Python ะดะปั ะฒะฐะปั–ะดะฐั†ั–ั— ะดะฐะฝะธั…. + +ะ’ะธ ะพะณะพะปะพัˆัƒั”ั‚ะต ยซั„ะพั€ะผัƒยป ะดะฐะฝะธั… ัะบ ะบะปะฐัะธ ะท ะฐั‚ั€ะธะฑัƒั‚ะฐะผะธ. + +ะ† ะบะพะถะตะฝ ะฐั‚ั€ะธะฑัƒั‚ ะผะฐั” ั‚ะธะฟ. + +ะŸะพั‚ั–ะผ ะฒะธ ัั‚ะฒะพั€ัŽั”ั‚ะต ะตะบะทะตะผะฟะปัั€ ั†ัŒะพะณะพ ะบะปะฐััƒ ะท ะดะตัะบะธะผะธ ะทะฝะฐั‡ะตะฝะฝัะผะธ, ั– ะฒั–ะฝ ะฟะตั€ะตะฒั–ั€ะธั‚ัŒ ั†ั– ะทะฝะฐั‡ะตะฝะฝั, ะฟะตั€ะตั‚ะฒะพั€ะธั‚ัŒ ั—ั… ัƒ ะฒั–ะดะฟะพะฒั–ะดะฝะธะน ั‚ะธะฟ (ัะบั‰ะพ ั” ะฟะพั‚ั€ะตะฑะฐ) ั– ะฝะฐะดะฐัั‚ัŒ ะฒะฐะผ ะพะฑโ€™ั”ะบั‚ ะท ัƒัั–ะผะฐ ะดะฐะฝะธะผะธ. + +ะ† ะฒะธ ะพั‚ั€ะธะผัƒั”ั‚ะต ะฒััŽ ะฟั–ะดั‚ั€ะธะผะบัƒ ั€ะตะดะฐะบั‚ะพั€ะฐ ะท ั†ะธะผ ะพั‚ั€ะธะผะฐะฝะธะผ ะพะฑโ€™ั”ะบั‚ะพะผ. + +ะŸั€ะธะบะปะฐะด ะท ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— Pydantic: + +=== "Python 3.8 ั– ะฒะธั‰ะต" + + ```Python + {!> ../../../docs_src/python_types/tutorial011.py!} + ``` + +=== "Python 3.9 ั– ะฒะธั‰ะต" + + ```Python + {!> ../../../docs_src/python_types/tutorial011_py39.py!} + ``` + +=== "Python 3.10 ั– ะฒะธั‰ะต" + + ```Python + {!> ../../../docs_src/python_types/tutorial011_py310.py!} + ``` + +!!! info + ะฉะพะฑ ะดั–ะทะฝะฐั‚ะธััŒ ะฑั–ะปัŒัˆะต ะฟั€ะพ Pydantic, ะฟะตั€ะตะณะปัะฝัŒั‚ะต ะนะพะณะพ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ัŽ. + +**FastAPI** ะฟะพะฒะฝั–ัั‚ัŽ ะฑะฐะทัƒั”ั‚ัŒัั ะฝะฐ Pydantic. + +ะ’ะธ ะฟะพะฑะฐั‡ะธั‚ะต ะฝะฐะฑะฐะณะฐั‚ะพ ะฑั–ะปัŒัˆะต ั†ัŒะพะณะพ ะฒััŒะพะณะพ ะฝะฐ ะฟั€ะฐะบั‚ะธั†ั– ะฒ [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}. + +## ะะฝะพั‚ะฐั†ั–ั— ั‚ะธะฟั–ะฒ ัƒ **FastAPI** + +**FastAPI** ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ั†ั– ะฟั–ะดะบะฐะทะบะธ ะดะปั ะฒะธะบะพะฝะฐะฝะฝั ะบั–ะปัŒะบะพั… ั€ะตั‡ะตะน. + +ะ— **FastAPI** ะฒะธ ะพะณะพะปะพัˆัƒั”ั‚ะต ะฟะฐั€ะฐะผะตั‚ั€ะธ ะท ะฟั–ะดะบะฐะทะบะฐะผะธ ั‚ะธะฟัƒ, ั– ะพั‚ั€ะธะผัƒั”ั‚ะต: + +* **ะŸั–ะดั‚ั€ะธะผะบัƒ ั€ะตะดะฐะบั‚ะพั€ะฐ**. +* **ะŸะตั€ะตะฒั–ั€ะบัƒ ั‚ะธะฟั–ะฒ**. + +...ั– **FastAPI** ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ั‚ั– ัะฐะผั– ะพะณะพะปะพัˆะตะฝะฝั ะดะปั: + +* **ะ’ะธะทะฝะฐั‡ะตะฝะฝั ะฒะธะผะพะณ**: ะท ะฟะฐั€ะฐะผะตั‚ั€ั–ะฒ ัˆะปัั…ัƒ ะทะฐะฟะธั‚ัƒ, ะฟะฐั€ะฐะผะตั‚ั€ั–ะฒ ะทะฐะฟะธั‚ัƒ, ะทะฐะณะพะปะพะฒะบั–ะฒ, ั‚ั–ะป, ะทะฐะปะตะถะฝะพัั‚ะตะน ั‚ะพั‰ะพ. +* **ะŸะตั€ะตั‚ะฒะพั€ะตะฝะฝั ะดะฐะฝะธั…**: ั–ะท ะทะฐะฟะธั‚ัƒ ะฒ ะฝะตะพะฑั…ั–ะดะฝะธะน ั‚ะธะฟ. +* **ะŸะตั€ะตะฒั–ั€ะบะฐ ะดะฐะฝะธั…**: ั‰ะพ ะฝะฐะดั…ะพะดัั‚ัŒ ะฒั–ะด ะบะพะถะฝะพะณะพ ะทะฐะฟะธั‚ัƒ: + * ะ“ะตะฝะตั€ัƒะฒะฐะฝะฝั **ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะธั… ะฟะพะผะธะปะพะบ**, ั‰ะพ ะฟะพะฒะตั€ั‚ะฐัŽั‚ัŒัั ะบะปั–ั”ะฝั‚ัƒ, ะบะพะปะธ ะดะฐะฝั– ะฝะตะดั–ะนัะฝั–. +* **ะ”ะพะบัƒะผะตะฝั‚ัƒะฒะฐะฝะฝั** API ะทะฐ ะดะพะฟะพะผะพะณะพัŽ OpenAPI: + * ัะบะธะน ะฟะพั‚ั–ะผ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ะดะปั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพั— ั–ะฝั‚ะตั€ะฐะบั‚ะธะฒะฝะพั— ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั— ะบะพั€ะธัั‚ัƒะฒะฐะปัŒะฝะธั†ัŒะบะธั… ั–ะฝั‚ะตั€ั„ะตะนัั–ะฒ. + +ะ’ัะต ั†ะต ะผะพะถะต ะทะดะฐั‚ะธัั ะฐะฑัั‚ั€ะฐะบั‚ะฝะธะผ. ะะต ั…ะฒะธะปัŽะนั‚ะตัั. ะ’ะธ ะฟะพะฑะฐั‡ะธั‚ะต ะฒัะต ั†ะต ะฒ ะดั–ั— ะฒ [ะขัƒั‚ะพั€ั–ะฐะป - ะŸะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ](tutorial/index.md){.internal-link target=_blank}. + +ะ’ะฐะถะปะธะฒะพ ั‚ะต, ั‰ะพ ะทะฐ ะดะพะฟะพะผะพะณะพัŽ ัั‚ะฐะฝะดะฐั€ั‚ะฝะธั… ั‚ะธะฟั–ะฒ Python ะฒ ะพะดะฝะพะผัƒ ะผั–ัั†ั– (ะทะฐะผั–ัั‚ัŒ ั‚ะพะณะพ, ั‰ะพะฑ ะดะพะดะฐะฒะฐั‚ะธ ะฑั–ะปัŒัˆะต ะบะปะฐัั–ะฒ, ะดะตะบะพั€ะฐั‚ะพั€ั–ะฒ ั‚ะพั‰ะพ), **FastAPI** ะทั€ะพะฑะธั‚ัŒ ะฑะฐะณะฐั‚ะพ ั€ะพะฑะพั‚ะธ ะทะฐ ะฒะฐั. + +!!! info + ะฏะบั‰ะพ ะฒะธ ะฒะถะต ะฟั€ะพะนัˆะปะธ ะฒะตััŒ ะฝะฐะฒั‡ะฐะปัŒะฝะธะน ะฟะพัั–ะฑะฝะธะบ ั– ะฟะพะฒะตั€ะฝัƒะปะธัั, ั‰ะพะฑ ะดั–ะทะฝะฐั‚ะธัั ะฑั–ะปัŒัˆะต ะฟั€ะพ ั‚ะธะฟะธ, ะพััŒ ั…ะพั€ะพัˆะธะน ั€ะตััƒั€ั "ัˆะฟะฐั€ะณะฐะปะบะฐ" ะฒั–ะด `mypy`. diff --git a/docs/uk/docs/tutorial/body.md b/docs/uk/docs/tutorial/body.md index e78c5de0e..9759e7f45 100644 --- a/docs/uk/docs/tutorial/body.md +++ b/docs/uk/docs/tutorial/body.md @@ -19,7 +19,7 @@ ะกะฟะพั‡ะฐั‚ะบัƒ ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ ั–ะผะฟะพั€ั‚ัƒะฒะฐั‚ะธ `BaseModel` ะท `pydantic`: -=== "Python 3.6 ั– ะฒะธั‰ะต" +=== "Python 3.8 ั– ะฒะธั‰ะต" ```Python hl_lines="4" {!> ../../../docs_src/body/tutorial001.py!} @@ -37,7 +37,7 @@ ะ’ะธะบะพั€ะธัั‚ะพะฒัƒะนั‚ะต ัั‚ะฐะฝะดะฐั€ั‚ะฝั– ั‚ะธะฟะธ Python ะดะปั ะฒัั–ั… ะฐั‚ั€ะธะฑัƒั‚ั–ะฒ: -=== "Python 3.6 ั– ะฒะธั‰ะต" +=== "Python 3.8 ั– ะฒะธั‰ะต" ```Python hl_lines="7-11" {!> ../../../docs_src/body/tutorial001.py!} @@ -75,7 +75,7 @@ ะฉะพะฑ ะดะพะดะฐั‚ะธ ะผะพะดะตะปัŒ ะดะฐะฝะธั… ะดะพ ะฒะฐัˆะพั— *ะพะฟะตั€ะฐั†ั–ั— ัˆะปัั…ัƒ*, ะพะณะพะปะพัั–ั‚ัŒ ั—ั— ั‚ะฐะบ ัะฐะผะพ, ัะบ ะฒะธ ะพะณะพะปะพัะธะปะธ ะฟะฐั€ะฐะผะตั‚ั€ะธ ัˆะปัั…ัƒ ั‚ะฐ ะทะฐะฟะธั‚ัƒ: -=== "Python 3.6 ั– ะฒะธั‰ะต" +=== "Python 3.8 ั– ะฒะธั‰ะต" ```Python hl_lines="18" {!> ../../../docs_src/body/tutorial001.py!} @@ -149,7 +149,7 @@ ะฃัะตั€ะตะดะธะฝั– ั„ัƒะฝะบั†ั–ั— ะฒะธ ะผะพะถะตั‚ะต ะพั‚ั€ะธะผะฐั‚ะธ ะฟั€ัะผะธะน ะดะพัั‚ัƒะฟ ะดะพ ะฒัั–ั… ะฐั‚ั€ะธะฑัƒั‚ั–ะฒ ะพะฑโ€™ั”ะบั‚ะฐ ะผะพะดะตะปั–: -=== "Python 3.6 ั– ะฒะธั‰ะต" +=== "Python 3.8 ั– ะฒะธั‰ะต" ```Python hl_lines="21" {!> ../../../docs_src/body/tutorial002.py!} @@ -167,7 +167,7 @@ **FastAPI** ั€ะพะทะฟั–ะทะฝะฐั”, ั‰ะพ ะฟะฐั€ะฐะผะตั‚ั€ะธ ั„ัƒะฝะบั†ั–ั—, ัะบั– ะฒั–ะดะฟะพะฒั–ะดะฐัŽั‚ัŒ ะฟะฐั€ะฐะผะตั‚ั€ะฐะผ ัˆะปัั…ัƒ, ะผะฐัŽั‚ัŒ ะฑัƒั‚ะธ **ะฒะทัั‚ั– ะท ัˆะปัั…ัƒ**, ะฐ ะฟะฐั€ะฐะผะตั‚ั€ะธ ั„ัƒะฝะบั†ั–ั—, ัะบั– ะพะณะพะปะพัˆัƒัŽั‚ัŒัั ัะบ ะผะพะดะตะปั– Pydantic, **ะฒะทัั‚ั– ะท ั‚ั–ะปะฐ ะทะฐะฟะธั‚ัƒ**. -=== "Python 3.6 ั– ะฒะธั‰ะต" +=== "Python 3.8 ั– ะฒะธั‰ะต" ```Python hl_lines="17-18" {!> ../../../docs_src/body/tutorial003.py!} @@ -185,7 +185,7 @@ **FastAPI** ั€ะพะทะฟั–ะทะฝะฐั” ะบะพะถะตะฝ ะท ะฝะธั… ั– ะฒั–ะทัŒะผะต ะดะฐะฝั– ะท ะฟะพั‚ั€ั–ะฑะฝะพะณะพ ะผั–ัั†ั. -=== "Python 3.6 ั– ะฒะธั‰ะต" +=== "Python 3.8 ั– ะฒะธั‰ะต" ```Python hl_lines="18" {!> ../../../docs_src/body/tutorial004.py!} diff --git a/docs/uk/docs/tutorial/cookie-params.md b/docs/uk/docs/tutorial/cookie-params.md index 2b0e8993c..199b93839 100644 --- a/docs/uk/docs/tutorial/cookie-params.md +++ b/docs/uk/docs/tutorial/cookie-params.md @@ -18,7 +18,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/cookie_params/tutorial001_an.py!} @@ -33,7 +33,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ะ‘ะฐะถะฐะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `Annotated` ะฒะตั€ัั–ัŽ, ัะบั‰ะพ ั†ะต ะผะพะถะปะธะฒะพ. @@ -60,7 +60,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/cookie_params/tutorial001_an.py!} @@ -75,7 +75,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ะ‘ะฐะถะฐะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `Annotated` ะฒะตั€ัั–ัŽ, ัะบั‰ะพ ั†ะต ะผะพะถะปะธะฒะพ. diff --git a/docs/uk/docs/tutorial/encoder.md b/docs/uk/docs/tutorial/encoder.md new file mode 100644 index 000000000..b6583341f --- /dev/null +++ b/docs/uk/docs/tutorial/encoder.md @@ -0,0 +1,42 @@ +# JSON Compatible Encoder + +ะ†ัะฝัƒัŽั‚ัŒ ะฒะธะฟะฐะดะบะธ, ะบะพะปะธ ะฒะฐะผ ะผะพะถะต ะทะฝะฐะดะพะฑะธั‚ะธัั ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ั‚ะธะฟ ะดะฐะฝะธั… (ะฝะฐะฟั€ะธะบะปะฐะด, ะผะพะดะตะปัŒ Pydantic) ะฒ ั‰ะพััŒ ััƒะผั–ัะฝะต ะท JSON (ะฝะฐะฟั€ะธะบะปะฐะด, `dict`, `list`, ั– ั‚. ะด.). + +ะะฐะฟั€ะธะบะปะฐะด, ัะบั‰ะพ ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ ะทะฑะตั€ะตะณั‚ะธ ั†ะต ะฒ ะฑะฐะทั– ะดะฐะฝะธั…. + +ะ”ะปั ั†ัŒะพะณะพ, **FastAPI** ะฝะฐะดะฐั” `jsonable_encoder()` ั„ัƒะฝะบั†ั–ัŽ. + +## ะ’ะธะบะพั€ะธัั‚ะฐะฝะฝั `jsonable_encoder` + +ะ”ะฐะฒะฐะนั‚ะต ัƒัะฒะธะผะพ, ั‰ะพ ัƒ ะฒะฐั ั” ะฑะฐะทะฐ ะดะฐะฝะธั… `fake_db`, ัะบะฐ ะฟั€ะธะนะผะฐั” ะปะธัˆะต ะดะฐะฝั–, ััƒะผั–ัะฝั– ะท JSON. + +ะะฐะฟั€ะธะบะปะฐะด, ะฒะพะฝะฐ ะฝะต ะฟั€ะธะนะผะฐั” ะพะฑ'ั”ะบั‚ะธ ั‚ะธะฟัƒ `datetime`, ะพัะบั–ะปัŒะบะธ ะฒะพะฝะธ ะฝะต ััƒะผั–ัะฝั– ะท JSON. + +ะžั‚ะถะต, ะพะฑ'ั”ะบั‚ ั‚ะธะฟัƒ `datetime` ะฟะพั‚ั€ั–ะฑะฝะพ ะฟะตั€ะตั‚ะฒะพั€ะธั‚ะธ ะฒ ั€ัะดะพะบ `str`, ัะบะธะน ะผั–ัั‚ะธั‚ัŒ ะดะฐะฝั– ะฒ ISO ั„ะพั€ะผะฐั‚ั–. + +ะขะธะผ ัะฐะผะธะผ ัะฟะพัะพะฑะพะผ ั†ั ะฑะฐะทะฐ ะดะฐะฝะธั… ะฝะต ะฟั€ะธะนะผะฐั‚ะธะผะต ะพะฑ'ั”ะบั‚ ั‚ะธะฟัƒ Pydantic model (ะพะฑ'ั”ะบั‚ ะท ะฐั‚ั€ะธะฑัƒั‚ะฐะผะธ), ะฐ ะปะธัˆะต `dict`. + +ะ’ะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `jsonable_encoder` ะดะปั ั†ัŒะพะณะพ. + +ะ’ะพะฝะฐ ะฟั€ะธะนะผะฐั” ะพะฑ'ั”ะบั‚, ั‚ะฐะบะธะน ัะบ Pydantic model, ั– ะฟะพะฒะตั€ั‚ะฐั” ะนะพะณะพ ะฒะตั€ัั–ัŽ, ััƒะผั–ัะฝัƒ ะท JSON: + +=== "Python 3.10+" + + ```Python hl_lines="4 21" + {!> ../../../docs_src/encoder/tutorial001_py310.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="5 22" + {!> ../../../docs_src/encoder/tutorial001.py!} + ``` + +ะฃ ั†ัŒะพะผัƒ ะฟั€ะธะบะปะฐะดั– ะฒะพะฝะฐ ะบะพะฝะฒะตั€ั‚ัƒั” Pydantic model ัƒ `dict`, ะฐ `datetime` ัƒ `str`. + +ะ ะตะทัƒะปัŒั‚ะฐั‚ ะฒะธะบะปะธะบัƒ ั†ั–ั”ั— ั„ัƒะฝะบั†ั–ั— - ั†ะต ั‰ะพััŒ, ั‰ะพ ะผะพะถะฝะฐ ะบะพะดัƒะฒะฐั‚ะธ ะท ะฒะธะบะพั€ะธัั‚ะฐะฝะฝัะผ ัั‚ะฐะฝะดะฐั€ั‚ัƒ Python `json.dumps()`. + +ะ’ะพะฝะฐ ะฝะต ะฟะพะฒะตั€ั‚ะฐั” ะฒะตะปะธะบัƒ ัั‚ั€ะพะบัƒ `str`, ัะบะฐ ะผั–ัั‚ะธั‚ัŒ ะดะฐะฝั– ัƒ ั„ะพั€ะผะฐั‚ั– JSON (ัะบ ัั‚ั€ะพะบะฐ). ะ’ะพะฝะฐ ะฟะพะฒะตั€ั‚ะฐั” ัั‚ะฐะฝะดะฐั€ั‚ะฝัƒ ัั‚ั€ัƒะบั‚ัƒั€ัƒ ะดะฐะฝะธั… Python (ะฝะฐะฟั€ะธะบะปะฐะด `dict`) ั–ะท ะทะฝะฐั‡ะตะฝะฝัะผะธ ั‚ะฐ ะฟั–ะดะทะฝะฐั‡ะตะฝะฝัะผะธ, ัะบั– ั” ััƒะผั–ัะฝะธะผะธ ะท JSON. + +!!! ะŸั€ะธะผั–ั‚ะบะฐ + `jsonable_encoder` ั„ะฐะบั‚ะธั‡ะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั **FastAPI** ะฒะฝัƒั‚ั€ั–ัˆะฝัŒะพ ะดะปั ะฟะตั€ะตั‚ะฒะพั€ะตะฝะฝั ะดะฐะฝะธั…. ะŸั€ะพั‚ะต ะฒะพะฝะฐ ะบะพั€ะธัะฝะฐ ะฒ ะฑะฐะณะฐั‚ัŒะพั… ั–ะฝัˆะธั… ัั†ะตะฝะฐั€ั–ัั…. diff --git a/docs/uk/docs/tutorial/extra-data-types.md b/docs/uk/docs/tutorial/extra-data-types.md new file mode 100644 index 000000000..ec5ec0d18 --- /dev/null +++ b/docs/uk/docs/tutorial/extra-data-types.md @@ -0,0 +1,130 @@ +# ะ”ะพะดะฐั‚ะบะพะฒั– ั‚ะธะฟะธ ะดะฐะฝะธั… + +ะ”ะพ ั†ัŒะพะณะพ ั‡ะฐััƒ, ะฒะธ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐะปะธ ะทะฐะณะฐะปัŒะฝะพะฟะพัˆะธั€ะตะฝั– ั‚ะธะฟะธ ะดะฐะฝะธั…, ั‚ะฐะบั– ัะบ: + +* `int` +* `float` +* `str` +* `bool` + +ะะปะต ะผะพะถะฝะฐ ั‚ะฐะบะพะถ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะฑั–ะปัŒัˆ ัะบะปะฐะดะฝั– ั‚ะธะฟะธ ะดะฐะฝะธั…. + +ะ† ะฒะธ ะฒัะต ั‰ะต ะผะฐั‚ะธะผะตั‚ะต ั‚ั– ะถ ะผะพะถะปะธะฒะพัั‚ั–, ัะบั– ะฑัƒะปะธ ะฟะพะบะฐะทะฐะฝั– ะดะพ ั†ัŒะพะณะพ: + +* ะงัƒะดะพะฒะฐ ะฟั–ะดั‚ั€ะธะผะบะฐ ั€ะตะดะฐะบั‚ะพั€ะฐ. +* ะšะพะฝะฒะตั€ั‚ะฐั†ั–ั ะดะฐะฝะธั… ะท ะฒั…ั–ะดะฝะธั… ะทะฐะฟะธั‚ั–ะฒ. +* ะšะพะฝะฒะตั€ั‚ะฐั†ั–ั ะดะฐะฝะธั… ะดะปั ะฒั–ะดะฟะพะฒั–ะดั–. +* ะ’ะฐะปั–ะดะฐั†ั–ั ะดะฐะฝะธั…. +* ะะฒั‚ะพะผะฐั‚ะธั‡ะฝะฐ ะฐะฝะพั‚ะฐั†ั–ั ั‚ะฐ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั. + +## ะ†ะฝัˆั– ั‚ะธะฟะธ ะดะฐะฝะธั… + +ะžััŒ ะดะพะดะฐั‚ะบะพะฒั– ั‚ะธะฟะธ ะดะฐะฝะธั… ะดะปั ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั: + +* `UUID`: + * ะกั‚ะฐะฝะดะฐั€ั‚ะฝะธะน "ะฃะฝั–ะฒะตั€ัะฐะปัŒะฝะธะน ะฃะฝั–ะบะฐะปัŒะฝะธะน ะ†ะดะตะฝั‚ะธั„ั–ะบะฐั‚ะพั€", ัะบะธะน ั‡ะฐัั‚ะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒั”ั‚ัŒัั ัะบ ั–ะดะตะฝั‚ะธั„ั–ะบะฐั‚ะพั€ ัƒ ะฑะฐะณะฐั‚ัŒะพั… ะฑะฐะทะฐั… ะดะฐะฝะธั… ั‚ะฐ ัะธัั‚ะตะผะฐั…. + * ะฃ ะทะฐะฟะธั‚ะฐั… ั‚ะฐ ะฒั–ะดะฟะพะฒั–ะดัั… ะฑัƒะดะต ะฟั€ะตะดัั‚ะฐะฒะปะตะฝะธะน ัะบ `str`. +* `datetime.datetime`: + * ะŸะฐะนั‚ะพะฝั–ะฒััŒะบะธะน `datetime.datetime`. + * ะฃ ะทะฐะฟะธั‚ะฐั… ั‚ะฐ ะฒั–ะดะฟะพะฒั–ะดัั… ะฑัƒะดะต ะฟั€ะตะดัั‚ะฐะฒะปะตะฝะธะน ัะบ `str` ะฒ ั„ะพั€ะผะฐั‚ั– ISO 8601, ัะบ: `2008-09-15T15:53:00+05:00`. +* `datetime.date`: + * ะŸะฐะนั‚ะพะฝั–ะฒััŒะบะธะน `datetime.date`. + * ะฃ ะทะฐะฟะธั‚ะฐั… ั‚ะฐ ะฒั–ะดะฟะพะฒั–ะดัั… ะฑัƒะดะต ะฟั€ะตะดัั‚ะฐะฒะปะตะฝะธะน ัะบ `str` ะฒ ั„ะพั€ะผะฐั‚ั– ISO 8601, ัะบ: `2008-09-15`. +* `datetime.time`: + * ะŸะฐะนั‚ะพะฝั–ะฒััŒะบะธะน `datetime.time`. + * ะฃ ะทะฐะฟะธั‚ะฐั… ั‚ะฐ ะฒั–ะดะฟะพะฒั–ะดัั… ะฑัƒะดะต ะฟั€ะตะดัั‚ะฐะฒะปะตะฝะธะน ัะบ `str` ะฒ ั„ะพั€ะผะฐั‚ั– ISO 8601, ัะบ: `14:23:55.003`. +* `datetime.timedelta`: + * ะŸะฐะนั‚ะพะฝั–ะฒััŒะบะธะน `datetime.timedelta`. + * ะฃ ะทะฐะฟะธั‚ะฐั… ั‚ะฐ ะฒั–ะดะฟะพะฒั–ะดัั… ะฑัƒะดะต ะฟั€ะตะดัั‚ะฐะฒะปะตะฝะธะน ัะบ `float` ะทะฐะณะฐะปัŒะฝะพั— ะบั–ะปัŒะบะพัั‚ั– ัะตะบัƒะฝะด. + * Pydantic ั‚ะฐะบะพะถ ะดะพะทะฒะพะปัั” ะฟั€ะตะดัั‚ะฐะฒะปัั‚ะธ ั†ะต ัะบ "ISO 8601 time diff encoding", ะฑั–ะปัŒัˆะต ั–ะฝั„ะพั€ะผะฐั†ั–ั— ะดะธะฒะธััŒ ัƒ ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั—. +* `frozenset`: + * ะฃ ะทะฐะฟะธั‚ะฐั… ั– ะฒั–ะดะฟะพะฒั–ะดัั… ั†ะต ะฑัƒะดะต ะพะฑั€ะพะฑะปะตะฝะพ ั‚ะฐะบ ัะฐะผะพ, ัะบ ั– `set`: + * ะฃ ะทะฐะฟะธั‚ะฐั… ัะฟะธัะพะบ ะฑัƒะดะต ะทั‡ะธั‚ะฐะฝะพ, ะดัƒะฑะปั–ะบะฐั‚ะธ ะฑัƒะดัƒั‚ัŒ ะฒะธะดะฐะปะตะฝั– ั‚ะฐ ะฒั–ะฝ ะฑัƒะดะต ะฟะตั€ะตั‚ะฒะพั€ะตะฝะธะน ะฝะฐ `set`. + * ะฃ ะฒั–ะดะฟะพะฒั–ะดัั…, `set` ะฑัƒะดะต ะฟะตั€ะตั‚ะฒะพั€ะตะฝะธะน ะฝะฐ `list`. + * ะ—ะณะตะฝะตั€ะพะฒะฐะฝะฐ ัั…ะตะผะฐ ะฑัƒะดะต ะฒะบะฐะทัƒะฒะฐั‚ะธ, ั‰ะพ ะทะฝะฐั‡ะตะฝะฝั `set` ั” ัƒะฝั–ะบะฐะปัŒะฝะธะผะธ (ะท ะฒะธะบะพั€ะธัั‚ะฐะฝะฝัะผ JSON Schema's `uniqueItems`). +* `bytes`: + * ะกั‚ะฐะฝะดะฐั€ั‚ะฝะธะน ะŸะฐะนั‚ะพะฝั–ะฒััŒะบะธะน `bytes`. + * ะฃ ะทะฐะฟะธั‚ะฐั… ั– ะฒั–ะดะฟะพะฒั–ะดัั… ั†ะต ะฑัƒะดะต ะพะฑั€ะพะฑะปะตะฝะพ ัะบ `str`. + * ะ—ะณะตะฝะตั€ะพะฒะฐะฝะฐ ัั…ะตะผะฐ ะฑัƒะดะต ะฒะบะฐะทัƒะฒะฐั‚ะธ, ั‰ะพ ั†ะต `str` ะท "ั„ะพั€ะผะฐั‚ะพะผ" `binary`. +* `Decimal`: + * ะกั‚ะฐะฝะดะฐั€ั‚ะฝะธะน ะŸะฐะนั‚ะพะฝั–ะฒััŒะบะธะน `Decimal`. + * ะฃ ะทะฐะฟะธั‚ะฐั… ั– ะฒั–ะดะฟะพะฒั–ะดัั… ั†ะต ะฑัƒะดะต ะพะฑั€ะพะฑะปะตะฝะพ ั‚ะฐะบ ัะฐะผะพ, ัะบ ั– `float`. +* ะ’ะธ ะผะพะถะตั‚ะต ะฟะตั€ะตะฒั–ั€ะธั‚ะธ ะฒัั– ะดั–ะนัะฝั– ั‚ะธะฟะธ ะดะฐะฝะธั… Pydantic ั‚ัƒั‚: ั‚ะธะฟะธ ะดะฐะฝะธั… Pydantic. + +## ะŸั€ะธะบะปะฐะด + +ะžััŒ ะฟั€ะธะบะปะฐะด *path operation* ะท ะฟะฐั€ะฐะผะตั‚ั€ะฐะผะธ, ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ ะดะตัะบั– ะท ะฒะธั‰ะตะทะฐะทะฝะฐั‡ะตะฝะธั… ั‚ะธะฟั–ะฒ. + +=== "Python 3.10+" + + ```Python hl_lines="1 3 12-16" + {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="1 3 12-16" + {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="1 3 13-17" + {!> ../../../docs_src/extra_data_types/tutorial001_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip + ะ‘ะฐะถะฐะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `Annotated` ะฒะตั€ัั–ัŽ, ัะบั‰ะพ ั†ะต ะผะพะถะปะธะฒะพ. + + ```Python hl_lines="1 2 11-15" + {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} + ``` + +=== "Python 3.8+ non-Annotated" + + !!! tip + ะ‘ะฐะถะฐะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `Annotated` ะฒะตั€ัั–ัŽ, ัะบั‰ะพ ั†ะต ะผะพะถะปะธะฒะพ. + + ```Python hl_lines="1 2 12-16" + {!> ../../../docs_src/extra_data_types/tutorial001.py!} + ``` + +ะ—ะฒะตั€ะฝั–ั‚ัŒ ัƒะฒะฐะณัƒ, ั‰ะพ ะฟะฐั€ะฐะผะตั‚ั€ะธ ะฒัะตั€ะตะดะธะฝั– ั„ัƒะฝะบั†ั–ั— ะผะฐัŽั‚ัŒ ัะฒั–ะน ะทะฒะธั‡ะฐะนะฝะธะน ั‚ะธะฟ ะดะฐะฝะธั…, ั– ะฒะธ ะผะพะถะตั‚ะต, ะฝะฐะฟั€ะธะบะปะฐะด, ะฒะธะบะพะฝัƒะฒะฐั‚ะธ ะทะฒะธั‡ะฐะนะฝั– ะผะฐะฝั–ะฟัƒะปัั†ั–ั— ะท ะดะฐั‚ะฐะผะธ, ั‚ะฐะบั– ัะบ: + +=== "Python 3.10+" + + ```Python hl_lines="18-19" + {!> ../../../docs_src/extra_data_types/tutorial001_an_py310.py!} + ``` + +=== "Python 3.9+" + + ```Python hl_lines="18-19" + {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="19-20" + {!> ../../../docs_src/extra_data_types/tutorial001_an.py!} + ``` + +=== "Python 3.10+ non-Annotated" + + !!! tip + ะ‘ะฐะถะฐะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `Annotated` ะฒะตั€ัั–ัŽ, ัะบั‰ะพ ั†ะต ะผะพะถะปะธะฒะพ. + + ```Python hl_lines="17-18" + {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} + ``` + +=== "Python 3.8+ non-Annotated" + + !!! tip + ะ‘ะฐะถะฐะฝะพ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ `Annotated` ะฒะตั€ัั–ัŽ, ัะบั‰ะพ ั†ะต ะผะพะถะปะธะฒะพ. + + ```Python hl_lines="18-19" + {!> ../../../docs_src/extra_data_types/tutorial001.py!} + ``` diff --git a/docs/uk/docs/tutorial/index.md b/docs/uk/docs/tutorial/index.md new file mode 100644 index 000000000..e5bae74bc --- /dev/null +++ b/docs/uk/docs/tutorial/index.md @@ -0,0 +1,80 @@ +# ะขัƒั‚ะพั€ั–ะฐะป - ะŸะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ + +ะฃ ั†ัŒะพะผัƒ ะฟะพัั–ะฑะฝะธะบัƒ ะฟะพะบะฐะทะฐะฝะพ, ัะบ ะบะพั€ะธัั‚ัƒะฒะฐั‚ะธัั **FastAPI** ะท ะฑั–ะปัŒัˆั–ัั‚ัŽ ะนะพะณะพ ั„ัƒะฝะบั†ั–ะน, ะบั€ะพะบ ะทะฐ ะบั€ะพะบะพะผ. + +ะšะพะถะตะฝ ั€ะพะทะดั–ะป ะฟะพัั‚ัƒะฟะพะฒะพ ะฝะฐะดะฑัƒะดะพะฒัƒั”ั‚ัŒัั ะฝะฐ ะฟะพะฟะตั€ะตะดะฝั–, ะฐะปะต ะฒั–ะฝ ัั‚ั€ัƒะบั‚ัƒั€ะพะฒะฐะฝะธะน ะฝะฐ ะพะบั€ะตะผั– ั‚ะตะผะธ, ั‰ะพะฑ ะฒะธ ะผะพะณะปะธ ะฟะตั€ะตะนั‚ะธ ะฑะตะทะฟะพัะตั€ะตะดะฝัŒะพ ะดะพ ะฑัƒะดัŒ-ัะบะพั— ะบะพะฝะบั€ะตั‚ะฝะพั—, ั‰ะพะฑ ะฒะธั€ั–ัˆะธั‚ะธ ะฒะฐัˆั– ะบะพะฝะบั€ะตั‚ะฝั– ะฟะพั‚ั€ะตะฑะธ API. + +ะ’ั–ะฝ ั‚ะฐะบะพะถ ัั‚ะฒะพั€ะตะฝะธะน ัะบ ะดะพะฒั–ะดะฝะธะบ ะดะปั ั€ะพะฑะพั‚ะธ ัƒ ะผะฐะนะฑัƒั‚ะฝัŒะพะผัƒ. + +ะขะพะถ ะฒะธ ะผะพะถะตั‚ะต ะฟะพะฒะตั€ะฝัƒั‚ะธัั ั– ะฟะพะฑะฐั‡ะธั‚ะธ ัะฐะผะต ั‚ะต, ั‰ะพ ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ. + +## ะ—ะฐะฟัƒัั‚ั–ั‚ัŒ ะบะพะด + +ะฃัั– ะฑะปะพะบะธ ะบะพะดัƒ ะผะพะถะฝะฐ ัะบะพะฟั–ัŽะฒะฐั‚ะธ ั‚ะฐ ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ะฑะตะทะฟะพัะตั€ะตะดะฝัŒะพ (ั†ะต ั„ะฐะบั‚ะธั‡ะฝะพ ะฟะตั€ะตะฒั–ั€ะตะฝั– ั„ะฐะนะปะธ Python). + +ะฉะพะฑ ะทะฐะฟัƒัั‚ะธั‚ะธ ะฑัƒะดัŒ-ัะบะธะน ั–ะท ะฟั€ะธะบะปะฐะดั–ะฒ, ัะบะพะฟั–ัŽะนั‚ะต ะบะพะด ัƒ ั„ะฐะนะป `main.py` ั– ะทะฐะฟัƒัั‚ั–ั‚ัŒ `uvicorn` ะทะฐ ะดะพะฟะพะผะพะณะพัŽ: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +**ะ”ะฃะ–ะ• ั€ะฐะดะธะผะพ** ะฝะฐะฟะธัะฐั‚ะธ ะฐะฑะพ ัะบะพะฟั–ัŽะฒะฐั‚ะธ ะบะพะด, ะฒั–ะดั€ะตะดะฐะณัƒะฒะฐั‚ะธ ะนะพะณะพ ั‚ะฐ ะทะฐะฟัƒัั‚ะธั‚ะธ ะปะพะบะฐะปัŒะฝะพ. + +ะ’ะธะบะพั€ะธัั‚ะฐะฝะฝั ะนะพะณะพ ัƒ ัะฒะพั”ะผัƒ ั€ะตะดะฐะบั‚ะพั€ั– โ€“ ั†ะต ั‚ะต, ั‰ะพ ะดั–ะนัะฝะพ ะฟะพะบะฐะทัƒั” ะฒะฐะผ ะฟะตั€ะตะฒะฐะณะธ FastAPI, ะฑะฐั‡ะธั‚ะต, ัะบ ะผะฐะปะพ ะบะพะดัƒ ะฒะฐะผ ะฟะพั‚ั€ั–ะฑะฝะพ ะฝะฐะฟะธัะฐั‚ะธ, ะฒัั– ะฟะตั€ะตะฒั–ั€ะบะธ ั‚ะธะฟั–ะฒ, ะฐะฒั‚ะพะทะฐะฟะพะฒะฝะตะฝะฝั ั‚ะพั‰ะพ. + +--- + +## ะ’ัั‚ะฐะฝะพะฒะปะตะฝะฝั FastAPI + +ะŸะตั€ัˆะธะผ ะบั€ะพะบะพะผ ั” ะฒัั‚ะฐะฝะพะฒะปะตะฝะฝั FastAPI. + +ะ”ะปั ั‚ัƒั‚ะพั€ั–ะฐะปัƒ ะฒะธ ะผะพะถะตั‚ะต ะฒัั‚ะฐะฝะพะฒะธั‚ะธ ะนะพะณะพ ะท ัƒัั–ะผะฐ ะฝะตะพะฑะพะฒโ€™ัะทะบะพะฒะธะผะธ ะทะฐะปะตะถะฝะพัั‚ัะผะธ ั‚ะฐ ั„ัƒะฝะบั†ั–ัะผะธ: + +
+ +```console +$ pip install "fastapi[all]" + +---> 100% +``` + +
+ +...ัะบะธะน ั‚ะฐะบะพะถ ะฒะบะปัŽั‡ะฐั” `uvicorn`, ัะบะธะน ะฒะธ ะผะพะถะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ัะบ ัะตั€ะฒะตั€, ัะบะธะน ะทะฐะฟัƒัะบะฐั” ะฒะฐัˆ ะบะพะด. + +!!! note + ะ’ะธ ั‚ะฐะบะพะถ ะผะพะถะตั‚ะต ะฒัั‚ะฐะฝะพะฒะธั‚ะธ ะนะพะณะพ ั‡ะฐัั‚ะธะฝะฐ ะทะฐ ั‡ะฐัั‚ะธะฝะพัŽ. + + ะฆะต ั‚ะต, ั‰ะพ ะฒะธ, ะนะผะพะฒั–ั€ะฝะพ, ะทั€ะพะฑะธะปะธ ะฑ, ะบะพะปะธ ะทะฐั…ะพั‡ะตั‚ะต ั€ะพะทะณะพั€ะฝัƒั‚ะธ ัะฒะพัŽ ะฟั€ะพะณั€ะฐะผัƒ ัƒ ะฒะธั€ะพะฑะฝะธั‡ะพะผัƒ ัะตั€ะตะดะพะฒะธั‰ั–: + + ``` + pip install fastapi + ``` + + ะขะฐะบะพะถ ะฒัั‚ะฐะฝะพะฒั–ั‚ัŒ `uvicorn`, ั‰ะพะฑ ะฒั–ะฝ ะฟั€ะฐั†ัŽะฒะฐะฒ ัะบ ัะตั€ะฒะตั€: + + ``` + pip install "uvicorn[standard]" + ``` + + ะ† ั‚ะต ัะฐะผะต ะดะปั ะบะพะถะฝะพั— ะท ะพะฟั†ั–ะพะฝะฐะปัŒะฝะธั… ะทะฐะปะตะถะฝะพัั‚ะตะน, ัะบั– ะฒะธ ั…ะพั‡ะตั‚ะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ. + +## ะ ะพะทัˆะธั€ะตะฝะธะน ะฟะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ + +ะ†ัะฝัƒั” ั‚ะฐะบะพะถ **ะ ะพะทัˆะธั€ะตะฝะธะน ะฟะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ**, ัะบะธะน ะฒะธ ะทะผะพะถะตั‚ะต ะฟั€ะพั‡ะธั‚ะฐั‚ะธ ะฟั–ะทะฝั–ัˆะต ะฟั–ัะปั ั†ัŒะพะณะพ **ะขัƒั‚ะพั€ั–ะฐะป - ะŸะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ**. + +**ะ ะพะทัˆะธั€ะตะฝะธะน ะฟะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ** ะทะฐัะฝะพะฒะฐะฝะพ ะฝะฐ ั†ัŒะพะผัƒ, ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ั‚ั– ัะฐะผั– ะบะพะฝั†ะตะฟั†ั–ั— ั‚ะฐ ะฝะฐะฒั‡ะฐั” ะฒะฐั ะดะตัะบะธะผ ะดะพะดะฐั‚ะบะพะฒะธะผ ั„ัƒะฝะบั†ั–ัะผ. + +ะะปะต ะฒะฐะผ ัะปั–ะด ัะฟะพั‡ะฐั‚ะบัƒ ะฟั€ะพั‡ะธั‚ะฐั‚ะธ **ะขัƒั‚ะพั€ั–ะฐะป - ะŸะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ** (ั‚ะต, ั‰ะพ ะฒะธ ะทะฐั€ะฐะท ั‡ะธั‚ะฐั”ั‚ะต). + +ะ’ั–ะฝ ั€ะพะทั€ะพะฑะปะตะฝะธะน ั‚ะฐะบะธะผ ั‡ะธะฝะพะผ, ั‰ะพ ะฒะธ ะผะพะถะตั‚ะต ัั‚ะฒะพั€ะธั‚ะธ ะฟะพะฒะฝัƒ ะฟั€ะพะณั€ะฐะผัƒ ะปะธัˆะต ะทะฐ ะดะพะฟะพะผะพะณะพัŽ **ะขัƒั‚ะพั€ั–ะฐะป - ะŸะพัั–ะฑะฝะธะบ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ**, ะฐ ะฟะพั‚ั–ะผ ั€ะพะทัˆะธั€ะธั‚ะธ ั—ั— ั€ั–ะทะฝะธะผะธ ัะฟะพัะพะฑะฐะผะธ, ะทะฐะปะตะถะฝะพ ะฒั–ะด ะฒะฐัˆะธั… ะฟะพั‚ั€ะตะฑ, ะฒะธะบะพั€ะธัั‚ะพะฒัƒัŽั‡ะธ ะดะตัะบั– ะท ะดะพะดะฐั‚ะบะพะฒะธั… ั–ะดะตะน ะท **ะ ะพะทัˆะธั€ะตะฝะพะณะพ ะฟะพัั–ะฑะฝะธะบะฐ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ** . diff --git a/docs/vi/docs/features.md b/docs/vi/docs/features.md index 0599530e8..306aeb359 100644 --- a/docs/vi/docs/features.md +++ b/docs/vi/docs/features.md @@ -26,7 +26,7 @@ Tร i liแป‡u tฦฐฦกng tรกc API vร  web giao diแป‡n ngฦฐแปi dรนng. Lร  mแป™t frame ### Chแป‰ cแบงn phiรชn bแบฃn Python hiแป‡n ฤ‘แบกi -Tแบฅt cแบฃ ฤ‘ฦฐแปฃc dแปฑa trรชn khai bรกo kiแปƒu dแปฏ liแป‡u chuแบฉn cแปงa **Python 3.6** (cแบฃm ฦกn Pydantic). Bแบกn khรดng cแบงn hแปc cรบ phรกp mแป›i, chแป‰ cแบงn biแบฟt chuแบฉn Python hiแป‡n ฤ‘แบกi. +Tแบฅt cแบฃ ฤ‘ฦฐแปฃc dแปฑa trรชn khai bรกo kiแปƒu dแปฏ liแป‡u chuแบฉn cแปงa **Python 3.8** (cแบฃm ฦกn Pydantic). Bแบกn khรดng cแบงn hแปc cรบ phรกp mแป›i, chแป‰ cแบงn biแบฟt chuแบฉn Python hiแป‡n ฤ‘แบกi. Nแบฟu bแบกn cแบงn 2 phรบt ฤ‘แปƒ lร m mแป›i lแบกi cรกch sแปญ dแปฅng cรกc kiแปƒu dแปฏ liแป‡u mแป›i cแปงa Python (thแบญm chรญ nแบฟu bแบกn khรดng sแปญ dแปฅng FastAPI), xem hฦฐแป›ng dแบซn ngแบฏn: [Kiแปƒu dแปฏ liแป‡u Python](python-types.md){.internal-link target=_blank}. diff --git a/docs/vi/docs/index.md b/docs/vi/docs/index.md index 0e773a011..3f416dbec 100644 --- a/docs/vi/docs/index.md +++ b/docs/vi/docs/index.md @@ -27,7 +27,7 @@ --- -FastAPI lร  mแป™t web framework hiแป‡n ฤ‘แบกi, hiแป‡u nฤƒng cao ฤ‘แปƒ xรขy dแปฑng web APIs vแป›i Python 3.7+ dแปฑa trรชn tiรชu chuแบฉn Python type hints. +FastAPI lร  mแป™t web framework hiแป‡n ฤ‘แบกi, hiแป‡u nฤƒng cao ฤ‘แปƒ xรขy dแปฑng web APIs vแป›i Python 3.8+ dแปฑa trรชn tiรชu chuแบฉn Python type hints. Nhแปฏng tรญnh nฤƒng nhฦฐ: @@ -116,7 +116,7 @@ Nแบฟu bแบกn ฤ‘ang xรขy dแปฑng mแป™t CLI ../../../docs_src/python_types/tutorial006_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" Tแปซ `typing`, import `List` (vแป›i chแปฏ cรกi `L` viแบฟt hoa): @@ -230,7 +230,7 @@ Bแบกn sแบฝ lร m ฤ‘iแปu tฦฐฦกng tแปฑ ฤ‘แปƒ khai bรกo cรกc `tuple` vร  cรกc `set {!> ../../../docs_src/python_types/tutorial007_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial007.py!} @@ -255,7 +255,7 @@ Tham sแป‘ kiแปƒu dแปฏ liแป‡u thแปฉ hai dร nh cho giรก trแป‹ cแปงa `dict`. {!> ../../../docs_src/python_types/tutorial008_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial008.py!} @@ -284,7 +284,7 @@ Trong Python 3.10 cลฉng cรณ mแป™t **cรบ phรกp mแป›i** mร  bแบกn cรณ thแปƒ ฤ‘แบทt {!> ../../../docs_src/python_types/tutorial008b_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial008b.py!} @@ -314,13 +314,13 @@ Sแปญ dแปฅng `Optional[str]` thay cho `str` sแบฝ cho phรฉp trรฌnh soแบกn thแบฃo g {!> ../../../docs_src/python_types/tutorial009_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial009.py!} ``` -=== "Python 3.6+ alternative" +=== "Python 3.8+ alternative" ```Python hl_lines="1 4" {!> ../../../docs_src/python_types/tutorial009b.py!} @@ -404,7 +404,7 @@ Nhแปฏng kiแปƒu dแปฏ liแป‡u nร y lแบฅy tham sแป‘ kiแปƒu dแปฏ liแป‡u trong dแบฅu n * `Optional` * ...and others. -=== "Python 3.6+" +=== "Python 3.8+" * `List` * `Tuple` @@ -464,7 +464,7 @@ Mแป™t vรญ dแปฅ tแปซ tร i liแป‡u chรญnh thแปฉc cแปงa Pydantic: {!> ../../../docs_src/python_types/tutorial011_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/python_types/tutorial011.py!} @@ -493,7 +493,7 @@ Python cลฉng cรณ mแป™t tรญnh nฤƒng cho phรฉp ฤ‘แบทt **metadata bแป• sung** trong {!> ../../../docs_src/python_types/tutorial013_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" แปž phiรชn bแบฃn dฦฐแป›i Python 3.9, bแบกn import `Annotated` tแปซ `typing_extensions`. diff --git a/docs/vi/docs/tutorial/first-steps.md b/docs/vi/docs/tutorial/first-steps.md new file mode 100644 index 000000000..712f00852 --- /dev/null +++ b/docs/vi/docs/tutorial/first-steps.md @@ -0,0 +1,333 @@ +# Nhแปฏng bฦฐแป›c ฤ‘แบงu tiรชn + +Tแป‡p tin FastAPI ฤ‘ฦกn giแบฃn nhแบฅt cรณ thแปƒ trรดng nhฦฐ nร y: + +```Python +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Sao chรฉp sang mแป™t tแป‡p tin `main.py`. + +Chแบกy live server: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +!!! note + Cรขu lแป‡nh `uvicorn main:app` ฤ‘ฦฐแปฃc giแบฃi thรญch nhฦฐ sau: + + * `main`: tแป‡p tin `main.py` (mแป™t Python "mรด ฤ‘un"). + * `app`: mแป™t object ฤ‘ฦฐแปฃc tแบกo ra bรชn trong `main.py` vแป›i dรฒng `app = FastAPI()`. + * `--reload`: lร m server khแปŸi ฤ‘แป™ng lแบกi sau mแป—i lแบงn thay ฤ‘แป•i. Chแป‰ sแปญ dแปฅng trong mรดi trฦฐแปng phรกt triแปƒn. + +Trong output, cรณ mแป™t dรฒng giแป‘ng nhฦฐ: + +```hl_lines="4" +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +Dรฒng ฤ‘รณ cho thแบฅy URL, nฦกi mร  app cแปงa bแบกn ฤ‘ang ฤ‘ฦฐแปฃc chแบกy, trong mรกy local cแปงa bแบกn. + +### Kiแปƒm tra + +MแปŸ trรฌnh duyแป‡t cแปงa bแบกn tแบกi http://127.0.0.1:8000. + +Bแบกn sแบฝ thแบฅy mแป™t JSON response nhฦฐ: + +```JSON +{"message": "Hello World"} +``` + +### Tร i liแป‡u tฦฐฦกng tรกc API + +Bรขy giแป tแป›i http://127.0.0.1:8000/docs. + +Bแบกn sแบฝ thแบฅy mแป™t tร i liแป‡u tฦฐฦกng tรกc API (cung cแบฅp bแปŸi Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### Phiรชn bแบฃn thay thแบฟ cแปงa tร i liแป‡u API + +Vร  bรขy giแป tแป›i http://127.0.0.1:8000/redoc. + +Bแบกn sแบฝ thแบฅy mแป™t bแบฃn thay thแบฟ cแปงa tร i liแป‡u (cung cแบฅp bแปŸi ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +### OpenAPI + +**FastAPI** sinh mแป™t "schema" vแป›i tแบฅt cแบฃ API cแปงa bแบกn sแปญ dแปฅng tiรชu chuแบฉn **OpenAPI** cho ฤ‘แป‹nh nghฤฉa cรกc API. + +#### "Schema" + +Mแป™t "schema" lร  mแป™t ฤ‘แป‹nh nghฤฉa hoแบทc mรด tแบฃ thแปฉ gรฌ ฤ‘รณ. Khรดng phแบฃi code triแปƒn khai cแปงa nรณ, nhฦฐng chแป‰ lร  mแป™t bแบฃn mรด tแบฃ trแปซu tฦฐแปฃng. + +#### API "schema" + +Trong trฦฐแปng hแปฃp nร y, OpenAPI lร  mแป™t bแบฃn mรด tแบฃ bแบฏt buแป™c cฦก chแบฟ ฤ‘แป‹nh nghฤฉa API cแปงa bแบกn. + +ฤแป‹nh nghฤฉa cแบฅu trรบc nร y bao gแป“m nhแปฏng ฤ‘ฦฐแปng dแบซn API cแปงa bแบกn, cรกc tham sแป‘ cรณ thแปƒ cรณ,... + +#### "Cแบฅu trรบc" dแปฏ liแป‡u + +Thuแบญt ngแปฏ "cแบฅu trรบc" (schema) cลฉng cรณ thแปƒ ฤ‘ฦฐแปฃc coi nhฦฐ lร  hรฌnh dแบกng cแปงa dแปฏ liแป‡u, tฦฐฦกng tแปฑ nhฦฐ mแป™t JSON content. + +Trong trฦฐแปng hแปฃp ฤ‘รณ, nรณ cรณ nghฤฉa lร  cรกc thuแป™c tรญnh JSON vร  cรกc kiแปƒu dแปฏ liแป‡u hแป cรณ,... + +#### OpenAPI vร  JSON Schema + +OpenAPI ฤ‘แป‹nh nghฤฉa mแป™t cแบฅu trรบc API cho API cแปงa bแบกn. Vร  cแบฅu trรบc ฤ‘รณ bao gแป“m cรกc dแป‹nh nghฤฉa (or "schema") vแป dแปฏ liแป‡u ฤ‘ฦฐแปฃc gแปญi ฤ‘i vร  nhแบญn vแป bแปŸi API cแปงa bแบกn, sแปญ dแปฅng **JSON Schema**, mแป™t tiรชu chuแบฉn cho cแบฅu trรบc dแปฏ liแป‡u JSON. + +#### Kiแปƒm tra `openapi.json` + +Nแบฟu bแบกn tรฒ mรฒ vแป viแป‡c cแบฅu trรบc OpenAPI nhรฌn nhฦฐ thแบฟ nร o thรฌ FastAPI tแปฑ ฤ‘แป™ng sinh mแป™t JSON (schema) vแป›i cรกc mรด tแบฃ cho tแบฅt cแบฃ API cแปงa bแบกn. + +Bแบกn cรณ thแปƒ thแบฅy nรณ trแปฑc tiแบฟp tแบกi: http://127.0.0.1:8000/openapi.json. + +Nรณ sแบฝ cho thแบฅy mแป™t JSON bแบฏt ฤ‘แบงu giแป‘ng nhฦฐ: + +```JSON +{ + "openapi": "3.1.0", + "info": { + "title": "FastAPI", + "version": "0.1.0" + }, + "paths": { + "/items/": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + + + +... +``` + +#### OpenAPI dรนng ฤ‘แปƒ lร m gรฌ? + +Cแบฅu trรบc OpenAPI lร  sแปฉc mแบกnh cแปงa tร i liแป‡u tฦฐฦกng tรกc. + +Vร  cรณ hร ng tรก cรกc bแบฃn thay thแบฟ, tแบฅt cแบฃ ฤ‘แปu dแปฑa trรชn OpenAPI. Bแบกn cรณ thแปƒ dแป… dร ng thรชm bแบฅt kรฌ bแบฃn thay thแบฟ bร o cho แปฉng dแปฅng cแปงa bแบกn ฤ‘ฦฐแปฃc xรขy dแปฑng vแป›i **FastAPI**. + +Bแบกn cลฉng cรณ thแปƒ sแปญ dแปฅng nรณ ฤ‘แปƒ sinh code tแปฑ ฤ‘แป™ng, vแป›i cรกc client giao viแบฟt qua API cแปงa bแบกn. Vรญ dแปฅ, frontend, mobile hoแบทc cรกc แปฉng dแปฅng IoT. + +## Tรณm lแบกi, tแปซng bฦฐแป›c mแป™t + +### Bฦฐแป›c 1: import `FastAPI` + +```Python hl_lines="1" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`FastAPI` lร  mแป™t Python class cung cแบฅp tแบฅt cแบฃ chแปฉc nฤƒng cho API cแปงa bแบกn. + +!!! note "Chi tiแบฟt kฤฉ thuแบญt" + `FastAPI` lร  mแป™t class kแบฟ thแปซa trแปฑc tiแบฟp `Starlette`. + + Bแบกn cลฉng cรณ thแปƒ sแปญ dแปฅng tแบฅt cแบฃ Starlette chแปฉc nฤƒng vแป›i `FastAPI`. + +### Bฦฐแป›c 2: Tแบกo mแป™t `FastAPI` "instance" + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Biแบฟn `app` nร y lร  mแป™t "instance" cแปงa class `FastAPI`. + +ฤรขy sแบฝ lร  ฤ‘iแปƒm cแป‘t lรตi ฤ‘แปƒ tแบกo ra tแบฅt cแบฃ API cแปงa bแบกn. + +`app` nร y chรญnh lร  ฤ‘iแปu ฤ‘ฦฐแปฃc nhแบฏc tแป›i bแปŸi `uvicorn` trong cรขu lแป‡nh: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Nแบฟu bแบกn tแบกo แปฉng dแปฅng cแปงa bแบกn giแป‘ng nhฦฐ: + +```Python hl_lines="3" +{!../../../docs_src/first_steps/tutorial002.py!} +``` + +Vร  ฤ‘แบทt nรณ trong mแป™t tแป‡p tin `main.py`, sau ฤ‘รณ bแบกn sแบฝ gแปi `uvicorn` giแป‘ng nhฦฐ: + +
+ +```console +$ uvicorn main:my_awesome_api --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +### Bฦฐแป›c 3: tแบกo mแป™t *ฤ‘ฦฐแปng dแบซn toรกn tแปญ* + +#### ฤฦฐแปng dแบซn + +"ฤฦฐแปng dแบซn" แปŸ ฤ‘รขy ฤ‘ฦฐแปฃc nhแบฏc tแป›i lร  phแบงn cuแป‘i cรนng cแปงa URL bแบฏt ฤ‘แบงu tแปซ `/`. + +Do ฤ‘รณ, trong mแป™t URL nhรฌn giแป‘ng nhฦฐ: + +``` +https://example.com/items/foo +``` + +...ฤ‘ฦฐแปng dแบซn sแบฝ lร : + +``` +/items/foo +``` + +!!! info + Mแป™t ฤ‘ฦฐแปng dแบซn cลฉng lร  mแป™t cรกch gแปi chung cho mแป™t "endpoint" hoแบทc mแป™t "route". + +Trong khi xรขy dแปฑng mแป™t API, "ฤ‘ฦฐแปng dแบซn" lร  cรกc chรญnh ฤ‘แปƒ phรขn tรกch "mแป‘i quan hแป‡" vร  "tร i nguyรชn". + +#### Toรกn tแปญ (Operation) + +"Toรกn tแปญ" แปŸ ฤ‘รขy ฤ‘ฦฐแปฃc nhแบฏc tแป›i lร  mแป™t trong cรกc "phฦฐฦกng thแปฉc" HTTP. + +Mแป™t trong nhแปฏng: + +* `POST` +* `GET` +* `PUT` +* `DELETE` + +...vร  mแป™t trong nhแปฏng cรกi cรฒn lแบกi: + +* `OPTIONS` +* `HEAD` +* `PATCH` +* `TRACE` + +Trong giao thแปฉc HTTP, bแบกn cรณ thแปƒ giao tiแบฟp trong mแป—i ฤ‘ฦฐแปng dแบซn sแปญ dแปฅng mแป™t (hoแบทc nhiแปu) trong cรกc "phฦฐฦกng thแปฉc nร y". + +--- + +Khi xรขy dแปฑng cรกc API, bแบกn thฦฐแปng sแปญ dแปฅng cแปฅ thแปƒ cรกc phฦฐฦกng thแปฉc HTTP nร y ฤ‘แปƒ thแปฑc hiแป‡n mแป™t hร nh ฤ‘แป™ng cแปฅ thแปƒ. + +Thรดng thฦฐแปng, bแบกn sแปญ dแปฅng + +* `POST`: ฤ‘แปƒ tแบกo dแปฏ liแป‡u. +* `GET`: ฤ‘แปƒ ฤ‘แปc dแปฏ liแป‡u. +* `PUT`: ฤ‘แปƒ cแบญp nhแบญt dแปฏ liแป‡u. +* `DELETE`: ฤ‘แปƒ xรณa dแปฏ liแป‡u. + +Do ฤ‘รณ, trong OpenAPI, mแป—i phฦฐฦกng thแปฉc HTTP ฤ‘ฦฐแปฃc gแปi lร  mแป™t "toรกn tแปญ (operation)". + +Chรบng ta cลฉng sแบฝ gแปi chรบng lร  "**cรกc toรกn tแปญ**". + +#### ฤแป‹nh nghฤฉa moojt *decorator cho ฤ‘ฦฐแปng dแบซn toรกn tแปญ* + +```Python hl_lines="6" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +`@app.get("/")` nรณi **FastAPI** rแบฑng hร m bรชn dฦฐแป›i cรณ trรกch nhiแป‡m xแปญ lรญ request tแป›i: + +* ฤ‘ฦฐแปng dแบซn `/` +* sแปญ dแปฅng mแป™t toรกn tแปญget + +!!! info Thรดng tin vแป "`@decorator`" + Cรบ phรกp `@something` trong Python ฤ‘ฦฐแปฃc gแปi lร  mแป™t "decorator". + + Bแบกn ฤ‘แบทt nรณ trรชn mแป™t hร m. Giแป‘ng nhฦฐ mแป™t chiแบฟc mลฉ xinh xแบฏn (Tรดi ddonas ฤ‘รณ lร  lรญ do mร  thuแบญt ngแปฏ nร y ra ฤ‘แปi). + + Mแป™t "decorator" lแบฅy mแป™t hร m bรชn dฦฐแป›i vร  thแปฑc hiแป‡n mแป™t vร i thแปฉ vแป›i nรณ. + + Trong trฦฐแปng hแปฃp cแปงa chรบng ta, decorator nร y nรณi **FastAPI** rแบฑng hร m bรชn dฦฐแป›i แปฉng vแป›i **ฤ‘ฦฐแปng dแบซn** `/` vร  mแป™t **toรกn tแปญ** `get`. + + Nรณ lร  mแป™t "**decorator ฤ‘ฦฐแปng dแบซn toรกn tแปญ**". + +Bแบกn cลฉng cรณ thแปƒ sแปญ dแปฅng vแป›i cรกc toรกn tแปญ khรกc: + +* `@app.post()` +* `@app.put()` +* `@app.delete()` + +Vร  nhiแปu hฦกn vแป›i cรกc toรกn tแปญ cรฒn lแบกi: + +* `@app.options()` +* `@app.head()` +* `@app.patch()` +* `@app.trace()` + +!!! tip + Bแบกn thoแบฃi mรกi sแปญ dแปฅng mแป—i toรกn tแปญ (phฦฐฦกng thแปฉc HTTP) nhฦฐ bแบกn mฦก ฦฐแป›c. + + **FastAPI** khรดng bแบฏt buแป™c bแบฅt kรฌ รฝ nghฤฉa cแปฅ thแปƒ nร o. + + Thรดng tin แปŸ ฤ‘รขy ฤ‘ฦฐแปฃc biแปƒu thแป‹ nhฦฐ lร  mแป™t chแป‰ dแบซn, khรดng phแบฃi lร  mแป™t yรชu cแบงu bแบฏt buแป™c. + + Vรญ dแปฅ, khi sแปญ dแปฅng GraphQL bแบกn thรดng thฦฐแปng thแปฑc hiแป‡n tแบฅt cแบฃ cรกc hร nh ฤ‘แป™ng chแป‰ bแบฑng viแป‡c sแปญ dแปฅng cรกc toรกn tแปญ `POST`. + +### Step 4: ฤแป‹nh nghฤฉa **hร m cho ฤ‘ฦฐแปng dแบซn toรกn tแปญ** + +ฤรขy lร  "**hร m cho ฤ‘ฦฐแปng dแบซn toรกn tแปญ**": + +* **ฤ‘ฦฐแปng dแบซn**: lร  `/`. +* **toรกn tแปญ**: lร  `get`. +* **hร m**: lร  hร m bรชn dฦฐแป›i "decorator" (bรชn dฦฐแป›i `@app.get("/")`). + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +ฤรขy lร  mแป™t hร m Python. + +Nรณ sแบฝ ฤ‘ฦฐแปฃc gแปi bแปŸi **FastAPI** bแบฅt cแปฉ khi nร o nรณ nhแบญn mแป™t request tแป›i URL "`/`" sแปญ dแปฅng mแป™t toรกn tแปญ `GET`. + +Trong trฦฐแปng hแปฃp nร y, nรณ lร  mแป™t hร m `async`. + +--- + +Bแบกn cลฉng cรณ thแปƒ ฤ‘แป‹nh nghฤฉa nรณ nhฦฐ lร  mแป™t hร m thรดng thฦฐแปng thay cho `async def`: + +```Python hl_lines="7" +{!../../../docs_src/first_steps/tutorial003.py!} +``` + +!!! note + Nแบฟu bแบกn khรดng biแบฟt sแปฑ khรกc nhau, kiแปƒm tra [Async: *"Trong khi vแป™i vร ng?"*](../async.md#in-a-hurry){.internal-link target=_blank}. + +### Bฦฐแป›c 5: Nแป™i dung trแบฃ vแป + +```Python hl_lines="8" +{!../../../docs_src/first_steps/tutorial001.py!} +``` + +Bแบกn cรณ thแปƒ trแบฃ vแป mแป™t `dict`, `list`, mแป™t trong nhแปฏng giรก trแป‹ ฤ‘ฦกn nhฦฐ `str`, `int`,... + +Bแบกn cลฉng cรณ thแปƒ trแบฃ vแป Pydantic model (bแบกn sแบฝ thแบฅy nhiแปu hฦกn vแป nรณ sau). + +Cรณ nhiแปu object vร  model khรกc nhau sแบฝ ฤ‘ฦฐแปฃc tแปฑ ฤ‘แป™ng chuyแปƒn ฤ‘แป•i sang JSON (bao gแป“m cแบฃ ORM,...). Thแปญ sแปญ dแปฅng loแบกi ฦฐa thรญch cแปงa bแบกn, nรณ cรณ khแบฃ nฤƒng cao ฤ‘รฃ ฤ‘ฦฐแปฃc hแป— trแปฃ. + +## Tรณm lแบกi + +* Import `FastAPI`. +* Tแบกo mแป™t `app` instance. +* Viแบฟt mแป™t **decorator cho ฤ‘ฦฐแปng dแบซn toรกn tแปญ** (giแป‘ng nhฦฐ `@app.get("/")`). +* Viแบฟt mแป™t **hร m cho ฤ‘ฦฐแปng dแบซn toรกn tแปญ** (giแป‘ng nhฦฐ `def root(): ...` แปŸ trรชn). +* Chแบกy server trong mรดi trฦฐแปng phรกt triแปƒn (giแป‘ng nhฦฐ `uvicorn main:app --reload`). diff --git a/docs/vi/docs/tutorial/index.md b/docs/vi/docs/tutorial/index.md new file mode 100644 index 000000000..e8a93fe40 --- /dev/null +++ b/docs/vi/docs/tutorial/index.md @@ -0,0 +1,80 @@ +# Hฦฐแป›ng dแบซn sแปญ dแปฅng + +Hฦฐแป›ng dแบซn nร y cho bแบกn thแบฅy tแปซng bฦฐแป›c cรกch sแปญ dแปฅng **FastAPI** ฤ‘a sแป‘ cรกc tรญnh nฤƒng cแปงa nรณ. + +Mแป—i phแบงn ฤ‘ฦฐแปฃc xรขy dแปฑng tแปซ nhแปฏng phแบงn trฦฐแป›c ฤ‘รณ, nhฦฐng nรณ ฤ‘ฦฐแปฃc cแบฅu trรบc thร nh cรกc chแปง ฤ‘แป riรชng biแป‡t, do ฤ‘รณ bแบกn cรณ thแปƒ xem trแปฑc tiแบฟp tแปซng phแบงn cแปฅ thแปƒ bแบฅt kรฌ ฤ‘แปƒ giแบฃi quyแบฟt nhแปฏng API cแปฅ thแปƒ mร  bแบกn cแบงn. + +Nรณ cลฉng ฤ‘ฦฐแปฃc xรขy dแปฑng ฤ‘แปƒ lร m viแป‡c nhฦฐ mแป™t tham chiแบฟu trong tฦฐฦกng lai. + +Do ฤ‘รณ bแบกn cรณ thแปƒ quay lแบกi vร  tรฌm chรญnh xรกc nhแปฏng gรฌ bแบกn cแบงn. + +## Chแบกy mรฃ + +Tแบฅt cแบฃ cรกc code block cรณ thแปƒ ฤ‘ฦฐแปฃc sao chรฉp vร  sแปญ dแปฅng trแปฑc tiแบฟp (chรบng thแปฑc chแบฅt lร  cรกc tแป‡p tin Python ฤ‘รฃ ฤ‘ฦฐแปฃc kiแปƒm thแปญ). + +ฤแปƒ chแบกy bแบฅt kรฌ vรญ dแปฅ nร o, sao chรฉp code tแป›i tแป‡p tin `main.py`, vร  bแบฏt ฤ‘แบงu `uvicorn` vแป›i: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +**Khuyแบฟn khรญch** bแบกn viแบฟt hoแบทc sao chรฉp code, sแปญa vร  chแบกy nรณ แปŸ local. + +Sแปญ dแปฅng nรณ trong trรฌnh soแบกn thแบฃo cแปงa bแบกn thแปฑc sแปฑ cho bแบกn thแบฅy nhแปฏng lแปฃi รญch cแปงa FastAPI, thแบฅy ฤ‘ฦฐแปฃc cรกch bแบกn viแบฟt code รญt hฦกn, tแบฅt cแบฃ ฤ‘แปu ฤ‘ฦฐแปฃc type check, autocompletion,... + +--- + +## Cร i ฤ‘แบทt FastAPI + +Bฦฐแป›c ฤ‘แบงu tiรชn lร  cร i ฤ‘แบทt FastAPI. + +Vแป›i hฦฐแป›ng dแบซn nร y, bแบกn cรณ thแปƒ muแป‘n cร i ฤ‘แบทt nรณ vแป›i tแบฅt cแบฃ cรกc phแปฅ thuแป™c vร  tรญnh nฤƒng tรนy chแปn: + +
+ +```console +$ pip install "fastapi[all]" + +---> 100% +``` + +
+ +...dรณ cลฉng bao gแป“m `uvicorn`, bแบกn cรณ thแปƒ sแปญ dแปฅng nhฦฐ mแป™t server ฤ‘แปƒ chแบกy code cแปงa bแบกn. + +!!! note + Bแบกn cลฉng cรณ thแปƒ cร i ฤ‘แบทt nรณ tแปซng phแบงn. + + ฤรขy lร  nhแปฏng gรฌ bแบกn cรณ thแปƒ sแบฝ lร m mแป™t lแบงn duy nhแบฅt bแบกn muแป‘n triแปƒn khai แปฉng dแปฅng cแปงa bแบกn lรชn production: + + ``` + pip install fastapi + ``` + + Cลฉng cร i ฤ‘แบทt `uvicorn` ฤ‘แปƒ lร m viแป‡c nhฦฐ mแป™t server: + + ``` + pip install "uvicorn[standard]" + ``` + + Vร  tฦฐฦกng tแปฑ vแป›i tแปซng phแปฅ thuแป™c tรนy chแปn mร  bแบกn muแป‘n sแปญ dแปฅng. + +## Hฦฐแป›ng dแบซn nรขng cao + +Cลฉng cรณ mแป™t **Hฦฐแป›ng dแบซn nรขng cao** mร  bแบกn cรณ thแปƒ ฤ‘แปc nรณ sau **Hฦฐแป›ng dแบซn sแปญ dแปฅng**. + +**Hฦฐแป›ng dแบซn sแปญ dแปฅng nรขng cao**, xรขy dแปฑng dแปฑa trรชn cรกi nร y, sแปญ dแปฅng cรกc khรกi niแป‡m tฦฐฦกng tแปฑ, vร  dแบกy bแบกn nhแปฏng tรญnh nฤƒng mแปŸ rแป™ng. + +Nhฦฐng bแบกn nรชn ฤ‘แปc **Hฦฐแป›ng dแบซn sแปญ dแปฅng** ฤ‘แบงu tiรชn (nhแปฏng gรฌ bแบกn ฤ‘ang ฤ‘แปc). + +Nรณ ฤ‘ฦฐแปฃc thiแบฟt kแบฟ do ฤ‘รณ bแบกn cรณ thแปƒ xรขy dแปฑng mแป™t แปฉng dแปฅng hoร n chแป‰nh chแป‰ vแป›i **Hฦฐแป›ng dแบซn sแปญ dแปฅng**, vร  sau ฤ‘รณ mแปŸ rแป™ng nรณ theo cรกc cรกch khรกc nhau, phแปฅ thuแป™c vร o nhแปฏng gรฌ bแบกn cแบงn, sแปญ dแปฅng mแป™t vร i รฝ tฦฐแปŸng bแป• sung tแปซ **Hฦฐแป›ng dแบซn sแปญ dแปฅng nรขng cao**. diff --git a/docs/yo/docs/index.md b/docs/yo/docs/index.md new file mode 100644 index 000000000..101e13b6b --- /dev/null +++ b/docs/yo/docs/index.md @@ -0,0 +1,470 @@ +

+ FastAPI +

+

+ รŒlร nร  wแบนฬแบนฬbรน FastAPI, iแนฃแบนฬ gรญga, รณ rแปrรนn lรกti kแปฬ€, o yรกra lรกti kรณรฒdรน, รณ sรฌ แนฃetรกn fรบn iแนฃelแปpแป nรญ lรญlo +

+

+ + Test + + + Coverage + + + Package version + + + Supported Python versions + +

+ +--- + +**ร€kแปsรญlแบนฬ€**: https://fastapi.tiangolo.com + +**Orisun Kรณรฒdรน**: https://github.com/tiangolo/fastapi + +--- + +FastAPI jแบนฬ รฌgbร lรณdรฉ, tรญ รณ yรกra (iแนฃแบน-giga), รฌlร nร  wแบนฬแบนฬbรน fรบn kikแป ร wแปn API pแบนฬ€lรบ Python 3.8+ รจyรญ tรญ รณ da lori ร wแปn รฌtแปฬkasรญ ร mรฌ irรบfแบนฬ Python. + +ร€wแปn แบนya pร tร kรฌ ni: + +* **ร“ yรกra**: Iแนฃแบน tรญ รณ ga pรบpแปฬ€, tรญ รณ wa ni ibamu pแบนฬ€lรบ **NodeJS** ร ti **Go** (แปpแบน si Starlette ร ti Pydantic). [แปŒkan nรญnรบ ร wแปn รฌlร nร  Python ti o yรกra jรนlแป ti o wa](#performance). +* **ร“ yรกra lรกti kรณรฒdรน**: O mu iyara pแป si lรกti kแป ร wแปn แบนya tuntun kรณรฒdรน nipasแบน "Igba รฌdรก แปgแปฬrรนn-รบn" (i.e. 200%) si "แปฬ€แปฬdรบrรบn รฌdรก แปgแปฬrรนn-รบn" (i.e. 300%). +* **ร€รฌtแปฬ kรฉkerรฉ**: O n din aแนฃiแนฃe ku bi แปgbon รฌdรก แปgแปฬrรนn-รบn (i.e. 40%) ti eda eniyan (oแนฃiแนฃแบน kรณรฒdรน) fa. * +* **แปŒgbแปฬn ร ti รฌmแปฬ€**: Atilแบนyin olootu nla. รŒparรญ nibi gbogbo. ร€kรณkรฒ dรญแบนฬ€ nipa wรญwรก ibi tรญ รฌแนฃรฒro kรณรฒdรน wร . +* **Irแปrun**: A kแป kรญ รณ le rแปrun lรกti lo ร ti lรกti kแป แบนkแป nรญnรบ rรจ. ร“ mรกa fรบn แป nรญ ร kรณkรฒ dรญแบนฬ€ lรกtฤฑ ka ร kแปsรญlแบน. +* **ร“ kรบkurรบ nรญ kikแป**: ร“ dรญn ร tรบnkแป ร ti ร tรบntรฒ kรณรฒdรน kรน. รŒkรฉde ร แนฃร yร n kแปฬ€แปฬ€kan nรญnรบ rแบนฬ€ nรญ แปฬ€pแปฬ€lแปpแปฬ€ ร wแปn รฌlรฒ. O แนฃe iranlแปwแป lรกti mรก แนฃe nรญ แปฬ€pแปฬ€lแปpแปฬ€ ร แนฃรฌแนฃe. +* **ร“ lรกgbรกra**: ร“ ล„ แนฃe ร gbรฉjรกde kรณรฒdรน tรญ รณ แนฃetรกn fรบn รฌแนฃelแปฬpแปฬ€. Pแบนฬ€lรบ ร kแปsรญlแบนฬ€ tรญ รณ mรกa แนฃร lร yรฉ ara rแบนฬ€ fรบn แบน nรญ รฌbรกแนฃepแปฬ€ alรกdร รกแนฃiแนฃแบนฬ pแบนฬ€lรบ rรจ. +* **Ajohunลกe/รŒtแปฬkasรญ**: ร“ da lori (ร ti ibamu ni kikun pแบนฬ€lรบ) ร wแปn รฌmแป ajohunลกe/รฌtแปฬkasรญ fรบn ร wแปn API: OpenAPI (รจyรญ tรญ a mแป tแบนlแบน si Swagger) ร ti JSON Schema. + +* iแนฃiro yi da lori ร wแปn idanwo tรญ แบนgbแบน รฌdร gbร sรณkรจ FastAPI แนฃe, nรญgbร tรญ wแปn kแป ร wแปn ohun elo iแนฃelแปpแป kรณรฒdรน pแบนฬ€lรบ rแบน. + +## ร€wแปn onรญgbแปฬ€wแปฬ + + + +{% if sponsors %} +{% for sponsor in sponsors.gold -%} + +{% endfor -%} +{%- for sponsor in sponsors.silver -%} + +{% endfor %} +{% endif %} + + + +ร€wแปn onรญgbแปฬ€wแปฬ mรญrร n + +## ร€wแปn ero ร ti รจsรฌ + +"_[...] Mรฒ ล„ lo **FastAPI** pรบpแปฬ€ nรญ lแบนฬnu ร รฌpแบนฬ yรฌรญ. [...] Mo n gbero lรกti lo o pแบนฬ€lรบ ร wแปn แบนgbแบน mi fรบn gbogbo iแนฃแบน **ML wa ni Microsoft**. Diแบน nรญnรบ wแปn ni afikun ti ifilelแบน ร wแปn แบนya ara ti แปja **Windows** wa pแบนฬ€lรบ ร wแปn ti **Office**._" + +
Kabir Khan - Microsoft (ref)
+ +--- + +"_A gba ร wแปn ohun รจlรฒ รฌwรฉ afแปwแปkแป **FastAPI** tรญ kรฒ yรญ padร  lรกti แนฃแบนฬ€dรก olรนpรญn **REST** tรญ a lรจ bรฉรจrรจ lแปฬwแปฬ rแบนฬ€ lรกti gba **ร sแปtแบนฬlแบนฬ€**. [fรบn Ludwig]_" + +
Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - Uber (ref)
+ +--- + +"_**Netflix** ni inudidun lรกti kede itusilแบน orisun kรณรฒdรน ti รฌlร nร  iแนฃแปkan **iแนฃakoso รŒแนฃรฒro** wa: **รŒfirรกnแนฃแบนฬ**! [a kแป pแบนฬ€lรบ **FastAPI**]_" + +
Kevin Glisson, Marc Vilanova, Forest Monsen - Netflix (ref)
+ +--- + +"_Inรบ mi dรนn pรบpแปฬ€ nรญpa **FastAPI**. ร“ mรบ inรบ แบนnรฌ dรนn pรบpแปฬ€!_" + +
Brian Okken - Python Bytes podcast host (ref)
+ +--- + +"_Nรญ tรฒรณtแปฬ, ohun tรญ o kแป dรกra รณ sรฌ tรบn dรกn. Nรญ แปฬ€pแปฬ€lแปpแปฬ€ แปฬ€nร , ohun tรญ mo fแบนฬ kรญ **Hug** jแบนฬ nรฌyแบนn - รณ wรบni lรณrรญ gan-an lรกti rรญ แบนnรฌkan tรญ รณ kแปฬ nวนkan bรญ รจyรญ._" + +
Timothy Crosley - Hug creator (ref)
+ +--- + +"_Ti o ba n wa lรกti kแป แปkan **รฌlร nร  igbalode** fรบn kikแป ร wแปn REST API, แนฃayแบนwo **FastAPI** [...] ร“ yรกra, รณ rแปrรนn lรกti lรฒ, รณ sรฌ rแปrรนn lรกti kแปฬ[...]_" + +"_A ti yipada si **FastAPI** fรบn **APIs** wa [...] Mo lรฉrรฒ pรฉ wร  รก fแบนฬrร n rแบนฬ€ [...]_" + +
Ines Montani - Matthew Honnibal - Explosion AI founders - spaCy creators (ref) - (ref)
+ +--- + +"_Ti แบนnikแบนni ba n wa lรกti kแป iแนฃelแปpแป API pแบนฬ€lรบ Python, รจmi yรณรฒ แนฃe'dรบrรณ fรบn **FastAPI**. ร“ jแบนฬ ohun tรญ **ร gbรฉkalแบนฬ€ rแบนฬ€ lแบนฬwร **, **รณ rแปrรนn lรกti lรฒ** ร ti wipe รณ ni **รฌwแปฬ€n gรญga**, o tรญ dรญ **bแปtini paati** nรญnรบ alakแปkแป API รฌdร gbร sรณkรจ kikแป fรบn wa, ร ti pe o ni ipa lori adaแนฃiแนฃแบน ร ti ร wแปn iแนฃแบน gแบนฬgแบนฬ bรญi Onรญmแปฬ€-แบนฬ€rแป TAC tรญ รณrรญ รล„tรกnแบนฬแบนฬ€tรฌ_" + +
Deon Pillsbury - Cisco (ref)
+ +--- + +## **Typer**, FastAPI ti CLIs + + + +Ti o ba n kแป ohun รจlรฒ CLI lรกti แนฃeรฉ lแป nรญnรบ ohun รจlรฒ lori ebute kแปmputa dipo API, แนฃayแบนwo **Typer**. + +**Typer** jแบนฬ ร bรบrรฒ รฌyรก FastAPI kรฉkerรฉ. ร€ti pรฉ wแปฬn kแปฬ lรกti jแบนฬ **FastAPI ti CLIs**. โŒจ๏ธ ๐Ÿš€ + +## รˆrรฒjร  + +Python 3.8+ + +FastAPI dรบrรณ lรณrรญ ร wแปn รจjรฌkรก tรญ ร wแปn รฒmรญrร n: + +* Starlette fรบn ร wแปn แบนฬ€yร  ayรฉlujรกra. +* Pydantic fรบn ร wแปn แบนฬ€yร  ร kรณjแปf'รกyแบนฬ€wรฒ. + +## Fifi sรณrรญ แบนrแป + +
+ +```console +$ pip install fastapi + +---> 100% +``` + +
+Iwแป yรณรฒ tรบn nรญlรฒ olupin ASGI, fรบn iแนฃelแปpแป bii Uvicorn tabi Hypercorn. + +
+ +```console +$ pip install "uvicorn[standard]" + +---> 100% +``` + +
+ +## ร€pแบนแบนrแบน + +### แนขแบนฬ€dรก rแบนฬ€ + +* แนขแบนฬ€dรก fรกรฌlรฌ `main.py (รจyรญ tรญรญ แนฃe, akแปkแป.py)` pแบนฬ€lรบ: + +```Python +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +
+Tร bรญ lรฒ async def... + +Tรญ kรณรฒdรน rแบนฬ€ bรก ล„ lรฒ `async` / `await`, lรฒ `async def`: + +```Python hl_lines="9 14" +from typing import Union + +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} +``` + +**Akiyesi**: + +Tรญ o kรฒ bรก mแปฬ€, แนฃร yแบนฬ€wรฒ ibi tรญ a ti nรญ _"In a hurry?"_ (i.e. _"Nรญ kรญรกkรญรก?"_) nรญpa `async` and `await` nรญnรบ ร kแปsรญlแบนฬ€. + +
+ +### Mu แนฃiแนฃแบน + +Mรบ olupin แนฃiแนฃแบน pแบนฬ€lรบ: + +
+ +```console +$ uvicorn main:app --reload + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +INFO: Started reloader process [28720] +INFO: Started server process [28722] +INFO: Waiting for application startup. +INFO: Application startup complete. +``` + +
+ +
+Nipa aแนฃแบน kรณรฒdรน nรกร  uvicorn main:app --reload... + +ร€แนฃแบน `uvicorn main:app` ล„ tแปฬka sรญ: + +* `main`: fรกรฌlรฌ nรกร  'main.py' (Python "module"). +* `app` jแบน object( i.e. nวนkan) tรญ a แนฃแบนฬ€dรก nรญnรบ `main.py` pแบนฬ€lรบ ilร  `app = FastAPI()`. +* `--reload`: รจyรญ yรณรฒ jแบนฬ ki olupin tรบn bแบนฬ€rแบนฬ€ lแบนฬhรฌn ร wแปn ร yรญpadร  kรณรฒdรน. Jแปฬ€wแปฬ, แนฃe รจyรญ fรบn รฌdร gbร sรณkรจ kรณรฒdรน nรฌkan, mรก แนฃe รฉ แนฃe lori ร gbรฉjรกde kรณรฒdรน tabi fรบn iแนฃelแปpแป kรณรฒdรน. + + +
+ +### แนขayแบนwo rแบน + +แนขii aแนฃร wรกkiri kแปฬ€วนpรบtร  rแบน ni http://127.0.0.1:8000/items/5?q=somequery. + +รŒwแป yรณรฒ sรฌ rรญ รฌdรกhรนn JSON bรญi: + +```JSON +{"item_id": 5, "q": "somequery"} +``` + +O tรญ แนฃแบนฬ€dรก API รจyรญ tรญ yรณรฒ: + +* Gbร  ร wแปn รฌbรฉรจrรจ HTTP ni ร wแปn _ipa แปฬ€nร _ `/` ร ti `/items/{item_id}`. +* รˆyรญ tรญ ร wแปn _ipa แปฬ€nร _ (i.e. _paths_) mรฉjรจรจjรฌ gbร  ร wแปn iแนฃแบน `GET` (a tun mแป si _ร wแปn แปna_ HTTP). +* รˆyรญ tรญ _ipa แปฬ€nร _ (i.e. _paths_) `/items/{item_id}` nรญ _ร wแปn ohun-ini ipa แปฬ€nร _ tรญ รณ yแบน kรญ รณ jแบนฬ `int` i.e. `ร’วธKร€`. +* รˆyรญ tรญ _ipa แปฬ€nร _ (i.e. _paths_) `/items/{item_id}` nรญ ร แนฃร yร n `str` _ร wแปn ohun-ini_ (i.e. _query parameter_) `q`. + +### รŒbรกแนฃepแปฬ€ ร kแปsรญlแบนฬ€ API + +Nรญ bรกyรฌรญ, lแป sรญ http://127.0.0.1:8000/docs. + +Lแบนฬyรฌn nรกร , iwแป yรณรฒ rรญ รฌdรกhรนn ร kแปsรญlแบนฬ€ API tรญ รณ jแบนฬ รฌbรกแนฃepแปฬ€ alaifแปwแปyi/alรกdร รกแนฃiแนฃแบนฬ (tรญ a pรจแนฃรจ nรญpaแนฃแบนฬ€ Swagger UI): + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png) + +### รŒdร kejรฌ ร kแปsรญlแบนฬ€ API + +Nรญ bรกyรฌรญ, lแป sรญ http://127.0.0.1:8000/redoc. + +Wร  รก rรญ ร wแปn ร kแปsรญlแบนฬ€ alรกdร รกแนฃiแนฃแบนฬ mรฌรญrร n (tรญ a pese nipasแบน ReDoc): + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png) + +## ร€pแบนแบนrแบน รฌgbรฉsรณkรจ mรฌรญrร n + +Nรญ bรกyรฌรญ แนฃe ร tรบnแนฃe fรกรฌlรฌ `main.py` lรกti gba kรณkรณ รจsรฌ lรกti inรบ รฌbรฉรจrรจ `PUT`. + +Nรญ bรกyรฌรญ, แนฃe รฌkรฉde kรณkรณ รจsรฌ API nรญnรบ kรณรฒdรน rแบน nipa lรญlo ร wแปn รฌtแปฬkasรญ ร mรฌ irรบfแบนฬ Python, แปpแบนฬ pร tร kรฌsi sรญ Pydantic. + +```Python hl_lines="4 9-12 25-27" +from typing import Union + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + is_offer: Union[bool, None] = None + + +@app.get("/") +def read_root(): + return {"Hello": "World"} + + +@app.get("/items/{item_id}") +def read_item(item_id: int, q: Union[str, None] = None): + return {"item_id": item_id, "q": q} + + +@app.put("/items/{item_id}") +def update_item(item_id: int, item: Item): + return {"item_name": item.name, "item_id": item_id} +``` + +Olupin yรณรฒ tรบn แนฃe ร tรบnแนฃe laifแปwแปyi/alรกdร รกแนฃiแนฃแบนฬ (nรญtorรญ wรญpรฉ รณ se ร fikรบn `-reload` si ร แนฃแบน kรณรฒdรน `uvicorn` lรณkรจ). + +### รŒbรกแนฃepแปฬ€ รฌgbรฉsรณkรจ ร kแปsรญlแบนฬ€ API + +Nรญ bรกyรฌรญ, lแป sรญ http://127.0.0.1:8000/docs. + +* รŒbรกแนฃepแปฬ€ ร kแปsรญlแบนฬ€ API yรณรฒ แนฃe imudojuiwแปn ร kแปsรญlแบนฬ€ API laifแปwแปyi, pแบนฬ€lรบ kรณkรณ รจsรฌ รฌdรกhรนn API tuntun: + +![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png) + +* Tแบน bแปtini "Gbiyanju rแบน" i.e. "Try it out", yรณรฒ gbร  แปฬ lรกร yรจ lรกti jแบนฬ kรญ รณ tแบนฬ ร lร yรฉ tรญ รณ nรญlรฒ kรญ รณ le sแปฬ€rแปฬ€ tร ร rร  pแบนฬ€lรบ API: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png) + +* Lแบนhinna tแบน bแปtini "แนขiแนฃe" i.e. "Execute", olรนmรบlรฒ (i.e. user interface) yรณรฒ sแปrแป pแบนฬ€lรบ API rแบน, yรณรฒ แนฃe afiranแนฃแบน ร wแปn รจrรฒjร , pร รกpร รก jรนlแป yรณรฒ gba ร wแปn ร bรกjรกde yรณรฒ si แนฃafihan wแปn loju รฌbรฒjรบ: + +![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png) + +### รŒdร kejรฌ รฌgbรฉsรณkรจ ร kแปsรญlแบนฬ€ API + +Nรญ bรกyรฌรญ, lแป sรญ http://127.0.0.1:8000/redoc. + +* รŒdร kejรฌ ร kแปsรญlแบนฬ€ API yรณรฒ แนฃ'afihan รฌbรฉรจrรจ รจrรฒjร /pร rรกmรญtร  tuntun ร ti kรณkรณ รจsรฌ ti API: + +![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png) + +### ร€tรบnyแบนฬ€wรฒ + +Ni akopแป, รฌwแป yรณรฒ kรฉde ni **kete** ร wแปn iru รจrรฒjร /pร rรกmรญtร , kรณkรณ รจsรฌ API, abbl (i.e. ร ti bแบนbแบน lแป), bi ร wแปn รจrรฒjร  iแนฃแบน. + +O แนฃe รฌyแบนn pแบนฬ€lรบ irรบfแบนฬ ร mรฌ รฌtแปฬkasรญ รฌgbร lรณdรฉ Python. + +O รฒ nรญlรฒ lรกti kแปฬ sรญล„tรกร sรฌ tuntun, รฌlร nร  tร bรญ แปฬ€wแปฬ kรญlรกร sรฌ kan pร tรณ, abbl (i.e. ร ti bแบนbแบน lแป). + +รŒtแปฬkasรญ **Python 3.8+** + +Fรบn ร pแบนแบนrแบน, fรบn `int`: + +```Python +item_id: int +``` + +tร bรญ fรบn ร wรฒแนฃe `Item` tรญ รณ nira dรญแบนฬ€ sรญi: + +```Python +item: Item +``` + +... ร ti pแบนฬ€lรบ รฌkรฉde kan แนฃoแนฃo yแบนn รฌwแป yรณรฒ gbร : + +* Atilแบนyin olootu, pแบนฬ€lรบ: + * Pipari. + * ร€yแบนฬ€wรฒ irรบfแบนฬ ร mรฌ รฌtแปฬkasรญ. +* รŒfแปwแปฬsรญ ร kรณjแปf'รกyแบนฬ€wรฒ (i.e. data): + * Aแนฃiแนฃe alaifแปwแปyi/alรกdร รกแนฃiแนฃแบนฬ ร ti aแนฃiแนฃe ti รณ hร n kedere nรญgbร tรญ ร wแปn ร kรณjแปf'รกyแบนฬ€wรฒ (i.e. data) kรฒ wulo tabi tรญ kรฒ fแบนsแบนฬ€ mรบlแบนฬ€. + * รŒfแปwแปฬsรญ fรบn ohun elo JSON tรญ รณ jรฌn gan-an. +* รŒyรญpadร  tรญ input ร kรณjแปf'รกyแบนฬ€wรฒ: tรญ รณ wร  lรกti nแบนtiwแปแปki si ร kรณjแปf'รกyแบนฬ€wรฒ ร ti irรบfแบนฬ ร mรฌ รฌtแปฬkasรญ Python. ร“ ล„ ka lรกti: + * JSON. + * รจrรฒjร  แปฬ€nร  tรญ รฒ gbรฉ gbร . + * รจrรฒjร  รฌbรฉรจrรจ. + * ร€wแปn Kรบkรฌ + * ร€wแปn ร€kแปlรฉ + * ร€wแปn Fแปแปmu + * ร€wแปn Fรกรฌlรฌ +* รŒyรญpadร  รจsรฌ ร kรณjแปf'รกyแบนฬ€wรฒ: yรญyรญpadร  lรกti ร kรณjแปf'รกyแบนฬ€wรฒ ร ti irรบfแบนฬ ร mรฌ รฌtแปฬkasรญ Python si nแบนtiwแปแปki (gแบนฬgแบนฬ bรญ JSON): + * Yรญ irรบfแบนฬ ร mรฌ รฌtแปฬkasรญ padร  (`str`, `int`, `float`, `bool`, `list`, abbl i.e. ร ti bรจbรจ lรณ). + * ร€wแปn ohun รจlรฒ `datetime`. + * ร€wแปn ohun รจlรฒ `UUID`. + * ร€wแปn awoแนฃแบนฬ ibi รฌpamแปฬ ร kรณjแปf'รกyแบนฬ€wรฒ. + * ...ร ti แปฬ€pแปฬ€lแปpแปฬ€ dรญแบนฬ€ sรญi. +* รŒbรกแนฃepแปฬ€ ร kแปsรญlแบนฬ€ API alรกdร รกแนฃiแนฃแบนฬ, pแบนฬ€lรบ รฌdร kejรฌ ร gbรฉkalแบนฬ€-ร wแปn-olรนmรบlรฒ (i.e user interfaces) mรฉjรฌ: + * ร€gbรฉkalแบนฬ€-olรนmรบlรฒ Swagger. + * ReDoc. + +--- + +Nisinsin yi, tรญ รณ padร  sรญ ร pแบนแบนrแบน ti tแบนฬlแบนฬ€, **FastAPI** yรณรฒ: + +* Fแปwแปฬ sรญ i pรฉ `item_id` wร  nรญnรบ แปฬ€nร  รฌbรฉรจrรจ HTTP fรบn `GET` ร ti `PUT`. +* Fแปwแปฬ sรญ i pรฉ `item_id` jแบนฬ irรบfแบนฬ ร mรฌ รฌtแปฬkasรญ `int` fรบn รฌbรฉรจrรจ HTTP `GET` ร ti `PUT`. + * Tรญ kรฌรญ bรก แนฃe bแบน, onรญbร รกrร  yรณรฒ rรญi ร แนฃรฌแนฃe tรญ รณ wรบlรฒ, kedere. +* แนขร yแบนฬ€wรฒ bรณyรก รฌbรฉรจrรจ ร แนฃร yร n pร rรกmรญtร  kan wร  tรญ orรบkแป rแบนฬ€ ล„ jแบนฬ `q` (gแบนฬgแบนฬ bรญi `http://127.0.0.1:8000/items/foo?q=somequery`) fรบn รฌbรฉรจrรจ HTTP `GET`. + * Bรญ wแปฬn แนฃe kรฉde pร rรกmรญtร  `q` pแบนฬ€lรบ `= None`, รณ jแบนฬ ร แนฃร yร n (i.e optional). + * Lรกรฌsรญ `None` yรณรฒ nรญlรฒ (gแบนฬgแบนฬ bรญ kรณkรณ รจsรฌ รฌbรฉรจrรจ HTTP แนฃe wร  pแบนฬ€lรบ `PUT`). +* Fรบn ร wแปn รฌbรฉรจrรจ HTTP `PUT` sรญ `/items/{item_id}`, kร  kรณkรณ รจsรฌ รฌbรฉรจrรจ HTTP gแบนฬgแบนฬ bรญ JSON: + * แนขร yแบนฬ€wรฒ pรฉ รณ nรญ ร bรนdรก tรญ รณ nรญlรฒ รจyรญ tรญรญ แนฃe `name` i.e. `orรบkแป` tรญ รณ yแบน kรญ รณ jแบนฬ `str`. + * แนขร yแบนฬ€wรฒ pรฉ รณ nรญ ร bรนdรก tรญ รณ nรญlรฒ รจyรญ tรญรญ แนฃe `price` i.e. `iye` tรญ รณ gbแปฬdแปฬ€ jแบนฬ `float`. + * แนขร yแบนฬ€wรฒ pรฉ รณ nรญ ร bรนdรก ร แนฃร yร n `is_offer`, tรญ รณ yแบน kรญ รณ jแบนฬ `bool`, tรญ รณ bรก wร  nรญbแบนฬ€. + * Gbogbo รจyรญ yรณรฒ tรบn แนฃiแนฃแบนฬ fรบn ร wแปn ohun รจlรฒ JSON tรญ รณ jรฌn gidi gan-an. +* Yรฌรญ padร  lรกti ร ti sรญ JSON lai fi แปwแปฬ yi. +* แนขe ร kแปsรญlแบนฬ€ ohun gbogbo pแบนฬ€lรบ OpenAPI, รจyรญ tรญ yรณรฒ wร  nรญ lรญlo nรญpaแนฃแบนฬ€: + * ร€wแปn รจtรฒ ร kแปsรญlแบนฬ€ รฌbรกแนฃepแปฬ€. + * Alรกdร รกแนฃiแนฃแบนฬ onรญbรกrร  รจlรจtรฒ tรญรญ แนฃแบนฬ€dรก kรณรฒdรน, fรบn แปฬ€pแปฬ€lแปpแปฬ€ ร wแปn รจdรจ. +* Pese ร kแปsรญlแบนฬ€ รฒnรญ รฌbรกแนฃepแปฬ€ ti ร wแปn ร gbรฉkalแบนฬ€ ayรฉlujรกra mรฉjรฌ tร ร rร . + +--- + +A ล„ แนฃแบนฬ€แนฃแบนฬ€ ล„ mรบ แบนyแบน bแปฬ lร pรฒ nรญ, แนฃรนgbแปฬn รณ ti ni รฒye bรญ gbogbo rแบนฬ€ แนฃe ล„ แนฃiแนฃแบนฬ. + +Gbiyanju lรกti yรญ รฌlร  padร  pแบนฬ€lรบ: + +```Python + return {"item_name": item.name, "item_id": item_id} +``` + +...lรกti: + +```Python + ... "item_name": item.name ... +``` + +...แนฃรญ: + +```Python + ... "item_price": item.price ... +``` + +.. kรญ o sรฌ wo bรญ olรณรฒtรบ rแบน yรณรฒ แนฃe parรญ ร wแปn ร bรนdรก nรกร  fรบnra rแบนฬ€, yรณรฒ sรฌ mแป irรบfแบนฬ wแปn: + +![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png) + +Fรบn ร pแบนแบนrแบน pรญpรฉ sรญi pแบนฬ€lรบ ร wแปn ร bรนdรก mรฌรญrร n, wo รŒdรกnilแบนฬkแปฬ€แปฬ - รŒtแปฬsแปฬnร  Olรนmรบlรฒ. + +**Itaniji gแบนฬgแบนฬ bรญ isแป'ye**: รฌdรกnilแบนฬkแปฬ€แปฬ - itแปsแปna olรนmรบlรฒ pแบนฬ€lรบ: + +* รŒkรฉde ร แนฃร yร n **pร rรกmรญtร ** lรกti ร wแปn oriแนฃiriแนฃi ibรฒmรญrร n gแบนฬgแบนฬ bรญi: ร wแปn **ร kแปlรฉ รจsรฌ API**, **kรบkรฌ**, **ร ร yรจ fแปแปmu**, ร ti **fรกรฌlรฌ**. +* Bรญi รณ แนฃe lรฉ แนฃรจtรฒ **ร wแปn รฌdรญwแปฬ รฌfแปwแปฬsรญ** bรญ `maximum_length` tร bรญ `regex`. +* ร“ lรกgbรกra pรบpแปฬ€ รณ sรฌ rแปrรนn lรกti lo รจtรฒ **ร€fikรบn รŒgbแบนฬkแบนฬ€lรฉ Kรณรฒdรน**. +* ร€ร bรฒ ร ti รฌfแปwแปฬsowแปฬpแปฬ€, pแบนฬ€lรบ ร tรฌlแบนฬyรฌn fรบn **OAuth2** pแบนฬ€lรบ **ร mรฌ JWT** ร ti **HTTP Ipilแบน รฌfแปwแปฬsowแปฬpแปฬ€**. +* ร€wแปn รฌlร nร  รฌlแปsรญwรกjรบ (แนฃรนgbแปฬn tรญ รณ rแปrรนn bรกkan nรกร ) fรบn รฌkรฉde **ร wแปn ร wรฒแนฃe JSON tรณ jinlแบนฬ€** (แปpแบนฬ pร tร kรฌsi sรญ Pydantic). +* Iแนฃแปpแป **GraphQL** pแบนฬ€lรบ Strawberry ร ti ร wแปn ohun รจlรฒ รฌwรฉ kรณรฒdรน afแปwแปkแป mรฌรญrร n tรญ kรฒ yรญ padร . +* แปŒpแปlแปpแป ร wแปn ร fikรบn ร wแปn แบนฬ€yร  (แปpแบนฬ pร tร kรฌsi sรญ Starlette) bรญ: + * **WebSockets** + * ร wแปn รฌdรกnwรฒ tรญ รณ rแปrรนn pรบpแปฬ€ lรณrรญ HTTPX ร ti `pytest` + * **CORS** + * **Cookie Sessions** + * ...ร ti sรญwรกjรบ sรญi. + +## รŒแนฃesรญ + +ร€wแปn ร lรก TechEmpower fi hร n pรฉ **FastAPI** ล„ แนฃiแนฃแบนฬ lรกbแบนฬ Uvicorn gแบนฬgแบนฬ bรญ แปฬ€kan lรกra ร wแปn รฌlร nร  Python tรญ รณ yรกra jรนlแป tรญ รณ wร , nรญ รฌsร lแบนฬ€ Starlette ร ti Uvicorn fรบnra wแปn (tรญ FastAPI ล„ lรฒ fรบnra rแบนฬ€). (*) + +Lรกti nรญ รฒye sรญi nรญpa rแบนฬ€, wo abala ร wแปn ร€lรก. + +## ร€แนฃร yร n ร€wแปn ร€fikรบn รŒgbแบนฬkแบนฬ€lรฉ Kรณรฒdรน + +รˆyรญ tรญ Pydantic ล„ lรฒ: + +* email_validator - fรบn ifแปwแปsi รญmeรจlรฌ. +* pydantic-settings - fรบn รจtรฒ รฌsร kรณso. +* pydantic-extra-types - fรบn ร fikรบn orรญแนฃi lรกti lแป pแบนฬ€lรบ Pydantic. + +รˆyรญ tรญ Starlette ล„ lรฒ: + +* httpx - Nรญlรฒ tรญ รณ bรก fแบนฬ lรกti lแป `TestClient`. +* jinja2 - Nรญlรฒ tรญ รณ bรก fแบนฬ lรกti lแป iแนฃeto awoแนฃe aiyipada. +* python-multipart - Nรญlรฒ tรญ รณ bรก fแบนฬ lรกti แนฃe ร tรฌlแบนฬyรฌn fรบn "ร yแบนฬ€wรฒ" fแปแปmu, pแบนฬ€lรบ `request.form()`. +* itsdangerous - Nรญlรฒ fรบn ร tรฌlแบนฬyรฌn `SessionMiddleware`. +* pyyaml - Nรญlรฒ fรบn ร tรฌlแบนฬyรฌn Starlette's `SchemaGenerator` (รณ แนฃe แนฃe kรญ รณ mรก nรญlรฒ rแบนฬ€ fรบn FastAPI). +* ujson - Nรญlรฒ tรญ รณ bรก fแบนฬ lรกti lแป `UJSONResponse`. + +รˆyรญ tรญ FastAPI / Starlette ล„ lรฒ: + +* uvicorn - Fรบn olupin tรญ yรณรฒ sแบนฬ ร mรบyแบน ร ti tรญ yรณรฒ แนฃe รฌpรจsรจ fรบn iแนฃแบนฬ rแบน tร bรญ ohun รจlรฒ rแบน. +* orjson - Nรญlรฒ tรญ รณ bรก fแบนฬ lรกti lแป `ORJSONResponse`. + +ร“ lรจ fi gbogbo ร wแปn wแปฬ€nyรญ sรณrรญ แบนrแป pแบนฬ€lรบ `pip install "fastapi[all]"`. + +## Iwe-aแนฃแบน + +Iแนฃแบนฬ yรฌรญ ni iwe-aแนฃแบน lรกbแบนฬ ร wแปn รฒfin tรญ iwe-aแนฃแบน MIT. diff --git a/docs/yo/mkdocs.yml b/docs/yo/mkdocs.yml new file mode 100644 index 000000000..de18856f4 --- /dev/null +++ b/docs/yo/mkdocs.yml @@ -0,0 +1 @@ +INHERIT: ../en/mkdocs.yml diff --git a/docs/zh/docs/advanced/generate-clients.md b/docs/zh/docs/advanced/generate-clients.md new file mode 100644 index 000000000..e222e479c --- /dev/null +++ b/docs/zh/docs/advanced/generate-clients.md @@ -0,0 +1,266 @@ +# ็”Ÿๆˆๅฎขๆˆท็ซฏ + +ๅ› ไธบ **FastAPI** ๆ˜ฏๅŸบไบŽOpenAPI่ง„่Œƒ็š„๏ผŒ่‡ช็„ถๆ‚จๅฏไปฅไฝฟ็”จ่ฎธๅคš็›ธๅŒน้…็š„ๅทฅๅ…ท๏ผŒๅŒ…ๆ‹ฌ่‡ชๅŠจ็”ŸๆˆAPIๆ–‡ๆกฃ (็”ฑ Swagger UI ๆไพ›)ใ€‚ + +ไธ€ไธชไธๅคชๆ˜Žๆ˜พ่€Œๅˆ็‰นๅˆซ็š„ไผ˜ๅŠฟๆ˜ฏ๏ผŒไฝ ๅฏไปฅไธบไฝ ็š„API้’ˆๅฏนไธๅŒ็š„**็ผ–็จ‹่ฏญ่จ€**ๆฅ**็”Ÿๆˆๅฎขๆˆท็ซฏ**(ๆœ‰ๆ—ถๅ€™่ขซๅซๅš **SDKs** )ใ€‚ + +## OpenAPI ๅฎขๆˆท็ซฏ็”Ÿๆˆ + +ๆœ‰่ฎธๅคšๅทฅๅ…ทๅฏไปฅไปŽ**OpenAPI**็”Ÿๆˆๅฎขๆˆท็ซฏใ€‚ + +ไธ€ไธชๅธธ่ง็š„ๅทฅๅ…ทๆ˜ฏ OpenAPI Generatorใ€‚ + +ๅฆ‚ๆžœๆ‚จๆญฃๅœจๅผ€ๅ‘**ๅ‰็ซฏ**๏ผŒไธ€ไธช้žๅธธๆœ‰่ถฃ็š„ๆ›ฟไปฃๆ–นๆกˆๆ˜ฏ openapi-typescript-codegenใ€‚ + +## ็”Ÿๆˆไธ€ไธช TypeScript ๅ‰็ซฏๅฎขๆˆท็ซฏ + +่ฎฉๆˆ‘ไปฌไปŽไธ€ไธช็ฎ€ๅ•็š„ FastAPI ๅบ”็”จๅผ€ๅง‹๏ผš + +=== "Python 3.9+" + + ```Python hl_lines="7-9 12-13 16-17 21" + {!> ../../../docs_src/generate_clients/tutorial001_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="9-11 14-15 18 19 23" + {!> ../../../docs_src/generate_clients/tutorial001.py!} + ``` + +่ฏทๆณจๆ„๏ผŒ*่ทฏๅพ„ๆ“ไฝœ* ๅฎšไน‰ไบ†ไป–ไปฌๆ‰€็”จไบŽ่ฏทๆฑ‚ๆ•ฐๆฎๅ’Œๅ›žๅบ”ๆ•ฐๆฎ็š„ๆจกๅž‹๏ผŒๆ‰€ไฝฟ็”จ็š„ๆจกๅž‹ๆ˜ฏ`Item` ๅ’Œ `ResponseMessage`ใ€‚ + +### API ๆ–‡ๆกฃ + +ๅฆ‚ๆžœๆ‚จ่ฎฟ้—ฎAPIๆ–‡ๆกฃ๏ผŒๆ‚จๅฐ†็œ‹ๅˆฐๅฎƒๅ…ทๆœ‰ๅœจ่ฏทๆฑ‚ไธญๅ‘้€ๅ’Œๅœจๅ“ๅบ”ไธญๆŽฅๆ”ถๆ•ฐๆฎ็š„**ๆจกๅผ(schemas)**๏ผš + + + +ๆ‚จๅฏไปฅ็œ‹ๅˆฐ่ฟ™ไบ›ๆจกๅผ๏ผŒๅ› ไธบๅฎƒไปฌๆ˜ฏ็”จ็จ‹ๅบไธญ็š„ๆจกๅž‹ๅฃฐๆ˜Ž็š„ใ€‚ + +้‚ฃไบ›ไฟกๆฏๅฏไปฅๅœจๅบ”็”จ็š„ **OpenAPIๆจกๅผ** ่ขซๆ‰พๅˆฐ๏ผŒ็„ถๅŽๆ˜พ็คบๅœจAPIๆ–‡ๆกฃไธญ๏ผˆ้€š่ฟ‡Swagger UI๏ผ‰ใ€‚ + +OpenAPIไธญๆ‰€ๅŒ…ๅซ็š„ๆจกๅž‹้‡Œๆœ‰็›ธๅŒ็š„ไฟกๆฏๅฏไปฅ็”จไบŽ **็”Ÿๆˆๅฎขๆˆท็ซฏไปฃ็ **ใ€‚ + +### ็”Ÿๆˆไธ€ไธชTypeScript ๅฎขๆˆท็ซฏ + +็Žฐๅœจๆˆ‘ไปฌๆœ‰ไบ†ๅธฆๆœ‰ๆจกๅž‹็š„ๅบ”็”จ๏ผŒๆˆ‘ไปฌๅฏไปฅไธบๅ‰็ซฏ็”Ÿๆˆๅฎขๆˆท็ซฏไปฃ็ ใ€‚ + +#### ๅฎ‰่ฃ… `openapi-typescript-codegen` + +ๆ‚จๅฏไปฅไฝฟ็”จไปฅไธ‹ๅทฅๅ…ทๅœจๅ‰็ซฏไปฃ็ ไธญๅฎ‰่ฃ… `openapi-typescript-codegen`: + +
+ +```console +$ npm install openapi-typescript-codegen --save-dev + +---> 100% +``` + +
+ +#### ็”Ÿๆˆๅฎขๆˆท็ซฏไปฃ็  + +่ฆ็”Ÿๆˆๅฎขๆˆท็ซฏไปฃ็ ๏ผŒๆ‚จๅฏไปฅไฝฟ็”จ็Žฐๅœจๅฐ†่ฆๅฎ‰่ฃ…็š„ๅ‘ฝไปค่กŒๅบ”็”จ็จ‹ๅบ `openapi`ใ€‚ + +ๅ› ไธบๅฎƒๅฎ‰่ฃ…ๅœจๆœฌๅœฐ้กน็›ฎไธญ๏ผŒๆ‰€ไปฅๆ‚จๅฏ่ƒฝๆ— ๆณ•็›ดๆŽฅไฝฟ็”จๆญคๅ‘ฝไปค๏ผŒไฝ†ๆ‚จๅฏไปฅๅฐ†ๅ…ถๆ”พๅœจ `package.json` ๆ–‡ไปถไธญใ€‚ + +ๅฎƒๅฏ่ƒฝ็œ‹่ตทๆฅๆ˜ฏ่ฟ™ๆ ท็š„: + +```JSON hl_lines="7" +{ + "name": "frontend-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "generate-client": "openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios" + }, + "author": "", + "license": "", + "devDependencies": { + "openapi-typescript-codegen": "^0.20.1", + "typescript": "^4.6.2" + } +} +``` + +ๅœจ่ฟ™้‡ŒๆทปๅŠ  NPM `generate-client` ่„šๆœฌๅŽ๏ผŒๆ‚จๅฏไปฅไฝฟ็”จไปฅไธ‹ๅ‘ฝไปค่ฟ่กŒๅฎƒ: + +
+ +```console +$ npm run generate-client + +frontend-app@1.0.0 generate-client /home/user/code/frontend-app +> openapi --input http://localhost:8000/openapi.json --output ./src/client --client axios +``` + +
+ +ๆญคๅ‘ฝไปคๅฐ†ๅœจ `./src/client` ไธญ็”Ÿๆˆไปฃ็ ๏ผŒๅนถๅฐ†ๅœจๅ…ถๅ†…้ƒจไฝฟ็”จ `axios`๏ผˆๅ‰็ซฏHTTPๅบ“๏ผ‰ใ€‚ + +### ๅฐ่ฏ•ๅฎขๆˆท็ซฏไปฃ็  + +็Žฐๅœจๆ‚จๅฏไปฅๅฏผๅ…ฅๅนถไฝฟ็”จๅฎขๆˆท็ซฏไปฃ็ ๏ผŒๅฎƒๅฏ่ƒฝ็œ‹่ตทๆฅๅƒ่ฟ™ๆ ท๏ผŒ่ฏทๆณจๆ„๏ผŒๆ‚จๅฏไปฅไธบ่ฟ™ไบ›ๆ–นๆณ•ไฝฟ็”จ่‡ชๅŠจ่กฅๅ…จ๏ผš + + + +ๆ‚จ่ฟ˜ๅฐ†่‡ชๅŠจ่กฅๅ…จ่ฆๅ‘้€็š„ๆ•ฐๆฎ๏ผš + + + +!!! tip + ่ฏทๆณจๆ„๏ผŒ `name` ๅ’Œ `price` ็š„่‡ชๅŠจ่กฅๅ…จ๏ผŒๆ˜ฏ้€š่ฟ‡ๅ…ถๅœจ`Item`ๆจกๅž‹(FastAPI)ไธญ็š„ๅฎšไน‰ๅฎž็Žฐ็š„ใ€‚ + +ๅฆ‚ๆžœๅ‘้€็š„ๆ•ฐๆฎๅญ—ๆฎตไธ็ฌฆ๏ผŒไฝ ไนŸไผš็œ‹ๅˆฐ็ผ–่พ‘ๅ™จ็š„้”™่ฏฏๆ็คบ: + + + +ๅ“ๅบ”(response)ๅฏน่ฑกไนŸๆ‹ฅๆœ‰่‡ชๅŠจ่กฅๅ…จ: + + + +## ๅธฆๆœ‰ๆ ‡็ญพ็š„ FastAPI ๅบ”็”จ + +ๅœจ่ฎธๅคšๆƒ…ๅ†ตไธ‹๏ผŒไฝ ็š„FastAPIๅบ”็”จ็จ‹ๅบไผšๆ›ดๅคๆ‚๏ผŒไฝ ๅฏ่ƒฝไผšไฝฟ็”จๆ ‡็ญพๆฅๅˆ†้š”ไธๅŒ็ป„็š„*่ทฏๅพ„ๆ“ไฝœ(path operations)*ใ€‚ + +ไพ‹ๅฆ‚๏ผŒๆ‚จๅฏไปฅๆœ‰ไธ€ไธช็”จ `items` ็š„้ƒจๅˆ†ๅ’Œๅฆไธ€ไธช็”จไบŽ `users` ็š„้ƒจๅˆ†๏ผŒๅฎƒไปฌๅฏไปฅ็”จๆ ‡็ญพๆฅๅˆ†้š”๏ผš + +=== "Python 3.9+" + + ```Python hl_lines="21 26 34" + {!> ../../../docs_src/generate_clients/tutorial002_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="23 28 36" + {!> ../../../docs_src/generate_clients/tutorial002.py!} + ``` + +### ็”Ÿๆˆๅธฆๆœ‰ๆ ‡็ญพ็š„ TypeScript ๅฎขๆˆท็ซฏ + +ๅฆ‚ๆžœๆ‚จไฝฟ็”จๆ ‡็ญพไธบFastAPIๅบ”็”จ็”Ÿๆˆๅฎขๆˆท็ซฏ๏ผŒๅฎƒ้€šๅธธไนŸไผšๆ นๆฎๆ ‡็ญพๅˆ†ๅ‰ฒๅฎขๆˆท็ซฏไปฃ็ ใ€‚ + +้€š่ฟ‡่ฟ™็งๆ–นๅผ๏ผŒๆ‚จๅฐ†่ƒฝๅคŸไธบๅฎขๆˆท็ซฏไปฃ็ ่ฟ›่กŒๆญฃ็กฎๅœฐๆŽ’ๅบๅ’Œๅˆ†็ป„๏ผš + + + +ๅœจ่ฟ™ไธชๆกˆไพ‹ไธญ๏ผŒๆ‚จๆœ‰๏ผš + +* `ItemsService` +* `UsersService` + +### ๅฎขๆˆท็ซฏๆ–นๆณ•ๅ็งฐ + +็Žฐๅœจ็”Ÿๆˆ็š„ๆ–นๆณ•ๅๅƒ `createItemItemsPost` ็œ‹่ตทๆฅไธๅคช็ฎ€ๆด: + +```TypeScript +ItemsService.createItemItemsPost({name: "Plumbus", price: 5}) +``` + +...่ฟ™ๆ˜ฏๅ› ไธบๅฎขๆˆท็ซฏ็”Ÿๆˆๅ™จไธบๆฏไธช *่ทฏๅพ„ๆ“ไฝœ* ไฝฟ็”จOpenAPI็š„ๅ†…้ƒจ **ๆ“ไฝœ ID(operation ID)**ใ€‚ + +OpenAPI่ฆๆฑ‚ๆฏไธชๆ“ไฝœ ID ๅœจๆ‰€ๆœ‰ *่ทฏๅพ„ๆ“ไฝœ* ไธญ้ƒฝๆ˜ฏๅ”ฏไธ€็š„๏ผŒๅ› ๆญค FastAPI ไฝฟ็”จ**ๅ‡ฝๆ•ฐๅ**ใ€**่ทฏๅพ„**ๅ’Œ**HTTPๆ–นๆณ•/ๆ“ไฝœ**ๆฅ็”Ÿๆˆๆญคๆ“ไฝœID๏ผŒๅ› ไธบ่ฟ™ๆ ทๅฏไปฅ็กฎไฟ่ฟ™ไบ›ๆ“ไฝœ ID ๆ˜ฏๅ”ฏไธ€็š„ใ€‚ + +ไฝ†ๆŽฅไธ‹ๆฅๆˆ‘ไผšๅ‘Š่ฏ‰ไฝ ๅฆ‚ไฝ•ๆ”น่ฟ›ใ€‚ ๐Ÿค“ + +## ่‡ชๅฎšไน‰ๆ“ไฝœIDๅ’Œๆ›ดๅฅฝ็š„ๆ–นๆณ•ๅ + +ๆ‚จๅฏไปฅ**ไฟฎๆ”น**่ฟ™ไบ›ๆ“ไฝœID็š„**็”Ÿๆˆ**ๆ–นๅผ๏ผŒไปฅไฝฟๅ…ถๆ›ด็ฎ€ๆด๏ผŒๅนถๅœจๅฎขๆˆท็ซฏไธญๅ…ทๆœ‰**ๆ›ด็ฎ€ๆด็š„ๆ–นๆณ•ๅ็งฐ**ใ€‚ + +ๅœจ่ฟ™็งๆƒ…ๅ†ตไธ‹๏ผŒๆ‚จๅฟ…้กป็กฎไฟๆฏไธชๆ“ไฝœIDๅœจๅ…ถไป–ๆ–น้ขๆ˜ฏ**ๅ”ฏไธ€**็š„ใ€‚ + +ไพ‹ๅฆ‚๏ผŒๆ‚จๅฏไปฅ็กฎไฟๆฏไธช*่ทฏๅพ„ๆ“ไฝœ*้ƒฝๆœ‰ไธ€ไธชๆ ‡็ญพ๏ผŒ็„ถๅŽๆ นๆฎ**ๆ ‡็ญพ**ๅ’Œ*่ทฏๅพ„ๆ“ไฝœ***ๅ็งฐ**๏ผˆๅ‡ฝๆ•ฐๅ๏ผ‰ๆฅ็”Ÿๆˆๆ“ไฝœIDใ€‚ + +### ่‡ชๅฎšไน‰็”Ÿๆˆๅ”ฏไธ€IDๅ‡ฝๆ•ฐ + +FastAPIไธบๆฏไธช*่ทฏๅพ„ๆ“ไฝœ*ไฝฟ็”จไธ€ไธช**ๅ”ฏไธ€ID**๏ผŒๅฎƒ็”จไบŽ**ๆ“ไฝœID**๏ผŒไนŸ็”จไบŽไปปไฝ•ๆ‰€้œ€่‡ชๅฎšไน‰ๆจกๅž‹็š„ๅ็งฐ๏ผŒ็”จไบŽ่ฏทๆฑ‚ๆˆ–ๅ“ๅบ”ใ€‚ + +ไฝ ๅฏไปฅ่‡ชๅฎšไน‰่ฏฅๅ‡ฝๆ•ฐใ€‚ๅฎƒๆŽฅๅ—ไธ€ไธช `APIRoute` ๅฏน่ฑกไฝœไธบ่พ“ๅ…ฅ๏ผŒๅนถ่พ“ๅ‡บไธ€ไธชๅญ—็ฌฆไธฒใ€‚ + +ไพ‹ๅฆ‚๏ผŒไปฅไธ‹ๆ˜ฏไธ€ไธช็คบไพ‹๏ผŒๅฎƒไฝฟ็”จ็ฌฌไธ€ไธชๆ ‡็ญพ๏ผˆไฝ ๅฏ่ƒฝๅชๆœ‰ไธ€ไธชๆ ‡็ญพ๏ผ‰ๅ’Œ*่ทฏๅพ„ๆ“ไฝœ*ๅ็งฐ๏ผˆๅ‡ฝๆ•ฐๅ๏ผ‰ใ€‚ + +็„ถๅŽ๏ผŒไฝ ๅฏไปฅๅฐ†่ฟ™ไธช่‡ชๅฎšไน‰ๅ‡ฝๆ•ฐไฝœไธบ `generate_unique_id_function` ๅ‚ๆ•ฐไผ ้€’็ป™ **FastAPI**: + +=== "Python 3.9+" + + ```Python hl_lines="6-7 10" + {!> ../../../docs_src/generate_clients/tutorial003_py39.py!} + ``` + +=== "Python 3.8+" + + ```Python hl_lines="8-9 12" + {!> ../../../docs_src/generate_clients/tutorial003.py!} + ``` + +### ไฝฟ็”จ่‡ชๅฎšไน‰ๆ“ไฝœID็”ŸๆˆTypeScriptๅฎขๆˆท็ซฏ + +็Žฐๅœจ๏ผŒๅฆ‚ๆžœไฝ ๅ†ๆฌก็”Ÿๆˆๅฎขๆˆท็ซฏ๏ผŒไฝ ไผšๅ‘็Žฐๅฎƒๅ…ทๆœ‰ๆ”นๅ–„็š„ๆ–นๆณ•ๅ็งฐ๏ผš + + + +ๆญฃๅฆ‚ไฝ ๆ‰€่ง๏ผŒ็Žฐๅœจๆ–นๆณ•ๅ็งฐไธญๅชๅŒ…ๅซๆ ‡็ญพๅ’Œๅ‡ฝๆ•ฐๅ๏ผŒไธๅ†ๅŒ…ๅซURL่ทฏๅพ„ๅ’ŒHTTPๆ“ไฝœ็š„ไฟกๆฏใ€‚ + +### ้ข„ๅค„็†็”จไบŽๅฎขๆˆท็ซฏ็”Ÿๆˆๅ™จ็š„OpenAPI่ง„่Œƒ + +็”Ÿๆˆ็š„ไปฃ็ ไป็„ถๅญ˜ๅœจไธ€ไบ›**้‡ๅค็š„ไฟกๆฏ**ใ€‚ + +ๆˆ‘ไปฌๅทฒ็ป็Ÿฅ้“่ฏฅๆ–นๆณ•ไธŽ **items** ็›ธๅ…ณ๏ผŒๅ› ไธบๅฎƒๅœจ `ItemsService` ไธญ๏ผˆไปŽๆ ‡็ญพไธญ่Žทๅ–๏ผ‰๏ผŒไฝ†ๆ–นๆณ•ๅไธญไป็„ถๆœ‰ๆ ‡็ญพๅไฝœไธบๅ‰็ผ€ใ€‚๐Ÿ˜• + +ไธ€่ˆฌๆƒ…ๅ†ตไธ‹ๅฏนไบŽOpenAPI๏ผŒๆˆ‘ไปฌๅฏ่ƒฝไป็„ถๅธŒๆœ›ไฟ็•™ๅฎƒ๏ผŒๅ› ไธบ่ฟ™ๅฐ†็กฎไฟๆ“ไฝœIDๆ˜ฏ**ๅ”ฏไธ€็š„**ใ€‚ + +ไฝ†ๅฏนไบŽ็”Ÿๆˆ็š„ๅฎขๆˆท็ซฏ๏ผŒๆˆ‘ไปฌๅฏไปฅๅœจ็”Ÿๆˆๅฎขๆˆท็ซฏไน‹ๅ‰**ไฟฎๆ”น** OpenAPI ๆ“ไฝœID๏ผŒไปฅไฝฟๆ–นๆณ•ๅ็งฐๆ›ดๅŠ ็พŽ่ง‚ๅ’Œ**็ฎ€ๆด**ใ€‚ + +ๆˆ‘ไปฌๅฏไปฅๅฐ† OpenAPI JSON ไธ‹่ฝฝๅˆฐไธ€ไธชๅไธบ`openapi.json`็š„ๆ–‡ไปถไธญ๏ผŒ็„ถๅŽไฝฟ็”จไปฅไธ‹่„šๆœฌ**ๅˆ ้™คๆญคๅ‰็ผ€็š„ๆ ‡็ญพ**๏ผš + +```Python +{!../../../docs_src/generate_clients/tutorial004.py!} +``` + +้€š่ฟ‡่ฟ™ๆ ทๅš๏ผŒๆ“ไฝœIDๅฐ†ไปŽ็ฑปไผผไบŽ `items-get_items` ็š„ๅ็งฐ้‡ๅ‘ฝๅไธบ `get_items` ๏ผŒ่ฟ™ๆ ทๅฎขๆˆท็ซฏ็”Ÿๆˆๅ™จๅฐฑๅฏไปฅ็”Ÿๆˆๆ›ด็ฎ€ๆด็š„ๆ–นๆณ•ๅ็งฐใ€‚ + +### ไฝฟ็”จ้ข„ๅค„็†็š„OpenAPI็”ŸๆˆTypeScriptๅฎขๆˆท็ซฏ + +็Žฐๅœจ๏ผŒ็”ฑไบŽๆœ€็ปˆ็ป“ๆžœไฟๅญ˜ๅœจๆ–‡ไปถopenapi.jsonไธญ๏ผŒไฝ ๅฏไปฅไฟฎๆ”น package.json ๆ–‡ไปถไปฅไฝฟ็”จๆญคๆœฌๅœฐๆ–‡ไปถ๏ผŒไพ‹ๅฆ‚๏ผš + +```JSON hl_lines="7" +{ + "name": "frontend-app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "generate-client": "openapi --input ./openapi.json --output ./src/client --client axios" + }, + "author": "", + "license": "", + "devDependencies": { + "openapi-typescript-codegen": "^0.20.1", + "typescript": "^4.6.2" + } +} +``` + +็”Ÿๆˆๆ–ฐ็š„ๅฎขๆˆท็ซฏไน‹ๅŽ๏ผŒไฝ ็Žฐๅœจๅฐ†ๆ‹ฅๆœ‰**ๆธ…ๆ™ฐ็š„ๆ–นๆณ•ๅ็งฐ**๏ผŒๅ…ทๅค‡**่‡ชๅŠจ่กฅๅ…จ**ใ€**้”™่ฏฏๆ็คบ**็ญ‰ๅŠŸ่ƒฝ๏ผš + + + +## ไผ˜็‚น + +ๅฝ“ไฝฟ็”จ่‡ชๅŠจ็”Ÿๆˆ็š„ๅฎขๆˆท็ซฏๆ—ถ๏ผŒไฝ ๅฐ†่Žทๅพ—ไปฅไธ‹็š„่‡ชๅŠจ่กฅๅ…จๅŠŸ่ƒฝ๏ผš + +* ๆ–นๆณ•ใ€‚ +* ่ฏทๆฑ‚ไฝ“ไธญ็š„ๆ•ฐๆฎใ€ๆŸฅ่ฏขๅ‚ๆ•ฐ็ญ‰ใ€‚ +* ๅ“ๅบ”ๆ•ฐๆฎใ€‚ + +ไฝ ่ฟ˜ๅฐ†่Žทๅพ—้’ˆๅฏนๆ‰€ๆœ‰ๅ†…ๅฎน็š„้”™่ฏฏๆ็คบใ€‚ + +ๆฏๅฝ“ไฝ ๆ›ดๆ–ฐๅŽ็ซฏไปฃ็ ๅนถ**้‡ๆ–ฐ็”Ÿๆˆ**ๅ‰็ซฏไปฃ็ ๆ—ถ๏ผŒๆ–ฐ็š„*่ทฏๅพ„ๆ“ไฝœ*ๅฐ†ไฝœไธบๆ–นๆณ•ๅฏ็”จ๏ผŒๆ—ง็š„ๆ–นๆณ•ๅฐ†่ขซๅˆ ้™ค๏ผŒๅนถไธ”ๅ…ถไป–ไปปไฝ•ๆ›ดๆ”นๅฐ†ๅๆ˜ ๅœจ็”Ÿๆˆ็š„ไปฃ็ ไธญใ€‚ ๐Ÿค“ + +่ฟ™ไนŸๆ„ๅ‘ณ็€ๅฆ‚ๆžœๆœ‰ไปปไฝ•ๆ›ดๆ”น๏ผŒๅฎƒๅฐ†่‡ชๅŠจ**ๅๆ˜ **ๅœจๅฎขๆˆท็ซฏไปฃ็ ไธญใ€‚ๅฆ‚ๆžœไฝ **ๆž„ๅปบ**ๅฎขๆˆท็ซฏ๏ผŒๅœจไฝฟ็”จ็š„ๆ•ฐๆฎไธŠๅญ˜ๅœจ**ไธๅŒน้…**ๆ—ถ๏ผŒๅฎƒๅฐ†ๆŠฅ้”™ใ€‚ + +ๅ› ๆญค๏ผŒไฝ ๅฐ†ๅœจๅผ€ๅ‘ๅ‘จๆœŸ็š„ๆ—ฉๆœŸ**ๆฃ€ๆต‹ๅˆฐ่ฎธๅคš้”™่ฏฏ**๏ผŒ่€Œไธๅฟ…็ญ‰ๅพ…้”™่ฏฏๅœจ็”Ÿไบง็Žฏๅขƒไธญๅ‘ๆœ€็ปˆ็”จๆˆทๅฑ•็คบ๏ผŒ็„ถๅŽๅฐ่ฏ•่ฐƒ่ฏ•้—ฎ้ข˜ๆ‰€ๅœจใ€‚ โœจ diff --git a/docs/zh/docs/advanced/settings.md b/docs/zh/docs/advanced/settings.md index 597e99a77..76070fb7f 100644 --- a/docs/zh/docs/advanced/settings.md +++ b/docs/zh/docs/advanced/settings.md @@ -223,13 +223,13 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app {!> ../../../docs_src/settings/app02_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="6 12-13" {!> ../../../docs_src/settings/app02_an/main.py!} ``` -=== "Python 3.6+ ้žๆณจ่งฃ็‰ˆๆœฌ" +=== "Python 3.8+ ้žๆณจ่งฃ็‰ˆๆœฌ" !!! tip ๅฆ‚ๆžœๅฏ่ƒฝ๏ผŒ่ฏทๅฐฝ้‡ไฝฟ็”จ `Annotated` ็‰ˆๆœฌใ€‚ @@ -239,7 +239,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app ``` !!! tip - ๆˆ‘ไปฌ็จๅŽไผš่ฎจ่ฎบ `@lru_cache()`ใ€‚ + ๆˆ‘ไปฌ็จๅŽไผš่ฎจ่ฎบ `@lru_cache`ใ€‚ ็›ฎๅ‰๏ผŒๆ‚จๅฏไปฅๅฐ† `get_settings()` ่ง†ไธบๆ™ฎ้€šๅ‡ฝๆ•ฐใ€‚ @@ -251,13 +251,13 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app {!> ../../../docs_src/settings/app02_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17 19-21" {!> ../../../docs_src/settings/app02_an/main.py!} ``` -=== "Python 3.6+ ้žๆณจ่งฃ็‰ˆๆœฌ" +=== "Python 3.8+ ้žๆณจ่งฃ็‰ˆๆœฌ" !!! tip ๅฆ‚ๆžœๅฏ่ƒฝ๏ผŒ่ฏทๅฐฝ้‡ไฝฟ็”จ `Annotated` ็‰ˆๆœฌใ€‚ @@ -289,7 +289,7 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp"uvicorn main:app ไฝ†ๆ˜ฏ๏ผŒdotenv ๆ–‡ไปถๅฎž้™…ไธŠไธไธ€ๅฎš่ฆๅ…ทๆœ‰็กฎๅˆ‡็š„ๆ–‡ไปถๅใ€‚ -Pydantic ๆ”ฏๆŒไฝฟ็”จๅค–้ƒจๅบ“ไปŽ่ฟ™ไบ›็ฑปๅž‹็š„ๆ–‡ไปถไธญ่ฏปๅ–ใ€‚ๆ‚จๅฏไปฅๅœจPydantic ่ฎพ็ฝฎ: Dotenv (.env) ๆ”ฏๆŒไธญ้˜…่ฏปๆ›ดๅคš็›ธๅ…ณไฟกๆฏใ€‚ +Pydantic ๆ”ฏๆŒไฝฟ็”จๅค–้ƒจๅบ“ไปŽ่ฟ™ไบ›็ฑปๅž‹็š„ๆ–‡ไปถไธญ่ฏปๅ–ใ€‚ๆ‚จๅฏไปฅๅœจPydantic ่ฎพ็ฝฎ: Dotenv (.env) ๆ”ฏๆŒไธญ้˜…่ฏปๆ›ดๅคš็›ธๅ…ณไฟกๆฏใ€‚ !!! tip ่ฆไฝฟๅ…ถๅทฅไฝœ๏ผŒๆ‚จ้œ€่ฆๆ‰ง่กŒ `pip install python-dotenv`ใ€‚ @@ -337,7 +337,7 @@ def get_settings(): ๆˆ‘ไปฌๅฐ†ไธบๆฏไธช่ฏทๆฑ‚ๅˆ›ๅปบ่ฏฅๅฏน่ฑก๏ผŒๅนถไธ”ๅฐ†ๅœจๆฏไธช่ฏทๆฑ‚ไธญ่ฏปๅ– `.env` ๆ–‡ไปถใ€‚ โš ๏ธ -ไฝ†ๆ˜ฏ๏ผŒ็”ฑไบŽๆˆ‘ไปฌๅœจ้กถ้ƒจไฝฟ็”จไบ† `@lru_cache()` ่ฃ…้ฅฐๅ™จ๏ผŒๅ› ๆญคๅชๆœ‰ๅœจ็ฌฌไธ€ๆฌก่ฐƒ็”จๅฎƒๆ—ถ๏ผŒๆ‰ไผšๅˆ›ๅปบ `Settings` ๅฏน่ฑกไธ€ๆฌกใ€‚ โœ”๏ธ +ไฝ†ๆ˜ฏ๏ผŒ็”ฑไบŽๆˆ‘ไปฌๅœจ้กถ้ƒจไฝฟ็”จไบ† `@lru_cache` ่ฃ…้ฅฐๅ™จ๏ผŒๅ› ๆญคๅชๆœ‰ๅœจ็ฌฌไธ€ๆฌก่ฐƒ็”จๅฎƒๆ—ถ๏ผŒๆ‰ไผšๅˆ›ๅปบ `Settings` ๅฏน่ฑกไธ€ๆฌกใ€‚ โœ”๏ธ === "Python 3.9+" @@ -345,13 +345,13 @@ def get_settings(): {!> ../../../docs_src/settings/app03_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 11" {!> ../../../docs_src/settings/app03_an/main.py!} ``` -=== "Python 3.6+ ้žๆณจ่งฃ็‰ˆๆœฌ" +=== "Python 3.8+ ้žๆณจ่งฃ็‰ˆๆœฌ" !!! tip ๅฆ‚ๆžœๅฏ่ƒฝ๏ผŒ่ฏทๅฐฝ้‡ไฝฟ็”จ `Annotated` ็‰ˆๆœฌใ€‚ @@ -364,13 +364,13 @@ def get_settings(): #### `lru_cache` ๆŠ€ๆœฏ็ป†่Š‚ -`@lru_cache()` ไฟฎๆ”นไบ†ๅฎƒๆ‰€่ฃ…้ฅฐ็š„ๅ‡ฝๆ•ฐ๏ผŒไปฅ่ฟ”ๅ›ž็ฌฌไธ€ๆฌก่ฟ”ๅ›ž็š„็›ธๅŒๅ€ผ๏ผŒ่€Œไธๆ˜ฏๅ†ๆฌก่ฎก็ฎ—ๅฎƒ๏ผŒๆฏๆฌก้ƒฝๆ‰ง่กŒๅ‡ฝๆ•ฐ็š„ไปฃ็ ใ€‚ +`@lru_cache` ไฟฎๆ”นไบ†ๅฎƒๆ‰€่ฃ…้ฅฐ็š„ๅ‡ฝๆ•ฐ๏ผŒไปฅ่ฟ”ๅ›ž็ฌฌไธ€ๆฌก่ฟ”ๅ›ž็š„็›ธๅŒๅ€ผ๏ผŒ่€Œไธๆ˜ฏๅ†ๆฌก่ฎก็ฎ—ๅฎƒ๏ผŒๆฏๆฌก้ƒฝๆ‰ง่กŒๅ‡ฝๆ•ฐ็š„ไปฃ็ ใ€‚ ๅ› ๆญค๏ผŒไธ‹้ข็š„ๅ‡ฝๆ•ฐๅฐ†ๅฏนๆฏไธชๅ‚ๆ•ฐ็ป„ๅˆๆ‰ง่กŒไธ€ๆฌกใ€‚็„ถๅŽ๏ผŒๆฏไธชๅ‚ๆ•ฐ็ป„ๅˆ่ฟ”ๅ›ž็š„ๅ€ผๅฐ†ๅœจไฝฟ็”จๅฎŒๅ…จ็›ธๅŒ็š„ๅ‚ๆ•ฐ็ป„ๅˆ่ฐƒ็”จๅ‡ฝๆ•ฐๆ—ถๅ†ๆฌกไฝฟ็”จใ€‚ ไพ‹ๅฆ‚๏ผŒๅฆ‚ๆžœๆ‚จๆœ‰ไธ€ไธชๅ‡ฝๆ•ฐ๏ผš ```Python -@lru_cache() +@lru_cache def say_hi(name: str, salutation: str = "Ms."): return f"Hello {salutation} {name}" ``` @@ -422,7 +422,7 @@ participant execute as Execute function ่ฟ™ๆ ท๏ผŒๅฎƒ็š„่กŒไธบๅ‡ ไนŽๅฐฑๅƒๆ˜ฏไธ€ไธชๅ…จๅฑ€ๅ˜้‡ใ€‚ไฝ†ๆ˜ฏ็”ฑไบŽๅฎƒไฝฟ็”จไบ†ไพ่ต–้กนๅ‡ฝๆ•ฐ๏ผŒๅ› ๆญคๆˆ‘ไปฌๅฏไปฅ่ฝปๆพๅœฐ่ฟ›่กŒๆต‹่ฏ•ๆ—ถ็š„่ฆ†็›–ใ€‚ -`@lru_cache()` ๆ˜ฏ `functools` ็š„ไธ€้ƒจๅˆ†๏ผŒๅฎƒๆ˜ฏ Python ๆ ‡ๅ‡†ๅบ“็š„ไธ€้ƒจๅˆ†๏ผŒๆ‚จๅฏไปฅๅœจPython ๆ–‡ๆกฃไธญไบ†่งฃๆœ‰ๅ…ณ `@lru_cache()` ็š„ๆ›ดๅคšไฟกๆฏใ€‚ +`@lru_cache` ๆ˜ฏ `functools` ็š„ไธ€้ƒจๅˆ†๏ผŒๅฎƒๆ˜ฏ Python ๆ ‡ๅ‡†ๅบ“็š„ไธ€้ƒจๅˆ†๏ผŒๆ‚จๅฏไปฅๅœจPython ๆ–‡ๆกฃไธญไบ†่งฃๆœ‰ๅ…ณ `@lru_cache` ็š„ๆ›ดๅคšไฟกๆฏใ€‚ ## ๅฐ็ป“ @@ -430,4 +430,4 @@ participant execute as Execute function * ้€š่ฟ‡ไฝฟ็”จไพ่ต–้กน๏ผŒๆ‚จๅฏไปฅ็ฎ€ๅŒ–ๆต‹่ฏ•ใ€‚ * ๆ‚จๅฏไปฅไฝฟ็”จ `.env` ๆ–‡ไปถใ€‚ -* ไฝฟ็”จ `@lru_cache()` ๅฏไปฅ้ฟๅ…ไธบๆฏไธช่ฏทๆฑ‚้‡ๅค่ฏปๅ– dotenv ๆ–‡ไปถ๏ผŒๅŒๆ—ถๅ…่ฎธๆ‚จๅœจๆต‹่ฏ•ๆ—ถ่ฟ›่กŒ่ฆ†็›–ใ€‚ +* ไฝฟ็”จ `@lru_cache` ๅฏไปฅ้ฟๅ…ไธบๆฏไธช่ฏทๆฑ‚้‡ๅค่ฏปๅ– dotenv ๆ–‡ไปถ๏ผŒๅŒๆ—ถๅ…่ฎธๆ‚จๅœจๆต‹่ฏ•ๆ—ถ่ฟ›่กŒ่ฆ†็›–ใ€‚ diff --git a/docs/zh/docs/advanced/websockets.md b/docs/zh/docs/advanced/websockets.md index a723487fd..a5cbdd965 100644 --- a/docs/zh/docs/advanced/websockets.md +++ b/docs/zh/docs/advanced/websockets.md @@ -118,7 +118,7 @@ $ uvicorn main:app --reload {!> ../../../docs_src/websockets/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="69-70 83" {!> ../../../docs_src/websockets/tutorial002_an.py!} @@ -133,7 +133,7 @@ $ uvicorn main:app --reload {!> ../../../docs_src/websockets/tutorial002_py310.py!} ``` -=== "Python 3.6+ ้žๅธฆๆณจ่งฃ็‰ˆๆœฌ" +=== "Python 3.8+ ้žๅธฆๆณจ่งฃ็‰ˆๆœฌ" !!! tip ๅฆ‚ๆžœๅฏ่ƒฝ๏ผŒ่ฏทๅฐฝ้‡ไฝฟ็”จ `Annotated` ็‰ˆๆœฌใ€‚ @@ -181,7 +181,7 @@ $ uvicorn main:app --reload {!> ../../../docs_src/websockets/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="81-83" {!> ../../../docs_src/websockets/tutorial003.py!} diff --git a/docs/zh/docs/async.md b/docs/zh/docs/async.md new file mode 100644 index 000000000..59eebd049 --- /dev/null +++ b/docs/zh/docs/async.md @@ -0,0 +1,430 @@ +# ๅนถๅ‘ async / await + +ๆœ‰ๅ…ณ่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ็š„ `async def` ่ฏญๆณ•ไปฅๅŠๅผ‚ๆญฅไปฃ็ ใ€ๅนถๅ‘ๅ’Œๅนถ่กŒ็š„ไธ€ไบ›่ƒŒๆ™ฏ็Ÿฅ่ฏ†ใ€‚ + +## ่ตถๆ—ถ้—ดๅ—๏ผŸ + +TL;DR: + +ๅฆ‚ๆžœไฝ ๆญฃๅœจไฝฟ็”จ็ฌฌไธ‰ๆ–นๅบ“๏ผŒๅฎƒไปฌไผšๅ‘Š่ฏ‰ไฝ ไฝฟ็”จ `await` ๅ…ณ้”ฎๅญ—ๆฅ่ฐƒ็”จๅฎƒไปฌ๏ผŒๅฐฑๅƒ่ฟ™ๆ ท๏ผš + +```Python +results = await some_library() +``` + +็„ถๅŽ๏ผŒ้€š่ฟ‡ `async def` ๅฃฐๆ˜Žไฝ ็š„ *่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ*๏ผš + +```Python hl_lines="2" +@app.get('/') +async def read_results(): + results = await some_library() + return results +``` + +!!! note + ไฝ ๅช่ƒฝๅœจ่ขซ `async def` ๅˆ›ๅปบ็š„ๅ‡ฝๆ•ฐๅ†…ไฝฟ็”จ `await` + +--- + +ๅฆ‚ๆžœไฝ ๆญฃๅœจไฝฟ็”จไธ€ไธช็ฌฌไธ‰ๆ–นๅบ“ๅ’ŒๆŸไบ›็ป„ไปถ๏ผˆๆฏ”ๅฆ‚๏ผšๆ•ฐๆฎๅบ“ใ€APIใ€ๆ–‡ไปถ็ณป็ปŸ...๏ผ‰่ฟ›่กŒ้€šไฟก๏ผŒ็ฌฌไธ‰ๆ–นๅบ“ๅˆไธๆ”ฏๆŒไฝฟ็”จ `await` ๏ผˆ็›ฎๅ‰ๅคงๅคšๆ•ฐๆ•ฐๆฎๅบ“ไธ‰ๆ–นๅบ“้ƒฝๆ˜ฏ่ฟ™ๆ ท๏ผ‰๏ผŒ่ฟ™็งๆƒ…ๅ†ตไฝ ๅฏไปฅๅƒๅนณๅธธ้‚ฃๆ ทไฝฟ็”จ `def` ๅฃฐๆ˜Žไธ€ไธช่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ๏ผŒๅฐฑๅƒ่ฟ™ๆ ท๏ผš + +```Python hl_lines="2" +@app.get('/') +def results(): + results = some_library() + return results +``` + +--- + +ๅฆ‚ๆžœไฝ ็š„ๅบ”็”จ็จ‹ๅบไธ้œ€่ฆไธŽๅ…ถไป–ไปปไฝ•ไธœ่ฅฟ้€šไฟก่€Œ็ญ‰ๅพ…ๅ…ถๅ“ๅบ”๏ผŒ่ฏทไฝฟ็”จ `async def`ใ€‚ + +--- + +ๅฆ‚ๆžœไฝ ไธๆธ…ๆฅš๏ผŒไฝฟ็”จ `def` ๅฐฑๅฅฝ. + +--- + +**ๆณจๆ„**๏ผšไฝ ๅฏไปฅๆ นๆฎ้œ€่ฆๅœจ่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐไธญๆททๅˆไฝฟ็”จ `def` ๅ’Œ `async def`๏ผŒๅนถไฝฟ็”จๆœ€้€‚ๅˆไฝ ็š„ๆ–นๅผๅŽปๅฎšไน‰ๆฏไธชๅ‡ฝๆ•ฐใ€‚FastAPI ๅฐ†ไธบไป–ไปฌๅšๆญฃ็กฎ็š„ไบ‹ๆƒ…ใ€‚ + +ๆ— ่ฎบๅฆ‚ไฝ•๏ผŒๅœจไธŠ่ฟฐไปปไฝ•ๆƒ…ๅ†ตไธ‹๏ผŒFastAPI ไปๅฐ†ๅผ‚ๆญฅๅทฅไฝœ๏ผŒ้€ŸๅบฆไนŸ้žๅธธๅฟซใ€‚ + +ไฝ†ๆ˜ฏ๏ผŒ้€š่ฟ‡้ตๅพชไธŠ่ฟฐๆญฅ้ชค๏ผŒๅฎƒๅฐ†่ƒฝๅคŸ่ฟ›่กŒไธ€ไบ›ๆ€ง่ƒฝไผ˜ๅŒ–ใ€‚ + +## ๆŠ€ๆœฏ็ป†่Š‚ + +Python ็š„็Žฐไปฃ็‰ˆๆœฌๆ”ฏๆŒ้€š่ฟ‡ไธ€็งๅซ**"ๅ็จ‹"**โ€”โ€”ไฝฟ็”จ `async` ๅ’Œ `await` ่ฏญๆณ•็š„ไธœ่ฅฟๆฅๅ†™**โ€ๅผ‚ๆญฅไปฃ็ โ€œ**ใ€‚ + +่ฎฉๆˆ‘ไปฌๅœจไธ‹้ข็š„้ƒจๅˆ†ไธญ้€ไธ€ไป‹็ป๏ผš + +* **ๅผ‚ๆญฅไปฃ็ ** +* **`async` ๅ’Œ `await`** +* **ๅ็จ‹** + +## ๅผ‚ๆญฅไปฃ็  + +ๅผ‚ๆญฅไปฃ็ ไป…ไป…ๆ„ๅ‘ณ็€็ผ–็จ‹่ฏญ่จ€ ๐Ÿ’ฌ ๆœ‰ๅŠžๆณ•ๅ‘Š่ฏ‰่ฎก็ฎ—ๆœบ/็จ‹ๅบ ๐Ÿค– ๅœจไปฃ็ ไธญ็š„ๆŸไธช็‚น๏ผŒๅฎƒ ๐Ÿค– ๅฐ†ไธๅพ—ไธ็ญ‰ๅพ…ๅœจๆŸไบ›ๅœฐๆ–นๅฎŒๆˆไธ€ไบ›ไบ‹ๆƒ…ใ€‚่ฎฉๆˆ‘ไปฌๅ‡่ฎพไธ€ไบ›ไบ‹ๆƒ…่ขซ็งฐไธบ "ๆ…ขๆ–‡ไปถ"๐Ÿ“. + +ๆ‰€ไปฅ๏ผŒๅœจ็ญ‰ๅพ…"ๆ…ขๆ–‡ไปถ"๐Ÿ“ๅฎŒๆˆ็š„่ฟ™ๆฎตๆ—ถ้—ด๏ผŒ่ฎก็ฎ—ๆœบๅฏไปฅๅšไธ€ไบ›ๅ…ถไป–ๅทฅไฝœใ€‚ + +็„ถๅŽ่ฎก็ฎ—ๆœบ/็จ‹ๅบ ๐Ÿค– ๆฏๆฌกๆœ‰ๆœบไผš้ƒฝไผšๅ›žๆฅ๏ผŒๅ› ไธบๅฎƒๅˆๅœจ็ญ‰ๅพ…๏ผŒๆˆ–่€…ๅฎƒ ๐Ÿค– ๅฎŒๆˆไบ†ๅฝ“ๅ‰ๆ‰€ๆœ‰็š„ๅทฅไฝœใ€‚่€Œไธ”ๅฎƒ ๐Ÿค– ๅฐ†ๆŸฅ็œ‹ๅฎƒ็ญ‰ๅพ…็š„ๆ‰€ๆœ‰ไปปๅŠกไธญๆ˜ฏๅฆๆœ‰ๅทฒ็ปๅฎŒๆˆ็š„๏ผŒๅšๅฎƒๅฟ…้กปๅš็š„ไปปไฝ•ไบ‹ๆƒ…ใ€‚ + +ๆŽฅไธ‹ๆฅ๏ผŒๅฎƒ ๐Ÿค– ๅฎŒๆˆ็ฌฌไธ€ไธชไปปๅŠก๏ผˆๆฏ”ๅฆ‚ๆ˜ฏๆˆ‘ไปฌ็š„"ๆ…ขๆ–‡ไปถ"๐Ÿ“) ๅนถ็ปง็ปญไธŽไน‹็›ธๅ…ณ็š„ไธ€ๅˆ‡ใ€‚ + +่ฟ™ไธช"็ญ‰ๅพ…ๅ…ถไป–ไบ‹ๆƒ…"้€šๅธธๆŒ‡็š„ๆ˜ฏไธ€ไบ›็›ธๅฏน่พƒๆ…ข๏ผˆไธŽๅค„็†ๅ™จๅ’Œ RAM ๅญ˜ๅ‚จๅ™จ็š„้€Ÿๅบฆ็›ธๆฏ”๏ผ‰็š„ I/O ๆ“ไฝœ๏ผŒๆฏ”ๅฆ‚่ฏด๏ผš + +* ้€š่ฟ‡็ฝ‘็ปœๅ‘้€ๆฅ่‡ชๅฎขๆˆท็ซฏ็š„ๆ•ฐๆฎ +* ๅฎขๆˆท็ซฏๆŽฅๆ”ถๆฅ่‡ช็ฝ‘็ปœไธญ็š„ๆ•ฐๆฎ +* ็ฃ็›˜ไธญ่ฆ็”ฑ็ณป็ปŸ่ฏปๅ–ๅนถๆไพ›็ป™็จ‹ๅบ็š„ๆ–‡ไปถ็š„ๅ†…ๅฎน +* ็จ‹ๅบๆไพ›็ป™็ณป็ปŸ็š„่ฆๅ†™ๅ…ฅ็ฃ็›˜็š„ๅ†…ๅฎน +* ไธ€ไธช API ็š„่ฟœ็จ‹่ฐƒ็”จ +* ไธ€ไธชๆ•ฐๆฎๅบ“ๆ“ไฝœ๏ผŒ็›ดๅˆฐๅฎŒๆˆ +* ไธ€ไธชๆ•ฐๆฎๅบ“ๆŸฅ่ฏข๏ผŒ็›ดๅˆฐ่ฟ”ๅ›ž็ป“ๆžœ +* ็ญ‰็ญ‰. + +่ฟ™ไธชๆ‰ง่กŒ็š„ๆ—ถ้—ดๅคงๅคšๆ˜ฏๅœจ็ญ‰ๅพ… I/O ๆ“ไฝœ๏ผŒๅ› ๆญคๅฎƒไปฌ่ขซๅซๅš "I/O ๅฏ†้›†ๅž‹" ๆ“ไฝœใ€‚ + +ๅฎƒ่ขซ็งฐไธบ"ๅผ‚ๆญฅ"็š„ๅŽŸๅ› ๆ˜ฏๅ› ไธบ่ฎก็ฎ—ๆœบ/็จ‹ๅบไธๅฟ…ไธŽๆ…ขไปปๅŠก"ๅŒๆญฅ"๏ผŒๅŽป็ญ‰ๅพ…ไปปๅŠกๅฎŒๆˆ็š„็กฎๅˆ‡ๆ—ถๅˆป๏ผŒ่€ŒๅœจๆญคๆœŸ้—ดไธๅšไปปไฝ•ไบ‹ๆƒ…็›ดๅˆฐ่ƒฝๅคŸ่Žทๅ–ไปปๅŠก็ป“ๆžœๆ‰็ปง็ปญๅทฅไฝœใ€‚ + +็›ธๅ๏ผŒไฝœไธบไธ€ไธช"ๅผ‚ๆญฅ"็ณป็ปŸ๏ผŒไธ€ๆ—ฆๅฎŒๆˆ๏ผŒไปปๅŠกๅฐฑๅฏไปฅๆŽ’้˜Ÿ็ญ‰ๅพ…ไธ€ๆฎตๆ—ถ้—ด๏ผˆๅ‡ ๅพฎ็ง’๏ผ‰๏ผŒ็ญ‰ๅพ…่ฎก็ฎ—ๆœบ็จ‹ๅบๅฎŒๆˆๅฎƒ่ฆๅš็š„ไปปไฝ•ไบ‹ๆƒ…๏ผŒ็„ถๅŽๅ›žๆฅ่Žทๅ–็ป“ๆžœๅนถ็ปง็ปญๅค„็†ๅฎƒไปฌใ€‚ + +ๅฏนไบŽ"ๅŒๆญฅ"๏ผˆไธŽ"ๅผ‚ๆญฅ"็›ธๅ๏ผ‰๏ผŒไป–ไปฌ้€šๅธธไนŸไฝฟ็”จ"้กบๅบ"ไธ€่ฏ๏ผŒๅ› ไธบ่ฎก็ฎ—ๆœบ็จ‹ๅบๅœจๅˆ‡ๆขๅˆฐๅฆไธ€ไธชไปปๅŠกไน‹ๅ‰ๆ˜ฏๆŒ‰้กบๅบๆ‰ง่กŒๆ‰€ๆœ‰ๆญฅ้ชค๏ผŒๅณไฝฟ่ฟ™ไบ›ๆญฅ้ชคๆถ‰ๅŠๅˆฐ็ญ‰ๅพ…ใ€‚ + +### ๅนถๅ‘ไธŽๆฑ‰ๅ ก + +ไธŠ่ฟฐๅผ‚ๆญฅไปฃ็ ็š„ๆ€ๆƒณๆœ‰ๆ—ถไนŸ่ขซ็งฐไธบโ€œๅนถๅ‘โ€๏ผŒๅฎƒไธๅŒไบŽโ€œๅนถ่กŒโ€ใ€‚ + +ๅนถๅ‘ๅ’Œๅนถ่กŒ้ƒฝไธŽโ€œไธๅŒ็š„ไบ‹ๆƒ…ๆˆ–ๅคšๆˆ–ๅฐ‘ๅŒๆ—ถๅ‘็”Ÿโ€ๆœ‰ๅ…ณใ€‚ + +ไฝ†ๆ˜ฏๅนถๅ‘ๅ’Œๅนถ่กŒไน‹้—ด็š„็ป†่Š‚ๆ˜ฏๅฎŒๅ…จไธๅŒ็š„ใ€‚ + +่ฆไบ†่งฃๅทฎๅผ‚๏ผŒ่ฏทๆƒณ่ฑกไปฅไธ‹ๅ…ณไบŽๆฑ‰ๅ ก็š„ๆ•…ไบ‹๏ผš + +### ๅนถๅ‘ๆฑ‰ๅ ก + +ไฝ ๅ’Œไฝ ็š„ๆ‹ไบบไธ€่ตทๅŽปๅฟซ้คๅบ—๏ผŒไฝ ๆŽ’้˜ŸๅœจๅŽ้ข๏ผŒๆ”ถ้“ถๅ‘˜ไปŽไฝ ๅ‰้ข็š„ไบบๆŽฅๅ•ใ€‚๐Ÿ˜ + + + +็„ถๅŽ่ฝฎๅˆฐไฝ ไบ†๏ผŒไฝ ไธบไฝ ็š„ๆ‹ไบบๅ’Œไฝ ้€‰ไบ†ไธคไธช้žๅธธ่ฑชๅŽ็š„ๆฑ‰ๅ กใ€‚๐Ÿ”๐Ÿ” + + + +ๆ”ถ้“ถๅ‘˜ๅฏนๅŽจๆˆฟ้‡Œ็š„ๅŽจๅธˆ่ฏดไบ†ไธ€ไบ›่ฏ๏ผŒ่ฎฉไป–ไปฌ็Ÿฅ้“ไป–ไปฌๅฟ…้กปไธบไฝ ๅ‡†ๅค‡ๆฑ‰ๅ ก๏ผˆๅฐฝ็ฎกไป–ไปฌ็›ฎๅ‰ๆญฃๅœจไธบไน‹ๅ‰็š„้กพๅฎขๅ‡†ๅค‡ๆฑ‰ๅ ก๏ผ‰ใ€‚ + + + +ไฝ ไป˜้’ฑไบ†ใ€‚ ๐Ÿ’ธ + +ๆ”ถ้“ถๅ‘˜็ป™ไฝ ่ฝฎๅˆฐ็š„ๅท็ ใ€‚ + + + +ๅฝ“ไฝ ๅœจ็ญ‰ๅพ…็š„ๆ—ถๅ€™๏ผŒไฝ ๅ’Œไฝ ็š„ๆ‹ไบบไธ€่ตทๅŽปๆŒ‘้€‰ไธ€ๅผ ๆกŒๅญ๏ผŒ็„ถๅŽไฝ ไปฌๅไธ‹ๆฅ่Šไบ†ๅพˆ้•ฟๆ—ถ้—ด๏ผˆๅ› ไธบๆฑ‰ๅ กๅพˆ่ฑชๅŽ๏ผŒ้œ€่ฆไธ€ไบ›ๆ—ถ้—ดๆฅๅ‡†ๅค‡๏ผ‰ใ€‚ + +ๅฝ“ไฝ ๅ’Œไฝ ็š„ๆ‹ไบบๅๅœจๆกŒๅญๆ—๏ผŒ็ญ‰ๅพ…ๆฑ‰ๅ ก็š„ๆ—ถๅ€™๏ผŒไฝ ๅฏไปฅ็”จ่ฟ™ๆฎตๆ—ถ้—ดๆฅๆฌฃ่ตไฝ ็š„ๆ‹ไบบๆ˜ฏๅคšไนˆ็š„ๆฃ’ใ€ๅฏ็ˆฑๅ’Œ่ชๆ˜Žโœจ๐Ÿ˜โœจใ€‚ + + + +ๅœจ็ญ‰ๅพ…ไธญๅ’Œไฝ ็š„ๆ‹ไบบไบค่ฐˆๆ—ถ๏ผŒไฝ ไผšไธๆ—ถๅœฐๆŸฅ็œ‹ๆŸœๅฐไธŠๆ˜พ็คบ็š„ๅท็ ๏ผŒ็œ‹็œ‹ๆ˜ฏๅฆๅทฒ็ป่ฝฎๅˆฐไฝ ไบ†ใ€‚ + +็„ถๅŽๅœจๆŸไธชๆ—ถๅˆป๏ผŒ็ปˆไบŽ่ฝฎๅˆฐไฝ ไบ†ใ€‚ไฝ ๅŽปๆŸœๅฐๆ‹ฟๆฑ‰ๅ ก็„ถๅŽๅ›žๅˆฐๆกŒๅญไธŠใ€‚ + + + +ไฝ ไปฌไบซ็”จไบ†ๆฑ‰ๅ ก๏ผŒๆ•ดไธช่ฟ‡็จ‹้ƒฝๅพˆๅผ€ๅฟƒใ€‚โœจ + + + +!!! info + ๆผ‚ไบฎ็š„ๆ’็”ปๆฅ่‡ช Ketrina Thompson. ๐ŸŽจ + +--- + +ๅœจ้‚ฃไธชๆ•…ไบ‹้‡Œ๏ผŒๅ‡่ฎพไฝ ๆ˜ฏ่ฎก็ฎ—ๆœบ็จ‹ๅบ ๐Ÿค– ใ€‚ + +ๅฝ“ไฝ ๅœจๆŽ’้˜Ÿๆ—ถ๏ผŒไฝ ๅชๆ˜ฏ้—ฒ็€๐Ÿ˜ด๏ผŒ ่ฝฎๅˆฐไฝ ๅ‰ไธๅšไปปไฝ•ไบ‹ๆƒ…๏ผˆไป…ๆŽ’้˜Ÿ๏ผ‰ใ€‚ไฝ†ๆŽ’้˜Ÿๅพˆๅฟซ๏ผŒๅ› ไธบๆ”ถ้“ถๅ‘˜ๅชๆŽฅ่ฎขๅ•๏ผˆไธๅ‡†ๅค‡่ฎขๅ•๏ผ‰๏ผŒๆ‰€ไปฅ่ฟ™ไธ€ๅˆ‡้ƒฝ่ฟ˜ๅฅฝใ€‚ + +็„ถๅŽ๏ผŒๅฝ“่ฝฎๅˆฐไฝ ๆ—ถ๏ผŒ้œ€่ฆไฝ ๅšไธ€ไบ›ๅฎž้™…ๆ€ง็š„ๅทฅไฝœ๏ผŒๆฏ”ๅฆ‚ๆŸฅ็œ‹่œๅ•๏ผŒๅ†ณๅฎšไฝ ๆƒณ่ฆไป€ไนˆ๏ผŒ่ฎฉไฝ ็š„ๆ‹ไบบ้€‰ๆ‹ฉ๏ผŒๆ”ฏไป˜๏ผŒๆฃ€ๆŸฅไฝ ๆ˜ฏๅฆๆไพ›ไบ†ๆญฃ็กฎ็š„่ดฆๅ•ๆˆ–ๅก๏ผŒๆฃ€ๆŸฅไฝ ็š„ๆ”ถ่ดนๆ˜ฏๅฆๆญฃ็กฎ๏ผŒๆฃ€ๆŸฅ่ฎขๅ•ๆ˜ฏๅฆๆœ‰ๆญฃ็กฎ็š„้กน็›ฎ๏ผŒ็ญ‰็ญ‰ใ€‚ + +ๆญคๆ—ถ๏ผŒๅณไฝฟไฝ ไป็„ถๆฒกๆœ‰ๆฑ‰ๅ ก๏ผŒไฝ ๅ’Œๆ”ถ้“ถๅ‘˜็š„ๅทฅไฝœไนŸ"ๆš‚ๅœ"ไบ†โธ๏ผŒ ๅ› ไธบไฝ ๅฟ…้กป็ญ‰ๅพ…ไธ€ๆฎตๆ—ถ้—ด ๐Ÿ•™ ่ฎฉไฝ ็š„ๆฑ‰ๅ กๅšๅฅฝใ€‚ + +ไฝ†ๆ˜ฏ๏ผŒๅฝ“ไฝ ็ฆปๅผ€ๆŸœๅฐๅนถๅๅœจๆกŒๅญๆ—๏ผŒๅœจ่ฝฎๅˆฐไฝ ็š„ๅท็ ๅ‰็š„่ฟ™ๆฎตๆ—ถ้—ด๏ผŒไฝ ๅฏไปฅๅฐ†็„ฆ็‚นๅˆ‡ๆขๅˆฐ ๐Ÿ”€ ไฝ ็š„ๆ‹ไบบไธŠ๏ผŒๅนถๅšไธ€ไบ›"ๅทฅไฝœ"โฏ ๐Ÿค“ใ€‚ไฝ ๅฏไปฅๅšไธ€ไบ›้žๅธธ"ๆœ‰ๆˆๆ•ˆ"็š„ไบ‹ๆƒ…๏ผŒๆฏ”ๅฆ‚ๅ’Œไฝ ็š„ๆ‹ไบบ่ฐƒๆƒ…๐Ÿ˜. + +ไน‹ๅŽ๏ผŒๆ”ถ้“ถๅ‘˜ ๐Ÿ’ ๆŠŠๅท็ ๆ˜พ็คบๅœจๆ˜พ็คบๅฑไธŠ๏ผŒๅนถ่ฏดๅˆฐ "ๆฑ‰ๅ กๅšๅฅฝไบ†"๏ผŒ่€Œๅฝ“ๆ˜พ็คบ็š„ๅท็ ๆ˜ฏไฝ ็š„ๅท็ ๆ—ถ๏ผŒไฝ ไธไผš็ซ‹ๅˆป็–ฏ็‹‚ๅœฐ่ทณ่ตทๆฅใ€‚ๅ› ไธบไฝ ็Ÿฅ้“ๆฒกๆœ‰ไบบไผšๅทไฝ ็š„ๆฑ‰ๅ ก๏ผŒๅ› ไธบไฝ ๆœ‰ไฝ ็š„ๅท็ ๏ผŒ่€Œๅ…ถไป–ไบบๅˆๆœ‰ไป–ไปฌ่‡ชๅทฑ็š„ๅท็ ใ€‚ + +ๆ‰€ไปฅไฝ ่ฆ็ญ‰ๅพ…ไฝ ็š„ๆ‹ไบบๅฎŒๆˆๆ•…ไบ‹๏ผˆๅฎŒๆˆๅฝ“ๅ‰็š„ๅทฅไฝœโฏ /ๆญฃๅœจๅš็š„ไบ‹๐Ÿค“)๏ผŒ ่ฝป่ฝปๅพฎ็ฌ‘๏ผŒ่ฏดไฝ ่ฆๅƒๆฑ‰ๅ กโธ. + +็„ถๅŽไฝ ๅŽปๆŸœๅฐ๐Ÿ”€๏ผŒ ๅˆฐ็Žฐๅœจๅˆๅง‹ไปปๅŠกๅทฒ็ปๅฎŒๆˆโฏ๏ผŒ ๆ‹ฟ่ตทๆฑ‰ๅ ก๏ผŒ่ฏดๅฃฐ่ฐข่ฐข๏ผŒ็„ถๅŽๆŠŠๅฎƒไปฌ้€ๅˆฐๆกŒไธŠใ€‚่ฟ™ๅฐฑๅฎŒๆˆไบ†ไธŽ่ฎกๆ•ฐๅ™จไบคไบ’็š„ๆญฅ้ชค/ไปปๅŠกโน. ่ฟ™ๅ่ฟ‡ๆฅๅˆไบง็”Ÿไบ†ไธ€้กนๆ–ฐไปปๅŠก๏ผŒๅณ"ๅƒๆฑ‰ๅ ก"๐Ÿ”€ โฏ๏ผŒ ไธŠไธ€ไธช"ๆ‹ฟๆฑ‰ๅ ก"็š„ไปปๅŠกๅทฒ็ป็ป“ๆŸไบ†โน. + +### ๅนถ่กŒๆฑ‰ๅ ก + +็Žฐๅœจ่ฎฉๆˆ‘ไปฌๅ‡่ฎพไธๆ˜ฏ"ๅนถๅ‘ๆฑ‰ๅ ก"๏ผŒ่€Œๆ˜ฏ"ๅนถ่กŒๆฑ‰ๅ ก"ใ€‚ + +ไฝ ๅ’Œไฝ ็š„ๆ‹ไบบไธ€่ตทๅŽปๅƒๅนถ่กŒๅฟซ้คใ€‚ + +ไฝ ็ซ™ๅœจ้˜Ÿไผไธญ๏ผŒๅŒๆ—ถๆ˜ฏๅŽจๅธˆ็š„ๅ‡ ไธชๆ”ถ้“ถๅ‘˜๏ผˆๆฏ”ๆ–น่ฏด8ไธช๏ผ‰ไปŽๅ‰้ข็š„ไบบ้‚ฃ้‡ŒๆŽฅๅ•ใ€‚ + +ไฝ ไน‹ๅ‰็š„ๆฏไธชไบบ้ƒฝๅœจ็ญ‰ๅพ…ไป–ไปฌ็š„ๆฑ‰ๅ กๅ‡†ๅค‡ๅฅฝๅŽๆ‰็ฆปๅผ€ๆŸœๅฐ๏ผŒๅ› ไธบ8ๅๆ”ถ้“ถๅ‘˜้ƒฝไผšๅœจไธ‹ไธ€ไปฝ่ฎขๅ•ๅ‰้ฉฌไธŠๅ‡†ๅค‡ๅฅฝๆฑ‰ๅ กใ€‚ + + + +็„ถๅŽ๏ผŒ็ปˆไบŽ่ฝฎๅˆฐไฝ ไบ†๏ผŒไฝ ไธบไฝ ็š„ๆ‹ไบบๅ’Œไฝ ่ฎข่ดญไบ†ไธคไธช้žๅธธ็ฒพ็พŽ็š„ๆฑ‰ๅ กใ€‚ + +ไฝ ไป˜้’ฑไบ† ๐Ÿ’ธใ€‚ + + + +ๆ”ถ้“ถๅ‘˜ๅŽปๅŽจๆˆฟใ€‚ + +ไฝ ็ซ™ๅœจๆŸœๅฐๅ‰ ๐Ÿ•™็ญ‰ๅพ…็€๏ผŒ่ฟ™ๆ ทๅฐฑไธไผšๆœ‰ไบบๅœจไฝ ไน‹ๅ‰ๆŠข่ตฐไฝ ็š„ๆฑ‰ๅ ก๏ผŒๅ› ไธบๆฒกๆœ‰่ฝฎๆต็š„ๅท็ ใ€‚ + + + +ๅฝ“ไฝ ๅ’Œไฝ ็š„ๆ‹ไบบๅฟ™ไบŽไธ่ฎฉไปปไฝ•ไบบๅ‡บ็Žฐๅœจไฝ ้ขๅ‰๏ผŒๅนถไธ”ๅœจไป–ไปฌๅˆฐๆฅ็š„ๆ—ถๅ€™ๆ‹ฟ่ตฐไฝ ็š„ๆฑ‰ๅ กๆ—ถ๏ผŒไฝ ๆ— ๆณ•ๅ…ณๆณจๅˆฐไฝ ็š„ๆ‹ไบบใ€‚๐Ÿ˜ž + +่ฟ™ๆ˜ฏ"ๅŒๆญฅ"็š„ๅทฅไฝœ๏ผŒไฝ ่ขซ่ฟซไธŽๆœๅŠกๅ‘˜/ๅŽจๅธˆ ๐Ÿ‘จโ€๐Ÿณ"ๅŒๆญฅ"ใ€‚ไฝ ๅœจๆญคๅฟ…้กป็ญ‰ๅพ… ๐Ÿ•™ ๏ผŒๅœจๆ”ถ้“ถๅ‘˜/ๅŽจๅธˆ ๐Ÿ‘จโ€๐Ÿณ ๅฎŒๆˆๆฑ‰ๅ กๅนถๅฐ†ๅฎƒไปฌไบค็ป™ไฝ ็š„็กฎๅˆ‡ๆ—ถ้—ดๅˆฐ่พพไน‹ๅ‰ไธ€็›ด็ญ‰ๅพ…๏ผŒๅฆๅˆ™ๅ…ถไป–ไบบๅฏ่ƒฝไผšๆ‹ฟ่ตฐๅฎƒไปฌใ€‚ + + + +ไฝ ็ป่ฟ‡้•ฟๆ—ถ้—ด็š„็ญ‰ๅพ… ๐Ÿ•™ ๏ผŒๆ”ถ้“ถๅ‘˜/ๅŽจๅธˆ ๐Ÿ‘จโ€๐Ÿณ็ปˆไบŽๅธฆ็€ๆฑ‰ๅ กๅ›žๅˆฐไบ†ๆŸœๅฐใ€‚ + + + +ไฝ ๆ‹ฟ็€ๆฑ‰ๅ ก๏ผŒๅ’Œไฝ ็š„ๆƒ…ไบบไธ€่ตทไธŠๆกŒใ€‚ + +ไฝ ไปฌไป…ไป…ๆ˜ฏๅƒไบ†ๅฎƒไปฌ๏ผŒๅฐฑ็ป“ๆŸไบ†ใ€‚โน + + + +ๆฒกๆœ‰ๅคชๅคš็š„ไบค่ฐˆๆˆ–่ฐƒๆƒ…๏ผŒๅ› ไธบๅคง้ƒจๅˆ†ๆ—ถ้—ด ๐Ÿ•™ ้ƒฝๅœจๆŸœๅฐๅ‰็ญ‰ๅพ…๐Ÿ˜žใ€‚ + +!!! info + ๆผ‚ไบฎ็š„ๆ’็”ปๆฅ่‡ช Ketrina Thompson. ๐ŸŽจ + +--- + +ๅœจ่ฟ™ไธชๅนถ่กŒๆฑ‰ๅ ก็š„ๅœบๆ™ฏไธญ๏ผŒไฝ ๆ˜ฏไธ€ไธช่ฎก็ฎ—ๆœบ็จ‹ๅบ ๐Ÿค– ไธ”ๆœ‰ไธคไธชๅค„็†ๅ™จ๏ผˆไฝ ๅ’Œไฝ ็š„ๆ‹ไบบ๏ผ‰๏ผŒ้ƒฝๅœจ็ญ‰ๅพ… ๐Ÿ•™ ๏ผŒๅนถๆŠ•ๅ…ฅไป–ไปฌ็š„ๆณจๆ„ๅŠ› โฏ ๅœจๆŸœๅฐไธŠ็ญ‰ๅพ…ไบ†ๅพˆ้•ฟไธ€ๆฎตๆ—ถ้—ดใ€‚ + +่ฟ™ๅฎถๅฟซ้คๅบ—ๆœ‰ 8 ไธชๅค„็†ๅ™จ๏ผˆๆ”ถ้“ถๅ‘˜/ๅŽจๅธˆ๏ผ‰ใ€‚่€Œๅนถๅ‘ๆฑ‰ๅ กๅบ—ๅฏ่ƒฝๅชๆœ‰ 2 ไธช๏ผˆไธ€ไธชๆ”ถ้“ถๅ‘˜ๅ’Œไธ€ไธชๅŽจๅธˆ๏ผ‰ใ€‚ + +ไฝ†ๆœ€็ปˆ็š„ไฝ“้ชŒไป็„ถไธๆ˜ฏๆœ€ๅฅฝ็š„ใ€‚๐Ÿ˜ž + +--- + +่ฟ™ๅฐ†ๆ˜ฏไธŽๆฑ‰ๅ ก็š„็ฑปไผผๆ•…ไบ‹ใ€‚๐Ÿ” + +ไธ€็งๆ›ด"่ดด่ฟ‘็”Ÿๆดป"็š„ไพ‹ๅญ๏ผŒๆƒณ่ฑกไธ€ๅฎถ้“ถ่กŒใ€‚ + +็›ดๅˆฐๆœ€่ฟ‘๏ผŒๅคงๅคšๆ•ฐ้“ถ่กŒ้ƒฝๆœ‰ๅคšไธชๅ‡บ็บณๅ‘˜ ๐Ÿ‘จโ€๐Ÿ’ผ๐Ÿ‘จโ€๐Ÿ’ผ๐Ÿ‘จโ€๐Ÿ’ผ๐Ÿ‘จโ€๐Ÿ’ผ ่ฟ˜ๆœ‰ไธ€ๆก้•ฟ้•ฟๆŽ’้˜Ÿ้˜Ÿไผ๐Ÿ•™๐Ÿ•™๐Ÿ•™๐Ÿ•™๐Ÿ•™๐Ÿ•™๐Ÿ•™๐Ÿ•™ใ€‚ + +ๆ‰€ๆœ‰ๆ”ถ้“ถๅ‘˜้ƒฝๆ˜ฏไธ€ไธชๆŽฅไธ€ไธช็š„ๅœจๅฎขๆˆท้ขๅ‰ๅšๅฎŒๆ‰€ๆœ‰็š„ๅทฅไฝœ๐Ÿ‘จโ€๐Ÿ’ผโฏ. + +ไฝ ๅฟ…้กป็ป่ฟ‡ ๐Ÿ•™ ่พƒ้•ฟๆ—ถ้—ดๆŽ’้˜Ÿ๏ผŒๅฆๅˆ™ไฝ ๅฐฑๆฒกๆœบไผšไบ†ใ€‚ + +ไฝ ๅฏไธไผšๆƒณๅธฆไฝ ็š„ๆ‹ไบบ ๐Ÿ˜ ๅ’Œไฝ ไธ€่ตทๅŽป้“ถ่กŒๅŠžไบ‹๐Ÿฆ. + +### ๆฑ‰ๅ ก็ป“่ฎบ + +ๅœจ"ไฝ ไธŽๆ‹ไบบไธ€่ตทๅƒๆฑ‰ๅ ก"็š„่ฟ™ไธชๅœบๆ™ฏไธญ๏ผŒๅ› ไธบๆœ‰ๅพˆๅคšไบบๅœจ็ญ‰ๅพ…๐Ÿ•™๏ผŒ ไฝฟ็”จๅนถๅ‘็ณป็ปŸๆ›ดๆœ‰ๆ„ไน‰โธ๐Ÿ”€โฏ. + +ๅคงๅคšๆ•ฐ Web ๅบ”็”จ้ƒฝๆ˜ฏ่ฟ™ๆ ท็š„ใ€‚ + +ไฝ ็š„ๆœๅŠกๅ™จๆญฃๅœจ็ญ‰ๅพ…ๅพˆๅคšๅพˆๅคš็”จๆˆท้€š่ฟ‡ไป–ไปฌไธๅคชๅฅฝ็š„็ฝ‘็ปœๅ‘้€ๆฅ็š„่ฏทๆฑ‚ใ€‚ + +็„ถๅŽๅ†ๆฌก็ญ‰ๅพ… ๐Ÿ•™ ๅ“ๅบ”ๅ›žๆฅใ€‚ + +่ฟ™ไธช"็ญ‰ๅพ…" ๐Ÿ•™ ๆ˜ฏไปฅๅพฎ็ง’ไธบๅ•ไฝๆต‹้‡็š„๏ผŒไฝ†ๆ€ป็š„ๆฅ่ฏด๏ผŒๆœ€ๅŽ่ฟ˜ๆ˜ฏ็ญ‰ๅพ…ๅพˆไน…ใ€‚ + +่ฟ™ๅฐฑๆ˜ฏไธบไป€ไนˆไฝฟ็”จๅผ‚ๆญฅๅฏนไบŽ Web API ๅพˆๆœ‰ๆ„ไน‰็š„ๅŽŸๅ›  โธ๐Ÿ”€โฏใ€‚ + +่ฟ™็งๅผ‚ๆญฅๆœบๅˆถๆญฃๆ˜ฏ NodeJS ๅ—ๅˆฐๆฌข่ฟŽ็š„ๅŽŸๅ› ๏ผˆๅฐฝ็ฎก NodeJS ไธๆ˜ฏๅนถ่กŒ็š„๏ผ‰๏ผŒไปฅๅŠ Go ไฝœไธบ็ผ–็จ‹่ฏญ่จ€็š„ไผ˜ๅŠฟๆ‰€ๅœจใ€‚ + +่ฟ™ไธŽ **FastAPI** ็š„ๆ€ง่ƒฝๆฐดๅนณ็›ธๅŒใ€‚ + +ๆ‚จๅฏไปฅๅŒๆ—ถๆ‹ฅๆœ‰ๅนถ่กŒๆ€งๅ’Œๅผ‚ๆญฅๆ€ง๏ผŒๆ‚จๅฏไปฅ่Žทๅพ—ๆฏ”ๅคงๅคšๆ•ฐ็ป่ฟ‡ๆต‹่ฏ•็š„ NodeJS ๆก†ๆžถๆ›ด้ซ˜็š„ๆ€ง่ƒฝ๏ผŒๅนถไธ”ไธŽ Go ไธ็›ธไธŠไธ‹๏ผŒ Go ๆ˜ฏไธ€็งๆ›ดๆŽฅ่ฟ‘ไบŽ C ็š„็ผ–่ฏ‘่ฏญ่จ€๏ผˆๅ…จ้ƒจๅฝ’ๅŠŸไบŽ Starlette๏ผ‰ใ€‚ + +### ๅนถๅ‘ๆฏ”ๅนถ่กŒๅฅฝๅ—๏ผŸ + +ไธ๏ผ่ฟ™ไธๆ˜ฏๆ•…ไบ‹็š„ๆœฌๆ„ใ€‚ + +ๅนถๅ‘ไธๅŒไบŽๅนถ่กŒใ€‚่€Œๆ˜ฏๅœจ้œ€่ฆๅคง้‡็ญ‰ๅพ…็š„็‰นๅฎšๅœบๆ™ฏไธ‹ๆ•ˆๆžœๆ›ดๅฅฝใ€‚ๅ› ๆญค๏ผŒๅœจ Web ๅบ”็”จ็จ‹ๅบๅผ€ๅ‘ไธญ๏ผŒๅฎƒ้€šๅธธๆฏ”ๅนถ่กŒ่ฆๅฅฝๅพ—ๅคš๏ผŒไฝ†่ฟ™ๅนถไธๆ„ๅ‘ณ็€ๅ…จ้ƒจใ€‚ + +ๅ› ๆญค๏ผŒไธบไบ†ๅนณ่กก่ฟ™ไธ€็‚น๏ผŒๆƒณ่ฑกไธ€ไธ‹ไธ‹้ข็š„็Ÿญ็ฏ‡ๆ•…ไบ‹๏ผš + +> ไฝ ๅฟ…้กปๆ‰“ๆ‰ซไธ€ไธชๅˆๅคงๅˆ่„็š„ๆˆฟๅญใ€‚ + +*ๆ˜ฏ็š„๏ผŒ่ฟ™ๅฐฑๆ˜ฏๅฎŒๆ•ด็š„ๆ•…ไบ‹ใ€‚* + +--- + +ๅœจไปปไฝ•ๅœฐๆ–น๏ผŒ ้ƒฝไธ้œ€่ฆ็ญ‰ๅพ… ๐Ÿ•™ ๏ผŒๅช้œ€่ฆๅœจๆˆฟๅญ็š„ๅคšไธชๅœฐๆ–นๅš็€ๅพˆๅคšๅทฅไฝœใ€‚ + +ไฝ ๅฏไปฅๅƒๆฑ‰ๅ ก็š„ไพ‹ๅญ้‚ฃๆ ท่ฝฎๆตๆ‰ง่กŒ๏ผŒๅ…ˆๆ˜ฏๅฎขๅŽ…๏ผŒ็„ถๅŽๆ˜ฏๅŽจๆˆฟ๏ผŒไฝ†ๅ› ไธบไฝ ไธ้œ€่ฆ็ญ‰ๅพ… ๐Ÿ•™ ๏ผŒๅฏนไบŽไปปไฝ•ไบ‹ๆƒ…้ƒฝๆ˜ฏๆธ…ๆด๏ผŒๆธ…ๆด๏ผŒ่ฟ˜ๆ˜ฏๆธ…ๆด๏ผŒ่ฝฎๆตไธไผšๅฝฑๅ“ไปปไฝ•ไบ‹ๆƒ…ใ€‚ + +ๆ— ่ฎบๆ˜ฏๅฆ่ฝฎๆตๆ‰ง่กŒ๏ผˆๅนถๅ‘๏ผ‰๏ผŒ้ƒฝ้œ€่ฆ็›ธๅŒ็š„ๆ—ถ้—ดๆฅๅฎŒๆˆ๏ผŒ่€Œไฝ ไนŸไผšๅฎŒๆˆ็›ธๅŒ็š„ๅทฅไฝœ้‡ใ€‚ + +ไฝ†ๅœจ่ฟ™็งๆƒ…ๅ†ตไธ‹๏ผŒๅฆ‚ๆžœไฝ ่ƒฝๅธฆไธŠ 8 ๅๅ‰ๆ”ถ้“ถๅ‘˜/ๅŽจๅธˆ๏ผŒ็Žฐๅœจๆ˜ฏๆธ…ๆดๅทฅไธ€่ตทๆธ…ๆ‰ซ๏ผŒไป–ไปฌไธญ็š„ๆฏไธ€ไธชไบบ๏ผˆๅŠ ไธŠไฝ ๏ผ‰้ƒฝ่ƒฝๅ ๆฎๆˆฟๅญ็š„ไธ€ไธชๅŒบๅŸŸๆฅๆธ…ๆ‰ซ๏ผŒไฝ ๅฐฑๅฏไปฅๅœจ้ขๅค–็š„ๅธฎๅŠฉไธ‹ๅนถ่กŒ็š„ๆ›ดๅฟซๅœฐๅฎŒๆˆๆ‰€ๆœ‰ๅทฅไฝœใ€‚ + +ๅœจ่ฟ™ไธชๅœบๆ™ฏไธญ๏ผŒๆฏไธชๆธ…ๆดๅทฅ๏ผˆๅŒ…ๆ‹ฌๆ‚จ๏ผ‰้ƒฝๅฐ†ๆ˜ฏไธ€ไธชๅค„็†ๅ™จ๏ผŒๅฎŒๆˆ่ฟ™ไธชๅทฅไฝœ็š„ไธ€้ƒจๅˆ†ใ€‚ + +็”ฑไบŽๅคงๅคšๆ•ฐๆ‰ง่กŒๆ—ถ้—ดๆ˜ฏ็”ฑๅฎž้™…ๅทฅไฝœ๏ผˆ่€Œไธๆ˜ฏ็ญ‰ๅพ…๏ผ‰ๅ ็”จ็š„๏ผŒๅนถไธ”่ฎก็ฎ—ๆœบไธญ็š„ๅทฅไฝœๆ˜ฏ็”ฑ CPU ๅฎŒๆˆ็š„๏ผŒๆ‰€ไปฅไป–ไปฌ็งฐ่ฟ™ไบ›้—ฎ้ข˜ไธบ"CPU ๅฏ†้›†ๅž‹"ใ€‚ + +--- + +CPU ๅฏ†้›†ๅž‹ๆ“ไฝœ็š„ๅธธ่ง็คบไพ‹ๆ˜ฏ้œ€่ฆๅคๆ‚็š„ๆ•ฐๅญฆๅค„็†ใ€‚ + +ไพ‹ๅฆ‚๏ผš + +* **้Ÿณ้ข‘**ๆˆ–**ๅ›พๅƒ**ๅค„็†๏ผ› +* **่ฎก็ฎ—ๆœบ่ง†่ง‰**: ไธ€ๅน…ๅ›พๅƒ็”ฑๆ•ฐ็™พไธ‡ๅƒ็ด ็ป„ๆˆ๏ผŒๆฏไธชๅƒ็ด ๆœ‰3็ง้ขœ่‰ฒๅ€ผ๏ผŒๅค„็†้€šๅธธ้œ€่ฆๅŒๆ—ถๅฏน่ฟ™ไบ›ๅƒ็ด ่ฟ›่กŒ่ฎก็ฎ—๏ผ› +* **ๆœบๅ™จๅญฆไน **: ๅฎƒ้€šๅธธ้œ€่ฆๅคง้‡็š„"็Ÿฉ้˜ต"ๅ’Œ"ๅ‘้‡"ไน˜ๆณ•ใ€‚ๆƒณ่ฑกไธ€ไธชๅŒ…ๅซๆ•ฐๅญ—็š„ๅทจๅคง็”ตๅญ่กจๆ ผ๏ผŒๅนถๅŒๆ—ถๅฐ†ๆ‰€ๆœ‰ๆ•ฐๅญ—็›ธไน˜๏ผ› +* **ๆทฑๅบฆๅญฆไน **: ่ฟ™ๆ˜ฏๆœบๅ™จๅญฆไน ็š„ไธ€ไธชๅญ้ข†ๅŸŸ๏ผŒๅŒๆ ท้€‚็”จใ€‚ๅชๆ˜ฏๆฒกๆœ‰ไธ€ไธชๆ•ฐๅญ—็š„็”ตๅญ่กจๆ ผๅฏไปฅ็›ธไน˜๏ผŒ่€Œๆ˜ฏไธ€ไธชๅบžๅคง็š„ๆ•ฐๅญ—้›†ๅˆ๏ผŒๅœจๅพˆๅคšๆƒ…ๅ†ตไธ‹๏ผŒไฝ ้œ€่ฆไฝฟ็”จไธ€ไธช็‰นๆฎŠ็š„ๅค„็†ๅ™จๆฅๆž„ๅปบๅ’Œไฝฟ็”จ่ฟ™ไบ›ๆจกๅž‹ใ€‚ + +### ๅนถๅ‘ + ๅนถ่กŒ: Web + ๆœบๅ™จๅญฆไน  + +ไฝฟ็”จ **FastAPI**๏ผŒๆ‚จๅฏไปฅๅˆฉ็”จ Web ๅผ€ๅ‘ไธญๅธธ่ง็š„ๅนถๅ‘ๆœบๅˆถ็š„ไผ˜ๅŠฟ๏ผˆNodeJS ็š„ไธป่ฆๅธๅผ•ๅŠ›๏ผ‰ใ€‚ + +ๅนถไธ”๏ผŒๆ‚จไนŸๅฏไปฅๅˆฉ็”จๅนถ่กŒๅ’Œๅคš่ฟ›็จ‹๏ผˆ่ฎฉๅคšไธช่ฟ›็จ‹ๅนถ่กŒ่ฟ่กŒ๏ผ‰็š„ไผ˜็‚นๆฅๅค„็†ไธŽๆœบๅ™จๅญฆไน ็ณป็ปŸไธญ็ฑปไผผ็š„ **CPU ๅฏ†้›†ๅž‹** ๅทฅไฝœใ€‚ + +่ฟ™ไธ€็‚น๏ผŒๅ†ๅŠ ไธŠ Python ๆ˜ฏ**ๆ•ฐๆฎ็ง‘ๅญฆ**ใ€ๆœบๅ™จๅญฆไน ๏ผˆๅฐคๅ…ถๆ˜ฏๆทฑๅบฆๅญฆไน ๏ผ‰็š„ไธป่ฆ่ฏญ่จ€่ฟ™ไธ€็ฎ€ๅ•ไบ‹ๅฎž๏ผŒไฝฟๅพ— **FastAPI** ไธŽๆ•ฐๆฎ็ง‘ๅญฆ/ๆœบๅ™จๅญฆไน  Web API ๅ’Œๅบ”็”จ็จ‹ๅบ๏ผˆไปฅๅŠๅ…ถไป–่ฎธๅคšๅบ”็”จ็จ‹ๅบ๏ผ‰้žๅธธๅŒน้…ใ€‚ + +ไบ†่งฃๅฆ‚ไฝ•ๅœจ็”Ÿไบง็Žฏๅขƒไธญๅฎž็Žฐ่ฟ™็งๅนถ่กŒๆ€ง๏ผŒๅฏๆŸฅ็œ‹ๆญคๆ–‡ [Deployment](deployment/index.md){.internal-link target=_blank}ใ€‚ + +## `async` ๅ’Œ `await` + +็Žฐไปฃ็‰ˆๆœฌ็š„ Python ๆœ‰ไธ€็ง้žๅธธ็›ด่ง‚็š„ๆ–นๅผๆฅๅฎšไน‰ๅผ‚ๆญฅไปฃ็ ใ€‚่ฟ™ไฝฟๅฎƒ็œ‹่ตทๆฅๅฐฑๅƒๆญฃๅธธ็š„"้กบๅบ"ไปฃ็ ๏ผŒๅนถๅœจ้€‚ๅฝ“็š„ๆ—ถๅ€™"็ญ‰ๅพ…"ใ€‚ + +ๅฝ“ๆœ‰ไธ€ไธชๆ“ไฝœ้œ€่ฆ็ญ‰ๅพ…ๆ‰่ƒฝ็ป™ๅ‡บ็ป“ๆžœ๏ผŒไธ”ๆ”ฏๆŒ่ฟ™ไธชๆ–ฐ็š„ Python ็‰นๆ€งๆ—ถ๏ผŒๆ‚จๅฏไปฅ็ผ–ๅ†™ๅฆ‚ไธ‹ไปฃ็ ๏ผš + +```Python +burgers = await get_burgers(2) +``` + +่ฟ™้‡Œ็š„ๅ…ณ้”ฎๆ˜ฏ `await`ใ€‚ๅฎƒๅ‘Š่ฏ‰ Python ๅฎƒๅฟ…้กป็ญ‰ๅพ… โธ `get_burgers(2)` ๅฎŒๆˆๅฎƒ็š„ๅทฅไฝœ ๐Ÿ•™ ๏ผŒ็„ถๅŽๅฐ†็ป“ๆžœๅญ˜ๅ‚จๅœจ `burgers` ไธญใ€‚่ฟ™ๆ ท๏ผŒPython ๅฐฑไผš็Ÿฅ้“ๆญคๆ—ถๅฎƒๅฏไปฅๅŽปๅšๅ…ถไป–ไบ‹ๆƒ… ๐Ÿ”€ โฏ ๏ผˆๆฏ”ๅฆ‚ๆŽฅๆ”ถๅฆไธ€ไธช่ฏทๆฑ‚๏ผ‰ใ€‚ + +่ฆไฝฟ `await` ๅทฅไฝœ๏ผŒๅฎƒๅฟ…้กปไฝไบŽๆ”ฏๆŒ่ฟ™็งๅผ‚ๆญฅๆœบๅˆถ็š„ๅ‡ฝๆ•ฐๅ†…ใ€‚ๅ› ๆญค๏ผŒๅช้œ€ไฝฟ็”จ `async def` ๅฃฐๆ˜Žๅฎƒ๏ผš + +```Python hl_lines="1" +async def get_burgers(number: int): + # Do some asynchronous stuff to create the burgers + return burgers +``` + +...่€Œไธๆ˜ฏ `def`: + +```Python hl_lines="2" +# This is not asynchronous +def get_sequential_burgers(number: int): + # Do some sequential stuff to create the burgers + return burgers +``` + +ไฝฟ็”จ `async def`๏ผŒPython ๅฐฑ็Ÿฅ้“ๅœจ่ฏฅๅ‡ฝๆ•ฐไธญ๏ผŒๅฎƒๅฐ†้‡ไธŠ `await`๏ผŒๅนถไธ”ๅฎƒๅฏไปฅ"ๆš‚ๅœ" โธ ๆ‰ง่กŒ่ฏฅๅ‡ฝๆ•ฐ๏ผŒ็›ด่‡ณๆ‰ง่กŒๅ…ถไป–ๆ“ไฝœ ๐Ÿ”€ ๅŽๅ›žๆฅใ€‚ + +ๅฝ“ไฝ ๆƒณ่ฐƒ็”จไธ€ไธช `async def` ๅ‡ฝๆ•ฐๆ—ถ๏ผŒไฝ ๅฟ…้กป"็ญ‰ๅพ…"ๅฎƒใ€‚ๅ› ๆญค๏ผŒ่ฟ™ไธไผš่ตทไฝœ็”จ๏ผš + +```Python +# This won't work, because get_burgers was defined with: async def +burgers = get_burgers(2) +``` + +--- + +ๅ› ๆญค๏ผŒๅฆ‚ๆžœๆ‚จไฝฟ็”จ็š„ๅบ“ๅ‘Š่ฏ‰ๆ‚จๅฏไปฅไฝฟ็”จ `await` ่ฐƒ็”จๅฎƒ๏ผŒๅˆ™้œ€่ฆไฝฟ็”จ `async def` ๅˆ›ๅปบ่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ ๏ผŒๅฆ‚๏ผš + +```Python hl_lines="2-3" +@app.get('/burgers') +async def read_burgers(): + burgers = await get_burgers(2) + return burgers +``` + +### ๆ›ดๅคšๆŠ€ๆœฏ็ป†่Š‚ + +ๆ‚จๅฏ่ƒฝๅทฒ็ปๆณจๆ„ๅˆฐ๏ผŒ`await` ๅช่ƒฝๅœจ `async def` ๅฎšไน‰็š„ๅ‡ฝๆ•ฐๅ†…้ƒจไฝฟ็”จใ€‚ + +ไฝ†ไธŽๆญคๅŒๆ—ถ๏ผŒๅฟ…้กป"็ญ‰ๅพ…"้€š่ฟ‡ `async def` ๅฎšไน‰็š„ๅ‡ฝๆ•ฐใ€‚ๅ› ๆญค๏ผŒๅธฆ `async def` ็š„ๅ‡ฝๆ•ฐไนŸๅช่ƒฝๅœจ `async def` ๅฎšไน‰็š„ๅ‡ฝๆ•ฐๅ†…้ƒจ่ฐƒ็”จใ€‚ + +้‚ฃไนˆ๏ผŒ่ฟ™ๅ…ณไบŽๅ…ˆๆœ‰้ธก่ฟ˜ๆ˜ฏๅ…ˆๆœ‰่›‹็š„้—ฎ้ข˜๏ผŒๅฆ‚ไฝ•่ฐƒ็”จ็ฌฌไธ€ไธช `async` ๅ‡ฝๆ•ฐ๏ผŸ + +ๅฆ‚ๆžœๆ‚จไฝฟ็”จ **FastAPI**๏ผŒไฝ ไธๅฟ…ๆ‹…ๅฟƒ่ฟ™ไธ€็‚น๏ผŒๅ› ไธบ"็ฌฌไธ€ไธช"ๅ‡ฝๆ•ฐๅฐ†ๆ˜ฏไฝ ็š„่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ๏ผŒFastAPI ๅฐ†็Ÿฅ้“ๅฆ‚ไฝ•ๅšๆญฃ็กฎ็š„ไบ‹ๆƒ…ใ€‚ + +ไฝ†ๅฆ‚ๆžœๆ‚จๆƒณๅœจๆฒกๆœ‰ FastAPI ็š„ๆƒ…ๅ†ตไธ‹ไฝฟ็”จ `async` / `await`๏ผŒๅˆ™ๅฏไปฅ่ฟ™ๆ ทๅšใ€‚ + +### ็ผ–ๅ†™่‡ชๅทฑ็š„ๅผ‚ๆญฅไปฃ็  + +Starlette ๏ผˆๅ’Œ **FastAPI**๏ผ‰ ๆ˜ฏๅŸบไบŽ AnyIO ๅฎž็Žฐ็š„๏ผŒ่ฟ™ไฝฟๅพ—ๅฎƒไปฌๅฏไปฅๅ…ผๅฎน Python ็š„ๆ ‡ๅ‡†ๅบ“ asyncio ๅ’Œ Trioใ€‚ + +็‰นๅˆซๆ˜ฏ๏ผŒไฝ ๅฏไปฅ็›ดๆŽฅไฝฟ็”จ AnyIO ๆฅๅค„็†้ซ˜็บง็š„ๅนถๅ‘็”จไพ‹๏ผŒ่ฟ™ไบ›็”จไพ‹้œ€่ฆๅœจ่‡ชๅทฑ็š„ไปฃ็ ไธญไฝฟ็”จๆ›ด้ซ˜็บง็š„ๆจกๅผใ€‚ + +ๅณไฝฟๆ‚จๆฒกๆœ‰ไฝฟ็”จ **FastAPI**๏ผŒๆ‚จไนŸๅฏไปฅไฝฟ็”จ AnyIO ็ผ–ๅ†™่‡ชๅทฑ็š„ๅผ‚ๆญฅ็จ‹ๅบ๏ผŒไฝฟๅ…ถๆ‹ฅๆœ‰่พƒ้ซ˜็š„ๅ…ผๅฎนๆ€งๅนถ่Žทๅพ—ไธ€ไบ›ๅฅฝๅค„๏ผˆไพ‹ๅฆ‚๏ผŒ ็ป“ๆž„ๅŒ–ๅนถๅ‘๏ผ‰ใ€‚ + +### ๅ…ถไป–ๅฝขๅผ็š„ๅผ‚ๆญฅไปฃ็  + +่ฟ™็งไฝฟ็”จ `async` ๅ’Œ `await` ็š„้ฃŽๆ ผๅœจ่ฏญ่จ€ไธญ็›ธๅฏน่พƒๆ–ฐใ€‚ + +ไฝ†ๅฎƒไฝฟๅค„็†ๅผ‚ๆญฅไปฃ็ ๅ˜ๅพ—ๅฎนๆ˜“ๅพˆๅคšใ€‚ + +่ฟ™็ง็›ธๅŒ็š„่ฏญๆณ•๏ผˆๆˆ–ๅ‡ ไนŽ็›ธๅŒ๏ผ‰ๆœ€่ฟ‘ไนŸๅŒ…ๅซๅœจ็Žฐไปฃ็‰ˆๆœฌ็š„ JavaScript ไธญ๏ผˆๅœจๆต่งˆๅ™จๅ’Œ NodeJS ไธญ๏ผ‰ใ€‚ + +ไฝ†ๅœจๆญคไน‹ๅ‰๏ผŒๅค„็†ๅผ‚ๆญฅไปฃ็ ้žๅธธๅคๆ‚ๅ’Œๅ›ฐ้šพใ€‚ + +ๅœจไปฅๅ‰็‰ˆๆœฌ็š„ Python๏ผŒไฝ ๅฏไปฅไฝฟ็”จๅคš็บฟ็จ‹ๆˆ–่€… Geventใ€‚ไฝ†ไปฃ็ ็š„็†่งฃใ€่ฐƒ่ฏ•ๅ’Œๆ€่€ƒ้ƒฝ่ฆๅคๆ‚่ฎธๅคšใ€‚ + +ๅœจไปฅๅ‰็‰ˆๆœฌ็š„ NodeJS / ๆต่งˆๅ™จ JavaScript ไธญ๏ผŒไฝ ไผšไฝฟ็”จ"ๅ›ž่ฐƒ"๏ผŒๅ› ๆญคไนŸๅฏ่ƒฝๅฏผ่‡ดๅ›ž่ฐƒๅœฐ็‹ฑใ€‚ + +## ๅ็จ‹ + +**ๅ็จ‹**ๅชๆ˜ฏ `async def` ๅ‡ฝๆ•ฐ่ฟ”ๅ›ž็š„ไธ€ไธช้žๅธธๅฅ‡็‰น็š„ไธœ่ฅฟ็š„็งฐๅ‘ผใ€‚Python ็Ÿฅ้“ๅฎƒๆœ‰็‚นๅƒไธ€ไธชๅ‡ฝๆ•ฐ๏ผŒๅฎƒๅฏไปฅๅฏๅŠจ๏ผŒไนŸไผšๅœจๆŸไธชๆ—ถๅˆป็ป“ๆŸ๏ผŒ่€Œไธ”ๅฎƒๅฏ่ƒฝไผšๅœจๅ†…้ƒจๆš‚ๅœ โธ ๏ผŒๅช่ฆๅ†…้ƒจๆœ‰ไธ€ไธช `await`ใ€‚ + +้€š่ฟ‡ไฝฟ็”จ `async` ๅ’Œ `await` ็š„ๅผ‚ๆญฅไปฃ็ ็š„ๆ‰€ๆœ‰ๅŠŸ่ƒฝๅคงๅคšๆ•ฐ่ขซๆฆ‚ๆ‹ฌไธบ"ๅ็จ‹"ใ€‚ๅฎƒๅฏไปฅไธŽ Go ็š„ไธป่ฆๅ…ณ้”ฎ็‰นๆ€ง "Goroutines" ็›ธๅชฒ็พŽใ€‚ + +## ็ป“่ฎบ + +่ฎฉๆˆ‘ไปฌๅ†ๆฅๅ›ž้กพไธ‹ไธŠๆ–‡ๆ‰€่ฏด็š„๏ผš + +> Python ็š„็Žฐไปฃ็‰ˆๆœฌๅฏไปฅ้€š่ฟ‡ไฝฟ็”จ `async` ๅ’Œ `await` ่ฏญๆณ•ๅˆ›ๅปบ**ๅ็จ‹**๏ผŒๅนถ็”จไบŽๆ”ฏๆŒ**ๅผ‚ๆญฅไปฃ็ **ใ€‚ + +็Žฐๅœจๅบ”่ฏฅ่ƒฝๆ˜Ž็™ฝๅ…ถๅซไน‰ไบ†ใ€‚โœจ + +ๆ‰€ๆœ‰่ฟ™ไบ›ไฝฟๅพ— FastAPI๏ผˆ้€š่ฟ‡ Starlette๏ผ‰ๅฆ‚ๆญคๅผบๅคง๏ผŒไนŸๆ˜ฏๅฎƒๆ‹ฅๆœ‰ๅฆ‚ๆญคไปคไบบๅฐ่ฑกๆทฑๅˆป็š„ๆ€ง่ƒฝ็š„ๅŽŸๅ› ใ€‚ + +## ้žๅธธๆŠ€ๆœฏๆ€ง็š„็ป†่Š‚ + +!!! warning + ไฝ ๅฏไปฅ่ทณ่ฟ‡่ฟ™้‡Œใ€‚ + + ่ฟ™ไบ›้ƒฝๆ˜ฏ FastAPI ๅฆ‚ไฝ•ๅœจๅ†…้ƒจๅทฅไฝœ็š„ๆŠ€ๆœฏ็ป†่Š‚ใ€‚ + + ๅฆ‚ๆžœๆ‚จๆœ‰็›ธๅฝ“ๅคš็š„ๆŠ€ๆœฏ็Ÿฅ่ฏ†๏ผˆๅ็จ‹ใ€็บฟ็จ‹ใ€้˜ปๅกž็ญ‰๏ผ‰๏ผŒๅนถไธ”ๅฏน FastAPI ๅฆ‚ไฝ•ๅค„็† `async def` ไธŽๅธธ่ง„ `def` ๆ„Ÿๅˆฐๅฅฝๅฅ‡๏ผŒ่ฏท็ปง็ปญใ€‚ + +### ่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ + +ๅฝ“ไฝ ไฝฟ็”จ `def` ่€Œไธๆ˜ฏ `async def` ๆฅๅฃฐๆ˜Žไธ€ไธช*่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ*ๆ—ถ๏ผŒๅฎƒ่ฟ่กŒๅœจๅค–้ƒจ็š„็บฟ็จ‹ๆฑ ไธญๅนถ็ญ‰ๅพ…ๅ…ถ็ป“ๆžœ๏ผŒ่€Œไธๆ˜ฏ็›ดๆŽฅ่ฐƒ็”จ๏ผˆๅ› ไธบๅฎƒไผš้˜ปๅกžๆœๅŠกๅ™จ๏ผ‰ใ€‚ + +ๅฆ‚ๆžœๆ‚จไฝฟ็”จ่ฟ‡ๅฆไธ€ไธชไธไปฅไธŠ่ฟฐๆ–นๅผๅทฅไฝœ็š„ๅผ‚ๆญฅๆก†ๆžถ๏ผŒๅนถไธ”ๆ‚จไน ๆƒฏไบŽ็”จๆ™ฎ้€š็š„ `def` ๅฎšไน‰ๆ™ฎ้€š็š„ไป…่ฎก็ฎ—่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ๏ผŒไปฅ่Žทๅพ—ๅพฎๅฐ็š„ๆ€ง่ƒฝๅขž็›Š๏ผˆๅคง็บฆ100็บณ็ง’๏ผ‰๏ผŒ่ฏทๆณจๆ„๏ผŒๅœจ FastAPI ไธญ๏ผŒๆ•ˆๆžœๅฐ†ๅฎŒๅ…จ็›ธๅใ€‚ๅœจ่ฟ™ไบ›ๆƒ…ๅ†ตไธ‹๏ผŒๆœ€ๅฅฝไฝฟ็”จ `async def`๏ผŒ้™ค้ž่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐๅ†…ไฝฟ็”จๆ‰ง่กŒ้˜ปๅกž I/O ็š„ไปฃ็ ใ€‚ + +ๅœจ่ฟ™ไธค็งๆƒ…ๅ†ตไธ‹๏ผŒไธŽๆ‚จไน‹ๅ‰็š„ๆก†ๆžถ็›ธๆฏ”๏ผŒ**FastAPI** ๅฏ่ƒฝ[ไป็„ถๅพˆๅฟซ](/#performance){.internal-link target=_blank}ใ€‚ + +### ไพ่ต– + +่ฟ™ๅŒๆ ท้€‚็”จไบŽ[ไพ่ต–](./tutorial/dependencies/index.md){.internal-link target=_blank}ใ€‚ๅฆ‚ๆžœไธ€ไธชไพ่ต–ๆ˜ฏๆ ‡ๅ‡†็š„ `def` ๅ‡ฝๆ•ฐ่€Œไธๆ˜ฏ `async def`๏ผŒๅฎƒๅฐ†่ขซ่ฟ่กŒๅœจๅค–้ƒจ็บฟ็จ‹ๆฑ ไธญใ€‚ + +### ๅญไพ่ต– + +ไฝ ๅฏไปฅๆ‹ฅๆœ‰ๅคšไธช็›ธไบ’ไพ่ต–็š„ไพ่ต–ไปฅๅŠ[ๅญไพ่ต–](./tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} ๏ผˆไฝœไธบๅ‡ฝๆ•ฐ็š„ๅ‚ๆ•ฐ๏ผ‰๏ผŒๅฎƒไปฌไธญ็š„ไธ€ไบ›ๅฏ่ƒฝๆ˜ฏ้€š่ฟ‡ `async def` ๅฃฐๆ˜Ž๏ผŒไนŸๅฏ่ƒฝๆ˜ฏ้€š่ฟ‡ `def` ๅฃฐๆ˜Žใ€‚ๅฎƒไปฌไป็„ถๅฏไปฅๆญฃๅธธๅทฅไฝœ๏ผŒ่ฟ™ไบ›้€š่ฟ‡ `def` ๅฃฐๆ˜Ž็š„ๅ‡ฝๆ•ฐๅฐ†ไผšๅœจๅค–้ƒจ็บฟ็จ‹ไธญ่ฐƒ็”จ๏ผˆๆฅ่‡ช็บฟ็จ‹ๆฑ ๏ผ‰๏ผŒ่€Œไธๆ˜ฏ"่ขซ็ญ‰ๅพ…"ใ€‚ + +### ๅ…ถไป–ๅ‡ฝๆ•ฐ + +ๆ‚จๅฏ็›ดๆŽฅ่ฐƒ็”จ้€š่ฟ‡ `def` ๆˆ– `async def` ๅˆ›ๅปบ็š„ไปปไฝ•ๅ…ถไป–ๅ‡ฝๆ•ฐ๏ผŒFastAPI ไธไผšๅฝฑๅ“ๆ‚จ่ฐƒ็”จๅฎƒไปฌ็š„ๆ–นๅผใ€‚ + +่ฟ™ไธŽ FastAPI ไธบๆ‚จ่ฐƒ็”จ*่ทฏๅพ„ๆ“ไฝœๅ‡ฝๆ•ฐ*ๅ’Œไพ่ต–้กน็š„้€ป่พ‘็›ธๅใ€‚ + +ๅฆ‚ๆžœไฝ ็š„ๅ‡ฝๆ•ฐๆ˜ฏ้€š่ฟ‡ `def` ๅฃฐๆ˜Ž็š„๏ผŒๅฎƒๅฐ†่ขซ็›ดๆŽฅ่ฐƒ็”จ๏ผˆๅœจไปฃ็ ไธญ็ผ–ๅ†™็š„ๅœฐๆ–น๏ผ‰๏ผŒ่€Œไธไผšๅœจ็บฟ็จ‹ๆฑ ไธญ๏ผŒๅฆ‚ๆžœ่ฟ™ไธชๅ‡ฝๆ•ฐ้€š่ฟ‡ `async def` ๅฃฐๆ˜Ž๏ผŒๅฝ“ๅœจไปฃ็ ไธญ่ฐƒ็”จๆ—ถ๏ผŒไฝ ๅฐฑๅบ”่ฏฅไฝฟ็”จ `await` ็ญ‰ๅพ…ๅ‡ฝๆ•ฐ็š„็ป“ๆžœใ€‚ + +--- + +ๅ†ๆฌกๆ้†’๏ผŒ่ฟ™ไบ›ๆ˜ฏ้žๅธธๆŠ€ๆœฏๆ€ง็š„็ป†่Š‚๏ผŒๅฆ‚ๆžœไฝ ๆฅๆœ็ดขๅฎƒๅฏ่ƒฝๅฏนไฝ ๆœ‰็”จใ€‚ + +ๅฆๅˆ™๏ผŒๆ‚จๆœ€ๅฅฝๅบ”่ฏฅ้ตๅฎˆ็š„ๆŒ‡ๅฏผๅŽŸๅˆ™่ตถๆ—ถ้—ดๅ—๏ผŸ. diff --git a/docs/zh/docs/deployment/versions.md b/docs/zh/docs/deployment/versions.md new file mode 100644 index 000000000..75b870139 --- /dev/null +++ b/docs/zh/docs/deployment/versions.md @@ -0,0 +1,87 @@ +# ๅ…ณไบŽ FastAPI ็‰ˆๆœฌ + +**FastAPI** ๅทฒๅœจ่ฎธๅคšๅบ”็”จ็จ‹ๅบๅ’Œ็ณป็ปŸ็š„็”Ÿไบง็Žฏๅขƒไธญไฝฟ็”จใ€‚ ๅนถไธ”ๆต‹่ฏ•่ฆ†็›–็އไฟๆŒๅœจ100%ใ€‚ ไฝ†ๅ…ถๅผ€ๅ‘่ฟ›ๅบฆไปๅœจๅฟซ้€ŸๆŽจ่ฟ›ใ€‚ + +็ปๅธธๆทปๅŠ ๆ–ฐๅŠŸ่ƒฝ๏ผŒๅฎšๆœŸไฟฎๅค้”™่ฏฏ๏ผŒๅนถไธ”ไปฃ็ ไปๅœจๆŒ็ปญๆ”น่ฟ›ใ€‚ + +่ฟ™ๅฐฑๆ˜ฏไธบไป€ไนˆๅฝ“ๅ‰็‰ˆๆœฌไป็„ถๆ˜ฏ`0.x.x`๏ผŒ่ฟ™ๅๆ˜ ๅ‡บๆฏไธช็‰ˆๆœฌ้ƒฝๅฏ่ƒฝๆœ‰Breaking changesใ€‚ ่ฟ™้ตๅพช่ฏญไน‰็‰ˆๆœฌๆŽงๅˆถ็š„็บฆๅฎšใ€‚ + +ไฝ ็Žฐๅœจๅฐฑๅฏไปฅไฝฟ็”จ **FastAPI** ๅˆ›ๅปบ็”Ÿไบง็Žฏๅขƒๅบ”็”จ็จ‹ๅบ๏ผˆไฝ ๅฏ่ƒฝๅทฒ็ป่ฟ™ๆ ทๅšไบ†ไธ€ๆฎตๆ—ถ้—ด๏ผ‰๏ผŒไฝ ๅช้œ€็กฎไฟไฝฟ็”จ็š„็‰ˆๆœฌๅฏไปฅไธŽๅ…ถไฝ™ไปฃ็ ๆญฃ็กฎ้…ๅˆๅณๅฏใ€‚ + +## ๅ›บๅฎšไฝ ็š„ `fastapi` ็‰ˆๆœฌ + +ไฝ ๅบ”่ฏฅๅš็š„็ฌฌไธ€ไปถไบ‹ๆ˜ฏๅฐ†ไฝ ๆญฃๅœจไฝฟ็”จ็š„ **FastAPI** ็‰ˆๆœฌโ€œๅ›บๅฎšโ€ๅˆฐไฝ ็Ÿฅ้“้€‚็”จไบŽไฝ ็š„ๅบ”็”จ็จ‹ๅบ็š„็‰นๅฎšๆœ€ๆ–ฐ็‰ˆๆœฌใ€‚ + +ไพ‹ๅฆ‚๏ผŒๅ‡่ฎพไฝ ๅœจๅบ”็”จ็จ‹ๅบไธญไฝฟ็”จ็‰ˆๆœฌ`0.45.0`ใ€‚ + +ๅฆ‚ๆžœไฝ ไฝฟ็”จ`requirements.txt`ๆ–‡ไปถ๏ผŒไฝ ๅฏไปฅไฝฟ็”จไปฅไธ‹ๅ‘ฝไปคๆŒ‡ๅฎš็‰ˆๆœฌ๏ผš + +````txt +fastapi==0.45.0 +```` + +่ฟ™ๆ„ๅ‘ณ็€ไฝ ๅฐ†ไฝฟ็”จ็‰ˆๆœฌ`0.45.0`ใ€‚ + +ๆˆ–่€…ไฝ ไนŸๅฏไปฅๅฐ†ๅ…ถๅ›บๅฎšไธบ๏ผš + +````txt +fastapi>=0.45.0,<0.46.0 +```` + +่ฟ™ๆ„ๅ‘ณ็€ไฝ ๅฐ†ไฝฟ็”จ`0.45.0`ๆˆ–ๆ›ด้ซ˜็‰ˆๆœฌ๏ผŒไฝ†ไฝŽไบŽ`0.46.0`๏ผŒไพ‹ๅฆ‚๏ผŒ็‰ˆๆœฌ`0.45.2`ไปไผš่ขซๆŽฅๅ—ใ€‚ + +ๅฆ‚ๆžœไฝ ไฝฟ็”จไปปไฝ•ๅ…ถไป–ๅทฅๅ…ทๆฅ็ฎก็†ไฝ ็š„ๅฎ‰่ฃ…๏ผŒไพ‹ๅฆ‚ Poetryใ€Pipenv ๆˆ–ๅ…ถไป–ๅทฅๅ…ท๏ผŒๅฎƒไปฌ้ƒฝๆœ‰ไธ€็งๅฎšไน‰ๅŒ…็š„็‰นๅฎš็‰ˆๆœฌ็š„ๆ–นๆณ•ใ€‚ + +## ๅฏ็”จ็‰ˆๆœฌ + +ไฝ ๅฏไปฅๅœจ[ๅ‘่กŒ่ฏดๆ˜Ž](../release-notes.md){.internal-link target=_blank}ไธญๆŸฅ็œ‹ๅฏ็”จ็‰ˆๆœฌ๏ผˆไพ‹ๅฆ‚ๆŸฅ็œ‹ๅฝ“ๅ‰ๆœ€ๆ–ฐ็‰ˆๆœฌ๏ผ‰ใ€‚ + +## ๅ…ณไบŽ็‰ˆๆœฌ + +้ตๅพช่ฏญไน‰็‰ˆๆœฌๆŽงๅˆถ็บฆๅฎš๏ผŒไปปไฝ•ไฝŽไบŽ`1.0.0`็š„็‰ˆๆœฌ้ƒฝๅฏ่ƒฝไผšๆทปๅŠ  breaking changesใ€‚ + +FastAPI ่ฟ˜้ตๅพช่ฟ™ๆ ท็š„็บฆๅฎš๏ผšไปปไฝ•`PATCH`็‰ˆๆœฌๆ›ดๆ”น้ƒฝๆ˜ฏไธบไบ†bugไฟฎๅคๅ’Œnon-breaking changesใ€‚ + +!!! tip + "PATCH"ๆ˜ฏๆœ€ๅŽไธ€ไธชๆ•ฐๅญ—๏ผŒไพ‹ๅฆ‚๏ผŒๅœจ`0.2.3`ไธญ๏ผŒPATCH็‰ˆๆœฌๆ˜ฏ`3`ใ€‚ + +ๅ› ๆญค๏ผŒไฝ ๅบ”่ฏฅ่ƒฝๅคŸๅ›บๅฎšๅˆฐๅฆ‚ไธ‹็‰ˆๆœฌ๏ผš + +```txt +fastapi>=0.45.0,<0.46.0 +``` + +"MINOR"็‰ˆๆœฌไธญไผšๆทปๅŠ breaking changesๅ’Œๆ–ฐๅŠŸ่ƒฝใ€‚ + +!!! tip + "MINOR"ๆ˜ฏไธญ้—ด็š„ๆ•ฐๅญ—๏ผŒไพ‹ๅฆ‚๏ผŒๅœจ`0.2.3`ไธญ๏ผŒMINOR็‰ˆๆœฌๆ˜ฏ`2`ใ€‚ + +## ๅ‡็บงFastAPI็‰ˆๆœฌ + +ไฝ ๅบ”่ฏฅไธบไฝ ็š„ๅบ”็”จ็จ‹ๅบๆทปๅŠ ๆต‹่ฏ•ใ€‚ + +ไฝฟ็”จ **FastAPI** ็ผ–ๅ†™ๆต‹่ฏ•้žๅธธ็ฎ€ๅ•๏ผˆๆ„Ÿ่ฐข Starlette๏ผ‰๏ผŒ่ฏทๅ‚่€ƒๆ–‡ๆกฃ๏ผš[ๆต‹่ฏ•](../tutorial/testing.md){.internal-link target=_blank} + +ๆทปๅŠ ๆต‹่ฏ•ๅŽ๏ผŒไฝ ๅฏไปฅๅฐ† **FastAPI** ็‰ˆๆœฌๅ‡็บงๅˆฐๆ›ดๆ–ฐ็‰ˆๆœฌ๏ผŒๅนถ้€š่ฟ‡่ฟ่กŒๆต‹่ฏ•ๆฅ็กฎไฟๆ‰€ๆœ‰ไปฃ็ ้ƒฝ่ƒฝๆญฃๅธธๅทฅไฝœใ€‚ + +ๅฆ‚ๆžœไธ€ๅˆ‡ๆญฃๅธธ๏ผŒๆˆ–่€…ๅœจ่ฟ›่กŒๅฟ…่ฆ็š„ๆ›ดๆ”นไน‹ๅŽ๏ผŒๅนถไธ”ๆ‰€ๆœ‰ๆต‹่ฏ•้ƒฝ้€š่ฟ‡ไบ†๏ผŒ้‚ฃไนˆไฝ ๅฏไปฅๅฐ†`fastapi`ๅ›บๅฎšๅˆฐๆ–ฐ็š„็‰ˆๆœฌใ€‚ + +## ๅ…ณไบŽStarlette + +ไฝ ไธๅบ”่ฏฅๅ›บๅฎš`starlette`็š„็‰ˆๆœฌใ€‚ + +ไธๅŒ็‰ˆๆœฌ็š„ **FastAPI** ๅฐ†ไฝฟ็”จ็‰นๅฎš็š„่พƒๆ–ฐ็‰ˆๆœฌ็š„ Starletteใ€‚ + +ๅ› ๆญค๏ผŒ**FastAPI** ่‡ชๅทฑๅฏไปฅไฝฟ็”จๆญฃ็กฎ็š„ Starlette ็‰ˆๆœฌใ€‚ + +## ๅ…ณไบŽ Pydantic + +Pydantic ๅŒ…ๅซ้’ˆๅฏน **FastAPI** ็š„ๆต‹่ฏ•ๅŠๅ…ถ่‡ชๅทฑ็š„ๆต‹่ฏ•๏ผŒๅ› ๆญค Pydantic ็š„ๆ–ฐ็‰ˆๆœฌ๏ผˆ`1.0.0`ไปฅไธŠ๏ผ‰ๅง‹็ปˆไธŽ FastAPI ๅ…ผๅฎนใ€‚ + +ไฝ ๅฏไปฅๅฐ† Pydantic ๅ›บๅฎšๅˆฐ้€‚ๅˆไฝ ็š„`1.0.0`ไปฅไธŠๅ’Œ`2.0.0`ไปฅไธ‹็š„ไปปไฝ•็‰ˆๆœฌใ€‚ + +ไพ‹ๅฆ‚๏ผš + +````txt +pydantic>=1.2.0,<2.0.0 +```` diff --git a/docs/zh/docs/help-fastapi.md b/docs/zh/docs/help-fastapi.md index 2a99950e3..9b70d115a 100644 --- a/docs/zh/docs/help-fastapi.md +++ b/docs/zh/docs/help-fastapi.md @@ -114,8 +114,6 @@ ่Šๅคฉๅฎคไป…ไพ›้—ฒ่Šใ€‚ -ๆˆ‘ไปฌไน‹ๅ‰่ฟ˜ไฝฟ็”จ่ฟ‡ Gitter chat๏ผŒไฝ†ๅฎƒไธๆ”ฏๆŒ้ข‘้“็ญ‰้ซ˜็บงๅŠŸ่ƒฝ๏ผŒ่ŠๅคฉไนŸๆฏ”่พƒ้บป็ƒฆ๏ผŒๆ‰€ไปฅ็ŽฐๅœจๆŽจ่ไฝฟ็”จ Discordใ€‚ - ### ๅˆซๅœจ่Šๅคฉๅฎค้‡Œๆ้—ฎ ๆณจๆ„๏ผŒ่Šๅคฉๅฎคๆ›ดๅ€พๅ‘ไบŽโ€œ้—ฒ่Šโ€๏ผŒ็ปๅธธๆœ‰ไบบไผšๆๅ‡บไธ€ไบ›็ฌผ็ปŸๅพ—่ฎฉไบบ้šพไปฅๅ›ž็ญ”็š„้—ฎ้ข˜๏ผŒๆ‰€ไปฅๅœจ่ฟ™้‡Œๆ้—ฎไธ€่ˆฌๆฒกไบบๅ›ž็ญ”ใ€‚ diff --git a/docs/zh/docs/index.md b/docs/zh/docs/index.md index 1de2a8d36..d776e5813 100644 --- a/docs/zh/docs/index.md +++ b/docs/zh/docs/index.md @@ -24,7 +24,7 @@ --- -FastAPI ๆ˜ฏไธ€ไธช็”จไบŽๆž„ๅปบ API ็š„็Žฐไปฃใ€ๅฟซ้€Ÿ๏ผˆ้ซ˜ๆ€ง่ƒฝ๏ผ‰็š„ web ๆก†ๆžถ๏ผŒไฝฟ็”จ Python 3.6+ ๅนถๅŸบไบŽๆ ‡ๅ‡†็š„ Python ็ฑปๅž‹ๆ็คบใ€‚ +FastAPI ๆ˜ฏไธ€ไธช็”จไบŽๆž„ๅปบ API ็š„็Žฐไปฃใ€ๅฟซ้€Ÿ๏ผˆ้ซ˜ๆ€ง่ƒฝ๏ผ‰็š„ web ๆก†ๆžถ๏ผŒไฝฟ็”จ Python 3.8+ ๅนถๅŸบไบŽๆ ‡ๅ‡†็š„ Python ็ฑปๅž‹ๆ็คบใ€‚ ๅ…ณ้”ฎ็‰นๆ€ง: @@ -107,7 +107,7 @@ FastAPI ๆ˜ฏไธ€ไธช็”จไบŽๆž„ๅปบ API ็š„็Žฐไปฃใ€ๅฟซ้€Ÿ๏ผˆ้ซ˜ๆ€ง่ƒฝ๏ผ‰็š„ web ๆก† ## ไพ่ต– -Python 3.6 ๅŠๆ›ด้ซ˜็‰ˆๆœฌ +Python 3.8 ๅŠๆ›ด้ซ˜็‰ˆๆœฌ FastAPI ็ซ™ๅœจไปฅไธ‹ๅทจไบบ็š„่‚ฉ่†€ไน‹ไธŠ๏ผš @@ -323,7 +323,7 @@ def update_item(item_id: int, item: Item): ไฝ ไธ้œ€่ฆๅŽปๅญฆไน ๆ–ฐ็š„่ฏญๆณ•ใ€ไบ†่งฃ็‰นๅฎšๅบ“็š„ๆ–นๆณ•ๆˆ–็ฑป๏ผŒ็ญ‰็ญ‰ใ€‚ -ๅช้œ€่ฆไฝฟ็”จๆ ‡ๅ‡†็š„ **Python 3.6 ๅŠๆ›ด้ซ˜็‰ˆๆœฌ**ใ€‚ +ๅช้œ€่ฆไฝฟ็”จๆ ‡ๅ‡†็š„ **Python 3.8 ๅŠๆ›ด้ซ˜็‰ˆๆœฌ**ใ€‚ ไธพไธชไพ‹ๅญ๏ผŒๆฏ”ๅฆ‚ๅฃฐๆ˜Ž `int` ็ฑปๅž‹๏ผš diff --git a/docs/zh/docs/tutorial/background-tasks.md b/docs/zh/docs/tutorial/background-tasks.md index c8568298b..94b75d4fd 100644 --- a/docs/zh/docs/tutorial/background-tasks.md +++ b/docs/zh/docs/tutorial/background-tasks.md @@ -69,7 +69,7 @@ {!> ../../../docs_src/background_tasks/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14 16 23 26" {!> ../../../docs_src/background_tasks/tutorial002_an.py!} @@ -84,7 +84,7 @@ {!> ../../../docs_src/background_tasks/tutorial002_py310.py!} ``` -=== "Python 3.6+ ๆฒกAnnotated" +=== "Python 3.8+ ๆฒกAnnotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/body-fields.md b/docs/zh/docs/tutorial/body-fields.md index c153784dc..fb6c6d9b6 100644 --- a/docs/zh/docs/tutorial/body-fields.md +++ b/docs/zh/docs/tutorial/body-fields.md @@ -18,7 +18,7 @@ {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4" {!> ../../../docs_src/body_fields/tutorial001_an.py!} @@ -33,7 +33,7 @@ {!> ../../../docs_src/body_fields/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -61,7 +61,7 @@ {!> ../../../docs_src/body_fields/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12-15" {!> ../../../docs_src/body_fields/tutorial001_an.py!} @@ -76,7 +76,7 @@ {!> ../../../docs_src/body_fields/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs/zh/docs/tutorial/body-multiple-params.md b/docs/zh/docs/tutorial/body-multiple-params.md index ee2cba6df..c93ef2f5c 100644 --- a/docs/zh/docs/tutorial/body-multiple-params.md +++ b/docs/zh/docs/tutorial/body-multiple-params.md @@ -20,7 +20,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="19-21" {!> ../../../docs_src/body_multiple_params/tutorial001_an.py!} @@ -35,7 +35,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -68,7 +68,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/body_multiple_params/tutorial002.py!} @@ -124,7 +124,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/body_multiple_params/tutorial003_an.py!} @@ -139,7 +139,7 @@ {!> ../../../docs_src/body_multiple_params/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -193,7 +193,7 @@ q: str = None {!> ../../../docs_src/body_multiple_params/tutorial004_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="28" {!> ../../../docs_src/body_multiple_params/tutorial004_an.py!} @@ -208,7 +208,7 @@ q: str = None {!> ../../../docs_src/body_multiple_params/tutorial004_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -247,7 +247,7 @@ item: Item = Body(embed=True) {!> ../../../docs_src/body_multiple_params/tutorial005_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/body_multiple_params/tutorial005_an.py!} @@ -262,7 +262,7 @@ item: Item = Body(embed=True) {!> ../../../docs_src/body_multiple_params/tutorial005_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/body-nested-models.md b/docs/zh/docs/tutorial/body-nested-models.md index 7704d2624..c65308bef 100644 --- a/docs/zh/docs/tutorial/body-nested-models.md +++ b/docs/zh/docs/tutorial/body-nested-models.md @@ -12,7 +12,7 @@ {!> ../../../docs_src/body_nested_models/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14" {!> ../../../docs_src/body_nested_models/tutorial001.py!} @@ -63,7 +63,7 @@ my_list: List[str] {!> ../../../docs_src/body_nested_models/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14" {!> ../../../docs_src/body_nested_models/tutorial002.py!} @@ -89,7 +89,7 @@ Python ๅ…ทๆœ‰ไธ€็ง็‰นๆฎŠ็š„ๆ•ฐๆฎ็ฑปๅž‹ๆฅไฟๅญ˜ไธ€็ป„ๅ”ฏไธ€็š„ๅ…ƒ็ด ๏ผŒๅณ `se {!> ../../../docs_src/body_nested_models/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 14" {!> ../../../docs_src/body_nested_models/tutorial003.py!} @@ -127,7 +127,7 @@ Pydantic ๆจกๅž‹็š„ๆฏไธชๅฑžๆ€ง้ƒฝๅ…ทๆœ‰็ฑปๅž‹ใ€‚ {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9-11" {!> ../../../docs_src/body_nested_models/tutorial004.py!} @@ -149,7 +149,7 @@ Pydantic ๆจกๅž‹็š„ๆฏไธชๅฑžๆ€ง้ƒฝๅ…ทๆœ‰็ฑปๅž‹ใ€‚ {!> ../../../docs_src/body_nested_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/body_nested_models/tutorial004.py!} @@ -198,7 +198,7 @@ Pydantic ๆจกๅž‹็š„ๆฏไธชๅฑžๆ€ง้ƒฝๅ…ทๆœ‰็ฑปๅž‹ใ€‚ {!> ../../../docs_src/body_nested_models/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 10" {!> ../../../docs_src/body_nested_models/tutorial005.py!} @@ -222,7 +222,7 @@ Pydantic ๆจกๅž‹็š„ๆฏไธชๅฑžๆ€ง้ƒฝๅ…ทๆœ‰็ฑปๅž‹ใ€‚ {!> ../../../docs_src/body_nested_models/tutorial006_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="20" {!> ../../../docs_src/body_nested_models/tutorial006.py!} @@ -273,7 +273,7 @@ Pydantic ๆจกๅž‹็š„ๆฏไธชๅฑžๆ€ง้ƒฝๅ…ทๆœ‰็ฑปๅž‹ใ€‚ {!> ../../../docs_src/body_nested_models/tutorial007_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 14 20 23 27" {!> ../../../docs_src/body_nested_models/tutorial007.py!} @@ -298,7 +298,7 @@ images: List[Image] {!> ../../../docs_src/body_nested_models/tutorial008_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15" {!> ../../../docs_src/body_nested_models/tutorial008.py!} @@ -338,7 +338,7 @@ images: List[Image] {!> ../../../docs_src/body_nested_models/tutorial009_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/body_nested_models/tutorial009.py!} diff --git a/docs/zh/docs/tutorial/body.md b/docs/zh/docs/tutorial/body.md index d00c96dc3..5cf53c0c2 100644 --- a/docs/zh/docs/tutorial/body.md +++ b/docs/zh/docs/tutorial/body.md @@ -23,7 +23,7 @@ {!> ../../../docs_src/body/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4" {!> ../../../docs_src/body/tutorial001.py!} @@ -41,7 +41,7 @@ {!> ../../../docs_src/body/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="7-11" {!> ../../../docs_src/body/tutorial001.py!} @@ -79,7 +79,7 @@ {!> ../../../docs_src/body/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/body/tutorial001.py!} @@ -142,7 +142,7 @@ Pydantic ๆœฌ่บซ็”š่‡ณไนŸ่ฟ›่กŒไบ†ไธ€ไบ›ๆ›ดๆ”นไปฅๆ”ฏๆŒๆญคๅŠŸ่ƒฝใ€‚ {!> ../../../docs_src/body/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="21" {!> ../../../docs_src/body/tutorial002.py!} @@ -160,7 +160,7 @@ Pydantic ๆœฌ่บซ็”š่‡ณไนŸ่ฟ›่กŒไบ†ไธ€ไบ›ๆ›ดๆ”นไปฅๆ”ฏๆŒๆญคๅŠŸ่ƒฝใ€‚ {!> ../../../docs_src/body/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17-18" {!> ../../../docs_src/body/tutorial003.py!} @@ -178,7 +178,7 @@ Pydantic ๆœฌ่บซ็”š่‡ณไนŸ่ฟ›่กŒไบ†ไธ€ไบ›ๆ›ดๆ”นไปฅๆ”ฏๆŒๆญคๅŠŸ่ƒฝใ€‚ {!> ../../../docs_src/body/tutorial004_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/body/tutorial004.py!} diff --git a/docs/zh/docs/tutorial/cookie-params.md b/docs/zh/docs/tutorial/cookie-params.md index 470fd8e82..f115f9677 100644 --- a/docs/zh/docs/tutorial/cookie-params.md +++ b/docs/zh/docs/tutorial/cookie-params.md @@ -18,7 +18,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/cookie_params/tutorial001_an.py!} @@ -33,7 +33,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -61,7 +61,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/cookie_params/tutorial001_an.py!} @@ -76,7 +76,7 @@ {!> ../../../docs_src/cookie_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md index f404820df..1866da298 100644 --- a/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md @@ -12,7 +12,7 @@ {!> ../../../docs_src/dependencies/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/dependencies/tutorial001.py!} @@ -85,7 +85,7 @@ fluffy = Cat(name="Mr Fluffy") {!> ../../../docs_src/dependencies/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11-15" {!> ../../../docs_src/dependencies/tutorial002.py!} diff --git a/docs/zh/docs/tutorial/encoder.md b/docs/zh/docs/tutorial/encoder.md index 76ed846ce..859ebc2e8 100644 --- a/docs/zh/docs/tutorial/encoder.md +++ b/docs/zh/docs/tutorial/encoder.md @@ -26,7 +26,7 @@ {!> ../../../docs_src/encoder/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="5 22" {!> ../../../docs_src/encoder/tutorial001.py!} diff --git a/docs/zh/docs/tutorial/extra-data-types.md b/docs/zh/docs/tutorial/extra-data-types.md index 76d606903..a74efa61b 100644 --- a/docs/zh/docs/tutorial/extra-data-types.md +++ b/docs/zh/docs/tutorial/extra-data-types.md @@ -67,7 +67,7 @@ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 3 13-17" {!> ../../../docs_src/extra_data_types/tutorial001_an.py!} @@ -82,7 +82,7 @@ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -105,7 +105,7 @@ {!> ../../../docs_src/extra_data_types/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="19-20" {!> ../../../docs_src/extra_data_types/tutorial001_an.py!} @@ -120,7 +120,7 @@ {!> ../../../docs_src/extra_data_types/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/extra-models.md b/docs/zh/docs/tutorial/extra-models.md index 32f8f9df1..06427a73d 100644 --- a/docs/zh/docs/tutorial/extra-models.md +++ b/docs/zh/docs/tutorial/extra-models.md @@ -23,7 +23,7 @@ {!> ../../../docs_src/extra_models/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41" {!> ../../../docs_src/extra_models/tutorial001.py!} @@ -164,7 +164,7 @@ UserInDB( {!> ../../../docs_src/extra_models/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 15-16 19-20 23-24" {!> ../../../docs_src/extra_models/tutorial002.py!} @@ -188,7 +188,7 @@ UserInDB( {!> ../../../docs_src/extra_models/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 14-15 18-20 33" {!> ../../../docs_src/extra_models/tutorial003.py!} @@ -206,7 +206,7 @@ UserInDB( {!> ../../../docs_src/extra_models/tutorial004_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 20" {!> ../../../docs_src/extra_models/tutorial004.py!} @@ -226,7 +226,7 @@ UserInDB( {!> ../../../docs_src/extra_models/tutorial005_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="1 8" {!> ../../../docs_src/extra_models/tutorial005.py!} diff --git a/docs/zh/docs/tutorial/header-params.md b/docs/zh/docs/tutorial/header-params.md index 22ff6dc27..2701167b3 100644 --- a/docs/zh/docs/tutorial/header-params.md +++ b/docs/zh/docs/tutorial/header-params.md @@ -18,7 +18,7 @@ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3" {!> ../../../docs_src/header_params/tutorial001_an.py!} @@ -33,7 +33,7 @@ {!> ../../../docs_src/header_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -60,7 +60,7 @@ {!> ../../../docs_src/header_params/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/header_params/tutorial001_an.py!} @@ -75,7 +75,7 @@ {!> ../../../docs_src/header_params/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -120,7 +120,7 @@ {!> ../../../docs_src/header_params/tutorial002_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="12" {!> ../../../docs_src/header_params/tutorial002_an.py!} @@ -135,7 +135,7 @@ {!> ../../../docs_src/header_params/tutorial002_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -170,7 +170,7 @@ {!> ../../../docs_src/header_params/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10" {!> ../../../docs_src/header_params/tutorial003_an.py!} @@ -194,7 +194,7 @@ {!> ../../../docs_src/header_params/tutorial003_py39.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/path-params-numeric-validations.md b/docs/zh/docs/tutorial/path-params-numeric-validations.md index 78fa922b4..9b41ad7cf 100644 --- a/docs/zh/docs/tutorial/path-params-numeric-validations.md +++ b/docs/zh/docs/tutorial/path-params-numeric-validations.md @@ -18,7 +18,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3-4" {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!} @@ -33,7 +33,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -60,7 +60,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="11" {!> ../../../docs_src/path_params_numeric_validations/tutorial001_an.py!} @@ -75,7 +75,7 @@ {!> ../../../docs_src/path_params_numeric_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ @@ -107,7 +107,7 @@ ๅ› ๆญค๏ผŒไฝ ๅฏไปฅๅฐ†ๅ‡ฝๆ•ฐๅฃฐๆ˜Žไธบ๏ผš -=== "Python 3.6 non-Annotated" +=== "Python 3.8 non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/query-params-str-validations.md b/docs/zh/docs/tutorial/query-params-str-validations.md index 7244aeade..39253eb0d 100644 --- a/docs/zh/docs/tutorial/query-params-str-validations.md +++ b/docs/zh/docs/tutorial/query-params-str-validations.md @@ -10,7 +10,7 @@ {!> ../../../docs_src/query_params_str_validations/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/query_params_str_validations/tutorial001.py!} diff --git a/docs/zh/docs/tutorial/request-files.md b/docs/zh/docs/tutorial/request-files.md index 03474907e..2c48f33ca 100644 --- a/docs/zh/docs/tutorial/request-files.md +++ b/docs/zh/docs/tutorial/request-files.md @@ -130,7 +130,7 @@ contents = myfile.file.read() {!> ../../../docs_src/request_files/tutorial001_02_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 17" {!> ../../../docs_src/request_files/tutorial001_02.py!} @@ -158,7 +158,7 @@ FastAPI ๆ”ฏๆŒๅŒๆ—ถไธŠไผ ๅคšไธชๆ–‡ไปถใ€‚ {!> ../../../docs_src/request_files/tutorial002_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="10 15" {!> ../../../docs_src/request_files/tutorial002.py!} @@ -183,7 +183,7 @@ FastAPI ๆ”ฏๆŒๅŒๆ—ถไธŠไผ ๅคšไธชๆ–‡ไปถใ€‚ {!> ../../../docs_src/request_files/tutorial003_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="18" {!> ../../../docs_src/request_files/tutorial003.py!} diff --git a/docs/zh/docs/tutorial/response-model.md b/docs/zh/docs/tutorial/response-model.md index f529cb0d8..e731b6989 100644 --- a/docs/zh/docs/tutorial/response-model.md +++ b/docs/zh/docs/tutorial/response-model.md @@ -20,7 +20,7 @@ {!> ../../../docs_src/response_model/tutorial001_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="17 22 24-27" {!> ../../../docs_src/response_model/tutorial001.py!} @@ -78,7 +78,7 @@ FastAPI ๅฐ†ไฝฟ็”จๆญค `response_model` ๆฅ๏ผš {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9 11 16" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -92,7 +92,7 @@ FastAPI ๅฐ†ไฝฟ็”จๆญค `response_model` ๆฅ๏ผš {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24" {!> ../../../docs_src/response_model/tutorial003.py!} @@ -106,7 +106,7 @@ FastAPI ๅฐ†ไฝฟ็”จๆญค `response_model` ๆฅ๏ผš {!> ../../../docs_src/response_model/tutorial003_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="22" {!> ../../../docs_src/response_model/tutorial003.py!} diff --git a/docs/zh/docs/tutorial/schema-extra-example.md b/docs/zh/docs/tutorial/schema-extra-example.md index 816e8f68e..ebc04da8b 100644 --- a/docs/zh/docs/tutorial/schema-extra-example.md +++ b/docs/zh/docs/tutorial/schema-extra-example.md @@ -16,7 +16,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15-23" {!> ../../../docs_src/schema_extra_example/tutorial001.py!} @@ -34,7 +34,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial002_py310.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="4 10-13" {!> ../../../docs_src/schema_extra_example/tutorial002.py!} @@ -61,7 +61,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="23-28" {!> ../../../docs_src/schema_extra_example/tutorial003_an.py!} @@ -76,7 +76,7 @@ {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/security/first-steps.md b/docs/zh/docs/tutorial/security/first-steps.md index 7b1052e12..dda956417 100644 --- a/docs/zh/docs/tutorial/security/first-steps.md +++ b/docs/zh/docs/tutorial/security/first-steps.md @@ -26,13 +26,13 @@ {!> ../../../docs_src/security/tutorial001_an_py39.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/security/tutorial001_an.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip ๅฐฝๅฏ่ƒฝ้€‰ๆ‹ฉไฝฟ็”จ `Annotated` ็š„็‰ˆๆœฌใ€‚ diff --git a/docs/zh/docs/tutorial/security/simple-oauth2.md b/docs/zh/docs/tutorial/security/simple-oauth2.md index 276f3d63b..c7f46177f 100644 --- a/docs/zh/docs/tutorial/security/simple-oauth2.md +++ b/docs/zh/docs/tutorial/security/simple-oauth2.md @@ -1,94 +1,98 @@ -# ไฝฟ็”จๅฏ†็ ๅ’Œ Bearer ็š„็ฎ€ๅ• OAuth2 +# OAuth2 ๅฎž็Žฐ็ฎ€ๅ•็š„ Password ๅ’Œ Bearer ้ชŒ่ฏ -็Žฐๅœจ่ฎฉๆˆ‘ไปฌๆŽฅ็€ไธŠไธ€็ซ ็ปง็ปญๅผ€ๅ‘๏ผŒๅนถๆทปๅŠ ็ผบๅฐ‘็š„้ƒจๅˆ†ไปฅๅฎž็Žฐไธ€ไธชๅฎŒๆ•ด็š„ๅฎ‰ๅ…จๆ€งๆต็จ‹ใ€‚ +ๆœฌ็ซ ๆทปๅŠ ไธŠไธ€็ซ ็คบไพ‹ไธญๆฌ ็ผบ็š„้ƒจๅˆ†๏ผŒๅฎž็ŽฐๅฎŒๆ•ด็š„ๅฎ‰ๅ…จๆตใ€‚ ## ่Žทๅ– `username` ๅ’Œ `password` -ๆˆ‘ไปฌๅฐ†ไฝฟ็”จ **FastAPI** ็š„ๅฎ‰ๅ…จๆ€งๅฎž็”จๅทฅๅ…ทๆฅ่Žทๅ– `username` ๅ’Œ `password`ใ€‚ +้ฆ–ๅ…ˆ๏ผŒไฝฟ็”จ **FastAPI** ๅฎ‰ๅ…จๅทฅๅ…ท่Žทๅ– `username` ๅ’Œ `password`ใ€‚ -OAuth2 ่ง„ๅฎšๅœจไฝฟ็”จ๏ผˆๆˆ‘ไปฌๆ‰“็ฎ—็”จ็š„๏ผ‰ใ€Œpassword ๆต็จ‹ใ€ๆ—ถ๏ผŒๅฎขๆˆท็ซฏ/็”จๆˆทๅฟ…้กปๅฐ† `username` ๅ’Œ `password` ๅญ—ๆฎตไฝœไธบ่กจๅ•ๆ•ฐๆฎๅ‘้€ใ€‚ +OAuth2 ่ง„่Œƒ่ฆๆฑ‚ไฝฟ็”จ**ๅฏ†็ ๆต**ๆ—ถ๏ผŒๅฎขๆˆท็ซฏๆˆ–็”จๆˆทๅฟ…้กปไปฅ่กจๅ•ๆ•ฐๆฎๅฝขๅผๅ‘้€ `username` ๅ’Œ `password` ๅญ—ๆฎตใ€‚ -่€Œไธ”่ง„่Œƒๆ˜Ž็กฎไบ†ๅญ—ๆฎตๅฟ…้กป่ฟ™ๆ ทๅ‘ฝๅใ€‚ๅ› ๆญค `user-name` ๆˆ– `email` ๆ˜ฏ่กŒไธ้€š็š„ใ€‚ +ๅนถไธ”๏ผŒ่ฟ™ไธคไธชๅญ—ๆฎตๅฟ…้กปๅ‘ฝๅไธบ `username` ๅ’Œ `password` ๏ผŒไธ่ƒฝไฝฟ็”จ `user-name` ๆˆ– `email` ็ญ‰ๅ…ถๅฎƒๅ็งฐใ€‚ -ไธ่ฟ‡ไธ็”จๆ‹…ๅฟƒ๏ผŒไฝ ๅฏไปฅๅœจๅ‰็ซฏๆŒ‰็…งไฝ ็š„ๆƒณๆณ•ๅฐ†ๅฎƒๅฑ•็คบ็ป™ๆœ€็ปˆ็”จๆˆทใ€‚ +ไธ่ฟ‡ไนŸไธ็”จๆ‹…ๅฟƒ๏ผŒๅ‰็ซฏไปๅฏไปฅๆ˜พ็คบ็ปˆ็ซฏ็”จๆˆทๆ‰€้œ€็š„ๅ็งฐใ€‚ -่€Œไธ”ไฝ ็š„ๆ•ฐๆฎๅบ“ๆจกๅž‹ไนŸๅฏไปฅไฝฟ็”จไฝ ๆƒณ็”จ็š„ไปปไฝ•ๅ…ถไป–ๅ็งฐใ€‚ +ๆ•ฐๆฎๅบ“ๆจกๅž‹ไนŸๅฏไปฅไฝฟ็”จๆ‰€้œ€็š„ๅ็งฐใ€‚ -ไฝ†ๆ˜ฏๅฏนไบŽ็™ปๅฝ•*่ทฏๅพ„ๆ“ไฝœ*๏ผŒๆˆ‘ไปฌ้œ€่ฆไฝฟ็”จ่ฟ™ไบ›ๅ็งฐๆฅไธŽ่ง„่Œƒๅ…ผๅฎน๏ผˆไปฅๅ…ทๅค‡ไพ‹ๅฆ‚ไฝฟ็”จ้›†ๆˆ็š„ API ๆ–‡ๆกฃ็ณป็ปŸ็š„่ƒฝๅŠ›๏ผ‰ใ€‚ +ไฝ†ๅฏนไบŽ็™ปๅฝ•*่ทฏๅพ„ๆ“ไฝœ*๏ผŒๅˆ™่ฆไฝฟ็”จๅ…ผๅฎน่ง„่Œƒ็š„ `username` ๅ’Œ `password`๏ผŒ๏ผˆไพ‹ๅฆ‚๏ผŒๅฎž็ŽฐไธŽ API ๆ–‡ๆกฃ้›†ๆˆ๏ผ‰ใ€‚ -่ง„่Œƒ่ฟ˜ๅ†™ๆ˜Žไบ† `username` ๅ’Œ `password` ๅฟ…้กปไฝœไธบ่กจๅ•ๆ•ฐๆฎๅ‘้€๏ผˆๅ› ๆญค๏ผŒๆญคๅค„ไธ่ƒฝไฝฟ็”จ JSON๏ผ‰ใ€‚ +่ฏฅ่ง„่Œƒ่ฆๆฑ‚ๅฟ…้กปไปฅ่กจๅ•ๆ•ฐๆฎๅฝขๅผๅ‘้€ `username` ๅ’Œ `password`๏ผŒๅ› ๆญค๏ผŒไธ่ƒฝไฝฟ็”จ JSON ๅฏน่ฑกใ€‚ -### `scope` +### `Scope`๏ผˆไฝœ็”จๅŸŸ๏ผ‰ -่ง„่Œƒ่ฟ˜ๆๅˆฐๅฎขๆˆท็ซฏๅฏไปฅๅ‘้€ๅฆไธ€ไธช่กจๅ•ๅญ—ๆฎตใ€Œ`scope`ใ€ใ€‚ +OAuth2 ่ฟ˜ๆ”ฏๆŒๅฎขๆˆท็ซฏๅ‘้€**`scope`**่กจๅ•ๅญ—ๆฎตใ€‚ -่ฟ™ไธช่กจๅ•ๅญ—ๆฎต็š„ๅ็งฐไธบ `scope`๏ผˆๅ•ๆ•ฐๅฝขๅผ๏ผ‰๏ผŒไฝ†ๅฎž้™…ไธŠๅฎƒๆ˜ฏไธ€ไธช็”ฑ็ฉบๆ ผๅˆ†้š”็š„ใ€Œไฝœ็”จๅŸŸใ€็ป„ๆˆ็š„้•ฟๅญ—็ฌฆไธฒใ€‚ +่™ฝ็„ถ่กจๅ•ๅญ—ๆฎต็š„ๅ็งฐๆ˜ฏ `scope`๏ผˆๅ•ๆ•ฐ๏ผ‰๏ผŒไฝ†ๅฎž้™…ไธŠ๏ผŒๅฎƒๆ˜ฏไปฅ็ฉบๆ ผๅˆ†้š”็š„๏ผŒ็”ฑๅคšไธช**scope**็ป„ๆˆ็š„้•ฟๅญ—็ฌฆไธฒใ€‚ -ๆฏไธชใ€Œไฝœ็”จๅŸŸใ€ๅชๆ˜ฏไธ€ไธชๅญ—็ฌฆไธฒ๏ผˆไธญ้—ดๆฒกๆœ‰็ฉบๆ ผ๏ผ‰ใ€‚ +**ไฝœ็”จๅŸŸ**ๅชๆ˜ฏไธๅธฆ็ฉบๆ ผ็š„ๅญ—็ฌฆไธฒใ€‚ -ๅฎƒไปฌ้€šๅธธ็”จไบŽๅฃฐๆ˜Ž็‰นๅฎš็š„ๅฎ‰ๅ…จๆƒ้™๏ผŒไพ‹ๅฆ‚๏ผš +ๅธธ็”จไบŽๅฃฐๆ˜ŽๆŒ‡ๅฎšๅฎ‰ๅ…จๆƒ้™๏ผŒไพ‹ๅฆ‚๏ผš -* `users:read` ๆˆ–่€… `users:write` ๆ˜ฏๅธธ่ง็š„ไพ‹ๅญใ€‚ -* Facebook / Instagram ไฝฟ็”จ `instagram_basic`ใ€‚ -* Google ไฝฟ็”จไบ† `https://www.googleapis.com/auth/drive` ใ€‚ +* ๅธธ่ง็”จไพ‹ไธบ๏ผŒ`users:read` ๆˆ– `users:write` +* ่„ธไนฆๅ’Œ Instagram ไฝฟ็”จ `instagram_basic` +* ่ฐทๆญŒไฝฟ็”จ `https://www.googleapis.com/auth/drive` -!!! info - ๅœจ OAuth2 ไธญใ€Œไฝœ็”จๅŸŸใ€ๅชๆ˜ฏไธ€ไธชๅฃฐๆ˜Žๆ‰€้œ€็‰นๅฎšๆƒ้™็š„ๅญ—็ฌฆไธฒใ€‚ +!!! info "่ฏดๆ˜Ž" - ๅฎƒๆœ‰ๆฒกๆœ‰ `:` ่ฟ™ๆ ท็š„ๅ…ถไป–ๅญ—็ฌฆๆˆ–่€…ๆ˜ฏไธๆ˜ฏ URL ้ƒฝๆฒกๆœ‰ๅ…ณ็ณปใ€‚ + OAuth2 ไธญ๏ผŒ**ไฝœ็”จๅŸŸ**ๅชๆ˜ฏๅฃฐๆ˜ŽๆŒ‡ๅฎšๆƒ้™็š„ๅญ—็ฌฆไธฒใ€‚ - ่ฟ™ไบ›็ป†่Š‚ๆ˜ฏๅ…ทไฝ“็š„ๅฎž็Žฐใ€‚ + ๆ˜ฏๅฆไฝฟ็”จๅ†’ๅท `:` ็ญ‰็ฌฆๅท๏ผŒๆˆ–ๆ˜ฏไธๆ˜ฏ URL ๅนถไธ้‡่ฆใ€‚ - ๅฏน OAuth2 ๆฅ่ฏดๅฎƒไปฌๅฐฑๅชๆ˜ฏๅญ—็ฌฆไธฒ่€Œๅทฒใ€‚ + ่ฟ™ไบ›็ป†่Š‚ๅชๆ˜ฏ็‰นๅฎš็š„ๅฎž็Žฐๆ–นๅผใ€‚ + + ๅฏน OAuth2 ๆฅ่ฏด๏ผŒ้ƒฝๅชๆ˜ฏๅญ—็ฌฆไธฒ่€Œๅทฒใ€‚ ## ่Žทๅ– `username` ๅ’Œ `password` ็š„ไปฃ็  -็Žฐๅœจ๏ผŒ่ฎฉๆˆ‘ไปฌไฝฟ็”จ **FastAPI** ๆไพ›็š„ๅฎž็”จๅทฅๅ…ทๆฅๅค„็†ๆญค้—ฎ้ข˜ใ€‚ +ๆŽฅไธ‹ๆฅ๏ผŒไฝฟ็”จ **FastAPI** ๅทฅๅ…ท่Žทๅ–็”จๆˆทๅไธŽๅฏ†็ ใ€‚ ### `OAuth2PasswordRequestForm` -้ฆ–ๅ…ˆ๏ผŒๅฏผๅ…ฅ `OAuth2PasswordRequestForm`๏ผŒ็„ถๅŽๅœจ `token` ็š„*่ทฏๅพ„ๆ“ไฝœ*ไธญ้€š่ฟ‡ `Depends` ๅฐ†ๅ…ถไฝœไธบไพ่ต–้กนไฝฟ็”จใ€‚ +้ฆ–ๅ…ˆ๏ผŒๅฏผๅ…ฅ `OAuth2PasswordRequestForm`๏ผŒ็„ถๅŽ๏ผŒๅœจ `/token` *่ทฏๅพ„ๆ“ไฝœ* ไธญ๏ผŒ็”จ `Depends` ๆŠŠ่ฏฅ็ฑปไฝœไธบไพ่ต–้กนใ€‚ ```Python hl_lines="4 76" {!../../../docs_src/security/tutorial003.py!} ``` -`OAuth2PasswordRequestForm` ๆ˜ฏไธ€ไธช็ฑปไพ่ต–้กน๏ผŒๅฃฐๆ˜Žไบ†ๅฆ‚ไธ‹็š„่ฏทๆฑ‚่กจๅ•๏ผš +`OAuth2PasswordRequestForm` ๆ˜ฏ็”จไปฅไธ‹ๅ‡ ้กนๅ†…ๅฎนๅฃฐๆ˜Ž่กจๅ•่ฏทๆฑ‚ไฝ“็š„็ฑปไพ่ต–้กน๏ผš -* `username`ใ€‚ -* `password`ใ€‚ -* ไธ€ไธชๅฏ้€‰็š„ `scope` ๅญ—ๆฎต๏ผŒๆ˜ฏไธ€ไธช็”ฑ็ฉบๆ ผๅˆ†้š”็š„ๅญ—็ฌฆไธฒ็ป„ๆˆ็š„ๅคงๅญ—็ฌฆไธฒใ€‚ -* ไธ€ไธชๅฏ้€‰็š„ `grant_type`. +* `username` +* `password` +* ๅฏ้€‰็š„ `scope` ๅญ—ๆฎต๏ผŒ็”ฑๅคšไธช็ฉบๆ ผๅˆ†้š”็š„ๅญ—็ฌฆไธฒ็ป„ๆˆ็š„้•ฟๅญ—็ฌฆไธฒ +* ๅฏ้€‰็š„ `grant_type` -!!! tip - OAuth2 ่ง„่Œƒๅฎž้™…ไธŠ*่ฆๆฑ‚* `grant_type` ๅญ—ๆฎตไฝฟ็”จไธ€ไธชๅ›บๅฎš็š„ๅ€ผ `password`๏ผŒไฝ†ๆ˜ฏ `OAuth2PasswordRequestForm` ๆฒกๆœ‰ไฝœๅผบๅˆถ็บฆๆŸใ€‚ +!!! tip "ๆ็คบ" - ๅฆ‚ๆžœไฝ ้œ€่ฆๅผบๅˆถ่ฆๆฑ‚่ฟ™ไธ€็‚น๏ผŒ่ฏทไฝฟ็”จ `OAuth2PasswordRequestFormStrict` ่€Œไธๆ˜ฏ `OAuth2PasswordRequestForm`ใ€‚ + ๅฎž้™…ไธŠ๏ผŒOAuth2 ่ง„่Œƒ*่ฆๆฑ‚* `grant_type` ๅญ—ๆฎตไฝฟ็”จๅ›บๅฎšๅ€ผ `password`๏ผŒไฝ† `OAuth2PasswordRequestForm` ๆฒกๆœ‰ไฝœๅผบๅˆถ็บฆๆŸใ€‚ -* ไธ€ไธชๅฏ้€‰็š„ `client_id`๏ผˆๆˆ‘ไปฌ็š„็คบไพ‹ไธ้œ€่ฆๅฎƒ๏ผ‰ใ€‚ -* ไธ€ไธชๅฏ้€‰็š„ `client_secret`๏ผˆๆˆ‘ไปฌ็š„็คบไพ‹ไธ้œ€่ฆๅฎƒ๏ผ‰ใ€‚ + ๅฆ‚้œ€ๅผบๅˆถไฝฟ็”จๅ›บๅฎšๅ€ผ `password`๏ผŒๅˆ™ไธ่ฆ็”จ `OAuth2PasswordRequestForm`๏ผŒ่€Œๆ˜ฏ็”จ `OAuth2PasswordRequestFormStrict`ใ€‚ -!!! info - `OAuth2PasswordRequestForm` ๅนถไธๅƒ `OAuth2PasswordBearer` ไธ€ๆ ทๆ˜ฏ FastAPI ็š„ไธ€ไธช็‰นๆฎŠ็š„็ฑปใ€‚ +* ๅฏ้€‰็š„ `client_id`๏ผˆๆœฌไพ‹ๆœชไฝฟ็”จ๏ผ‰ +* ๅฏ้€‰็š„ `client_secret`๏ผˆๆœฌไพ‹ๆœชไฝฟ็”จ๏ผ‰ - `OAuth2PasswordBearer` ไฝฟๅพ— **FastAPI** ๆ˜Ž็™ฝๅฎƒๆ˜ฏไธ€ไธชๅฎ‰ๅ…จๆ–นๆกˆใ€‚ๆ‰€ไปฅๅฎƒๅพ—ไปฅ้€š่ฟ‡่ฟ™็งๆ–นๅผๆทปๅŠ ๅˆฐ OpenAPI ไธญใ€‚ +!!! info "่ฏดๆ˜Ž" - ไฝ† `OAuth2PasswordRequestForm` ๅชๆ˜ฏไธ€ไธชไฝ ๅฏไปฅ่‡ชๅทฑ็ผ–ๅ†™็š„็ฑปไพ่ต–้กน๏ผŒๆˆ–่€…ไฝ ไนŸๅฏไปฅ็›ดๆŽฅๅฃฐๆ˜Ž `Form` ๅ‚ๆ•ฐใ€‚ + `OAuth2PasswordRequestForm` ไธŽ `OAuth2PasswordBearer` ไธ€ๆ ท๏ผŒ้ƒฝไธๆ˜ฏ FastAPI ็š„็‰นๆฎŠ็ฑปใ€‚ - ไฝ†ๆ˜ฏ็”ฑไบŽ่ฟ™ๆ˜ฏไธ€็งๅธธ่ง็š„ไฝฟ็”จๅœบๆ™ฏ๏ผŒๅ› ๆญค FastAPI ๅ‡บไบŽ็ฎ€ไพฟ็›ดๆŽฅๆไพ›ไบ†ๅฎƒใ€‚ + **FastAPI** ๆŠŠ `OAuth2PasswordBearer` ่ฏ†ๅˆซไธบๅฎ‰ๅ…จๆ–นๆกˆใ€‚ๅ› ๆญค๏ผŒๅฏไปฅ้€š่ฟ‡่ฟ™็งๆ–นๅผๆŠŠๅฎƒๆทปๅŠ ่‡ณ OpenAPIใ€‚ + + ไฝ† `OAuth2PasswordRequestForm` ๅชๆ˜ฏๅฏไปฅ่‡ช่กŒ็ผ–ๅ†™็š„็ฑปไพ่ต–้กน๏ผŒไนŸๅฏไปฅ็›ดๆŽฅๅฃฐๆ˜Ž `Form` ๅ‚ๆ•ฐใ€‚ + + ไฝ†็”ฑไบŽ่ฟ™็ง็”จไพ‹ๅพˆๅธธ่ง๏ผŒFastAPI ไธบไบ†็ฎ€ไพฟ๏ผŒๅฐฑ็›ดๆŽฅๆไพ›ไบ†ๅฏนๅฎƒ็š„ๆ”ฏๆŒใ€‚ ### ไฝฟ็”จ่กจๅ•ๆ•ฐๆฎ -!!! tip - ็ฑปไพ่ต–้กน `OAuth2PasswordRequestForm` ็š„ๅฎžไพ‹ไธไผšๆœ‰็”จ็ฉบๆ ผๅˆ†้š”็š„้•ฟๅญ—็ฌฆไธฒๅฑžๆ€ง `scope`๏ผŒ่€Œๆ˜ฏๅ…ทๆœ‰ไธ€ไธช `scopes` ๅฑžๆ€ง๏ผŒ่ฏฅๅฑžๆ€งๅฐ†ๅŒ…ๅซๅฎž้™…่ขซๅ‘้€็š„ๆฏไธชไฝœ็”จๅŸŸๅญ—็ฌฆไธฒ็ป„ๆˆ็š„ๅˆ—่กจใ€‚ +!!! tip "ๆ็คบ" - ๅœจๆญค็คบไพ‹ไธญๆˆ‘ไปฌๆฒกๆœ‰ไฝฟ็”จ `scopes`๏ผŒไฝ†ๅฆ‚ๆžœไฝ ้œ€่ฆ็š„่ฏๅฏไปฅไฝฟ็”จ่ฏฅๅŠŸ่ƒฝใ€‚ + `OAuth2PasswordRequestForm` ็ฑปไพ่ต–้กน็š„ๅฎžไพ‹ๆฒกๆœ‰ไปฅ็ฉบๆ ผๅˆ†้š”็š„้•ฟๅญ—็ฌฆไธฒๅฑžๆ€ง `scope`๏ผŒไฝ†ๅฎƒๆ”ฏๆŒ `scopes` ๅฑžๆ€ง๏ผŒ็”ฑๅทฒๅ‘้€็š„ scope ๅญ—็ฌฆไธฒๅˆ—่กจ็ป„ๆˆใ€‚ -็Žฐๅœจ๏ผŒไฝฟ็”จ่กจๅ•ๅญ—ๆฎตไธญ็š„ `username` ไปŽ๏ผˆไผช๏ผ‰ๆ•ฐๆฎๅบ“ไธญ่Žทๅ–็”จๆˆทๆ•ฐๆฎใ€‚ + ๆœฌไพ‹ๆฒกๆœ‰ไฝฟ็”จ `scopes`๏ผŒไฝ†ๅผ€ๅ‘่€…ไนŸๅฏไปฅๆ นๆฎ้œ€่ฆไฝฟ็”จ่ฏฅๅฑžๆ€งใ€‚ -ๅฆ‚ๆžœๆฒกๆœ‰่ฟ™ไธช็”จๆˆท๏ผŒๆˆ‘ไปฌๅฐ†่ฟ”ๅ›žไธ€ไธช้”™่ฏฏๆถˆๆฏ๏ผŒๆ็คบใ€Œ็”จๆˆทๅๆˆ–ๅฏ†็ ้”™่ฏฏใ€ใ€‚ +็Žฐๅœจ๏ผŒๅณๅฏไฝฟ็”จ่กจๅ•ๅญ—ๆฎต `username`๏ผŒไปŽ๏ผˆไผช๏ผ‰ๆ•ฐๆฎๅบ“ไธญ่Žทๅ–็”จๆˆทๆ•ฐๆฎใ€‚ -ๅฏนไบŽ่ฟ™ไธช้”™่ฏฏ๏ผŒๆˆ‘ไปฌไฝฟ็”จ `HTTPException` ๅผ‚ๅธธ๏ผš +ๅฆ‚ๆžœไธๅญ˜ๅœจๆŒ‡ๅฎš็”จๆˆท๏ผŒๅˆ™่ฟ”ๅ›ž้”™่ฏฏๆถˆๆฏ๏ผŒๆ็คบ**็”จๆˆทๅๆˆ–ๅฏ†็ ้”™่ฏฏ**ใ€‚ + +ๆœฌไพ‹ไฝฟ็”จ `HTTPException` ๅผ‚ๅธธๆ˜พ็คบๆญค้”™่ฏฏ๏ผš ```Python hl_lines="3 77-79" {!../../../docs_src/security/tutorial003.py!} @@ -96,27 +100,27 @@ OAuth2 ่ง„ๅฎšๅœจไฝฟ็”จ๏ผˆๆˆ‘ไปฌๆ‰“็ฎ—็”จ็š„๏ผ‰ใ€Œpassword ๆต็จ‹ใ€ๆ—ถ๏ผŒๅฎขๆˆท ### ๆ ก้ชŒๅฏ†็  -็›ฎๅ‰ๆˆ‘ไปฌๅทฒ็ปไปŽๆ•ฐๆฎๅบ“ไธญ่Žทๅ–ไบ†็”จๆˆทๆ•ฐๆฎ๏ผŒไฝ†ๅฐšๆœชๆ ก้ชŒๅฏ†็ ใ€‚ +่‡ณๆญค๏ผŒๆˆ‘ไปฌๅทฒ็ปไปŽๆ•ฐๆฎๅบ“ไธญ่Žทๅ–ไบ†็”จๆˆทๆ•ฐๆฎ๏ผŒไฝ†ๅฐšๆœชๆ ก้ชŒๅฏ†็ ใ€‚ -่ฎฉๆˆ‘ไปฌ้ฆ–ๅ…ˆๅฐ†่ฟ™ไบ›ๆ•ฐๆฎๆ”พๅ…ฅ Pydantic `UserInDB` ๆจกๅž‹ไธญใ€‚ +ๆŽฅไธ‹ๆฅ๏ผŒ้ฆ–ๅ…ˆๅฐ†ๆ•ฐๆฎๆ”พๅ…ฅ Pydantic ็š„ `UserInDB` ๆจกๅž‹ใ€‚ -ๆฐธ่ฟœไธ่ฆไฟๅญ˜ๆ˜Žๆ–‡ๅฏ†็ ๏ผŒๅ› ๆญค๏ผŒๆˆ‘ไปฌๅฐ†ไฝฟ็”จ๏ผˆไผช๏ผ‰ๅ“ˆๅธŒๅฏ†็ ็ณป็ปŸใ€‚ +ๆณจๆ„๏ผšๆฐธ่ฟœไธ่ฆไฟๅญ˜ๆ˜Žๆ–‡ๅฏ†็ ๏ผŒๆœฌไพ‹ๆš‚ๆ—ถๅ…ˆไฝฟ็”จ๏ผˆไผช๏ผ‰ๅ“ˆๅธŒๅฏ†็ ็ณป็ปŸใ€‚ -ๅฆ‚ๆžœๅฏ†็ ไธๅŒน้…๏ผŒๆˆ‘ไปฌๅฐ†่ฟ”ๅ›žๅŒไธ€ไธช้”™่ฏฏใ€‚ +ๅฆ‚ๆžœๅฏ†็ ไธๅŒน้…๏ผŒๅˆ™่ฟ”ๅ›žไธŽไธŠ้ข็›ธๅŒ็š„้”™่ฏฏใ€‚ -#### ๅ“ˆๅธŒๅฏ†็  +#### ๅฏ†็ ๅ“ˆๅธŒ -ใ€Œๅ“ˆๅธŒใ€็š„ๆ„ๆ€ๆ˜ฏ๏ผšๅฐ†ๆŸไบ›ๅ†…ๅฎน๏ผˆๅœจๆœฌไพ‹ไธญไธบๅฏ†็ ๏ผ‰่ฝฌๆขไธบ็œ‹่ตทๆฅๅƒไนฑ็ ็š„ๅญ—่Š‚ๅบๅˆ—๏ผˆๅชๆ˜ฏไธ€ไธชๅญ—็ฌฆไธฒ๏ผ‰ใ€‚ +**ๅ“ˆๅธŒ**ๆ˜ฏๆŒ‡๏ผŒๅฐ†ๆŒ‡ๅฎšๅ†…ๅฎน๏ผˆๆœฌไพ‹ไธญไธบๅฏ†็ ๏ผ‰่ฝฌๆขไธบๅฝขไผผไนฑ็ ็š„ๅญ—่Š‚ๅบๅˆ—๏ผˆๅ…ถๅฎžๅฐฑๆ˜ฏๅญ—็ฌฆไธฒ๏ผ‰ใ€‚ -ๆฏๆฌกไฝ ไผ ๅ…ฅๅฎŒๅ…จ็›ธๅŒ็š„ๅ†…ๅฎน๏ผˆๅฎŒๅ…จ็›ธๅŒ็š„ๅฏ†็ ๏ผ‰ๆ—ถ๏ผŒไฝ ้ƒฝไผšๅพ—ๅˆฐๅฎŒๅ…จ็›ธๅŒ็š„ไนฑ็ ใ€‚ +ๆฏๆฌกไผ ๅ…ฅๅฎŒๅ…จ็›ธๅŒ็š„ๅ†…ๅฎน๏ผˆๆฏ”ๅฆ‚๏ผŒๅฎŒๅ…จ็›ธๅŒ็š„ๅฏ†็ ๏ผ‰ๆ—ถ๏ผŒๅพ—ๅˆฐ็š„้ƒฝๆ˜ฏๅฎŒๅ…จ็›ธๅŒ็š„ไนฑ็ ใ€‚ -ไฝ†ๆ˜ฏไฝ ไธ่ƒฝไปŽไนฑ็ ่ฝฌๆขๅ›žๅฏ†็ ใ€‚ +ไฝ†่ฟ™ไธชไนฑ็ ๆ— ๆณ•่ฝฌๆขๅ›žไผ ๅ…ฅ็š„ๅฏ†็ ใ€‚ -##### ไธบไป€ไนˆไฝฟ็”จๅ“ˆๅธŒๅฏ†็  +##### ไธบไป€ไนˆไฝฟ็”จๅฏ†็ ๅ“ˆๅธŒ -ๅฆ‚ๆžœไฝ ็š„ๆ•ฐๆฎๅบ“่ขซ็›—๏ผŒๅฐๅทๅฐ†ๆ— ๆณ•่Žทๅพ—็”จๆˆท็š„ๆ˜Žๆ–‡ๅฏ†็ ๏ผŒๅชๆœ‰ๅ“ˆๅธŒๅ€ผใ€‚ +ๅŽŸๅ› ๅพˆ็ฎ€ๅ•๏ผŒๅ‡ๅฆ‚ๆ•ฐๆฎๅบ“่ขซ็›—๏ผŒ็ชƒ่ดผๆ— ๆณ•่Žทๅ–็”จๆˆท็š„ๆ˜Žๆ–‡ๅฏ†็ ๏ผŒๅพ—ๅˆฐ็š„ๅชๆ˜ฏๅ“ˆๅธŒๅ€ผใ€‚ -ๅ› ๆญค๏ผŒๅฐๅทๅฐ†ๆ— ๆณ•ๅฐ่ฏ•ๅœจๅฆไธ€ไธช็ณป็ปŸไธญไฝฟ็”จ่ฟ™ไบ›็›ธๅŒ็š„ๅฏ†็ ๏ผˆ็”ฑไบŽ่ฎธๅคš็”จๆˆทๅœจไปปไฝ•ๅœฐๆ–น้ƒฝไฝฟ็”จ็›ธๅŒ็š„ๅฏ†็ ๏ผŒๅ› ๆญค่ฟ™ๅพˆๅฑ้™ฉ๏ผ‰ใ€‚ +่ฟ™ๆ ทไธ€ๆฅ๏ผŒ็ชƒ่ดผๅฐฑๆ— ๆณ•ๅœจๅ…ถๅฎƒๅบ”็”จไธญไฝฟ็”จ็ชƒๅ–็š„ๅฏ†็ ๏ผŒ่ฆ็Ÿฅ้“๏ผŒๅพˆๅคš็”จๆˆทๅœจๆ‰€ๆœ‰็ณป็ปŸไธญ้ƒฝไฝฟ็”จ็›ธๅŒ็š„ๅฏ†็ ๏ผŒ้ฃŽ้™ฉ่ถ…ๅคงใ€‚ ```Python hl_lines="80-83" {!../../../docs_src/security/tutorial003.py!} @@ -124,9 +128,9 @@ OAuth2 ่ง„ๅฎšๅœจไฝฟ็”จ๏ผˆๆˆ‘ไปฌๆ‰“็ฎ—็”จ็š„๏ผ‰ใ€Œpassword ๆต็จ‹ใ€ๆ—ถ๏ผŒๅฎขๆˆท #### ๅ…ณไบŽ `**user_dict` -`UserInDB(**user_dict)` ่กจ็คบ๏ผš +`UserInDB(**user_dict)` ๆ˜ฏๆŒ‡๏ผš -*็›ดๆŽฅๅฐ† `user_dict` ็š„้”ฎๅ’Œๅ€ผไฝœไธบๅ…ณ้”ฎๅญ—ๅ‚ๆ•ฐไผ ้€’๏ผŒ็ญ‰ๅŒไบŽ๏ผš* +*็›ดๆŽฅๆŠŠ `user_dict` ็š„้”ฎไธŽๅ€ผๅฝ“ไฝœๅ…ณ้”ฎๅญ—ๅ‚ๆ•ฐไผ ้€’๏ผŒ็ญ‰ๆ•ˆไบŽ๏ผš* ```Python UserInDB( @@ -138,75 +142,79 @@ UserInDB( ) ``` -!!! info - ๆœ‰ๅ…ณ `user_dict` ็š„ๆ›ดๅฎŒๆ•ด่ฏดๆ˜Ž๏ผŒ่ฏทๅ‚้˜…[**้ขๅค–็š„ๆจกๅž‹**ๆ–‡ๆกฃ](../extra-models.md#about-user_indict){.internal-link target=_blank}ใ€‚ +!!! info "่ฏดๆ˜Ž" -## ่ฟ”ๅ›žไปค็‰Œ + `user_dict` ็š„่ฏดๆ˜Ž๏ผŒ่ฏฆ่ง[**ๆ›ดๅคšๆจกๅž‹**ไธ€็ซ ](../extra-models.md#about-user_indict){.internal-link target=_blank}ใ€‚ -`token` ็ซฏ็‚น็š„ๅ“ๅบ”ๅฟ…้กปๆ˜ฏไธ€ไธช JSON ๅฏน่ฑกใ€‚ +## ่ฟ”ๅ›ž Token -ๅฎƒๅบ”่ฏฅๆœ‰ไธ€ไธช `token_type`ใ€‚ๅœจๆˆ‘ไปฌ็š„ไพ‹ๅญไธญ๏ผŒ็”ฑไบŽๆˆ‘ไปฌไฝฟ็”จ็š„ๆ˜ฏใ€ŒBearerใ€ไปค็‰Œ๏ผŒๅ› ๆญคไปค็‰Œ็ฑปๅž‹ๅบ”ไธบใ€Œ`bearer`ใ€ใ€‚ +`token` ็ซฏ็‚น็š„ๅ“ๅบ”ๅฟ…้กปๆ˜ฏ JSON ๅฏน่ฑกใ€‚ -ๅนถไธ”่ฟ˜ๅบ”่ฏฅๆœ‰ไธ€ไธช `access_token` ๅญ—ๆฎต๏ผŒๅฎƒๆ˜ฏไธ€ไธชๅŒ…ๅซๆˆ‘ไปฌ็š„่ฎฟ้—ฎไปค็‰Œ็š„ๅญ—็ฌฆไธฒใ€‚ +ๅ“ๅบ”่ฟ”ๅ›ž็š„ๅ†…ๅฎนๅบ”่ฏฅๅŒ…ๅซ `token_type`ใ€‚ๆœฌไพ‹ไธญ็”จ็š„ๆ˜ฏ**Bearer**Token๏ผŒๅ› ๆญค๏ผŒ Token ็ฑปๅž‹ๅบ”ไธบ**`bearer`**ใ€‚ -ๅฏนไบŽ่ฟ™ไธช็ฎ€ๅ•็š„็คบไพ‹๏ผŒๆˆ‘ไปฌๅฐ†ๆžๅ…ถไธๅฎ‰ๅ…จๅœฐ่ฟ”ๅ›ž็›ธๅŒ็š„ `username` ไฝœไธบไปค็‰Œใ€‚ +่ฟ”ๅ›žๅ†…ๅฎน่ฟ˜ๅบ”ๅŒ…ๅซ `access_token` ๅญ—ๆฎต๏ผŒๅฎƒๆ˜ฏๅŒ…ๅซๆƒ้™ Token ็š„ๅญ—็ฌฆไธฒใ€‚ -!!! tip - ๅœจไธ‹ไธ€็ซ ไธญ๏ผŒไฝ ๅฐ†็œ‹ๅˆฐไธ€ไธช็œŸๅฎž็š„ๅฎ‰ๅ…จๅฎž็Žฐ๏ผŒไฝฟ็”จไบ†ๅ“ˆๅธŒๅฏ†็ ๅ’Œ JWT ไปค็‰Œใ€‚ +ๆœฌไพ‹ๅชๆ˜ฏ็ฎ€ๅ•็š„ๆผ”็คบ๏ผŒ่ฟ”ๅ›ž็š„ Token ๅฐฑๆ˜ฏ `username`๏ผŒไฝ†่ฟ™็งๆ–นๅผๆžไธๅฎ‰ๅ…จใ€‚ - ไฝ†็Žฐๅœจ๏ผŒ่ฎฉๆˆ‘ไปฌไป…ๅ…ณๆณจๆˆ‘ไปฌ้œ€่ฆ็š„็‰นๅฎš็ป†่Š‚ใ€‚ +!!! tip "ๆ็คบ" + + ไธ‹ไธ€็ซ ไป‹็ปไฝฟ็”จๅ“ˆๅธŒๅฏ†็ ๅ’Œ JWT Token ็š„็œŸๆญฃๅฎ‰ๅ…จๆœบๅˆถใ€‚ + + ไฝ†็Žฐๅœจ๏ผŒไป…ๅ…ณๆณจๆ‰€้œ€็š„็‰นๅฎš็ป†่Š‚ใ€‚ ```Python hl_lines="85" {!../../../docs_src/security/tutorial003.py!} ``` -!!! tip - ๆ นๆฎ่ง„่Œƒ๏ผŒไฝ ๅบ”่ฏฅๅƒๆœฌ็คบไพ‹ไธ€ๆ ท๏ผŒ่ฟ”ๅ›žไธ€ไธชๅธฆๆœ‰ `access_token` ๅ’Œ `token_type` ็š„ JSONใ€‚ +!!! tip "ๆ็คบ" - ่ฟ™ๆ˜ฏไฝ ๅฟ…้กปๅœจไปฃ็ ไธญ่‡ช่กŒๅฎŒๆˆ็š„ๅทฅไฝœ๏ผŒๅนถไธ”่ฆ็กฎไฟไฝฟ็”จไบ†่ฟ™ไบ› JSON ๅญ—ๆฎตใ€‚ + ๆŒ‰่ง„่Œƒ็š„่ฆๆฑ‚๏ผŒๅบ”ๅƒๆœฌ็คบไพ‹ไธ€ๆ ท๏ผŒ่ฟ”ๅ›žๅธฆๆœ‰ `access_token` ๅ’Œ `token_type` ็š„ JSON ๅฏน่ฑกใ€‚ - ่ฟ™ๅ‡ ไนŽๆ˜ฏๅ”ฏไธ€็š„ไฝ ้œ€่ฆ่‡ชๅทฑ่ฎฐไฝๅนถๆญฃ็กฎๅœฐๆ‰ง่กŒไปฅ็ฌฆๅˆ่ง„่Œƒ็š„ไบ‹ๆƒ…ใ€‚ + ่ฟ™ๆ˜ฏๅผ€ๅ‘่€…ๅฟ…้กปๅœจไปฃ็ ไธญ่‡ช่กŒๅฎŒๆˆ็š„ๅทฅไฝœ๏ผŒๅนถไธ”่ฆ็กฎไฟไฝฟ็”จ่ฟ™ไบ› JSON ็š„้”ฎใ€‚ - ๅ…ถไฝ™็š„๏ผŒ**FastAPI** ้ƒฝไผšไธบไฝ ๅค„็†ใ€‚ + ่ฟ™ๅ‡ ไนŽๆ˜ฏๅ”ฏไธ€้œ€่ฆๅผ€ๅ‘่€…็‰ข่ฎฐๅœจๅฟƒ๏ผŒๅนถๆŒ‰่ง„่Œƒ่ฆๆฑ‚ๆญฃ็กฎๆ‰ง่กŒ็š„ไบ‹ใ€‚ + + **FastAPI** ๅˆ™่ดŸ่ดฃๅค„็†ๅ…ถๅฎƒ็š„ๅทฅไฝœใ€‚ ## ๆ›ดๆ–ฐไพ่ต–้กน -็Žฐๅœจๆˆ‘ไปฌๅฐ†ๆ›ดๆ–ฐๆˆ‘ไปฌ็š„ไพ่ต–้กนใ€‚ +ๆŽฅไธ‹ๆฅ๏ผŒๆ›ดๆ–ฐไพ่ต–้กนใ€‚ -ๆˆ‘ไปฌๆƒณ่ฆไป…ๅฝ“ๆญค็”จๆˆทๅค„ไบŽๅฏ็”จ็Šถๆ€ๆ—ถๆ‰่ƒฝ่Žทๅ– `current_user`ใ€‚ +ไฝฟไน‹ไป…ๅœจๅฝ“ๅ‰็”จๆˆทไธบๆฟ€ๆดป็Šถๆ€ๆ—ถ๏ผŒๆ‰่ƒฝ่Žทๅ– `current_user`ใ€‚ -ๅ› ๆญค๏ผŒๆˆ‘ไปฌๅˆ›ๅปบไบ†ไธ€ไธช้ขๅค–็š„ไพ่ต–้กน `get_current_active_user`๏ผŒ่€Œ่ฏฅไพ่ต–้กนๅˆไปฅ `get_current_user` ไฝœไธบไพ่ต–้กนใ€‚ +ไธบๆญค๏ผŒ่ฆๅ†ๅˆ›ๅปบไธ€ไธชไพ่ต–้กน `get_current_active_user`๏ผŒๆญคไพ่ต–้กนไปฅ `get_current_user` ไพ่ต–้กนไธบๅŸบ็ก€ใ€‚ -ๅฆ‚ๆžœ็”จๆˆทไธๅญ˜ๅœจๆˆ–ๅค„ไบŽๆœชๅฏ็”จ็Šถๆ€๏ผŒๅˆ™่ฟ™ไธคไธชไพ่ต–้กน้ƒฝๅฐ†ไป…่ฟ”ๅ›ž HTTP ้”™่ฏฏใ€‚ +ๅฆ‚ๆžœ็”จๆˆทไธๅญ˜ๅœจ๏ผŒๆˆ–็Šถๆ€ไธบๆœชๆฟ€ๆดป๏ผŒ่ฟ™ไธคไธชไพ่ต–้กน้ƒฝไผš่ฟ”ๅ›ž HTTP ้”™่ฏฏใ€‚ -ๅ› ๆญค๏ผŒๅœจๆˆ‘ไปฌ็š„็ซฏ็‚นไธญ๏ผŒๅชๆœ‰ๅฝ“็”จๆˆทๅญ˜ๅœจ๏ผŒ่บซไปฝ่ฎค่ฏ้€š่ฟ‡ไธ”ๅค„ไบŽๅฏ็”จ็Šถๆ€ๆ—ถ๏ผŒๆˆ‘ไปฌๆ‰่ƒฝ่Žทๅพ—่ฏฅ็”จๆˆท๏ผš +ๅ› ๆญค๏ผŒๅœจ็ซฏ็‚นไธญ๏ผŒๅชๆœ‰ๅฝ“็”จๆˆทๅญ˜ๅœจใ€้€š่ฟ‡่บซไปฝ้ชŒ่ฏใ€ไธ”็Šถๆ€ไธบๆฟ€ๆดปๆ—ถ๏ผŒๆ‰่ƒฝ่Žทๅพ—่ฏฅ็”จๆˆท๏ผš ```Python hl_lines="58-67 69-72 90" {!../../../docs_src/security/tutorial003.py!} ``` -!!! info - ๆˆ‘ไปฌๅœจๆญคๅค„่ฟ”ๅ›ž็š„ๅ€ผไธบ `Bearer` ็š„้ขๅค–ๅ“ๅบ”ๅคด `WWW-Authenticate` ไนŸๆ˜ฏ่ง„่Œƒ็š„ไธ€้ƒจๅˆ†ใ€‚ +!!! info "่ฏดๆ˜Ž" - ไปปไฝ•็š„ 401ใ€Œๆœช่ฎค่ฏใ€HTTP๏ผˆ้”™่ฏฏ๏ผ‰็Šถๆ€็ ้ƒฝๅบ”่ฏฅ่ฟ”ๅ›ž `WWW-Authenticate` ๅ“ๅบ”ๅคดใ€‚ + ๆญคๅค„่ฟ”ๅ›žๅ€ผไธบ `Bearer` ็š„ๅ“ๅบ”ๅคด `WWW-Authenticate` ไนŸๆ˜ฏ่ง„่Œƒ็š„ไธ€้ƒจๅˆ†ใ€‚ - ๅฏนไบŽ bearer ไปค็‰Œ๏ผˆๆˆ‘ไปฌ็š„ไพ‹ๅญ๏ผ‰๏ผŒ่ฏฅๅ“ๅบ”ๅคด็š„ๅ€ผๅบ”ไธบ `Bearer`ใ€‚ + ไปปไฝ• 401**UNAUTHORIZED**HTTP๏ผˆ้”™่ฏฏ๏ผ‰็Šถๆ€็ ้ƒฝๅบ”่ฟ”ๅ›ž `WWW-Authenticate` ๅ“ๅบ”ๅคดใ€‚ - ๅฎž้™…ไธŠไฝ ๅฏไปฅๅฟฝ็•ฅ่ฟ™ไธช้ขๅค–็š„ๅ“ๅบ”ๅคด๏ผŒไธไผšๆœ‰ไป€ไนˆ้—ฎ้ข˜ใ€‚ + ๆœฌไพ‹ไธญ๏ผŒๅ› ไธบไฝฟ็”จ็š„ๆ˜ฏ Bearer Token๏ผŒ่ฏฅๅ“ๅบ”ๅคด็š„ๅ€ผๅบ”ไธบ `Bearer`ใ€‚ - ไฝ†ๆญคๅค„ๆไพ›ไบ†ๅฎƒไปฅ็ฌฆๅˆ่ง„่Œƒใ€‚ + ๅฎž้™…ไธŠ๏ผŒๅฟฝ็•ฅ่ฟ™ไธช้™„ๅŠ ๅ“ๅบ”ๅคด๏ผŒไนŸไธไผšๆœ‰ไป€ไนˆ้—ฎ้ข˜ใ€‚ - ่€Œไธ”๏ผŒ๏ผˆ็Žฐๅœจๆˆ–ๅฐ†ๆฅ๏ผ‰ๅฏ่ƒฝไผšๆœ‰ๅทฅๅ…ทๆœŸๆœ›ๅพ—ๅˆฐๅนถไฝฟ็”จๅฎƒ๏ผŒ็„ถๅŽๅฏนไฝ ๆˆ–ไฝ ็š„็”จๆˆทๆœ‰็”จๅค„ใ€‚ + ไน‹ๆ‰€ไปฅๅœจๆญคๆไพ›่ฟ™ไธช้™„ๅŠ ๅ“ๅบ”ๅคด๏ผŒๆ˜ฏไธบไบ†็ฌฆๅˆ่ง„่Œƒ็š„่ฆๆฑ‚ใ€‚ - ่ฟ™ๅฐฑๆ˜ฏ้ตๅพชๆ ‡ๅ‡†็š„ๅฅฝๅค„... + ่ฏดไธๅฎšไป€ไนˆๆ—ถๅ€™๏ผŒๅฐฑๆœ‰ๅทฅๅ…ท็”จๅพ—ไธŠๅฎƒ๏ผŒ่€Œไธ”๏ผŒๅผ€ๅ‘่€…ๆˆ–็”จๆˆทไนŸๅฏ่ƒฝ็”จๅพ—ไธŠใ€‚ + + ่ฟ™ๅฐฑๆ˜ฏ้ตๅพชๆ ‡ๅ‡†็š„ๅฅฝๅค„โ€ฆโ€ฆ ## ๅฎž้™…ๆ•ˆๆžœ -ๆ‰“ๅผ€ไบคไบ’ๅผๆ–‡ๆกฃ๏ผšhttp://127.0.0.1:8000/docsใ€‚ +ๆ‰“ๅผ€ API ๆ–‡ๆกฃ๏ผšhttp://127.0.0.1:8000/docsใ€‚ -### ่บซไปฝ่ฎค่ฏ +### ่บซไปฝ้ชŒ่ฏ -็‚นๅ‡ปใ€ŒAuthorizeใ€ๆŒ‰้’ฎใ€‚ +็‚นๅ‡ป**Authorize**ๆŒ‰้’ฎใ€‚ ไฝฟ็”จไปฅไธ‹ๅ‡ญ่ฏ๏ผš @@ -216,15 +224,15 @@ UserInDB( -ๅœจ็ณป็ปŸไธญ่ฟ›่กŒ่บซไปฝ่ฎค่ฏๅŽ๏ผŒไฝ ๅฐ†็œ‹ๅˆฐ๏ผš +้€š่ฟ‡่บซไปฝ้ชŒ่ฏๅŽ๏ผŒๆ˜พ็คบไธ‹ๅ›พๆ‰€็คบ็š„ๅ†…ๅฎน๏ผš -### ่Žทๅ–ๆœฌไบบ็š„็”จๆˆทๆ•ฐๆฎ +### ่Žทๅ–ๅฝ“ๅ‰็”จๆˆทๆ•ฐๆฎ -็Žฐๅœจๆ‰ง่กŒ `/users/me` ่ทฏๅพ„็š„ `GET` ๆ“ไฝœใ€‚ +ไฝฟ็”จ `/users/me` ่ทฏๅพ„็š„ `GET` ๆ“ไฝœใ€‚ -ไฝ ๅฐ†่Žทๅพ—ไฝ ็š„็”จๆˆทๆ•ฐๆฎ๏ผŒๅฆ‚๏ผš +ๅฏไปฅๆๅ–ๅฆ‚ไธ‹ๅฝ“ๅ‰็”จๆˆทๆ•ฐๆฎ๏ผš ```JSON { @@ -238,7 +246,7 @@ UserInDB( -ๅฆ‚ๆžœไฝ ็‚นๅ‡ป้”ๅฎšๅ›พๆ ‡ๅนถๆณจ้”€๏ผŒ็„ถๅŽๅ†ๆฌกๅฐ่ฏ•ๅŒไธ€ๆ“ไฝœ๏ผŒๅˆ™ไผšๅพ—ๅˆฐ HTTP 401 ้”™่ฏฏ๏ผš +็‚นๅ‡ปๅฐ้”ๅ›พๆ ‡๏ผŒๆณจ้”€ๅŽ๏ผŒๅ†ๆ‰ง่กŒๅŒๆ ท็š„ๆ“ไฝœ๏ผŒๅˆ™ไผšๅพ—ๅˆฐ HTTP 401 ้”™่ฏฏ๏ผš ```JSON { @@ -246,17 +254,17 @@ UserInDB( } ``` -### ๆœชๅฏ็”จ็š„็”จๆˆท +### ๆœชๆฟ€ๆดป็”จๆˆท -็Žฐๅœจๅฐ่ฏ•ไฝฟ็”จๆœชๅฏ็”จ็š„็”จๆˆท๏ผŒๅนถ้€š่ฟ‡ไปฅไธ‹ๆ–นๅผ่ฟ›่กŒ่บซไปฝ่ฎค่ฏ๏ผš +ๆต‹่ฏ•ๆœชๆฟ€ๆดป็”จๆˆท๏ผŒ่พ“ๅ…ฅไปฅไธ‹ไฟกๆฏ๏ผŒ่ฟ›่กŒ่บซไปฝ้ชŒ่ฏ๏ผš ็”จๆˆทๅ๏ผš`alice` ๅฏ†็ ๏ผš`secret2` -็„ถๅŽๅฐ่ฏ•ๆ‰ง่กŒ `/users/me` ่ทฏๅพ„็š„ `GET` ๆ“ไฝœใ€‚ +็„ถๅŽ๏ผŒๆ‰ง่กŒ `/users/me` ่ทฏๅพ„็š„ `GET` ๆ“ไฝœใ€‚ -ไฝ ๅฐ†ๅพ—ๅˆฐไธ€ไธชใ€Œๆœชๅฏ็”จ็š„็”จๆˆทใ€้”™่ฏฏ๏ผŒๅฆ‚๏ผš +ๆ˜พ็คบไธ‹ๅˆ—**ๆœชๆฟ€ๆดป็”จๆˆท**้”™่ฏฏไฟกๆฏ๏ผš ```JSON { @@ -264,12 +272,12 @@ UserInDB( } ``` -## ๆ€ป็ป“ +## ๅฐ็ป“ -็Žฐๅœจไฝ ๆŽŒๆกไบ†ไธบไฝ ็š„ API ๅฎž็Žฐไธ€ไธชๅŸบไบŽ `username` ๅ’Œ `password` ็š„ๅฎŒๆ•ดๅฎ‰ๅ…จ็ณป็ปŸ็š„ๅทฅๅ…ทใ€‚ +ไฝฟ็”จๆœฌ็ซ ็š„ๅทฅๅ…ทๅฎž็ŽฐๅŸบไบŽ `username` ๅ’Œ `password` ็š„ๅฎŒๆ•ด API ๅฎ‰ๅ…จ็ณป็ปŸใ€‚ -ไฝฟ็”จ่ฟ™ไบ›ๅทฅๅ…ท๏ผŒไฝ ๅฏไปฅไฝฟๅฎ‰ๅ…จ็ณป็ปŸไธŽไปปไฝ•ๆ•ฐๆฎๅบ“ไปฅๅŠไปปไฝ•็”จๆˆทๆˆ–ๆ•ฐๆฎๆจกๅž‹ๅ…ผๅฎนใ€‚ +่ฟ™ไบ›ๅทฅๅ…ท่ฎฉๅฎ‰ๅ…จ็ณป็ปŸๅ…ผๅฎนไปปไฝ•ๆ•ฐๆฎๅบ“ใ€็”จๆˆทๅŠๆ•ฐๆฎๆจกๅž‹ใ€‚ -ๅ”ฏไธ€็ผบๅฐ‘็š„็ป†่Š‚ๆ˜ฏๅฎƒๅฎž้™…ไธŠ่ฟ˜ๅนถไธใ€Œๅฎ‰ๅ…จใ€ใ€‚ +ๅ”ฏไธ€ๆฌ ็ผบ็š„ๆ˜ฏ๏ผŒๅฎƒไป็„ถไธๆ˜ฏ็œŸ็š„**ๅฎ‰ๅ…จ**ใ€‚ -ๅœจไธ‹ไธ€็ซ ไธญ๏ผŒไฝ ๅฐ†็œ‹ๅˆฐๅฆ‚ไฝ•ไฝฟ็”จไธ€ไธชๅฎ‰ๅ…จ็š„ๅ“ˆๅธŒๅฏ†็ ๅบ“ๅ’Œ JWT ไปค็‰Œใ€‚ +ไธ‹ไธ€็ซ ๏ผŒไป‹็ปไฝฟ็”จๅฏ†็ ๅ“ˆๅธŒๆ”ฏๆŒๅบ“ไธŽ JWT ไปค็‰Œๅฎž็Žฐ็œŸๆญฃ็š„ๅฎ‰ๅ…จๆœบๅˆถใ€‚ diff --git a/docs/zh/docs/tutorial/sql-databases.md b/docs/zh/docs/tutorial/sql-databases.md index 482588f94..8b09dc677 100644 --- a/docs/zh/docs/tutorial/sql-databases.md +++ b/docs/zh/docs/tutorial/sql-databases.md @@ -258,7 +258,7 @@ connect_args={"check_same_thread": False} {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="3 6-8 11-12 23-24 27-28" {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -302,7 +302,7 @@ name: str {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15-17 31-34" {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -331,7 +331,7 @@ name: str {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15 19-20 31 36-37" {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -471,7 +471,7 @@ current_user.items {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="9" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -505,7 +505,7 @@ current_user.items {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="15-20" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -530,7 +530,7 @@ current_user.items {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="24 32 38 47 53" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -551,7 +551,7 @@ current_user.items {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="23-28 31-34 37-42 45-49 52-55" {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -650,7 +650,7 @@ def read_user(user_id: int, db: Session = Depends(get_db)): {!> ../../../docs_src/sql_databases/sql_app_py39/schemas.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/sql_databases/sql_app/schemas.py!} @@ -670,7 +670,7 @@ def read_user(user_id: int, db: Session = Depends(get_db)): {!> ../../../docs_src/sql_databases/sql_app_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/sql_databases/sql_app/main.py!} @@ -729,7 +729,7 @@ $ uvicorn sql_app.main:app --reload {!> ../../../docs_src/sql_databases/sql_app_py39/alt_main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python hl_lines="14-22" {!> ../../../docs_src/sql_databases/sql_app/alt_main.py!} diff --git a/docs/zh/docs/tutorial/testing.md b/docs/zh/docs/tutorial/testing.md index 41f01f8d8..77fff7596 100644 --- a/docs/zh/docs/tutorial/testing.md +++ b/docs/zh/docs/tutorial/testing.md @@ -122,7 +122,7 @@ {!> ../../../docs_src/app_testing/app_b_an_py39/main.py!} ``` -=== "Python 3.6+" +=== "Python 3.8+" ```Python {!> ../../../docs_src/app_testing/app_b_an/main.py!} @@ -137,7 +137,7 @@ {!> ../../../docs_src/app_testing/app_b_py310/main.py!} ``` -=== "Python 3.6+ non-Annotated" +=== "Python 3.8+ non-Annotated" !!! tip Prefer to use the `Annotated` version if possible. diff --git a/docs_src/extending_openapi/tutorial003.py b/docs_src/configure_swagger_ui/tutorial001.py similarity index 100% rename from docs_src/extending_openapi/tutorial003.py rename to docs_src/configure_swagger_ui/tutorial001.py diff --git a/docs_src/extending_openapi/tutorial004.py b/docs_src/configure_swagger_ui/tutorial002.py similarity index 100% rename from docs_src/extending_openapi/tutorial004.py rename to docs_src/configure_swagger_ui/tutorial002.py diff --git a/docs_src/extending_openapi/tutorial005.py b/docs_src/configure_swagger_ui/tutorial003.py similarity index 100% rename from docs_src/extending_openapi/tutorial005.py rename to docs_src/configure_swagger_ui/tutorial003.py diff --git a/docs_src/custom_docs_ui/tutorial001.py b/docs_src/custom_docs_ui/tutorial001.py new file mode 100644 index 000000000..4384433e3 --- /dev/null +++ b/docs_src/custom_docs_ui/tutorial001.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) + +app = FastAPI(docs_url=None, redoc_url=None) + + +@app.get("/docs", include_in_schema=False) +async def custom_swagger_ui_html(): + return get_swagger_ui_html( + openapi_url=app.openapi_url, + title=app.title + " - Swagger UI", + oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, + swagger_js_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js", + swagger_css_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css", + ) + + +@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) +async def swagger_ui_redirect(): + return get_swagger_ui_oauth2_redirect_html() + + +@app.get("/redoc", include_in_schema=False) +async def redoc_html(): + return get_redoc_html( + openapi_url=app.openapi_url, + title=app.title + " - ReDoc", + redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js", + ) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/extending_openapi/tutorial002.py b/docs_src/custom_docs_ui/tutorial002.py similarity index 100% rename from docs_src/extending_openapi/tutorial002.py rename to docs_src/custom_docs_ui/tutorial002.py diff --git a/docs_src/header_params/tutorial002_an.py b/docs_src/header_params/tutorial002_an.py index 65d972d46..82fe49ba2 100644 --- a/docs_src/header_params/tutorial002_an.py +++ b/docs_src/header_params/tutorial002_an.py @@ -10,6 +10,6 @@ app = FastAPI() async def read_items( strange_header: Annotated[ Union[str, None], Header(convert_underscores=False) - ] = None + ] = None, ): return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial002_an_py39.py b/docs_src/header_params/tutorial002_an_py39.py index 7f6a99f9c..008e4b6e1 100644 --- a/docs_src/header_params/tutorial002_an_py39.py +++ b/docs_src/header_params/tutorial002_an_py39.py @@ -9,6 +9,6 @@ app = FastAPI() async def read_items( strange_header: Annotated[ Union[str, None], Header(convert_underscores=False) - ] = None + ] = None, ): return {"strange_header": strange_header} diff --git a/docs_src/openapi_webhooks/tutorial001.py b/docs_src/openapi_webhooks/tutorial001.py index 5016f5b00..55822bb48 100644 --- a/docs_src/openapi_webhooks/tutorial001.py +++ b/docs_src/openapi_webhooks/tutorial001.py @@ -8,7 +8,7 @@ app = FastAPI() class Subscription(BaseModel): username: str - montly_fee: float + monthly_fee: float start_date: datetime diff --git a/docs_src/python_types/tutorial011.py b/docs_src/python_types/tutorial011.py index c8634cbff..297a84db6 100644 --- a/docs_src/python_types/tutorial011.py +++ b/docs_src/python_types/tutorial011.py @@ -6,7 +6,7 @@ from pydantic import BaseModel class User(BaseModel): id: int - name = "John Doe" + name: str = "John Doe" signup_ts: Union[datetime, None] = None friends: List[int] = [] diff --git a/docs_src/python_types/tutorial011_py310.py b/docs_src/python_types/tutorial011_py310.py index 7f173880f..842760c60 100644 --- a/docs_src/python_types/tutorial011_py310.py +++ b/docs_src/python_types/tutorial011_py310.py @@ -5,7 +5,7 @@ from pydantic import BaseModel class User(BaseModel): id: int - name = "John Doe" + name: str = "John Doe" signup_ts: datetime | None = None friends: list[int] = [] diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py index 468496f51..4eb40b405 100644 --- a/docs_src/python_types/tutorial011_py39.py +++ b/docs_src/python_types/tutorial011_py39.py @@ -6,7 +6,7 @@ from pydantic import BaseModel class User(BaseModel): id: int - name = "John Doe" + name: str = "John Doe" signup_ts: Union[datetime, None] = None friends: list[int] = [] diff --git a/docs_src/query_params_str_validations/tutorial004.py b/docs_src/query_params_str_validations/tutorial004.py index 3639b6c38..64a647a16 100644 --- a/docs_src/query_params_str_validations/tutorial004.py +++ b/docs_src/query_params_str_validations/tutorial004.py @@ -9,7 +9,7 @@ app = FastAPI() async def read_items( q: Union[str, None] = Query( default=None, min_length=3, max_length=50, pattern="^fixedquery$" - ) + ), ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial004_an.py b/docs_src/query_params_str_validations/tutorial004_an.py index 24698c7b3..c75d45d63 100644 --- a/docs_src/query_params_str_validations/tutorial004_an.py +++ b/docs_src/query_params_str_validations/tutorial004_an.py @@ -10,7 +10,7 @@ app = FastAPI() async def read_items( q: Annotated[ Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$") - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial004_an_py310.py b/docs_src/query_params_str_validations/tutorial004_an_py310.py index b7b629ee8..20cf1988f 100644 --- a/docs_src/query_params_str_validations/tutorial004_an_py310.py +++ b/docs_src/query_params_str_validations/tutorial004_an_py310.py @@ -9,7 +9,7 @@ app = FastAPI() async def read_items( q: Annotated[ str | None, Query(min_length=3, max_length=50, pattern="^fixedquery$") - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py b/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py index 8fd375b3d..21e0d3eb8 100644 --- a/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py +++ b/docs_src/query_params_str_validations/tutorial004_an_py310_regex.py @@ -9,7 +9,7 @@ app = FastAPI() async def read_items( q: Annotated[ str | None, Query(min_length=3, max_length=50, regex="^fixedquery$") - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial004_an_py39.py b/docs_src/query_params_str_validations/tutorial004_an_py39.py index 8e9a6fc32..de27097b3 100644 --- a/docs_src/query_params_str_validations/tutorial004_an_py39.py +++ b/docs_src/query_params_str_validations/tutorial004_an_py39.py @@ -9,7 +9,7 @@ app = FastAPI() async def read_items( q: Annotated[ Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$") - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial004_py310.py b/docs_src/query_params_str_validations/tutorial004_py310.py index f80798bcb..7801e7500 100644 --- a/docs_src/query_params_str_validations/tutorial004_py310.py +++ b/docs_src/query_params_str_validations/tutorial004_py310.py @@ -5,8 +5,9 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: str - | None = Query(default=None, min_length=3, max_length=50, pattern="^fixedquery$") + q: str | None = Query( + default=None, min_length=3, max_length=50, pattern="^fixedquery$" + ), ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial008.py b/docs_src/query_params_str_validations/tutorial008.py index d112a9ab8..e3e0b50aa 100644 --- a/docs_src/query_params_str_validations/tutorial008.py +++ b/docs_src/query_params_str_validations/tutorial008.py @@ -12,7 +12,7 @@ async def read_items( title="Query string", description="Query string for the items to search in the database that have a good match", min_length=3, - ) + ), ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial008_an.py b/docs_src/query_params_str_validations/tutorial008_an.py index 5699f1e88..01606a920 100644 --- a/docs_src/query_params_str_validations/tutorial008_an.py +++ b/docs_src/query_params_str_validations/tutorial008_an.py @@ -15,7 +15,7 @@ async def read_items( description="Query string for the items to search in the database that have a good match", min_length=3, ), - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial008_an_py310.py b/docs_src/query_params_str_validations/tutorial008_an_py310.py index 4aaadf8b4..44b3082b6 100644 --- a/docs_src/query_params_str_validations/tutorial008_an_py310.py +++ b/docs_src/query_params_str_validations/tutorial008_an_py310.py @@ -14,7 +14,7 @@ async def read_items( description="Query string for the items to search in the database that have a good match", min_length=3, ), - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial008_an_py39.py b/docs_src/query_params_str_validations/tutorial008_an_py39.py index 1c3b36176..f3f2f2c0e 100644 --- a/docs_src/query_params_str_validations/tutorial008_an_py39.py +++ b/docs_src/query_params_str_validations/tutorial008_an_py39.py @@ -14,7 +14,7 @@ async def read_items( description="Query string for the items to search in the database that have a good match", min_length=3, ), - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial008_py310.py b/docs_src/query_params_str_validations/tutorial008_py310.py index 489f631d5..574385272 100644 --- a/docs_src/query_params_str_validations/tutorial008_py310.py +++ b/docs_src/query_params_str_validations/tutorial008_py310.py @@ -5,13 +5,12 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: str - | None = Query( + q: str | None = Query( default=None, title="Query string", description="Query string for the items to search in the database that have a good match", min_length=3, - ) + ), ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial010.py b/docs_src/query_params_str_validations/tutorial010.py index 3314f8b6d..ff29176fe 100644 --- a/docs_src/query_params_str_validations/tutorial010.py +++ b/docs_src/query_params_str_validations/tutorial010.py @@ -16,7 +16,7 @@ async def read_items( max_length=50, pattern="^fixedquery$", deprecated=True, - ) + ), ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial010_an.py b/docs_src/query_params_str_validations/tutorial010_an.py index c5df00897..ed343230f 100644 --- a/docs_src/query_params_str_validations/tutorial010_an.py +++ b/docs_src/query_params_str_validations/tutorial010_an.py @@ -19,7 +19,7 @@ async def read_items( pattern="^fixedquery$", deprecated=True, ), - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial010_an_py310.py b/docs_src/query_params_str_validations/tutorial010_an_py310.py index a8e8c099b..775095bda 100644 --- a/docs_src/query_params_str_validations/tutorial010_an_py310.py +++ b/docs_src/query_params_str_validations/tutorial010_an_py310.py @@ -18,7 +18,7 @@ async def read_items( pattern="^fixedquery$", deprecated=True, ), - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial010_an_py39.py b/docs_src/query_params_str_validations/tutorial010_an_py39.py index 955880dd6..b126c116f 100644 --- a/docs_src/query_params_str_validations/tutorial010_an_py39.py +++ b/docs_src/query_params_str_validations/tutorial010_an_py39.py @@ -18,7 +18,7 @@ async def read_items( pattern="^fixedquery$", deprecated=True, ), - ] = None + ] = None, ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/query_params_str_validations/tutorial010_py310.py b/docs_src/query_params_str_validations/tutorial010_py310.py index 9ea7b3c49..530e6cf5b 100644 --- a/docs_src/query_params_str_validations/tutorial010_py310.py +++ b/docs_src/query_params_str_validations/tutorial010_py310.py @@ -5,8 +5,7 @@ app = FastAPI() @app.get("/items/") async def read_items( - q: str - | None = Query( + q: str | None = Query( default=None, alias="item-query", title="Query string", @@ -15,7 +14,7 @@ async def read_items( max_length=50, pattern="^fixedquery$", deprecated=True, - ) + ), ): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: diff --git a/docs_src/schema_extra_example/tutorial005.py b/docs_src/schema_extra_example/tutorial005.py new file mode 100644 index 000000000..b8217c27e --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005.py @@ -0,0 +1,51 @@ +from typing import Union + +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + price: float + tax: Union[float, None] = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item = Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_an.py b/docs_src/schema_extra_example/tutorial005_an.py new file mode 100644 index 000000000..4b2d9c662 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_an.py @@ -0,0 +1,55 @@ +from typing import Union + +from fastapi import Body, FastAPI +from pydantic import BaseModel +from typing_extensions import Annotated + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + price: float + tax: Union[float, None] = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Annotated[ + Item, + Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), + ], +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_an_py310.py b/docs_src/schema_extra_example/tutorial005_an_py310.py new file mode 100644 index 000000000..64dc2cf90 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_an_py310.py @@ -0,0 +1,54 @@ +from typing import Annotated + +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Annotated[ + Item, + Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), + ], +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_an_py39.py b/docs_src/schema_extra_example/tutorial005_an_py39.py new file mode 100644 index 000000000..edeb1affc --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_an_py39.py @@ -0,0 +1,54 @@ +from typing import Annotated, Union + +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + price: float + tax: Union[float, None] = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Annotated[ + Item, + Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), + ], +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/schema_extra_example/tutorial005_py310.py b/docs_src/schema_extra_example/tutorial005_py310.py new file mode 100644 index 000000000..eef973343 --- /dev/null +++ b/docs_src/schema_extra_example/tutorial005_py310.py @@ -0,0 +1,49 @@ +from fastapi import Body, FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str | None = None + price: float + tax: float | None = None + + +@app.put("/items/{item_id}") +async def update_item( + *, + item_id: int, + item: Item = Body( + openapi_examples={ + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": { + "name": "Bar", + "price": "35.4", + }, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + ), +): + results = {"item_id": item_id, "item": item} + return results diff --git a/docs_src/separate_openapi_schemas/tutorial001.py b/docs_src/separate_openapi_schemas/tutorial001.py new file mode 100644 index 000000000..415eef8e2 --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial001.py @@ -0,0 +1,28 @@ +from typing import List, Union + +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + + +app = FastAPI() + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> List[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial001_py310.py b/docs_src/separate_openapi_schemas/tutorial001_py310.py new file mode 100644 index 000000000..289cb54ed --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial001_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + + +app = FastAPI() + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial001_py39.py b/docs_src/separate_openapi_schemas/tutorial001_py39.py new file mode 100644 index 000000000..63cffd1e3 --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial001_py39.py @@ -0,0 +1,28 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: Optional[str] = None + + +app = FastAPI() + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial002.py b/docs_src/separate_openapi_schemas/tutorial002.py new file mode 100644 index 000000000..7df93783b --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial002.py @@ -0,0 +1,28 @@ +from typing import List, Union + +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: Union[str, None] = None + + +app = FastAPI(separate_input_output_schemas=False) + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> List[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial002_py310.py b/docs_src/separate_openapi_schemas/tutorial002_py310.py new file mode 100644 index 000000000..5db210872 --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial002_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: str | None = None + + +app = FastAPI(separate_input_output_schemas=False) + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/separate_openapi_schemas/tutorial002_py39.py b/docs_src/separate_openapi_schemas/tutorial002_py39.py new file mode 100644 index 000000000..50d997d92 --- /dev/null +++ b/docs_src/separate_openapi_schemas/tutorial002_py39.py @@ -0,0 +1,28 @@ +from typing import Optional + +from fastapi import FastAPI +from pydantic import BaseModel + + +class Item(BaseModel): + name: str + description: Optional[str] = None + + +app = FastAPI(separate_input_output_schemas=False) + + +@app.post("/items/") +def create_item(item: Item): + return item + + +@app.get("/items/") +def read_items() -> list[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + ), + Item(name="Plumbus"), + ] diff --git a/docs_src/settings/app02/main.py b/docs_src/settings/app02/main.py index 163aa2614..941f82e6b 100644 --- a/docs_src/settings/app02/main.py +++ b/docs_src/settings/app02/main.py @@ -7,7 +7,7 @@ from .config import Settings app = FastAPI() -@lru_cache() +@lru_cache def get_settings(): return Settings() diff --git a/docs_src/settings/app02_an/main.py b/docs_src/settings/app02_an/main.py index cb679202d..3a578cc33 100644 --- a/docs_src/settings/app02_an/main.py +++ b/docs_src/settings/app02_an/main.py @@ -8,7 +8,7 @@ from .config import Settings app = FastAPI() -@lru_cache() +@lru_cache def get_settings(): return Settings() diff --git a/docs_src/settings/app02_an_py39/main.py b/docs_src/settings/app02_an_py39/main.py index 61be74fcb..6d5db12a8 100644 --- a/docs_src/settings/app02_an_py39/main.py +++ b/docs_src/settings/app02_an_py39/main.py @@ -8,7 +8,7 @@ from .config import Settings app = FastAPI() -@lru_cache() +@lru_cache def get_settings(): return Settings() diff --git a/docs_src/settings/app03/main.py b/docs_src/settings/app03/main.py index 69bc8c6e0..ea64a5709 100644 --- a/docs_src/settings/app03/main.py +++ b/docs_src/settings/app03/main.py @@ -7,7 +7,7 @@ from . import config app = FastAPI() -@lru_cache() +@lru_cache def get_settings(): return config.Settings() diff --git a/docs_src/settings/app03_an/main.py b/docs_src/settings/app03_an/main.py index c33b98f47..2f64b9cd1 100644 --- a/docs_src/settings/app03_an/main.py +++ b/docs_src/settings/app03_an/main.py @@ -8,7 +8,7 @@ from . import config app = FastAPI() -@lru_cache() +@lru_cache def get_settings(): return config.Settings() diff --git a/docs_src/settings/app03_an_py39/main.py b/docs_src/settings/app03_an_py39/main.py index b89c6b6cf..62f347639 100644 --- a/docs_src/settings/app03_an_py39/main.py +++ b/docs_src/settings/app03_an_py39/main.py @@ -8,7 +8,7 @@ from . import config app = FastAPI() -@lru_cache() +@lru_cache def get_settings(): return config.Settings() diff --git a/fastapi/__init__.py b/fastapi/__init__.py index d8abf2103..dd16ea34d 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.101.1" +__version__ = "0.105.0" from starlette import status as status diff --git a/fastapi/_compat.py b/fastapi/_compat.py index 9ffcaf409..35d4a8723 100644 --- a/fastapi/_compat.py +++ b/fastapi/_compat.py @@ -58,9 +58,15 @@ if PYDANTIC_V2: from pydantic_core import CoreSchema as CoreSchema from pydantic_core import PydanticUndefined, PydanticUndefinedType from pydantic_core import Url as Url - from pydantic_core.core_schema import ( - general_plain_validator_function as general_plain_validator_function, - ) + + try: + from pydantic_core.core_schema import ( + with_info_plain_validator_function as with_info_plain_validator_function, + ) + except ImportError: # pragma: no cover + from pydantic_core.core_schema import ( + general_plain_validator_function as with_info_plain_validator_function, # noqa: F401 + ) Required = PydanticUndefined Undefined = PydanticUndefined @@ -181,15 +187,19 @@ if PYDANTIC_V2: field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Dict[str, Any]: + override_mode: Union[Literal["validation"], None] = ( + None if separate_input_output_schemas else "validation" + ) # This expects that GenerateJsonSchema was already used to generate the definitions - json_schema = field_mapping[(field, field.mode)] + json_schema = field_mapping[(field, override_mode or field.mode)] if "$ref" not in json_schema: # TODO remove when deprecating Pydantic v1 # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207 - json_schema[ - "title" - ] = field.field_info.title or field.alias.title().replace("_", " ") + json_schema["title"] = ( + field.field_info.title or field.alias.title().replace("_", " ") + ) return json_schema def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap: @@ -200,14 +210,19 @@ if PYDANTIC_V2: fields: List[ModelField], schema_generator: GenerateJsonSchema, model_name_map: ModelNameMap, + separate_input_output_schemas: bool = True, ) -> Tuple[ Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], Dict[str, Dict[str, Any]], ]: + override_mode: Union[Literal["validation"], None] = ( + None if separate_input_output_schemas else "validation" + ) inputs = [ - (field, field.mode, field._type_adapter.core_schema) for field in fields + (field, override_mode or field.mode, field._type_adapter.core_schema) + for field in fields ] field_mapping, definitions = schema_generator.generate_definitions( inputs=inputs @@ -234,7 +249,12 @@ if PYDANTIC_V2: return is_bytes_sequence_annotation(field.type_) def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: - return type(field_info).from_annotation(annotation) + cls = type(field_info) + merged_field_info = cls.from_annotation(annotation) + new_field_info = copy(field_info) + new_field_info.metadata = merged_field_info.metadata + new_field_info.annotation = merged_field_info.annotation + return new_field_info def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: origin_type = ( @@ -336,7 +356,7 @@ else: class PydanticSchemaGenerationError(Exception): # type: ignore[no-redef] pass - def general_plain_validator_function( # type: ignore[misc] + def with_info_plain_validator_function( # type: ignore[misc] function: Callable[..., Any], *, ref: Union[str, None] = None, @@ -429,6 +449,7 @@ else: field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Dict[str, Any]: # This expects that GenerateJsonSchema was already used to generate the definitions return field_schema( # type: ignore[no-any-return] @@ -444,6 +465,7 @@ else: fields: List[ModelField], schema_generator: GenerateJsonSchema, model_name_map: ModelNameMap, + separate_input_output_schemas: bool = True, ) -> Tuple[ Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue diff --git a/fastapi/applications.py b/fastapi/applications.py index e32cfa03d..3021d7593 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -43,56 +43,785 @@ from starlette.requests import Request from starlette.responses import HTMLResponse, JSONResponse, Response from starlette.routing import BaseRoute from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send +from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined] AppType = TypeVar("AppType", bound="FastAPI") class FastAPI(Starlette): + """ + `FastAPI` app class, the main entrypoint to use FastAPI. + + Read more in the + [FastAPI docs for First Steps](https://fastapi.tiangolo.com/tutorial/first-steps/). + + ## Example + + ```python + from fastapi import FastAPI + + app = FastAPI() + ``` + """ + def __init__( self: AppType, *, - debug: bool = False, - routes: Optional[List[BaseRoute]] = None, - title: str = "FastAPI", - summary: Optional[str] = None, - description: str = "", - version: str = "0.1.0", - openapi_url: Optional[str] = "/openapi.json", - openapi_tags: Optional[List[Dict[str, Any]]] = None, - servers: Optional[List[Dict[str, Union[str, Any]]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - default_response_class: Type[Response] = Default(JSONResponse), - redirect_slashes: bool = True, - docs_url: Optional[str] = "/docs", - redoc_url: Optional[str] = "/redoc", - swagger_ui_oauth2_redirect_url: Optional[str] = "/docs/oauth2-redirect", - swagger_ui_init_oauth: Optional[Dict[str, Any]] = None, - middleware: Optional[Sequence[Middleware]] = None, - exception_handlers: Optional[ - Dict[ - Union[int, Type[Exception]], - Callable[[Request, Any], Coroutine[Any, Any, Response]], - ] + debug: Annotated[ + bool, + Doc( + """ + Boolean indicating if debug tracebacks should be returned on server + errors. + + Read more in the + [Starlette docs for Applications](https://www.starlette.io/applications/#instantiating-the-application). + """ + ), + ] = False, + routes: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + **Note**: you probably shouldn't use this parameter, it is inherited + from Starlette and supported for compatibility. + + --- + + A list of routes to serve incoming HTTP and WebSocket requests. + """ + ), + deprecated( + """ + You normally wouldn't use this parameter with FastAPI, it is inherited + from Starlette and supported for compatibility. + + In FastAPI, you normally would use the *path operation methods*, + like `app.get()`, `app.post()`, etc. + """ + ), ] = None, - on_startup: Optional[Sequence[Callable[[], Any]]] = None, - on_shutdown: Optional[Sequence[Callable[[], Any]]] = None, - lifespan: Optional[Lifespan[AppType]] = None, - terms_of_service: Optional[str] = None, - contact: Optional[Dict[str, Union[str, Any]]] = None, - license_info: Optional[Dict[str, Union[str, Any]]] = None, - openapi_prefix: str = "", - root_path: str = "", - root_path_in_servers: bool = True, - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - callbacks: Optional[List[BaseRoute]] = None, - webhooks: Optional[routing.APIRouter] = None, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - swagger_ui_parameters: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), - **extra: Any, + title: Annotated[ + str, + Doc( + """ + The title of the API. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(title="ChimichangApp") + ``` + """ + ), + ] = "FastAPI", + summary: Annotated[ + Optional[str], + Doc( + """ + A short summary of the API. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(summary="Deadpond's favorite app. Nuff said.") + ``` + """ + ), + ] = None, + description: Annotated[ + str, + Doc( + ''' + A description of the API. Supports Markdown (using + [CommonMark syntax](https://commonmark.org/)). + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI( + description=""" + ChimichangApp API helps you do awesome stuff. ๐Ÿš€ + + ## Items + + You can **read items**. + + ## Users + + You will be able to: + + * **Create users** (_not implemented_). + * **Read users** (_not implemented_). + + """ + ) + ``` + ''' + ), + ] = "", + version: Annotated[ + str, + Doc( + """ + The version of the API. + + **Note** This is the version of your application, not the version of + the OpenAPI specification nor the version of FastAPI being used. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(version="0.0.1") + ``` + """ + ), + ] = "0.1.0", + openapi_url: Annotated[ + Optional[str], + Doc( + """ + The URL where the OpenAPI schema will be served from. + + If you set it to `None`, no OpenAPI schema will be served publicly, and + the default automatic endpoints `/docs` and `/redoc` will also be + disabled. + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#openapi-url). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(openapi_url="/api/v1/openapi.json") + ``` + """ + ), + ] = "/openapi.json", + openapi_tags: Annotated[ + Optional[List[Dict[str, Any]]], + Doc( + """ + A list of tags used by OpenAPI, these are the same `tags` you can set + in the *path operations*, like: + + * `@app.get("/users/", tags=["users"])` + * `@app.get("/items/", tags=["items"])` + + The order of the tags can be used to specify the order shown in + tools like Swagger UI, used in the automatic path `/docs`. + + It's not required to specify all the tags used. + + The tags that are not declared MAY be organized randomly or based + on the tools' logic. Each tag name in the list MUST be unique. + + The value of each item is a `dict` containing: + + * `name`: The name of the tag. + * `description`: A short description of the tag. + [CommonMark syntax](https://commonmark.org/) MAY be used for rich + text representation. + * `externalDocs`: Additional external documentation for this tag. If + provided, it would contain a `dict` with: + * `description`: A short description of the target documentation. + [CommonMark syntax](https://commonmark.org/) MAY be used for + rich text representation. + * `url`: The URL for the target documentation. Value MUST be in + the form of a URL. + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-tags). + + **Example** + + ```python + from fastapi import FastAPI + + tags_metadata = [ + { + "name": "users", + "description": "Operations with users. The **login** logic is also here.", + }, + { + "name": "items", + "description": "Manage items. So _fancy_ they have their own docs.", + "externalDocs": { + "description": "Items external docs", + "url": "https://fastapi.tiangolo.com/", + }, + }, + ] + + app = FastAPI(openapi_tags=tags_metadata) + ``` + """ + ), + ] = None, + servers: Annotated[ + Optional[List[Dict[str, Union[str, Any]]]], + Doc( + """ + A `list` of `dict`s with connectivity information to a target server. + + You would use it, for example, if your application is served from + different domains and you want to use the same Swagger UI in the + browser to interact with each of them (instead of having multiple + browser tabs open). Or if you want to leave fixed the possible URLs. + + If the servers `list` is not provided, or is an empty `list`, the + default value would be a a `dict` with a `url` value of `/`. + + Each item in the `list` is a `dict` containing: + + * `url`: A URL to the target host. This URL supports Server Variables + and MAY be relative, to indicate that the host location is relative + to the location where the OpenAPI document is being served. Variable + substitutions will be made when a variable is named in `{`brackets`}`. + * `description`: An optional string describing the host designated by + the URL. [CommonMark syntax](https://commonmark.org/) MAY be used for + rich text representation. + * `variables`: A `dict` between a variable name and its value. The value + is used for substitution in the server's URL template. + + Read more in the + [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#additional-servers). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI( + servers=[ + {"url": "https://stag.example.com", "description": "Staging environment"}, + {"url": "https://prod.example.com", "description": "Production environment"}, + ] + ) + ``` + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of global dependencies, they will be applied to each + *path operation*, including in sub-routers. + + Read more about it in the + [FastAPI docs for Global Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/global-dependencies/). + + **Example** + + ```python + from fastapi import Depends, FastAPI + + from .dependencies import func_dep_1, func_dep_2 + + app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)]) + ``` + """ + ), + ] = None, + default_response_class: Annotated[ + Type[Response], + Doc( + """ + The default response class to be used. + + Read more in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). + + **Example** + + ```python + from fastapi import FastAPI + from fastapi.responses import ORJSONResponse + + app = FastAPI(default_response_class=ORJSONResponse) + ``` + """ + ), + ] = Default(JSONResponse), + redirect_slashes: Annotated[ + bool, + Doc( + """ + Whether to detect and redirect slashes in URLs when the client doesn't + use the same format. + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(redirect_slashes=True) # the default + + @app.get("/items/") + async def read_items(): + return [{"item_id": "Foo"}] + ``` + + With this app, if a client goes to `/items` (without a trailing slash), + they will be automatically redirected with an HTTP status code of 307 + to `/items/`. + """ + ), + ] = True, + docs_url: Annotated[ + Optional[str], + Doc( + """ + The path to the automatic interactive API documentation. + It is handled in the browser by Swagger UI. + + The default URL is `/docs`. You can disable it by setting it to `None`. + + If `openapi_url` is set to `None`, this will be automatically disabled. + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(docs_url="/documentation", redoc_url=None) + ``` + """ + ), + ] = "/docs", + redoc_url: Annotated[ + Optional[str], + Doc( + """ + The path to the alternative automatic interactive API documentation + provided by ReDoc. + + The default URL is `/redoc`. You can disable it by setting it to `None`. + + If `openapi_url` is set to `None`, this will be automatically disabled. + + Read more in the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#docs-urls). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(docs_url="/documentation", redoc_url="redocumentation") + ``` + """ + ), + ] = "/redoc", + swagger_ui_oauth2_redirect_url: Annotated[ + Optional[str], + Doc( + """ + The OAuth2 redirect endpoint for the Swagger UI. + + By default it is `/docs/oauth2-redirect`. + + This is only used if you use OAuth2 (with the "Authorize" button) + with Swagger UI. + """ + ), + ] = "/docs/oauth2-redirect", + swagger_ui_init_oauth: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + OAuth2 configuration for the Swagger UI, by default shown at `/docs`. + + Read more about the available configuration options in the + [Swagger UI docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/). + """ + ), + ] = None, + middleware: Annotated[ + Optional[Sequence[Middleware]], + Doc( + """ + List of middleware to be added when creating the application. + + In FastAPI you would normally do this with `app.add_middleware()` + instead. + + Read more in the + [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/). + """ + ), + ] = None, + exception_handlers: Annotated[ + Optional[ + Dict[ + Union[int, Type[Exception]], + Callable[[Request, Any], Coroutine[Any, Any, Response]], + ] + ], + Doc( + """ + A dictionary with handlers for exceptions. + + In FastAPI, you would normally use the decorator + `@app.exception_handler()`. + + Read more in the + [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). + """ + ), + ] = None, + on_startup: Annotated[ + Optional[Sequence[Callable[[], Any]]], + Doc( + """ + A list of startup event handler functions. + + You should instead use the `lifespan` handlers. + + Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). + """ + ), + ] = None, + on_shutdown: Annotated[ + Optional[Sequence[Callable[[], Any]]], + Doc( + """ + A list of shutdown event handler functions. + + You should instead use the `lifespan` handlers. + + Read more in the + [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). + """ + ), + ] = None, + lifespan: Annotated[ + Optional[Lifespan[AppType]], + Doc( + """ + A `Lifespan` context manager handler. This replaces `startup` and + `shutdown` functions with a single context manager. + + Read more in the + [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). + """ + ), + ] = None, + terms_of_service: Annotated[ + Optional[str], + Doc( + """ + A URL to the Terms of Service for your API. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more at the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). + + **Example** + + ```python + app = FastAPI(terms_of_service="http://example.com/terms/") + ``` + """ + ), + ] = None, + contact: Annotated[ + Optional[Dict[str, Union[str, Any]]], + Doc( + """ + A dictionary with the contact information for the exposed API. + + It can contain several fields. + + * `name`: (`str`) The name of the contact person/organization. + * `url`: (`str`) A URL pointing to the contact information. MUST be in + the format of a URL. + * `email`: (`str`) The email address of the contact person/organization. + MUST be in the format of an email address. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more at the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). + + **Example** + + ```python + app = FastAPI( + contact={ + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + } + ) + ``` + """ + ), + ] = None, + license_info: Annotated[ + Optional[Dict[str, Union[str, Any]]], + Doc( + """ + A dictionary with the license information for the exposed API. + + It can contain several fields. + + * `name`: (`str`) **REQUIRED** (if a `license_info` is set). The + license name used for the API. + * `identifier`: (`str`) An [SPDX](https://spdx.dev/) license expression + for the API. The `identifier` field is mutually exclusive of the `url` + field. Available since OpenAPI 3.1.0, FastAPI 0.99.0. + * `url`: (`str`) A URL to the license used for the API. This MUST be + the format of a URL. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more at the + [FastAPI docs for Metadata and Docs URLs](https://fastapi.tiangolo.com/tutorial/metadata/#metadata-for-api). + + **Example** + + ```python + app = FastAPI( + license_info={ + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html", + } + ) + ``` + """ + ), + ] = None, + openapi_prefix: Annotated[ + str, + Doc( + """ + A URL prefix for the OpenAPI URL. + """ + ), + deprecated( + """ + "openapi_prefix" has been deprecated in favor of "root_path", which + follows more closely the ASGI standard, is simpler, and more + automatic. + """ + ), + ] = "", + root_path: Annotated[ + str, + Doc( + """ + A path prefix handled by a proxy that is not seen by the application + but is seen by external clients, which affects things like Swagger UI. + + Read more about it at the + [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(root_path="/api/v1") + ``` + """ + ), + ] = "", + root_path_in_servers: Annotated[ + bool, + Doc( + """ + To disable automatically generating the URLs in the `servers` field + in the autogenerated OpenAPI using the `root_path`. + + Read more about it in the + [FastAPI docs for Behind a Proxy](https://fastapi.tiangolo.com/advanced/behind-a-proxy/#disable-automatic-server-from-root_path). + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI(root_path_in_servers=False) + ``` + """ + ), + ] = True, + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses to be shown in OpenAPI. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). + + And in the + [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + OpenAPI callbacks that should apply to all *path operations*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + webhooks: Annotated[ + Optional[routing.APIRouter], + Doc( + """ + Add OpenAPI webhooks. This is similar to `callbacks` but it doesn't + depend on specific *path operations*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + **Note**: This is available since OpenAPI 3.1.0, FastAPI 0.99.0. + + Read more about it in the + [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark all *path operations* as deprecated. You probably don't need it, + but it's available. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) all the *path operations* in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + swagger_ui_parameters: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Parameters to configure Swagger UI, the autogenerated interactive API + documentation (by default at `/docs`). + + Read more about it in the + [FastAPI docs about how to Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), + separate_input_output_schemas: Annotated[ + bool, + Doc( + """ + Whether to generate separate OpenAPI schemas for request body and + response body when the results would be more precise. + + This is particularly useful when automatically generating clients. + + For example, if you have a model like: + + ```python + from pydantic import BaseModel + + class Item(BaseModel): + name: str + tags: list[str] = [] + ``` + + When `Item` is used for input, a request body, `tags` is not required, + the client doesn't have to provide it. + + But when using `Item` for output, for a response body, `tags` is always + available because it has a default value, even if it's just an empty + list. So, the client should be able to always expect it. + + In this case, there would be two different schemas, one for input and + another one for output. + """ + ), + ] = True, + **extra: Annotated[ + Any, + Doc( + """ + Extra keyword arguments to be stored in the app, not used by FastAPI + anywhere. + """ + ), + ], ) -> None: self.debug = debug self.title = title @@ -111,8 +840,39 @@ class FastAPI(Starlette): self.swagger_ui_init_oauth = swagger_ui_init_oauth self.swagger_ui_parameters = swagger_ui_parameters self.servers = servers or [] + self.separate_input_output_schemas = separate_input_output_schemas self.extra = extra - self.openapi_version = "3.1.0" + self.openapi_version: Annotated[ + str, + Doc( + """ + The version string of OpenAPI. + + FastAPI will generate OpenAPI version 3.1.0, and will output that as + the OpenAPI version. But some tools, even though they might be + compatible with OpenAPI 3.1.0, might not recognize it as a valid. + + So you could override this value to trick those tools into using + the generated OpenAPI. Have in mind that this is a hack. But if you + avoid using features added in OpenAPI 3.1.0, it might work for your + use case. + + This is not passed as a parameter to the `FastAPI` class to avoid + giving the false idea that FastAPI would generate a different OpenAPI + schema. It is only available as an attribute. + + **Example** + + ```python + from fastapi import FastAPI + + app = FastAPI() + + app.openapi_version = "3.0.2" + ``` + """ + ), + ] = "3.1.0" self.openapi_schema: Optional[Dict[str, Any]] = None if self.openapi_url: assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" @@ -125,10 +885,53 @@ class FastAPI(Starlette): "automatic. Check the docs at " "https://fastapi.tiangolo.com/advanced/sub-applications/" ) - self.webhooks = webhooks or routing.APIRouter() + self.webhooks: Annotated[ + routing.APIRouter, + Doc( + """ + The `app.webhooks` attribute is an `APIRouter` with the *path + operations* that will be used just for documentation of webhooks. + + Read more about it in the + [FastAPI docs for OpenAPI Webhooks](https://fastapi.tiangolo.com/advanced/openapi-webhooks/). + """ + ), + ] = webhooks or routing.APIRouter() self.root_path = root_path or openapi_prefix - self.state: State = State() - self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {} + self.state: Annotated[ + State, + Doc( + """ + A state object for the application. This is the same object for the + entire application, it doesn't change from request to request. + + You normally woudln't use this in FastAPI, for most of the cases you + would instead use FastAPI dependencies. + + This is simply inherited from Starlette. + + Read more about it in the + [Starlette docs for Applications](https://www.starlette.io/applications/#storing-state-on-the-app-instance). + """ + ), + ] = State() + self.dependency_overrides: Annotated[ + Dict[Callable[..., Any], Callable[..., Any]], + Doc( + """ + A dictionary with overrides for the dependencies. + + Each key is the original dependency callable, and the value is the + actual dependency that should be called. + + This is for testing, to replace expensive dependencies with testing + versions. + + Read more about it in the + [FastAPI docs for Testing Dependencies with Overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/). + """ + ), + ] = {} self.router: routing.APIRouter = routing.APIRouter( routes=routes, redirect_slashes=redirect_slashes, @@ -146,7 +949,7 @@ class FastAPI(Starlette): ) self.exception_handlers: Dict[ Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]] - ] = ({} if exception_handlers is None else dict(exception_handlers)) + ] = {} if exception_handlers is None else dict(exception_handlers) self.exception_handlers.setdefault(HTTPException, http_exception_handler) self.exception_handlers.setdefault( RequestValidationError, request_validation_exception_handler @@ -187,20 +990,20 @@ class FastAPI(Starlette): # contextvars. # This needs to happen after user middlewares because those create a # new contextvars context copy by using a new AnyIO task group. - # The initial part of dependencies with yield is executed in the - # FastAPI code, inside all the middlewares, but the teardown part - # (after yield) is executed in the AsyncExitStack in this middleware, - # if the AsyncExitStack lived outside of the custom middlewares and - # contextvars were set in a dependency with yield in that internal + # The initial part of dependencies with 'yield' is executed in the + # FastAPI code, inside all the middlewares. However, the teardown part + # (after 'yield') is executed in the AsyncExitStack in this middleware. + # If the AsyncExitStack lived outside of the custom middlewares and + # contextvars were set in a dependency with 'yield' in that internal # contextvars context, the values would not be available in the - # outside context of the AsyncExitStack. - # By putting the middleware and the AsyncExitStack here, inside all - # user middlewares, the code before and after yield in dependencies - # with yield is executed in the same contextvars context, so all values - # set in contextvars before yield is still available after yield as - # would be expected. + # outer context of the AsyncExitStack. + # By placing the middleware and the AsyncExitStack here, inside all + # user middlewares, the code before and after 'yield' in dependencies + # with 'yield' is executed in the same contextvars context. Thus, all values + # set in contextvars before 'yield' are still available after 'yield,' as + # expected. # Additionally, by having this AsyncExitStack here, after the - # ExceptionMiddleware, now dependencies can catch handled exceptions, + # ExceptionMiddleware, dependencies can now catch handled exceptions, # e.g. HTTPException, to customize the teardown code (e.g. DB session # rollback). Middleware(AsyncExitStackMiddleware), @@ -213,6 +1016,19 @@ class FastAPI(Starlette): return app def openapi(self) -> Dict[str, Any]: + """ + Generate the OpenAPI schema of the application. This is called by FastAPI + internally. + + The first time it is called it stores the result in the attribute + `app.openapi_schema`, and next times it is called, it just returns that same + result. To avoid the cost of generating the schema every time. + + If you need to modify the generated OpenAPI schema, you could modify it. + + Read more in the + [FastAPI docs for OpenAPI](https://fastapi.tiangolo.com/how-to/extending-openapi/). + """ if not self.openapi_schema: self.openapi_schema = get_openapi( title=self.title, @@ -227,6 +1043,7 @@ class FastAPI(Starlette): webhooks=self.webhooks.routes, tags=self.openapi_tags, servers=self.servers, + separate_input_output_schemas=self.separate_input_output_schemas, ) return self.openapi_schema @@ -424,11 +1241,58 @@ class FastAPI(Starlette): def websocket( self, - path: str, - name: Optional[str] = None, + path: Annotated[ + str, + Doc( + """ + WebSocket path. + """ + ), + ], + name: Annotated[ + Optional[str], + Doc( + """ + A name for the WebSocket. Only used internally. + """ + ), + ] = None, *, - dependencies: Optional[Sequence[Depends]] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be used for this + WebSocket. + + Read more about it in the + [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). + """ + ), + ] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Decorate a WebSocket function. + + Read more about it in the + [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). + + **Example** + + ```python + from fastapi import FastAPI, WebSocket + + app = FastAPI() + + @app.websocket("/ws") + async def websocket_endpoint(websocket: WebSocket): + await websocket.accept() + while True: + data = await websocket.receive_text() + await websocket.send_text(f"Message text was: {data}") + ``` + """ + def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_api_websocket_route( path, @@ -442,20 +1306,196 @@ class FastAPI(Starlette): def include_router( self, - router: routing.APIRouter, + router: Annotated[routing.APIRouter, Doc("The `APIRouter` to include.")], *, - prefix: str = "", - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - default_response_class: Type[Response] = Default(JSONResponse), - callbacks: Optional[List[BaseRoute]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to all the *path operations* in this + router. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to all the + *path operations* in this router. + + Read more about it in the + [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). + + **Example** + + ```python + from fastapi import Depends, FastAPI + + from .dependencies import get_token_header + from .internal import admin + + app = FastAPI() + + app.include_router( + admin.router, + dependencies=[Depends(get_token_header)], + ) + ``` + """ + ), + ] = None, + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses to be shown in OpenAPI. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). + + And in the + [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark all the *path operations* in this router as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + **Example** + + ```python + from fastapi import FastAPI + + from .internal import old_api + + app = FastAPI() + + app.include_router( + old_api.router, + deprecated=True, + ) + ``` + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include (or not) all the *path operations* in this router in the + generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + **Example** + + ```python + from fastapi import FastAPI + + from .internal import old_api + + app = FastAPI() + + app.include_router( + old_api.router, + include_in_schema=False, + ) + ``` + """ + ), + ] = True, + default_response_class: Annotated[ + Type[Response], + Doc( + """ + Default response class to be used for the *path operations* in this + router. + + Read more in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). + + **Example** + + ```python + from fastapi import FastAPI + from fastapi.responses import ORJSONResponse + + from .internal import old_api + + app = FastAPI() + + app.include_router( + old_api.router, + default_response_class=ORJSONResponse, + ) + ``` + """ + ), + ] = Default(JSONResponse), + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> None: + """ + Include an `APIRouter` in the same app. + + Read more about it in the + [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/). + + ## Example + + ```python + from fastapi import FastAPI + + from .users import users_router + + app = FastAPI() + + app.include_router(users_router) + ``` + """ self.router.include_router( router, prefix=prefix, @@ -471,33 +1511,351 @@ class FastAPI(Starlette): def get( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP GET operation. + + ## Example + + ```python + from fastapi import FastAPI + + app = FastAPI() + + @app.get("/items/") + def read_items(): + return [{"name": "Empanada"}, {"name": "Arepa"}] + ``` + """ return self.router.get( path, response_model=response_model, @@ -526,33 +1884,356 @@ class FastAPI(Starlette): def put( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP PUT operation. + + ## Example + + ```python + from fastapi import FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + + @app.put("/items/{item_id}") + def replace_item(item_id: str, item: Item): + return {"message": "Item replaced", "id": item_id} + ``` + """ return self.router.put( path, response_model=response_model, @@ -581,33 +2262,356 @@ class FastAPI(Starlette): def post( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP POST operation. + + ## Example + + ```python + from fastapi import FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + + @app.post("/items/") + def create_item(item: Item): + return {"message": "Item created"} + ``` + """ return self.router.post( path, response_model=response_model, @@ -636,33 +2640,351 @@ class FastAPI(Starlette): def delete( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP DELETE operation. + + ## Example + + ```python + from fastapi import FastAPI + + app = FastAPI() + + @app.delete("/items/{item_id}") + def delete_item(item_id: str): + return {"message": "Item deleted"} + ``` + """ return self.router.delete( path, response_model=response_model, @@ -691,33 +3013,351 @@ class FastAPI(Starlette): def options( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP OPTIONS operation. + + ## Example + + ```python + from fastapi import FastAPI + + app = FastAPI() + + @app.options("/items/") + def get_item_options(): + return {"additions": ["Aji", "Guacamole"]} + ``` + """ return self.router.options( path, response_model=response_model, @@ -746,33 +3386,351 @@ class FastAPI(Starlette): def head( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP HEAD operation. + + ## Example + + ```python + from fastapi import FastAPI, Response + + app = FastAPI() + + @app.head("/items/", status_code=204) + def get_items_headers(response: Response): + response.headers["X-Cat-Dog"] = "Alone in the world" + ``` + """ return self.router.head( path, response_model=response_model, @@ -801,33 +3759,356 @@ class FastAPI(Starlette): def patch( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP PATCH operation. + + ## Example + + ```python + from fastapi import FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + + @app.patch("/items/") + def update_item(item: Item): + return {"message": "Item updated in place"} + ``` + """ return self.router.patch( path, response_model=response_model, @@ -856,33 +4137,351 @@ class FastAPI(Starlette): def trace( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[routing.APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP TRACE operation. + + ## Example + + ```python + from fastapi import FastAPI + + app = FastAPI() + + @app.put("/items/{item_id}") + def trace_item(item_id: str): + return None + ``` + """ return self.router.trace( path, response_model=response_model, @@ -918,14 +4517,72 @@ class FastAPI(Starlette): return decorator + @deprecated( + """ + on_event is deprecated, use lifespan event handlers instead. + + Read more about it in the + [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). + """ + ) def on_event( - self, event_type: str + self, + event_type: Annotated[ + str, + Doc( + """ + The type of event. `startup` or `shutdown`. + """ + ), + ], ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add an event handler for the application. + + `on_event` is deprecated, use `lifespan` event handlers instead. + + Read more about it in the + [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated). + """ return self.router.on_event(event_type) def middleware( - self, middleware_type: str + self, + middleware_type: Annotated[ + str, + Doc( + """ + The type of middleware. Currently only supports `http`. + """ + ), + ], ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a middleware to the application. + + Read more about it in the + [FastAPI docs for Middleware](https://fastapi.tiangolo.com/tutorial/middleware/). + + ## Example + + ```python + import time + + from fastapi import FastAPI, Request + + app = FastAPI() + + + @app.middleware("http") + async def add_process_time_header(request: Request, call_next): + start_time = time.time() + response = await call_next(request) + process_time = time.time() - start_time + response.headers["X-Process-Time"] = str(process_time) + return response + ``` + """ + def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_middleware(BaseHTTPMiddleware, dispatch=func) return func @@ -933,8 +4590,46 @@ class FastAPI(Starlette): return decorator def exception_handler( - self, exc_class_or_status_code: Union[int, Type[Exception]] + self, + exc_class_or_status_code: Annotated[ + Union[int, Type[Exception]], + Doc( + """ + The Exception class this would handle, or a status code. + """ + ), + ], ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add an exception handler to the app. + + Read more about it in the + [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). + + ## Example + + ```python + from fastapi import FastAPI, Request + from fastapi.responses import JSONResponse + + + class UnicornException(Exception): + def __init__(self, name: str): + self.name = name + + + app = FastAPI() + + + @app.exception_handler(UnicornException) + async def unicorn_exception_handler(request: Request, exc: UnicornException): + return JSONResponse( + status_code=418, + content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."}, + ) + ``` + """ + def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_exception_handler(exc_class_or_status_code, func) return func diff --git a/fastapi/background.py b/fastapi/background.py index dd3bbe249..35ab1b227 100644 --- a/fastapi/background.py +++ b/fastapi/background.py @@ -1 +1,59 @@ -from starlette.background import BackgroundTasks as BackgroundTasks # noqa +from typing import Any, Callable + +from starlette.background import BackgroundTasks as StarletteBackgroundTasks +from typing_extensions import Annotated, Doc, ParamSpec # type: ignore [attr-defined] + +P = ParamSpec("P") + + +class BackgroundTasks(StarletteBackgroundTasks): + """ + A collection of background tasks that will be called after a response has been + sent to the client. + + Read more about it in the + [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/). + + ## Example + + ```python + from fastapi import BackgroundTasks, FastAPI + + app = FastAPI() + + + def write_notification(email: str, message=""): + with open("log.txt", mode="w") as email_file: + content = f"notification for {email}: {message}" + email_file.write(content) + + + @app.post("/send-notification/{email}") + async def send_notification(email: str, background_tasks: BackgroundTasks): + background_tasks.add_task(write_notification, email, message="some notification") + return {"message": "Notification sent in the background"} + ``` + """ + + def add_task( + self, + func: Annotated[ + Callable[P, Any], + Doc( + """ + The function to call after the response is sent. + + It can be a regular `def` function or an `async def` function. + """ + ), + ], + *args: P.args, + **kwargs: P.kwargs, + ) -> None: + """ + Add a function to be called in the background after the response is sent. + + Read more about it in the + [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/). + """ + return super().add_task(func, *args, **kwargs) diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py index 3c96c56c7..ce03e3ce4 100644 --- a/fastapi/datastructures.py +++ b/fastapi/datastructures.py @@ -1,11 +1,21 @@ -from typing import Any, Callable, Dict, Iterable, Type, TypeVar, cast +from typing import ( + Any, + BinaryIO, + Callable, + Dict, + Iterable, + Optional, + Type, + TypeVar, + cast, +) from fastapi._compat import ( PYDANTIC_V2, CoreSchema, GetJsonSchemaHandler, JsonSchemaValue, - general_plain_validator_function, + with_info_plain_validator_function, ) from starlette.datastructures import URL as URL # noqa: F401 from starlette.datastructures import Address as Address # noqa: F401 @@ -14,9 +24,120 @@ from starlette.datastructures import Headers as Headers # noqa: F401 from starlette.datastructures import QueryParams as QueryParams # noqa: F401 from starlette.datastructures import State as State # noqa: F401 from starlette.datastructures import UploadFile as StarletteUploadFile +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] class UploadFile(StarletteUploadFile): + """ + A file uploaded in a request. + + Define it as a *path operation function* (or dependency) parameter. + + If you are using a regular `def` function, you can use the `upload_file.file` + attribute to access the raw standard Python file (blocking, not async), useful and + needed for non-async code. + + Read more about it in the + [FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/). + + ## Example + + ```python + from typing import Annotated + + from fastapi import FastAPI, File, UploadFile + + app = FastAPI() + + + @app.post("/files/") + async def create_file(file: Annotated[bytes, File()]): + return {"file_size": len(file)} + + + @app.post("/uploadfile/") + async def create_upload_file(file: UploadFile): + return {"filename": file.filename} + ``` + """ + + file: Annotated[ + BinaryIO, + Doc("The standard Python file object (non-async)."), + ] + filename: Annotated[Optional[str], Doc("The original file name.")] + size: Annotated[Optional[int], Doc("The size of the file in bytes.")] + headers: Annotated[Headers, Doc("The headers of the request.")] + content_type: Annotated[ + Optional[str], Doc("The content type of the request, from the headers.") + ] + + async def write( + self, + data: Annotated[ + bytes, + Doc( + """ + The bytes to write to the file. + """ + ), + ], + ) -> None: + """ + Write some bytes to the file. + + You normally wouldn't use this from a file you read in a request. + + To be awaitable, compatible with async, this is run in threadpool. + """ + return await super().write(data) + + async def read( + self, + size: Annotated[ + int, + Doc( + """ + The number of bytes to read from the file. + """ + ), + ] = -1, + ) -> bytes: + """ + Read some bytes from the file. + + To be awaitable, compatible with async, this is run in threadpool. + """ + return await super().read(size) + + async def seek( + self, + offset: Annotated[ + int, + Doc( + """ + The position in bytes to seek to in the file. + """ + ), + ], + ) -> None: + """ + Move to a position in the file. + + Any next read or write will be done from that position. + + To be awaitable, compatible with async, this is run in threadpool. + """ + return await super().seek(offset) + + async def close(self) -> None: + """ + Close the file. + + To be awaitable, compatible with async, this is run in threadpool. + """ + return await super().close() + @classmethod def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]: yield cls.validate @@ -49,7 +170,7 @@ class UploadFile(StarletteUploadFile): def __get_pydantic_core_schema__( cls, source: Type[Any], handler: Callable[[Any], CoreSchema] ) -> CoreSchema: - return general_plain_validator_function(cls._validate) + return with_info_plain_validator_function(cls._validate) class DefaultPlaceholder: diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index e2915268c..4e88410a5 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -44,6 +44,7 @@ from fastapi._compat import ( serialize_sequence_value, value_is_sequence, ) +from fastapi.background import BackgroundTasks from fastapi.concurrency import ( AsyncExitStack, asynccontextmanager, @@ -56,7 +57,7 @@ from fastapi.security.oauth2 import OAuth2, SecurityScopes from fastapi.security.open_id_connect_url import OpenIdConnect from fastapi.utils import create_response_field, get_path_param_names from pydantic.fields import FieldInfo -from starlette.background import BackgroundTasks +from starlette.background import BackgroundTasks as StarletteBackgroundTasks from starlette.concurrency import run_in_threadpool from starlette.datastructures import FormData, Headers, QueryParams, UploadFile from starlette.requests import HTTPConnection, Request @@ -305,7 +306,7 @@ def add_non_field_param_to_dependency( elif lenient_issubclass(type_annotation, Response): dependant.response_param_name = param_name return True - elif lenient_issubclass(type_annotation, BackgroundTasks): + elif lenient_issubclass(type_annotation, StarletteBackgroundTasks): dependant.background_tasks_param_name = param_name return True elif lenient_issubclass(type_annotation, SecurityScopes): @@ -324,10 +325,11 @@ def analyze_param( field_info = None depends = None type_annotation: Any = Any - if ( - annotation is not inspect.Signature.empty - and get_origin(annotation) is Annotated - ): + use_annotation: Any = Any + if annotation is not inspect.Signature.empty: + use_annotation = annotation + type_annotation = annotation + if get_origin(use_annotation) is Annotated: annotated_args = get_args(annotation) type_annotation = annotated_args[0] fastapi_annotations = [ @@ -335,14 +337,21 @@ def analyze_param( for arg in annotated_args[1:] if isinstance(arg, (FieldInfo, params.Depends)) ] - assert ( - len(fastapi_annotations) <= 1 - ), f"Cannot specify multiple `Annotated` FastAPI arguments for {param_name!r}" - fastapi_annotation = next(iter(fastapi_annotations), None) + fastapi_specific_annotations = [ + arg + for arg in fastapi_annotations + if isinstance(arg, (params.Param, params.Body, params.Depends)) + ] + if fastapi_specific_annotations: + fastapi_annotation: Union[ + FieldInfo, params.Depends, None + ] = fastapi_specific_annotations[-1] + else: + fastapi_annotation = None if isinstance(fastapi_annotation, FieldInfo): # Copy `field_info` because we mutate `field_info.default` below. field_info = copy_field_info( - field_info=fastapi_annotation, annotation=annotation + field_info=fastapi_annotation, annotation=use_annotation ) assert field_info.default is Undefined or field_info.default is Required, ( f"`{field_info.__class__.__name__}` default value cannot be set in" @@ -355,8 +364,6 @@ def analyze_param( field_info.default = Required elif isinstance(fastapi_annotation, params.Depends): depends = fastapi_annotation - elif annotation is not inspect.Signature.empty: - type_annotation = annotation if isinstance(value, params.Depends): assert depends is None, ( @@ -382,7 +389,14 @@ def analyze_param( if lenient_issubclass( type_annotation, - (Request, WebSocket, HTTPConnection, Response, BackgroundTasks, SecurityScopes), + ( + Request, + WebSocket, + HTTPConnection, + Response, + StarletteBackgroundTasks, + SecurityScopes, + ), ): assert depends is None, f"Cannot specify `Depends` for type {type_annotation!r}" assert ( @@ -394,15 +408,15 @@ def analyze_param( # We might check here that `default_value is Required`, but the fact is that the same # parameter might sometimes be a path parameter and sometimes not. See # `tests/test_infer_param_optionality.py` for an example. - field_info = params.Path(annotation=type_annotation) + field_info = params.Path(annotation=use_annotation) elif is_uploadfile_or_nonable_uploadfile_annotation( type_annotation ) or is_uploadfile_sequence_annotation(type_annotation): - field_info = params.File(annotation=type_annotation, default=default_value) + field_info = params.File(annotation=use_annotation, default=default_value) elif not field_annotation_is_scalar(annotation=type_annotation): - field_info = params.Body(annotation=type_annotation, default=default_value) + field_info = params.Body(annotation=use_annotation, default=default_value) else: - field_info = params.Query(annotation=type_annotation, default=default_value) + field_info = params.Query(annotation=use_annotation, default=default_value) field = None if field_info is not None: @@ -416,8 +430,8 @@ def analyze_param( and getattr(field_info, "in_", None) is None ): field_info.in_ = params.ParamTypes.query - use_annotation = get_annotation_from_field_info( - type_annotation, + use_annotation_from_field_info = get_annotation_from_field_info( + use_annotation, field_info, param_name, ) @@ -428,7 +442,7 @@ def analyze_param( field_info.alias = alias field = create_response_field( name=param_name, - type_=use_annotation, + type_=use_annotation_from_field_info, default=field_info.default, alias=alias, required=field_info.default in (Required, Undefined), @@ -458,16 +472,17 @@ def is_body_param(*, param_field: ModelField, is_path_param: bool) -> bool: def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None: - field_info = cast(params.Param, field.field_info) - if field_info.in_ == params.ParamTypes.path: + field_info = field.field_info + field_info_in = getattr(field_info, "in_", None) + if field_info_in == params.ParamTypes.path: dependant.path_params.append(field) - elif field_info.in_ == params.ParamTypes.query: + elif field_info_in == params.ParamTypes.query: dependant.query_params.append(field) - elif field_info.in_ == params.ParamTypes.header: + elif field_info_in == params.ParamTypes.header: dependant.header_params.append(field) else: assert ( - field_info.in_ == params.ParamTypes.cookie + field_info_in == params.ParamTypes.cookie ), f"non-body parameters must be in path, query, header or cookie: {field.name}" dependant.cookie_params.append(field) @@ -510,14 +525,14 @@ async def solve_dependencies( request: Union[Request, WebSocket], dependant: Dependant, body: Optional[Union[Dict[str, Any], FormData]] = None, - background_tasks: Optional[BackgroundTasks] = None, + background_tasks: Optional[StarletteBackgroundTasks] = None, response: Optional[Response] = None, dependency_overrides_provider: Optional[Any] = None, dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None, ) -> Tuple[ Dict[str, Any], List[Any], - Optional[BackgroundTasks], + Optional[StarletteBackgroundTasks], Response, Dict[Tuple[Callable[..., Any], Tuple[str]], Any], ]: diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 30493697e..e50171393 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -22,6 +22,7 @@ from pydantic import BaseModel from pydantic.color import Color from pydantic.networks import AnyUrl, NameEmail from pydantic.types import SecretBytes, SecretStr +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] from ._compat import PYDANTIC_V2, Url, _model_dump @@ -99,16 +100,107 @@ encoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE) def jsonable_encoder( - obj: Any, - include: Optional[IncEx] = None, - exclude: Optional[IncEx] = None, - by_alias: bool = True, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None, - sqlalchemy_safe: bool = True, + obj: Annotated[ + Any, + Doc( + """ + The input object to convert to JSON. + """ + ), + ], + include: Annotated[ + Optional[IncEx], + Doc( + """ + Pydantic's `include` parameter, passed to Pydantic models to set the + fields to include. + """ + ), + ] = None, + exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Pydantic's `exclude` parameter, passed to Pydantic models to set the + fields to exclude. + """ + ), + ] = None, + by_alias: Annotated[ + bool, + Doc( + """ + Pydantic's `by_alias` parameter, passed to Pydantic models to define if + the output should use the alias names (when provided) or the Python + attribute names. In an API, if you set an alias, it's probably because you + want to use it in the result, so you probably want to leave this set to + `True`. + """ + ), + ] = True, + exclude_unset: Annotated[ + bool, + Doc( + """ + Pydantic's `exclude_unset` parameter, passed to Pydantic models to define + if it should exclude from the output the fields that were not explicitly + set (and that only had their default values). + """ + ), + ] = False, + exclude_defaults: Annotated[ + bool, + Doc( + """ + Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define + if it should exclude from the output the fields that had the same default + value, even when they were explicitly set. + """ + ), + ] = False, + exclude_none: Annotated[ + bool, + Doc( + """ + Pydantic's `exclude_none` parameter, passed to Pydantic models to define + if it should exclude from the output any fields that have a `None` value. + """ + ), + ] = False, + custom_encoder: Annotated[ + Optional[Dict[Any, Callable[[Any], Any]]], + Doc( + """ + Pydantic's `custom_encoder` parameter, passed to Pydantic models to define + a custom encoder. + """ + ), + ] = None, + sqlalchemy_safe: Annotated[ + bool, + Doc( + """ + Exclude from the output any fields that start with the name `_sa`. + + This is mainly a hack for compatibility with SQLAlchemy objects, they + store internal SQLAlchemy-specific state in attributes named with `_sa`, + and those objects can't (and shouldn't be) serialized to JSON. + """ + ), + ] = True, ) -> Any: + """ + Convert any object to something that can be encoded in JSON. + + This is used internally by FastAPI to make sure anything you return can be + encoded as JSON before it is sent to the client. + + You can also use it yourself, for example to convert objects before saving them + in a database that supports only JSON. + + Read more about it in the + [FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/). + """ custom_encoder = custom_encoder or {} if custom_encoder: if type(obj) in custom_encoder: diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py index 42f4709fb..680d288e4 100644 --- a/fastapi/exceptions.py +++ b/fastapi/exceptions.py @@ -1,20 +1,141 @@ -from typing import Any, Dict, Optional, Sequence, Type +from typing import Any, Dict, Optional, Sequence, Type, Union from pydantic import BaseModel, create_model from starlette.exceptions import HTTPException as StarletteHTTPException -from starlette.exceptions import WebSocketException as WebSocketException # noqa: F401 +from starlette.exceptions import WebSocketException as StarletteWebSocketException +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] class HTTPException(StarletteHTTPException): + """ + An HTTP exception you can raise in your own code to show errors to the client. + + This is for client errors, invalid authentication, invalid data, etc. Not for server + errors in your code. + + Read more about it in the + [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/). + + ## Example + + ```python + from fastapi import FastAPI, HTTPException + + app = FastAPI() + + items = {"foo": "The Foo Wrestlers"} + + + @app.get("/items/{item_id}") + async def read_item(item_id: str): + if item_id not in items: + raise HTTPException(status_code=404, detail="Item not found") + return {"item": items[item_id]} + ``` + """ + def __init__( self, - status_code: int, - detail: Any = None, - headers: Optional[Dict[str, str]] = None, + status_code: Annotated[ + int, + Doc( + """ + HTTP status code to send to the client. + """ + ), + ], + detail: Annotated[ + Any, + Doc( + """ + Any data to be sent to the client in the `detail` key of the JSON + response. + """ + ), + ] = None, + headers: Annotated[ + Optional[Dict[str, str]], + Doc( + """ + Any headers to send to the client in the response. + """ + ), + ] = None, ) -> None: super().__init__(status_code=status_code, detail=detail, headers=headers) +class WebSocketException(StarletteWebSocketException): + """ + A WebSocket exception you can raise in your own code to show errors to the client. + + This is for client errors, invalid authentication, invalid data, etc. Not for server + errors in your code. + + Read more about it in the + [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). + + ## Example + + ```python + from typing import Annotated + + from fastapi import ( + Cookie, + FastAPI, + WebSocket, + WebSocketException, + status, + ) + + app = FastAPI() + + @app.websocket("/items/{item_id}/ws") + async def websocket_endpoint( + *, + websocket: WebSocket, + session: Annotated[str | None, Cookie()] = None, + item_id: str, + ): + if session is None: + raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) + await websocket.accept() + while True: + data = await websocket.receive_text() + await websocket.send_text(f"Session cookie is: {session}") + await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") + ``` + """ + + def __init__( + self, + code: Annotated[ + int, + Doc( + """ + A closing code from the + [valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1). + """ + ), + ], + reason: Annotated[ + Union[str, None], + Doc( + """ + The reason to close the WebSocket connection. + + It is UTF-8-encoded data. The interpretation of the reason is up to the + application, it is not specified by the WebSocket specification. + + It could contain text that could be human-readable or interpretable + by the client code, etc. + """ + ), + ] = None, + ) -> None: + super().__init__(code=code, reason=reason) + + RequestErrorModel: Type[BaseModel] = create_model("Request") WebSocketErrorModel: Type[BaseModel] = create_model("WebSocket") diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py index 81f67dcc5..69473d19c 100644 --- a/fastapi/openapi/docs.py +++ b/fastapi/openapi/docs.py @@ -3,8 +3,18 @@ from typing import Any, Dict, Optional from fastapi.encoders import jsonable_encoder from starlette.responses import HTMLResponse +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] -swagger_ui_default_parameters = { +swagger_ui_default_parameters: Annotated[ + Dict[str, Any], + Doc( + """ + Default configurations for Swagger UI. + + You can use it as a template to add any other configurations needed. + """ + ), +] = { "dom_id": "#swagger-ui", "layout": "BaseLayout", "deepLinking": True, @@ -15,15 +25,91 @@ swagger_ui_default_parameters = { def get_swagger_ui_html( *, - openapi_url: str, - title: str, - swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js", - swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css", - swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png", - oauth2_redirect_url: Optional[str] = None, - init_oauth: Optional[Dict[str, Any]] = None, - swagger_ui_parameters: Optional[Dict[str, Any]] = None, + openapi_url: Annotated[ + str, + Doc( + """ + The OpenAPI URL that Swagger UI should load and use. + + This is normally done automatically by FastAPI using the default URL + `/openapi.json`. + """ + ), + ], + title: Annotated[ + str, + Doc( + """ + The HTML `` content, normally shown in the browser tab. + """ + ), + ], + swagger_js_url: Annotated[ + str, + Doc( + """ + The URL to use to load the Swagger UI JavaScript. + + It is normally set to a CDN URL. + """ + ), + ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js", + swagger_css_url: Annotated[ + str, + Doc( + """ + The URL to use to load the Swagger UI CSS. + + It is normally set to a CDN URL. + """ + ), + ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css", + swagger_favicon_url: Annotated[ + str, + Doc( + """ + The URL of the favicon to use. It is normally shown in the browser tab. + """ + ), + ] = "https://fastapi.tiangolo.com/img/favicon.png", + oauth2_redirect_url: Annotated[ + Optional[str], + Doc( + """ + The OAuth2 redirect URL, it is normally automatically handled by FastAPI. + """ + ), + ] = None, + init_oauth: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + A dictionary with Swagger UI OAuth2 initialization configurations. + """ + ), + ] = None, + swagger_ui_parameters: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Configuration parameters for Swagger UI. + + It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters]. + """ + ), + ] = None, ) -> HTMLResponse: + """ + Generate and return the HTML that loads Swagger UI for the interactive + API docs (normally served at `/docs`). + + You would only call this function yourself if you needed to override some parts, + for example the URLs to use to load Swagger UI's JavaScript and CSS. + + Read more about it in the + [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/) + and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/). + """ current_swagger_ui_parameters = swagger_ui_default_parameters.copy() if swagger_ui_parameters: current_swagger_ui_parameters.update(swagger_ui_parameters) @@ -74,12 +160,62 @@ def get_swagger_ui_html( def get_redoc_html( *, - openapi_url: str, - title: str, - redoc_js_url: str = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js", - redoc_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png", - with_google_fonts: bool = True, + openapi_url: Annotated[ + str, + Doc( + """ + The OpenAPI URL that ReDoc should load and use. + + This is normally done automatically by FastAPI using the default URL + `/openapi.json`. + """ + ), + ], + title: Annotated[ + str, + Doc( + """ + The HTML `<title>` content, normally shown in the browser tab. + """ + ), + ], + redoc_js_url: Annotated[ + str, + Doc( + """ + The URL to use to load the ReDoc JavaScript. + + It is normally set to a CDN URL. + """ + ), + ] = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js", + redoc_favicon_url: Annotated[ + str, + Doc( + """ + The URL of the favicon to use. It is normally shown in the browser tab. + """ + ), + ] = "https://fastapi.tiangolo.com/img/favicon.png", + with_google_fonts: Annotated[ + bool, + Doc( + """ + Load and use Google Fonts. + """ + ), + ] = True, ) -> HTMLResponse: + """ + Generate and return the HTML response that loads ReDoc for the alternative + API docs (normally served at `/redoc`). + + You would only call this function yourself if you needed to override some parts, + for example the URLs to use to load ReDoc's JavaScript and CSS. + + Read more about it in the + [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/). + """ html = f""" <!DOCTYPE html> <html> @@ -118,6 +254,11 @@ def get_redoc_html( def get_swagger_ui_oauth2_redirect_html() -> HTMLResponse: + """ + Generate the HTML response with the OAuth2 redirection for Swagger UI. + + You normally don't need to use or change this. + """ # copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html html = """ <!doctype html> diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 2268dd229..5f3bdbb20 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -7,11 +7,11 @@ from fastapi._compat import ( GetJsonSchemaHandler, JsonSchemaValue, _model_rebuild, - general_plain_validator_function, + with_info_plain_validator_function, ) from fastapi.logger import logger from pydantic import AnyUrl, BaseModel, Field -from typing_extensions import Annotated, Literal +from typing_extensions import Annotated, Literal, TypedDict from typing_extensions import deprecated as typing_deprecated try: @@ -52,7 +52,7 @@ except ImportError: # pragma: no cover def __get_pydantic_core_schema__( cls, source: Type[Any], handler: Callable[[Any], CoreSchema] ) -> CoreSchema: - return general_plain_validator_function(cls._validate) + return with_info_plain_validator_function(cls._validate) class Contact(BaseModel): @@ -267,14 +267,14 @@ class Schema(BaseModel): SchemaOrBool = Union[Schema, bool] -class Example(BaseModel): - summary: Optional[str] = None - description: Optional[str] = None - value: Optional[Any] = None - externalValue: Optional[AnyUrl] = None +class Example(TypedDict, total=False): + summary: Optional[str] + description: Optional[str] + value: Optional[Any] + externalValue: Optional[AnyUrl] - if PYDANTIC_V2: - model_config = {"extra": "allow"} + if PYDANTIC_V2: # type: ignore [misc] + __pydantic_config__ = {"extra": "allow"} else: diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index e295361e6..5bfb5acef 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -95,6 +95,7 @@ def get_openapi_operation_parameters( field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> List[Dict[str, Any]]: parameters = [] for param in all_route_params: @@ -107,6 +108,7 @@ def get_openapi_operation_parameters( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) parameter = { "name": param.alias, @@ -116,7 +118,9 @@ def get_openapi_operation_parameters( } if field_info.description: parameter["description"] = field_info.description - if field_info.example != Undefined: + if field_info.openapi_examples: + parameter["examples"] = jsonable_encoder(field_info.openapi_examples) + elif field_info.example != Undefined: parameter["example"] = jsonable_encoder(field_info.example) if field_info.deprecated: parameter["deprecated"] = field_info.deprecated @@ -132,6 +136,7 @@ def get_openapi_operation_request_body( field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Optional[Dict[str, Any]]: if not body_field: return None @@ -141,6 +146,7 @@ def get_openapi_operation_request_body( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) field_info = cast(Body, body_field.field_info) request_media_type = field_info.media_type @@ -149,7 +155,11 @@ def get_openapi_operation_request_body( if required: request_body_oai["required"] = required request_media_content: Dict[str, Any] = {"schema": body_schema} - if field_info.example != Undefined: + if field_info.openapi_examples: + request_media_content["examples"] = jsonable_encoder( + field_info.openapi_examples + ) + elif field_info.example != Undefined: request_media_content["example"] = jsonable_encoder(field_info.example) request_body_oai["content"] = {request_media_type: request_media_content} return request_body_oai @@ -211,6 +221,7 @@ def get_openapi_path( field_mapping: Dict[ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], + separate_input_output_schemas: bool = True, ) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]: path = {} security_schemes: Dict[str, Any] = {} @@ -242,6 +253,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) parameters.extend(operation_parameters) if parameters: @@ -263,6 +275,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) if request_body_oai: operation["requestBody"] = request_body_oai @@ -280,6 +293,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) callbacks[callback.name] = {callback.path: cb_path} operation["callbacks"] = callbacks @@ -310,6 +324,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) else: response_schema = {} @@ -343,6 +358,7 @@ def get_openapi_path( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) media_type = route_response_media_type or "application/json" additional_schema = ( @@ -433,6 +449,7 @@ def get_openapi( terms_of_service: Optional[str] = None, contact: Optional[Dict[str, Union[str, Any]]] = None, license_info: Optional[Dict[str, Union[str, Any]]] = None, + separate_input_output_schemas: bool = True, ) -> Dict[str, Any]: info: Dict[str, Any] = {"title": title, "version": version} if summary: @@ -459,6 +476,7 @@ def get_openapi( fields=all_fields, schema_generator=schema_generator, model_name_map=model_name_map, + separate_input_output_schemas=separate_input_output_schemas, ) for route in routes or []: if isinstance(route, routing.APIRoute): @@ -468,6 +486,7 @@ def get_openapi( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) if result: path, security_schemes, path_definitions = result @@ -487,6 +506,7 @@ def get_openapi( schema_generator=schema_generator, model_name_map=model_name_map, field_mapping=field_mapping, + separate_input_output_schemas=separate_input_output_schemas, ) if result: path, security_schemes, path_definitions = result diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index a43afaf31..3f6dbc959 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -2,43 +2,219 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Union from fastapi import params from fastapi._compat import Undefined -from typing_extensions import Annotated, deprecated +from fastapi.openapi.models import Example +from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined] _Unset: Any = Undefined def Path( # noqa: N802 - default: Any = ..., + default: Annotated[ + Any, + Doc( + """ + Default value if the parameter field is not set. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = ..., *, - default_factory: Union[Callable[[], Any], None] = _Unset, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, + default_factory: Annotated[ + Union[Callable[[], Any], None], + Doc( + """ + A callable to generate the default value. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = _Unset, + alias: Annotated[ + Optional[str], + Doc( + """ + An alternative name for the parameter field. + + This will be used to extract the data and for the generated OpenAPI. + It is particularly useful when you can't use the name you want because it + is a Python reserved keyword or similar. + """ + ), + ] = None, + alias_priority: Annotated[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, # TODO: update when deprecating Pydantic v1, import these types # validation_alias: str | AliasPath | AliasChoices | None - validation_alias: Union[str, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + validation_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Whitelist' validation step. The parameter field will be the single one + allowed by the alias or set of aliases defined. + """ + ), + ] = None, + serialization_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Blacklist' validation step. The vanilla parameter field will be the + single one of the alias' or set of aliases' fields and all the other + fields will be ignored at serialization time. + """ + ), + ] = None, + title: Annotated[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, regex: Annotated[ Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[List[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, example: Annotated[ Optional[Any], deprecated( @@ -46,11 +222,87 @@ def Path( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, - **extra: Any, + openapi_examples: Annotated[ + Optional[Dict[str, Example]], + Doc( + """ + OpenAPI-specific examples. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Swagger UI (that provides the `/docs` interface) has better support for the + OpenAPI-specific examples than the JSON Schema `examples`, that's the main + use case for this. + + Read more about it in the + [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this parameter field as deprecated. + + It will affect the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) this parameter field in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + json_schema_extra: Annotated[ + Union[Dict[str, Any], None], + Doc( + """ + Any additional JSON schema data. + """ + ), + ] = None, + **extra: Annotated[ + Any, + Doc( + """ + Include extra fields used by the JSON Schema. + """ + ), + deprecated( + """ + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + """ + ), + ], ) -> Any: + """ + Declare a path parameter for a *path operation*. + + Read more about it in the + [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/). + + ```python + from typing import Annotated + + from fastapi import FastAPI, Path + + app = FastAPI() + + + @app.get("/items/{item_id}") + async def read_items( + item_id: Annotated[int, Path(title="The ID of the item to get")], + ): + return {"item_id": item_id} + ``` + """ return params.Path( default=default, default_factory=default_factory, @@ -76,6 +328,7 @@ def Path( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -84,37 +337,209 @@ def Path( # noqa: N802 def Query( # noqa: N802 - default: Any = Undefined, + default: Annotated[ + Any, + Doc( + """ + Default value if the parameter field is not set. + """ + ), + ] = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, + default_factory: Annotated[ + Union[Callable[[], Any], None], + Doc( + """ + A callable to generate the default value. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = _Unset, + alias: Annotated[ + Optional[str], + Doc( + """ + An alternative name for the parameter field. + + This will be used to extract the data and for the generated OpenAPI. + It is particularly useful when you can't use the name you want because it + is a Python reserved keyword or similar. + """ + ), + ] = None, + alias_priority: Annotated[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, # TODO: update when deprecating Pydantic v1, import these types # validation_alias: str | AliasPath | AliasChoices | None - validation_alias: Union[str, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + validation_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Whitelist' validation step. The parameter field will be the single one + allowed by the alias or set of aliases defined. + """ + ), + ] = None, + serialization_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Blacklist' validation step. The vanilla parameter field will be the + single one of the alias' or set of aliases' fields and all the other + fields will be ignored at serialization time. + """ + ), + ] = None, + title: Annotated[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, regex: Annotated[ Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[List[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, example: Annotated[ Optional[Any], deprecated( @@ -122,10 +547,65 @@ def Query( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, - **extra: Any, + openapi_examples: Annotated[ + Optional[Dict[str, Example]], + Doc( + """ + OpenAPI-specific examples. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Swagger UI (that provides the `/docs` interface) has better support for the + OpenAPI-specific examples than the JSON Schema `examples`, that's the main + use case for this. + + Read more about it in the + [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this parameter field as deprecated. + + It will affect the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) this parameter field in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + json_schema_extra: Annotated[ + Union[Dict[str, Any], None], + Doc( + """ + Any additional JSON schema data. + """ + ), + ] = None, + **extra: Annotated[ + Any, + Doc( + """ + Include extra fields used by the JSON Schema. + """ + ), + deprecated( + """ + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + """ + ), + ], ) -> Any: return params.Query( default=default, @@ -152,6 +632,7 @@ def Query( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -160,38 +641,220 @@ def Query( # noqa: N802 def Header( # noqa: N802 - default: Any = Undefined, + default: Annotated[ + Any, + Doc( + """ + Default value if the parameter field is not set. + """ + ), + ] = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, + default_factory: Annotated[ + Union[Callable[[], Any], None], + Doc( + """ + A callable to generate the default value. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = _Unset, + alias: Annotated[ + Optional[str], + Doc( + """ + An alternative name for the parameter field. + + This will be used to extract the data and for the generated OpenAPI. + It is particularly useful when you can't use the name you want because it + is a Python reserved keyword or similar. + """ + ), + ] = None, + alias_priority: Annotated[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, # TODO: update when deprecating Pydantic v1, import these types # validation_alias: str | AliasPath | AliasChoices | None - validation_alias: Union[str, None] = None, - serialization_alias: Union[str, None] = None, - convert_underscores: bool = True, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + validation_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Whitelist' validation step. The parameter field will be the single one + allowed by the alias or set of aliases defined. + """ + ), + ] = None, + serialization_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Blacklist' validation step. The vanilla parameter field will be the + single one of the alias' or set of aliases' fields and all the other + fields will be ignored at serialization time. + """ + ), + ] = None, + convert_underscores: Annotated[ + bool, + Doc( + """ + Automatically convert underscores to hyphens in the parameter field name. + + Read more about it in the + [FastAPI docs for Header Parameters](https://fastapi.tiangolo.com/tutorial/header-params/#automatic-conversion) + """ + ), + ] = True, + title: Annotated[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, regex: Annotated[ Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[List[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, example: Annotated[ Optional[Any], deprecated( @@ -199,10 +862,65 @@ def Header( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, - **extra: Any, + openapi_examples: Annotated[ + Optional[Dict[str, Example]], + Doc( + """ + OpenAPI-specific examples. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Swagger UI (that provides the `/docs` interface) has better support for the + OpenAPI-specific examples than the JSON Schema `examples`, that's the main + use case for this. + + Read more about it in the + [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this parameter field as deprecated. + + It will affect the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) this parameter field in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + json_schema_extra: Annotated[ + Union[Dict[str, Any], None], + Doc( + """ + Any additional JSON schema data. + """ + ), + ] = None, + **extra: Annotated[ + Any, + Doc( + """ + Include extra fields used by the JSON Schema. + """ + ), + deprecated( + """ + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + """ + ), + ], ) -> Any: return params.Header( default=default, @@ -230,6 +948,7 @@ def Header( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -238,37 +957,209 @@ def Header( # noqa: N802 def Cookie( # noqa: N802 - default: Any = Undefined, + default: Annotated[ + Any, + Doc( + """ + Default value if the parameter field is not set. + """ + ), + ] = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, + default_factory: Annotated[ + Union[Callable[[], Any], None], + Doc( + """ + A callable to generate the default value. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = _Unset, + alias: Annotated[ + Optional[str], + Doc( + """ + An alternative name for the parameter field. + + This will be used to extract the data and for the generated OpenAPI. + It is particularly useful when you can't use the name you want because it + is a Python reserved keyword or similar. + """ + ), + ] = None, + alias_priority: Annotated[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, # TODO: update when deprecating Pydantic v1, import these types # validation_alias: str | AliasPath | AliasChoices | None - validation_alias: Union[str, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + validation_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Whitelist' validation step. The parameter field will be the single one + allowed by the alias or set of aliases defined. + """ + ), + ] = None, + serialization_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Blacklist' validation step. The vanilla parameter field will be the + single one of the alias' or set of aliases' fields and all the other + fields will be ignored at serialization time. + """ + ), + ] = None, + title: Annotated[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, regex: Annotated[ Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[List[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, example: Annotated[ Optional[Any], deprecated( @@ -276,10 +1167,65 @@ def Cookie( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, - **extra: Any, + openapi_examples: Annotated[ + Optional[Dict[str, Example]], + Doc( + """ + OpenAPI-specific examples. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Swagger UI (that provides the `/docs` interface) has better support for the + OpenAPI-specific examples than the JSON Schema `examples`, that's the main + use case for this. + + Read more about it in the + [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this parameter field as deprecated. + + It will affect the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) this parameter field in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + json_schema_extra: Annotated[ + Union[Dict[str, Any], None], + Doc( + """ + Any additional JSON schema data. + """ + ), + ] = None, + **extra: Annotated[ + Any, + Doc( + """ + Include extra fields used by the JSON Schema. + """ + ), + deprecated( + """ + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + """ + ), + ], ) -> Any: return params.Cookie( default=default, @@ -306,6 +1252,7 @@ def Cookie( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -314,39 +1261,232 @@ def Cookie( # noqa: N802 def Body( # noqa: N802 - default: Any = Undefined, + default: Annotated[ + Any, + Doc( + """ + Default value if the parameter field is not set. + """ + ), + ] = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - embed: bool = False, - media_type: str = "application/json", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, + default_factory: Annotated[ + Union[Callable[[], Any], None], + Doc( + """ + A callable to generate the default value. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = _Unset, + embed: Annotated[ + bool, + Doc( + """ + When `embed` is `True`, the parameter will be expected in a JSON body as a + key instead of being the JSON body itself. + + This happens automatically when more than one `Body` parameter is declared. + + Read more about it in the + [FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter). + """ + ), + ] = False, + media_type: Annotated[ + str, + Doc( + """ + The media type of this parameter field. Changing it would affect the + generated OpenAPI, but currently it doesn't affect the parsing of the data. + """ + ), + ] = "application/json", + alias: Annotated[ + Optional[str], + Doc( + """ + An alternative name for the parameter field. + + This will be used to extract the data and for the generated OpenAPI. + It is particularly useful when you can't use the name you want because it + is a Python reserved keyword or similar. + """ + ), + ] = None, + alias_priority: Annotated[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, # TODO: update when deprecating Pydantic v1, import these types # validation_alias: str | AliasPath | AliasChoices | None - validation_alias: Union[str, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + validation_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Whitelist' validation step. The parameter field will be the single one + allowed by the alias or set of aliases defined. + """ + ), + ] = None, + serialization_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Blacklist' validation step. The vanilla parameter field will be the + single one of the alias' or set of aliases' fields and all the other + fields will be ignored at serialization time. + """ + ), + ] = None, + title: Annotated[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, regex: Annotated[ Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[List[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, example: Annotated[ Optional[Any], deprecated( @@ -354,10 +1494,65 @@ def Body( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, - **extra: Any, + openapi_examples: Annotated[ + Optional[Dict[str, Example]], + Doc( + """ + OpenAPI-specific examples. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Swagger UI (that provides the `/docs` interface) has better support for the + OpenAPI-specific examples than the JSON Schema `examples`, that's the main + use case for this. + + Read more about it in the + [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this parameter field as deprecated. + + It will affect the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) this parameter field in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + json_schema_extra: Annotated[ + Union[Dict[str, Any], None], + Doc( + """ + Any additional JSON schema data. + """ + ), + ] = None, + **extra: Annotated[ + Any, + Doc( + """ + Include extra fields used by the JSON Schema. + """ + ), + deprecated( + """ + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + """ + ), + ], ) -> Any: return params.Body( default=default, @@ -386,6 +1581,7 @@ def Body( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -394,38 +1590,218 @@ def Body( # noqa: N802 def Form( # noqa: N802 - default: Any = Undefined, + default: Annotated[ + Any, + Doc( + """ + Default value if the parameter field is not set. + """ + ), + ] = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - media_type: str = "application/x-www-form-urlencoded", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, + default_factory: Annotated[ + Union[Callable[[], Any], None], + Doc( + """ + A callable to generate the default value. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = _Unset, + media_type: Annotated[ + str, + Doc( + """ + The media type of this parameter field. Changing it would affect the + generated OpenAPI, but currently it doesn't affect the parsing of the data. + """ + ), + ] = "application/x-www-form-urlencoded", + alias: Annotated[ + Optional[str], + Doc( + """ + An alternative name for the parameter field. + + This will be used to extract the data and for the generated OpenAPI. + It is particularly useful when you can't use the name you want because it + is a Python reserved keyword or similar. + """ + ), + ] = None, + alias_priority: Annotated[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, # TODO: update when deprecating Pydantic v1, import these types # validation_alias: str | AliasPath | AliasChoices | None - validation_alias: Union[str, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + validation_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Whitelist' validation step. The parameter field will be the single one + allowed by the alias or set of aliases defined. + """ + ), + ] = None, + serialization_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Blacklist' validation step. The vanilla parameter field will be the + single one of the alias' or set of aliases' fields and all the other + fields will be ignored at serialization time. + """ + ), + ] = None, + title: Annotated[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, regex: Annotated[ Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[List[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, example: Annotated[ Optional[Any], deprecated( @@ -433,10 +1809,65 @@ def Form( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, - **extra: Any, + openapi_examples: Annotated[ + Optional[Dict[str, Example]], + Doc( + """ + OpenAPI-specific examples. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Swagger UI (that provides the `/docs` interface) has better support for the + OpenAPI-specific examples than the JSON Schema `examples`, that's the main + use case for this. + + Read more about it in the + [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this parameter field as deprecated. + + It will affect the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) this parameter field in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + json_schema_extra: Annotated[ + Union[Dict[str, Any], None], + Doc( + """ + Any additional JSON schema data. + """ + ), + ] = None, + **extra: Annotated[ + Any, + Doc( + """ + Include extra fields used by the JSON Schema. + """ + ), + deprecated( + """ + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + """ + ), + ], ) -> Any: return params.Form( default=default, @@ -464,6 +1895,7 @@ def Form( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -472,38 +1904,218 @@ def Form( # noqa: N802 def File( # noqa: N802 - default: Any = Undefined, + default: Annotated[ + Any, + Doc( + """ + Default value if the parameter field is not set. + """ + ), + ] = Undefined, *, - default_factory: Union[Callable[[], Any], None] = _Unset, - media_type: str = "multipart/form-data", - alias: Optional[str] = None, - alias_priority: Union[int, None] = _Unset, + default_factory: Annotated[ + Union[Callable[[], Any], None], + Doc( + """ + A callable to generate the default value. + + This doesn't affect `Path` parameters as the value is always required. + The parameter is available only for compatibility. + """ + ), + ] = _Unset, + media_type: Annotated[ + str, + Doc( + """ + The media type of this parameter field. Changing it would affect the + generated OpenAPI, but currently it doesn't affect the parsing of the data. + """ + ), + ] = "multipart/form-data", + alias: Annotated[ + Optional[str], + Doc( + """ + An alternative name for the parameter field. + + This will be used to extract the data and for the generated OpenAPI. + It is particularly useful when you can't use the name you want because it + is a Python reserved keyword or similar. + """ + ), + ] = None, + alias_priority: Annotated[ + Union[int, None], + Doc( + """ + Priority of the alias. This affects whether an alias generator is used. + """ + ), + ] = _Unset, # TODO: update when deprecating Pydantic v1, import these types # validation_alias: str | AliasPath | AliasChoices | None - validation_alias: Union[str, None] = None, - serialization_alias: Union[str, None] = None, - title: Optional[str] = None, - description: Optional[str] = None, - gt: Optional[float] = None, - ge: Optional[float] = None, - lt: Optional[float] = None, - le: Optional[float] = None, - min_length: Optional[int] = None, - max_length: Optional[int] = None, - pattern: Optional[str] = None, + validation_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Whitelist' validation step. The parameter field will be the single one + allowed by the alias or set of aliases defined. + """ + ), + ] = None, + serialization_alias: Annotated[ + Union[str, None], + Doc( + """ + 'Blacklist' validation step. The vanilla parameter field will be the + single one of the alias' or set of aliases' fields and all the other + fields will be ignored at serialization time. + """ + ), + ] = None, + title: Annotated[ + Optional[str], + Doc( + """ + Human-readable title. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Human-readable description. + """ + ), + ] = None, + gt: Annotated[ + Optional[float], + Doc( + """ + Greater than. If set, value must be greater than this. Only applicable to + numbers. + """ + ), + ] = None, + ge: Annotated[ + Optional[float], + Doc( + """ + Greater than or equal. If set, value must be greater than or equal to + this. Only applicable to numbers. + """ + ), + ] = None, + lt: Annotated[ + Optional[float], + Doc( + """ + Less than. If set, value must be less than this. Only applicable to numbers. + """ + ), + ] = None, + le: Annotated[ + Optional[float], + Doc( + """ + Less than or equal. If set, value must be less than or equal to this. + Only applicable to numbers. + """ + ), + ] = None, + min_length: Annotated[ + Optional[int], + Doc( + """ + Minimum length for strings. + """ + ), + ] = None, + max_length: Annotated[ + Optional[int], + Doc( + """ + Maximum length for strings. + """ + ), + ] = None, + pattern: Annotated[ + Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), + ] = None, regex: Annotated[ Optional[str], + Doc( + """ + RegEx pattern for strings. + """ + ), deprecated( "Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead." ), ] = None, - discriminator: Union[str, None] = None, - strict: Union[bool, None] = _Unset, - multiple_of: Union[float, None] = _Unset, - allow_inf_nan: Union[bool, None] = _Unset, - max_digits: Union[int, None] = _Unset, - decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + discriminator: Annotated[ + Union[str, None], + Doc( + """ + Parameter field name for discriminating the type in a tagged union. + """ + ), + ] = None, + strict: Annotated[ + Union[bool, None], + Doc( + """ + If `True`, strict validation is applied to the field. + """ + ), + ] = _Unset, + multiple_of: Annotated[ + Union[float, None], + Doc( + """ + Value must be a multiple of this. Only applicable to numbers. + """ + ), + ] = _Unset, + allow_inf_nan: Annotated[ + Union[bool, None], + Doc( + """ + Allow `inf`, `-inf`, `nan`. Only applicable to numbers. + """ + ), + ] = _Unset, + max_digits: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of allow digits for strings. + """ + ), + ] = _Unset, + decimal_places: Annotated[ + Union[int, None], + Doc( + """ + Maximum number of decimal places allowed for numbers. + """ + ), + ] = _Unset, + examples: Annotated[ + Optional[List[Any]], + Doc( + """ + Example values for this field. + """ + ), + ] = None, example: Annotated[ Optional[Any], deprecated( @@ -511,10 +2123,65 @@ def File( # noqa: N802 "although still supported. Use examples instead." ), ] = _Unset, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, - **extra: Any, + openapi_examples: Annotated[ + Optional[Dict[str, Example]], + Doc( + """ + OpenAPI-specific examples. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Swagger UI (that provides the `/docs` interface) has better support for the + OpenAPI-specific examples than the JSON Schema `examples`, that's the main + use case for this. + + Read more about it in the + [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this parameter field as deprecated. + + It will affect the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) this parameter field in the generated OpenAPI. + You probably don't need it, but it's available. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + json_schema_extra: Annotated[ + Union[Dict[str, Any], None], + Doc( + """ + Any additional JSON schema data. + """ + ), + ] = None, + **extra: Annotated[ + Any, + Doc( + """ + Include extra fields used by the JSON Schema. + """ + ), + deprecated( + """ + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + """ + ), + ], ) -> Any: return params.File( default=default, @@ -542,6 +2209,7 @@ def File( # noqa: N802 decimal_places=decimal_places, example=example, examples=examples, + openapi_examples=openapi_examples, deprecated=deprecated, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, @@ -550,15 +2218,143 @@ def File( # noqa: N802 def Depends( # noqa: N802 - dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True + dependency: Annotated[ + Optional[Callable[..., Any]], + Doc( + """ + A "dependable" callable (like a function). + + Don't call it directly, FastAPI will call it for you, just pass the object + directly. + """ + ), + ] = None, + *, + use_cache: Annotated[ + bool, + Doc( + """ + By default, after a dependency is called the first time in a request, if + the dependency is declared again for the rest of the request (for example + if the dependency is needed by several dependencies), the value will be + re-used for the rest of the request. + + Set `use_cache` to `False` to disable this behavior and ensure the + dependency is called again (if declared more than once) in the same request. + """ + ), + ] = True, ) -> Any: + """ + Declare a FastAPI dependency. + + It takes a single "dependable" callable (like a function). + + Don't call it directly, FastAPI will call it for you. + + Read more about it in the + [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/). + + **Example** + + ```python + from typing import Annotated + + from fastapi import Depends, FastAPI + + app = FastAPI() + + + async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100): + return {"q": q, "skip": skip, "limit": limit} + + + @app.get("/items/") + async def read_items(commons: Annotated[dict, Depends(common_parameters)]): + return commons + ``` + """ return params.Depends(dependency=dependency, use_cache=use_cache) def Security( # noqa: N802 - dependency: Optional[Callable[..., Any]] = None, + dependency: Annotated[ + Optional[Callable[..., Any]], + Doc( + """ + A "dependable" callable (like a function). + + Don't call it directly, FastAPI will call it for you, just pass the object + directly. + """ + ), + ] = None, *, - scopes: Optional[Sequence[str]] = None, - use_cache: bool = True, + scopes: Annotated[ + Optional[Sequence[str]], + Doc( + """ + OAuth2 scopes required for the *path operation* that uses this Security + dependency. + + The term "scope" comes from the OAuth2 specification, it seems to be + intentionaly vague and interpretable. It normally refers to permissions, + in cases to roles. + + These scopes are integrated with OpenAPI (and the API docs at `/docs`). + So they are visible in the OpenAPI specification. + ) + """ + ), + ] = None, + use_cache: Annotated[ + bool, + Doc( + """ + By default, after a dependency is called the first time in a request, if + the dependency is declared again for the rest of the request (for example + if the dependency is needed by several dependencies), the value will be + re-used for the rest of the request. + + Set `use_cache` to `False` to disable this behavior and ensure the + dependency is called again (if declared more than once) in the same request. + """ + ), + ] = True, ) -> Any: + """ + Declare a FastAPI Security dependency. + + The only difference with a regular dependency is that it can declare OAuth2 + scopes that will be integrated with OpenAPI and the automatic UI docs (by default + at `/docs`). + + It takes a single "dependable" callable (like a function). + + Don't call it directly, FastAPI will call it for you. + + Read more about it in the + [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/) and + in the + [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/). + + **Example** + + ```python + from typing import Annotated + + from fastapi import Depends, FastAPI + + from .db import User + from .security import get_current_active_user + + app = FastAPI() + + @app.get("/users/me/items/") + async def read_own_items( + current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])] + ): + return [{"item_id": "Foo", "owner": current_user.username}] + ``` + """ return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache) diff --git a/fastapi/params.py b/fastapi/params.py index 2d8100650..b40944dba 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -2,6 +2,7 @@ import warnings from enum import Enum from typing import Any, Callable, Dict, List, Optional, Sequence, Union +from fastapi.openapi.models import Example from pydantic.fields import FieldInfo from typing_extensions import Annotated, deprecated @@ -61,6 +62,7 @@ class Param(FieldInfo): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -75,6 +77,7 @@ class Param(FieldInfo): ) self.example = example self.include_in_schema = include_in_schema + self.openapi_examples = openapi_examples kwargs = dict( default=default, default_factory=default_factory, @@ -170,6 +173,7 @@ class Path(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -204,6 +208,7 @@ class Path(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -254,6 +259,7 @@ class Query(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -286,6 +292,7 @@ class Query(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -337,6 +344,7 @@ class Header(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -370,6 +378,7 @@ class Header(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -420,6 +429,7 @@ class Cookie(Param): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -452,6 +462,7 @@ class Cookie(Param): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -502,6 +513,7 @@ class Body(FieldInfo): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -518,6 +530,7 @@ class Body(FieldInfo): ) self.example = example self.include_in_schema = include_in_schema + self.openapi_examples = openapi_examples kwargs = dict( default=default, default_factory=default_factory, @@ -613,6 +626,7 @@ class Form(Body): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -647,6 +661,7 @@ class Form(Body): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, @@ -696,6 +711,7 @@ class File(Form): "although still supported. Use examples instead." ), ] = _Unset, + openapi_examples: Optional[Dict[str, Example]] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, json_schema_extra: Union[Dict[str, Any], None] = None, @@ -729,6 +745,7 @@ class File(Form): deprecated=deprecated, example=example, examples=examples, + openapi_examples=openapi_examples, include_in_schema=include_in_schema, json_schema_extra=json_schema_extra, **extra, diff --git a/fastapi/responses.py b/fastapi/responses.py index c0a13b755..6c8db6f33 100644 --- a/fastapi/responses.py +++ b/fastapi/responses.py @@ -21,12 +21,26 @@ except ImportError: # pragma: nocover class UJSONResponse(JSONResponse): + """ + JSON response using the high-performance ujson library to serialize data to JSON. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/). + """ + def render(self, content: Any) -> bytes: assert ujson is not None, "ujson must be installed to use UJSONResponse" return ujson.dumps(content, ensure_ascii=False).encode("utf-8") class ORJSONResponse(JSONResponse): + """ + JSON response using the high-performance orjson library to serialize data to JSON. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/). + """ + def render(self, content: Any) -> bytes: assert orjson is not None, "orjson must be installed to use ORJSONResponse" return orjson.dumps( diff --git a/fastapi/routing.py b/fastapi/routing.py index 1e3dfb4d5..54d53bbbf 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -69,6 +69,7 @@ from starlette.routing import ( from starlette.routing import Mount as Mount # noqa from starlette.types import ASGIApp, Lifespan, Scope from starlette.websockets import WebSocket +from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined] def _prepare_response_content( @@ -519,30 +520,246 @@ class APIRoute(routing.Route): class APIRouter(routing.Router): + """ + `APIRouter` class, used to group *path operations*, for example to structure + an app in multiple files. It would then be included in the `FastAPI` app, or + in another `APIRouter` (ultimately included in the app). + + Read more about it in the + [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/). + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + + app = FastAPI() + router = APIRouter() + + + @router.get("/users/", tags=["users"]) + async def read_users(): + return [{"username": "Rick"}, {"username": "Morty"}] + + + app.include_router(router) + ``` + """ + def __init__( self, *, - prefix: str = "", - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - default_response_class: Type[Response] = Default(JSONResponse), - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - callbacks: Optional[List[BaseRoute]] = None, - routes: Optional[List[routing.BaseRoute]] = None, - redirect_slashes: bool = True, - default: Optional[ASGIApp] = None, - dependency_overrides_provider: Optional[Any] = None, - route_class: Type[APIRoute] = APIRoute, - on_startup: Optional[Sequence[Callable[[], Any]]] = None, - on_shutdown: Optional[Sequence[Callable[[], Any]]] = None, + prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to all the *path operations* in this + router. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to all the + *path operations* in this router. + + Read more about it in the + [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). + """ + ), + ] = None, + default_response_class: Annotated[ + Type[Response], + Doc( + """ + The default response class to be used. + + Read more in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). + """ + ), + ] = Default(JSONResponse), + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses to be shown in OpenAPI. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). + + And in the + [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + OpenAPI callbacks that should apply to all *path operations* in this + router. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + routes: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + **Note**: you probably shouldn't use this parameter, it is inherited + from Starlette and supported for compatibility. + + --- + + A list of routes to serve incoming HTTP and WebSocket requests. + """ + ), + deprecated( + """ + You normally wouldn't use this parameter with FastAPI, it is inherited + from Starlette and supported for compatibility. + + In FastAPI, you normally would use the *path operation methods*, + like `router.get()`, `router.post()`, etc. + """ + ), + ] = None, + redirect_slashes: Annotated[ + bool, + Doc( + """ + Whether to detect and redirect slashes in URLs when the client doesn't + use the same format. + """ + ), + ] = True, + default: Annotated[ + Optional[ASGIApp], + Doc( + """ + Default function handler for this router. Used to handle + 404 Not Found errors. + """ + ), + ] = None, + dependency_overrides_provider: Annotated[ + Optional[Any], + Doc( + """ + Only used internally by FastAPI to handle dependency overrides. + + You shouldn't need to use it. It normally points to the `FastAPI` app + object. + """ + ), + ] = None, + route_class: Annotated[ + Type[APIRoute], + Doc( + """ + Custom route (*path operation*) class to be used by this router. + + Read more about it in the + [FastAPI docs for Custom Request and APIRoute class](https://fastapi.tiangolo.com/how-to/custom-request-and-route/#custom-apiroute-class-in-a-router). + """ + ), + ] = APIRoute, + on_startup: Annotated[ + Optional[Sequence[Callable[[], Any]]], + Doc( + """ + A list of startup event handler functions. + + You should instead use the `lifespan` handlers. + + Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). + """ + ), + ] = None, + on_shutdown: Annotated[ + Optional[Sequence[Callable[[], Any]]], + Doc( + """ + A list of shutdown event handler functions. + + You should instead use the `lifespan` handlers. + + Read more in the + [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). + """ + ), + ] = None, # the generic to Lifespan[AppType] is the type of the top level application # which the router cannot know statically, so we use typing.Any - lifespan: Optional[Lifespan[Any]] = None, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + lifespan: Annotated[ + Optional[Lifespan[Any]], + Doc( + """ + A `Lifespan` context manager handler. This replaces `startup` and + `shutdown` functions with a single context manager. + + Read more in the + [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark all *path operations* in this router as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + To include (or not) all the *path operations* in this router in the + generated OpenAPI. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> None: super().__init__( routes=routes, @@ -755,11 +972,63 @@ class APIRouter(routing.Router): def websocket( self, - path: str, - name: Optional[str] = None, + path: Annotated[ + str, + Doc( + """ + WebSocket path. + """ + ), + ], + name: Annotated[ + Optional[str], + Doc( + """ + A name for the WebSocket. Only used internally. + """ + ), + ] = None, *, - dependencies: Optional[Sequence[params.Depends]] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be used for this + WebSocket. + + Read more about it in the + [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). + """ + ), + ] = None, ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Decorate a WebSocket function. + + Read more about it in the + [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/). + + **Example** + + ## Example + + ```python + from fastapi import APIRouter, FastAPI, WebSocket + + app = FastAPI() + router = APIRouter() + + @router.websocket("/ws") + async def websocket_endpoint(websocket: WebSocket): + await websocket.accept() + while True: + data = await websocket.receive_text() + await websocket.send_text(f"Message text was: {data}") + + app.include_router(router) + ``` + """ + def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_api_websocket_route( path, func, name=name, dependencies=dependencies @@ -779,20 +1048,139 @@ class APIRouter(routing.Router): def include_router( self, - router: "APIRouter", + router: Annotated["APIRouter", Doc("The `APIRouter` to include.")], *, - prefix: str = "", - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - default_response_class: Type[Response] = Default(JSONResponse), - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - callbacks: Optional[List[BaseRoute]] = None, - deprecated: Optional[bool] = None, - include_in_schema: bool = True, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to all the *path operations* in this + router. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to all the + *path operations* in this router. + + Read more about it in the + [FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). + """ + ), + ] = None, + default_response_class: Annotated[ + Type[Response], + Doc( + """ + The default response class to be used. + + Read more in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class). + """ + ), + ] = Default(JSONResponse), + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses to be shown in OpenAPI. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/). + + And in the + [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies). + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + OpenAPI callbacks that should apply to all *path operations* in this + router. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark all *path operations* in this router as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include (or not) all the *path operations* in this router in the + generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = True, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> None: + """ + Include another `APIRouter` in the same current `APIRouter`. + + Read more about it in the + [FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/). + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + + app = FastAPI() + internal_router = APIRouter() + users_router = APIRouter() + + @users_router.get("/users/") + def read_users(): + return [{"name": "Rick"}, {"name": "Morty"}] + + internal_router.include_router(users_router) + app.include_router(internal_router) + ``` + """ if prefix: assert prefix.startswith("/"), "A path prefix must start with '/'" assert not prefix.endswith( @@ -900,33 +1288,354 @@ class APIRouter(routing.Router): def get( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP GET operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + + app = FastAPI() + router = APIRouter() + + @router.get("/items/") + def read_items(): + return [{"name": "Empanada"}, {"name": "Arepa"}] + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -956,33 +1665,359 @@ class APIRouter(routing.Router): def put( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP PUT operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + router = APIRouter() + + @router.put("/items/{item_id}") + def replace_item(item_id: str, item: Item): + return {"message": "Item replaced", "id": item_id} + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -1012,33 +2047,359 @@ class APIRouter(routing.Router): def post( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP POST operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + router = APIRouter() + + @router.post("/items/") + def create_item(item: Item): + return {"message": "Item created"} + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -1068,33 +2429,354 @@ class APIRouter(routing.Router): def delete( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP DELETE operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + + app = FastAPI() + router = APIRouter() + + @router.delete("/items/{item_id}") + def delete_item(item_id: str): + return {"message": "Item deleted"} + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -1124,33 +2806,354 @@ class APIRouter(routing.Router): def options( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP OPTIONS operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + + app = FastAPI() + router = APIRouter() + + @router.options("/items/") + def get_item_options(): + return {"additions": ["Aji", "Guacamole"]} + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -1180,33 +3183,359 @@ class APIRouter(routing.Router): def head( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP HEAD operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + router = APIRouter() + + @router.head("/items/", status_code=204) + def get_items_headers(response: Response): + response.headers["X-Cat-Dog"] = "Alone in the world" + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -1236,33 +3565,359 @@ class APIRouter(routing.Router): def patch( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP PATCH operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + router = APIRouter() + + @router.patch("/items/") + def update_item(item: Item): + return {"message": "Item updated in place"} + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -1292,33 +3947,359 @@ class APIRouter(routing.Router): def trace( self, - path: str, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/items`, the path is `/items`. + """ + ), + ], *, - response_model: Any = Default(None), - status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, - dependencies: Optional[Sequence[params.Depends]] = None, - summary: Optional[str] = None, - description: Optional[str] = None, - response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - deprecated: Optional[bool] = None, - operation_id: Optional[str] = None, - response_model_include: Optional[IncEx] = None, - response_model_exclude: Optional[IncEx] = None, - response_model_by_alias: bool = True, - response_model_exclude_unset: bool = False, - response_model_exclude_defaults: bool = False, - response_model_exclude_none: bool = False, - include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), - name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, - generate_unique_id_function: Callable[[APIRoute], str] = Default( - generate_unique_id - ), + response_model: Annotated[ + Any, + Doc( + """ + The type to use for the response. + + It could be any valid Pydantic *field* type. So, it doesn't have to + be a Pydantic model, it could be other things, like a `list`, `dict`, + etc. + + It will be used for: + + * Documentation: the generated OpenAPI (and the UI at `/docs`) will + show it as the response (JSON Schema). + * Serialization: you could return an arbitrary object and the + `response_model` would be used to serialize that object into the + corresponding JSON. + * Filtering: the JSON sent to the client will only contain the data + (fields) defined in the `response_model`. If you returned an object + that contains an attribute `password` but the `response_model` does + not include that field, the JSON sent to the client would not have + that `password`. + * Validation: whatever you return will be serialized with the + `response_model`, converting any data as necessary to generate the + corresponding JSON. But if the data in the object returned is not + valid, that would mean a violation of the contract with the client, + so it's an error from the API developer. So, FastAPI will raise an + error and return a 500 error code (Internal Server Error). + + Read more about it in the + [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/). + """ + ), + ] = Default(None), + status_code: Annotated[ + Optional[int], + Doc( + """ + The default status code to be used for the response. + + You could override the status code by returning a response directly. + + Read more about it in the + [FastAPI docs for Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). + """ + ), + ] = None, + tags: Annotated[ + Optional[List[Union[str, Enum]]], + Doc( + """ + A list of tags to be applied to the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/#tags). + """ + ), + ] = None, + dependencies: Annotated[ + Optional[Sequence[params.Depends]], + Doc( + """ + A list of dependencies (using `Depends()`) to be applied to the + *path operation*. + + Read more about it in the + [FastAPI docs for Dependencies in path operation decorators](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-in-path-operation-decorators/). + """ + ), + ] = None, + summary: Annotated[ + Optional[str], + Doc( + """ + A summary for the *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + A description for the *path operation*. + + If not provided, it will be extracted automatically from the docstring + of the *path operation function*. + + It can contain Markdown. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/). + """ + ), + ] = None, + response_description: Annotated[ + str, + Doc( + """ + The description for the default response. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = "Successful Response", + responses: Annotated[ + Optional[Dict[Union[int, str], Dict[str, Any]]], + Doc( + """ + Additional responses that could be returned by this *path operation*. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + deprecated: Annotated[ + Optional[bool], + Doc( + """ + Mark this *path operation* as deprecated. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + operation_id: Annotated[ + Optional[str], + Doc( + """ + Custom operation ID to be used by this *path operation*. + + By default, it is generated automatically. + + If you provide a custom operation ID, you need to make sure it is + unique for the whole API. + + You can customize the + operation ID generation with the parameter + `generate_unique_id_function` in the `FastAPI` class. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = None, + response_model_include: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to include only certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_exclude: Annotated[ + Optional[IncEx], + Doc( + """ + Configuration passed to Pydantic to exclude certain fields in the + response data. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = None, + response_model_by_alias: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response model + should be serialized by alias when an alias is used. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_include-and-response_model_exclude). + """ + ), + ] = True, + response_model_exclude_unset: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that were not set and + have their default values. This is different from + `response_model_exclude_defaults` in that if the fields are set, + they will be included in the response, even if the value is the same + as the default. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_defaults: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data + should have all the fields, including the ones that have the same value + as the default. This is different from `response_model_exclude_unset` + in that if the fields are set but contain the same default values, + they will be excluded from the response. + + When `True`, default values are omitted from the response. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#use-the-response_model_exclude_unset-parameter). + """ + ), + ] = False, + response_model_exclude_none: Annotated[ + bool, + Doc( + """ + Configuration passed to Pydantic to define if the response data should + exclude fields set to `None`. + + This is much simpler (less smart) than `response_model_exclude_unset` + and `response_model_exclude_defaults`. You probably want to use one of + those two instead of this one, as those allow returning `None` values + when it makes sense. + + Read more about it in the + [FastAPI docs for Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/#response_model_exclude_none). + """ + ), + ] = False, + include_in_schema: Annotated[ + bool, + Doc( + """ + Include this *path operation* in the generated OpenAPI schema. + + This affects the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + """ + ), + ] = True, + response_class: Annotated[ + Type[Response], + Doc( + """ + Response class to be used for this *path operation*. + + This will not be used if you return a response directly. + + Read more about it in the + [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#redirectresponse). + """ + ), + ] = Default(JSONResponse), + name: Annotated[ + Optional[str], + Doc( + """ + Name for this *path operation*. Only used internally. + """ + ), + ] = None, + callbacks: Annotated[ + Optional[List[BaseRoute]], + Doc( + """ + List of *path operations* that will be used as OpenAPI callbacks. + + This is only for OpenAPI documentation, the callbacks won't be used + directly. + + It will be added to the generated OpenAPI (e.g. visible at `/docs`). + + Read more about it in the + [FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/). + """ + ), + ] = None, + openapi_extra: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + Extra metadata to be included in the OpenAPI schema for this *path + operation*. + + Read more about it in the + [FastAPI docs for Path Operation Advanced Configuration](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#custom-openapi-path-operation-schema). + """ + ), + ] = None, + generate_unique_id_function: Annotated[ + Callable[[APIRoute], str], + Doc( + """ + Customize the function used to generate unique IDs for the *path + operations* shown in the generated OpenAPI. + + This is particularly useful when automatically generating clients or + SDKs for your API. + + Read more about it in the + [FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function). + """ + ), + ] = Default(generate_unique_id), ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *path operation* using an HTTP TRACE operation. + + ## Example + + ```python + from fastapi import APIRouter, FastAPI + from pydantic import BaseModel + + class Item(BaseModel): + name: str + description: str | None = None + + app = FastAPI() + router = APIRouter() + + @router.put("/items/{item_id}") + def trace_item(item_id: str): + return None + + app.include_router(router) + ``` + """ return self.api_route( path=path, response_model=response_model, @@ -1346,9 +4327,34 @@ class APIRouter(routing.Router): generate_unique_id_function=generate_unique_id_function, ) + @deprecated( + """ + on_event is deprecated, use lifespan event handlers instead. + + Read more about it in the + [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/). + """ + ) def on_event( - self, event_type: str + self, + event_type: Annotated[ + str, + Doc( + """ + The type of event. `startup` or `shutdown`. + """ + ), + ], ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add an event handler for the router. + + `on_event` is deprecated, use `lifespan` event handlers instead. + + Read more about it in the + [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated). + """ + def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_event_handler(event_type, func) return func diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py index 8b2c5c080..b1a6b4f94 100644 --- a/fastapi/security/api_key.py +++ b/fastapi/security/api_key.py @@ -5,6 +5,7 @@ from fastapi.security.base import SecurityBase from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.status import HTTP_403_FORBIDDEN +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] class APIKeyBase(SecurityBase): @@ -12,13 +13,83 @@ class APIKeyBase(SecurityBase): class APIKeyQuery(APIKeyBase): + """ + API key authentication using a query parameter. + + This defines the name of the query parameter that should be provided in the request + with the API key and integrates that into the OpenAPI documentation. It extracts + the key value sent in the query parameter automatically and provides it as the + dependency result. But it doesn't define how to send that API key to the client. + + ## Usage + + Create an instance object and use that object as the dependency in `Depends()`. + + The dependency result will be a string containing the key value. + + ## Example + + ```python + from fastapi import Depends, FastAPI + from fastapi.security import APIKeyQuery + + app = FastAPI() + + query_scheme = APIKeyQuery(name="api_key") + + + @app.get("/items/") + async def read_items(api_key: str = Depends(query_scheme)): + return {"api_key": api_key} + ``` + """ + def __init__( self, *, - name: str, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + name: Annotated[ + str, + Doc("Query parameter name."), + ], + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if the query parameter is not provided, `APIKeyQuery` will + automatically cancel the request and sebd the client an error. + + If `auto_error` is set to `False`, when the query parameter is not + available, instead of erroring out, the dependency result will be + `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, in a query + parameter or in an HTTP Bearer token). + """ + ), + ] = True, ): self.model: APIKey = APIKey( **{"in": APIKeyIn.query}, # type: ignore[arg-type] @@ -41,13 +112,79 @@ class APIKeyQuery(APIKeyBase): class APIKeyHeader(APIKeyBase): + """ + API key authentication using a header. + + This defines the name of the header that should be provided in the request with + the API key and integrates that into the OpenAPI documentation. It extracts + the key value sent in the header automatically and provides it as the dependency + result. But it doesn't define how to send that key to the client. + + ## Usage + + Create an instance object and use that object as the dependency in `Depends()`. + + The dependency result will be a string containing the key value. + + ## Example + + ```python + from fastapi import Depends, FastAPI + from fastapi.security import APIKeyHeader + + app = FastAPI() + + header_scheme = APIKeyHeader(name="x-key") + + + @app.get("/items/") + async def read_items(key: str = Depends(header_scheme)): + return {"key": key} + ``` + """ + def __init__( self, *, - name: str, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + name: Annotated[str, Doc("Header name.")], + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if the header is not provided, `APIKeyHeader` will + automatically cancel the request and send the client an error. + + If `auto_error` is set to `False`, when the header is not available, + instead of erroring out, the dependency result will be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, in a header or + in an HTTP Bearer token). + """ + ), + ] = True, ): self.model: APIKey = APIKey( **{"in": APIKeyIn.header}, # type: ignore[arg-type] @@ -70,13 +207,79 @@ class APIKeyHeader(APIKeyBase): class APIKeyCookie(APIKeyBase): + """ + API key authentication using a cookie. + + This defines the name of the cookie that should be provided in the request with + the API key and integrates that into the OpenAPI documentation. It extracts + the key value sent in the cookie automatically and provides it as the dependency + result. But it doesn't define how to set that cookie. + + ## Usage + + Create an instance object and use that object as the dependency in `Depends()`. + + The dependency result will be a string containing the key value. + + ## Example + + ```python + from fastapi import Depends, FastAPI + from fastapi.security import APIKeyCookie + + app = FastAPI() + + cookie_scheme = APIKeyCookie(name="session") + + + @app.get("/items/") + async def read_items(session: str = Depends(cookie_scheme)): + return {"session": session} + ``` + """ + def __init__( self, *, - name: str, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + name: Annotated[str, Doc("Cookie name.")], + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if the cookie is not provided, `APIKeyCookie` will + automatically cancel the request and send the client an error. + + If `auto_error` is set to `False`, when the cookie is not available, + instead of erroring out, the dependency result will be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, in a cookie or + in an HTTP Bearer token). + """ + ), + ] = True, ): self.model: APIKey = APIKey( **{"in": APIKeyIn.cookie}, # type: ignore[arg-type] diff --git a/fastapi/security/http.py b/fastapi/security/http.py index 8fc0aafd9..738455de3 100644 --- a/fastapi/security/http.py +++ b/fastapi/security/http.py @@ -10,16 +10,60 @@ from fastapi.security.utils import get_authorization_scheme_param from pydantic import BaseModel from starlette.requests import Request from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] class HTTPBasicCredentials(BaseModel): - username: str - password: str + """ + The HTTP Basic credendials given as the result of using `HTTPBasic` in a + dependency. + + Read more about it in the + [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/). + """ + + username: Annotated[str, Doc("The HTTP Basic username.")] + password: Annotated[str, Doc("The HTTP Basic password.")] class HTTPAuthorizationCredentials(BaseModel): - scheme: str - credentials: str + """ + The HTTP authorization credentials in the result of using `HTTPBearer` or + `HTTPDigest` in a dependency. + + The HTTP authorization header value is split by the first space. + + The first part is the `scheme`, the second part is the `credentials`. + + For example, in an HTTP Bearer token scheme, the client will send a header + like: + + ``` + Authorization: Bearer deadbeef12346 + ``` + + In this case: + + * `scheme` will have the value `"Bearer"` + * `credentials` will have the value `"deadbeef12346"` + """ + + scheme: Annotated[ + str, + Doc( + """ + The HTTP authorization scheme extracted from the header value. + """ + ), + ] + credentials: Annotated[ + str, + Doc( + """ + The HTTP authorization credentials extracted from the header value. + """ + ), + ] class HTTPBase(SecurityBase): @@ -51,13 +95,89 @@ class HTTPBase(SecurityBase): class HTTPBasic(HTTPBase): + """ + HTTP Basic authentication. + + ## Usage + + Create an instance object and use that object as the dependency in `Depends()`. + + The dependency result will be an `HTTPBasicCredentials` object containing the + `username` and the `password`. + + Read more about it in the + [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/). + + ## Example + + ```python + from typing import Annotated + + from fastapi import Depends, FastAPI + from fastapi.security import HTTPBasic, HTTPBasicCredentials + + app = FastAPI() + + security = HTTPBasic() + + + @app.get("/users/me") + def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]): + return {"username": credentials.username, "password": credentials.password} + ``` + """ + def __init__( self, *, - scheme_name: Optional[str] = None, - realm: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + realm: Annotated[ + Optional[str], + Doc( + """ + HTTP Basic authentication realm. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if the HTTP Basic authentication is not provided (a + header), `HTTPBasic` will automatically cancel the request and send the + client an error. + + If `auto_error` is set to `False`, when the HTTP Basic authentication + is not available, instead of erroring out, the dependency result will + be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, in HTTP Basic + authentication or in an HTTP Bearer token). + """ + ), + ] = True, ): self.model = HTTPBaseModel(scheme="basic", description=description) self.scheme_name = scheme_name or self.__class__.__name__ @@ -90,7 +210,7 @@ class HTTPBasic(HTTPBase): try: data = b64decode(param).decode("ascii") except (ValueError, UnicodeDecodeError, binascii.Error): - raise invalid_user_credentials_exc + raise invalid_user_credentials_exc # noqa: B904 username, separator, password = data.partition(":") if not separator: raise invalid_user_credentials_exc @@ -98,13 +218,81 @@ class HTTPBasic(HTTPBase): class HTTPBearer(HTTPBase): + """ + HTTP Bearer token authentication. + + ## Usage + + Create an instance object and use that object as the dependency in `Depends()`. + + The dependency result will be an `HTTPAuthorizationCredentials` object containing + the `scheme` and the `credentials`. + + ## Example + + ```python + from typing import Annotated + + from fastapi import Depends, FastAPI + from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer + + app = FastAPI() + + security = HTTPBearer() + + + @app.get("/users/me") + def read_current_user( + credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)] + ): + return {"scheme": credentials.scheme, "credentials": credentials.credentials} + ``` + """ + def __init__( self, *, - bearerFormat: Optional[str] = None, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + bearerFormat: Annotated[Optional[str], Doc("Bearer token format.")] = None, + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if the HTTP Bearer token not provided (in an + `Authorization` header), `HTTPBearer` will automatically cancel the + request and send the client an error. + + If `auto_error` is set to `False`, when the HTTP Bearer token + is not available, instead of erroring out, the dependency result will + be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, in an HTTP + Bearer token or in a cookie). + """ + ), + ] = True, ): self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description) self.scheme_name = scheme_name or self.__class__.__name__ @@ -134,12 +322,79 @@ class HTTPBearer(HTTPBase): class HTTPDigest(HTTPBase): + """ + HTTP Digest authentication. + + ## Usage + + Create an instance object and use that object as the dependency in `Depends()`. + + The dependency result will be an `HTTPAuthorizationCredentials` object containing + the `scheme` and the `credentials`. + + ## Example + + ```python + from typing import Annotated + + from fastapi import Depends, FastAPI + from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest + + app = FastAPI() + + security = HTTPDigest() + + + @app.get("/users/me") + def read_current_user( + credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)] + ): + return {"scheme": credentials.scheme, "credentials": credentials.credentials} + ``` + """ + def __init__( self, *, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if the HTTP Digest not provided, `HTTPDigest` will + automatically cancel the request and send the client an error. + + If `auto_error` is set to `False`, when the HTTP Digest is not + available, instead of erroring out, the dependency result will + be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, in HTTP + Digest or in a cookie). + """ + ), + ] = True, ): self.model = HTTPBaseModel(scheme="digest", description=description) self.scheme_name = scheme_name or self.__class__.__name__ diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py index e4c4357e7..9281dfb64 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -10,51 +10,136 @@ from starlette.requests import Request from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN # TODO: import from typing when deprecating Python 3.9 -from typing_extensions import Annotated +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] class OAuth2PasswordRequestForm: """ - This is a dependency class, use it like: + This is a dependency class to collect the `username` and `password` as form data + for an OAuth2 password flow. - @app.post("/login") - def login(form_data: OAuth2PasswordRequestForm = Depends()): - data = form_data.parse() - print(data.username) - print(data.password) - for scope in data.scopes: - print(scope) - if data.client_id: - print(data.client_id) - if data.client_secret: - print(data.client_secret) - return data + The OAuth2 specification dictates that for a password flow the data should be + collected using form data (instead of JSON) and that it should have the specific + fields `username` and `password`. + + All the initialization parameters are extracted from the request. + + Read more about it in the + [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). + + ## Example + + ```python + from typing import Annotated + + from fastapi import Depends, FastAPI + from fastapi.security import OAuth2PasswordRequestForm + + app = FastAPI() - It creates the following Form request parameters in your endpoint: + @app.post("/login") + def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): + data = {} + data["scopes"] = [] + for scope in form_data.scopes: + data["scopes"].append(scope) + if form_data.client_id: + data["client_id"] = form_data.client_id + if form_data.client_secret: + data["client_secret"] = form_data.client_secret + return data + ``` - grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password". - Nevertheless, this dependency class is permissive and allows not passing it. If you want to enforce it, - use instead the OAuth2PasswordRequestFormStrict dependency. - username: username string. The OAuth2 spec requires the exact field name "username". - password: password string. The OAuth2 spec requires the exact field name "password". - scope: Optional string. Several scopes (each one a string) separated by spaces. E.g. - "items:read items:write users:read profile openid" - client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any) - using HTTP Basic auth, as: client_id:client_secret - client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any) - using HTTP Basic auth, as: client_id:client_secret + Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. + You could have custom internal logic to separate it by colon caracters (`:`) or + similar, and get the two parts `items` and `read`. Many applications do that to + group and organize permisions, you could do it as well in your application, just + know that that it is application specific, it's not part of the specification. """ def __init__( self, *, - grant_type: Annotated[Union[str, None], Form(pattern="password")] = None, - username: Annotated[str, Form()], - password: Annotated[str, Form()], - scope: Annotated[str, Form()] = "", - client_id: Annotated[Union[str, None], Form()] = None, - client_secret: Annotated[Union[str, None], Form()] = None, + grant_type: Annotated[ + Union[str, None], + Form(pattern="password"), + Doc( + """ + The OAuth2 spec says it is required and MUST be the fixed string + "password". Nevertheless, this dependency class is permissive and + allows not passing it. If you want to enforce it, use instead the + `OAuth2PasswordRequestFormStrict` dependency. + """ + ), + ] = None, + username: Annotated[ + str, + Form(), + Doc( + """ + `username` string. The OAuth2 spec requires the exact field name + `username`. + """ + ), + ], + password: Annotated[ + str, + Form(), + Doc( + """ + `password` string. The OAuth2 spec requires the exact field name + `password". + """ + ), + ], + scope: Annotated[ + str, + Form(), + Doc( + """ + A single string with actually several scopes separated by spaces. Each + scope is also a string. + + For example, a single string with: + + ```python + "items:read items:write users:read profile openid" + ```` + + would represent the scopes: + + * `items:read` + * `items:write` + * `users:read` + * `profile` + * `openid` + """ + ), + ] = "", + client_id: Annotated[ + Union[str, None], + Form(), + Doc( + """ + If there's a `client_id`, it can be sent as part of the form fields. + But the OAuth2 specification recommends sending the `client_id` and + `client_secret` (if any) using HTTP Basic auth. + """ + ), + ] = None, + client_secret: Annotated[ + Union[str, None], + Form(), + Doc( + """ + If there's a `client_password` (and a `client_id`), they can be sent + as part of the form fields. But the OAuth2 specification recommends + sending the `client_id` and `client_secret` (if any) using HTTP Basic + auth. + """ + ), + ] = None, ): self.grant_type = grant_type self.username = username @@ -66,23 +151,54 @@ class OAuth2PasswordRequestForm: class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): """ - This is a dependency class, use it like: + This is a dependency class to collect the `username` and `password` as form data + for an OAuth2 password flow. - @app.post("/login") - def login(form_data: OAuth2PasswordRequestFormStrict = Depends()): - data = form_data.parse() - print(data.username) - print(data.password) - for scope in data.scopes: - print(scope) - if data.client_id: - print(data.client_id) - if data.client_secret: - print(data.client_secret) - return data + The OAuth2 specification dictates that for a password flow the data should be + collected using form data (instead of JSON) and that it should have the specific + fields `username` and `password`. + + All the initialization parameters are extracted from the request. + + The only difference between `OAuth2PasswordRequestFormStrict` and + `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the + client to send the form field `grant_type` with the value `"password"`, which + is required in the OAuth2 specification (it seems that for no particular reason), + while for `OAuth2PasswordRequestForm` `grant_type` is optional. + + Read more about it in the + [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). + + ## Example + + ```python + from typing import Annotated + + from fastapi import Depends, FastAPI + from fastapi.security import OAuth2PasswordRequestForm + + app = FastAPI() - It creates the following Form request parameters in your endpoint: + @app.post("/login") + def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]): + data = {} + data["scopes"] = [] + for scope in form_data.scopes: + data["scopes"].append(scope) + if form_data.client_id: + data["client_id"] = form_data.client_id + if form_data.client_secret: + data["client_secret"] = form_data.client_secret + return data + ``` + + Note that for OAuth2 the scope `items:read` is a single scope in an opaque string. + You could have custom internal logic to separate it by colon caracters (`:`) or + similar, and get the two parts `items` and `read`. Many applications do that to + group and organize permisions, you could do it as well in your application, just + know that that it is application specific, it's not part of the specification. + grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password". This dependency is strict about it. If you want to be permissive, use instead the @@ -99,12 +215,85 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): def __init__( self, - grant_type: Annotated[str, Form(pattern="password")], - username: Annotated[str, Form()], - password: Annotated[str, Form()], - scope: Annotated[str, Form()] = "", - client_id: Annotated[Union[str, None], Form()] = None, - client_secret: Annotated[Union[str, None], Form()] = None, + grant_type: Annotated[ + str, + Form(pattern="password"), + Doc( + """ + The OAuth2 spec says it is required and MUST be the fixed string + "password". This dependency is strict about it. If you want to be + permissive, use instead the `OAuth2PasswordRequestForm` dependency + class. + """ + ), + ], + username: Annotated[ + str, + Form(), + Doc( + """ + `username` string. The OAuth2 spec requires the exact field name + `username`. + """ + ), + ], + password: Annotated[ + str, + Form(), + Doc( + """ + `password` string. The OAuth2 spec requires the exact field name + `password". + """ + ), + ], + scope: Annotated[ + str, + Form(), + Doc( + """ + A single string with actually several scopes separated by spaces. Each + scope is also a string. + + For example, a single string with: + + ```python + "items:read items:write users:read profile openid" + ```` + + would represent the scopes: + + * `items:read` + * `items:write` + * `users:read` + * `profile` + * `openid` + """ + ), + ] = "", + client_id: Annotated[ + Union[str, None], + Form(), + Doc( + """ + If there's a `client_id`, it can be sent as part of the form fields. + But the OAuth2 specification recommends sending the `client_id` and + `client_secret` (if any) using HTTP Basic auth. + """ + ), + ] = None, + client_secret: Annotated[ + Union[str, None], + Form(), + Doc( + """ + If there's a `client_password` (and a `client_id`), they can be sent + as part of the form fields. But the OAuth2 specification recommends + sending the `client_id` and `client_secret` (if any) using HTTP Basic + auth. + """ + ), + ] = None, ): super().__init__( grant_type=grant_type, @@ -117,13 +306,69 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): class OAuth2(SecurityBase): + """ + This is the base class for OAuth2 authentication, an instance of it would be used + as a dependency. All other OAuth2 classes inherit from it and customize it for + each OAuth2 flow. + + You normally would not create a new class inheriting from it but use one of the + existing subclasses, and maybe compose them if you want to support multiple flows. + + Read more about it in the + [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/). + """ + def __init__( self, *, - flows: Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]] = OAuthFlowsModel(), - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + flows: Annotated[ + Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]], + Doc( + """ + The dictionary of OAuth2 flows. + """ + ), + ] = OAuthFlowsModel(), + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if no HTTP Auhtorization header is provided, required for + OAuth2 authentication, it will automatically cancel the request and + send the client an error. + + If `auto_error` is set to `False`, when the HTTP Authorization header + is not available, instead of erroring out, the dependency result will + be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, with OAuth2 + or in a cookie). + """ + ), + ] = True, ): self.model = OAuth2Model( flows=cast(OAuthFlowsModel, flows), description=description @@ -144,13 +389,74 @@ class OAuth2(SecurityBase): class OAuth2PasswordBearer(OAuth2): + """ + OAuth2 flow for authentication using a bearer token obtained with a password. + An instance of it would be used as a dependency. + + Read more about it in the + [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/). + """ + def __init__( self, - tokenUrl: str, - scheme_name: Optional[str] = None, - scopes: Optional[Dict[str, str]] = None, - description: Optional[str] = None, - auto_error: bool = True, + tokenUrl: Annotated[ + str, + Doc( + """ + The URL to obtain the OAuth2 token. This would be the *path operation* + that has `OAuth2PasswordRequestForm` as a dependency. + """ + ), + ], + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + scopes: Annotated[ + Optional[Dict[str, str]], + Doc( + """ + The OAuth2 scopes that would be required by the *path operations* that + use this dependency. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if no HTTP Auhtorization header is provided, required for + OAuth2 authentication, it will automatically cancel the request and + send the client an error. + + If `auto_error` is set to `False`, when the HTTP Authorization header + is not available, instead of erroring out, the dependency result will + be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, with OAuth2 + or in a cookie). + """ + ), + ] = True, ): if not scopes: scopes = {} @@ -180,15 +486,79 @@ class OAuth2PasswordBearer(OAuth2): class OAuth2AuthorizationCodeBearer(OAuth2): + """ + OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code + flow. An instance of it would be used as a dependency. + """ + def __init__( self, authorizationUrl: str, - tokenUrl: str, - refreshUrl: Optional[str] = None, - scheme_name: Optional[str] = None, - scopes: Optional[Dict[str, str]] = None, - description: Optional[str] = None, - auto_error: bool = True, + tokenUrl: Annotated[ + str, + Doc( + """ + The URL to obtain the OAuth2 token. + """ + ), + ], + refreshUrl: Annotated[ + Optional[str], + Doc( + """ + The URL to refresh the token and obtain a new one. + """ + ), + ] = None, + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + scopes: Annotated[ + Optional[Dict[str, str]], + Doc( + """ + The OAuth2 scopes that would be required by the *path operations* that + use this dependency. + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if no HTTP Auhtorization header is provided, required for + OAuth2 authentication, it will automatically cancel the request and + send the client an error. + + If `auto_error` is set to `False`, when the HTTP Authorization header + is not available, instead of erroring out, the dependency result will + be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, with OAuth2 + or in a cookie). + """ + ), + ] = True, ): if not scopes: scopes = {} @@ -226,6 +596,43 @@ class OAuth2AuthorizationCodeBearer(OAuth2): class SecurityScopes: - def __init__(self, scopes: Optional[List[str]] = None): - self.scopes = scopes or [] - self.scope_str = " ".join(self.scopes) + """ + This is a special class that you can define in a parameter in a dependency to + obtain the OAuth2 scopes required by all the dependencies in the same chain. + + This way, multiple dependencies can have different scopes, even when used in the + same *path operation*. And with this, you can access all the scopes required in + all those dependencies in a single place. + + Read more about it in the + [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/). + """ + + def __init__( + self, + scopes: Annotated[ + Optional[List[str]], + Doc( + """ + This will be filled by FastAPI. + """ + ), + ] = None, + ): + self.scopes: Annotated[ + List[str], + Doc( + """ + The list of all the scopes required by dependencies. + """ + ), + ] = scopes or [] + self.scope_str: Annotated[ + str, + Doc( + """ + All the scopes required by all the dependencies in a single string + separated by spaces, as defined in the OAuth2 specification. + """ + ), + ] = " ".join(self.scopes) diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py index 4e65f1f6c..c612b475d 100644 --- a/fastapi/security/open_id_connect_url.py +++ b/fastapi/security/open_id_connect_url.py @@ -5,16 +5,66 @@ from fastapi.security.base import SecurityBase from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.status import HTTP_403_FORBIDDEN +from typing_extensions import Annotated, Doc # type: ignore [attr-defined] class OpenIdConnect(SecurityBase): + """ + OpenID Connect authentication class. An instance of it would be used as a + dependency. + """ + def __init__( self, *, - openIdConnectUrl: str, - scheme_name: Optional[str] = None, - description: Optional[str] = None, - auto_error: bool = True, + openIdConnectUrl: Annotated[ + str, + Doc( + """ + The OpenID Connect URL. + """ + ), + ], + scheme_name: Annotated[ + Optional[str], + Doc( + """ + Security scheme name. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + description: Annotated[ + Optional[str], + Doc( + """ + Security scheme description. + + It will be included in the generated OpenAPI (e.g. visible at `/docs`). + """ + ), + ] = None, + auto_error: Annotated[ + bool, + Doc( + """ + By default, if no HTTP Auhtorization header is provided, required for + OpenID Connect authentication, it will automatically cancel the request + and send the client an error. + + If `auto_error` is set to `False`, when the HTTP Authorization header + is not available, instead of erroring out, the dependency result will + be `None`. + + This is useful when you want to have optional authentication. + + It is also useful when you want to have authentication that can be + provided in one of multiple optional ways (for example, with OpenID + Connect or in a cookie). + """ + ), + ] = True, ): self.model = OpenIdConnectModel( openIdConnectUrl=openIdConnectUrl, description=description diff --git a/fastapi/types.py b/fastapi/types.py index 7adf565a7..3205654c7 100644 --- a/fastapi/types.py +++ b/fastapi/types.py @@ -6,6 +6,5 @@ from pydantic import BaseModel DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any]) UnionType = getattr(types, "UnionType", Union) -NoneType = getattr(types, "UnionType", None) ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str] IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]] diff --git a/fastapi/utils.py b/fastapi/utils.py index 267d64ce8..f8463dda2 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -117,7 +117,7 @@ def create_cloned_field( if PYDANTIC_V2: return field # cloned_types caches already cloned types to support recursive models and improve - # performance by avoiding unecessary cloning + # performance by avoiding unnecessary cloning if cloned_types is None: cloned_types = _CLONED_TYPES_CACHE @@ -152,7 +152,8 @@ def create_cloned_field( ] if field.key_field: # type: ignore[attr-defined] new_field.key_field = create_cloned_field( # type: ignore[attr-defined] - field.key_field, cloned_types=cloned_types # type: ignore[attr-defined] + field.key_field, # type: ignore[attr-defined] + cloned_types=cloned_types, ) new_field.validators = field.validators # type: ignore[attr-defined] new_field.pre_validators = field.pre_validators # type: ignore[attr-defined] diff --git a/pyproject.toml b/pyproject.toml index 9b7cca9c9..e67486ae3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" name = "fastapi" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.8" license = "MIT" authors = [ { name = "Sebastiรกn Ramรญrez", email = "tiangolo@gmail.com" }, @@ -32,7 +32,6 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -43,7 +42,9 @@ classifiers = [ dependencies = [ "starlette>=0.27.0,<0.28.0", "pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0", - "typing-extensions>=4.5.0", + "typing-extensions>=4.8.0", + # TODO: remove this pin after upgrading Starlette 0.31.1 + "anyio>=3.7.1,<4.0.0", ] dynamic = ["version"] @@ -129,11 +130,13 @@ select = [ "I", # isort "C", # flake8-comprehensions "B", # flake8-bugbear + "UP", # pyupgrade ] ignore = [ "E501", # line too long, handled by black "B008", # do not perform function calls in argument defaults "C901", # too complex + "W191", # indentation contains tabs ] [tool.ruff.per-file-ignores] @@ -153,6 +156,22 @@ ignore = [ "docs_src/query_params_str_validations/tutorial012_an_py39.py" = ["B006"] "docs_src/query_params_str_validations/tutorial013_an.py" = ["B006"] "docs_src/query_params_str_validations/tutorial013_an_py39.py" = ["B006"] +"docs_src/security/tutorial004.py" = ["B904"] +"docs_src/security/tutorial004_an.py" = ["B904"] +"docs_src/security/tutorial004_an_py310.py" = ["B904"] +"docs_src/security/tutorial004_an_py39.py" = ["B904"] +"docs_src/security/tutorial004_py310.py" = ["B904"] +"docs_src/security/tutorial005.py" = ["B904"] +"docs_src/security/tutorial005_an.py" = ["B904"] +"docs_src/security/tutorial005_an_py310.py" = ["B904"] +"docs_src/security/tutorial005_an_py39.py" = ["B904"] +"docs_src/security/tutorial005_py310.py" = ["B904"] +"docs_src/security/tutorial005_py39.py" = ["B904"] + [tool.ruff.isort] known-third-party = ["fastapi", "pydantic", "starlette"] + +[tool.ruff.pyupgrade] +# Preserve types, even if a file imports `from __future__ import annotations`. +keep-runtime-typing = true diff --git a/requirements-docs-tests.txt b/requirements-docs-tests.txt new file mode 100644 index 000000000..b82df4933 --- /dev/null +++ b/requirements-docs-tests.txt @@ -0,0 +1,2 @@ +# For mkdocstrings and tests +httpx >=0.23.0,<0.25.0 diff --git a/requirements-docs.txt b/requirements-docs.txt index 220d1ec3a..28408a9f1 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,13 +1,19 @@ -e . -mkdocs-material==9.1.21 +-r requirements-docs-tests.txt +mkdocs-material==9.4.7 mdx-include >=1.4.1,<2.0.0 mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0 +mkdocs-redirects>=1.2.1,<1.3.0 typer-cli >=0.0.13,<0.0.14 typer[all] >=0.6.1,<0.8.0 pyyaml >=5.3.1,<7.0.0 # For Material for MkDocs, Chinese search jieba==0.42.1 # For image processing by Material for MkDocs -pillow==9.5.0 +pillow==10.1.0 # For image processing by Material for MkDocs cairosvg==2.7.0 +mkdocstrings[python]==0.23.0 +griffe-typingdoc==0.2.2 +# For griffe, it formats with black +black==23.3.0 diff --git a/requirements-tests.txt b/requirements-tests.txt index 0113b6f7a..e1a976c13 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -1,17 +1,15 @@ -e . +-r requirements-docs-tests.txt pydantic-settings >=2.0.0 pytest >=7.1.3,<8.0.0 coverage[toml] >= 6.5.0,< 8.0 mypy ==1.4.1 -ruff ==0.0.275 -black == 23.3.0 -httpx >=0.23.0,<0.25.0 +ruff ==0.1.2 email_validator >=1.1.1,<3.0.0 dirty-equals ==0.6.0 # TODO: once removing databases from tutorial, upgrade SQLAlchemy # probably when including SQLModel sqlalchemy >=1.3.18,<1.4.43 -peewee >=3.13.3,<4.0.0 databases[sqlite] >=0.3.2,<0.7.0 orjson >=3.2.1,<4.0.0 ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0 diff --git a/requirements.txt b/requirements.txt index 7e746016a..ef25ec483 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,5 @@ -r requirements-docs.txt uvicorn[standard] >=0.12.0,<0.23.0 pre-commit >=2.17.0,<4.0.0 +# For generating screenshots +playwright diff --git a/scripts/docs.py b/scripts/docs.py index 968dd9a3d..73e1900ad 100644 --- a/scripts/docs.py +++ b/scripts/docs.py @@ -36,7 +36,7 @@ site_path = Path("site").absolute() build_site_path = Path("site_build").absolute() -@lru_cache() +@lru_cache def is_mkdocs_insiders() -> bool: version = metadata.version("mkdocs-material") return "insiders" in version @@ -104,7 +104,7 @@ def new_lang(lang: str = typer.Argument(..., callback=lang_callback)): def build_lang( lang: str = typer.Argument( ..., callback=lang_callback, autocompletion=complete_existing_lang - ) + ), ) -> None: """ Build the docs for a language. @@ -153,17 +153,21 @@ index_sponsors_template = """ def generate_readme_content() -> str: en_index = en_docs_path / "docs" / "index.md" content = en_index.read_text("utf-8") + match_pre = re.search(r"</style>\n\n", content) match_start = re.search(r"<!-- sponsors -->", content) match_end = re.search(r"<!-- /sponsors -->", content) sponsors_data_path = en_docs_path / "data" / "sponsors.yml" sponsors = mkdocs.utils.yaml_load(sponsors_data_path.read_text(encoding="utf-8")) if not (match_start and match_end): raise RuntimeError("Couldn't auto-generate sponsors section") + if not match_pre: + raise RuntimeError("Couldn't find pre section (<style>) in index.md") + frontmatter_end = match_pre.end() pre_end = match_start.end() post_start = match_end.start() template = Template(index_sponsors_template) message = template.render(sponsors=sponsors) - pre_content = content[:pre_end] + pre_content = content[frontmatter_end:pre_end] post_content = content[post_start:] new_content = pre_content + message + post_content return new_content @@ -247,7 +251,7 @@ def serve() -> None: def live( lang: str = typer.Argument( None, callback=lang_callback, autocompletion=complete_existing_lang - ) + ), ) -> None: """ Serve with livereload a docs site for a specific language. @@ -286,7 +290,6 @@ def update_config() -> None: else: use_name = alternate_dict[url] new_alternate.append({"link": url, "name": use_name}) - config["nav"][1] = {"Languages": languages} config["extra"]["alternate"] = new_alternate en_config_path.write_text( yaml.dump(config, sort_keys=False, width=200, allow_unicode=True), diff --git a/scripts/format.sh b/scripts/format.sh index 3fb3eb4f1..11f25f1ce 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -2,4 +2,4 @@ set -x ruff fastapi tests docs_src scripts --fix -black fastapi tests docs_src scripts +ruff format fastapi tests docs_src scripts diff --git a/scripts/gitter_releases_bot.py b/scripts/gitter_releases_bot.py deleted file mode 100644 index a033d0d69..000000000 --- a/scripts/gitter_releases_bot.py +++ /dev/null @@ -1,67 +0,0 @@ -import inspect -import os - -import requests - -room_id = "5c9c9540d73408ce4fbc1403" # FastAPI -# room_id = "5cc46398d73408ce4fbed233" # Gitter development - -gitter_token = os.getenv("GITTER_TOKEN") -assert gitter_token -github_token = os.getenv("GITHUB_TOKEN") -assert github_token -tag_name = os.getenv("TAG") -assert tag_name - - -def get_github_graphql(tag_name: str): - github_graphql = """ - { - repository(owner: "tiangolo", name: "fastapi") { - release (tagName: "{{tag_name}}" ) { - description - } - } - } - """ - github_graphql = github_graphql.replace("{{tag_name}}", tag_name) - return github_graphql - - -def get_github_release_text(tag_name: str): - url = "https://api.github.com/graphql" - headers = {"Authorization": f"Bearer {github_token}"} - github_graphql = get_github_graphql(tag_name=tag_name) - response = requests.post(url, json={"query": github_graphql}, headers=headers) - assert response.status_code == 200 - data = response.json() - return data["data"]["repository"]["release"]["description"] - - -def get_gitter_message(release_text: str): - text = f""" - New release! :tada: :rocket: - (by FastAPI bot) - - ## {tag_name} - """ - text = inspect.cleandoc(text) + "\n\n" + release_text - return text - - -def send_gitter_message(text: str): - headers = {"Authorization": f"Bearer {gitter_token}"} - url = f"https://api.gitter.im/v1/rooms/{room_id}/chatMessages" - data = {"text": text} - response = requests.post(url, headers=headers, json=data) - assert response.status_code == 200 - - -def main(): - release_text = get_github_release_text(tag_name=tag_name) - text = get_gitter_message(release_text=release_text) - send_gitter_message(text=text) - - -if __name__ == "__main__": - main() diff --git a/scripts/lint.sh b/scripts/lint.sh index 4db5caa96..c0e24db9f 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -5,4 +5,4 @@ set -x mypy fastapi ruff fastapi tests docs_src scripts -black fastapi tests --check +ruff format fastapi tests --check diff --git a/scripts/mkdocs_hooks.py b/scripts/mkdocs_hooks.py index 008751f8a..8335a13f6 100644 --- a/scripts/mkdocs_hooks.py +++ b/scripts/mkdocs_hooks.py @@ -8,18 +8,23 @@ from mkdocs.structure.files import File, Files from mkdocs.structure.nav import Link, Navigation, Section from mkdocs.structure.pages import Page +non_traslated_sections = [ + "reference/", + "release-notes.md", +] -@lru_cache() + +@lru_cache def get_missing_translation_content(docs_dir: str) -> str: docs_dir_path = Path(docs_dir) missing_translation_path = docs_dir_path.parent.parent / "missing-translation.md" return missing_translation_path.read_text(encoding="utf-8") -@lru_cache() +@lru_cache def get_mkdocs_material_langs() -> List[str]: material_path = Path(material.__file__).parent - material_langs_path = material_path / "partials" / "languages" + material_langs_path = material_path / "templates" / "partials" / "languages" langs = [file.stem for file in material_langs_path.glob("*.html")] return langs @@ -123,6 +128,9 @@ def on_page_markdown( markdown: str, *, page: Page, config: MkDocsConfig, files: Files ) -> str: if isinstance(page.file, EnFile): + for excluded_section in non_traslated_sections: + if page.file.src_path.startswith(excluded_section): + return markdown missing_translation_content = get_missing_translation_content(config.docs_dir) header = "" body = markdown diff --git a/scripts/notify.sh b/scripts/notify.sh deleted file mode 100755 index 8ce550026..000000000 --- a/scripts/notify.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -e - -python scripts/gitter_releases_bot.py diff --git a/scripts/playwright/separate_openapi_schemas/image01.py b/scripts/playwright/separate_openapi_schemas/image01.py new file mode 100644 index 000000000..0b40f3bbc --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image01.py @@ -0,0 +1,29 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_text("POST/items/Create Item").click() + page.get_by_role("tab", name="Schema").first.click() + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image02.py b/scripts/playwright/separate_openapi_schemas/image02.py new file mode 100644 index 000000000..f76af7ee2 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image02.py @@ -0,0 +1,30 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_text("GET/items/Read Items").click() + page.get_by_role("button", name="Try it out").click() + page.get_by_role("button", name="Execute").click() + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image03.py b/scripts/playwright/separate_openapi_schemas/image03.py new file mode 100644 index 000000000..127f5c428 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image03.py @@ -0,0 +1,30 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_text("GET/items/Read Items").click() + page.get_by_role("tab", name="Schema").click() + page.get_by_label("Schema").get_by_role("button", name="Expand all").click() + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image04.py b/scripts/playwright/separate_openapi_schemas/image04.py new file mode 100644 index 000000000..208eaf8a0 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image04.py @@ -0,0 +1,29 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_role("button", name="Item-Input").click() + page.get_by_role("button", name="Item-Output").click() + page.set_viewport_size({"width": 960, "height": 820}) + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png" + ) + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial001:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/scripts/playwright/separate_openapi_schemas/image05.py b/scripts/playwright/separate_openapi_schemas/image05.py new file mode 100644 index 000000000..83966b449 --- /dev/null +++ b/scripts/playwright/separate_openapi_schemas/image05.py @@ -0,0 +1,29 @@ +import subprocess + +from playwright.sync_api import Playwright, sync_playwright + + +def run(playwright: Playwright) -> None: + browser = playwright.chromium.launch(headless=False) + context = browser.new_context(viewport={"width": 960, "height": 1080}) + page = context.new_page() + page.goto("http://localhost:8000/docs") + page.get_by_role("button", name="Item", exact=True).click() + page.set_viewport_size({"width": 960, "height": 700}) + page.screenshot( + path="docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png" + ) + + # --------------------- + context.close() + browser.close() + + +process = subprocess.Popen( + ["uvicorn", "docs_src.separate_openapi_schemas.tutorial002:app"] +) +try: + with sync_playwright() as playwright: + run(playwright) +finally: + process.terminate() diff --git a/tests/test_ambiguous_params.py b/tests/test_ambiguous_params.py index 42bcc27a1..8a31442eb 100644 --- a/tests/test_ambiguous_params.py +++ b/tests/test_ambiguous_params.py @@ -1,6 +1,8 @@ import pytest from fastapi import Depends, FastAPI, Path from fastapi.param_functions import Query +from fastapi.testclient import TestClient +from fastapi.utils import PYDANTIC_V2 from typing_extensions import Annotated app = FastAPI() @@ -28,18 +30,13 @@ def test_no_annotated_defaults(): pass # pragma: nocover -def test_no_multiple_annotations(): +def test_multiple_annotations(): async def dep(): pass # pragma: nocover - with pytest.raises( - AssertionError, - match="Cannot specify multiple `Annotated` FastAPI arguments for 'foo'", - ): - - @app.get("/") - async def get(foo: Annotated[int, Query(min_length=1), Query()]): - pass # pragma: nocover + @app.get("/multi-query") + async def get(foo: Annotated[int, Query(gt=2), Query(lt=10)]): + return foo with pytest.raises( AssertionError, @@ -64,3 +61,15 @@ def test_no_multiple_annotations(): @app.get("/") async def get3(foo: Annotated[int, Query(min_length=1)] = Depends(dep)): pass # pragma: nocover + + client = TestClient(app) + response = client.get("/multi-query", params={"foo": "5"}) + assert response.status_code == 200 + assert response.json() == 5 + + response = client.get("/multi-query", params={"foo": "123"}) + assert response.status_code == 422 + + if PYDANTIC_V2: + response = client.get("/multi-query", params={"foo": "1"}) + assert response.status_code == 422 diff --git a/tests/test_annotated.py b/tests/test_annotated.py index 541f84bca..2222be978 100644 --- a/tests/test_annotated.py +++ b/tests/test_annotated.py @@ -57,7 +57,7 @@ foo_is_short = { { "ctx": {"min_length": 1}, "loc": ["query", "foo"], - "msg": "String should have at least 1 characters", + "msg": "String should have at least 1 character", "type": "string_too_short", "input": "", "url": match_pydantic_error_url("string_too_short"), diff --git a/tests/test_compat.py b/tests/test_compat.py index 47160ee76..bf268b860 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -24,7 +24,7 @@ def test_model_field_default_required(): @needs_pydanticv1 -def test_upload_file_dummy_general_plain_validator_function(): +def test_upload_file_dummy_with_info_plain_validator_function(): # For coverage assert UploadFile.__get_pydantic_core_schema__(str, lambda x: None) == {} diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py index b91467265..7e57d525c 100644 --- a/tests/test_datastructures.py +++ b/tests/test_datastructures.py @@ -1,3 +1,4 @@ +import io from pathlib import Path from typing import List @@ -52,3 +53,20 @@ def test_upload_file_is_closed(tmp_path: Path): assert testing_file_store assert testing_file_store[0].file.closed + + +# For UploadFile coverage, segments copied from Starlette tests + + +@pytest.mark.anyio +async def test_upload_file(): + stream = io.BytesIO(b"data") + file = UploadFile(filename="file", file=stream, size=4) + assert await file.read() == b"data" + assert file.size == 4 + await file.write(b" and more data!") + assert await file.read() == b"" + assert file.size == 19 + await file.seek(0) + assert await file.read() == b"data and more data!" + await file.close() diff --git a/tests/test_filter_pydantic_sub_model_pv2.py b/tests/test_filter_pydantic_sub_model_pv2.py index 9f5e6b08f..9097d2ce5 100644 --- a/tests/test_filter_pydantic_sub_model_pv2.py +++ b/tests/test_filter_pydantic_sub_model_pv2.py @@ -12,7 +12,7 @@ from .utils import needs_pydanticv2 @pytest.fixture(name="client") def get_client(): - from pydantic import BaseModel, FieldValidationInfo, field_validator + from pydantic import BaseModel, ValidationInfo, field_validator app = FastAPI() @@ -28,7 +28,7 @@ def get_client(): foo: ModelB @field_validator("name") - def lower_username(cls, name: str, info: FieldValidationInfo): + def lower_username(cls, name: str, info: ValidationInfo): if not name.endswith("A"): raise ValueError("name must end in A") return name diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py index 931f08fc1..a51ca7253 100644 --- a/tests/test_multi_body_errors.py +++ b/tests/test_multi_body_errors.py @@ -51,7 +51,7 @@ def test_jsonable_encoder_requiring_error(): "loc": ["body", 0, "age"], "msg": "Input should be greater than 0", "input": -1.0, - "ctx": {"gt": "0"}, + "ctx": {"gt": 0}, "url": match_pydantic_error_url("greater_than"), } ] @@ -84,25 +84,12 @@ def test_put_incorrect_body_multiple(): "input": {"age": "five"}, "url": match_pydantic_error_url("missing"), }, - { - "ctx": {"class": "Decimal"}, - "input": "five", - "loc": ["body", 0, "age", "is-instance[Decimal]"], - "msg": "Input should be an instance of Decimal", - "type": "is_instance_of", - "url": match_pydantic_error_url("is_instance_of"), - }, { "type": "decimal_parsing", - "loc": [ - "body", - 0, - "age", - "function-after[to_decimal(), " - "union[int,constrained-str,function-plain[str()]]]", - ], + "loc": ["body", 0, "age"], "msg": "Input should be a valid decimal", "input": "five", + "url": match_pydantic_error_url("decimal_parsing"), }, { "type": "missing", @@ -111,25 +98,12 @@ def test_put_incorrect_body_multiple(): "input": {"age": "six"}, "url": match_pydantic_error_url("missing"), }, - { - "ctx": {"class": "Decimal"}, - "input": "six", - "loc": ["body", 1, "age", "is-instance[Decimal]"], - "msg": "Input should be an instance of Decimal", - "type": "is_instance_of", - "url": match_pydantic_error_url("is_instance_of"), - }, { "type": "decimal_parsing", - "loc": [ - "body", - 1, - "age", - "function-after[to_decimal(), " - "union[int,constrained-str,function-plain[str()]]]", - ], + "loc": ["body", 1, "age"], "msg": "Input should be a valid decimal", "input": "six", + "url": match_pydantic_error_url("decimal_parsing"), }, ] } diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py new file mode 100644 index 000000000..6597e5058 --- /dev/null +++ b/tests/test_openapi_examples.py @@ -0,0 +1,458 @@ +from typing import Union + +from dirty_equals import IsDict +from fastapi import Body, Cookie, FastAPI, Header, Path, Query +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + data: str + + +@app.post("/examples/") +def examples( + item: Item = Body( + examples=[ + {"data": "Data in Body examples, example1"}, + ], + openapi_examples={ + "Example One": { + "summary": "Example One Summary", + "description": "Example One Description", + "value": {"data": "Data in Body examples, example1"}, + }, + "Example Two": { + "value": {"data": "Data in Body examples, example2"}, + }, + }, + ), +): + return item + + +@app.get("/path_examples/{item_id}") +def path_examples( + item_id: str = Path( + examples=[ + "json_schema_item_1", + "json_schema_item_2", + ], + openapi_examples={ + "Path One": { + "summary": "Path One Summary", + "description": "Path One Description", + "value": "item_1", + }, + "Path Two": { + "value": "item_2", + }, + }, + ), +): + return item_id + + +@app.get("/query_examples/") +def query_examples( + data: Union[str, None] = Query( + default=None, + examples=[ + "json_schema_query1", + "json_schema_query2", + ], + openapi_examples={ + "Query One": { + "summary": "Query One Summary", + "description": "Query One Description", + "value": "query1", + }, + "Query Two": { + "value": "query2", + }, + }, + ), +): + return data + + +@app.get("/header_examples/") +def header_examples( + data: Union[str, None] = Header( + default=None, + examples=[ + "json_schema_header1", + "json_schema_header2", + ], + openapi_examples={ + "Header One": { + "summary": "Header One Summary", + "description": "Header One Description", + "value": "header1", + }, + "Header Two": { + "value": "header2", + }, + }, + ), +): + return data + + +@app.get("/cookie_examples/") +def cookie_examples( + data: Union[str, None] = Cookie( + default=None, + examples=["json_schema_cookie1", "json_schema_cookie2"], + openapi_examples={ + "Cookie One": { + "summary": "Cookie One Summary", + "description": "Cookie One Description", + "value": "cookie1", + }, + "Cookie Two": { + "value": "cookie2", + }, + }, + ), +): + return data + + +client = TestClient(app) + + +def test_call_api(): + response = client.post("/examples/", json={"data": "example1"}) + assert response.status_code == 200, response.text + + response = client.get("/path_examples/foo") + assert response.status_code == 200, response.text + + response = client.get("/query_examples/") + assert response.status_code == 200, response.text + + response = client.get("/header_examples/") + assert response.status_code == 200, response.text + + response = client.get("/cookie_examples/") + assert response.status_code == 200, response.text + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/examples/": { + "post": { + "summary": "Examples", + "operationId": "examples_examples__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + {"data": "Data in Body examples, example1"} + ], + }, + "examples": { + "Example One": { + "summary": "Example One Summary", + "description": "Example One Description", + "value": { + "data": "Data in Body examples, example1" + }, + }, + "Example Two": { + "value": { + "data": "Data in Body examples, example2" + } + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/path_examples/{item_id}": { + "get": { + "summary": "Path Examples", + "operationId": "path_examples_path_examples__item_id__get", + "parameters": [ + { + "name": "item_id", + "in": "path", + "required": True, + "schema": { + "type": "string", + "examples": [ + "json_schema_item_1", + "json_schema_item_2", + ], + "title": "Item Id", + }, + "examples": { + "Path One": { + "summary": "Path One Summary", + "description": "Path One Description", + "value": "item_1", + }, + "Path Two": {"value": "item_2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/query_examples/": { + "get": { + "summary": "Query Examples", + "operationId": "query_examples_query_examples__get", + "parameters": [ + { + "name": "data", + "in": "query", + "required": False, + "schema": IsDict( + { + "anyOf": [{"type": "string"}, {"type": "null"}], + "examples": [ + "json_schema_query1", + "json_schema_query2", + ], + "title": "Data", + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "examples": [ + "json_schema_query1", + "json_schema_query2", + ], + "type": "string", + "title": "Data", + } + ), + "examples": { + "Query One": { + "summary": "Query One Summary", + "description": "Query One Description", + "value": "query1", + }, + "Query Two": {"value": "query2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/header_examples/": { + "get": { + "summary": "Header Examples", + "operationId": "header_examples_header_examples__get", + "parameters": [ + { + "name": "data", + "in": "header", + "required": False, + "schema": IsDict( + { + "anyOf": [{"type": "string"}, {"type": "null"}], + "examples": [ + "json_schema_header1", + "json_schema_header2", + ], + "title": "Data", + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "type": "string", + "examples": [ + "json_schema_header1", + "json_schema_header2", + ], + "title": "Data", + } + ), + "examples": { + "Header One": { + "summary": "Header One Summary", + "description": "Header One Description", + "value": "header1", + }, + "Header Two": {"value": "header2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + "/cookie_examples/": { + "get": { + "summary": "Cookie Examples", + "operationId": "cookie_examples_cookie_examples__get", + "parameters": [ + { + "name": "data", + "in": "cookie", + "required": False, + "schema": IsDict( + { + "anyOf": [{"type": "string"}, {"type": "null"}], + "examples": [ + "json_schema_cookie1", + "json_schema_cookie2", + ], + "title": "Data", + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "type": "string", + "examples": [ + "json_schema_cookie1", + "json_schema_cookie2", + ], + "title": "Data", + } + ), + "examples": { + "Cookie One": { + "summary": "Cookie One Summary", + "description": "Cookie One Description", + "value": "cookie1", + }, + "Cookie Two": {"value": "cookie2"}, + }, + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": {"data": {"type": "string", "title": "Data"}}, + "type": "object", + "required": ["data"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_openapi_separate_input_output_schemas.py b/tests/test_openapi_separate_input_output_schemas.py new file mode 100644 index 000000000..aeb85f735 --- /dev/null +++ b/tests/test_openapi_separate_input_output_schemas.py @@ -0,0 +1,494 @@ +from typing import List, Optional + +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + +from .utils import PYDANTIC_V2, needs_pydanticv2 + + +class SubItem(BaseModel): + subname: str + sub_description: Optional[str] = None + tags: List[str] = [] + if PYDANTIC_V2: + model_config = {"json_schema_serialization_defaults_required": True} + + +class Item(BaseModel): + name: str + description: Optional[str] = None + sub: Optional[SubItem] = None + if PYDANTIC_V2: + model_config = {"json_schema_serialization_defaults_required": True} + + +def get_app_client(separate_input_output_schemas: bool = True) -> TestClient: + app = FastAPI(separate_input_output_schemas=separate_input_output_schemas) + + @app.post("/items/") + def create_item(item: Item): + return item + + @app.post("/items-list/") + def create_item_list(item: List[Item]): + return item + + @app.get("/items/") + def read_items() -> List[Item]: + return [ + Item( + name="Portal Gun", + description="Device to travel through the multi-rick-verse", + sub=SubItem(subname="subname"), + ), + Item(name="Plumbus"), + ] + + client = TestClient(app) + return client + + +def test_create_item(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + response = client.post("/items/", json={"name": "Plumbus"}) + response2 = client_no.post("/items/", json={"name": "Plumbus"}) + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == {"name": "Plumbus", "description": None, "sub": None} + ) + + +def test_create_item_with_sub(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + data = { + "name": "Plumbus", + "sub": {"subname": "SubPlumbus", "sub_description": "Sub WTF"}, + } + response = client.post("/items/", json=data) + response2 = client_no.post("/items/", json=data) + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == { + "name": "Plumbus", + "description": None, + "sub": {"subname": "SubPlumbus", "sub_description": "Sub WTF", "tags": []}, + } + ) + + +def test_create_item_list(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + data = [ + {"name": "Plumbus"}, + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + ] + response = client.post("/items-list/", json=data) + response2 = client_no.post("/items-list/", json=data) + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == [ + {"name": "Plumbus", "description": None, "sub": None}, + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + "sub": None, + }, + ] + ) + + +def test_read_items(): + client = get_app_client() + client_no = get_app_client(separate_input_output_schemas=False) + response = client.get("/items/") + response2 = client_no.get("/items/") + assert response.status_code == response2.status_code == 200, response.text + assert ( + response.json() + == response2.json() + == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + "sub": {"subname": "subname", "sub_description": None, "tags": []}, + }, + {"name": "Plumbus", "description": None, "sub": None}, + ] + ) + + +@needs_pydanticv2 +def test_openapi_schema(): + client = get_app_client() + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Item-Output" + }, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item-Input"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/items-list/": { + "post": { + "summary": "Create Item List", + "operationId": "create_item_list_items_list__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/Item-Input" + }, + "type": "array", + "title": "Item", + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item-Input": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + "sub": { + "anyOf": [ + {"$ref": "#/components/schemas/SubItem-Input"}, + {"type": "null"}, + ] + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "Item-Output": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + "sub": { + "anyOf": [ + {"$ref": "#/components/schemas/SubItem-Output"}, + {"type": "null"}, + ] + }, + }, + "type": "object", + "required": ["name", "description", "sub"], + "title": "Item", + }, + "SubItem-Input": { + "properties": { + "subname": {"type": "string", "title": "Subname"}, + "sub_description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Sub Description", + }, + "tags": { + "items": {"type": "string"}, + "type": "array", + "title": "Tags", + "default": [], + }, + }, + "type": "object", + "required": ["subname"], + "title": "SubItem", + }, + "SubItem-Output": { + "properties": { + "subname": {"type": "string", "title": "Subname"}, + "sub_description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Sub Description", + }, + "tags": { + "items": {"type": "string"}, + "type": "array", + "title": "Tags", + "default": [], + }, + }, + "type": "object", + "required": ["subname", "sub_description", "tags"], + "title": "SubItem", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } + + +@needs_pydanticv2 +def test_openapi_schema_no_separate(): + client = get_app_client(separate_input_output_schemas=False) + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + }, + "/items-list/": { + "post": { + "summary": "Create Item List", + "operationId": "create_item_list_items_list__post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Item", + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + }, + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + "sub": { + "anyOf": [ + {"$ref": "#/components/schemas/SubItem"}, + {"type": "null"}, + ] + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "SubItem": { + "properties": { + "subname": {"type": "string", "title": "Subname"}, + "sub_description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Sub Description", + }, + "tags": { + "items": {"type": "string"}, + "type": "array", + "title": "Tags", + "default": [], + }, + }, + "type": "object", + "required": ["subname"], + "title": "SubItem", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_router_events.py b/tests/test_router_events.py index ba6b76382..1b9de18ae 100644 --- a/tests/test_router_events.py +++ b/tests/test_router_events.py @@ -21,6 +21,9 @@ def state() -> State: return State() +@pytest.mark.filterwarnings( + r"ignore:\s*on_event is deprecated, use lifespan event handlers instead.*:DeprecationWarning" +) def test_router_events(state: State) -> None: app = FastAPI() diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py index a1505afe2..b313f47e9 100644 --- a/tests/test_schema_extra_examples.py +++ b/tests/test_schema_extra_examples.py @@ -40,7 +40,7 @@ def create_app(): {"data": "Data in Body examples, example1"}, {"data": "Data in Body examples, example2"}, ], - ) + ), ): return item @@ -54,7 +54,7 @@ def create_app(): {"data": "examples example_examples 1"}, {"data": "examples example_examples 2"}, ], - ) + ), ): return item diff --git a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py index 25d6df3e9..13568a532 100644 --- a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py +++ b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py @@ -1,13 +1,20 @@ +import pytest +from fastapi import FastAPI from fastapi.testclient import TestClient -from docs_src.async_sql_databases.tutorial001 import app - from ...utils import needs_pydanticv1 +@pytest.fixture(name="app", scope="module") +def get_app(): + with pytest.warns(DeprecationWarning): + from docs_src.async_sql_databases.tutorial001 import app + yield app + + # TODO: pv2 add version with Pydantic v2 @needs_pydanticv1 -def test_create_read(): +def test_create_read(app: FastAPI): with TestClient(app) as client: note = {"text": "Foo bar", "completed": False} response = client.post("/notes/", json=note) @@ -21,7 +28,7 @@ def test_create_read(): assert data in response.json() -def test_openapi_schema(): +def test_openapi_schema(app: FastAPI): with TestClient(app) as client: response = client.get("/openapi.json") assert response.status_code == 200, response.text diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py index f1a46210a..e586534a0 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py @@ -52,9 +52,7 @@ def test_openapi_schema(client: TestClient): "description": "Successful Response", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -86,9 +84,7 @@ def test_openapi_schema(client: TestClient): "description": "Successful Response", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -116,7 +112,7 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/ItemInput"} + "schema": {"$ref": "#/components/schemas/Item"} } }, "required": True, @@ -126,35 +122,9 @@ def test_openapi_schema(client: TestClient): }, "components": { "schemas": { - "ItemInput": { - "title": "Item", + "Item": { "type": "object", - "properties": { - "name": { - "title": "Name", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "description": { - "title": "Description", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "price": { - "title": "Price", - "anyOf": [{"type": "number"}, {"type": "null"}], - }, - "tax": {"title": "Tax", "type": "number", "default": 10.5}, - "tags": { - "title": "Tags", - "type": "array", - "items": {"type": "string"}, - "default": [], - }, - }, - }, - "ItemOutput": { "title": "Item", - "type": "object", - "required": ["name", "description", "price", "tax", "tags"], "properties": { "name": { "anyOf": [{"type": "string"}, {"type": "null"}], diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py index ab696e4c8..6bc969d43 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py @@ -55,9 +55,7 @@ def test_openapi_schema(client: TestClient): "description": "Successful Response", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -89,9 +87,7 @@ def test_openapi_schema(client: TestClient): "description": "Successful Response", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -119,7 +115,7 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/ItemInput"} + "schema": {"$ref": "#/components/schemas/Item"} } }, "required": True, @@ -129,35 +125,9 @@ def test_openapi_schema(client: TestClient): }, "components": { "schemas": { - "ItemInput": { - "title": "Item", + "Item": { "type": "object", - "properties": { - "name": { - "title": "Name", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "description": { - "title": "Description", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "price": { - "title": "Price", - "anyOf": [{"type": "number"}, {"type": "null"}], - }, - "tax": {"title": "Tax", "type": "number", "default": 10.5}, - "tags": { - "title": "Tags", - "type": "array", - "items": {"type": "string"}, - "default": [], - }, - }, - }, - "ItemOutput": { "title": "Item", - "type": "object", - "required": ["name", "description", "price", "tax", "tags"], "properties": { "name": { "anyOf": [{"type": "string"}, {"type": "null"}], diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py index 2ee6a5cb4..a1edb3370 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py @@ -55,9 +55,7 @@ def test_openapi_schema(client: TestClient): "description": "Successful Response", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -89,9 +87,7 @@ def test_openapi_schema(client: TestClient): "description": "Successful Response", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -119,7 +115,7 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/ItemInput"} + "schema": {"$ref": "#/components/schemas/Item"} } }, "required": True, @@ -129,35 +125,9 @@ def test_openapi_schema(client: TestClient): }, "components": { "schemas": { - "ItemInput": { - "title": "Item", + "Item": { "type": "object", - "properties": { - "name": { - "title": "Name", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "description": { - "title": "Description", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "price": { - "title": "Price", - "anyOf": [{"type": "number"}, {"type": "null"}], - }, - "tax": {"title": "Tax", "type": "number", "default": 10.5}, - "tags": { - "title": "Tags", - "type": "array", - "items": {"type": "string"}, - "default": [], - }, - }, - }, - "ItemOutput": { "title": "Item", - "type": "object", - "required": ["name", "description", "price", "tax", "tags"], "properties": { "name": { "anyOf": [{"type": "string"}, {"type": "null"}], diff --git a/docs_src/sql_databases_peewee/__init__.py b/tests/test_tutorial/test_configure_swagger_ui/__init__.py similarity index 100% rename from docs_src/sql_databases_peewee/__init__.py rename to tests/test_tutorial/test_configure_swagger_ui/__init__.py diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial003.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py similarity index 95% rename from tests/test_tutorial/test_extending_openapi/test_tutorial003.py rename to tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py index 0184dd9f8..72db54bd2 100644 --- a/tests/test_tutorial/test_extending_openapi/test_tutorial003.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.extending_openapi.tutorial003 import app +from docs_src.configure_swagger_ui.tutorial001 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial004.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py similarity index 96% rename from tests/test_tutorial/test_extending_openapi/test_tutorial004.py rename to tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py index 4f7615126..166901188 100644 --- a/tests/test_tutorial/test_extending_openapi/test_tutorial004.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.extending_openapi.tutorial004 import app +from docs_src.configure_swagger_ui.tutorial002 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial005.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py similarity index 96% rename from tests/test_tutorial/test_extending_openapi/test_tutorial005.py rename to tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py index 24aeb93db..187e89ace 100644 --- a/tests/test_tutorial/test_extending_openapi/test_tutorial005.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.extending_openapi.tutorial005 import app +from docs_src.configure_swagger_ui.tutorial003 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_sql_databases_peewee/__init__.py b/tests/test_tutorial/test_custom_docs_ui/__init__.py similarity index 100% rename from tests/test_tutorial/test_sql_databases_peewee/__init__.py rename to tests/test_tutorial/test_custom_docs_ui/__init__.py diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py new file mode 100644 index 000000000..34a18b12c --- /dev/null +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py @@ -0,0 +1,44 @@ +import os +from pathlib import Path + +import pytest +from fastapi.testclient import TestClient + + +@pytest.fixture(scope="module") +def client(): + static_dir: Path = Path(os.getcwd()) / "static" + print(static_dir) + static_dir.mkdir(exist_ok=True) + from docs_src.custom_docs_ui.tutorial001 import app + + with TestClient(app) as client: + yield client + static_dir.rmdir() + + +def test_swagger_ui_html(client: TestClient): + response = client.get("/docs") + assert response.status_code == 200, response.text + assert ( + "https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js" in response.text + ) + assert "https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css" in response.text + + +def test_swagger_ui_oauth2_redirect_html(client: TestClient): + response = client.get("/docs/oauth2-redirect") + assert response.status_code == 200, response.text + assert "window.opener.swaggerUIRedirectOauth2" in response.text + + +def test_redoc_html(client: TestClient): + response = client.get("/redoc") + assert response.status_code == 200, response.text + assert "https://unpkg.com/redoc@next/bundles/redoc.standalone.js" in response.text + + +def test_api(client: TestClient): + response = client.get("/users/john") + assert response.status_code == 200, response.text + assert response.json()["message"] == "Hello john" diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial002.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py similarity index 95% rename from tests/test_tutorial/test_extending_openapi/test_tutorial002.py rename to tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py index 654db2e4c..712618807 100644 --- a/tests/test_tutorial/test_extending_openapi/test_tutorial002.py +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py @@ -10,7 +10,7 @@ def client(): static_dir: Path = Path(os.getcwd()) / "static" print(static_dir) static_dir.mkdir(exist_ok=True) - from docs_src.extending_openapi.tutorial002 import app + from docs_src.custom_docs_ui.tutorial002 import app with TestClient(app) as client: yield client diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py index 2e5809914..dd0e36735 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py @@ -79,7 +79,7 @@ def test_openapi_schema(): "schema": { "title": "Items", "type": "array", - "items": {"$ref": "#/components/schemas/ItemInput"}, + "items": {"$ref": "#/components/schemas/Item"}, } } }, @@ -134,14 +134,14 @@ def test_openapi_schema(): "schemas": { "Author": { "title": "Author", - "required": ["name", "items"], + "required": ["name"], "type": "object", "properties": { "name": {"title": "Name", "type": "string"}, "items": { "title": "Items", "type": "array", - "items": {"$ref": "#/components/schemas/ItemOutput"}, + "items": {"$ref": "#/components/schemas/Item"}, }, }, }, @@ -156,27 +156,15 @@ def test_openapi_schema(): } }, }, - "ItemInput": { + "Item": { "title": "Item", "required": ["name"], "type": "object", "properties": { "name": {"title": "Name", "type": "string"}, "description": { - "title": "Description", "anyOf": [{"type": "string"}, {"type": "null"}], - }, - }, - }, - "ItemOutput": { - "title": "Item", - "required": ["name", "description"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "description": { "title": "Description", - "anyOf": [{"type": "string"}, {"type": "null"}], }, }, }, diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py index a5bb299ac..f65b92d12 100644 --- a/tests/test_tutorial/test_events/test_tutorial001.py +++ b/tests/test_tutorial/test_events/test_tutorial001.py @@ -1,16 +1,23 @@ +import pytest +from fastapi import FastAPI from fastapi.testclient import TestClient -from docs_src.events.tutorial001 import app + +@pytest.fixture(name="app", scope="module") +def get_app(): + with pytest.warns(DeprecationWarning): + from docs_src.events.tutorial001 import app + yield app -def test_events(): +def test_events(app: FastAPI): with TestClient(app) as client: response = client.get("/items/foo") assert response.status_code == 200, response.text assert response.json() == {"name": "Fighters"} -def test_openapi_schema(): +def test_openapi_schema(app: FastAPI): with TestClient(app) as client: response = client.get("/openapi.json") assert response.status_code == 200, response.text diff --git a/tests/test_tutorial/test_events/test_tutorial002.py b/tests/test_tutorial/test_events/test_tutorial002.py index 81cbf4ab6..137294d73 100644 --- a/tests/test_tutorial/test_events/test_tutorial002.py +++ b/tests/test_tutorial/test_events/test_tutorial002.py @@ -1,9 +1,16 @@ +import pytest +from fastapi import FastAPI from fastapi.testclient import TestClient -from docs_src.events.tutorial002 import app + +@pytest.fixture(name="app", scope="module") +def get_app(): + with pytest.warns(DeprecationWarning): + from docs_src.events.tutorial002 import app + yield app -def test_events(): +def test_events(app: FastAPI): with TestClient(app) as client: response = client.get("/items/") assert response.status_code == 200, response.text @@ -12,7 +19,7 @@ def test_events(): assert "Application shutdown" in log.read() -def test_openapi_schema(): +def test_openapi_schema(app: FastAPI): with TestClient(app) as client: response = client.get("/openapi.json") assert response.status_code == 200, response.text diff --git a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py index 9111fdb2f..dc67ec401 100644 --- a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py +++ b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py @@ -85,7 +85,7 @@ def test_openapi_schema(): "Subscription": { "properties": { "username": {"type": "string", "title": "Username"}, - "montly_fee": {"type": "number", "title": "Montly Fee"}, + "monthly_fee": {"type": "number", "title": "Monthly Fee"}, "start_date": { "type": "string", "format": "date-time", @@ -93,7 +93,7 @@ def test_openapi_schema(): }, }, "type": "object", - "required": ["username", "montly_fee", "start_date"], + "required": ["username", "monthly_fee", "start_date"], "title": "Subscription", }, "ValidationError": { diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py index 3ffc0bca7..4f69e4646 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py @@ -34,9 +34,7 @@ def test_openapi_schema(): "description": "Successful Response", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -57,7 +55,7 @@ def test_openapi_schema(): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/ItemInput"} + "schema": {"$ref": "#/components/schemas/Item"} } }, "required": True, @@ -67,7 +65,7 @@ def test_openapi_schema(): }, "components": { "schemas": { - "ItemInput": { + "Item": { "title": "Item", "required": ["name", "price"], "type": "object", @@ -91,30 +89,6 @@ def test_openapi_schema(): }, }, }, - "ItemOutput": { - "title": "Item", - "required": ["name", "description", "price", "tax", "tags"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "description": { - "title": "Description", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "price": {"title": "Price", "type": "number"}, - "tax": { - "title": "Tax", - "anyOf": [{"type": "number"}, {"type": "null"}], - }, - "tags": { - "title": "Tags", - "uniqueItems": True, - "type": "array", - "items": {"type": "string"}, - "default": [], - }, - }, - }, "ValidationError": { "title": "ValidationError", "required": ["loc", "msg", "type"], diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py index ff98295a6..d3792e701 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py @@ -34,9 +34,7 @@ def test_openapi_schema(): "description": "The created item", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -57,7 +55,7 @@ def test_openapi_schema(): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/ItemInput"} + "schema": {"$ref": "#/components/schemas/Item"} } }, "required": True, @@ -67,7 +65,7 @@ def test_openapi_schema(): }, "components": { "schemas": { - "ItemInput": { + "Item": { "title": "Item", "required": ["name", "price"], "type": "object", @@ -91,30 +89,6 @@ def test_openapi_schema(): }, }, }, - "ItemOutput": { - "title": "Item", - "required": ["name", "description", "price", "tax", "tags"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "description": { - "anyOf": [{"type": "string"}, {"type": "null"}], - "title": "Description", - }, - "price": {"title": "Price", "type": "number"}, - "tax": { - "title": "Tax", - "anyOf": [{"type": "number"}, {"type": "null"}], - }, - "tags": { - "title": "Tags", - "uniqueItems": True, - "type": "array", - "items": {"type": "string"}, - "default": [], - }, - }, - }, "ValidationError": { "title": "ValidationError", "required": ["loc", "msg", "type"], diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py index ad1c09eae..a68deb3df 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py @@ -41,9 +41,7 @@ def test_openapi_schema(client: TestClient): "description": "The created item", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -64,7 +62,7 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/ItemInput"} + "schema": {"$ref": "#/components/schemas/Item"} } }, "required": True, @@ -74,7 +72,7 @@ def test_openapi_schema(client: TestClient): }, "components": { "schemas": { - "ItemInput": { + "Item": { "title": "Item", "required": ["name", "price"], "type": "object", @@ -98,30 +96,6 @@ def test_openapi_schema(client: TestClient): }, }, }, - "ItemOutput": { - "title": "Item", - "required": ["name", "description", "price", "tax", "tags"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "description": { - "anyOf": [{"type": "string"}, {"type": "null"}], - "title": "Description", - }, - "price": {"title": "Price", "type": "number"}, - "tax": { - "title": "Tax", - "anyOf": [{"type": "number"}, {"type": "null"}], - }, - "tags": { - "title": "Tags", - "uniqueItems": True, - "type": "array", - "items": {"type": "string"}, - "default": [], - }, - }, - }, "ValidationError": { "title": "ValidationError", "required": ["loc", "msg", "type"], diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py index 045d1d402..e17f2592d 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py @@ -41,9 +41,7 @@ def test_openapi_schema(client: TestClient): "description": "The created item", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ItemOutput" - } + "schema": {"$ref": "#/components/schemas/Item"} } }, }, @@ -64,7 +62,7 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/ItemInput"} + "schema": {"$ref": "#/components/schemas/Item"} } }, "required": True, @@ -74,7 +72,7 @@ def test_openapi_schema(client: TestClient): }, "components": { "schemas": { - "ItemInput": { + "Item": { "title": "Item", "required": ["name", "price"], "type": "object", @@ -98,30 +96,6 @@ def test_openapi_schema(client: TestClient): }, }, }, - "ItemOutput": { - "title": "Item", - "required": ["name", "description", "price", "tax", "tags"], - "type": "object", - "properties": { - "name": {"title": "Name", "type": "string"}, - "description": { - "anyOf": [{"type": "string"}, {"type": "null"}], - "title": "Description", - }, - "price": {"title": "Price", "type": "number"}, - "tax": { - "title": "Tax", - "anyOf": [{"type": "number"}, {"type": "null"}], - }, - "tags": { - "title": "Tags", - "uniqueItems": True, - "type": "array", - "items": {"type": "string"}, - "default": [], - }, - }, - }, "ValidationError": { "title": "ValidationError", "required": ["loc", "msg", "type"], diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py index 90fa6adaf..2e4b0146b 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial005.py +++ b/tests/test_tutorial/test_path_params/test_tutorial005.py @@ -33,9 +33,9 @@ def test_get_enums_invalid(): { "type": "enum", "loc": ["path", "model_name"], - "msg": "Input should be 'alexnet','resnet' or 'lenet'", + "msg": "Input should be 'alexnet', 'resnet' or 'lenet'", "input": "foo", - "ctx": {"expected": "'alexnet','resnet' or 'lenet'"}, + "ctx": {"expected": "'alexnet', 'resnet' or 'lenet'"}, } ] } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py new file mode 100644 index 000000000..94a40ed5a --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py @@ -0,0 +1,166 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005 import app + + client = TestClient(app) + return client + + +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an.py new file mode 100644 index 000000000..da92f98f6 --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an.py @@ -0,0 +1,166 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_an import app + + client = TestClient(app) + return client + + +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py310.py new file mode 100644 index 000000000..9109cb14e --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py310.py @@ -0,0 +1,170 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_an_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +@needs_py310 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py39.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py39.py new file mode 100644 index 000000000..fd4ec0575 --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_an_py39.py @@ -0,0 +1,170 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + +from ...utils import needs_py39 + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_an_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +@needs_py39 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_py310.py new file mode 100644 index 000000000..05df53422 --- /dev/null +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005_py310.py @@ -0,0 +1,170 @@ +import pytest +from dirty_equals import IsDict +from fastapi.testclient import TestClient + +from ...utils import needs_py310 + + +@pytest.fixture(name="client") +def get_client(): + from docs_src.schema_extra_example.tutorial005_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_post_body_example(client: TestClient): + response = client.put( + "/items/5", + json={ + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + ) + assert response.status_code == 200 + + +@needs_py310 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/{item_id}": { + "put": { + "summary": "Update Item", + "operationId": "update_item_items__item_id__put", + "parameters": [ + { + "required": True, + "schema": {"title": "Item Id", "type": "integer"}, + "name": "item_id", + "in": "path", + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": IsDict({"$ref": "#/components/schemas/Item"}) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "allOf": [ + {"$ref": "#/components/schemas/Item"} + ], + "title": "Item", + } + ), + "examples": { + "normal": { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, + }, + "converted": { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, + }, + "invalid": { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + }, + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "title": "HTTPValidationError", + "type": "object", + "properties": { + "detail": { + "title": "Detail", + "type": "array", + "items": {"$ref": "#/components/schemas/ValidationError"}, + } + }, + }, + "Item": { + "title": "Item", + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"title": "Name", "type": "string"}, + "description": IsDict( + { + "title": "Description", + "anyOf": [{"type": "string"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Description", "type": "string"} + ), + "price": {"title": "Price", "type": "number"}, + "tax": IsDict( + { + "title": "Tax", + "anyOf": [{"type": "number"}, {"type": "null"}], + } + ) + | IsDict( + # TODO: remove when deprecating Pydantic v1 + {"title": "Tax", "type": "number"} + ), + }, + }, + "ValidationError": { + "title": "ValidationError", + "required": ["loc", "msg", "type"], + "type": "object", + "properties": { + "loc": { + "title": "Location", + "type": "array", + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + }, + "msg": {"title": "Message", "type": "string"}, + "type": {"title": "Error Type", "type": "string"}, + }, + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/__init__.py b/tests/test_tutorial/test_separate_openapi_schemas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py new file mode 100644 index 000000000..cdfae9f8c --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py @@ -0,0 +1,133 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial001 import app + + client = TestClient(app) + return client + + +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py310.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py310.py new file mode 100644 index 000000000..3b22146f6 --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py310.py @@ -0,0 +1,136 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial001_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py310 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py310 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py39.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py39.py new file mode 100644 index 000000000..991abe811 --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001_py39.py @@ -0,0 +1,136 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial001_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py39 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py39 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py new file mode 100644 index 000000000..d2cf7945b --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py @@ -0,0 +1,133 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial002 import app + + client = TestClient(app) + return client + + +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py310.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py310.py new file mode 100644 index 000000000..89c9ce977 --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py310.py @@ -0,0 +1,136 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py310, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial002_py310 import app + + client = TestClient(app) + return client + + +@needs_py310 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py310 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py310 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py39.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py39.py new file mode 100644 index 000000000..6ac3d8f79 --- /dev/null +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002_py39.py @@ -0,0 +1,136 @@ +import pytest +from fastapi.testclient import TestClient + +from ...utils import needs_py39, needs_pydanticv2 + + +@pytest.fixture(name="client") +def get_client() -> TestClient: + from docs_src.separate_openapi_schemas.tutorial002_py39 import app + + client = TestClient(app) + return client + + +@needs_py39 +def test_create_item(client: TestClient) -> None: + response = client.post("/items/", json={"name": "Foo"}) + assert response.status_code == 200, response.text + assert response.json() == {"name": "Foo", "description": None} + + +@needs_py39 +def test_read_items(client: TestClient) -> None: + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [ + { + "name": "Portal Gun", + "description": "Device to travel through the multi-rick-verse", + }, + {"name": "Plumbus", "description": None}, + ] + + +@needs_py39 +@needs_pydanticv2 +def test_openapi_schema(client: TestClient) -> None: + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "items": {"$ref": "#/components/schemas/Item"}, + "type": "array", + "title": "Response Read Items Items Get", + } + } + }, + } + }, + }, + "post": { + "summary": "Create Item", + "operationId": "create_item_items__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Item"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + }, + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Item": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "description": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Description", + }, + }, + "type": "object", + "required": ["name"], + "title": "Item", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py deleted file mode 100644 index 4350567d1..000000000 --- a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py +++ /dev/null @@ -1,454 +0,0 @@ -import time -from pathlib import Path -from unittest.mock import MagicMock - -import pytest -from fastapi.testclient import TestClient - -from ...utils import needs_pydanticv1 - - -@pytest.fixture(scope="module") -def client(): - # Import while creating the client to create the DB after starting the test session - from docs_src.sql_databases_peewee.sql_app.main import app - - test_db = Path("./test.db") - with TestClient(app) as c: - yield c - test_db.unlink() - - -@needs_pydanticv1 -def test_create_user(client): - test_user = {"email": "johndoe@example.com", "password": "secret"} - response = client.post("/users/", json=test_user) - assert response.status_code == 200, response.text - data = response.json() - assert test_user["email"] == data["email"] - assert "id" in data - response = client.post("/users/", json=test_user) - assert response.status_code == 400, response.text - - -@needs_pydanticv1 -def test_get_user(client): - response = client.get("/users/1") - assert response.status_code == 200, response.text - data = response.json() - assert "email" in data - assert "id" in data - - -@needs_pydanticv1 -def test_inexistent_user(client): - response = client.get("/users/999") - assert response.status_code == 404, response.text - - -@needs_pydanticv1 -def test_get_users(client): - response = client.get("/users/") - assert response.status_code == 200, response.text - data = response.json() - assert "email" in data[0] - assert "id" in data[0] - - -time.sleep = MagicMock() - - -@needs_pydanticv1 -def test_get_slowusers(client): - response = client.get("/slowusers/") - assert response.status_code == 200, response.text - data = response.json() - assert "email" in data[0] - assert "id" in data[0] - - -@needs_pydanticv1 -def test_create_item(client): - item = {"title": "Foo", "description": "Something that fights"} - response = client.post("/users/1/items/", json=item) - assert response.status_code == 200, response.text - item_data = response.json() - assert item["title"] == item_data["title"] - assert item["description"] == item_data["description"] - assert "id" in item_data - assert "owner_id" in item_data - response = client.get("/users/1") - assert response.status_code == 200, response.text - user_data = response.json() - item_to_check = [it for it in user_data["items"] if it["id"] == item_data["id"]][0] - assert item_to_check["title"] == item["title"] - assert item_to_check["description"] == item["description"] - response = client.get("/users/1") - assert response.status_code == 200, response.text - user_data = response.json() - item_to_check = [it for it in user_data["items"] if it["id"] == item_data["id"]][0] - assert item_to_check["title"] == item["title"] - assert item_to_check["description"] == item["description"] - - -@needs_pydanticv1 -def test_read_items(client): - response = client.get("/items/") - assert response.status_code == 200, response.text - data = response.json() - assert data - first_item = data[0] - assert "title" in first_item - assert "description" in first_item - - -@needs_pydanticv1 -def test_openapi_schema(client): - response = client.get("/openapi.json") - assert response.status_code == 200, response.text - assert response.json() == { - "openapi": "3.1.0", - "info": {"title": "FastAPI", "version": "0.1.0"}, - "paths": { - "/users/": { - "get": { - "summary": "Read Users", - "operationId": "read_users_users__get", - "parameters": [ - { - "required": False, - "schema": { - "title": "Skip", - "type": "integer", - "default": 0, - }, - "name": "skip", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Users Users Get", - "type": "array", - "items": {"$ref": "#/components/schemas/User"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - "post": { - "summary": "Create User", - "operationId": "create_user_users__post", - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/UserCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/User"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - }, - }, - "/users/{user_id}": { - "get": { - "summary": "Read User", - "operationId": "read_user_users__user_id__get", - "parameters": [ - { - "required": True, - "schema": {"title": "User Id", "type": "integer"}, - "name": "user_id", - "in": "path", - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/User"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - } - }, - "/users/{user_id}/items/": { - "post": { - "summary": "Create Item For User", - "operationId": "create_item_for_user_users__user_id__items__post", - "parameters": [ - { - "required": True, - "schema": {"title": "User Id", "type": "integer"}, - "name": "user_id", - "in": "path", - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/ItemCreate"} - } - }, - "required": True, - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {"$ref": "#/components/schemas/Item"} - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - } - }, - "/items/": { - "get": { - "summary": "Read Items", - "operationId": "read_items_items__get", - "parameters": [ - { - "required": False, - "schema": { - "title": "Skip", - "type": "integer", - "default": 0, - }, - "name": "skip", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Items Items Get", - "type": "array", - "items": {"$ref": "#/components/schemas/Item"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - } - }, - "/slowusers/": { - "get": { - "summary": "Read Slow Users", - "operationId": "read_slow_users_slowusers__get", - "parameters": [ - { - "required": False, - "schema": { - "title": "Skip", - "type": "integer", - "default": 0, - }, - "name": "skip", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Limit", - "type": "integer", - "default": 100, - }, - "name": "limit", - "in": "query", - }, - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": { - "title": "Response Read Slow Users Slowusers Get", - "type": "array", - "items": {"$ref": "#/components/schemas/User"}, - } - } - }, - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - }, - }, - }, - } - }, - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": {"$ref": "#/components/schemas/ValidationError"}, - } - }, - }, - "Item": { - "title": "Item", - "required": ["title", "id", "owner_id"], - "type": "object", - "properties": { - "title": {"title": "Title", "type": "string"}, - "description": {"title": "Description", "type": "string"}, - "id": {"title": "Id", "type": "integer"}, - "owner_id": {"title": "Owner Id", "type": "integer"}, - }, - }, - "ItemCreate": { - "title": "ItemCreate", - "required": ["title"], - "type": "object", - "properties": { - "title": {"title": "Title", "type": "string"}, - "description": {"title": "Description", "type": "string"}, - }, - }, - "User": { - "title": "User", - "required": ["email", "id", "is_active"], - "type": "object", - "properties": { - "email": {"title": "Email", "type": "string"}, - "id": {"title": "Id", "type": "integer"}, - "is_active": {"title": "Is Active", "type": "boolean"}, - "items": { - "title": "Items", - "type": "array", - "items": {"$ref": "#/components/schemas/Item"}, - "default": [], - }, - }, - }, - "UserCreate": { - "title": "UserCreate", - "required": ["email", "password"], - "type": "object", - "properties": { - "email": {"title": "Email", "type": "string"}, - "password": {"title": "Password", "type": "string"}, - }, - }, - "ValidationError": { - "title": "ValidationError", - "required": ["loc", "msg", "type"], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": { - "anyOf": [{"type": "string"}, {"type": "integer"}] - }, - }, - "msg": {"title": "Message", "type": "string"}, - "type": {"title": "Error Type", "type": "string"}, - }, - }, - } - }, - } diff --git a/tests/test_tutorial/test_testing/test_tutorial003.py b/tests/test_tutorial/test_testing/test_tutorial003.py index d9e16390e..2a5d67071 100644 --- a/tests/test_tutorial/test_testing/test_tutorial003.py +++ b/tests/test_tutorial/test_testing/test_tutorial003.py @@ -1,5 +1,7 @@ -from docs_src.app_testing.tutorial003 import test_read_items +import pytest def test_main(): + with pytest.warns(DeprecationWarning): + from docs_src.app_testing.tutorial003 import test_read_items test_read_items() diff --git a/tests/test_webhooks_security.py b/tests/test_webhooks_security.py index a1c7b18fb..21a694cb5 100644 --- a/tests/test_webhooks_security.py +++ b/tests/test_webhooks_security.py @@ -13,7 +13,7 @@ bearer_scheme = HTTPBearer() class Subscription(BaseModel): username: str - montly_fee: float + monthly_fee: float start_date: datetime @@ -93,7 +93,7 @@ def test_openapi_schema(): "Subscription": { "properties": { "username": {"type": "string", "title": "Username"}, - "montly_fee": {"type": "number", "title": "Montly Fee"}, + "monthly_fee": {"type": "number", "title": "Monthly Fee"}, "start_date": { "type": "string", "format": "date-time", @@ -101,7 +101,7 @@ def test_openapi_schema(): }, }, "type": "object", - "required": ["username", "montly_fee", "start_date"], + "required": ["username", "monthly_fee", "start_date"], "title": "Subscription", }, "ValidationError": {